1 // Copyright (C) 2023 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 <log/log.h>
16 
17 #include "GfxstreamEnd2EndTests.h"
18 
19 namespace gfxstream {
20 namespace tests {
21 namespace {
22 
23 using testing::Eq;
24 using testing::Gt;
25 using testing::HasSubstr;
26 using testing::IsEmpty;
27 using testing::IsTrue;
28 using testing::Le;
29 using testing::Not;
30 
31 MATCHER_P(IsOkWith, expected, std::string(" equals ") + expected.ToString()) {
32     const auto& actual = arg;
33 
34     if (actual.ok() && actual.value().r == expected.r && actual.value().g == expected.g &&
35         actual.value().b == expected.b && actual.value().a == expected.a) {
36         return true;
37     }
38 
39     if (actual.ok()) {
40         *result_listener << "actual: " << actual.value().ToString();
41     } else {
42         *result_listener << "actual: {" << " error: " << actual.error() << " };";
43     }
44     return false;
45 }
46 
47 MATCHER_P4(IsOkWithRGBA, r, g, b, a,
48            std::string(" equals ") + PixelR8G8B8A8(r, g, b, a).ToString()) {
49     const auto& actual = arg;
50 
51     if (actual.ok() && actual.value().r == r && actual.value().g == g && actual.value().b == b &&
52         actual.value().a == a) {
53         return true;
54     }
55 
56     if (actual.ok()) {
57         *result_listener << "actual: " << actual.value().ToString();
58     } else {
59         *result_listener << "actual: {" << " error: " << actual.error() << " };";
60     }
61     return false;
62 }
63 
64 class SimpleLatch {
65    public:
SimpleLatch(std::uint32_t count)66     SimpleLatch(std::uint32_t count) : mCount(count) {}
67 
68     SimpleLatch(const SimpleLatch&) = delete;
69     SimpleLatch& operator=(const SimpleLatch&) = delete;
70 
71     SimpleLatch(SimpleLatch&&) = delete;
72     SimpleLatch& operator=(SimpleLatch&&) = delete;
73 
count_down()74     void count_down() {
75         {
76             std::unique_lock lock(mMutex);
77             --mCount;
78         }
79         mConditionVariable.notify_all();
80     }
81 
wait()82     void wait() {
83         std::unique_lock lock(mMutex);
84         mConditionVariable.wait(lock, [this] { return mCount == 0; });
85     }
86 
87    private:
88     std::mutex mMutex;
89     std::condition_variable mConditionVariable;
90     std::uint32_t mCount;
91 };
92 
93 class GfxstreamEnd2EndGlTest : public GfxstreamEnd2EndTest {
94    protected:
GetPixelAt(GLint x,GLint y)95     Result<PixelR8G8B8A8> GetPixelAt(GLint x, GLint y) {
96         if (!mGl) {
97             return gfxstream::unexpected("GL not available, running with `with_gl = false`?");
98         }
99 
100         GLubyte rgba[4] = {0, 0, 0, 0};
101         mGl->glReadPixels(x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, rgba);
102 
103         if (GLenum error = mGl->glGetError(); error != GL_NO_ERROR) {
104             return gfxstream::unexpected("Failed to glReadPixels() with error " +
105                                              std::to_string(error));
106         }
107 
108         return PixelR8G8B8A8(x, y, rgba[0], rgba[1], rgba[2], rgba[3]);
109     }
110 
SetUp()111     void SetUp() override {
112         GfxstreamEnd2EndTest::SetUp();
113 
114         SetUpEglContextAndSurface(2, mSurfaceWidth, mSurfaceHeight, &mDisplay, &mContext,
115                                   &mSurface);
116     }
117 
TearDown()118     void TearDown() override {
119         TearDownEglContextAndSurface(mDisplay, mContext, mSurface);
120 
121         GfxstreamEnd2EndTest::TearDown();
122     }
123 
124     int mSurfaceWidth = 32;
125     int mSurfaceHeight = 32;
126     EGLDisplay mDisplay;
127     EGLContext mContext;
128     EGLSurface mSurface;
129 };
130 
TEST_P(GfxstreamEnd2EndGlTest,BasicViewport)131 TEST_P(GfxstreamEnd2EndGlTest, BasicViewport) {
132     GLint viewport[4] = {};
133     mGl->glGetIntegerv(GL_VIEWPORT, viewport);
134 
135     EXPECT_THAT(viewport[0], Eq(0));
136     EXPECT_THAT(viewport[1], Eq(0));
137     EXPECT_THAT(viewport[2], Eq(mSurfaceWidth));
138     EXPECT_THAT(viewport[3], Eq(mSurfaceHeight));
139 }
140 
TEST_P(GfxstreamEnd2EndGlTest,CreateWindowSurface)141 TEST_P(GfxstreamEnd2EndGlTest, CreateWindowSurface) {
142     // clang-format off
143     static const EGLint configAttributes[] = {
144         EGL_SURFACE_TYPE,    EGL_PBUFFER_BIT,
145         EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
146         EGL_NONE,
147     };
148     // clang-format on
149 
150     int numConfigs = 0;
151     ASSERT_THAT(mGl->eglChooseConfig(mDisplay, configAttributes, nullptr, 1, &numConfigs),
152                 IsTrue());
153     ASSERT_THAT(numConfigs, Gt(0));
154 
155     EGLConfig config = nullptr;
156     ASSERT_THAT(mGl->eglChooseConfig(mDisplay, configAttributes, &config, 1, &numConfigs),
157                 IsTrue());
158     ASSERT_THAT(config, Not(Eq(nullptr)));
159 
160     // clang-format off
161     static const EGLint contextAttribs[] = {
162         EGL_CONTEXT_CLIENT_VERSION, 3,
163         EGL_NONE,
164     };
165     // clang-format on
166 
167     EGLContext context = mGl->eglCreateContext(mDisplay, config, EGL_NO_CONTEXT, contextAttribs);
168     ASSERT_THAT(context, Not(Eq(EGL_NO_CONTEXT)));
169 
170     constexpr const int width = 32;
171     constexpr const int height = 32;
172 
173     auto anw = mAnwHelper->createNativeWindowForTesting(mGralloc.get(), width, height);
174 
175     EGLSurface surface = mGl->eglCreateWindowSurface(mDisplay, config, anw, nullptr);
176     ASSERT_THAT(surface, Not(Eq(EGL_NO_SURFACE)));
177 
178     ASSERT_THAT(mGl->eglMakeCurrent(mDisplay, surface, surface, context), IsTrue());
179 
180     constexpr const int iterations = 120;
181     for (int i = 0; i < iterations; i++) {
182         mGl->glViewport(0, 0, width, height);
183         mGl->glClearColor(1.0f, 0.0f, static_cast<float>(i) / static_cast<float>(iterations), 1.0f);
184         mGl->glClear(GL_COLOR_BUFFER_BIT);
185         mGl->glFinish();
186         mGl->eglSwapBuffers(mDisplay, surface);
187     }
188 
189     ASSERT_THAT(mGl->eglDestroyContext(mDisplay, context), IsTrue());
190     ASSERT_THAT(mGl->eglDestroySurface(mDisplay, surface), IsTrue());
191 
192     mAnwHelper->release(anw);
193 }
194 
TEST_P(GfxstreamEnd2EndGlTest,SwitchContext)195 TEST_P(GfxstreamEnd2EndGlTest, SwitchContext) {
196     ASSERT_THAT(mGl->eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT),
197                 IsTrue());
198     for (int i = 0; i < 100; i++) {
199         ASSERT_THAT(mGl->eglMakeCurrent(mDisplay, mSurface, mSurface, mContext), IsTrue());
200         ASSERT_THAT(mGl->eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT),
201                     IsTrue());
202     }
203 }
204 
TEST_P(GfxstreamEnd2EndGlTest,MappedMemory)205 TEST_P(GfxstreamEnd2EndGlTest, MappedMemory) {
206     constexpr GLsizei kBufferSize = 64;
207 
208     ScopedGlBuffer buffer(*mGl);
209     mGl->glBindBuffer(GL_ARRAY_BUFFER, buffer);
210     mGl->glBufferData(GL_ARRAY_BUFFER, kBufferSize, 0, GL_DYNAMIC_DRAW);
211 
212     std::vector<uint8_t> bufferData(kBufferSize);
213     for (uint8_t i = 0; i < kBufferSize; ++i) {
214         bufferData[i] = i;
215     }
216 
217     {
218         auto* mappedBufferData = reinterpret_cast<uint8_t*>(
219             mGl->glMapBufferRange(GL_ARRAY_BUFFER, 0, kBufferSize,
220                                   GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT));
221 
222         for (uint8_t i = 0; i < kBufferSize; ++i) {
223             mappedBufferData[i] = bufferData[i];
224         }
225 
226         mGl->glFlushMappedBufferRange(GL_ARRAY_BUFFER, 0, kBufferSize);
227         mGl->glUnmapBuffer(GL_ARRAY_BUFFER);
228     }
229 
230     {
231         auto* mappedBufferData = reinterpret_cast<uint8_t*>(
232             mGl->glMapBufferRange(GL_ARRAY_BUFFER, 0, kBufferSize, GL_MAP_READ_BIT));
233 
234         for (uint8_t i = 0; i < kBufferSize; ++i) {
235             EXPECT_THAT(mappedBufferData[i], Eq(bufferData[i]));
236         }
237 
238         mGl->glUnmapBuffer(GL_ARRAY_BUFFER);
239     }
240 
241     mGl->glBindBuffer(GL_ARRAY_BUFFER, 0);
242 }
243 
TEST_P(GfxstreamEnd2EndGlTest,ContextStrings)244 TEST_P(GfxstreamEnd2EndGlTest, ContextStrings) {
245     EGLDisplay display = mGl->eglGetDisplay(EGL_DEFAULT_DISPLAY);
246     ASSERT_THAT(display, Not(Eq(EGL_NO_DISPLAY)));
247 
248     int versionMajor = 0;
249     int versionMinor = 0;
250     ASSERT_THAT(mGl->eglInitialize(display, &versionMajor, &versionMinor), IsTrue());
251 
252     ASSERT_THAT(mGl->eglBindAPI(EGL_OPENGL_ES_API), IsTrue());
253 
254     // clang-format off
255     static const EGLint configAttributes[] = {
256         EGL_SURFACE_TYPE,    EGL_PBUFFER_BIT,
257         EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT,
258         EGL_NONE,
259     };
260     // clang-format on
261 
262     int numConfigs = 0;
263     ASSERT_THAT(mGl->eglChooseConfig(display, configAttributes, nullptr, 1, &numConfigs), IsTrue());
264     ASSERT_THAT(numConfigs, Gt(0));
265 
266     EGLConfig config = nullptr;
267     ASSERT_THAT(mGl->eglChooseConfig(display, configAttributes, &config, 1, &numConfigs), IsTrue());
268     ASSERT_THAT(config, Not(Eq(nullptr)));
269 
270     // clang-format off
271     static const EGLint gles1ContextAttribs[] = {
272         EGL_CONTEXT_CLIENT_VERSION, 1,
273         EGL_NONE,
274     };
275     // clang-format on
276 
277     EGLContext gles1Context = mGl->eglCreateContext(display, config, EGL_NO_CONTEXT, gles1ContextAttribs);
278     ASSERT_THAT(gles1Context, Not(Eq(EGL_NO_CONTEXT)));
279 
280     // clang-format off
281     static const EGLint gles2ContextAttribs[] = {
282         EGL_CONTEXT_CLIENT_VERSION, 2,
283         EGL_NONE,
284     };
285     // clang-format on
286 
287     EGLContext gles2Context = mGl->eglCreateContext(display, config, EGL_NO_CONTEXT, gles2ContextAttribs);
288     ASSERT_THAT(gles2Context, Not(Eq(EGL_NO_CONTEXT)));
289 
290     constexpr const int width = 32;
291     constexpr const int height = 32;
292 
293     // clang-format off
294     static const EGLint surfaceAttributes[] = {
295         EGL_WIDTH,  width,
296         EGL_HEIGHT, height,
297         EGL_NONE,
298     };
299     // clang-format on
300 
301     EGLSurface surface = mGl->eglCreatePbufferSurface(display, config, surfaceAttributes);
302     ASSERT_THAT(surface, Not(Eq(EGL_NO_SURFACE)));
303 
304     {
305         ASSERT_THAT(mGl->eglMakeCurrent(display, surface, surface, gles2Context), IsTrue());
306         const auto versionString = (const char*)mGl->glGetString(GL_VERSION);
307         const auto extensionString = (const char*)mGl->glGetString(GL_EXTENSIONS);
308         EXPECT_THAT(versionString, HasSubstr("ES 3"));
309         EXPECT_THAT(extensionString, Not(HasSubstr("OES_draw_texture")));
310     }
311     {
312         ASSERT_THAT(mGl->eglMakeCurrent(display, surface, surface, gles1Context), IsTrue());
313         const auto versionString = (const char*)mGl->glGetString(GL_VERSION);
314         const auto extensionString = (const char*)mGl->glGetString(GL_EXTENSIONS);
315         EXPECT_THAT(versionString, HasSubstr("ES-CM"));
316         EXPECT_THAT(extensionString, HasSubstr("OES_draw_texture"));
317     }
318     {
319         ASSERT_THAT(mGl->eglMakeCurrent(display, surface, surface, gles2Context), IsTrue());
320         const auto versionString = (const char*)mGl->glGetString(GL_VERSION);
321         const auto extensionString = (const char*)mGl->glGetString(GL_EXTENSIONS);
322         EXPECT_THAT(versionString, HasSubstr("ES 3"));
323         EXPECT_THAT(extensionString, Not(HasSubstr("OES_draw_texture")));
324     }
325 
326     ASSERT_THAT(mGl->eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT), IsTrue());
327     ASSERT_THAT(mGl->eglDestroyContext(display, gles1Context), IsTrue());
328     ASSERT_THAT(mGl->eglDestroyContext(display, gles2Context), IsTrue());
329     ASSERT_THAT(mGl->eglDestroySurface(display, surface), IsTrue());
330 }
331 
TEST_P(GfxstreamEnd2EndGlTest,FramebufferFetchShader)332 TEST_P(GfxstreamEnd2EndGlTest, FramebufferFetchShader) {
333     const std::string extensionsString = (const char*)mGl->glGetString(GL_EXTENSIONS);
334     ASSERT_THAT(extensionsString, Not(IsEmpty()));
335 
336     const bool supportsFramebufferFetch =
337         extensionsString.find("GL_EXT_shader_framebuffer_fetch") != std::string::npos;
338 
339     const std::string shaderSource = R"(\
340 #version 300 es
341 #extension GL_EXT_shader_framebuffer_fetch : require
342 precision highp float;
343 in vec3 color_varying;
344 out vec4 fragColor;
345 void main() {
346     fragColor = vec4(color_varying, 1.0);
347 }
348     )";
349     auto result = SetUpShader(GL_FRAGMENT_SHADER, shaderSource);
350     if (result.ok()) {
351         ASSERT_THAT(supportsFramebufferFetch, Eq(GL_TRUE));
352     } else {
353         ASSERT_THAT(supportsFramebufferFetch, Eq(GL_FALSE));
354     }
355 }
356 
TEST_P(GfxstreamEnd2EndGlTest,ConstantMatrixShader)357 TEST_P(GfxstreamEnd2EndGlTest, ConstantMatrixShader) {
358     const std::string shaderSource = R"(\
359 #version 300 es
360 precision mediump float;
361 in highp vec4 dEQP_Position;
362 out vec2 out0;
363 
364 void main() {
365     const mat4x2 matA = mat4x2( 2.0,  4.0,   8.0,  16.0,
366                                32.0, 64.0, 128.0, 256.0);
367     const mat4x2 matB = mat4x2(1.0 /  2.0, 1.0 /  4.0, 1.0 /   8.0, 1.0 /  16.0,
368                                1.0 / 32.0, 1.0 / 64.0, 1.0 / 128.0, 1.0 / 256.0);
369     mat4x2 result = matrixCompMult(matA, matB);
370 
371     out0 = result * vec4(1.0, 1.0, 1.0, 1.0);
372     gl_Position = dEQP_Position;
373 }
374     )";
375 
376     auto result = SetUpShader(GL_VERTEX_SHADER, shaderSource);
377     ASSERT_THAT(result, IsOk());
378 }
379 
TEST_P(GfxstreamEnd2EndGlTest,Draw)380 TEST_P(GfxstreamEnd2EndGlTest, Draw) {
381     const std::string vertSource = R"(\
382 #version 300 es
383 precision highp float;
384 
385 layout (location = 0) in vec2 pos;
386 layout (location = 1) in vec3 color;
387 
388 uniform mat4 transform;
389 
390 out vec3 color_varying;
391 
392 void main() {
393     gl_Position = transform * vec4(pos, 0.0, 1.0);
394     color_varying = (transform * vec4(color, 1.0)).xyz;
395 }
396     )";
397 
398     const std::string fragSource = R"(\
399 #version 300 es
400 precision highp float;
401 
402 in vec3 color_varying;
403 
404 out vec4 fragColor;
405 
406 void main() {
407     fragColor = vec4(color_varying, 1.0);
408 }
409     )";
410 
411     ScopedGlProgram program = GFXSTREAM_ASSERT(SetUpProgram(vertSource, fragSource));
412 
413     GLint transformUniformLocation = mGl->glGetUniformLocation(program, "transform");
414     mGl->glEnableVertexAttribArray(0);
415     mGl->glEnableVertexAttribArray(1);
416 
417     struct VertexAttributes {
418         float position[2];
419         float color[3];
420     };
421     const VertexAttributes vertexAttrs[] = {
422         // clang-format off
423         { { -0.5f, -0.5f,}, { 0.2, 0.1, 0.9, }, },
424         { {  0.5f, -0.5f,}, { 0.8, 0.3, 0.1, }, },
425         { {  0.0f,  0.5f,}, { 0.1, 0.9, 0.6, }, },
426         // clang-format on
427     };
428 
429     ScopedGlBuffer buffer(*mGl);
430     mGl->glBindBuffer(GL_ARRAY_BUFFER, buffer);
431     mGl->glBufferData(GL_ARRAY_BUFFER, sizeof(vertexAttrs), vertexAttrs, GL_STATIC_DRAW);
432 
433     mGl->glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(VertexAttributes), 0);
434     mGl->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(VertexAttributes), (GLvoid*)offsetof(VertexAttributes, color));
435 
436     mGl->glUseProgram(program);
437 
438     mGl->glViewport(0, 0, 1, 1);
439 
440     mGl->glClearColor(0.2f, 0.2f, 0.3f, 0.0f);
441     mGl->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
442 
443     const float matrix[16] = {
444         // clang-format off
445         1.0f, 0.0f, 0.0f, 0.0f,
446         0.0f, 1.0f, 0.0f, 0.0f,
447         0.0f, 0.0f, 1.0f, 0.0f,
448         0.0f, 0.0f, 0.0f, 1.0f,
449         // clang-format on
450     };
451 
452     constexpr uint32_t kDrawIterations = 200;
453     for (uint32_t i = 0; i < kDrawIterations; i++) {
454         mGl->glUniformMatrix4fv(transformUniformLocation, 1, GL_FALSE, matrix);
455         mGl->glBindBuffer(GL_ARRAY_BUFFER, buffer);
456         mGl->glDrawArrays(GL_TRIANGLES, 0, 3);
457     }
458 
459     mGl->glFinish();
460     mGl->glBindBuffer(GL_ARRAY_BUFFER, 0);
461     mGl->glUseProgram(0);
462 }
463 
TEST_P(GfxstreamEnd2EndGlTest,ProgramBinaryWithAHB)464 TEST_P(GfxstreamEnd2EndGlTest, ProgramBinaryWithAHB) {
465     const uint32_t width = 2;
466     const uint32_t height = 2;
467     auto ahb = GFXSTREAM_ASSERT(ScopedAHardwareBuffer::Allocate(
468         *mGralloc, width, height, GFXSTREAM_AHB_FORMAT_R8G8B8A8_UNORM));
469 
470     GFXSTREAM_ASSERT(FillAhb(ahb, PixelR8G8B8A8(0, 0, 128, 255)));
471 
472     const EGLint ahbImageAttribs[] = {
473         // clang-format off
474         EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
475         EGL_NONE,
476         // clang-format on
477     };
478     EGLImageKHR ahbImage = mGl->eglCreateImageKHR(mDisplay, EGL_NO_CONTEXT,
479                                                   EGL_NATIVE_BUFFER_ANDROID, ahb, ahbImageAttribs);
480     ASSERT_THAT(ahbImage, Not(Eq(EGL_NO_IMAGE_KHR)));
481 
482     ScopedGlTexture ahbTexture(*mGl);
483     mGl->glBindTexture(GL_TEXTURE_EXTERNAL_OES, ahbTexture);
484     mGl->glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
485     mGl->glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
486     mGl->glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, ahbImage);
487     ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
488 
489     GLenum programBinaryFormat = GL_NONE;
490     std::vector<uint8_t> programBinaryData;
491     {
492         const std::string vertSource = R"(\
493             #version 300 es
494 
495             layout (location = 0) in vec2 pos;
496             layout (location = 1) in vec2 tex;
497 
498             out vec2 vTex;
499 
500             void main() {
501                 gl_Position = vec4(pos, 0.0, 1.0);
502                 vTex = tex;
503             })";
504 
505         const std::string fragSource = R"(\
506             #version 300 es
507 
508             precision highp float;
509 
510             uniform float uMultiplier;
511             uniform sampler2D uTexture;
512 
513             in vec2 vTex;
514 
515             out vec4 oColor;
516 
517             void main() {
518                 oColor = texture(uTexture, vTex) * uMultiplier;
519             })";
520 
521         ScopedGlProgram program = GFXSTREAM_ASSERT(SetUpProgram(vertSource, fragSource));
522 
523         GLint programBinaryLength = 0;
524         mGl->glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH, &programBinaryLength);
525         ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
526 
527         programBinaryData.resize(programBinaryLength);
528 
529         GLint readProgramBinaryLength = 0;
530         mGl->glGetProgramBinary(program, programBinaryLength, &readProgramBinaryLength,
531                                 &programBinaryFormat, programBinaryData.data());
532         ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
533         ASSERT_THAT(programBinaryLength, Eq(readProgramBinaryLength));
534     }
535 
536     ScopedGlProgram program =
537         GFXSTREAM_ASSERT(SetUpProgram(programBinaryFormat, programBinaryData));
538     ASSERT_THAT(program, Not(Eq(0)));
539 
540     GLint textureUniformLoc = mGl->glGetUniformLocation(program, "uTexture");
541     ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
542     ASSERT_THAT(textureUniformLoc, Not(Eq(-1)));
543 
544     GLint multiplierUniformLoc = mGl->glGetUniformLocation(program, "uMultiplier");
545     ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
546     ASSERT_THAT(multiplierUniformLoc, Not(Eq(-1)));
547 
548     const GLsizei kFramebufferWidth = 4;
549     const GLsizei kFramebufferHeight = 4;
550     ScopedGlFramebuffer framebuffer(*mGl);
551     mGl->glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
552     ScopedGlTexture framebufferTexture(*mGl);
553     mGl->glBindTexture(GL_TEXTURE_2D, framebufferTexture);
554     mGl->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kFramebufferWidth, kFramebufferHeight, 0, GL_RGBA,
555                       GL_UNSIGNED_BYTE, nullptr);
556     mGl->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
557                                 framebufferTexture, 0);
558     ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
559     ASSERT_THAT(mGl->glCheckFramebufferStatus(GL_FRAMEBUFFER), Eq(GL_FRAMEBUFFER_COMPLETE));
560     mGl->glBindTexture(GL_TEXTURE_2D, 0);
561     ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
562 
563     struct VertexAttributes {
564         float pos[2];
565         float tex[2];
566     };
567     const VertexAttributes vertexAttrs[] = {
568         // clang-format off
569         { { -1.0f, -1.0f,}, { 0.0f, 0.0f }, },
570         { {  3.0f, -1.0f,}, { 2.0f, 0.0f }, },
571         { { -1.0f,  3.0f,}, { 0.0f, 2.0f }, },
572         // clang-format on
573     };
574     ScopedGlBuffer buffer(*mGl);
575     mGl->glBindBuffer(GL_ARRAY_BUFFER, buffer);
576     mGl->glBufferData(GL_ARRAY_BUFFER, sizeof(vertexAttrs), vertexAttrs, GL_STATIC_DRAW);
577 
578     mGl->glUseProgram(program);
579     ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
580 
581     mGl->glBindBuffer(GL_ARRAY_BUFFER, buffer);
582     mGl->glEnableVertexAttribArray(0);
583     mGl->glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(VertexAttributes),
584                                (GLvoid*)offsetof(VertexAttributes, pos));
585     mGl->glEnableVertexAttribArray(1);
586     mGl->glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(VertexAttributes),
587                                (GLvoid*)offsetof(VertexAttributes, tex));
588     ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
589 
590     mGl->glActiveTexture(GL_TEXTURE0);
591     mGl->glBindTexture(GL_TEXTURE_2D, ahbTexture);
592     mGl->glUniform1i(textureUniformLoc, 0);
593     ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
594 
595     mGl->glUniform1f(multiplierUniformLoc, 2.0f);
596     ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
597 
598     mGl->glDrawArrays(GL_TRIANGLES, 0, 3);
599     ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
600 
601     for (int x = 0; x < kFramebufferWidth; x++) {
602         for (int y = 0; y < kFramebufferHeight; y++) {
603             EXPECT_THAT(GetPixelAt(x, y), IsOkWithRGBA(0, 0, 255, 255));
604         }
605     }
606 
607     mGl->glBindFramebuffer(GL_FRAMEBUFFER, 0);
608 }
609 
TEST_P(GfxstreamEnd2EndGlTest,ProgramBinaryWithTexture)610 TEST_P(GfxstreamEnd2EndGlTest, ProgramBinaryWithTexture) {
611     const GLsizei kTextureWidth = 2;
612     const GLsizei kTextureHeight = 2;
613     const GLubyte kTextureData[16] = {
614         // clang-format off
615         0, 0, 128, 255,   0, 0, 128, 255,
616 
617         0, 0, 128, 255,   0, 0, 128, 255,
618         // clang-format on
619     };
620     ScopedGlTexture texture(*mGl);
621     mGl->glBindTexture(GL_TEXTURE_2D, texture);
622     mGl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
623     mGl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
624     mGl->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kTextureWidth, kTextureHeight, 0, GL_RGBA,
625                       GL_UNSIGNED_BYTE, kTextureData);
626     ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
627 
628     GLenum programBinaryFormat = GL_NONE;
629     std::vector<uint8_t> programBinaryData;
630     {
631         const std::string vertSource = R"(\
632             #version 300 es
633 
634             layout (location = 0) in vec2 pos;
635             layout (location = 1) in vec2 tex;
636 
637             out vec2 vTex;
638 
639             void main() {
640                 gl_Position = vec4(pos, 0.0, 1.0);
641                 vTex = tex;
642             })";
643 
644         const std::string fragSource = R"(\
645             #version 300 es
646 
647             precision highp float;
648 
649             uniform float uMultiplier;
650             uniform sampler2D uTexture;
651 
652             in vec2 vTex;
653 
654             out vec4 oColor;
655 
656             void main() {
657                 oColor = texture(uTexture, vTex) * uMultiplier;
658             })";
659 
660         ScopedGlProgram program = GFXSTREAM_ASSERT(SetUpProgram(vertSource, fragSource));
661 
662         GLint programBinaryLength = 0;
663         mGl->glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH, &programBinaryLength);
664         ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
665 
666         programBinaryData.resize(programBinaryLength);
667 
668         GLint readProgramBinaryLength = 0;
669         mGl->glGetProgramBinary(program, programBinaryLength, &readProgramBinaryLength,
670                                 &programBinaryFormat, programBinaryData.data());
671         ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
672         ASSERT_THAT(programBinaryLength, Eq(readProgramBinaryLength));
673     }
674 
675     ScopedGlProgram program =
676         GFXSTREAM_ASSERT(SetUpProgram(programBinaryFormat, programBinaryData));
677     ASSERT_THAT(program, Not(Eq(0)));
678 
679     GLint textureUniformLoc = mGl->glGetUniformLocation(program, "uTexture");
680     ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
681     ASSERT_THAT(textureUniformLoc, Not(Eq(-1)));
682 
683     GLint multiplierUniformLoc = mGl->glGetUniformLocation(program, "uMultiplier");
684     ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
685     ASSERT_THAT(multiplierUniformLoc, Not(Eq(-1)));
686 
687     const GLsizei kFramebufferWidth = 4;
688     const GLsizei kFramebufferHeight = 4;
689     ScopedGlFramebuffer framebuffer(*mGl);
690     mGl->glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
691     ScopedGlTexture framebufferTexture(*mGl);
692     mGl->glBindTexture(GL_TEXTURE_2D, framebufferTexture);
693     mGl->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kFramebufferWidth, kFramebufferHeight, 0, GL_RGBA,
694                       GL_UNSIGNED_BYTE, nullptr);
695     mGl->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
696                                 framebufferTexture, 0);
697     ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
698     ASSERT_THAT(mGl->glCheckFramebufferStatus(GL_FRAMEBUFFER), Eq(GL_FRAMEBUFFER_COMPLETE));
699     mGl->glBindTexture(GL_TEXTURE_2D, 0);
700     ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
701 
702     struct VertexAttributes {
703         float pos[2];
704         float tex[2];
705     };
706     const VertexAttributes vertexAttrs[] = {
707         // clang-format off
708         { { -1.0f, -1.0f,}, { 0.0f, 0.0f }, },
709         { {  3.0f, -1.0f,}, { 2.0f, 0.0f }, },
710         { { -1.0f,  3.0f,}, { 0.0f, 2.0f }, },
711         // clang-format on
712     };
713     ScopedGlBuffer buffer(*mGl);
714     mGl->glBindBuffer(GL_ARRAY_BUFFER, buffer);
715     mGl->glBufferData(GL_ARRAY_BUFFER, sizeof(vertexAttrs), vertexAttrs, GL_STATIC_DRAW);
716 
717     mGl->glUseProgram(program);
718     ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
719 
720     mGl->glBindBuffer(GL_ARRAY_BUFFER, buffer);
721     mGl->glEnableVertexAttribArray(0);
722     mGl->glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(VertexAttributes),
723                                (GLvoid*)offsetof(VertexAttributes, pos));
724     mGl->glEnableVertexAttribArray(1);
725     mGl->glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(VertexAttributes),
726                                (GLvoid*)offsetof(VertexAttributes, tex));
727     ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
728 
729     mGl->glActiveTexture(GL_TEXTURE0);
730     mGl->glBindTexture(GL_TEXTURE_2D, texture);
731     mGl->glUniform1i(textureUniformLoc, 0);
732     ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
733 
734     mGl->glUniform1f(multiplierUniformLoc, 2.0f);
735     ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
736 
737     mGl->glDrawArrays(GL_TRIANGLES, 0, 3);
738     ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
739 
740     for (int x = 0; x < kFramebufferWidth; x++) {
741         for (int y = 0; y < kFramebufferHeight; y++) {
742             EXPECT_THAT(GetPixelAt(x, y), IsOkWithRGBA(0, 0, 255, 255));
743         }
744     }
745 
746     mGl->glBindFramebuffer(GL_FRAMEBUFFER, 0);
747 }
748 
TEST_P(GfxstreamEnd2EndGlTest,AhbTextureUploadAndReadback)749 TEST_P(GfxstreamEnd2EndGlTest, AhbTextureUploadAndReadback) {
750     const uint32_t width = 2;
751     const uint32_t height = 2;
752 
753     const auto lockPixel = PixelR8G8B8A8(11, 22, 33, 44);
754 
755     const auto uploadPixel = PixelR8G8B8A8(55, 66, 77, 88);
756     const auto uploadPixels = Fill(width, height, uploadPixel);
757 
758     auto ahb = GFXSTREAM_ASSERT(ScopedAHardwareBuffer::Allocate(
759         *mGralloc, width, height, GFXSTREAM_AHB_FORMAT_R8G8B8A8_UNORM));
760 
761     // Initialize AHB with `lockPixel`
762     GFXSTREAM_ASSERT(FillAhb(ahb, lockPixel));
763 
764     // Update AHB with `uploadPixel` via texture upload:
765     {
766         const EGLint ahbImageAttribs[] = {
767             // clang-format off
768             EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
769             EGL_NONE,
770             // clang-format on
771         };
772         EGLImageKHR ahbImage = mGl->eglCreateImageKHR(
773             mDisplay, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, ahb, ahbImageAttribs);
774         ASSERT_THAT(ahbImage, Not(Eq(EGL_NO_IMAGE_KHR)));
775 
776         ScopedGlTexture ahbTexture(*mGl);
777         mGl->glBindTexture(GL_TEXTURE_2D, ahbTexture);
778         mGl->glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, ahbImage);
779         ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
780 
781         mGl->glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE,
782                              uploadPixels.data());
783         ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
784 
785         EGLSync uploadFence = mGl->eglCreateSyncKHR(mDisplay, EGL_SYNC_FENCE_KHR, nullptr);
786         ASSERT_THAT(mGl->eglGetError(), Eq(EGL_SUCCESS));
787 
788         mGl->glFlush();
789 
790         ahbTexture.Reset();
791 
792         mGl->eglClientWaitSyncKHR(mDisplay, uploadFence, /*flags=*/0,
793                                   /*timeout=2 seconds*/ 2 * 1000 * 1000 * 1000);
794         ASSERT_THAT(mGl->eglGetError(), Eq(EGL_SUCCESS));
795 
796         mGl->eglDestroySyncKHR(mDisplay, uploadFence);
797         ASSERT_THAT(mGl->eglGetError(), Eq(EGL_SUCCESS));
798 
799         mGl->eglDestroyImageKHR(mDisplay, ahbImage);
800         ASSERT_THAT(mGl->eglGetError(), Eq(EGL_SUCCESS));
801     }
802 
803     // Blit from AHB to an additional framebuffer and readback:
804     {
805         const EGLint ahbImageAttribs[] = {
806             // clang-format off
807             EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
808             EGL_NONE,
809             // clang-format on
810         };
811         EGLImageKHR ahbImage = mGl->eglCreateImageKHR(
812             mDisplay, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, ahb, ahbImageAttribs);
813         ASSERT_THAT(ahbImage, Not(Eq(EGL_NO_IMAGE_KHR)));
814 
815         ScopedGlTexture ahbTexture(*mGl);
816         mGl->glBindTexture(GL_TEXTURE_2D, ahbTexture);
817         mGl->glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, ahbImage);
818         ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
819 
820         ScopedGlFramebuffer readbackFramebuffer(*mGl);
821         mGl->glBindFramebuffer(GL_FRAMEBUFFER, readbackFramebuffer);
822         mGl->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, ahbTexture,
823                                     0);
824         ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
825         ASSERT_THAT(mGl->glCheckFramebufferStatus(GL_FRAMEBUFFER), Eq(GL_FRAMEBUFFER_COMPLETE));
826         ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
827 
828         for (int x = 0; x < width; x++) {
829             for (int y = 0; y < height; y++) {
830                 EXPECT_THAT(GetPixelAt(x, y), IsOkWith(uploadPixel));
831             }
832         }
833 
834         mGl->glBindFramebuffer(GL_FRAMEBUFFER, 0);
835     }
836 }
837 
TEST_P(GfxstreamEnd2EndGlTest,AhbTextureUploadAndBlit)838 TEST_P(GfxstreamEnd2EndGlTest, AhbTextureUploadAndBlit) {
839     const uint32_t width = 2;
840     const uint32_t height = 2;
841 
842     ScopedGlTexture blitFramebufferTexture(*mGl);
843     mGl->glBindTexture(GL_TEXTURE_2D, blitFramebufferTexture);
844     mGl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
845     mGl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
846     mGl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
847     mGl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
848     mGl->glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, width, height);
849     mGl->glBindTexture(GL_TEXTURE_2D, 0);
850 
851     ScopedGlFramebuffer blitFramebuffer(*mGl);
852     mGl->glBindFramebuffer(GL_FRAMEBUFFER, blitFramebuffer);
853     mGl->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
854                                 blitFramebufferTexture, 0);
855 
856     ASSERT_THAT(mGl->glCheckFramebufferStatus(GL_FRAMEBUFFER), Eq(GL_FRAMEBUFFER_COMPLETE));
857     ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
858 
859     const auto lockPixel = PixelR8G8B8A8(11, 22, 33, 44);
860 
861     const auto uploadPixel = PixelR8G8B8A8(55, 66, 77, 88);
862     const auto uploadPixels = Fill(width, height, uploadPixel);
863 
864     auto ahb = GFXSTREAM_ASSERT(ScopedAHardwareBuffer::Allocate(
865         *mGralloc, width, height, GFXSTREAM_AHB_FORMAT_R8G8B8A8_UNORM));
866 
867     // Initialize AHB with `lockPixel`
868     GFXSTREAM_ASSERT(FillAhb(ahb, lockPixel));
869 
870     // Update AHB with `uploadPixel` via texture upload:
871     {
872         const EGLint ahbImageAttribs[] = {
873             // clang-format off
874             EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
875             EGL_NONE,
876             // clang-format on
877         };
878         EGLImageKHR ahbImage = mGl->eglCreateImageKHR(
879             mDisplay, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, ahb, ahbImageAttribs);
880         ASSERT_THAT(ahbImage, Not(Eq(EGL_NO_IMAGE_KHR)));
881 
882         ScopedGlTexture ahbTexture(*mGl);
883         mGl->glBindTexture(GL_TEXTURE_2D, ahbTexture);
884         mGl->glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, ahbImage);
885         mGl->glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE,
886                              uploadPixels.data());
887         ASSERT_THAT(mGl->eglGetError(), Eq(EGL_SUCCESS));
888 
889         EGLSync uploadFence = mGl->eglCreateSyncKHR(mDisplay, EGL_SYNC_FENCE_KHR, nullptr);
890 
891         mGl->glFlush();
892 
893         ahbTexture.Reset();
894 
895         mGl->eglClientWaitSyncKHR(mDisplay, uploadFence, /*flags=*/0,
896                                   /*timeout=2 seconds*/ 2 * 1000 * 1000 * 1000);
897         ASSERT_THAT(mGl->eglGetError(), Eq(EGL_SUCCESS));
898 
899         mGl->eglDestroySyncKHR(mDisplay, uploadFence);
900         ASSERT_THAT(mGl->eglGetError(), Eq(EGL_SUCCESS));
901 
902         mGl->eglDestroyImageKHR(mDisplay, ahbImage);
903         ASSERT_THAT(mGl->eglGetError(), Eq(EGL_SUCCESS));
904     }
905 
906     // Blit from AHB to an additional framebuffer and readback:
907     {
908         const std::string blitTextureVertSource = R"(\
909             #version 300 es
910 
911             layout (location = 0) in vec2 pos;
912             layout (location = 1) in vec2 tex;
913 
914             out vec2 vTex;
915 
916             void main() {
917                 gl_Position = vec4(pos, 0.0, 1.0);
918                 vTex = tex;
919             })";
920 
921         const std::string blitTextureFragSource = R"(\
922             #version 300 es
923 
924             precision highp float;
925 
926             uniform sampler2D uTexture;
927 
928             in vec2 vTex;
929 
930             out vec4 oColor;
931 
932             void main() {
933                 oColor = texture(uTexture, vTex);
934             })";
935 
936         ScopedGlProgram program =
937             GFXSTREAM_ASSERT(SetUpProgram(blitTextureVertSource, blitTextureFragSource));
938 
939         GLint textureUniformLoc = mGl->glGetUniformLocation(program, "uTexture");
940         ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
941         ASSERT_THAT(textureUniformLoc, Not(Eq(-1)));
942 
943         struct VertexAttributes {
944             float pos[2];
945             float tex[2];
946         };
947         const std::vector<VertexAttributes> fullscreenTriVerts = {
948             // clang-format off
949             { .pos = { -1.0f, -1.0f }, .tex = { 0.0f, 0.0f }, },
950             { .pos = {  3.0f, -1.0f }, .tex = { 2.0f, 0.0f }, },
951             { .pos = { -1.0f,  3.0f }, .tex = { 0.0f, 2.0f }, },
952             // clang-format on
953         };
954         ScopedGlBuffer buffer(*mGl);
955         mGl->glBindBuffer(GL_ARRAY_BUFFER, buffer);
956         mGl->glBufferData(GL_ARRAY_BUFFER, sizeof(VertexAttributes) * fullscreenTriVerts.size(),
957                           fullscreenTriVerts.data(), GL_STATIC_DRAW);
958 
959         mGl->glUseProgram(program);
960         ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
961         mGl->glViewport(0, 0, width, height);
962         mGl->glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
963         mGl->glClear(GL_COLOR_BUFFER_BIT);
964         mGl->glBindBuffer(GL_ARRAY_BUFFER, buffer);
965         mGl->glEnableVertexAttribArray(0);
966         mGl->glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(VertexAttributes),
967                                    (GLvoid*)offsetof(VertexAttributes, pos));
968         mGl->glEnableVertexAttribArray(1);
969         mGl->glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(VertexAttributes),
970                                    (GLvoid*)offsetof(VertexAttributes, tex));
971         ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
972 
973         const EGLint ahbImageAttribs[] = {
974             // clang-format off
975             EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
976             EGL_NONE,
977             // clang-format on
978         };
979         EGLImageKHR ahbImage = mGl->eglCreateImageKHR(
980             mDisplay, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, ahb, ahbImageAttribs);
981         ASSERT_THAT(ahbImage, Not(Eq(EGL_NO_IMAGE_KHR)));
982 
983         ScopedGlTexture ahbTexture(*mGl);
984         mGl->glBindTexture(GL_TEXTURE_2D, ahbTexture);
985         mGl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
986         mGl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
987         mGl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
988         mGl->glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, ahbImage);
989         ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
990 
991         mGl->glActiveTexture(GL_TEXTURE0);
992         mGl->glBindTexture(GL_TEXTURE_2D, ahbTexture);
993         mGl->glUniform1i(textureUniformLoc, 0);
994         ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
995 
996         mGl->glDrawArrays(GL_TRIANGLES, 0, 3);
997         ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
998 
999         mGl->glFinish();
1000 
1001         for (int x = 0; x < width; x++) {
1002             for (int y = 0; y < height; y++) {
1003                 EXPECT_THAT(GetPixelAt(x, y), IsOkWith(uploadPixel));
1004             }
1005         }
1006 
1007         mGl->glBindFramebuffer(GL_FRAMEBUFFER, 0);
1008     }
1009 }
1010 
TEST_P(GfxstreamEnd2EndGlTest,MultiThreadedAhbTextureUploadAndReadback)1011 TEST_P(GfxstreamEnd2EndGlTest, MultiThreadedAhbTextureUploadAndReadback) {
1012     const uint32_t width = 2;
1013     const uint32_t height = 2;
1014 
1015     const auto lockPixel = PixelR8G8B8A8(11, 22, 33, 44);
1016 
1017     const auto uploadPixel = PixelR8G8B8A8(55, 66, 77, 88);
1018     const auto uploadPixels = Fill(width, height, uploadPixel);
1019 
1020     auto ahb = GFXSTREAM_ASSERT(ScopedAHardwareBuffer::Allocate(
1021         *mGralloc, width, height, GFXSTREAM_AHB_FORMAT_R8G8B8A8_UNORM));
1022 
1023     const EGLint ahbImageAttribs[] = {
1024         // clang-format off
1025         EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
1026         EGL_NONE,
1027         // clang-format on
1028     };
1029     EGLImageKHR ahbImage = mGl->eglCreateImageKHR(mDisplay, EGL_NO_CONTEXT,
1030                                                   EGL_NATIVE_BUFFER_ANDROID, ahb, ahbImageAttribs);
1031     ASSERT_THAT(ahbImage, Not(Eq(EGL_NO_IMAGE_KHR)));
1032 
1033     std::vector<PixelR8G8B8A8> readbackPixels;
1034 
1035     SimpleLatch readbackThreadInitialized{1};
1036     SimpleLatch readbackThreadCanReadback{1};
1037     SimpleLatch readbackThreadDidReadback{1};
1038     SimpleLatch readbackThreadCanCleanup{1};
1039     std::thread readbackThread([&]() {
1040         EGLContext readbackThreadContext;
1041         EGLSurface readbackThreadSurface;
1042         SetUpEglContextAndSurface(2, 32, 32, &mDisplay, &readbackThreadContext,
1043                                   &readbackThreadSurface);
1044         {
1045             // Create a framebuffer for blitting the AHB into and reading back the blitted results
1046             // from:
1047             ScopedGlTexture readbackTexture(*mGl);
1048             mGl->glBindTexture(GL_TEXTURE_2D, readbackTexture);
1049             mGl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1050             mGl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1051             mGl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1052             mGl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1053             mGl->glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, width, height);
1054             mGl->glBindTexture(GL_TEXTURE_2D, 0);
1055             ScopedGlFramebuffer readbackFramebuffer(*mGl);
1056             mGl->glBindFramebuffer(GL_FRAMEBUFFER, readbackFramebuffer);
1057             mGl->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
1058                                         readbackTexture, 0);
1059             ASSERT_THAT(mGl->glCheckFramebufferStatus(GL_FRAMEBUFFER), Eq(GL_FRAMEBUFFER_COMPLETE));
1060             ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
1061 
1062             // Create fullscreen triangle vertex buffer:
1063             struct VertexAttributes {
1064                 float pos[2];
1065                 float tex[2];
1066             };
1067             const std::vector<VertexAttributes> fullscreenTriVerts = {
1068                 // clang-format off
1069                 { .pos = { -1.0f, -1.0f }, .tex = { 0.0f, 0.0f }, },
1070                 { .pos = {  3.0f, -1.0f }, .tex = { 2.0f, 0.0f }, },
1071                 { .pos = { -1.0f,  3.0f }, .tex = { 0.0f, 2.0f }, },
1072                 // clang-format on
1073             };
1074             ScopedGlBuffer buffer(*mGl);
1075             mGl->glBindBuffer(GL_ARRAY_BUFFER, buffer);
1076             mGl->glBufferData(GL_ARRAY_BUFFER, sizeof(VertexAttributes) * fullscreenTriVerts.size(),
1077                               fullscreenTriVerts.data(), GL_STATIC_DRAW);
1078 
1079             const std::string vertSource = R"(\
1080                     #version 300 es
1081                     layout (location = 0) in vec2 pos;
1082                     layout (location = 1) in vec2 tex;
1083                     out vec2 vTex;
1084                     void main() {
1085                         gl_Position = vec4(pos, 0.0, 1.0);
1086                         vTex = tex;
1087                     })";
1088             const std::string fragSource = R"(\
1089                     #version 300 es
1090                     precision highp float;
1091                     uniform sampler2D uTexture;
1092                     in vec2 vTex;
1093                     out vec4 oColor;
1094                     void main() {
1095                         oColor = texture(uTexture, vTex);
1096                     })";
1097             ScopedGlProgram program = GFXSTREAM_ASSERT(SetUpProgram(vertSource, fragSource));
1098             ASSERT_THAT(program, Not(Eq(0)));
1099 
1100             GLint textureUniformLoc = mGl->glGetUniformLocation(program, "uTexture");
1101             ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
1102             ASSERT_THAT(textureUniformLoc, Not(Eq(-1)));
1103 
1104             readbackThreadInitialized.count_down();
1105 
1106             readbackThreadCanReadback.wait();
1107             {
1108                 EGLImageKHR readbackAhbImage = mGl->eglCreateImageKHR(
1109                     mDisplay, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, ahb, ahbImageAttribs);
1110                 ASSERT_THAT(readbackAhbImage, Not(Eq(EGL_NO_IMAGE_KHR)));
1111                 ScopedGlTexture readbackAhbTexture(*mGl);
1112                 mGl->glBindTexture(GL_TEXTURE_2D, readbackAhbTexture);
1113                 mGl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1114                 mGl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1115                 mGl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1116                 mGl->glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, readbackAhbImage);
1117                 ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
1118 
1119                 mGl->glUseProgram(program);
1120                 ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
1121                 mGl->glViewport(0, 0, width, height);
1122                 mGl->glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
1123                 mGl->glClear(GL_COLOR_BUFFER_BIT);
1124                 mGl->glBindBuffer(GL_ARRAY_BUFFER, buffer);
1125                 mGl->glEnableVertexAttribArray(0);
1126                 mGl->glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(VertexAttributes),
1127                                            (GLvoid*)offsetof(VertexAttributes, pos));
1128                 mGl->glEnableVertexAttribArray(1);
1129                 mGl->glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(VertexAttributes),
1130                                            (GLvoid*)offsetof(VertexAttributes, tex));
1131                 ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
1132 
1133                 mGl->glActiveTexture(GL_TEXTURE0);
1134                 mGl->glBindTexture(GL_TEXTURE_2D, readbackAhbTexture);
1135                 mGl->glUniform1i(textureUniformLoc, 0);
1136                 ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
1137                 mGl->glDrawArrays(GL_TRIANGLES, 0, 3);
1138                 ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
1139                 mGl->glFinish();
1140 
1141                 std::vector<uint8_t> readbackBytes(width * height * 4);
1142                 mGl->glPixelStorei(GL_PACK_ALIGNMENT, 1);
1143                 mGl->glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE,
1144                                   readbackBytes.data());
1145 
1146                 const uint8_t* readbackBytesPtr = readbackBytes.data();
1147                 for (uint32_t y = 0; y < height; y++) {
1148                     for (uint32_t x = 0; x < width; x++) {
1149                         PixelR8G8B8A8 readbackPixel;
1150                         readbackPixel.x = x;
1151                         readbackPixel.y = y;
1152                         readbackPixel.r = *readbackBytesPtr;
1153                         ++readbackBytesPtr;
1154                         readbackPixel.g = *readbackBytesPtr;
1155                         ++readbackBytesPtr;
1156                         readbackPixel.b = *readbackBytesPtr;
1157                         ++readbackBytesPtr;
1158                         readbackPixel.a = *readbackBytesPtr;
1159                         ++readbackBytesPtr;
1160                         readbackPixels.push_back(readbackPixel);
1161                     }
1162                 }
1163             }
1164             readbackThreadDidReadback.count_down();
1165         }
1166         readbackThreadCanCleanup.wait();
1167         TearDownEglContextAndSurface(mDisplay, readbackThreadContext, readbackThreadSurface);
1168     });
1169 
1170     EGLSync uploadCompleteFence = EGL_NO_SYNC;
1171 
1172     SimpleLatch uploadThreadInitialized{1};
1173     SimpleLatch uploadThreadStartUpload{1};
1174     SimpleLatch uploadThreadStartedUpload{1};
1175     SimpleLatch uploadThreadCanCleanup{1};
1176     std::thread uploadThread([&]() {
1177         EGLContext uploadThreadContext;
1178         EGLSurface uploadThreadSurface;
1179         SetUpEglContextAndSurface(2, 32, 32, &mDisplay, &uploadThreadContext, &uploadThreadSurface);
1180         uploadThreadInitialized.count_down();
1181 
1182         {
1183             // Update AHB with `uploadPixel` via texture upload:
1184             uploadThreadStartUpload.wait();
1185             {
1186                 ScopedGlTexture uploadTexture(*mGl);
1187                 mGl->glBindTexture(GL_TEXTURE_2D, uploadTexture);
1188                 mGl->glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, ahbImage);
1189                 mGl->glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA,
1190                                      GL_UNSIGNED_BYTE, uploadPixels.data());
1191                 ASSERT_THAT(mGl->eglGetError(), Eq(EGL_SUCCESS));
1192 
1193                 uploadCompleteFence = mGl->eglCreateSyncKHR(mDisplay, EGL_SYNC_FENCE_KHR, nullptr);
1194                 ASSERT_THAT(mGl->eglGetError(), Eq(EGL_SUCCESS));
1195                 ASSERT_THAT(uploadCompleteFence, Not(Eq(EGL_NO_SYNC)));
1196 
1197                 mGl->glFlush();
1198             }
1199             uploadThreadStartedUpload.count_down();
1200         }
1201 
1202         uploadThreadCanCleanup.wait();
1203         TearDownEglContextAndSurface(mDisplay, uploadThreadContext, uploadThreadSurface);
1204     });
1205 
1206     readbackThreadInitialized.wait();
1207     uploadThreadInitialized.wait();
1208 
1209     // "MainThread" updates the AHB with `lockPixel` via Gralloc->Lock():
1210     GFXSTREAM_ASSERT(FillAhb(ahb, lockPixel));
1211 
1212     // "UploadThread" updates the AHB with `uploadPixel` via GL texture upload:
1213     uploadThreadStartUpload.count_down();
1214 
1215     // "MainThread" waits on upload fence:
1216     {
1217         uploadThreadStartedUpload.wait();
1218 
1219         ASSERT_THAT(uploadCompleteFence, Not(Eq(EGL_NO_SYNC)));
1220         mGl->eglClientWaitSyncKHR(mDisplay, uploadCompleteFence, /*flags=*/0,
1221                                   /*timeout=2 seconds*/ 2 * 1000 * 1000 * 1000);
1222         ASSERT_THAT(mGl->eglGetError(), Eq(EGL_SUCCESS));
1223 
1224         mGl->eglDestroySyncKHR(mDisplay, uploadCompleteFence);
1225         ASSERT_THAT(mGl->eglGetError(), Eq(EGL_SUCCESS));
1226 
1227         mGl->eglDestroyImageKHR(mDisplay, ahbImage);
1228     }
1229 
1230     // "ReadbackThread" blits the AHB contents to an internal framebuffer and performs readback:
1231     readbackThreadCanReadback.count_down();
1232 
1233     // Check readback results:
1234     readbackThreadDidReadback.wait();
1235     for (int x = 0; x < width; x++) {
1236         for (int y = 0; y < height; y++) {
1237             EXPECT_THAT(readbackPixels[(y * width) + x], Eq(uploadPixel));
1238         }
1239     }
1240 
1241     readbackThreadCanCleanup.count_down();
1242     readbackThread.join();
1243 
1244     uploadThreadCanCleanup.count_down();
1245     uploadThread.join();
1246 }
1247 
TEST_P(GfxstreamEnd2EndGlTest,AhbTextureUploadAndExternalOesBlit)1248 TEST_P(GfxstreamEnd2EndGlTest, AhbTextureUploadAndExternalOesBlit) {
1249     const uint32_t width = 2;
1250     const uint32_t height = 2;
1251 
1252     ScopedGlTexture readbackTexture(*mGl);
1253     mGl->glBindTexture(GL_TEXTURE_2D, readbackTexture);
1254     mGl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1255     mGl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1256     mGl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1257     mGl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1258     mGl->glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, width, height);
1259     mGl->glBindTexture(GL_TEXTURE_2D, 0);
1260     ScopedGlFramebuffer readbackFramebuffer(*mGl);
1261     mGl->glBindFramebuffer(GL_FRAMEBUFFER, readbackFramebuffer);
1262     mGl->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
1263                                 readbackTexture, 0);
1264     ASSERT_THAT(mGl->glCheckFramebufferStatus(GL_FRAMEBUFFER), Eq(GL_FRAMEBUFFER_COMPLETE));
1265     ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
1266 
1267     const auto lockPixel = PixelR8G8B8A8(11, 22, 33, 44);
1268 
1269     const auto uploadPixel = PixelR8G8B8A8(55, 66, 77, 88);
1270     const auto uploadPixels = Fill(width, height, uploadPixel);
1271 
1272     auto ahb = GFXSTREAM_ASSERT(ScopedAHardwareBuffer::Allocate(
1273         *mGralloc, width, height, GFXSTREAM_AHB_FORMAT_R8G8B8A8_UNORM));
1274 
1275     const EGLint ahbImageAttribs[] = {
1276         // clang-format off
1277         EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
1278         EGL_NONE,
1279         // clang-format on
1280     };
1281 
1282     // Initialize AHB with `lockPixel`
1283     GFXSTREAM_ASSERT(FillAhb(ahb, lockPixel));
1284 
1285     // Update AHB with `uploadPixel` via texture upload:
1286     {
1287         EGLImageKHR uploadAhbImage = mGl->eglCreateImageKHR(
1288             mDisplay, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, ahb, ahbImageAttribs);
1289         ASSERT_THAT(uploadAhbImage, Not(Eq(EGL_NO_IMAGE_KHR)));
1290 
1291         ScopedGlTexture uploadAhbTexture(*mGl);
1292         mGl->glBindTexture(GL_TEXTURE_2D, uploadAhbTexture);
1293         mGl->glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, uploadAhbImage);
1294         mGl->glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE,
1295                              uploadPixels.data());
1296         ASSERT_THAT(mGl->eglGetError(), Eq(EGL_SUCCESS));
1297 
1298         EGLSync uploadFence = mGl->eglCreateSyncKHR(mDisplay, EGL_SYNC_FENCE_KHR, nullptr);
1299 
1300         mGl->glFlush();
1301 
1302         uploadAhbTexture.Reset();
1303 
1304         mGl->eglClientWaitSyncKHR(mDisplay, uploadFence, /*flags=*/0,
1305                                   /*timeout=2 seconds*/ 2 * 1000 * 1000 * 1000);
1306         ASSERT_THAT(mGl->eglGetError(), Eq(EGL_SUCCESS));
1307 
1308         mGl->eglDestroySyncKHR(mDisplay, uploadFence);
1309         ASSERT_THAT(mGl->eglGetError(), Eq(EGL_SUCCESS));
1310 
1311         mGl->eglDestroyImageKHR(mDisplay, uploadAhbImage);
1312         ASSERT_THAT(mGl->eglGetError(), Eq(EGL_SUCCESS));
1313     }
1314 
1315     // Blit from AHB to an additional framebuffer for readback:
1316     {
1317         const std::string blitTextureVertSource = R"(\
1318             #version 300 es
1319             layout (location = 0) in vec2 pos;
1320             layout (location = 1) in vec2 tex;
1321             out vec2 vTex;
1322             void main() {
1323                 gl_Position = vec4(pos, 0.0, 1.0);
1324                 vTex = tex;
1325             })";
1326 
1327         const std::string blitTextureFragSource = R"(\
1328             #version 300 es
1329             #extension GL_OES_EGL_image_external
1330             precision highp float;
1331             uniform samplerExternalOES uTexture;
1332             in vec2 vTex;
1333             out vec4 oColor;
1334             void main() {
1335                 oColor = texture(uTexture, vTex);
1336             })";
1337 
1338         ScopedGlProgram program =
1339             GFXSTREAM_ASSERT(SetUpProgram(blitTextureVertSource, blitTextureFragSource));
1340 
1341         GLint textureUniformLoc = mGl->glGetUniformLocation(program, "uTexture");
1342         ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
1343         ASSERT_THAT(textureUniformLoc, Not(Eq(-1)));
1344 
1345         struct VertexAttributes {
1346             float pos[2];
1347             float tex[2];
1348         };
1349         const std::vector<VertexAttributes> fullscreenTriVerts = {
1350             // clang-format off
1351             { .pos = { -1.0f, -1.0f }, .tex = { 0.0f, 0.0f }, },
1352             { .pos = {  3.0f, -1.0f }, .tex = { 2.0f, 0.0f }, },
1353             { .pos = { -1.0f,  3.0f }, .tex = { 0.0f, 2.0f }, },
1354             // clang-format on
1355         };
1356         ScopedGlBuffer buffer(*mGl);
1357         mGl->glBindBuffer(GL_ARRAY_BUFFER, buffer);
1358         mGl->glBufferData(GL_ARRAY_BUFFER, sizeof(VertexAttributes) * fullscreenTriVerts.size(),
1359                           fullscreenTriVerts.data(), GL_STATIC_DRAW);
1360 
1361         mGl->glUseProgram(program);
1362         ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
1363         mGl->glViewport(0, 0, width, height);
1364         mGl->glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
1365         mGl->glClear(GL_COLOR_BUFFER_BIT);
1366         mGl->glBindBuffer(GL_ARRAY_BUFFER, buffer);
1367         mGl->glEnableVertexAttribArray(0);
1368         mGl->glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(VertexAttributes),
1369                                    (GLvoid*)offsetof(VertexAttributes, pos));
1370         mGl->glEnableVertexAttribArray(1);
1371         mGl->glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(VertexAttributes),
1372                                    (GLvoid*)offsetof(VertexAttributes, tex));
1373         ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
1374 
1375         EGLImageKHR blitAhbImage = mGl->eglCreateImageKHR(
1376             mDisplay, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, ahb, ahbImageAttribs);
1377         ASSERT_THAT(blitAhbImage, Not(Eq(EGL_NO_IMAGE_KHR)));
1378 
1379         ScopedGlTexture blitAhbTexture(*mGl);
1380         mGl->glBindTexture(GL_TEXTURE_EXTERNAL_OES, blitAhbTexture);
1381         mGl->glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, blitAhbImage);
1382         ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
1383 
1384         mGl->glActiveTexture(GL_TEXTURE0);
1385         mGl->glBindTexture(GL_TEXTURE_EXTERNAL_OES, blitAhbTexture);
1386         mGl->glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1387         mGl->glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1388         mGl->glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1389 
1390         mGl->glUniform1i(textureUniformLoc, 0);
1391         ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
1392 
1393         mGl->glDrawArrays(GL_TRIANGLES, 0, 3);
1394         ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
1395 
1396         mGl->glFinish();
1397     }
1398 
1399     // Readback and compare:
1400     {
1401         for (int x = 0; x < width; x++) {
1402             for (int y = 0; y < height; y++) {
1403                 EXPECT_THAT(GetPixelAt(x, y), IsOkWith(uploadPixel));
1404             }
1405         }
1406 
1407         mGl->glBindFramebuffer(GL_FRAMEBUFFER, 0);
1408     }
1409 }
1410 
TEST_P(GfxstreamEnd2EndGlTest,AhbExternalOesTextureBlit)1411 TEST_P(GfxstreamEnd2EndGlTest, AhbExternalOesTextureBlit) {
1412     const uint32_t width = 2;
1413     const uint32_t height = 2;
1414 
1415     ScopedGlTexture readbackTexture(*mGl);
1416     mGl->glBindTexture(GL_TEXTURE_2D, readbackTexture);
1417     mGl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1418     mGl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1419     mGl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1420     mGl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1421     mGl->glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, width, height);
1422     mGl->glBindTexture(GL_TEXTURE_2D, 0);
1423     ScopedGlFramebuffer readbackFramebuffer(*mGl);
1424     mGl->glBindFramebuffer(GL_FRAMEBUFFER, readbackFramebuffer);
1425     mGl->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
1426                                 readbackTexture, 0);
1427     ASSERT_THAT(mGl->glCheckFramebufferStatus(GL_FRAMEBUFFER), Eq(GL_FRAMEBUFFER_COMPLETE));
1428     ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
1429 
1430     const auto lockPixel = PixelR8G8B8A8(11, 22, 33, 44);
1431 
1432     auto ahb = GFXSTREAM_ASSERT(ScopedAHardwareBuffer::Allocate(
1433         *mGralloc, width, height, GFXSTREAM_AHB_FORMAT_R8G8B8A8_UNORM));
1434 
1435     const EGLint ahbImageAttribs[] = {
1436         // clang-format off
1437         EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
1438         EGL_NONE,
1439         // clang-format on
1440     };
1441 
1442     // Initialize AHB with `lockPixel`
1443     GFXSTREAM_ASSERT(FillAhb(ahb, lockPixel));
1444 
1445     // Blit from AHB to an additional framebuffer and readback:
1446     {
1447         const std::string blitTextureVertSource = R"(\
1448             #version 300 es
1449 
1450             layout (location = 0) in vec2 pos;
1451             layout (location = 1) in vec2 tex;
1452 
1453             out vec2 vTex;
1454 
1455             void main() {
1456                 gl_Position = vec4(pos, 0.0, 1.0);
1457                 vTex = tex;
1458             })";
1459 
1460         const std::string blitTextureFragSource = R"(\
1461             #version 300 es
1462             #extension GL_OES_EGL_image_external
1463 
1464             precision highp float;
1465 
1466             uniform samplerExternalOES uTexture;
1467 
1468             in vec2 vTex;
1469 
1470             out vec4 oColor;
1471 
1472             void main() {
1473                 oColor = texture(uTexture, vTex);
1474             })";
1475 
1476         ScopedGlProgram program =
1477             GFXSTREAM_ASSERT(SetUpProgram(blitTextureVertSource, blitTextureFragSource));
1478 
1479         GLint textureUniformLoc = mGl->glGetUniformLocation(program, "uTexture");
1480         ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
1481         ASSERT_THAT(textureUniformLoc, Not(Eq(-1)));
1482 
1483         struct VertexAttributes {
1484             float pos[2];
1485             float tex[2];
1486         };
1487         const std::vector<VertexAttributes> fullscreenTriVerts = {
1488             // clang-format off
1489             { .pos = { -1.0f, -1.0f }, .tex = { 0.0f, 0.0f }, },
1490             { .pos = {  3.0f, -1.0f }, .tex = { 2.0f, 0.0f }, },
1491             { .pos = { -1.0f,  3.0f }, .tex = { 0.0f, 2.0f }, },
1492             // clang-format on
1493         };
1494         ScopedGlBuffer buffer(*mGl);
1495         mGl->glBindBuffer(GL_ARRAY_BUFFER, buffer);
1496         mGl->glBufferData(GL_ARRAY_BUFFER, sizeof(VertexAttributes) * fullscreenTriVerts.size(),
1497                           fullscreenTriVerts.data(), GL_STATIC_DRAW);
1498 
1499         mGl->glUseProgram(program);
1500         ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
1501         mGl->glViewport(0, 0, width, height);
1502         mGl->glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
1503         mGl->glClear(GL_COLOR_BUFFER_BIT);
1504         mGl->glBindBuffer(GL_ARRAY_BUFFER, buffer);
1505         mGl->glEnableVertexAttribArray(0);
1506         mGl->glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(VertexAttributes),
1507                                    (GLvoid*)offsetof(VertexAttributes, pos));
1508         mGl->glEnableVertexAttribArray(1);
1509         mGl->glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(VertexAttributes),
1510                                    (GLvoid*)offsetof(VertexAttributes, tex));
1511         ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
1512 
1513         EGLImageKHR blitAhbImage = mGl->eglCreateImageKHR(
1514             mDisplay, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, ahb, ahbImageAttribs);
1515         ASSERT_THAT(blitAhbImage, Not(Eq(EGL_NO_IMAGE_KHR)));
1516 
1517         ScopedGlTexture blitAhbTexture(*mGl);
1518         mGl->glBindTexture(GL_TEXTURE_EXTERNAL_OES, blitAhbTexture);
1519         mGl->glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, blitAhbImage);
1520         ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
1521 
1522         mGl->glActiveTexture(GL_TEXTURE0);
1523         mGl->glBindTexture(GL_TEXTURE_EXTERNAL_OES, blitAhbTexture);
1524         mGl->glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1525         mGl->glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1526         mGl->glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1527 
1528         mGl->glUniform1i(textureUniformLoc, 0);
1529         ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
1530 
1531         mGl->glDrawArrays(GL_TRIANGLES, 0, 3);
1532         ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
1533 
1534         mGl->glFinish();
1535 
1536         for (int x = 0; x < width; x++) {
1537             for (int y = 0; y < height; y++) {
1538                 EXPECT_THAT(GetPixelAt(x, y), IsOkWith(lockPixel));
1539             }
1540         }
1541 
1542         mGl->glBindFramebuffer(GL_FRAMEBUFFER, 0);
1543     }
1544 }
1545 
TEST_P(GfxstreamEnd2EndGlTest,AhbExternalOesTextureBlitProgramBinary)1546 TEST_P(GfxstreamEnd2EndGlTest, AhbExternalOesTextureBlitProgramBinary) {
1547     if (GetParam().with_features.count("GlProgramBinaryLinkStatus") == 0) {
1548         GTEST_SKIP() << "Skipping test, GlProgramBinaryLinkStatus not enabled.";
1549     }
1550 
1551     const uint32_t width = 2;
1552     const uint32_t height = 2;
1553 
1554     ScopedGlTexture readbackTexture(*mGl);
1555     mGl->glBindTexture(GL_TEXTURE_2D, readbackTexture);
1556     mGl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1557     mGl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1558     mGl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1559     mGl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1560     mGl->glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, width, height);
1561     mGl->glBindTexture(GL_TEXTURE_2D, 0);
1562     ScopedGlFramebuffer readbackFramebuffer(*mGl);
1563     mGl->glBindFramebuffer(GL_FRAMEBUFFER, readbackFramebuffer);
1564     mGl->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
1565                                 readbackTexture, 0);
1566     ASSERT_THAT(mGl->glCheckFramebufferStatus(GL_FRAMEBUFFER), Eq(GL_FRAMEBUFFER_COMPLETE));
1567     ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
1568 
1569     const auto lockPixel = PixelR8G8B8A8(11, 22, 33, 44);
1570 
1571     auto ahb = GFXSTREAM_ASSERT(ScopedAHardwareBuffer::Allocate(
1572         *mGralloc, width, height, GFXSTREAM_AHB_FORMAT_R8G8B8A8_UNORM));
1573 
1574     const EGLint ahbImageAttribs[] = {
1575         // clang-format off
1576         EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
1577         EGL_NONE,
1578         // clang-format on
1579     };
1580 
1581     // Initialize AHB with `lockPixel`
1582     GFXSTREAM_ASSERT(FillAhb(ahb, lockPixel));
1583 
1584     // Setup blit program:
1585     GLenum programBinaryFormat = GL_NONE;
1586     std::vector<uint8_t> programBinaryData;
1587     {
1588         const std::string vertSource = R"(\
1589             #version 300 es
1590             layout (location = 0) in vec2 pos;
1591             layout (location = 1) in vec2 tex;
1592             out vec2 vTex;
1593             void main() {
1594                 gl_Position = vec4(pos, 0.0, 1.0);
1595                 vTex = tex;
1596             })";
1597 
1598         const std::string fragSource = R"(\
1599             #version 300 es
1600             #extension GL_OES_EGL_image_external
1601             precision highp float;
1602             uniform samplerExternalOES uTexture;
1603             in vec2 vTex;
1604             out vec4 oColor;
1605             void main() {
1606                 oColor = texture(uTexture, vTex);
1607             })";
1608 
1609         ScopedGlProgram program = GFXSTREAM_ASSERT(SetUpProgram(vertSource, fragSource));
1610 
1611         GLint programBinaryLength = 0;
1612         mGl->glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH, &programBinaryLength);
1613         ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
1614 
1615         programBinaryData.resize(programBinaryLength);
1616 
1617         GLint readProgramBinaryLength = 0;
1618         mGl->glGetProgramBinary(program, programBinaryLength, &readProgramBinaryLength,
1619                                 &programBinaryFormat, programBinaryData.data());
1620         ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
1621         ASSERT_THAT(readProgramBinaryLength, Eq(programBinaryLength));
1622     }
1623 
1624     // Blit from AHB to an additional framebuffer and readback:
1625     {
1626         ScopedGlProgram program =
1627             GFXSTREAM_ASSERT(SetUpProgram(programBinaryFormat, programBinaryData));
1628         ASSERT_THAT(program, Not(Eq(0)));
1629 
1630         GLint textureUniformLoc = mGl->glGetUniformLocation(program, "uTexture");
1631         ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
1632         ASSERT_THAT(textureUniformLoc, Not(Eq(-1)));
1633 
1634         struct VertexAttributes {
1635             float pos[2];
1636             float tex[2];
1637         };
1638         const std::vector<VertexAttributes> fullscreenTriVerts = {
1639             // clang-format off
1640             { .pos = { -1.0f, -1.0f }, .tex = { 0.0f, 0.0f }, },
1641             { .pos = {  3.0f, -1.0f }, .tex = { 2.0f, 0.0f }, },
1642             { .pos = { -1.0f,  3.0f }, .tex = { 0.0f, 2.0f }, },
1643             // clang-format on
1644         };
1645         ScopedGlBuffer buffer(*mGl);
1646         mGl->glBindBuffer(GL_ARRAY_BUFFER, buffer);
1647         mGl->glBufferData(GL_ARRAY_BUFFER, sizeof(VertexAttributes) * fullscreenTriVerts.size(),
1648                           fullscreenTriVerts.data(), GL_STATIC_DRAW);
1649 
1650         mGl->glUseProgram(program);
1651         ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
1652         mGl->glViewport(0, 0, width, height);
1653         mGl->glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
1654         mGl->glClear(GL_COLOR_BUFFER_BIT);
1655         mGl->glBindBuffer(GL_ARRAY_BUFFER, buffer);
1656         mGl->glEnableVertexAttribArray(0);
1657         mGl->glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(VertexAttributes),
1658                                    (GLvoid*)offsetof(VertexAttributes, pos));
1659         mGl->glEnableVertexAttribArray(1);
1660         mGl->glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(VertexAttributes),
1661                                    (GLvoid*)offsetof(VertexAttributes, tex));
1662         ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
1663 
1664         EGLImageKHR blitAhbImage = mGl->eglCreateImageKHR(
1665             mDisplay, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, ahb, ahbImageAttribs);
1666         ASSERT_THAT(blitAhbImage, Not(Eq(EGL_NO_IMAGE_KHR)));
1667 
1668         ScopedGlTexture blitAhbTexture(*mGl);
1669         mGl->glBindTexture(GL_TEXTURE_EXTERNAL_OES, blitAhbTexture);
1670         mGl->glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, blitAhbImage);
1671         ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
1672 
1673         mGl->glActiveTexture(GL_TEXTURE0);
1674         mGl->glBindTexture(GL_TEXTURE_EXTERNAL_OES, blitAhbTexture);
1675         mGl->glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1676         mGl->glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1677         mGl->glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1678 
1679         mGl->glUniform1i(textureUniformLoc, 0);
1680         ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
1681 
1682         mGl->glDrawArrays(GL_TRIANGLES, 0, 3);
1683         ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
1684 
1685         mGl->glFinish();
1686 
1687         for (int x = 0; x < width; x++) {
1688             for (int y = 0; y < height; y++) {
1689                 EXPECT_THAT(GetPixelAt(x, y), IsOkWith(lockPixel));
1690             }
1691         }
1692 
1693         mGl->glBindFramebuffer(GL_FRAMEBUFFER, 0);
1694     }
1695 }
1696 
1697 INSTANTIATE_TEST_CASE_P(GfxstreamEnd2EndTests, GfxstreamEnd2EndGlTest,
1698                         ::testing::ValuesIn({
1699                             TestParams{
1700                                 .with_gl = true,
1701                                 .with_vk = false,
1702                                 .with_features = {"GlProgramBinaryLinkStatus"},
1703                             },
1704                             TestParams{
1705                                 .with_gl = true,
1706                                 .with_vk = true,
1707                                 .with_features = {"GlProgramBinaryLinkStatus"},
1708                             },
1709                         }),
1710                         &GetTestName);
1711 
1712 }  // namespace
1713 }  // namespace tests
1714 }  // namespace gfxstream
1715