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