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