xref: /aosp_15_r20/external/angle/src/tests/gl_tests/PbufferTest.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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