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 struct PixelR8G8B8A8 {
PixelR8G8B8A8gfxstream::tests::__anonae118ccb0111::PixelR8G8B8A832 PixelR8G8B8A8(uint8_t rr, uint8_t gg, uint8_t bb, uint8_t aa) : r(rr), g(gg), b(bb), a(aa) {}
33
PixelR8G8B8A8gfxstream::tests::__anonae118ccb0111::PixelR8G8B8A834 PixelR8G8B8A8(int xx, int yy, uint8_t rr, uint8_t gg, uint8_t bb, uint8_t aa)
35 : x(xx), y(yy), r(rr), g(gg), b(bb), a(aa) {}
36
37 std::optional<int> x;
38 std::optional<int> y;
39
40 uint8_t r;
41 uint8_t g;
42 uint8_t b;
43 uint8_t a;
44
ToStringgfxstream::tests::__anonae118ccb0111::PixelR8G8B8A845 std::string ToString() const {
46 std::string ret = std::string("Pixel");
47 if (x) {
48 ret += std::string(" x:") + std::to_string(*x);
49 }
50 if (y) {
51 ret += std::string(" y:") + std::to_string(*y);
52 }
53 ret += std::string(" {");
54 ret += std::string(" r:") + std::to_string(static_cast<int>(r));
55 ret += std::string(" g:") + std::to_string(static_cast<int>(g));
56 ret += std::string(" b:") + std::to_string(static_cast<int>(b));
57 ret += std::string(" a:") + std::to_string(static_cast<int>(a));
58 ret += std::string(" }");
59 return ret;
60 }
61
PrintTo(const PixelR8G8B8A8 & pixel,std::ostream * os)62 friend void PrintTo(const PixelR8G8B8A8& pixel, std::ostream* os) { *os << pixel.ToString(); }
63 };
64
65 MATCHER_P4(IsOkWithRGBA, r, g, b, a,
66 std::string(" equals ") + PixelR8G8B8A8(r, g, b, a).ToString()) {
67 const auto& actual = arg;
68
69 if (actual.ok() && actual.value().r == r && actual.value().g == g && actual.value().b == b &&
70 actual.value().a == a) {
71 return true;
72 }
73
74 if (actual.ok()) {
75 *result_listener << "actual: " << actual.value().ToString();
76 } else {
77 *result_listener << "actual: {" << " error: " << actual.error() << " };";
78 }
79 return false;
80 }
81
82 class GfxstreamEnd2EndGlTest : public GfxstreamEnd2EndTest {
83 protected:
GetPixelAt(GLint x,GLint y)84 GlExpected<PixelR8G8B8A8> GetPixelAt(GLint x, GLint y) {
85 if (!mGl) {
86 return android::base::unexpected("GL not available, running with `with_gl = false`?");
87 }
88
89 GLubyte rgba[4] = {0, 0, 0, 0};
90 mGl->glReadPixels(x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, rgba);
91
92 if (GLenum error = mGl->glGetError(); error != GL_NO_ERROR) {
93 return android::base::unexpected("Failed to glReadPixels() with error " +
94 std::to_string(error));
95 }
96
97 return PixelR8G8B8A8(x, y, rgba[0], rgba[1], rgba[2], rgba[3]);
98 }
99
SetUp()100 void SetUp() override {
101 GfxstreamEnd2EndTest::SetUp();
102
103 SetUpEglContextAndSurface(2, mSurfaceWidth, mSurfaceHeight, &mDisplay, &mContext,
104 &mSurface);
105 }
106
TearDown()107 void TearDown() override {
108 TearDownEglContextAndSurface(mDisplay, mContext, mSurface);
109
110 GfxstreamEnd2EndTest::TearDown();
111 }
112
113 int mSurfaceWidth = 32;
114 int mSurfaceHeight = 32;
115 EGLDisplay mDisplay;
116 EGLContext mContext;
117 EGLSurface mSurface;
118 };
119
TEST_P(GfxstreamEnd2EndGlTest,BasicViewport)120 TEST_P(GfxstreamEnd2EndGlTest, BasicViewport) {
121 GLint viewport[4] = {};
122 mGl->glGetIntegerv(GL_VIEWPORT, viewport);
123
124 EXPECT_THAT(viewport[0], Eq(0));
125 EXPECT_THAT(viewport[1], Eq(0));
126 EXPECT_THAT(viewport[2], Eq(mSurfaceWidth));
127 EXPECT_THAT(viewport[3], Eq(mSurfaceHeight));
128 }
129
TEST_P(GfxstreamEnd2EndGlTest,CreateWindowSurface)130 TEST_P(GfxstreamEnd2EndGlTest, CreateWindowSurface) {
131 // clang-format off
132 static const EGLint configAttributes[] = {
133 EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
134 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
135 EGL_NONE,
136 };
137 // clang-format on
138
139 int numConfigs = 0;
140 ASSERT_THAT(mGl->eglChooseConfig(mDisplay, configAttributes, nullptr, 1, &numConfigs),
141 IsTrue());
142 ASSERT_THAT(numConfigs, Gt(0));
143
144 EGLConfig config = nullptr;
145 ASSERT_THAT(mGl->eglChooseConfig(mDisplay, configAttributes, &config, 1, &numConfigs),
146 IsTrue());
147 ASSERT_THAT(config, Not(Eq(nullptr)));
148
149 // clang-format off
150 static const EGLint contextAttribs[] = {
151 EGL_CONTEXT_CLIENT_VERSION, 3,
152 EGL_NONE,
153 };
154 // clang-format on
155
156 EGLContext context = mGl->eglCreateContext(mDisplay, config, EGL_NO_CONTEXT, contextAttribs);
157 ASSERT_THAT(context, Not(Eq(EGL_NO_CONTEXT)));
158
159 constexpr const int width = 32;
160 constexpr const int height = 32;
161
162 auto anw = mAnwHelper->createNativeWindowForTesting(mGralloc.get(), width, height);
163
164 EGLSurface surface = mGl->eglCreateWindowSurface(mDisplay, config, anw, nullptr);
165 ASSERT_THAT(surface, Not(Eq(EGL_NO_SURFACE)));
166
167 ASSERT_THAT(mGl->eglMakeCurrent(mDisplay, surface, surface, context), IsTrue());
168
169 constexpr const int iterations = 120;
170 for (int i = 0; i < iterations; i++) {
171 mGl->glViewport(0, 0, width, height);
172 mGl->glClearColor(1.0f, 0.0f, static_cast<float>(i) / static_cast<float>(iterations), 1.0f);
173 mGl->glClear(GL_COLOR_BUFFER_BIT);
174 mGl->glFinish();
175 mGl->eglSwapBuffers(mDisplay, surface);
176 }
177
178 ASSERT_THAT(mGl->eglDestroyContext(mDisplay, context), IsTrue());
179 ASSERT_THAT(mGl->eglDestroySurface(mDisplay, surface), IsTrue());
180
181 mAnwHelper->release(anw);
182 }
183
TEST_P(GfxstreamEnd2EndGlTest,SwitchContext)184 TEST_P(GfxstreamEnd2EndGlTest, SwitchContext) {
185 ASSERT_THAT(mGl->eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT),
186 IsTrue());
187 for (int i = 0; i < 100; i++) {
188 ASSERT_THAT(mGl->eglMakeCurrent(mDisplay, mSurface, mSurface, mContext), IsTrue());
189 ASSERT_THAT(mGl->eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT),
190 IsTrue());
191 }
192 }
193
TEST_P(GfxstreamEnd2EndGlTest,MappedMemory)194 TEST_P(GfxstreamEnd2EndGlTest, MappedMemory) {
195 constexpr GLsizei kBufferSize = 64;
196
197 ScopedGlBuffer buffer(*mGl);
198 mGl->glBindBuffer(GL_ARRAY_BUFFER, buffer);
199 mGl->glBufferData(GL_ARRAY_BUFFER, kBufferSize, 0, GL_DYNAMIC_DRAW);
200
201 std::vector<uint8_t> bufferData(kBufferSize);
202 for (uint8_t i = 0; i < kBufferSize; ++i) {
203 bufferData[i] = i;
204 }
205
206 {
207 auto* mappedBufferData = reinterpret_cast<uint8_t*>(
208 mGl->glMapBufferRange(GL_ARRAY_BUFFER, 0, kBufferSize,
209 GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT));
210
211 for (uint8_t i = 0; i < kBufferSize; ++i) {
212 mappedBufferData[i] = bufferData[i];
213 }
214
215 mGl->glFlushMappedBufferRange(GL_ARRAY_BUFFER, 0, kBufferSize);
216 mGl->glUnmapBuffer(GL_ARRAY_BUFFER);
217 }
218
219 {
220 auto* mappedBufferData = reinterpret_cast<uint8_t*>(
221 mGl->glMapBufferRange(GL_ARRAY_BUFFER, 0, kBufferSize, GL_MAP_READ_BIT));
222
223 for (uint8_t i = 0; i < kBufferSize; ++i) {
224 EXPECT_THAT(mappedBufferData[i], Eq(bufferData[i]));
225 }
226
227 mGl->glUnmapBuffer(GL_ARRAY_BUFFER);
228 }
229
230 mGl->glBindBuffer(GL_ARRAY_BUFFER, 0);
231 }
232
TEST_P(GfxstreamEnd2EndGlTest,ContextStrings)233 TEST_P(GfxstreamEnd2EndGlTest, ContextStrings) {
234 EGLDisplay display = mGl->eglGetDisplay(EGL_DEFAULT_DISPLAY);
235 ASSERT_THAT(display, Not(Eq(EGL_NO_DISPLAY)));
236
237 int versionMajor = 0;
238 int versionMinor = 0;
239 ASSERT_THAT(mGl->eglInitialize(display, &versionMajor, &versionMinor), IsTrue());
240
241 ASSERT_THAT(mGl->eglBindAPI(EGL_OPENGL_ES_API), IsTrue());
242
243 // clang-format off
244 static const EGLint configAttributes[] = {
245 EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
246 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT,
247 EGL_NONE,
248 };
249 // clang-format on
250
251 int numConfigs = 0;
252 ASSERT_THAT(mGl->eglChooseConfig(display, configAttributes, nullptr, 1, &numConfigs), IsTrue());
253 ASSERT_THAT(numConfigs, Gt(0));
254
255 EGLConfig config = nullptr;
256 ASSERT_THAT(mGl->eglChooseConfig(display, configAttributes, &config, 1, &numConfigs), IsTrue());
257 ASSERT_THAT(config, Not(Eq(nullptr)));
258
259 // clang-format off
260 static const EGLint gles1ContextAttribs[] = {
261 EGL_CONTEXT_CLIENT_VERSION, 1,
262 EGL_NONE,
263 };
264 // clang-format on
265
266 EGLContext gles1Context = mGl->eglCreateContext(display, config, EGL_NO_CONTEXT, gles1ContextAttribs);
267 ASSERT_THAT(gles1Context, Not(Eq(EGL_NO_CONTEXT)));
268
269 // clang-format off
270 static const EGLint gles2ContextAttribs[] = {
271 EGL_CONTEXT_CLIENT_VERSION, 2,
272 EGL_NONE,
273 };
274 // clang-format on
275
276 EGLContext gles2Context = mGl->eglCreateContext(display, config, EGL_NO_CONTEXT, gles2ContextAttribs);
277 ASSERT_THAT(gles2Context, Not(Eq(EGL_NO_CONTEXT)));
278
279 constexpr const int width = 32;
280 constexpr const int height = 32;
281
282 // clang-format off
283 static const EGLint surfaceAttributes[] = {
284 EGL_WIDTH, width,
285 EGL_HEIGHT, height,
286 EGL_NONE,
287 };
288 // clang-format on
289
290 EGLSurface surface = mGl->eglCreatePbufferSurface(display, config, surfaceAttributes);
291 ASSERT_THAT(surface, Not(Eq(EGL_NO_SURFACE)));
292
293 {
294 ASSERT_THAT(mGl->eglMakeCurrent(display, surface, surface, gles2Context), IsTrue());
295 const auto versionString = (const char*)mGl->glGetString(GL_VERSION);
296 const auto extensionString = (const char*)mGl->glGetString(GL_EXTENSIONS);
297 EXPECT_THAT(versionString, HasSubstr("ES 3"));
298 EXPECT_THAT(extensionString, Not(HasSubstr("OES_draw_texture")));
299 }
300 {
301 ASSERT_THAT(mGl->eglMakeCurrent(display, surface, surface, gles1Context), IsTrue());
302 const auto versionString = (const char*)mGl->glGetString(GL_VERSION);
303 const auto extensionString = (const char*)mGl->glGetString(GL_EXTENSIONS);
304 EXPECT_THAT(versionString, HasSubstr("ES-CM"));
305 EXPECT_THAT(extensionString, HasSubstr("OES_draw_texture"));
306 }
307 {
308 ASSERT_THAT(mGl->eglMakeCurrent(display, surface, surface, gles2Context), IsTrue());
309 const auto versionString = (const char*)mGl->glGetString(GL_VERSION);
310 const auto extensionString = (const char*)mGl->glGetString(GL_EXTENSIONS);
311 EXPECT_THAT(versionString, HasSubstr("ES 3"));
312 EXPECT_THAT(extensionString, Not(HasSubstr("OES_draw_texture")));
313 }
314
315 ASSERT_THAT(mGl->eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT), IsTrue());
316 ASSERT_THAT(mGl->eglDestroyContext(display, gles1Context), IsTrue());
317 ASSERT_THAT(mGl->eglDestroyContext(display, gles2Context), IsTrue());
318 ASSERT_THAT(mGl->eglDestroySurface(display, surface), IsTrue());
319 }
320
TEST_P(GfxstreamEnd2EndGlTest,FramebufferFetchShader)321 TEST_P(GfxstreamEnd2EndGlTest, FramebufferFetchShader) {
322 const std::string extensionsString = (const char*)mGl->glGetString(GL_EXTENSIONS);
323 ASSERT_THAT(extensionsString, Not(IsEmpty()));
324
325 const bool supportsFramebufferFetch =
326 extensionsString.find("GL_EXT_shader_framebuffer_fetch") != std::string::npos;
327
328 const std::string shaderSource = R"(\
329 #version 300 es
330 #extension GL_EXT_shader_framebuffer_fetch : require
331 precision highp float;
332 in vec3 color_varying;
333 out vec4 fragColor;
334 void main() {
335 fragColor = vec4(color_varying, 1.0);
336 }
337 )";
338 auto result = SetUpShader(GL_FRAGMENT_SHADER, shaderSource);
339 if (result.ok()) {
340 ASSERT_THAT(supportsFramebufferFetch, Eq(GL_TRUE));
341 } else {
342 ASSERT_THAT(supportsFramebufferFetch, Eq(GL_FALSE));
343 }
344 }
345
TEST_P(GfxstreamEnd2EndGlTest,ConstantMatrixShader)346 TEST_P(GfxstreamEnd2EndGlTest, ConstantMatrixShader) {
347 const std::string shaderSource = R"(\
348 #version 300 es
349 precision mediump float;
350 in highp vec4 dEQP_Position;
351 out vec2 out0;
352
353 void main() {
354 const mat4x2 matA = mat4x2( 2.0, 4.0, 8.0, 16.0,
355 32.0, 64.0, 128.0, 256.0);
356 const mat4x2 matB = mat4x2(1.0 / 2.0, 1.0 / 4.0, 1.0 / 8.0, 1.0 / 16.0,
357 1.0 / 32.0, 1.0 / 64.0, 1.0 / 128.0, 1.0 / 256.0);
358 mat4x2 result = matrixCompMult(matA, matB);
359
360 out0 = result * vec4(1.0, 1.0, 1.0, 1.0);
361 gl_Position = dEQP_Position;
362 }
363 )";
364
365 auto result = SetUpShader(GL_VERTEX_SHADER, shaderSource);
366 ASSERT_THAT(result, IsOk());
367 }
368
TEST_P(GfxstreamEnd2EndGlTest,Draw)369 TEST_P(GfxstreamEnd2EndGlTest, Draw) {
370 const std::string vertSource = R"(\
371 #version 300 es
372 precision highp float;
373
374 layout (location = 0) in vec2 pos;
375 layout (location = 1) in vec3 color;
376
377 uniform mat4 transform;
378
379 out vec3 color_varying;
380
381 void main() {
382 gl_Position = transform * vec4(pos, 0.0, 1.0);
383 color_varying = (transform * vec4(color, 1.0)).xyz;
384 }
385 )";
386
387 const std::string fragSource = R"(\
388 #version 300 es
389 precision highp float;
390
391 in vec3 color_varying;
392
393 out vec4 fragColor;
394
395 void main() {
396 fragColor = vec4(color_varying, 1.0);
397 }
398 )";
399
400 ScopedGlProgram program = GL_ASSERT(SetUpProgram(vertSource, fragSource));
401
402 GLint transformUniformLocation = mGl->glGetUniformLocation(program, "transform");
403 mGl->glEnableVertexAttribArray(0);
404 mGl->glEnableVertexAttribArray(1);
405
406 struct VertexAttributes {
407 float position[2];
408 float color[3];
409 };
410 const VertexAttributes vertexAttrs[] = {
411 // clang-format off
412 { { -0.5f, -0.5f,}, { 0.2, 0.1, 0.9, }, },
413 { { 0.5f, -0.5f,}, { 0.8, 0.3, 0.1, }, },
414 { { 0.0f, 0.5f,}, { 0.1, 0.9, 0.6, }, },
415 // clang-format on
416 };
417
418 ScopedGlBuffer buffer(*mGl);
419 mGl->glBindBuffer(GL_ARRAY_BUFFER, buffer);
420 mGl->glBufferData(GL_ARRAY_BUFFER, sizeof(vertexAttrs), vertexAttrs, GL_STATIC_DRAW);
421
422 mGl->glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(VertexAttributes), 0);
423 mGl->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(VertexAttributes), (GLvoid*)offsetof(VertexAttributes, color));
424
425 mGl->glUseProgram(program);
426
427 mGl->glViewport(0, 0, 1, 1);
428
429 mGl->glClearColor(0.2f, 0.2f, 0.3f, 0.0f);
430 mGl->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
431
432 const float matrix[16] = {
433 // clang-format off
434 1.0f, 0.0f, 0.0f, 0.0f,
435 0.0f, 1.0f, 0.0f, 0.0f,
436 0.0f, 0.0f, 1.0f, 0.0f,
437 0.0f, 0.0f, 0.0f, 1.0f,
438 // clang-format on
439 };
440
441 constexpr uint32_t kDrawIterations = 200;
442 for (uint32_t i = 0; i < kDrawIterations; i++) {
443 mGl->glUniformMatrix4fv(transformUniformLocation, 1, GL_FALSE, matrix);
444 mGl->glBindBuffer(GL_ARRAY_BUFFER, buffer);
445 mGl->glDrawArrays(GL_TRIANGLES, 0, 3);
446 }
447
448 mGl->glFinish();
449 mGl->glBindBuffer(GL_ARRAY_BUFFER, 0);
450 mGl->glUseProgram(0);
451 }
452
TEST_P(GfxstreamEnd2EndGlTest,ProgramBinaryWithAHB)453 TEST_P(GfxstreamEnd2EndGlTest, ProgramBinaryWithAHB) {
454 const uint32_t width = 2;
455 const uint32_t height = 2;
456 auto ahb =
457 GL_ASSERT(ScopedAHardwareBuffer::Allocate(*mGralloc, width, height, GFXSTREAM_AHB_FORMAT_R8G8B8A8_UNORM));
458
459 {
460 uint8_t* mapped = GL_ASSERT(ahb.Lock());
461 uint32_t pos = 0;
462 for (uint32_t h = 0; h < height; h++) {
463 for (uint32_t w = 0; w < width; w++) {
464 mapped[pos++] = 0;
465 mapped[pos++] = 0;
466 mapped[pos++] = 128;
467 mapped[pos++] = 255;
468 }
469 }
470 ahb.Unlock();
471 }
472
473 const EGLint ahbImageAttribs[] = {
474 // clang-format off
475 EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
476 EGL_NONE,
477 // clang-format on
478 };
479 EGLImageKHR ahbImage = mGl->eglCreateImageKHR(mDisplay, EGL_NO_CONTEXT,
480 EGL_NATIVE_BUFFER_ANDROID, ahb, ahbImageAttribs);
481 ASSERT_THAT(ahbImage, Not(Eq(EGL_NO_IMAGE_KHR)));
482
483 ScopedGlTexture ahbTexture(*mGl);
484 mGl->glBindTexture(GL_TEXTURE_EXTERNAL_OES, ahbTexture);
485 mGl->glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
486 mGl->glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
487 mGl->glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, ahbImage);
488 ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
489
490 GLenum programBinaryFormat = GL_NONE;
491 std::vector<uint8_t> programBinaryData;
492 {
493 const std::string vertSource = R"(\
494 #version 300 es
495
496 layout (location = 0) in vec2 pos;
497 layout (location = 1) in vec2 tex;
498
499 out vec2 vTex;
500
501 void main() {
502 gl_Position = vec4(pos, 0.0, 1.0);
503 vTex = tex;
504 })";
505
506 const std::string fragSource = R"(\
507 #version 300 es
508
509 precision highp float;
510
511 uniform float uMultiplier;
512 uniform sampler2D uTexture;
513
514 in vec2 vTex;
515
516 out vec4 oColor;
517
518 void main() {
519 oColor = texture(uTexture, vTex) * uMultiplier;
520 })";
521
522 ScopedGlProgram program = GL_ASSERT(SetUpProgram(vertSource, fragSource));
523
524 GLint programBinaryLength = 0;
525 mGl->glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH, &programBinaryLength);
526 ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
527
528 programBinaryData.resize(programBinaryLength);
529
530 GLint readProgramBinaryLength = 0;
531 mGl->glGetProgramBinary(program, programBinaryLength, &readProgramBinaryLength,
532 &programBinaryFormat, programBinaryData.data());
533 ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
534 ASSERT_THAT(programBinaryLength, Eq(readProgramBinaryLength));
535 }
536
537 ScopedGlProgram program = GL_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 = GL_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 = GL_ASSERT(SetUpProgram(programBinaryFormat, programBinaryData));
676 ASSERT_THAT(program, Not(Eq(0)));
677
678 GLint textureUniformLoc = mGl->glGetUniformLocation(program, "uTexture");
679 ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
680 ASSERT_THAT(textureUniformLoc, Not(Eq(-1)));
681
682 GLint multiplierUniformLoc = mGl->glGetUniformLocation(program, "uMultiplier");
683 ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
684 ASSERT_THAT(multiplierUniformLoc, Not(Eq(-1)));
685
686 const GLsizei kFramebufferWidth = 4;
687 const GLsizei kFramebufferHeight = 4;
688 ScopedGlFramebuffer framebuffer(*mGl);
689 mGl->glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
690 ScopedGlTexture framebufferTexture(*mGl);
691 mGl->glBindTexture(GL_TEXTURE_2D, framebufferTexture);
692 mGl->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kFramebufferWidth, kFramebufferHeight, 0, GL_RGBA,
693 GL_UNSIGNED_BYTE, nullptr);
694 mGl->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
695 framebufferTexture, 0);
696 ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
697 ASSERT_THAT(mGl->glCheckFramebufferStatus(GL_FRAMEBUFFER), Eq(GL_FRAMEBUFFER_COMPLETE));
698 mGl->glBindTexture(GL_TEXTURE_2D, 0);
699 ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
700
701 struct VertexAttributes {
702 float pos[2];
703 float tex[2];
704 };
705 const VertexAttributes vertexAttrs[] = {
706 // clang-format off
707 { { -1.0f, -1.0f,}, { 0.0f, 0.0f }, },
708 { { 3.0f, -1.0f,}, { 2.0f, 0.0f }, },
709 { { -1.0f, 3.0f,}, { 0.0f, 2.0f }, },
710 // clang-format on
711 };
712 ScopedGlBuffer buffer(*mGl);
713 mGl->glBindBuffer(GL_ARRAY_BUFFER, buffer);
714 mGl->glBufferData(GL_ARRAY_BUFFER, sizeof(vertexAttrs), vertexAttrs, GL_STATIC_DRAW);
715
716 mGl->glUseProgram(program);
717 ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
718
719 mGl->glBindBuffer(GL_ARRAY_BUFFER, buffer);
720 mGl->glEnableVertexAttribArray(0);
721 mGl->glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(VertexAttributes),
722 (GLvoid*)offsetof(VertexAttributes, pos));
723 mGl->glEnableVertexAttribArray(1);
724 mGl->glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(VertexAttributes),
725 (GLvoid*)offsetof(VertexAttributes, tex));
726 ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
727
728 mGl->glActiveTexture(GL_TEXTURE0);
729 mGl->glBindTexture(GL_TEXTURE_2D, texture);
730 mGl->glUniform1i(textureUniformLoc, 0);
731 ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
732
733 mGl->glUniform1f(multiplierUniformLoc, 2.0f);
734 ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
735
736 mGl->glDrawArrays(GL_TRIANGLES, 0, 3);
737 ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
738
739 for (int x = 0; x < kFramebufferWidth; x++) {
740 for (int y = 0; y < kFramebufferHeight; y++) {
741 EXPECT_THAT(GetPixelAt(x, y), IsOkWithRGBA(0, 0, 255, 255));
742 }
743 }
744
745 mGl->glBindFramebuffer(GL_FRAMEBUFFER, 0);
746 }
747
748 INSTANTIATE_TEST_CASE_P(GfxstreamEnd2EndTests, GfxstreamEnd2EndGlTest,
749 ::testing::ValuesIn({
750 TestParams{
751 .with_gl = true,
752 .with_vk = false,
753 },
754 TestParams{
755 .with_gl = true,
756 .with_vk = true,
757 },
758 }),
759 &GetTestName);
760
761 } // namespace
762 } // namespace tests
763 } // namespace gfxstream
764