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