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 
9 using namespace angle;
10 
11 class PbufferTest : public ANGLETest
12 {
13   protected:
PbufferTest()14     PbufferTest()
15     {
16         setWindowWidth(512);
17         setWindowHeight(512);
18         setConfigRedBits(8);
19         setConfigGreenBits(8);
20         setConfigBlueBits(8);
21         setConfigAlphaBits(8);
22     }
23 
SetUp()24     virtual void SetUp()
25     {
26         ANGLETest::SetUp();
27 
28         const std::string vsSource = SHADER_SOURCE
29         (
30             precision highp float;
31             attribute vec4 position;
32             varying vec2 texcoord;
33 
34             void main()
35             {
36                 gl_Position = position;
37                 texcoord = (position.xy * 0.5) + 0.5;
38                 texcoord.y = 1.0 - texcoord.y;
39             }
40         );
41 
42         const std::string textureFSSource = SHADER_SOURCE
43         (
44             precision highp float;
45             uniform sampler2D tex;
46             varying vec2 texcoord;
47 
48             void main()
49             {
50                 gl_FragColor = texture2D(tex, texcoord);
51             }
52         );
53 
54         mTextureProgram = CompileProgram(vsSource, textureFSSource);
55         if (mTextureProgram == 0)
56         {
57             FAIL() << "shader compilation failed.";
58         }
59 
60         mTextureUniformLocation = glGetUniformLocation(mTextureProgram, "tex");
61 
62         EGLWindow *window = getEGLWindow();
63 
64         EGLint surfaceType = 0;
65         eglGetConfigAttrib(window->getDisplay(), window->getConfig(), EGL_SURFACE_TYPE, &surfaceType);
66         mSupportsPbuffers = (surfaceType & EGL_PBUFFER_BIT) != 0;
67 
68         EGLint bindToTextureRGBA = 0;
69         eglGetConfigAttrib(window->getDisplay(), window->getConfig(), EGL_BIND_TO_TEXTURE_RGBA, &bindToTextureRGBA);
70         mSupportsBindTexImage = (bindToTextureRGBA == EGL_TRUE);
71 
72         const EGLint pBufferAttributes[] =
73         {
74             EGL_WIDTH, static_cast<EGLint>(mPbufferSize),
75             EGL_HEIGHT, static_cast<EGLint>(mPbufferSize),
76             EGL_TEXTURE_FORMAT, mSupportsBindTexImage ? EGL_TEXTURE_RGBA : EGL_NO_TEXTURE,
77             EGL_TEXTURE_TARGET, mSupportsBindTexImage ? EGL_TEXTURE_2D : EGL_NO_TEXTURE,
78             EGL_NONE, EGL_NONE,
79         };
80 
81         mPbuffer = eglCreatePbufferSurface(window->getDisplay(), window->getConfig(), pBufferAttributes);
82         if (mSupportsPbuffers)
83         {
84             ASSERT_NE(mPbuffer, EGL_NO_SURFACE);
85             ASSERT_EGL_SUCCESS();
86         }
87         else
88         {
89             ASSERT_EQ(mPbuffer, EGL_NO_SURFACE);
90             ASSERT_EGL_ERROR(EGL_BAD_MATCH);
91         }
92 
93         ASSERT_GL_NO_ERROR();
94     }
95 
TearDown()96     virtual void TearDown()
97     {
98         glDeleteProgram(mTextureProgram);
99 
100         EGLWindow *window = getEGLWindow();
101         eglDestroySurface(window->getDisplay(), mPbuffer);
102 
103         ANGLETest::TearDown();
104     }
105 
106     GLuint mTextureProgram;
107     GLint mTextureUniformLocation;
108 
109     const size_t mPbufferSize = 32;
110     EGLSurface mPbuffer;
111     bool mSupportsPbuffers;
112     bool mSupportsBindTexImage;
113 };
114 
115 // Test clearing a Pbuffer and checking the color is correct
TEST_P(PbufferTest,Clearing)116 TEST_P(PbufferTest, Clearing)
117 {
118     if (!mSupportsPbuffers)
119     {
120         std::cout << "Test skipped because Pbuffers are not supported." << std::endl;
121         return;
122     }
123 
124     EGLWindow *window = getEGLWindow();
125 
126     // Clear the window surface to blue and verify
127     eglMakeCurrent(window->getDisplay(), window->getSurface(), window->getSurface(), window->getContext());
128     ASSERT_EGL_SUCCESS();
129 
130     glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
131     glClear(GL_COLOR_BUFFER_BIT);
132     ASSERT_GL_NO_ERROR();
133     EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 255, 255);
134 
135     // Apply the Pbuffer and clear it to purple and verify
136     eglMakeCurrent(window->getDisplay(), mPbuffer, mPbuffer, window->getContext());
137     ASSERT_EGL_SUCCESS();
138 
139     glViewport(0, 0, static_cast<GLsizei>(mPbufferSize), static_cast<GLsizei>(mPbufferSize));
140     glClearColor(1.0f, 0.0f, 1.0f, 1.0f);
141     glClear(GL_COLOR_BUFFER_BIT);
142     ASSERT_GL_NO_ERROR();
143     EXPECT_PIXEL_EQ(static_cast<GLint>(mPbufferSize) / 2, static_cast<GLint>(mPbufferSize) / 2, 255,
144                     0, 255, 255);
145 
146     // Rebind the window surface and verify that it is still blue
147     eglMakeCurrent(window->getDisplay(), window->getSurface(), window->getSurface(), window->getContext());
148     ASSERT_EGL_SUCCESS();
149     EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 255, 255);
150 }
151 
152 // Bind the Pbuffer to a texture and verify it renders correctly
TEST_P(PbufferTest,BindTexImage)153 TEST_P(PbufferTest, BindTexImage)
154 {
155     if (!mSupportsPbuffers)
156     {
157         std::cout << "Test skipped because Pbuffers are not supported." << std::endl;
158         return;
159     }
160 
161     if (!mSupportsBindTexImage)
162     {
163         std::cout << "Test skipped because Pbuffer does not support binding to RGBA textures." << std::endl;
164         return;
165     }
166 
167     EGLWindow *window = getEGLWindow();
168 
169     // Apply the Pbuffer and clear it to purple
170     eglMakeCurrent(window->getDisplay(), mPbuffer, mPbuffer, window->getContext());
171     ASSERT_EGL_SUCCESS();
172 
173     glViewport(0, 0, static_cast<GLsizei>(mPbufferSize), static_cast<GLsizei>(mPbufferSize));
174     glClearColor(1.0f, 0.0f, 1.0f, 1.0f);
175     glClear(GL_COLOR_BUFFER_BIT);
176     ASSERT_GL_NO_ERROR();
177 
178     EXPECT_PIXEL_EQ(static_cast<GLint>(mPbufferSize) / 2, static_cast<GLint>(mPbufferSize) / 2, 255,
179                     0, 255, 255);
180 
181     // Apply the window surface
182     eglMakeCurrent(window->getDisplay(), window->getSurface(), window->getSurface(), window->getContext());
183 
184     // Create a texture and bind the Pbuffer to it
185     GLuint texture = 0;
186     glGenTextures(1, &texture);
187     glBindTexture(GL_TEXTURE_2D, texture);
188     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
189     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
190     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
191     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
192     EXPECT_GL_NO_ERROR();
193 
194     eglBindTexImage(window->getDisplay(), mPbuffer, EGL_BACK_BUFFER);
195     glViewport(0, 0, getWindowWidth(), getWindowHeight());
196     ASSERT_EGL_SUCCESS();
197 
198     // Draw a quad and verify that it is purple
199     glUseProgram(mTextureProgram);
200     glUniform1i(mTextureUniformLocation, 0);
201 
202     drawQuad(mTextureProgram, "position", 0.5f);
203     EXPECT_GL_NO_ERROR();
204 
205     // Unbind the texture
206     eglReleaseTexImage(window->getDisplay(), mPbuffer, EGL_BACK_BUFFER);
207     ASSERT_EGL_SUCCESS();
208 
209     // Verify that purple was drawn
210     EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 255, 0, 255, 255);
211 
212     glDeleteTextures(1, &texture);
213 }
214 
215 // Verify that when eglBind/ReleaseTexImage are called, the texture images are freed and their
216 // size information is correctly updated.
TEST_P(PbufferTest,TextureSizeReset)217 TEST_P(PbufferTest, TextureSizeReset)
218 {
219     if (!mSupportsPbuffers)
220     {
221         std::cout << "Test skipped because Pbuffers are not supported." << std::endl;
222         return;
223     }
224 
225     if (!mSupportsBindTexImage)
226     {
227         std::cout << "Test skipped because Pbuffer does not support binding to RGBA textures." << std::endl;
228         return;
229     }
230 
231     GLuint texture = 0;
232     glGenTextures(1, &texture);
233     glBindTexture(GL_TEXTURE_2D, texture);
234     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
235     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
236     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
237     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
238     EXPECT_GL_NO_ERROR();
239 
240     glUseProgram(mTextureProgram);
241     glUniform1i(mTextureUniformLocation, 0);
242 
243     // Fill the texture with white pixels
244     std::vector<GLubyte> whitePixels(mPbufferSize * mPbufferSize * 4, 255);
245     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, static_cast<GLsizei>(mPbufferSize),
246                  static_cast<GLsizei>(mPbufferSize), 0, GL_RGBA, GL_UNSIGNED_BYTE, &whitePixels[0]);
247     EXPECT_GL_NO_ERROR();
248 
249     // Draw the white texture and verify that the pixels are correct
250     drawQuad(mTextureProgram, "position", 0.5f);
251     EXPECT_PIXEL_EQ(0, 0, 255, 255, 255, 255);
252 
253     // Bind the EGL surface and draw with it, results are undefined since nothing has
254     // been written to it
255     EGLWindow *window = getEGLWindow();
256     eglBindTexImage(window->getDisplay(), mPbuffer, EGL_BACK_BUFFER);
257     drawQuad(mTextureProgram, "position", 0.5f);
258     EXPECT_GL_NO_ERROR();
259 
260     // Clear the back buffer to a unique color (green)
261     glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
262     glClear(GL_COLOR_BUFFER_BIT);
263     EXPECT_PIXEL_EQ(0, 0, 0, 255, 0, 255);
264 
265     // Unbind the EGL surface and try to draw with the texture again, the texture's size should
266     // now be zero and incomplete so the back buffer should be black
267     eglReleaseTexImage(window->getDisplay(), mPbuffer, EGL_BACK_BUFFER);
268     drawQuad(mTextureProgram, "position", 0.5f);
269     EXPECT_PIXEL_EQ(0, 0, 0, 0, 0, 255);
270 }
271 
272 // Bind a Pbuffer, redefine the texture, and verify it renders correctly
TEST_P(PbufferTest,BindTexImageAndRedefineTexture)273 TEST_P(PbufferTest, BindTexImageAndRedefineTexture)
274 {
275     if (!mSupportsPbuffers)
276     {
277         std::cout << "Test skipped because Pbuffers are not supported." << std::endl;
278         return;
279     }
280 
281     if (!mSupportsBindTexImage)
282     {
283         std::cout << "Test skipped because Pbuffer does not support binding to RGBA textures." << std::endl;
284         return;
285     }
286 
287     EGLWindow *window = getEGLWindow();
288 
289     // Apply the Pbuffer and clear it to purple
290     eglMakeCurrent(window->getDisplay(), mPbuffer, mPbuffer, window->getContext());
291     ASSERT_EGL_SUCCESS();
292 
293     glViewport(0, 0, static_cast<GLsizei>(mPbufferSize), static_cast<GLsizei>(mPbufferSize));
294     glClearColor(1.0f, 0.0f, 1.0f, 1.0f);
295     glClear(GL_COLOR_BUFFER_BIT);
296     ASSERT_GL_NO_ERROR();
297 
298     EXPECT_PIXEL_EQ(static_cast<GLint>(mPbufferSize) / 2, static_cast<GLint>(mPbufferSize) / 2, 255,
299                     0, 255, 255);
300 
301     // Apply the window surface
302     eglMakeCurrent(window->getDisplay(), window->getSurface(), window->getSurface(), window->getContext());
303 
304     // Create a texture and bind the Pbuffer to it
305     GLuint texture = 0;
306     glGenTextures(1, &texture);
307     glBindTexture(GL_TEXTURE_2D, texture);
308     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
309     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
310     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
311     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
312     EXPECT_GL_NO_ERROR();
313 
314     eglBindTexImage(window->getDisplay(), mPbuffer, EGL_BACK_BUFFER);
315     glViewport(0, 0, getWindowWidth(), getWindowHeight());
316     ASSERT_EGL_SUCCESS();
317 
318     // Redefine the texture
319     unsigned int pixelValue = 0xFFFF00FF;
320     std::vector<unsigned int> pixelData(getWindowWidth() * getWindowHeight(), pixelValue);
321     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, getWindowWidth(), getWindowHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, &pixelData[0]);
322 
323     // Draw a quad and verify that it is magenta
324     glUseProgram(mTextureProgram);
325     glUniform1i(mTextureUniformLocation, 0);
326 
327     drawQuad(mTextureProgram, "position", 0.5f);
328     EXPECT_GL_NO_ERROR();
329 
330     // Verify that magenta was drawn
331     EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 255, 0, 255, 255);
332 
333     glDeleteTextures(1, &texture);
334 }
335 
336 // Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
337 ANGLE_INSTANTIATE_TEST(PbufferTest,
338                        ES2_D3D9(),
339                        ES2_D3D11(),
340                        ES2_OPENGL(),
341                        ES2_D3D11_WARP(),
342                        ES2_D3D11_REFERENCE(),
343                        ES2_OPENGLES());
344