1 //
2 // Copyright 2015 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6
7 #include "test_utils/ANGLETest.h"
8 #include "test_utils/gl_raii.h"
9 #include "util/EGLWindow.h"
10
11 using namespace angle;
12
13 class PbufferTest : public ANGLETest<>
14 {
15 protected:
PbufferTest()16 PbufferTest()
17 {
18 setWindowWidth(512);
19 setWindowHeight(512);
20 setConfigRedBits(8);
21 setConfigGreenBits(8);
22 setConfigBlueBits(8);
23 setConfigAlphaBits(8);
24 }
25
testSetUp()26 void testSetUp() override
27 {
28 constexpr char kVS[] =
29 R"(precision highp float;
30 attribute vec4 position;
31 varying vec2 texcoord;
32
33 void main()
34 {
35 gl_Position = position;
36 texcoord = (position.xy * 0.5) + 0.5;
37 texcoord.y = 1.0 - texcoord.y;
38 })";
39
40 constexpr char kFS[] =
41 R"(precision highp float;
42 uniform sampler2D tex;
43 varying vec2 texcoord;
44
45 void main()
46 {
47 gl_FragColor = texture2D(tex, texcoord);
48 })";
49
50 mTextureProgram = CompileProgram(kVS, kFS);
51 if (mTextureProgram == 0)
52 {
53 FAIL() << "shader compilation failed.";
54 }
55
56 mTextureUniformLocation = glGetUniformLocation(mTextureProgram, "tex");
57
58 EGLWindow *window = getEGLWindow();
59
60 EGLint surfaceType = 0;
61 eglGetConfigAttrib(window->getDisplay(), window->getConfig(), EGL_SURFACE_TYPE,
62 &surfaceType);
63 mSupportsPbuffers = (surfaceType & EGL_PBUFFER_BIT) != 0;
64
65 mPbuffer = createTestPbufferSurface();
66 if (mSupportsPbuffers)
67 {
68 ASSERT_NE(mPbuffer, EGL_NO_SURFACE);
69 ASSERT_EGL_SUCCESS();
70 }
71 else
72 {
73 ASSERT_EQ(mPbuffer, EGL_NO_SURFACE);
74 ASSERT_EGL_ERROR(EGL_BAD_MATCH);
75 }
76 ASSERT_GL_NO_ERROR();
77 }
78
createTestPbufferSurface()79 EGLSurface createTestPbufferSurface()
80 {
81 EGLWindow *window = getEGLWindow();
82 EGLint bindToTextureRGBA = 0;
83 eglGetConfigAttrib(window->getDisplay(), window->getConfig(), EGL_BIND_TO_TEXTURE_RGBA,
84 &bindToTextureRGBA);
85 mSupportsBindTexImage = (bindToTextureRGBA == EGL_TRUE);
86
87 const EGLint pBufferAttributes[] = {
88 EGL_WIDTH, static_cast<EGLint>(mPbufferSize),
89 EGL_HEIGHT, static_cast<EGLint>(mPbufferSize),
90 EGL_TEXTURE_FORMAT, mSupportsBindTexImage ? EGL_TEXTURE_RGBA : EGL_NO_TEXTURE,
91 EGL_TEXTURE_TARGET, mSupportsBindTexImage ? EGL_TEXTURE_2D : EGL_NO_TEXTURE,
92 EGL_NONE, EGL_NONE,
93 };
94
95 return eglCreatePbufferSurface(window->getDisplay(), window->getConfig(),
96 pBufferAttributes);
97 }
98
testTearDown()99 void testTearDown() override
100 {
101 glDeleteProgram(mTextureProgram);
102
103 destroyPbuffer();
104 }
105
destroyPbuffer()106 void destroyPbuffer()
107 {
108 if (mPbuffer)
109 {
110 destroyTestPbufferSurface(mPbuffer);
111 }
112 }
113
destroyTestPbufferSurface(EGLSurface pbuffer)114 void destroyTestPbufferSurface(EGLSurface pbuffer)
115 {
116 EGLWindow *window = getEGLWindow();
117 eglDestroySurface(window->getDisplay(), pbuffer);
118 }
119
recreatePbufferInSrgbColorspace()120 void recreatePbufferInSrgbColorspace()
121 {
122 EGLWindow *window = getEGLWindow();
123
124 destroyPbuffer();
125
126 const EGLint pBufferSrgbAttributes[] = {
127 EGL_WIDTH,
128 static_cast<EGLint>(mPbufferSize),
129 EGL_HEIGHT,
130 static_cast<EGLint>(mPbufferSize),
131 EGL_TEXTURE_FORMAT,
132 mSupportsBindTexImage ? EGL_TEXTURE_RGBA : EGL_NO_TEXTURE,
133 EGL_TEXTURE_TARGET,
134 mSupportsBindTexImage ? EGL_TEXTURE_2D : EGL_NO_TEXTURE,
135 EGL_GL_COLORSPACE_KHR,
136 EGL_GL_COLORSPACE_SRGB_KHR,
137 EGL_NONE,
138 EGL_NONE,
139 };
140
141 mPbuffer = eglCreatePbufferSurface(window->getDisplay(), window->getConfig(),
142 pBufferSrgbAttributes);
143 }
144
drawColorQuad(GLColor color)145 void drawColorQuad(GLColor color)
146 {
147 ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor());
148 glUseProgram(program);
149 GLint colorUniformLocation =
150 glGetUniformLocation(program, angle::essl1_shaders::ColorUniform());
151 ASSERT_NE(colorUniformLocation, -1);
152 glUniform4fv(colorUniformLocation, 1, color.toNormalizedVector().data());
153 drawQuad(program, essl1_shaders::PositionAttrib(), 0);
154 glUseProgram(0);
155 }
156
157 GLuint mTextureProgram;
158 GLint mTextureUniformLocation;
159
160 const size_t mPbufferSize = 32;
161 EGLSurface mPbuffer = EGL_NO_SURFACE;
162 bool mSupportsPbuffers;
163 bool mSupportsBindTexImage;
164 };
165
166 class PbufferColorspaceTest : public PbufferTest
167 {};
168
169 // Test clearing a Pbuffer and checking the color is correct
TEST_P(PbufferTest,Clearing)170 TEST_P(PbufferTest, Clearing)
171 {
172 ANGLE_SKIP_TEST_IF(!mSupportsPbuffers);
173
174 EGLWindow *window = getEGLWindow();
175
176 // Clear the window surface to blue and verify
177 window->makeCurrent();
178 ASSERT_EGL_SUCCESS();
179
180 glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
181 glClear(GL_COLOR_BUFFER_BIT);
182 ASSERT_GL_NO_ERROR();
183 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue);
184
185 // Apply the Pbuffer and clear it to purple and verify
186 eglMakeCurrent(window->getDisplay(), mPbuffer, mPbuffer, window->getContext());
187 ASSERT_EGL_SUCCESS();
188
189 glViewport(0, 0, static_cast<GLsizei>(mPbufferSize), static_cast<GLsizei>(mPbufferSize));
190 glClearColor(1.0f, 0.0f, 1.0f, 1.0f);
191 glClear(GL_COLOR_BUFFER_BIT);
192 ASSERT_GL_NO_ERROR();
193 EXPECT_PIXEL_EQ(static_cast<GLint>(mPbufferSize) / 2, static_cast<GLint>(mPbufferSize) / 2, 255,
194 0, 255, 255);
195
196 // Rebind the window surface and verify that it is still blue
197 window->makeCurrent();
198 ASSERT_EGL_SUCCESS();
199 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 255, 255);
200 }
201
202 // Bind the Pbuffer to a texture and verify it renders correctly
TEST_P(PbufferTest,BindTexImage)203 TEST_P(PbufferTest, BindTexImage)
204 {
205 // Test skipped because Pbuffers are not supported or Pbuffer does not support binding to RGBA
206 // textures.
207 ANGLE_SKIP_TEST_IF(!mSupportsPbuffers || !mSupportsBindTexImage);
208
209 EGLWindow *window = getEGLWindow();
210
211 // Apply the Pbuffer and clear it to purple
212 eglMakeCurrent(window->getDisplay(), mPbuffer, mPbuffer, window->getContext());
213 ASSERT_EGL_SUCCESS();
214
215 glViewport(0, 0, static_cast<GLsizei>(mPbufferSize), static_cast<GLsizei>(mPbufferSize));
216 glClearColor(1.0f, 0.0f, 1.0f, 1.0f);
217 glClear(GL_COLOR_BUFFER_BIT);
218 ASSERT_GL_NO_ERROR();
219
220 EXPECT_PIXEL_COLOR_EQ(static_cast<GLint>(mPbufferSize) / 2,
221 static_cast<GLint>(mPbufferSize) / 2, GLColor::magenta);
222
223 // Apply the window surface
224 window->makeCurrent();
225
226 // Create a texture and bind the Pbuffer to it
227 GLuint texture = 0;
228 glGenTextures(1, &texture);
229 glBindTexture(GL_TEXTURE_2D, texture);
230 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
231 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
232 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
233 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
234 EXPECT_GL_NO_ERROR();
235
236 eglBindTexImage(window->getDisplay(), mPbuffer, EGL_BACK_BUFFER);
237 glViewport(0, 0, getWindowWidth(), getWindowHeight());
238 ASSERT_EGL_SUCCESS();
239
240 // Draw a quad and verify that it is purple
241 glUseProgram(mTextureProgram);
242 glUniform1i(mTextureUniformLocation, 0);
243
244 drawQuad(mTextureProgram, "position", 0.5f);
245 EXPECT_GL_NO_ERROR();
246
247 // Unbind the texture
248 eglReleaseTexImage(window->getDisplay(), mPbuffer, EGL_BACK_BUFFER);
249 ASSERT_EGL_SUCCESS();
250
251 // Verify that purple was drawn
252 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 255, 0, 255, 255);
253
254 glDeleteTextures(1, &texture);
255 }
256
257 // Test various EGL level cases for eglBindTexImage.
TEST_P(PbufferTest,BindTexImageAlreadyBound)258 TEST_P(PbufferTest, BindTexImageAlreadyBound)
259 {
260 // Test skipped because Pbuffers are not supported or Pbuffer does not support binding to RGBA
261 // textures.
262 ANGLE_SKIP_TEST_IF(!mSupportsPbuffers || !mSupportsBindTexImage);
263 EGLWindow *window = getEGLWindow();
264 window->makeCurrent();
265
266 GLTexture texture;
267 glBindTexture(GL_TEXTURE_2D, texture);
268 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
269 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
270 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
271 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
272 GLFramebuffer fbo;
273 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
274 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
275 EXPECT_GL_NO_ERROR();
276
277 // This is being tested
278 EXPECT_TRUE(eglBindTexImage(window->getDisplay(), mPbuffer, EGL_BACK_BUFFER));
279 ASSERT_EGL_SUCCESS();
280 // If buffer is already bound to a texture then an EGL_BAD_ACCESS error is returned.
281 EXPECT_FALSE(eglBindTexImage(window->getDisplay(), mPbuffer, EGL_BACK_BUFFER));
282 ASSERT_EGL_ERROR(EGL_BAD_ACCESS);
283
284 GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
285 ANGLE_SKIP_TEST_IF(status == GL_FRAMEBUFFER_UNSUPPORTED);
286 EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, status);
287
288 drawColorQuad(GLColor::magenta);
289 ASSERT_GL_NO_ERROR();
290
291 EXPECT_PIXEL_COLOR_EQ(static_cast<GLint>(mPbufferSize) / 2,
292 static_cast<GLint>(mPbufferSize) / 2, GLColor::magenta);
293
294 destroyPbuffer();
295 ASSERT_EGL_SUCCESS();
296 ASSERT_GL_NO_ERROR();
297 }
298
299 // Test that eglBindTexImage overwriting previous bind works.
TEST_P(PbufferTest,BindTexImageOverwrite)300 TEST_P(PbufferTest, BindTexImageOverwrite)
301 {
302 // Test skipped because Pbuffers are not supported or Pbuffer does not support binding to RGBA
303 // textures.
304 ANGLE_SKIP_TEST_IF(!mSupportsPbuffers || !mSupportsBindTexImage);
305
306 EGLWindow *window = getEGLWindow();
307 window->makeCurrent();
308
309 GLTexture texture;
310 glBindTexture(GL_TEXTURE_2D, texture);
311 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
312 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
313 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
314 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
315 GLFramebuffer fbo;
316 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
317 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
318 EXPECT_GL_NO_ERROR();
319
320 // This is being tested: setup a binding that will be overwritten.
321 EXPECT_TRUE(eglBindTexImage(window->getDisplay(), mPbuffer, EGL_BACK_BUFFER));
322 ASSERT_EGL_SUCCESS();
323
324 GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
325 ANGLE_SKIP_TEST_IF(status == GL_FRAMEBUFFER_UNSUPPORTED);
326 EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, status);
327
328 drawColorQuad(GLColor::magenta);
329 ASSERT_GL_NO_ERROR();
330
331 EXPECT_PIXEL_COLOR_EQ(static_cast<GLint>(mPbufferSize) / 2,
332 static_cast<GLint>(mPbufferSize) / 2, GLColor::magenta);
333
334 EGLSurface otherPbuffer = createTestPbufferSurface();
335 ASSERT_NE(otherPbuffer, EGL_NO_SURFACE);
336 // This is being tested: replace the previous binding.
337 EXPECT_TRUE(eglBindTexImage(window->getDisplay(), otherPbuffer, EGL_BACK_BUFFER));
338 ASSERT_EGL_SUCCESS();
339
340 drawColorQuad(GLColor::yellow);
341 ASSERT_GL_NO_ERROR();
342
343 EXPECT_PIXEL_COLOR_EQ(static_cast<GLint>(mPbufferSize) / 2,
344 static_cast<GLint>(mPbufferSize) / 2, GLColor::yellow);
345
346 destroyTestPbufferSurface(otherPbuffer);
347 destroyPbuffer();
348 ASSERT_EGL_SUCCESS();
349 ASSERT_GL_NO_ERROR();
350 }
351
352 // Test that eglBindTexImage overwriting previous bind works and does not crash on releaseTexImage.
TEST_P(PbufferTest,BindTexImageOverwriteNoCrashOnReleaseTexImage)353 TEST_P(PbufferTest, BindTexImageOverwriteNoCrashOnReleaseTexImage)
354 {
355 // Test skipped because Pbuffers are not supported or Pbuffer does not support binding to RGBA
356 // textures.
357 ANGLE_SKIP_TEST_IF(!mSupportsPbuffers || !mSupportsBindTexImage);
358 EGLWindow *window = getEGLWindow();
359 window->makeCurrent();
360
361 GLTexture texture;
362 glBindTexture(GL_TEXTURE_2D, texture);
363 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
364 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
365 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
366 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
367 EXPECT_GL_NO_ERROR();
368
369 EGLSurface otherPbuffer = createTestPbufferSurface();
370 ASSERT_NE(otherPbuffer, EGL_NO_SURFACE);
371
372 EXPECT_TRUE(eglBindTexImage(window->getDisplay(), mPbuffer, EGL_BACK_BUFFER));
373 ASSERT_EGL_SUCCESS();
374 EXPECT_TRUE(eglBindTexImage(window->getDisplay(), otherPbuffer, EGL_BACK_BUFFER));
375 ASSERT_EGL_SUCCESS();
376 EXPECT_TRUE(eglReleaseTexImage(window->getDisplay(), otherPbuffer, EGL_BACK_BUFFER));
377 ASSERT_EGL_SUCCESS();
378 EXPECT_TRUE(eglReleaseTexImage(window->getDisplay(), mPbuffer, EGL_BACK_BUFFER)); // No-op.
379 ASSERT_EGL_SUCCESS();
380 EXPECT_TRUE(eglBindTexImage(window->getDisplay(), mPbuffer, EGL_BACK_BUFFER));
381 ASSERT_EGL_SUCCESS();
382 EXPECT_TRUE(eglReleaseTexImage(window->getDisplay(), mPbuffer, EGL_BACK_BUFFER));
383 ASSERT_EGL_SUCCESS();
384
385 destroyTestPbufferSurface(otherPbuffer);
386 destroyPbuffer();
387 ASSERT_EGL_SUCCESS();
388 ASSERT_GL_NO_ERROR();
389 }
390
391 // Test that eglBindTexImage pbuffer is unbound when the texture is destroyed.
TEST_P(PbufferTest,BindTexImageReleaseViaTextureDestroy)392 TEST_P(PbufferTest, BindTexImageReleaseViaTextureDestroy)
393 {
394 // Test skipped because Pbuffers are not supported or Pbuffer does not support binding to RGBA
395 // textures.
396 ANGLE_SKIP_TEST_IF(!mSupportsPbuffers || !mSupportsBindTexImage);
397 EGLWindow *window = getEGLWindow();
398 window->makeCurrent();
399
400 // Bind to a texture that will be destroyed.
401 {
402 GLTexture texture;
403 glBindTexture(GL_TEXTURE_2D, texture);
404 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
405 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
406 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
407 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
408 GLFramebuffer fbo;
409 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
410 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
411 EXPECT_GL_NO_ERROR();
412
413 // This is being tested: setup a binding that will be overwritten.
414 EXPECT_TRUE(eglBindTexImage(window->getDisplay(), mPbuffer, EGL_BACK_BUFFER));
415 ASSERT_EGL_SUCCESS();
416
417 GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
418 ANGLE_SKIP_TEST_IF(status == GL_FRAMEBUFFER_UNSUPPORTED);
419 EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, status);
420
421 drawColorQuad(GLColor::magenta);
422 ASSERT_GL_NO_ERROR();
423 }
424
425 GLTexture texture;
426 glBindTexture(GL_TEXTURE_2D, texture);
427 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
428 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
429 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
430 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
431 GLFramebuffer fbo;
432 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
433 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
434 EXPECT_GL_NO_ERROR();
435
436 // This is being tested.
437 EXPECT_TRUE(eglBindTexImage(window->getDisplay(), mPbuffer, EGL_BACK_BUFFER));
438 ASSERT_EGL_SUCCESS();
439
440 EXPECT_PIXEL_COLOR_EQ(static_cast<GLint>(mPbufferSize) / 2,
441 static_cast<GLint>(mPbufferSize) / 2, GLColor::magenta);
442
443 destroyPbuffer();
444 ASSERT_EGL_SUCCESS();
445 ASSERT_GL_NO_ERROR();
446 }
447
448 // Test that eglBindTexImage pbuffer is unbound when eglReleaseTexImage is called.
TEST_P(PbufferTest,BindTexImagePbufferReleaseWhileBoundToFBOColorBuffer)449 TEST_P(PbufferTest, BindTexImagePbufferReleaseWhileBoundToFBOColorBuffer)
450 {
451 // Test skipped because Pbuffers are not supported or Pbuffer does not support binding to RGBA
452 // textures.
453 ANGLE_SKIP_TEST_IF(!mSupportsPbuffers || !mSupportsBindTexImage);
454 EGLWindow *window = getEGLWindow();
455 window->makeCurrent();
456
457 GLTexture texture;
458 glBindTexture(GL_TEXTURE_2D, texture);
459 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
460 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
461 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
462 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
463 GLFramebuffer fbo;
464 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
465 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
466 EXPECT_GL_NO_ERROR();
467
468 // This is being tested: setup a binding to a pbuffer that will be unbound.
469 EXPECT_TRUE(eglBindTexImage(window->getDisplay(), mPbuffer, EGL_BACK_BUFFER));
470 ASSERT_EGL_SUCCESS();
471
472 GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
473 ANGLE_SKIP_TEST_IF(status == GL_FRAMEBUFFER_UNSUPPORTED);
474 EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, status);
475
476 // This is being tested: unbind the pbuffer, detect it via framebuffer status.
477 EXPECT_TRUE(eglReleaseTexImage(window->getDisplay(), mPbuffer, EGL_BACK_BUFFER));
478 status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
479 EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT, status);
480
481 destroyPbuffer();
482 ASSERT_EGL_SUCCESS();
483 ASSERT_GL_NO_ERROR();
484 }
485
486 // Test that eglBindTexImage pbuffer is bound when the pbuffer is destroyed.
TEST_P(PbufferTest,BindTexImagePbufferDestroyWhileBound)487 TEST_P(PbufferTest, BindTexImagePbufferDestroyWhileBound)
488 {
489 // Test skipped because Pbuffers are not supported or Pbuffer does not support binding to RGBA
490 // textures.
491 ANGLE_SKIP_TEST_IF(!mSupportsPbuffers || !mSupportsBindTexImage);
492 EGLWindow *window = getEGLWindow();
493 window->makeCurrent();
494
495 GLTexture texture;
496 glBindTexture(GL_TEXTURE_2D, texture);
497 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
498 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
499 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
500 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
501 GLFramebuffer fbo;
502 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
503 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
504 EXPECT_GL_NO_ERROR();
505
506 // This is being tested: setup a binding to a pbuffer that will be destroyed.
507 EXPECT_TRUE(eglBindTexImage(window->getDisplay(), mPbuffer, EGL_BACK_BUFFER));
508 ASSERT_EGL_SUCCESS();
509
510 GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
511 ANGLE_SKIP_TEST_IF(status == GL_FRAMEBUFFER_UNSUPPORTED);
512 EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, status);
513
514 drawColorQuad(GLColor::magenta);
515 ASSERT_GL_NO_ERROR();
516
517 // This is being tested: destroy the pbuffer, but the underlying binding still works.
518 destroyPbuffer();
519 status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
520 EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, status);
521
522 EXPECT_PIXEL_COLOR_EQ(static_cast<GLint>(mPbufferSize) / 2,
523 static_cast<GLint>(mPbufferSize) / 2, GLColor::magenta);
524
525 ASSERT_EGL_SUCCESS();
526 ASSERT_GL_NO_ERROR();
527 }
528
529 // Test that eglBindTexImage overwrite releases the previous pbuffer if the previous is orphaned.
TEST_P(PbufferTest,BindTexImageOverwriteReleasesOrphanedPbuffer)530 TEST_P(PbufferTest, BindTexImageOverwriteReleasesOrphanedPbuffer)
531 {
532 // Test skipped because Pbuffers are not supported or Pbuffer does not support binding to RGBA
533 // textures.
534 ANGLE_SKIP_TEST_IF(!mSupportsPbuffers || !mSupportsBindTexImage);
535
536 EGLWindow *window = getEGLWindow();
537 window->makeCurrent();
538
539 GLTexture texture;
540 glBindTexture(GL_TEXTURE_2D, texture);
541 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
542 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
543 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
544 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
545 GLFramebuffer fbo;
546 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
547 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
548 EXPECT_GL_NO_ERROR();
549
550 // This is being tested: setup a binding to a pbuffer that will be destroyed.
551 EXPECT_TRUE(eglBindTexImage(window->getDisplay(), mPbuffer, EGL_BACK_BUFFER));
552 ASSERT_EGL_SUCCESS();
553
554 GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
555 ANGLE_SKIP_TEST_IF(status == GL_FRAMEBUFFER_UNSUPPORTED);
556 EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, status);
557
558 // Write magenta. This shouldn't be read below.
559 drawColorQuad(GLColor::magenta);
560 ASSERT_GL_NO_ERROR();
561
562 // This is being tested: destroy the pbuffer, but the underlying binding still works.
563 destroyPbuffer();
564 status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
565 EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, status);
566
567 EGLSurface otherPbuffer = createTestPbufferSurface();
568 // This is being tested: bind a new pbuffer. The one orphaned above will now be really
569 // deallocated and we hope some sort of assert fires if something goes wrong.
570 EXPECT_TRUE(eglBindTexImage(window->getDisplay(), otherPbuffer, EGL_BACK_BUFFER));
571
572 // Write yellow.
573 drawColorQuad(GLColor::yellow);
574 ASSERT_GL_NO_ERROR();
575
576 EXPECT_PIXEL_COLOR_EQ(static_cast<GLint>(mPbufferSize) / 2,
577 static_cast<GLint>(mPbufferSize) / 2, GLColor::yellow);
578
579 destroyTestPbufferSurface(otherPbuffer);
580 ASSERT_EGL_SUCCESS();
581 ASSERT_GL_NO_ERROR();
582 }
583
584 // Verify that binding a pbuffer works after using a texture normally.
TEST_P(PbufferTest,BindTexImageAfterTexImage)585 TEST_P(PbufferTest, BindTexImageAfterTexImage)
586 {
587 // Test skipped because Pbuffers are not supported or Pbuffer does not support binding to RGBA
588 // textures.
589 ANGLE_SKIP_TEST_IF(!mSupportsPbuffers || !mSupportsBindTexImage);
590
591 EGLWindow *window = getEGLWindow();
592
593 // Apply the Pbuffer and clear it to magenta
594 eglMakeCurrent(window->getDisplay(), mPbuffer, mPbuffer, window->getContext());
595 ASSERT_EGL_SUCCESS();
596
597 glViewport(0, 0, static_cast<GLsizei>(mPbufferSize), static_cast<GLsizei>(mPbufferSize));
598 glClearColor(1.0f, 0.0f, 1.0f, 1.0f);
599 glClear(GL_COLOR_BUFFER_BIT);
600 ASSERT_GL_NO_ERROR();
601
602 EXPECT_PIXEL_COLOR_EQ(static_cast<GLint>(mPbufferSize) / 2,
603 static_cast<GLint>(mPbufferSize) / 2, GLColor::magenta);
604
605 // Apply the window surface
606 window->makeCurrent();
607 glViewport(0, 0, getWindowWidth(), getWindowHeight());
608
609 // Create a simple blue texture.
610 GLTexture texture;
611 glBindTexture(GL_TEXTURE_2D, texture);
612 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
613 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
614 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
615 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
616 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::blue);
617 EXPECT_GL_NO_ERROR();
618
619 // Draw a quad and verify blue
620 glUseProgram(mTextureProgram);
621 glUniform1i(mTextureUniformLocation, 0);
622 drawQuad(mTextureProgram, "position", 0.5f);
623 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
624
625 // Bind the Pbuffer to the texture
626 eglBindTexImage(window->getDisplay(), mPbuffer, EGL_BACK_BUFFER);
627 ASSERT_EGL_SUCCESS();
628
629 // Draw a quad and verify magenta
630 drawQuad(mTextureProgram, "position", 0.5f);
631 EXPECT_GL_NO_ERROR();
632 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::magenta);
633
634 // Unbind the texture
635 eglReleaseTexImage(window->getDisplay(), mPbuffer, EGL_BACK_BUFFER);
636 ASSERT_EGL_SUCCESS();
637 }
638
639 // Test clearing a Pbuffer in sRGB colorspace and checking the color is correct.
640 // Then bind the Pbuffer to a texture and verify it renders correctly
TEST_P(PbufferTest,ClearAndBindTexImageSrgb)641 TEST_P(PbufferTest, ClearAndBindTexImageSrgb)
642 {
643 EGLWindow *window = getEGLWindow();
644
645 // Test skipped because Pbuffers are not supported or Pbuffer does not support binding to RGBA
646 // textures.
647 ANGLE_SKIP_TEST_IF(!mSupportsPbuffers || !mSupportsBindTexImage);
648 ANGLE_SKIP_TEST_IF(
649 !IsEGLDisplayExtensionEnabled(window->getDisplay(), "EGL_KHR_gl_colorspace"));
650 // Possible GLES driver bug on Pixel2 devices: http://anglebug.com/42263865
651 ANGLE_SKIP_TEST_IF(IsPixel2() && IsOpenGLES());
652
653 GLubyte kLinearColor[] = {132, 55, 219, 255};
654 GLubyte kSrgbColor[] = {190, 128, 238, 255};
655
656 // Switch to sRGB
657 recreatePbufferInSrgbColorspace();
658 EGLint colorspace = 0;
659 eglQuerySurface(window->getDisplay(), mPbuffer, EGL_GL_COLORSPACE, &colorspace);
660 EXPECT_EQ(colorspace, EGL_GL_COLORSPACE_SRGB_KHR);
661
662 // Clear the Pbuffer surface with `kLinearColor`
663 eglMakeCurrent(window->getDisplay(), mPbuffer, mPbuffer, window->getContext());
664 ASSERT_EGL_SUCCESS();
665
666 glViewport(0, 0, static_cast<GLsizei>(mPbufferSize), static_cast<GLsizei>(mPbufferSize));
667 glClearColor(kLinearColor[0] / 255.0f, kLinearColor[1] / 255.0f, kLinearColor[2] / 255.0f,
668 kLinearColor[3] / 255.0f);
669 glClear(GL_COLOR_BUFFER_BIT);
670 ASSERT_GL_NO_ERROR();
671
672 // Expect glReadPixels to be `kSrgbColor` with a tolerance of 1
673 EXPECT_PIXEL_NEAR(static_cast<GLint>(mPbufferSize) / 2, static_cast<GLint>(mPbufferSize) / 2,
674 kSrgbColor[0], kSrgbColor[1], kSrgbColor[2], kSrgbColor[3], 1);
675
676 window->makeCurrent();
677
678 // Create a texture and bind the Pbuffer to it
679 GLuint texture = 0;
680 glGenTextures(1, &texture);
681 glBindTexture(GL_TEXTURE_2D, texture);
682 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
683 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
684 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
685 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
686 EXPECT_GL_NO_ERROR();
687
688 eglBindTexImage(window->getDisplay(), mPbuffer, EGL_BACK_BUFFER);
689 glViewport(0, 0, getWindowWidth(), getWindowHeight());
690 ASSERT_EGL_SUCCESS();
691
692 // Sample from a texture with `kSrgbColor` data and render into a surface in linear colorspace.
693 glUseProgram(mTextureProgram);
694 glUniform1i(mTextureUniformLocation, 0);
695
696 drawQuad(mTextureProgram, "position", 0.5f);
697 EXPECT_GL_NO_ERROR();
698
699 // Unbind the texture
700 eglReleaseTexImage(window->getDisplay(), mPbuffer, EGL_BACK_BUFFER);
701 ASSERT_EGL_SUCCESS();
702
703 // Expect glReadPixels to be `kLinearColor` with a tolerance of 1
704 EXPECT_PIXEL_NEAR(getWindowWidth() / 2, getWindowHeight() / 2, kLinearColor[0], kLinearColor[1],
705 kLinearColor[2], kLinearColor[3], 1);
706
707 glDeleteTextures(1, &texture);
708 }
709
710 // Test clearing a Pbuffer in sRGB colorspace and checking the color is correct.
711 // Then bind the Pbuffer to a texture and verify it renders correctly.
712 // Then change texture state to skip decode and verify it renders correctly.
TEST_P(PbufferTest,ClearAndBindTexImageSrgbSkipDecode)713 TEST_P(PbufferTest, ClearAndBindTexImageSrgbSkipDecode)
714 {
715 EGLWindow *window = getEGLWindow();
716
717 // Test skipped because Pbuffers are not supported or Pbuffer does not support binding to RGBA
718 // textures.
719 ANGLE_SKIP_TEST_IF(!mSupportsPbuffers || !mSupportsBindTexImage);
720 ANGLE_SKIP_TEST_IF(
721 !IsEGLDisplayExtensionEnabled(window->getDisplay(), "EGL_KHR_gl_colorspace"));
722 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_sRGB_decode"));
723 // Possible GLES driver bug on Pixel devices: http://anglebug.com/42263865
724 ANGLE_SKIP_TEST_IF((IsPixel2() || IsPixel4()) && IsOpenGLES());
725
726 GLubyte kLinearColor[] = {132, 55, 219, 255};
727 GLubyte kSrgbColor[] = {190, 128, 238, 255};
728
729 // Switch to sRGB
730 recreatePbufferInSrgbColorspace();
731 EGLint colorspace = 0;
732 eglQuerySurface(window->getDisplay(), mPbuffer, EGL_GL_COLORSPACE, &colorspace);
733 EXPECT_EQ(colorspace, EGL_GL_COLORSPACE_SRGB_KHR);
734
735 // Clear the Pbuffer surface with `kLinearColor`
736 eglMakeCurrent(window->getDisplay(), mPbuffer, mPbuffer, window->getContext());
737 ASSERT_EGL_SUCCESS();
738
739 glViewport(0, 0, static_cast<GLsizei>(mPbufferSize), static_cast<GLsizei>(mPbufferSize));
740 glClearColor(kLinearColor[0] / 255.0f, kLinearColor[1] / 255.0f, kLinearColor[2] / 255.0f,
741 kLinearColor[3] / 255.0f);
742 glClear(GL_COLOR_BUFFER_BIT);
743 ASSERT_GL_NO_ERROR();
744
745 // Expect glReadPixels to be `kSrgbColor` with a tolerance of 1
746 EXPECT_PIXEL_NEAR(static_cast<GLint>(mPbufferSize) / 2, static_cast<GLint>(mPbufferSize) / 2,
747 kSrgbColor[0], kSrgbColor[1], kSrgbColor[2], kSrgbColor[3], 1);
748
749 window->makeCurrent();
750
751 // Create a texture and bind the Pbuffer to it
752 GLuint texture = 0;
753 glGenTextures(1, &texture);
754 glBindTexture(GL_TEXTURE_2D, texture);
755 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
756 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
757 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
758 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
759 EXPECT_GL_NO_ERROR();
760
761 eglBindTexImage(window->getDisplay(), mPbuffer, EGL_BACK_BUFFER);
762 glViewport(0, 0, getWindowWidth(), getWindowHeight());
763 ASSERT_EGL_SUCCESS();
764
765 // Sample from a texture with `kSrgbColor` data and render into a surface in linear colorspace.
766 glUseProgram(mTextureProgram);
767 glUniform1i(mTextureUniformLocation, 0);
768
769 drawQuad(mTextureProgram, "position", 0.5f);
770 EXPECT_GL_NO_ERROR();
771
772 // Expect glReadPixels to be `kLinearColor` with a tolerance of 1
773 EXPECT_PIXEL_NEAR(getWindowWidth() / 2, getWindowHeight() / 2, kLinearColor[0], kLinearColor[1],
774 kLinearColor[2], kLinearColor[3], 1);
775
776 // Set skip decode for the texture
777 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT);
778 drawQuad(mTextureProgram, "position", 0.5f);
779
780 // Texture is in skip decode mode, expect glReadPixels to be `kSrgbColor` with tolerance of 1
781 EXPECT_PIXEL_NEAR(getWindowWidth() / 2, getWindowHeight() / 2, kSrgbColor[0], kSrgbColor[1],
782 kSrgbColor[2], kSrgbColor[3], 1);
783
784 // Unbind the texture
785 eglReleaseTexImage(window->getDisplay(), mPbuffer, EGL_BACK_BUFFER);
786 ASSERT_EGL_SUCCESS();
787
788 glDeleteTextures(1, &texture);
789 }
790
791 // Verify that when eglBind/ReleaseTexImage are called, the texture images are freed and their
792 // size information is correctly updated.
TEST_P(PbufferTest,TextureSizeReset)793 TEST_P(PbufferTest, TextureSizeReset)
794 {
795 ANGLE_SKIP_TEST_IF(!mSupportsPbuffers);
796 ANGLE_SKIP_TEST_IF(!mSupportsBindTexImage);
797 ANGLE_SKIP_TEST_IF(IsARM64() && IsWindows() && IsD3D());
798
799 GLTexture texture;
800 glBindTexture(GL_TEXTURE_2D, texture);
801 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
802 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
803 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
804 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
805 EXPECT_GL_NO_ERROR();
806
807 glUseProgram(mTextureProgram);
808 glUniform1i(mTextureUniformLocation, 0);
809
810 // Fill the texture with white pixels
811 std::vector<GLColor> whitePixels(mPbufferSize * mPbufferSize, GLColor::white);
812 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, static_cast<GLsizei>(mPbufferSize),
813 static_cast<GLsizei>(mPbufferSize), 0, GL_RGBA, GL_UNSIGNED_BYTE,
814 whitePixels.data());
815 EXPECT_GL_NO_ERROR();
816
817 // Draw the white texture and verify that the pixels are correct
818 drawQuad(mTextureProgram, "position", 0.5f);
819 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white);
820
821 // Bind the EGL surface and draw with it, results are undefined since nothing has
822 // been written to it
823 EGLWindow *window = getEGLWindow();
824 eglBindTexImage(window->getDisplay(), mPbuffer, EGL_BACK_BUFFER);
825 drawQuad(mTextureProgram, "position", 0.5f);
826 EXPECT_GL_NO_ERROR();
827
828 // Clear the back buffer to a unique color (green)
829 glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
830 glClear(GL_COLOR_BUFFER_BIT);
831 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
832
833 // Unbind the EGL surface and try to draw with the texture again, the texture's size should
834 // now be zero and incomplete so the back buffer should be black
835 eglReleaseTexImage(window->getDisplay(), mPbuffer, EGL_BACK_BUFFER);
836 drawQuad(mTextureProgram, "position", 0.5f);
837 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
838 }
839
840 // Bind a Pbuffer, redefine the texture, and verify it renders correctly
TEST_P(PbufferTest,BindTexImageAndRedefineTexture)841 TEST_P(PbufferTest, BindTexImageAndRedefineTexture)
842 {
843 // Test skipped because Pbuffers are not supported or Pbuffer does not support binding to RGBA
844 // textures.
845 ANGLE_SKIP_TEST_IF(!mSupportsPbuffers || !mSupportsBindTexImage);
846
847 EGLWindow *window = getEGLWindow();
848
849 // Apply the Pbuffer and clear it to purple
850 eglMakeCurrent(window->getDisplay(), mPbuffer, mPbuffer, window->getContext());
851 ASSERT_EGL_SUCCESS();
852
853 glViewport(0, 0, static_cast<GLsizei>(mPbufferSize), static_cast<GLsizei>(mPbufferSize));
854 glClearColor(1.0f, 0.0f, 1.0f, 1.0f);
855 glClear(GL_COLOR_BUFFER_BIT);
856 ASSERT_GL_NO_ERROR();
857
858 EXPECT_PIXEL_EQ(static_cast<GLint>(mPbufferSize) / 2, static_cast<GLint>(mPbufferSize) / 2, 255,
859 0, 255, 255);
860
861 // Apply the window surface
862 window->makeCurrent();
863
864 // Create a texture and bind the Pbuffer to it
865 GLuint texture = 0;
866 glGenTextures(1, &texture);
867 glBindTexture(GL_TEXTURE_2D, texture);
868 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
869 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
870 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
871 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
872 EXPECT_GL_NO_ERROR();
873
874 eglBindTexImage(window->getDisplay(), mPbuffer, EGL_BACK_BUFFER);
875 glViewport(0, 0, getWindowWidth(), getWindowHeight());
876 ASSERT_EGL_SUCCESS();
877
878 // Redefine the texture
879 unsigned int pixelValue = 0xFFFF00FF;
880 std::vector<unsigned int> pixelData(getWindowWidth() * getWindowHeight(), pixelValue);
881 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, getWindowWidth(), getWindowHeight(), 0, GL_RGBA,
882 GL_UNSIGNED_BYTE, &pixelData[0]);
883
884 // Draw a quad and verify that it is magenta
885 glUseProgram(mTextureProgram);
886 glUniform1i(mTextureUniformLocation, 0);
887
888 drawQuad(mTextureProgram, "position", 0.5f);
889 EXPECT_GL_NO_ERROR();
890
891 // Verify that magenta was drawn
892 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 255, 0, 255, 255);
893
894 glDeleteTextures(1, &texture);
895 }
896
897 // Bind the Pbuffer to a texture, use that texture as Framebuffer color attachment and then
898 // destroy framebuffer, texture and Pbuffer.
TEST_P(PbufferTest,UseAsFramebufferColorThenDestroy)899 TEST_P(PbufferTest, UseAsFramebufferColorThenDestroy)
900 {
901 // Test skipped because Pbuffers are not supported or Pbuffer does not support binding to RGBA
902 // textures.
903 ANGLE_SKIP_TEST_IF(!mSupportsPbuffers || !mSupportsBindTexImage);
904
905 EGLWindow *window = getEGLWindow();
906
907 // Apply the window surface
908 window->makeCurrent();
909
910 // Create a texture and bind the Pbuffer to it
911 GLuint texture = 0;
912 glGenTextures(1, &texture);
913 glBindTexture(GL_TEXTURE_2D, texture);
914 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
915 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
916 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
917 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
918 EXPECT_GL_NO_ERROR();
919
920 eglBindTexImage(window->getDisplay(), mPbuffer, EGL_BACK_BUFFER);
921 ASSERT_EGL_SUCCESS();
922
923 // Create Framebuffer and use texture as color attachment
924 GLuint fbo;
925 glGenFramebuffers(1, &fbo);
926 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
927 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
928 GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
929 ANGLE_SKIP_TEST_IF(status == GL_FRAMEBUFFER_UNSUPPORTED);
930 EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, status);
931 glDisable(GL_DEPTH_TEST);
932 glViewport(0, 0, static_cast<GLsizei>(mPbufferSize), static_cast<GLsizei>(mPbufferSize));
933 ASSERT_GL_NO_ERROR();
934
935 // Draw a quad in order to open a RenderPass
936 ANGLE_GL_PROGRAM(redProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
937 glUseProgram(redProgram);
938 ASSERT_GL_NO_ERROR();
939
940 drawQuad(redProgram, essl1_shaders::PositionAttrib(), 0.5f);
941 ASSERT_GL_NO_ERROR();
942
943 // Unbind resources
944 glBindFramebuffer(GL_FRAMEBUFFER, 0);
945 glBindTexture(GL_TEXTURE_2D, 0);
946 glViewport(0, 0, getWindowWidth(), getWindowHeight());
947 ASSERT_GL_NO_ERROR();
948
949 // Delete resources
950 glDeleteFramebuffers(1, &fbo);
951 glDeleteTextures(1, &texture);
952 ASSERT_GL_NO_ERROR();
953
954 // Destroy Pbuffer
955 destroyPbuffer();
956
957 // Finish work
958 glFinish();
959 ASSERT_GL_NO_ERROR();
960 }
961
962 // Bind the Pbuffer to a texture, use that texture as Framebuffer color attachment and then
963 // destroy framebuffer, texture and Pbuffer. A bound but released TexImages are destroyed
964 // only when the binding is overwritten.
TEST_P(PbufferTest,UseAsFramebufferColorThenDeferredDestroy)965 TEST_P(PbufferTest, UseAsFramebufferColorThenDeferredDestroy)
966 {
967 // Test skipped because Pbuffers are not supported or Pbuffer does not support binding to RGBA
968 // textures.
969 ANGLE_SKIP_TEST_IF(!mSupportsPbuffers || !mSupportsBindTexImage);
970 EGLWindow *window = getEGLWindow();
971 window->makeCurrent();
972
973 // Create a texture and bind the Pbuffer to it
974 GLTexture texture;
975 glBindTexture(GL_TEXTURE_2D, texture);
976 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
977 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
978 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
979 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
980 EXPECT_GL_NO_ERROR();
981
982 EGLSurface otherPbuffer = createTestPbufferSurface();
983 ASSERT_EGL_SUCCESS();
984 ASSERT_NE(otherPbuffer, EGL_NO_SURFACE);
985
986 eglBindTexImage(window->getDisplay(), mPbuffer, EGL_BACK_BUFFER);
987 ASSERT_EGL_SUCCESS();
988 eglBindTexImage(window->getDisplay(), mPbuffer, EGL_BACK_BUFFER);
989 ASSERT_EGL_ERROR(EGL_BAD_ACCESS);
990 eglBindTexImage(window->getDisplay(), otherPbuffer, EGL_BACK_BUFFER);
991 ASSERT_EGL_SUCCESS();
992 eglReleaseTexImage(window->getDisplay(), otherPbuffer, EGL_BACK_BUFFER);
993 ASSERT_EGL_SUCCESS();
994 eglBindTexImage(window->getDisplay(), mPbuffer, EGL_BACK_BUFFER);
995 ASSERT_EGL_SUCCESS();
996 eglReleaseTexImage(window->getDisplay(), mPbuffer, EGL_BACK_BUFFER);
997 ASSERT_EGL_SUCCESS();
998
999 destroyPbuffer();
1000 destroyTestPbufferSurface(otherPbuffer);
1001 ASSERT_EGL_SUCCESS();
1002
1003 // Finish work
1004 glFinish();
1005 ASSERT_GL_NO_ERROR();
1006 }
1007
1008 // Test that passing colorspace attributes do not generate EGL validation errors
1009 // when EGL_ANGLE_colorspace_attribute_passthrough extension is supported.
TEST_P(PbufferColorspaceTest,CreateSurfaceWithColorspace)1010 TEST_P(PbufferColorspaceTest, CreateSurfaceWithColorspace)
1011 {
1012 EGLDisplay dpy = getEGLWindow()->getDisplay();
1013 const bool extensionSupported =
1014 IsEGLDisplayExtensionEnabled(dpy, "EGL_EXT_gl_colorspace_display_p3_passthrough");
1015 const bool passthroughExtensionSupported =
1016 IsEGLDisplayExtensionEnabled(dpy, "EGL_ANGLE_colorspace_attribute_passthrough");
1017
1018 EGLSurface pbufferSurface = EGL_NO_SURFACE;
1019 const EGLint pBufferAttributes[] = {
1020 EGL_WIDTH, static_cast<EGLint>(mPbufferSize),
1021 EGL_HEIGHT, static_cast<EGLint>(mPbufferSize),
1022 EGL_GL_COLORSPACE, EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT,
1023 EGL_NONE, EGL_NONE,
1024 };
1025
1026 pbufferSurface = eglCreatePbufferSurface(dpy, getEGLWindow()->getConfig(), pBufferAttributes);
1027 if (extensionSupported)
1028 {
1029 // If EGL_EXT_gl_colorspace_display_p3_passthrough is supported
1030 // "pbufferSurface" should be a valid pbuffer surface.
1031 ASSERT_NE(pbufferSurface, EGL_NO_SURFACE);
1032 ASSERT_EGL_SUCCESS();
1033 }
1034 else if (!extensionSupported && passthroughExtensionSupported)
1035 {
1036 // If EGL_ANGLE_colorspace_attribute_passthrough was the only extension supported
1037 // we should not expect a validation error.
1038 ASSERT_NE(eglGetError(), EGL_BAD_ATTRIBUTE);
1039 }
1040 else
1041 {
1042 // Otherwise we should expect an EGL_BAD_ATTRIBUTE validation error.
1043 ASSERT_EGL_ERROR(EGL_BAD_ATTRIBUTE);
1044 }
1045
1046 // Cleanup
1047 if (pbufferSurface != EGL_NO_SURFACE)
1048 {
1049 eglDestroySurface(dpy, pbufferSurface);
1050 }
1051 }
1052
1053 ANGLE_INSTANTIATE_TEST_ES2(PbufferTest);
1054
1055 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(PbufferColorspaceTest);
1056 ANGLE_INSTANTIATE_TEST_ES3_AND(PbufferColorspaceTest,
1057 ES3_VULKAN().enable(Feature::EglColorspaceAttributePassthrough));
1058