• 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 "base/PathUtils.h"
18 #include "base/StdioStream.h"
19 #include "base/System.h"
20 #include "base/testing/TestSystem.h"
21 #include "snapshot/TextureLoader.h"
22 #include "snapshot/TextureSaver.h"
23 
24 #include "GLTestUtils.h"
25 #include "OpenGLTestContext.h"
26 
27 #include <gtest/gtest.h>
28 
29 #include <EGL/egl.h>
30 #include <GLES2/gl2.h>
31 #include <GLES3/gl31.h>
32 
33 namespace emugl {
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 
compareGlobalGlFloat(const GLESv2Dispatch * gl,GLenum name,GLfloat expected)91 testing::AssertionResult compareGlobalGlFloat(const GLESv2Dispatch* gl,
92                                               GLenum name,
93                                               GLfloat expected) {
94     GLfloat current;
95     gl->glGetFloatv(name, &current);
96     EXPECT_EQ(GL_NO_ERROR, gl->glGetError());
97     return compareValue<GLfloat>(expected, current,
98                                  "GL global float mismatch for parameter " +
99                                          describeGlEnum(name) + ":");
100 }
101 
102 template <class T>
compareVector(const std::vector<T> & expected,const std::vector<T> & actual,const std::string & description)103 testing::AssertionResult compareVector(const std::vector<T>& expected,
104                                        const std::vector<T>& actual,
105                                        const std::string& description) {
106     std::stringstream message;
107     if (expected.size() != actual.size()) {
108         message << "    (!) sizes do not match (actual " << actual.size()
109                 << ", expected " << expected.size() << ")\n";
110     }
111 
112     int mismatches = 0;
113     for (int i = 0; i < expected.size(); i++) {
114         if (i >= actual.size()) {
115             if (mismatches < 10) {
116                 mismatches++;
117                 message << "    no match for:\t"
118                         << testing::PrintToString(expected[i]) << "\n";
119             } else {
120                 mismatches += expected.size() - i;
121                 message << "\n    nothing can match remaining elements.\n";
122                 break;
123             }
124         } else if (expected[i] != actual[i]) {
125             mismatches++;
126             if (mismatches < 15) {
127                 message << "    at index " << i << ":\n\tvalue was:\t"
128                         << testing::PrintToString(actual[i])
129                         << "\n\t expected:\t"
130                         << testing::PrintToString(expected[i]) << "\n";
131             } else if (mismatches == 15) {
132                 message << "    ... and indices " << i;
133             } else if (mismatches < 50) {
134                 message << ", " << i;
135             } else if (mismatches == 50) {
136                 message << ", etc...";
137             }
138         }
139     }
140     if (mismatches > 0) {
141         return testing::AssertionFailure()
142                << description << " had " << mismatches << " mismatches.\n"
143                << "  expected: " << testing::PrintToString(expected) << "\n"
144                << "    actual: " << testing::PrintToString(actual) << "\n"
145                << message.str() << "  \n";
146     }
147     return testing::AssertionSuccess();
148 }
149 
150 template testing::AssertionResult compareVector<GLboolean>(
151         const std::vector<GLboolean>&,
152         const std::vector<GLboolean>&,
153         const std::string&);
154 template testing::AssertionResult compareVector<GLint>(
155         const std::vector<GLint>&,
156         const std::vector<GLint>&,
157         const std::string&);
158 template testing::AssertionResult compareVector<GLfloat>(
159         const std::vector<GLfloat>&,
160         const std::vector<GLfloat>&,
161         const std::string&);
162 
compareGlobalGlBooleanv(const GLESv2Dispatch * gl,GLenum name,const std::vector<GLboolean> & expected,GLuint size)163 testing::AssertionResult compareGlobalGlBooleanv(
164         const GLESv2Dispatch* gl,
165         GLenum name,
166         const std::vector<GLboolean>& expected,
167         GLuint size) {
168     std::vector<GLboolean> current;
169     current.resize(std::max(size, static_cast<GLuint>(expected.size())));
170     gl->glGetBooleanv(name, &current[0]);
171     EXPECT_EQ(GL_NO_ERROR, gl->glGetError());
172     return compareVector<GLboolean>(
173             expected, current,
174             "GL global booleanv parameter " + describeGlEnum(name));
175 }
176 
compareGlobalGlIntv(const GLESv2Dispatch * gl,GLenum name,const std::vector<GLint> & expected,GLuint size)177 testing::AssertionResult compareGlobalGlIntv(const GLESv2Dispatch* gl,
178                                              GLenum name,
179                                              const std::vector<GLint>& expected,
180                                              GLuint size) {
181     std::vector<GLint> current;
182     current.resize(std::max(size, static_cast<GLuint>(expected.size())));
183     gl->glGetIntegerv(name, &current[0]);
184     EXPECT_EQ(GL_NO_ERROR, gl->glGetError());
185     return compareVector<GLint>(
186             expected, current,
187             "GL global intv parameter " + describeGlEnum(name));
188 }
189 
compareGlobalGlFloatv(const GLESv2Dispatch * gl,GLenum name,const std::vector<GLfloat> & expected,GLuint size)190 testing::AssertionResult compareGlobalGlFloatv(
191         const GLESv2Dispatch* gl,
192         GLenum name,
193         const std::vector<GLfloat>& expected,
194         GLuint size) {
195     std::vector<GLfloat> current;
196     current.resize(std::max(size, static_cast<GLuint>(expected.size())));
197     gl->glGetFloatv(name, &current[0]);
198     EXPECT_EQ(GL_NO_ERROR, gl->glGetError());
199     return compareVector<GLfloat>(
200             expected, current,
201             "GL global floatv parameter " + describeGlEnum(name));
202 }
203 
SetUp()204 void SnapshotTest::SetUp() {
205     GLTest::SetUp();
206     mTestSystem.getTempRoot()->makeSubDir("Snapshots");
207     mSnapshotPath = mTestSystem.getTempRoot()->makeSubPath("Snapshots");
208 }
209 
saveSnapshot(const std::string streamFile,const std::string textureFile)210 void SnapshotTest::saveSnapshot(const std::string streamFile,
211                                 const std::string textureFile) {
212     const EGLDispatch* egl = LazyLoadedEGLDispatch::get();
213 
214     std::unique_ptr<StdioStream> m_stream(new StdioStream(
215             android_fopen(streamFile.c_str(), "wb"), StdioStream::kOwner));
216     auto egl_stream = static_cast<EGLStream>(m_stream.get());
217     std::unique_ptr<TextureSaver> m_texture_saver(new TextureSaver(StdioStream(
218             android_fopen(textureFile.c_str(), "wb"), StdioStream::kOwner)));
219 
220     egl->eglPreSaveContext(m_display, m_context, egl_stream);
221     egl->eglSaveAllImages(m_display, egl_stream, &m_texture_saver);
222 
223     egl->eglSaveContext(m_display, m_context, egl_stream);
224 
225     // Skip saving a bunch of FrameBuffer's fields
226     // Skip saving colorbuffers
227     // Skip saving window surfaces
228 
229     egl->eglSaveConfig(m_display, m_config, egl_stream);
230 
231     // Skip saving a bunch of process-owned objects
232 
233     egl->eglPostSaveContext(m_display, m_context, egl_stream);
234 
235     m_stream->close();
236     m_texture_saver->done();
237 }
238 
loadSnapshot(const std::string streamFile,const std::string textureFile)239 void SnapshotTest::loadSnapshot(const std::string streamFile,
240                                 const std::string textureFile) {
241     const EGLDispatch* egl = LazyLoadedEGLDispatch::get();
242 
243     std::unique_ptr<StdioStream> m_stream(new StdioStream(
244             android_fopen(streamFile.c_str(), "rb"), StdioStream::kOwner));
245     auto egl_stream = static_cast<EGLStream>(m_stream.get());
246     std::shared_ptr<TextureLoader> m_texture_loader(
247             new TextureLoader(StdioStream(android_fopen(textureFile.c_str(), "rb"),
248                                           StdioStream::kOwner)));
249 
250     egl->eglLoadAllImages(m_display, egl_stream, &m_texture_loader);
251 
252     EGLint contextAttribs[5] = {EGL_CONTEXT_CLIENT_VERSION, 3,
253                                 EGL_CONTEXT_MINOR_VERSION_KHR, 0, EGL_NONE};
254 
255     m_context = egl->eglLoadContext(m_display, &contextAttribs[0], egl_stream);
256     m_config = egl->eglLoadConfig(m_display, egl_stream);
257     m_surface = pbufferSurface(m_display, m_config, kTestSurfaceSize[0],
258                                kTestSurfaceSize[0]);
259     egl->eglPostLoadAllImages(m_display, egl_stream);
260 
261     m_stream->close();
262     m_texture_loader->join();
263     egl->eglMakeCurrent(m_display, m_surface, m_surface, m_context);
264 }
265 
preloadReset()266 void SnapshotTest::preloadReset() {
267     GLTest::TearDown();
268     GLTest::SetUp();
269 }
270 
__anonc7d861d00102null271 void SnapshotTest::doSnapshot(std::function<void()> preloadCheck = [] {}) {
272     std::string timeStamp =
273             std::to_string(android::base::getUnixTimeUs());
274     std::string snapshotFile =
275             android::base::pj({mSnapshotPath, std::string("snapshot_") + timeStamp + ".snap"});
276     std::string textureFile =
277             android::base::pj({mSnapshotPath, std::string("textures_") + timeStamp + ".stex"});
278 
279     saveSnapshot(snapshotFile, textureFile);
280 
281     preloadReset();
282     preloadCheck();
283 
284     loadSnapshot(snapshotFile, textureFile);
285 
286     EXPECT_NE(m_context, EGL_NO_CONTEXT);
287     EXPECT_NE(m_surface, EGL_NO_SURFACE);
288 }
289 
doCheckedSnapshot()290 void SnapshotPreserveTest::doCheckedSnapshot() {
291     {
292         SCOPED_TRACE("during pre-snapshot default state check");
293         defaultStateCheck();
294         ASSERT_EQ(GL_NO_ERROR, gl->glGetError());
295     }
296     {
297         SCOPED_TRACE("during pre-snapshot state change");
298         stateChange();
299         ASSERT_EQ(GL_NO_ERROR, gl->glGetError());
300     }
301     {
302         SCOPED_TRACE("during pre-snapshot changed state check");
303         changedStateCheck();
304     }
305     SnapshotTest::doSnapshot([this] {
306         SCOPED_TRACE("during post-reset default state check");
307         EXPECT_EQ(GL_NO_ERROR, gl->glGetError());
308         defaultStateCheck();
309     });
310     EXPECT_EQ(GL_NO_ERROR, gl->glGetError());
311     {
312         SCOPED_TRACE("during post-snapshot changed state check");
313         changedStateCheck();
314         EXPECT_EQ(GL_NO_ERROR, gl->glGetError());
315     }
316 }
317 
318 }  // namespace emugl
319