• 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         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