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 EGLint bindToTextureRGBA = 0;
66 eglGetConfigAttrib(window->getDisplay(), window->getConfig(), EGL_BIND_TO_TEXTURE_RGBA,
67 &bindToTextureRGBA);
68 mSupportsBindTexImage = (bindToTextureRGBA == EGL_TRUE);
69
70 const EGLint pBufferAttributes[] = {
71 EGL_WIDTH, static_cast<EGLint>(mPbufferSize),
72 EGL_HEIGHT, static_cast<EGLint>(mPbufferSize),
73 EGL_TEXTURE_FORMAT, mSupportsBindTexImage ? EGL_TEXTURE_RGBA : EGL_NO_TEXTURE,
74 EGL_TEXTURE_TARGET, mSupportsBindTexImage ? EGL_TEXTURE_2D : EGL_NO_TEXTURE,
75 EGL_NONE, EGL_NONE,
76 };
77
78 mPbuffer =
79 eglCreatePbufferSurface(window->getDisplay(), window->getConfig(), pBufferAttributes);
80 if (mSupportsPbuffers)
81 {
82 ASSERT_NE(mPbuffer, EGL_NO_SURFACE);
83 ASSERT_EGL_SUCCESS();
84 }
85 else
86 {
87 ASSERT_EQ(mPbuffer, EGL_NO_SURFACE);
88 ASSERT_EGL_ERROR(EGL_BAD_MATCH);
89 }
90
91 ASSERT_GL_NO_ERROR();
92 }
93
testTearDown()94 void testTearDown() override
95 {
96 glDeleteProgram(mTextureProgram);
97
98 destroyPbuffer();
99 }
100
destroyPbuffer()101 void destroyPbuffer()
102 {
103 if (mPbuffer)
104 {
105 EGLWindow *window = getEGLWindow();
106 eglDestroySurface(window->getDisplay(), mPbuffer);
107 }
108 }
109
recreatePbufferInSrgbColorspace()110 void recreatePbufferInSrgbColorspace()
111 {
112 EGLWindow *window = getEGLWindow();
113
114 destroyPbuffer();
115
116 const EGLint pBufferSrgbAttributes[] = {
117 EGL_WIDTH,
118 static_cast<EGLint>(mPbufferSize),
119 EGL_HEIGHT,
120 static_cast<EGLint>(mPbufferSize),
121 EGL_TEXTURE_FORMAT,
122 mSupportsBindTexImage ? EGL_TEXTURE_RGBA : EGL_NO_TEXTURE,
123 EGL_TEXTURE_TARGET,
124 mSupportsBindTexImage ? EGL_TEXTURE_2D : EGL_NO_TEXTURE,
125 EGL_GL_COLORSPACE_KHR,
126 EGL_GL_COLORSPACE_SRGB_KHR,
127 EGL_NONE,
128 EGL_NONE,
129 };
130
131 mPbuffer = eglCreatePbufferSurface(window->getDisplay(), window->getConfig(),
132 pBufferSrgbAttributes);
133 }
134
135 GLuint mTextureProgram;
136 GLint mTextureUniformLocation;
137
138 const size_t mPbufferSize = 32;
139 EGLSurface mPbuffer = EGL_NO_SURFACE;
140 bool mSupportsPbuffers;
141 bool mSupportsBindTexImage;
142 };
143
144 class PbufferColorspaceTest : public PbufferTest
145 {};
146
147 // Test clearing a Pbuffer and checking the color is correct
TEST_P(PbufferTest,Clearing)148 TEST_P(PbufferTest, Clearing)
149 {
150 ANGLE_SKIP_TEST_IF(!mSupportsPbuffers);
151
152 EGLWindow *window = getEGLWindow();
153
154 // Clear the window surface to blue and verify
155 window->makeCurrent();
156 ASSERT_EGL_SUCCESS();
157
158 glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
159 glClear(GL_COLOR_BUFFER_BIT);
160 ASSERT_GL_NO_ERROR();
161 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue);
162
163 // Apply the Pbuffer and clear it to purple and verify
164 eglMakeCurrent(window->getDisplay(), mPbuffer, mPbuffer, window->getContext());
165 ASSERT_EGL_SUCCESS();
166
167 glViewport(0, 0, static_cast<GLsizei>(mPbufferSize), static_cast<GLsizei>(mPbufferSize));
168 glClearColor(1.0f, 0.0f, 1.0f, 1.0f);
169 glClear(GL_COLOR_BUFFER_BIT);
170 ASSERT_GL_NO_ERROR();
171 EXPECT_PIXEL_EQ(static_cast<GLint>(mPbufferSize) / 2, static_cast<GLint>(mPbufferSize) / 2, 255,
172 0, 255, 255);
173
174 // Rebind the window surface and verify that it is still blue
175 window->makeCurrent();
176 ASSERT_EGL_SUCCESS();
177 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 255, 255);
178 }
179
180 // Bind the Pbuffer to a texture and verify it renders correctly
TEST_P(PbufferTest,BindTexImage)181 TEST_P(PbufferTest, BindTexImage)
182 {
183 // Test skipped because Pbuffers are not supported or Pbuffer does not support binding to RGBA
184 // textures.
185 ANGLE_SKIP_TEST_IF(!mSupportsPbuffers || !mSupportsBindTexImage);
186
187 EGLWindow *window = getEGLWindow();
188
189 // Apply the Pbuffer and clear it to purple
190 eglMakeCurrent(window->getDisplay(), mPbuffer, mPbuffer, window->getContext());
191 ASSERT_EGL_SUCCESS();
192
193 glViewport(0, 0, static_cast<GLsizei>(mPbufferSize), static_cast<GLsizei>(mPbufferSize));
194 glClearColor(1.0f, 0.0f, 1.0f, 1.0f);
195 glClear(GL_COLOR_BUFFER_BIT);
196 ASSERT_GL_NO_ERROR();
197
198 EXPECT_PIXEL_COLOR_EQ(static_cast<GLint>(mPbufferSize) / 2,
199 static_cast<GLint>(mPbufferSize) / 2, GLColor::magenta);
200
201 // Apply the window surface
202 window->makeCurrent();
203
204 // Create a texture and bind the Pbuffer to it
205 GLuint texture = 0;
206 glGenTextures(1, &texture);
207 glBindTexture(GL_TEXTURE_2D, texture);
208 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
209 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
210 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
211 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
212 EXPECT_GL_NO_ERROR();
213
214 eglBindTexImage(window->getDisplay(), mPbuffer, EGL_BACK_BUFFER);
215 glViewport(0, 0, getWindowWidth(), getWindowHeight());
216 ASSERT_EGL_SUCCESS();
217
218 // Draw a quad and verify that it is purple
219 glUseProgram(mTextureProgram);
220 glUniform1i(mTextureUniformLocation, 0);
221
222 drawQuad(mTextureProgram, "position", 0.5f);
223 EXPECT_GL_NO_ERROR();
224
225 // Unbind the texture
226 eglReleaseTexImage(window->getDisplay(), mPbuffer, EGL_BACK_BUFFER);
227 ASSERT_EGL_SUCCESS();
228
229 // Verify that purple was drawn
230 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 255, 0, 255, 255);
231
232 glDeleteTextures(1, &texture);
233 }
234
235 // Verify that binding a pbuffer works after using a texture normally.
TEST_P(PbufferTest,BindTexImageAfterTexImage)236 TEST_P(PbufferTest, BindTexImageAfterTexImage)
237 {
238 // Test skipped because Pbuffers are not supported or Pbuffer does not support binding to RGBA
239 // textures.
240 ANGLE_SKIP_TEST_IF(!mSupportsPbuffers || !mSupportsBindTexImage);
241
242 EGLWindow *window = getEGLWindow();
243
244 // Apply the Pbuffer and clear it to magenta
245 eglMakeCurrent(window->getDisplay(), mPbuffer, mPbuffer, window->getContext());
246 ASSERT_EGL_SUCCESS();
247
248 glViewport(0, 0, static_cast<GLsizei>(mPbufferSize), static_cast<GLsizei>(mPbufferSize));
249 glClearColor(1.0f, 0.0f, 1.0f, 1.0f);
250 glClear(GL_COLOR_BUFFER_BIT);
251 ASSERT_GL_NO_ERROR();
252
253 EXPECT_PIXEL_COLOR_EQ(static_cast<GLint>(mPbufferSize) / 2,
254 static_cast<GLint>(mPbufferSize) / 2, GLColor::magenta);
255
256 // Apply the window surface
257 window->makeCurrent();
258 glViewport(0, 0, getWindowWidth(), getWindowHeight());
259
260 // Create a simple blue texture.
261 GLTexture texture;
262 glBindTexture(GL_TEXTURE_2D, texture);
263 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
264 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
265 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
266 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
267 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::blue);
268 EXPECT_GL_NO_ERROR();
269
270 // Draw a quad and verify blue
271 glUseProgram(mTextureProgram);
272 glUniform1i(mTextureUniformLocation, 0);
273 drawQuad(mTextureProgram, "position", 0.5f);
274 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
275
276 // Bind the Pbuffer to the texture
277 eglBindTexImage(window->getDisplay(), mPbuffer, EGL_BACK_BUFFER);
278 ASSERT_EGL_SUCCESS();
279
280 // Draw a quad and verify magenta
281 drawQuad(mTextureProgram, "position", 0.5f);
282 EXPECT_GL_NO_ERROR();
283 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::magenta);
284
285 // Unbind the texture
286 eglReleaseTexImage(window->getDisplay(), mPbuffer, EGL_BACK_BUFFER);
287 ASSERT_EGL_SUCCESS();
288 }
289
290 // Test clearing a Pbuffer in sRGB colorspace and checking the color is correct.
291 // Then bind the Pbuffer to a texture and verify it renders correctly
TEST_P(PbufferTest,ClearAndBindTexImageSrgb)292 TEST_P(PbufferTest, ClearAndBindTexImageSrgb)
293 {
294 EGLWindow *window = getEGLWindow();
295
296 // Test skipped because Pbuffers are not supported or Pbuffer does not support binding to RGBA
297 // textures.
298 ANGLE_SKIP_TEST_IF(!mSupportsPbuffers || !mSupportsBindTexImage);
299 ANGLE_SKIP_TEST_IF(
300 !IsEGLDisplayExtensionEnabled(window->getDisplay(), "EGL_KHR_gl_colorspace"));
301 // Possible GLES driver bug on Pixel2 devices: http://anglebug.com/5321
302 ANGLE_SKIP_TEST_IF(IsPixel2() && IsOpenGLES());
303
304 GLubyte kLinearColor[] = {132, 55, 219, 255};
305 GLubyte kSrgbColor[] = {190, 128, 238, 255};
306
307 // Switch to sRGB
308 recreatePbufferInSrgbColorspace();
309 EGLint colorspace = 0;
310 eglQuerySurface(window->getDisplay(), mPbuffer, EGL_GL_COLORSPACE, &colorspace);
311 EXPECT_EQ(colorspace, EGL_GL_COLORSPACE_SRGB_KHR);
312
313 // Clear the Pbuffer surface with `kLinearColor`
314 eglMakeCurrent(window->getDisplay(), mPbuffer, mPbuffer, window->getContext());
315 ASSERT_EGL_SUCCESS();
316
317 glViewport(0, 0, static_cast<GLsizei>(mPbufferSize), static_cast<GLsizei>(mPbufferSize));
318 glClearColor(kLinearColor[0] / 255.0f, kLinearColor[1] / 255.0f, kLinearColor[2] / 255.0f,
319 kLinearColor[3] / 255.0f);
320 glClear(GL_COLOR_BUFFER_BIT);
321 ASSERT_GL_NO_ERROR();
322
323 // Expect glReadPixels to be `kSrgbColor` with a tolerance of 1
324 EXPECT_PIXEL_NEAR(static_cast<GLint>(mPbufferSize) / 2, static_cast<GLint>(mPbufferSize) / 2,
325 kSrgbColor[0], kSrgbColor[1], kSrgbColor[2], kSrgbColor[3], 1);
326
327 window->makeCurrent();
328
329 // Create a texture and bind the Pbuffer to it
330 GLuint texture = 0;
331 glGenTextures(1, &texture);
332 glBindTexture(GL_TEXTURE_2D, texture);
333 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
334 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
335 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
336 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
337 EXPECT_GL_NO_ERROR();
338
339 eglBindTexImage(window->getDisplay(), mPbuffer, EGL_BACK_BUFFER);
340 glViewport(0, 0, getWindowWidth(), getWindowHeight());
341 ASSERT_EGL_SUCCESS();
342
343 // Sample from a texture with `kSrgbColor` data and render into a surface in linear colorspace.
344 glUseProgram(mTextureProgram);
345 glUniform1i(mTextureUniformLocation, 0);
346
347 drawQuad(mTextureProgram, "position", 0.5f);
348 EXPECT_GL_NO_ERROR();
349
350 // Unbind the texture
351 eglReleaseTexImage(window->getDisplay(), mPbuffer, EGL_BACK_BUFFER);
352 ASSERT_EGL_SUCCESS();
353
354 // Expect glReadPixels to be `kLinearColor` with a tolerance of 1
355 EXPECT_PIXEL_NEAR(getWindowWidth() / 2, getWindowHeight() / 2, kLinearColor[0], kLinearColor[1],
356 kLinearColor[2], kLinearColor[3], 1);
357
358 glDeleteTextures(1, &texture);
359 }
360
361 // Test clearing a Pbuffer in sRGB colorspace and checking the color is correct.
362 // Then bind the Pbuffer to a texture and verify it renders correctly.
363 // Then change texture state to skip decode and verify it renders correctly.
TEST_P(PbufferTest,ClearAndBindTexImageSrgbSkipDecode)364 TEST_P(PbufferTest, ClearAndBindTexImageSrgbSkipDecode)
365 {
366 EGLWindow *window = getEGLWindow();
367
368 // Test skipped because Pbuffers are not supported or Pbuffer does not support binding to RGBA
369 // textures.
370 ANGLE_SKIP_TEST_IF(!mSupportsPbuffers || !mSupportsBindTexImage);
371 ANGLE_SKIP_TEST_IF(
372 !IsEGLDisplayExtensionEnabled(window->getDisplay(), "EGL_KHR_gl_colorspace"));
373 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_sRGB_decode"));
374 // Possible GLES driver bug on Pixel devices: http://anglebug.com/5321
375 ANGLE_SKIP_TEST_IF((IsPixel2() || IsPixel4()) && IsOpenGLES());
376
377 GLubyte kLinearColor[] = {132, 55, 219, 255};
378 GLubyte kSrgbColor[] = {190, 128, 238, 255};
379
380 // Switch to sRGB
381 recreatePbufferInSrgbColorspace();
382 EGLint colorspace = 0;
383 eglQuerySurface(window->getDisplay(), mPbuffer, EGL_GL_COLORSPACE, &colorspace);
384 EXPECT_EQ(colorspace, EGL_GL_COLORSPACE_SRGB_KHR);
385
386 // Clear the Pbuffer surface with `kLinearColor`
387 eglMakeCurrent(window->getDisplay(), mPbuffer, mPbuffer, window->getContext());
388 ASSERT_EGL_SUCCESS();
389
390 glViewport(0, 0, static_cast<GLsizei>(mPbufferSize), static_cast<GLsizei>(mPbufferSize));
391 glClearColor(kLinearColor[0] / 255.0f, kLinearColor[1] / 255.0f, kLinearColor[2] / 255.0f,
392 kLinearColor[3] / 255.0f);
393 glClear(GL_COLOR_BUFFER_BIT);
394 ASSERT_GL_NO_ERROR();
395
396 // Expect glReadPixels to be `kSrgbColor` with a tolerance of 1
397 EXPECT_PIXEL_NEAR(static_cast<GLint>(mPbufferSize) / 2, static_cast<GLint>(mPbufferSize) / 2,
398 kSrgbColor[0], kSrgbColor[1], kSrgbColor[2], kSrgbColor[3], 1);
399
400 window->makeCurrent();
401
402 // Create a texture and bind the Pbuffer to it
403 GLuint texture = 0;
404 glGenTextures(1, &texture);
405 glBindTexture(GL_TEXTURE_2D, texture);
406 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
407 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
408 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
409 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
410 EXPECT_GL_NO_ERROR();
411
412 eglBindTexImage(window->getDisplay(), mPbuffer, EGL_BACK_BUFFER);
413 glViewport(0, 0, getWindowWidth(), getWindowHeight());
414 ASSERT_EGL_SUCCESS();
415
416 // Sample from a texture with `kSrgbColor` data and render into a surface in linear colorspace.
417 glUseProgram(mTextureProgram);
418 glUniform1i(mTextureUniformLocation, 0);
419
420 drawQuad(mTextureProgram, "position", 0.5f);
421 EXPECT_GL_NO_ERROR();
422
423 // Expect glReadPixels to be `kLinearColor` with a tolerance of 1
424 EXPECT_PIXEL_NEAR(getWindowWidth() / 2, getWindowHeight() / 2, kLinearColor[0], kLinearColor[1],
425 kLinearColor[2], kLinearColor[3], 1);
426
427 // Set skip decode for the texture
428 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT);
429 drawQuad(mTextureProgram, "position", 0.5f);
430
431 // Texture is in skip decode mode, expect glReadPixels to be `kSrgbColor` with tolerance of 1
432 EXPECT_PIXEL_NEAR(getWindowWidth() / 2, getWindowHeight() / 2, kSrgbColor[0], kSrgbColor[1],
433 kSrgbColor[2], kSrgbColor[3], 1);
434
435 // Unbind the texture
436 eglReleaseTexImage(window->getDisplay(), mPbuffer, EGL_BACK_BUFFER);
437 ASSERT_EGL_SUCCESS();
438
439 glDeleteTextures(1, &texture);
440 }
441
442 // Verify that when eglBind/ReleaseTexImage are called, the texture images are freed and their
443 // size information is correctly updated.
TEST_P(PbufferTest,TextureSizeReset)444 TEST_P(PbufferTest, TextureSizeReset)
445 {
446 ANGLE_SKIP_TEST_IF(!mSupportsPbuffers);
447 ANGLE_SKIP_TEST_IF(!mSupportsBindTexImage);
448 ANGLE_SKIP_TEST_IF(IsARM64() && IsWindows() && IsD3D());
449
450 GLTexture texture;
451 glBindTexture(GL_TEXTURE_2D, texture);
452 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
453 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
454 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
455 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
456 EXPECT_GL_NO_ERROR();
457
458 glUseProgram(mTextureProgram);
459 glUniform1i(mTextureUniformLocation, 0);
460
461 // Fill the texture with white pixels
462 std::vector<GLColor> whitePixels(mPbufferSize * mPbufferSize, GLColor::white);
463 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, static_cast<GLsizei>(mPbufferSize),
464 static_cast<GLsizei>(mPbufferSize), 0, GL_RGBA, GL_UNSIGNED_BYTE,
465 whitePixels.data());
466 EXPECT_GL_NO_ERROR();
467
468 // Draw the white texture and verify that the pixels are correct
469 drawQuad(mTextureProgram, "position", 0.5f);
470 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white);
471
472 // Bind the EGL surface and draw with it, results are undefined since nothing has
473 // been written to it
474 EGLWindow *window = getEGLWindow();
475 eglBindTexImage(window->getDisplay(), mPbuffer, EGL_BACK_BUFFER);
476 drawQuad(mTextureProgram, "position", 0.5f);
477 EXPECT_GL_NO_ERROR();
478
479 // Clear the back buffer to a unique color (green)
480 glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
481 glClear(GL_COLOR_BUFFER_BIT);
482 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
483
484 // Unbind the EGL surface and try to draw with the texture again, the texture's size should
485 // now be zero and incomplete so the back buffer should be black
486 eglReleaseTexImage(window->getDisplay(), mPbuffer, EGL_BACK_BUFFER);
487 drawQuad(mTextureProgram, "position", 0.5f);
488 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
489 }
490
491 // Bind a Pbuffer, redefine the texture, and verify it renders correctly
TEST_P(PbufferTest,BindTexImageAndRedefineTexture)492 TEST_P(PbufferTest, BindTexImageAndRedefineTexture)
493 {
494 // Test skipped because Pbuffers are not supported or Pbuffer does not support binding to RGBA
495 // textures.
496 ANGLE_SKIP_TEST_IF(!mSupportsPbuffers || !mSupportsBindTexImage);
497
498 EGLWindow *window = getEGLWindow();
499
500 // Apply the Pbuffer and clear it to purple
501 eglMakeCurrent(window->getDisplay(), mPbuffer, mPbuffer, window->getContext());
502 ASSERT_EGL_SUCCESS();
503
504 glViewport(0, 0, static_cast<GLsizei>(mPbufferSize), static_cast<GLsizei>(mPbufferSize));
505 glClearColor(1.0f, 0.0f, 1.0f, 1.0f);
506 glClear(GL_COLOR_BUFFER_BIT);
507 ASSERT_GL_NO_ERROR();
508
509 EXPECT_PIXEL_EQ(static_cast<GLint>(mPbufferSize) / 2, static_cast<GLint>(mPbufferSize) / 2, 255,
510 0, 255, 255);
511
512 // Apply the window surface
513 window->makeCurrent();
514
515 // Create a texture and bind the Pbuffer to it
516 GLuint texture = 0;
517 glGenTextures(1, &texture);
518 glBindTexture(GL_TEXTURE_2D, texture);
519 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
520 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
521 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
522 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
523 EXPECT_GL_NO_ERROR();
524
525 eglBindTexImage(window->getDisplay(), mPbuffer, EGL_BACK_BUFFER);
526 glViewport(0, 0, getWindowWidth(), getWindowHeight());
527 ASSERT_EGL_SUCCESS();
528
529 // Redefine the texture
530 unsigned int pixelValue = 0xFFFF00FF;
531 std::vector<unsigned int> pixelData(getWindowWidth() * getWindowHeight(), pixelValue);
532 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, getWindowWidth(), getWindowHeight(), 0, GL_RGBA,
533 GL_UNSIGNED_BYTE, &pixelData[0]);
534
535 // Draw a quad and verify that it is magenta
536 glUseProgram(mTextureProgram);
537 glUniform1i(mTextureUniformLocation, 0);
538
539 drawQuad(mTextureProgram, "position", 0.5f);
540 EXPECT_GL_NO_ERROR();
541
542 // Verify that magenta was drawn
543 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 255, 0, 255, 255);
544
545 glDeleteTextures(1, &texture);
546 }
547
548 // Bind the Pbuffer to a texture, use that texture as Framebuffer color attachment and then
549 // destroy framebuffer, texture and Pbuffer.
TEST_P(PbufferTest,UseAsFramebufferColorThenDestroy)550 TEST_P(PbufferTest, UseAsFramebufferColorThenDestroy)
551 {
552 // Test skipped because Pbuffers are not supported or Pbuffer does not support binding to RGBA
553 // textures.
554 ANGLE_SKIP_TEST_IF(!mSupportsPbuffers || !mSupportsBindTexImage);
555
556 EGLWindow *window = getEGLWindow();
557
558 // Apply the window surface
559 window->makeCurrent();
560
561 // Create a texture and bind the Pbuffer to it
562 GLuint texture = 0;
563 glGenTextures(1, &texture);
564 glBindTexture(GL_TEXTURE_2D, texture);
565 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
566 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
567 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
568 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
569 EXPECT_GL_NO_ERROR();
570
571 eglBindTexImage(window->getDisplay(), mPbuffer, EGL_BACK_BUFFER);
572 ASSERT_EGL_SUCCESS();
573
574 // Create Framebuffer and use texture as color attachment
575 GLuint fbo;
576 glGenFramebuffers(1, &fbo);
577 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
578 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
579 GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
580 ANGLE_SKIP_TEST_IF(status == GL_FRAMEBUFFER_UNSUPPORTED);
581 EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, status);
582 glDisable(GL_DEPTH_TEST);
583 glViewport(0, 0, static_cast<GLsizei>(mPbufferSize), static_cast<GLsizei>(mPbufferSize));
584 ASSERT_GL_NO_ERROR();
585
586 // Draw a quad in order to open a RenderPass
587 ANGLE_GL_PROGRAM(redProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
588 glUseProgram(redProgram);
589 ASSERT_GL_NO_ERROR();
590
591 drawQuad(redProgram, essl1_shaders::PositionAttrib(), 0.5f);
592 ASSERT_GL_NO_ERROR();
593
594 // Unbind resources
595 glBindFramebuffer(GL_FRAMEBUFFER, 0);
596 glBindTexture(GL_TEXTURE_2D, 0);
597 glViewport(0, 0, getWindowWidth(), getWindowHeight());
598 ASSERT_GL_NO_ERROR();
599
600 // Delete resources
601 glDeleteFramebuffers(1, &fbo);
602 glDeleteTextures(1, &texture);
603 ASSERT_GL_NO_ERROR();
604
605 // Destroy Pbuffer
606 destroyPbuffer();
607
608 // Finish work
609 glFinish();
610 ASSERT_GL_NO_ERROR();
611 }
612
613 // Test that passing colorspace attributes do not generate EGL validation errors
614 // when EGL_ANGLE_colorspace_attribute_passthrough extension is supported.
TEST_P(PbufferColorspaceTest,CreateSurfaceWithColorspace)615 TEST_P(PbufferColorspaceTest, CreateSurfaceWithColorspace)
616 {
617 EGLDisplay dpy = getEGLWindow()->getDisplay();
618 const bool extensionSupported =
619 IsEGLDisplayExtensionEnabled(dpy, "EGL_EXT_gl_colorspace_display_p3_passthrough");
620 const bool passthroughExtensionSupported =
621 IsEGLDisplayExtensionEnabled(dpy, "EGL_ANGLE_colorspace_attribute_passthrough");
622
623 EGLSurface pbufferSurface = EGL_NO_SURFACE;
624 const EGLint pBufferAttributes[] = {
625 EGL_WIDTH, static_cast<EGLint>(mPbufferSize),
626 EGL_HEIGHT, static_cast<EGLint>(mPbufferSize),
627 EGL_GL_COLORSPACE, EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT,
628 EGL_NONE, EGL_NONE,
629 };
630
631 pbufferSurface = eglCreatePbufferSurface(dpy, getEGLWindow()->getConfig(), pBufferAttributes);
632 if (extensionSupported)
633 {
634 // If EGL_EXT_gl_colorspace_display_p3_passthrough is supported
635 // "pbufferSurface" should be a valid pbuffer surface.
636 ASSERT_NE(pbufferSurface, EGL_NO_SURFACE);
637 ASSERT_EGL_SUCCESS();
638 }
639 else if (!extensionSupported && passthroughExtensionSupported)
640 {
641 // If EGL_ANGLE_colorspace_attribute_passthrough was the only extension supported
642 // we should not expect a validation error.
643 ASSERT_NE(eglGetError(), EGL_BAD_ATTRIBUTE);
644 }
645 else
646 {
647 // Otherwise we should expect an EGL_BAD_ATTRIBUTE validation error.
648 ASSERT_EGL_ERROR(EGL_BAD_ATTRIBUTE);
649 }
650
651 // Cleanup
652 if (pbufferSurface != EGL_NO_SURFACE)
653 {
654 eglDestroySurface(dpy, pbufferSurface);
655 }
656 }
657
658 ANGLE_INSTANTIATE_TEST_ES2(PbufferTest);
659
660 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(PbufferColorspaceTest);
661 ANGLE_INSTANTIATE_TEST_ES3_AND(PbufferColorspaceTest,
662 ES3_VULKAN().enable(Feature::EglColorspaceAttributePassthrough));
663