• 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/frame_capture_test_utils.h"
28 
29 // Build the right context header based on replay ID
30 // This will expand to "angle_capture_context<#>.h"
31 #include ANGLE_MACRO_STRINGIZE(ANGLE_CAPTURE_REPLAY_COMPOSITE_TESTS_HEADER)
32 
33 constexpr char kResultTag[] = "*RESULT";
34 
35 class CaptureReplayTests
36 {
37   public:
CaptureReplayTests()38     CaptureReplayTests()
39     {
40         // Load EGL library so we can initialize the display.
41         mEntryPointsLib.reset(
42             angle::OpenSharedLibrary(ANGLE_EGL_LIBRARY_NAME, angle::SearchType::ModuleDir));
43 
44         mOSWindow = OSWindow::New();
45         mOSWindow->disableErrorMessageDialog();
46     }
47 
~CaptureReplayTests()48     ~CaptureReplayTests()
49     {
50         EGLWindow::Delete(&mEGLWindow);
51         OSWindow::Delete(&mOSWindow);
52     }
53 
initializeTest(uint32_t testIndex,const TestTraceInfo & testTraceInfo)54     bool initializeTest(uint32_t testIndex, const TestTraceInfo &testTraceInfo)
55     {
56         if (!mOSWindow->initialize(testTraceInfo.testName, testTraceInfo.replayDrawSurfaceWidth,
57                                    testTraceInfo.replayDrawSurfaceHeight))
58         {
59             return false;
60         }
61 
62         mOSWindow->disableErrorMessageDialog();
63         mOSWindow->setVisible(true);
64 
65         if (mEGLWindow && !mEGLWindow->isContextVersion(testTraceInfo.replayContextMajorVersion,
66                                                         testTraceInfo.replayContextMinorVersion))
67         {
68             EGLWindow::Delete(&mEGLWindow);
69             mEGLWindow = nullptr;
70         }
71 
72         if (!mEGLWindow)
73         {
74             mEGLWindow = EGLWindow::New(testTraceInfo.replayContextMajorVersion,
75                                         testTraceInfo.replayContextMinorVersion);
76         }
77 
78         ConfigParameters configParams;
79         configParams.redBits     = testTraceInfo.defaultFramebufferRedBits;
80         configParams.greenBits   = testTraceInfo.defaultFramebufferGreenBits;
81         configParams.blueBits    = testTraceInfo.defaultFramebufferBlueBits;
82         configParams.alphaBits   = testTraceInfo.defaultFramebufferAlphaBits;
83         configParams.depthBits   = testTraceInfo.defaultFramebufferDepthBits;
84         configParams.stencilBits = testTraceInfo.defaultFramebufferStencilBits;
85 
86         configParams.clientArraysEnabled   = testTraceInfo.areClientArraysEnabled;
87         configParams.bindGeneratesResource = testTraceInfo.bindGeneratesResources;
88         configParams.webGLCompatibility    = testTraceInfo.webGLCompatibility;
89         configParams.robustResourceInit    = testTraceInfo.robustResourceInit;
90 
91         mPlatformParams.renderer   = testTraceInfo.replayPlatformType;
92         mPlatformParams.deviceType = testTraceInfo.replayDeviceType;
93 
94         if (!mEGLWindow->initializeGL(mOSWindow, mEntryPointsLib.get(),
95                                       angle::GLESDriverType::AngleEGL, mPlatformParams,
96                                       configParams))
97         {
98             mOSWindow->destroy();
99             return false;
100         }
101         // Disable vsync
102         if (!mEGLWindow->setSwapInterval(0))
103         {
104             cleanupTest();
105             return false;
106         }
107 
108         mStartingDirectory = angle::GetCWD().value();
109 
110         // Load trace
111         mTraceLibrary.reset(new angle::TraceLibrary(testTraceInfo.testName.c_str()));
112 
113         // Set CWD to executable directory.
114         std::string exeDir = angle::GetExecutableDirectory();
115         if (!angle::SetCWD(exeDir.c_str()))
116         {
117             cleanupTest();
118             return false;
119         }
120         if (testTraceInfo.isBinaryDataCompressed)
121         {
122             mTraceLibrary->setBinaryDataDecompressCallback(angle::DecompressBinaryData);
123         }
124         mTraceLibrary->setBinaryDataDir(ANGLE_CAPTURE_REPLAY_TEST_DATA_DIR);
125 
126         mTraceLibrary->setupReplay();
127         return true;
128     }
129 
cleanupTest()130     void cleanupTest()
131     {
132         angle::SetCWD(mStartingDirectory.c_str());
133         mTraceLibrary.reset(nullptr);
134         mEGLWindow->destroyGL();
135         mOSWindow->destroy();
136     }
137 
swap()138     void swap() { mEGLWindow->swap(); }
139 
runTest(uint32_t testIndex,const TestTraceInfo & testTraceInfo)140     int runTest(uint32_t testIndex, const TestTraceInfo &testTraceInfo)
141     {
142         if (!initializeTest(testIndex, testTraceInfo))
143         {
144             return -1;
145         }
146 
147         for (uint32_t frame = testTraceInfo.replayFrameStart; frame <= testTraceInfo.replayFrameEnd;
148              frame++)
149         {
150             mTraceLibrary->replayFrame(frame);
151 
152             const GLubyte *bytes = glGetString(GL_SERIALIZED_CONTEXT_STRING_ANGLE);
153             bool isEqual =
154                 compareSerializedContexts(testIndex, frame, reinterpret_cast<const char *>(bytes));
155             // Swap always to allow RenderDoc/other tools to capture frames.
156             swap();
157             if (!isEqual)
158             {
159                 std::ostringstream replayName;
160                 replayName << testTraceInfo.testName << "_ContextReplayed" << frame << ".json";
161                 std::ofstream debugReplay(replayName.str());
162                 debugReplay << reinterpret_cast<const char *>(bytes) << "\n";
163 
164                 std::ostringstream captureName;
165                 captureName << testTraceInfo.testName << "_ContextCaptured" << frame << ".json";
166                 std::ofstream debugCapture(captureName.str());
167 
168                 debugCapture << mTraceLibrary->getSerializedContextState(frame) << "\n";
169 
170                 cleanupTest();
171                 return -1;
172             }
173         }
174         cleanupTest();
175         return 0;
176     }
177 
run()178     int run()
179     {
180         for (size_t i = 0; i < testTraceInfos.size(); i++)
181         {
182             int result = runTest(static_cast<uint32_t>(i), testTraceInfos[i]);
183             std::cout << kResultTag << " " << testTraceInfos[i].testName << " " << result << "\n";
184         }
185         return 0;
186     }
187 
188   private:
compareSerializedContexts(uint32_t testIndex,uint32_t frame,const char * replaySerializedContextState)189     bool compareSerializedContexts(uint32_t testIndex,
190                                    uint32_t frame,
191                                    const char *replaySerializedContextState)
192     {
193 
194         return !strcmp(replaySerializedContextState,
195                        mTraceLibrary->getSerializedContextState(frame));
196     }
197 
198     std::string mStartingDirectory;
199     OSWindow *mOSWindow   = nullptr;
200     EGLWindow *mEGLWindow = nullptr;
201     EGLPlatformParameters mPlatformParams;
202     // Handle to the entry point binding library.
203     std::unique_ptr<angle::Library> mEntryPointsLib;
204     std::unique_ptr<angle::TraceLibrary> mTraceLibrary;
205 };
206 
main(int argc,char ** argv)207 int main(int argc, char **argv)
208 {
209     CaptureReplayTests app;
210     return app.run();
211 }
212