• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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