• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include "GLSnapshotTestDispatch.h"
2 
3 #include "FrameBuffer.h"
4 #include "GLSnapshotTesting.h"
5 #include "GLTestUtils.h"
6 #include "apigen-codec-common/glUtils.h"
7 #include "RenderThreadInfo.h"
8 
9 #include "aemu/base/files/PathUtils.h"
10 #include "aemu/base/files/StdioStream.h"
11 #include "aemu/base/system/System.h"
12 #include "snapshot/TextureLoader.h"
13 #include "snapshot/TextureSaver.h"
14 
15 namespace gfxstream {
16 namespace gl {
17 
18 using android::base::StdioStream;
19 using android::snapshot::TextureLoader;
20 using android::snapshot::TextureSaver;
21 
sSnapshotTestDispatch()22 static SnapshotTestDispatch* sSnapshotTestDispatch() {
23     static SnapshotTestDispatch* s = new SnapshotTestDispatch;
24     return s;
25 }
26 
27 // static
getSnapshotTestDispatch()28 const GLESv2Dispatch* getSnapshotTestDispatch() {
29     return sSnapshotTestDispatch();
30 }
31 
SnapshotTestDispatch()32 SnapshotTestDispatch::SnapshotTestDispatch() {
33     mTestSystem.getTempRoot()->makeSubDir("SampleSnapshots");
34     mSnapshotPath = mTestSystem.getTempRoot()->makeSubPath("SampleSnapshots");
35 
36     mValid = gles2_dispatch_init(this);
37     if (mValid) {
38         overrideFunctions();
39     } else {
40         fprintf(stderr, "SnapshotTestDispatch failed to initialize.\n");
41         ADD_FAILURE() << "SnapshotTestDispatch could not initialize.";
42     }
43 }
44 
overrideFunctions()45 void SnapshotTestDispatch::overrideFunctions() {
46     this->glDrawArrays = (glDrawArrays_t)test_glDrawArrays;
47     this->glDrawElements = (glDrawElements_t)test_glDrawElements;
48 }
49 
saveSnapshot()50 void SnapshotTestDispatch::saveSnapshot() {
51     FrameBuffer* fb = FrameBuffer::getFB();
52     if (!fb) {
53         FAIL() << "Could not get FrameBuffer during snapshot test.";
54     }
55 
56     std::string timeStamp =
57             std::to_string(android::base::getUnixTimeUs()) + "-" +
58             std::to_string(mLoadCount);
59     mSnapshotFile = android::base::pj({mSnapshotPath, std::string("snapshot_") + timeStamp + ".snap"});
60     mTextureFile = android::base::pj({mSnapshotPath, std::string("textures_") + timeStamp + ".stex"});
61     std::unique_ptr<StdioStream> m_stream(new StdioStream(
62             android_fopen(mSnapshotFile.c_str(), "wb"), StdioStream::kOwner));
63     auto a_stream = static_cast<android::base::Stream*>(m_stream.get());
64     std::shared_ptr<TextureSaver> m_texture_saver(new TextureSaver(StdioStream(
65             android_fopen(mTextureFile.c_str(), "wb"), StdioStream::kOwner)));
66 
67     fb->onSave(a_stream, m_texture_saver);
68 
69     // Save thread's context and surface handles so we can restore the bind
70     // after load is complete.
71     RenderThreadInfo* threadInfo = RenderThreadInfo::get();
72     if (threadInfo) {
73         threadInfo->onSave(a_stream);
74     }
75 
76     m_stream->close();
77     m_texture_saver->done();
78 }
79 
loadSnapshot()80 void SnapshotTestDispatch::loadSnapshot() {
81     FrameBuffer* fb = FrameBuffer::getFB();
82     if (!fb) {
83         FAIL() << "Could not get FrameBuffer during snapshot test.";
84     }
85 
86     // unbind so load will destroy previous objects
87     fb->bindContext(0, 0, 0);
88 
89     std::unique_ptr<StdioStream> m_stream(new StdioStream(
90             android_fopen(mSnapshotFile.c_str(), "rb"), StdioStream::kOwner));
91     std::shared_ptr<TextureLoader> m_texture_loader(
92             new TextureLoader(StdioStream(android_fopen(mTextureFile.c_str(), "rb"),
93                                           StdioStream::kOwner)));
94 
95     fb->onLoad(m_stream.get(), m_texture_loader);
96 
97     RenderThreadInfo* threadInfo = RenderThreadInfo::get();
98     if (threadInfo) {
99         threadInfo->onLoad(m_stream.get());
100         // rebind to context
101         fb->bindContext(
102                 threadInfo->m_glInfo->currContext ? threadInfo->m_glInfo->currContext->getHndl()
103                                         : 0,
104                 threadInfo->m_glInfo->currDrawSurf ? threadInfo->m_glInfo->currDrawSurf->getHndl()
105                                          : 0,
106                 threadInfo->m_glInfo->currReadSurf ? threadInfo->m_glInfo->currReadSurf->getHndl()
107                                          : 0);
108     }
109 
110     m_stream->close();
111     m_texture_loader->join();
112 
113     mLoadCount++;
114 }
115 
116 // static
testDraw(std::function<void ()> doDraw)117 void SnapshotTestDispatch::testDraw(std::function<void()> doDraw) {
118     const GLESv2Dispatch* gl = LazyLoadedGLESv2Dispatch::get();
119     ASSERT_NE(nullptr, gl);
120 
121     FrameBuffer* fb = FrameBuffer::getFB();
122     if (!fb) {
123         ADD_FAILURE() << "No framebuffer, test cannot snapshot.";
124         doDraw();
125         return;
126     }
127 
128     // save then draw
129     ((SnapshotTestDispatch*)getSnapshotTestDispatch())->saveSnapshot();
130     // Since current framebuffer contents are not saved, we need to draw
131     // onto a clean slate in order to check the result of the draw call
132     gl->glClear(GL_COLOR_BUFFER_BIT);
133     doDraw();
134 
135     // save the framebuffer contents
136     GLuint width, height, bytesPerPixel;
137     width = fb->getWidth();
138     height = fb->getHeight();
139     bytesPerPixel = glUtilsPixelBitSize(GL_RGBA, GL_UNSIGNED_BYTE) / 8;
140     std::vector<GLubyte> prePixels = {};
141     prePixels.resize(width * height * bytesPerPixel);
142     gl->glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE,
143                      prePixels.data());
144 
145     // To verify that the snapshot is restoring our context, we modify the
146     // clear color.
147     std::vector<GLfloat> oldClear = {};
148     oldClear.resize(4);
149     gl->glGetFloatv(GL_COLOR_CLEAR_VALUE, oldClear.data());
150     EXPECT_TRUE(compareGlobalGlFloatv(gl, GL_COLOR_CLEAR_VALUE, oldClear));
151     gl->glClearColor(1, 1, 1, 1);
152     gl->glClear(GL_COLOR_BUFFER_BIT);
153     EXPECT_TRUE(compareGlobalGlFloatv(gl, GL_COLOR_CLEAR_VALUE, {1, 1, 1, 1}));
154 
155     // load and redraw
156     ((SnapshotTestDispatch*)getSnapshotTestDispatch())->loadSnapshot();
157     gl->glClear(GL_COLOR_BUFFER_BIT);
158     doDraw();
159 
160     // check that clear is restored
161     EXPECT_TRUE(compareGlobalGlFloatv(gl, GL_COLOR_CLEAR_VALUE, oldClear));
162 
163     // compare the framebuffer contents
164     std::vector<GLubyte> postPixels = {};
165     postPixels.resize(width * height * bytesPerPixel);
166     gl->glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE,
167                      postPixels.data());
168 
169     EXPECT_TRUE(ImageMatches(width, height, bytesPerPixel, width,
170                              prePixels.data(), postPixels.data()));
171 }
172 
173 }  // namespace gl
174 }  // namespace gfxstream
175