• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2020 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // CaptureReplayTest.cpp:
7 //   Application that runs replay for testing of capture replay
8 //
9 
10 #include "common/debug.h"
11 #include "common/system_utils.h"
12 #include "util/EGLPlatformParameters.h"
13 #include "util/EGLWindow.h"
14 #include "util/OSWindow.h"
15 
16 #include <stdint.h>
17 #include <string.h>
18 #include <fstream>
19 #include <functional>
20 #include <iostream>
21 #include <list>
22 #include <memory>
23 #include <ostream>
24 #include <string>
25 #include <utility>
26 
27 #include "util/capture/frame_capture_test_utils.h"
28 
29 constexpr char kResultTag[] = "*RESULT";
30 constexpr char kTracePath[] = ANGLE_CAPTURE_REPLAY_TEST_NAMES_PATH;
31 
32 class CaptureReplayTests
33 {
34   public:
CaptureReplayTests()35     CaptureReplayTests()
36     {
37         // Load EGL library so we can initialize the display.
38         mEntryPointsLib.reset(
39             angle::OpenSharedLibrary(ANGLE_EGL_LIBRARY_NAME, angle::SearchType::ModuleDir));
40 
41         mOSWindow = OSWindow::New();
42         mOSWindow->disableErrorMessageDialog();
43     }
44 
~CaptureReplayTests()45     ~CaptureReplayTests()
46     {
47         EGLWindow::Delete(&mEGLWindow);
48         OSWindow::Delete(&mOSWindow);
49     }
50 
initializeTest(const std::string & execDir,const angle::TraceInfo & traceInfo)51     bool initializeTest(const std::string &execDir, const angle::TraceInfo &traceInfo)
52     {
53         if (!mOSWindow->initialize(traceInfo.name, traceInfo.drawSurfaceWidth,
54                                    traceInfo.drawSurfaceHeight))
55         {
56             return false;
57         }
58 
59         mOSWindow->disableErrorMessageDialog();
60         mOSWindow->setVisible(true);
61 
62         if (mEGLWindow && !mEGLWindow->isContextVersion(traceInfo.contextClientMajorVersion,
63                                                         traceInfo.contextClientMinorVersion))
64         {
65             EGLWindow::Delete(&mEGLWindow);
66             mEGLWindow = nullptr;
67         }
68 
69         if (!mEGLWindow)
70         {
71             mEGLWindow = EGLWindow::New(traceInfo.contextClientMajorVersion,
72                                         traceInfo.contextClientMinorVersion);
73         }
74 
75         ConfigParameters configParams;
76         configParams.redBits     = traceInfo.configRedBits;
77         configParams.greenBits   = traceInfo.configGreenBits;
78         configParams.blueBits    = traceInfo.configBlueBits;
79         configParams.alphaBits   = traceInfo.configAlphaBits;
80         configParams.depthBits   = traceInfo.configDepthBits;
81         configParams.stencilBits = traceInfo.configStencilBits;
82 
83         configParams.clientArraysEnabled   = traceInfo.areClientArraysEnabled;
84         configParams.bindGeneratesResource = traceInfo.isBindGeneratesResourcesEnabled;
85         configParams.webGLCompatibility    = traceInfo.isWebGLCompatibilityEnabled;
86         configParams.robustResourceInit    = traceInfo.isRobustResourceInitEnabled;
87 
88         mPlatformParams.renderer   = traceInfo.displayPlatformType;
89         mPlatformParams.deviceType = traceInfo.displayDeviceType;
90         mPlatformParams.enable(angle::Feature::ForceInitShaderVariables);
91 
92         if (!mEGLWindow->initializeGL(mOSWindow, mEntryPointsLib.get(),
93                                       angle::GLESDriverType::AngleEGL, mPlatformParams,
94                                       configParams))
95         {
96             mOSWindow->destroy();
97             return false;
98         }
99         // Disable vsync
100         if (!mEGLWindow->setSwapInterval(0))
101         {
102             cleanupTest();
103             return false;
104         }
105 
106         // Load trace
107         mTraceLibrary.reset(new angle::TraceLibrary(traceInfo.name));
108         if (!mTraceLibrary->valid())
109         {
110             std::cout << "Failed to load trace library: " << traceInfo.name << "\n";
111             return false;
112         }
113 
114         if (traceInfo.isBinaryDataCompressed)
115         {
116             mTraceLibrary->setBinaryDataDecompressCallback(angle::DecompressBinaryData);
117         }
118 
119         std::stringstream binaryPathStream;
120         binaryPathStream << execDir << angle::GetPathSeparator()
121                          << ANGLE_CAPTURE_REPLAY_TEST_DATA_DIR;
122 
123         mTraceLibrary->setBinaryDataDir(binaryPathStream.str().c_str());
124 
125         mTraceLibrary->setupReplay();
126         return true;
127     }
128 
cleanupTest()129     void cleanupTest()
130     {
131         mTraceLibrary.reset(nullptr);
132         mEGLWindow->destroyGL();
133         mOSWindow->destroy();
134     }
135 
swap()136     void swap() { mEGLWindow->swap(); }
137 
runTest(const std::string & exeDir,const angle::TraceInfo & traceInfo)138     int runTest(const std::string &exeDir, const angle::TraceInfo &traceInfo)
139     {
140         if (!initializeTest(exeDir, traceInfo))
141         {
142             return -1;
143         }
144 
145         for (uint32_t frame = traceInfo.frameStart; frame <= traceInfo.frameEnd; frame++)
146         {
147             mTraceLibrary->replayFrame(frame);
148 
149             const char *replayedSerializedState =
150                 reinterpret_cast<const char *>(glGetString(GL_SERIALIZED_CONTEXT_STRING_ANGLE));
151             const char *capturedSerializedState = mTraceLibrary->getSerializedContextState(frame);
152 
153             bool isEqual =
154                 (capturedSerializedState && replayedSerializedState)
155                     ? compareSerializedContexts(replayedSerializedState, capturedSerializedState)
156                     : (capturedSerializedState == replayedSerializedState);
157 
158             // Swap always to allow RenderDoc/other tools to capture frames.
159             swap();
160             if (!isEqual)
161             {
162                 std::ostringstream replayName;
163                 replayName << exeDir << angle::GetPathSeparator() << traceInfo.name
164                            << "_ContextReplayed" << frame << ".json";
165 
166                 std::ofstream debugReplay(replayName.str());
167                 debugReplay << (replayedSerializedState ? replayedSerializedState : "") << "\n";
168 
169                 std::ostringstream captureName;
170                 captureName << exeDir << angle::GetPathSeparator() << traceInfo.name
171                             << "_ContextCaptured" << frame << ".json";
172                 std::ofstream debugCapture(captureName.str());
173 
174                 debugCapture << (capturedSerializedState ? capturedSerializedState : "") << "\n";
175 
176                 cleanupTest();
177                 return -1;
178             }
179         }
180         cleanupTest();
181         return 0;
182     }
183 
run()184     int run()
185     {
186         std::string startingDirectory = angle::GetCWD().value();
187 
188         // Set CWD to executable directory.
189         std::string exeDir = angle::GetExecutableDirectory();
190 
191         std::vector<std::string> traces;
192 
193         std::stringstream tracePathStream;
194         tracePathStream << exeDir << angle::GetPathSeparator() << kTracePath;
195 
196         if (!angle::LoadTraceNamesFromJSON(tracePathStream.str(), &traces))
197         {
198             std::cout << "Unable to load trace names from " << kTracePath << "\n";
199             return 1;
200         }
201 
202         for (const std::string &trace : traces)
203         {
204             std::stringstream traceJsonPathStream;
205             traceJsonPathStream << exeDir << angle::GetPathSeparator()
206                                 << ANGLE_CAPTURE_REPLAY_TEST_DATA_DIR << angle::GetPathSeparator()
207                                 << trace << ".json";
208             std::string traceJsonPath = traceJsonPathStream.str();
209 
210             int result                 = -1;
211             angle::TraceInfo traceInfo = {};
212             if (!angle::LoadTraceInfoFromJSON(trace, traceJsonPath, &traceInfo))
213             {
214                 std::cout << "Unable to load trace data: " << traceJsonPath << "\n";
215             }
216             else
217             {
218                 result = runTest(exeDir, traceInfo);
219             }
220             std::cout << kResultTag << " " << trace << " " << result << "\n";
221         }
222 
223         angle::SetCWD(startingDirectory.c_str());
224         return 0;
225     }
226 
227   private:
compareSerializedContexts(const char * capturedSerializedContextState,const char * replaySerializedContextState)228     bool compareSerializedContexts(const char *capturedSerializedContextState,
229                                    const char *replaySerializedContextState)
230     {
231 
232         return !strcmp(replaySerializedContextState, capturedSerializedContextState);
233     }
234 
235     OSWindow *mOSWindow   = nullptr;
236     EGLWindow *mEGLWindow = nullptr;
237     EGLPlatformParameters mPlatformParams;
238     // Handle to the entry point binding library.
239     std::unique_ptr<angle::Library> mEntryPointsLib;
240     std::unique_ptr<angle::TraceLibrary> mTraceLibrary;
241 };
242 
main(int argc,char ** argv)243 int main(int argc, char **argv)
244 {
245     CaptureReplayTests app;
246     return app.run();
247 }
248