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 EGLWindow *window = getEGLWindow();
99 eglDestroySurface(window->getDisplay(), mPbuffer);
100 }
101
102 GLuint mTextureProgram;
103 GLint mTextureUniformLocation;
104
105 const size_t mPbufferSize = 32;
106 EGLSurface mPbuffer;
107 bool mSupportsPbuffers;
108 bool mSupportsBindTexImage;
109 };
110
111 // Test clearing a Pbuffer and checking the color is correct
TEST_P(PbufferTest,Clearing)112 TEST_P(PbufferTest, Clearing)
113 {
114 ANGLE_SKIP_TEST_IF(!mSupportsPbuffers);
115
116 EGLWindow *window = getEGLWindow();
117
118 // Clear the window surface to blue and verify
119 window->makeCurrent();
120 ASSERT_EGL_SUCCESS();
121
122 glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
123 glClear(GL_COLOR_BUFFER_BIT);
124 ASSERT_GL_NO_ERROR();
125 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 255, 255);
126
127 // Apply the Pbuffer and clear it to purple and verify
128 eglMakeCurrent(window->getDisplay(), mPbuffer, mPbuffer, window->getContext());
129 ASSERT_EGL_SUCCESS();
130
131 glViewport(0, 0, static_cast<GLsizei>(mPbufferSize), static_cast<GLsizei>(mPbufferSize));
132 glClearColor(1.0f, 0.0f, 1.0f, 1.0f);
133 glClear(GL_COLOR_BUFFER_BIT);
134 ASSERT_GL_NO_ERROR();
135 EXPECT_PIXEL_EQ(static_cast<GLint>(mPbufferSize) / 2, static_cast<GLint>(mPbufferSize) / 2, 255,
136 0, 255, 255);
137
138 // Rebind the window surface and verify that it is still blue
139 window->makeCurrent();
140 ASSERT_EGL_SUCCESS();
141 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 255, 255);
142 }
143
144 // Bind the Pbuffer to a texture and verify it renders correctly
TEST_P(PbufferTest,BindTexImage)145 TEST_P(PbufferTest, BindTexImage)
146 {
147 // Test skipped because Pbuffers are not supported or Pbuffer does not support binding to RGBA
148 // textures.
149 ANGLE_SKIP_TEST_IF(!mSupportsPbuffers || !mSupportsBindTexImage);
150
151 EGLWindow *window = getEGLWindow();
152
153 // Apply the Pbuffer and clear it to purple
154 eglMakeCurrent(window->getDisplay(), mPbuffer, mPbuffer, window->getContext());
155 ASSERT_EGL_SUCCESS();
156
157 glViewport(0, 0, static_cast<GLsizei>(mPbufferSize), static_cast<GLsizei>(mPbufferSize));
158 glClearColor(1.0f, 0.0f, 1.0f, 1.0f);
159 glClear(GL_COLOR_BUFFER_BIT);
160 ASSERT_GL_NO_ERROR();
161
162 EXPECT_PIXEL_EQ(static_cast<GLint>(mPbufferSize) / 2, static_cast<GLint>(mPbufferSize) / 2, 255,
163 0, 255, 255);
164
165 // Apply the window surface
166 window->makeCurrent();
167
168 // Create a texture and bind the Pbuffer to it
169 GLuint texture = 0;
170 glGenTextures(1, &texture);
171 glBindTexture(GL_TEXTURE_2D, texture);
172 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
173 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
174 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
175 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
176 EXPECT_GL_NO_ERROR();
177
178 eglBindTexImage(window->getDisplay(), mPbuffer, EGL_BACK_BUFFER);
179 glViewport(0, 0, getWindowWidth(), getWindowHeight());
180 ASSERT_EGL_SUCCESS();
181
182 // Draw a quad and verify that it is purple
183 glUseProgram(mTextureProgram);
184 glUniform1i(mTextureUniformLocation, 0);
185
186 drawQuad(mTextureProgram, "position", 0.5f);
187 EXPECT_GL_NO_ERROR();
188
189 // Unbind the texture
190 eglReleaseTexImage(window->getDisplay(), mPbuffer, EGL_BACK_BUFFER);
191 ASSERT_EGL_SUCCESS();
192
193 // Verify that purple was drawn
194 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 255, 0, 255, 255);
195
196 glDeleteTextures(1, &texture);
197 }
198
199 // Verify that when eglBind/ReleaseTexImage are called, the texture images are freed and their
200 // size information is correctly updated.
TEST_P(PbufferTest,TextureSizeReset)201 TEST_P(PbufferTest, TextureSizeReset)
202 {
203 ANGLE_SKIP_TEST_IF(!mSupportsPbuffers);
204 ANGLE_SKIP_TEST_IF(!mSupportsBindTexImage);
205 ANGLE_SKIP_TEST_IF(IsARM64() && IsWindows() && IsD3D());
206
207 GLTexture texture;
208 glBindTexture(GL_TEXTURE_2D, texture);
209 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
210 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
211 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
212 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
213 EXPECT_GL_NO_ERROR();
214
215 glUseProgram(mTextureProgram);
216 glUniform1i(mTextureUniformLocation, 0);
217
218 // Fill the texture with white pixels
219 std::vector<GLColor> whitePixels(mPbufferSize * mPbufferSize, GLColor::white);
220 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, static_cast<GLsizei>(mPbufferSize),
221 static_cast<GLsizei>(mPbufferSize), 0, GL_RGBA, GL_UNSIGNED_BYTE,
222 whitePixels.data());
223 EXPECT_GL_NO_ERROR();
224
225 // Draw the white texture and verify that the pixels are correct
226 drawQuad(mTextureProgram, "position", 0.5f);
227 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white);
228
229 // Bind the EGL surface and draw with it, results are undefined since nothing has
230 // been written to it
231 EGLWindow *window = getEGLWindow();
232 eglBindTexImage(window->getDisplay(), mPbuffer, EGL_BACK_BUFFER);
233 drawQuad(mTextureProgram, "position", 0.5f);
234 EXPECT_GL_NO_ERROR();
235
236 // Clear the back buffer to a unique color (green)
237 glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
238 glClear(GL_COLOR_BUFFER_BIT);
239 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
240
241 // Unbind the EGL surface and try to draw with the texture again, the texture's size should
242 // now be zero and incomplete so the back buffer should be black
243 eglReleaseTexImage(window->getDisplay(), mPbuffer, EGL_BACK_BUFFER);
244 drawQuad(mTextureProgram, "position", 0.5f);
245 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
246 }
247
248 // Bind a Pbuffer, redefine the texture, and verify it renders correctly
TEST_P(PbufferTest,BindTexImageAndRedefineTexture)249 TEST_P(PbufferTest, BindTexImageAndRedefineTexture)
250 {
251 // Test skipped because Pbuffers are not supported or Pbuffer does not support binding to RGBA
252 // textures.
253 ANGLE_SKIP_TEST_IF(!mSupportsPbuffers || !mSupportsBindTexImage);
254
255 EGLWindow *window = getEGLWindow();
256
257 // Apply the Pbuffer and clear it to purple
258 eglMakeCurrent(window->getDisplay(), mPbuffer, mPbuffer, window->getContext());
259 ASSERT_EGL_SUCCESS();
260
261 glViewport(0, 0, static_cast<GLsizei>(mPbufferSize), static_cast<GLsizei>(mPbufferSize));
262 glClearColor(1.0f, 0.0f, 1.0f, 1.0f);
263 glClear(GL_COLOR_BUFFER_BIT);
264 ASSERT_GL_NO_ERROR();
265
266 EXPECT_PIXEL_EQ(static_cast<GLint>(mPbufferSize) / 2, static_cast<GLint>(mPbufferSize) / 2, 255,
267 0, 255, 255);
268
269 // Apply the window surface
270 window->makeCurrent();
271
272 // Create a texture and bind the Pbuffer to it
273 GLuint texture = 0;
274 glGenTextures(1, &texture);
275 glBindTexture(GL_TEXTURE_2D, texture);
276 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
277 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
278 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
279 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
280 EXPECT_GL_NO_ERROR();
281
282 eglBindTexImage(window->getDisplay(), mPbuffer, EGL_BACK_BUFFER);
283 glViewport(0, 0, getWindowWidth(), getWindowHeight());
284 ASSERT_EGL_SUCCESS();
285
286 // Redefine the texture
287 unsigned int pixelValue = 0xFFFF00FF;
288 std::vector<unsigned int> pixelData(getWindowWidth() * getWindowHeight(), pixelValue);
289 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, getWindowWidth(), getWindowHeight(), 0, GL_RGBA,
290 GL_UNSIGNED_BYTE, &pixelData[0]);
291
292 // Draw a quad and verify that it is magenta
293 glUseProgram(mTextureProgram);
294 glUniform1i(mTextureUniformLocation, 0);
295
296 drawQuad(mTextureProgram, "position", 0.5f);
297 EXPECT_GL_NO_ERROR();
298
299 // Verify that magenta was drawn
300 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 255, 0, 255, 255);
301
302 glDeleteTextures(1, &texture);
303 }
304
305 ANGLE_INSTANTIATE_TEST_ES2(PbufferTest);
306