• 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 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, &current);
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, &current);
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, &current);
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, &current);
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, &current[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,  &current[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, &current[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, &current[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