1 // Copyright (C) 2018 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "GLSnapshotTesting.h"
16
17 #include "aemu/base/files/PathUtils.h"
18 #include "aemu/base/files/StdioStream.h"
19 #include "aemu/base/system/System.h"
20 #include "snapshot/TextureLoader.h"
21 #include "snapshot/TextureSaver.h"
22
23 #include "GLTestUtils.h"
24 #include "OpenGLTestContext.h"
25
26 #include <gtest/gtest.h>
27
28 #include <EGL/egl.h>
29 #include <GLES2/gl2.h>
30 #include <GLES3/gl31.h>
31
32 namespace gfxstream {
33 namespace gl {
34
35 static constexpr const GLenum kNoError = GL_NO_ERROR;
36
37 using android::base::StdioStream;
38 using android::snapshot::TextureLoader;
39 using android::snapshot::TextureSaver;
40
describeGlEnum(GLenum enumValue)41 std::string describeGlEnum(GLenum enumValue) {
42 std::ostringstream description;
43 description << "0x" << std::hex << enumValue
44 << " (" << getEnumString(enumValue) << ")";
45 return description.str();
46 }
47
48 template <class T>
compareValue(T expected,T actual,const std::string & description)49 testing::AssertionResult compareValue(T expected,
50 T actual,
51 const std::string& description) {
52 if (expected != actual) {
53 return testing::AssertionFailure()
54 << description << "\n\tvalue was:\t"
55 << testing::PrintToString(actual) << "\n\t expected:\t"
56 << testing::PrintToString(expected) << "\t";
57 }
58 return testing::AssertionSuccess();
59 }
60
61 template testing::AssertionResult compareValue<GLboolean>(GLboolean,
62 GLboolean,
63 const std::string&);
64 template testing::AssertionResult compareValue<GLint>(GLint,
65 GLint,
66 const std::string&);
67 template testing::AssertionResult compareValue<GLfloat>(GLfloat,
68 GLfloat,
69 const std::string&);
70
compareGlobalGlBoolean(const GLESv2Dispatch * gl,GLenum name,GLboolean expected)71 testing::AssertionResult compareGlobalGlBoolean(const GLESv2Dispatch* gl,
72 GLenum name,
73 GLboolean expected) {
74 GLboolean current;
75 gl->glGetBooleanv(name, ¤t);
76 EXPECT_EQ(kNoError, gl->glGetError());
77 return compareValue<GLboolean>(expected, current,
78 "GL global boolean mismatch for parameter " +
79 describeGlEnum(name) + ":");
80 }
81
compareGlobalGlInt(const GLESv2Dispatch * gl,GLenum name,GLint expected)82 testing::AssertionResult compareGlobalGlInt(const GLESv2Dispatch* gl,
83 GLenum name,
84 GLint expected) {
85 GLint current;
86 gl->glGetIntegerv(name, ¤t);
87 EXPECT_EQ(kNoError, gl->glGetError());
88 return compareValue<GLint>(expected, current,
89 "GL global int mismatch for parameter " +
90 describeGlEnum(name) + ":");
91 }
92
compareGlobalGlInt_i(const GLESv2Dispatch * gl,GLenum name,GLuint index,GLint expected)93 testing::AssertionResult compareGlobalGlInt_i(const GLESv2Dispatch* gl,
94 GLenum name,
95 GLuint index,
96 GLint expected) {
97 GLint current;
98 gl->glGetIntegeri_v(name, index, ¤t);
99 EXPECT_EQ(kNoError, gl->glGetError());
100 return compareValue<GLint>(expected, current,
101 "GL global int_i mismatch for parameter " +
102 describeGlEnum(name) + ":" + std::to_string(index));
103
104 }
105
compareGlobalGlFloat(const GLESv2Dispatch * gl,GLenum name,GLfloat expected)106 testing::AssertionResult compareGlobalGlFloat(const GLESv2Dispatch* gl,
107 GLenum name,
108 GLfloat expected) {
109 GLfloat current;
110 gl->glGetFloatv(name, ¤t);
111 EXPECT_EQ(kNoError, gl->glGetError());
112 return compareValue<GLfloat>(expected, current,
113 "GL global float mismatch for parameter " +
114 describeGlEnum(name) + ":");
115 }
116
117 template <class T>
compareVector(const std::vector<T> & expected,const std::vector<T> & actual,const std::string & description)118 testing::AssertionResult compareVector(const std::vector<T>& expected,
119 const std::vector<T>& actual,
120 const std::string& description) {
121 std::stringstream message;
122 if (expected.size() != actual.size()) {
123 message << " (!) sizes do not match (actual " << actual.size()
124 << ", expected " << expected.size() << ")\n";
125 }
126
127 int mismatches = 0;
128 for (size_t i = 0; i < expected.size(); i++) {
129 if (i >= actual.size()) {
130 if (mismatches < 10) {
131 mismatches++;
132 message << " no match for:\t"
133 << testing::PrintToString(expected[i]) << "\n";
134 } else {
135 mismatches += expected.size() - i;
136 message << "\n nothing can match remaining elements.\n";
137 break;
138 }
139 } else if (expected[i] != actual[i]) {
140 mismatches++;
141 if (mismatches < 15) {
142 message << " at index " << i << ":\n\tvalue was:\t"
143 << testing::PrintToString(actual[i])
144 << "\n\t expected:\t"
145 << testing::PrintToString(expected[i]) << "\n";
146 } else if (mismatches == 15) {
147 message << " ... and indices " << i;
148 } else if (mismatches < 50) {
149 message << ", " << i;
150 } else if (mismatches == 50) {
151 message << ", etc...";
152 }
153 }
154 }
155 if (mismatches > 0) {
156 return testing::AssertionFailure()
157 << description << " had " << mismatches << " mismatches.\n"
158 << " expected: " << testing::PrintToString(expected) << "\n"
159 << " actual: " << testing::PrintToString(actual) << "\n"
160 << message.str() << " \n";
161 }
162 return testing::AssertionSuccess();
163 }
164
165 template testing::AssertionResult compareVector<GLboolean>(
166 const std::vector<GLboolean>&,
167 const std::vector<GLboolean>&,
168 const std::string&);
169 template testing::AssertionResult compareVector<GLint>(
170 const std::vector<GLint>&,
171 const std::vector<GLint>&,
172 const std::string&);
173 template testing::AssertionResult compareVector<GLfloat>(
174 const std::vector<GLfloat>&,
175 const std::vector<GLfloat>&,
176 const std::string&);
177
compareGlobalGlBooleanv(const GLESv2Dispatch * gl,GLenum name,const std::vector<GLboolean> & expected,GLuint size)178 testing::AssertionResult compareGlobalGlBooleanv(
179 const GLESv2Dispatch* gl,
180 GLenum name,
181 const std::vector<GLboolean>& expected,
182 GLuint size) {
183 std::vector<GLboolean> current;
184 current.resize(std::max(size, static_cast<GLuint>(expected.size())));
185 gl->glGetBooleanv(name, ¤t[0]);
186 EXPECT_EQ(kNoError, gl->glGetError());
187 return compareVector<GLboolean>(
188 expected, current,
189 "GL global booleanv parameter " + describeGlEnum(name));
190 }
191
192
compareGlobalGlBooleanv_i(const GLESv2Dispatch * gl,GLenum name,GLuint index,const std::vector<GLboolean> & expected,GLuint size)193 testing::AssertionResult compareGlobalGlBooleanv_i(
194 const GLESv2Dispatch* gl,
195 GLenum name,
196 GLuint index,
197 const std::vector<GLboolean>& expected,
198 GLuint size) {
199 std::vector<GLboolean> current;
200 current.resize(std::max(size, static_cast<GLuint>(expected.size())));
201 gl->glGetBooleani_v(name, index, ¤t[0]);
202 EXPECT_EQ(kNoError, gl->glGetError());
203 return compareVector<GLboolean>(
204 expected, current,
205 "GL global booleanv_i parameter " + describeGlEnum(name) + ":" + std::to_string(index) );
206 }
207
compareGlobalGlIntv(const GLESv2Dispatch * gl,GLenum name,const std::vector<GLint> & expected,GLuint size)208 testing::AssertionResult compareGlobalGlIntv(const GLESv2Dispatch* gl,
209 GLenum name,
210 const std::vector<GLint>& expected,
211 GLuint size) {
212 std::vector<GLint> current;
213 current.resize(std::max(size, static_cast<GLuint>(expected.size())));
214 gl->glGetIntegerv(name, ¤t[0]);
215 EXPECT_EQ(kNoError, gl->glGetError());
216 return compareVector<GLint>(
217 expected, current,
218 "GL global intv parameter " + describeGlEnum(name));
219 }
220
221
compareGlobalGlFloatv(const GLESv2Dispatch * gl,GLenum name,const std::vector<GLfloat> & expected,GLuint size)222 testing::AssertionResult compareGlobalGlFloatv(
223 const GLESv2Dispatch* gl,
224 GLenum name,
225 const std::vector<GLfloat>& expected,
226 GLuint size) {
227 std::vector<GLfloat> current;
228 current.resize(std::max(size, static_cast<GLuint>(expected.size())));
229 gl->glGetFloatv(name, ¤t[0]);
230 EXPECT_EQ(kNoError, gl->glGetError());
231 return compareVector<GLfloat>(
232 expected, current,
233 "GL global floatv parameter " + describeGlEnum(name));
234 }
235
SetUp()236 void SnapshotTest::SetUp() {
237 GLTest::SetUp();
238 mTestSystem.getTempRoot()->makeSubDir("Snapshots");
239 mSnapshotPath = mTestSystem.getTempRoot()->makeSubPath("Snapshots");
240 }
241
saveSnapshot(const std::string streamFile,const std::string textureFile)242 void SnapshotTest::saveSnapshot(const std::string streamFile,
243 const std::string textureFile) {
244 const EGLDispatch* egl = LazyLoadedEGLDispatch::get();
245
246 std::unique_ptr<StdioStream> m_stream(new StdioStream(
247 android_fopen(streamFile.c_str(), "wb"), StdioStream::kOwner));
248 auto egl_stream = static_cast<EGLStreamKHR>(m_stream.get());
249 std::unique_ptr<TextureSaver> m_texture_saver(new TextureSaver(StdioStream(
250 android_fopen(textureFile.c_str(), "wb"), StdioStream::kOwner)));
251
252 egl->eglPreSaveContext(m_display, m_context, egl_stream);
253 egl->eglSaveAllImages(m_display, egl_stream, &m_texture_saver);
254
255 egl->eglSaveContext(m_display, m_context, egl_stream);
256
257 // Skip saving a bunch of FrameBuffer's fields
258 // Skip saving colorbuffers
259 // Skip saving window surfaces
260
261 egl->eglSaveConfig(m_display, m_config, egl_stream);
262
263 // Skip saving a bunch of process-owned objects
264
265 egl->eglPostSaveContext(m_display, m_context, egl_stream);
266
267 m_stream->close();
268 m_texture_saver->done();
269 }
270
loadSnapshot(const std::string streamFile,const std::string textureFile)271 void SnapshotTest::loadSnapshot(const std::string streamFile,
272 const std::string textureFile) {
273 const EGLDispatch* egl = LazyLoadedEGLDispatch::get();
274
275 std::unique_ptr<StdioStream> m_stream(new StdioStream(
276 android_fopen(streamFile.c_str(), "rb"), StdioStream::kOwner));
277 auto egl_stream = static_cast<EGLStreamKHR>(m_stream.get());
278 std::shared_ptr<TextureLoader> m_texture_loader(
279 new TextureLoader(StdioStream(android_fopen(textureFile.c_str(), "rb"),
280 StdioStream::kOwner)));
281
282 egl->eglLoadAllImages(m_display, egl_stream, &m_texture_loader);
283
284 EGLint contextAttribs[5] = {EGL_CONTEXT_CLIENT_VERSION, 3,
285 EGL_CONTEXT_MINOR_VERSION_KHR, 0, EGL_NONE};
286
287 m_context = egl->eglLoadContext(m_display, &contextAttribs[0], egl_stream);
288 m_config = egl->eglLoadConfig(m_display, egl_stream);
289 m_surface = pbufferSurface(m_display, m_config, kTestSurfaceSize[0],
290 kTestSurfaceSize[0]);
291 egl->eglPostLoadAllImages(m_display, egl_stream);
292
293 m_stream->close();
294 m_texture_loader->join();
295 egl->eglMakeCurrent(m_display, m_surface, m_surface, m_context);
296 }
297
preloadReset()298 void SnapshotTest::preloadReset() {
299 GLTest::TearDown();
300 GLTest::SetUp();
301 }
302
__anon34268c7f0102null303 void SnapshotTest::doSnapshot(std::function<void()> preloadCheck = [] {}) {
304 std::string timeStamp =
305 std::to_string(android::base::getUnixTimeUs());
306 std::string snapshotFile =
307 android::base::pj({mSnapshotPath, std::string("snapshot_") + timeStamp + ".snap"});
308 std::string textureFile =
309 android::base::pj({mSnapshotPath, std::string("textures_") + timeStamp + ".stex"});
310
311 saveSnapshot(snapshotFile, textureFile);
312
313 preloadReset();
314 preloadCheck();
315
316 loadSnapshot(snapshotFile, textureFile);
317
318 EXPECT_NE(m_context, EGL_NO_CONTEXT);
319 EXPECT_NE(m_surface, EGL_NO_SURFACE);
320 }
321
doCheckedSnapshot()322 void SnapshotPreserveTest::doCheckedSnapshot() {
323 {
324 SCOPED_TRACE("during pre-snapshot default state check");
325 defaultStateCheck();
326 ASSERT_EQ(kNoError, gl->glGetError());
327 }
328 {
329 SCOPED_TRACE("during pre-snapshot state change");
330 stateChange();
331 ASSERT_EQ(kNoError, gl->glGetError());
332 }
333 {
334 SCOPED_TRACE("during pre-snapshot changed state check");
335 changedStateCheck();
336 }
337 SnapshotTest::doSnapshot([this] {
338 SCOPED_TRACE("during post-reset default state check");
339 EXPECT_EQ(kNoError, gl->glGetError());
340 defaultStateCheck();
341 });
342 EXPECT_EQ(kNoError, gl->glGetError());
343 {
344 SCOPED_TRACE("during post-snapshot changed state check");
345 changedStateCheck();
346 EXPECT_EQ(kNoError, gl->glGetError());
347 }
348 }
349
350 } // namespace gl
351 } // namespace gfxstream
352