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