• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, &current);
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, &current);
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, &current);
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, &current);
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, &current[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,  &current[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, &current[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, &current[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