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