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 // Framebuffer tests:
7 // Various tests related for Frambuffers.
8 //
9
10 #include "test_utils/ANGLETest.h"
11
12 using namespace angle;
13
14 class FramebufferFormatsTest : public ANGLETest
15 {
16 protected:
FramebufferFormatsTest()17 FramebufferFormatsTest() : mFramebuffer(0), mTexture(0), mRenderbuffer(0), mProgram(0)
18 {
19 setWindowWidth(128);
20 setWindowHeight(128);
21 setConfigRedBits(8);
22 setConfigGreenBits(8);
23 setConfigBlueBits(8);
24 setConfigAlphaBits(8);
25 }
26
checkBitCount(GLuint fbo,GLenum channel,GLint minBits)27 void checkBitCount(GLuint fbo, GLenum channel, GLint minBits)
28 {
29 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
30
31 GLint bits = 0;
32 glGetIntegerv(channel, &bits);
33
34 if (minBits == 0)
35 {
36 EXPECT_EQ(minBits, bits);
37 }
38 else
39 {
40 EXPECT_GE(bits, minBits);
41 }
42 }
43
testBitCounts(GLuint fbo,GLint minRedBits,GLint minGreenBits,GLint minBlueBits,GLint minAlphaBits,GLint minDepthBits,GLint minStencilBits)44 void testBitCounts(GLuint fbo,
45 GLint minRedBits,
46 GLint minGreenBits,
47 GLint minBlueBits,
48 GLint minAlphaBits,
49 GLint minDepthBits,
50 GLint minStencilBits)
51 {
52 checkBitCount(fbo, GL_RED_BITS, minRedBits);
53 checkBitCount(fbo, GL_GREEN_BITS, minGreenBits);
54 checkBitCount(fbo, GL_BLUE_BITS, minBlueBits);
55 checkBitCount(fbo, GL_ALPHA_BITS, minAlphaBits);
56 checkBitCount(fbo, GL_DEPTH_BITS, minDepthBits);
57 checkBitCount(fbo, GL_STENCIL_BITS, minStencilBits);
58 }
59
testTextureFormat(GLenum internalFormat,GLint minRedBits,GLint minGreenBits,GLint minBlueBits,GLint minAlphaBits)60 void testTextureFormat(GLenum internalFormat,
61 GLint minRedBits,
62 GLint minGreenBits,
63 GLint minBlueBits,
64 GLint minAlphaBits)
65 {
66 glGenTextures(1, &mTexture);
67 glBindTexture(GL_TEXTURE_2D, mTexture);
68 glTexStorage2DEXT(GL_TEXTURE_2D, 1, internalFormat, 1, 1);
69
70 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTexture, 0);
71
72 testBitCounts(mFramebuffer, minRedBits, minGreenBits, minBlueBits, minAlphaBits, 0, 0);
73 }
74
testRenderbufferMultisampleFormat(int minESVersion,GLenum attachmentType,GLenum internalFormat)75 void testRenderbufferMultisampleFormat(int minESVersion,
76 GLenum attachmentType,
77 GLenum internalFormat)
78 {
79 // TODO(geofflang): Figure out why this is broken on Intel OpenGL
80 if (IsIntel() && getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
81 {
82 std::cout << "Test skipped on Intel OpenGL." << std::endl;
83 return;
84 }
85
86 int clientVersion = getClientMajorVersion();
87 if (clientVersion < minESVersion)
88 {
89 return;
90 }
91
92 // Check that multisample is supported with at least two samples (minimum required is 1)
93 bool supports2Samples = false;
94
95 if (clientVersion == 2)
96 {
97 if (extensionEnabled("ANGLE_framebuffer_multisample"))
98 {
99 int maxSamples;
100 glGetIntegerv(GL_MAX_SAMPLES_ANGLE, &maxSamples);
101 supports2Samples = maxSamples >= 2;
102 }
103 }
104 else
105 {
106 assert(clientVersion >= 3);
107 int maxSamples;
108 glGetIntegerv(GL_MAX_SAMPLES, &maxSamples);
109 supports2Samples = maxSamples >= 2;
110 }
111
112 if (!supports2Samples)
113 {
114 return;
115 }
116
117 glGenRenderbuffers(1, &mRenderbuffer);
118 glBindRenderbuffer(GL_RENDERBUFFER, mRenderbuffer);
119
120 EXPECT_GL_NO_ERROR();
121 glRenderbufferStorageMultisampleANGLE(GL_RENDERBUFFER, 2, internalFormat, 128, 128);
122 EXPECT_GL_NO_ERROR();
123 glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachmentType, GL_RENDERBUFFER, mRenderbuffer);
124 EXPECT_GL_NO_ERROR();
125 }
126
testZeroHeightRenderbuffer()127 void testZeroHeightRenderbuffer()
128 {
129 glGenRenderbuffers(1, &mRenderbuffer);
130 glBindRenderbuffer(GL_RENDERBUFFER, mRenderbuffer);
131 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 1, 0);
132 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
133 mRenderbuffer);
134 EXPECT_GL_NO_ERROR();
135 }
136
SetUp()137 void SetUp() override
138 {
139 ANGLETest::SetUp();
140
141 glGenFramebuffers(1, &mFramebuffer);
142 glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
143 }
144
TearDown()145 void TearDown() override
146 {
147 ANGLETest::TearDown();
148
149 if (mTexture != 0)
150 {
151 glDeleteTextures(1, &mTexture);
152 mTexture = 0;
153 }
154
155 if (mRenderbuffer != 0)
156 {
157 glDeleteRenderbuffers(1, &mRenderbuffer);
158 mRenderbuffer = 0;
159 }
160
161 if (mFramebuffer != 0)
162 {
163 glDeleteFramebuffers(1, &mFramebuffer);
164 mFramebuffer = 0;
165 }
166
167 if (mProgram != 0)
168 {
169 glDeleteProgram(mProgram);
170 mProgram = 0;
171 }
172 }
173
174 GLuint mFramebuffer;
175 GLuint mTexture;
176 GLuint mRenderbuffer;
177 GLuint mProgram;
178 };
179
TEST_P(FramebufferFormatsTest,RGBA4)180 TEST_P(FramebufferFormatsTest, RGBA4)
181 {
182 testTextureFormat(GL_RGBA4, 4, 4, 4, 4);
183 }
184
TEST_P(FramebufferFormatsTest,RGB565)185 TEST_P(FramebufferFormatsTest, RGB565)
186 {
187 testTextureFormat(GL_RGB565, 5, 6, 5, 0);
188 }
189
TEST_P(FramebufferFormatsTest,RGB8)190 TEST_P(FramebufferFormatsTest, RGB8)
191 {
192 if (getClientMajorVersion() < 3 && !extensionEnabled("GL_OES_rgb8_rgba8"))
193 {
194 std::cout << "Test skipped due to missing ES3 or GL_OES_rgb8_rgba8." << std::endl;
195 return;
196 }
197
198 testTextureFormat(GL_RGB8_OES, 8, 8, 8, 0);
199 }
200
TEST_P(FramebufferFormatsTest,BGRA8)201 TEST_P(FramebufferFormatsTest, BGRA8)
202 {
203 if (!extensionEnabled("GL_EXT_texture_format_BGRA8888"))
204 {
205 std::cout << "Test skipped due to missing GL_EXT_texture_format_BGRA8888." << std::endl;
206 return;
207 }
208
209 testTextureFormat(GL_BGRA8_EXT, 8, 8, 8, 8);
210 }
211
TEST_P(FramebufferFormatsTest,RGBA8)212 TEST_P(FramebufferFormatsTest, RGBA8)
213 {
214 if (getClientMajorVersion() < 3 && !extensionEnabled("GL_OES_rgb8_rgba8"))
215 {
216 std::cout << "Test skipped due to missing ES3 or GL_OES_rgb8_rgba8." << std::endl;
217 return;
218 }
219
220 testTextureFormat(GL_RGBA8_OES, 8, 8, 8, 8);
221 }
222
TEST_P(FramebufferFormatsTest,RenderbufferMultisample_DEPTH16)223 TEST_P(FramebufferFormatsTest, RenderbufferMultisample_DEPTH16)
224 {
225 testRenderbufferMultisampleFormat(2, GL_DEPTH_ATTACHMENT, GL_DEPTH_COMPONENT16);
226 }
227
TEST_P(FramebufferFormatsTest,RenderbufferMultisample_DEPTH24)228 TEST_P(FramebufferFormatsTest, RenderbufferMultisample_DEPTH24)
229 {
230 testRenderbufferMultisampleFormat(3, GL_DEPTH_ATTACHMENT, GL_DEPTH_COMPONENT24);
231 }
232
TEST_P(FramebufferFormatsTest,RenderbufferMultisample_DEPTH32F)233 TEST_P(FramebufferFormatsTest, RenderbufferMultisample_DEPTH32F)
234 {
235 if (getClientMajorVersion() < 3)
236 {
237 std::cout << "Test skipped due to missing ES3." << std::endl;
238 return;
239 }
240
241 testRenderbufferMultisampleFormat(3, GL_DEPTH_ATTACHMENT, GL_DEPTH_COMPONENT32F);
242 }
243
TEST_P(FramebufferFormatsTest,RenderbufferMultisample_DEPTH24_STENCIL8)244 TEST_P(FramebufferFormatsTest, RenderbufferMultisample_DEPTH24_STENCIL8)
245 {
246 testRenderbufferMultisampleFormat(3, GL_DEPTH_STENCIL_ATTACHMENT, GL_DEPTH24_STENCIL8);
247 }
248
TEST_P(FramebufferFormatsTest,RenderbufferMultisample_DEPTH32F_STENCIL8)249 TEST_P(FramebufferFormatsTest, RenderbufferMultisample_DEPTH32F_STENCIL8)
250 {
251 if (getClientMajorVersion() < 3)
252 {
253 std::cout << "Test skipped due to missing ES3." << std::endl;
254 return;
255 }
256
257 testRenderbufferMultisampleFormat(3, GL_DEPTH_STENCIL_ATTACHMENT, GL_DEPTH32F_STENCIL8);
258 }
259
TEST_P(FramebufferFormatsTest,RenderbufferMultisample_STENCIL_INDEX8)260 TEST_P(FramebufferFormatsTest, RenderbufferMultisample_STENCIL_INDEX8)
261 {
262 // TODO(geofflang): Figure out how to support GLSTENCIL_INDEX8 on desktop GL
263 if (GetParam().getRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
264 {
265 std::cout << "Test skipped on Desktop OpenGL." << std::endl;
266 return;
267 }
268
269 testRenderbufferMultisampleFormat(2, GL_STENCIL_ATTACHMENT, GL_STENCIL_INDEX8);
270 }
271
272 // Test that binding an incomplete cube map is rejected by ANGLE.
TEST_P(FramebufferFormatsTest,IncompleteCubeMap)273 TEST_P(FramebufferFormatsTest, IncompleteCubeMap)
274 {
275 // First make a complete CubeMap.
276 glGenTextures(1, &mTexture);
277 glBindTexture(GL_TEXTURE_CUBE_MAP, mTexture);
278 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, GL_RGBA, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE,
279 nullptr);
280 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, GL_RGBA, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE,
281 nullptr);
282 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, GL_RGBA, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE,
283 nullptr);
284 glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, GL_RGBA, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE,
285 nullptr);
286 glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GL_RGBA, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE,
287 nullptr);
288 glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, GL_RGBA, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE,
289 nullptr);
290 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
291 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
292
293 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X,
294 mTexture, 0);
295
296 // Verify the framebuffer is complete.
297 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
298
299 // Make the CubeMap cube-incomplete.
300 glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE,
301 nullptr);
302
303 // Verify the framebuffer is incomplete.
304 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,
305 glCheckFramebufferStatus(GL_FRAMEBUFFER));
306
307 // Verify drawing with the incomplete framebuffer produces a GL error
308 const std::string &vs = "attribute vec4 position; void main() { gl_Position = position; }";
309 const std::string &ps = "void main() { gl_FragColor = vec4(1, 0, 0, 1); }";
310 mProgram = CompileProgram(vs, ps);
311 ASSERT_NE(0u, mProgram);
312 drawQuad(mProgram, "position", 0.5f);
313 ASSERT_GL_ERROR(GL_INVALID_FRAMEBUFFER_OPERATION);
314 }
315
316 // Test that a renderbuffer with zero height but nonzero width is handled without crashes/asserts.
TEST_P(FramebufferFormatsTest,ZeroHeightRenderbuffer)317 TEST_P(FramebufferFormatsTest, ZeroHeightRenderbuffer)
318 {
319 if (getClientMajorVersion() < 3)
320 {
321 std::cout << "Test skipped due to missing ES3" << std::endl;
322 return;
323 }
324
325 testZeroHeightRenderbuffer();
326 }
327
328 // Use this to select which configurations (e.g. which renderer, which GLES major version) these
329 // tests should be run against.
330 ANGLE_INSTANTIATE_TEST(FramebufferFormatsTest,
331 ES2_D3D9(),
332 ES2_D3D11(),
333 ES3_D3D11(),
334 ES2_OPENGL(),
335 ES3_OPENGL(),
336 ES2_OPENGLES(),
337 ES3_OPENGLES());
338
339 class FramebufferInvalidateTest : public ANGLETest
340 {
341 protected:
FramebufferInvalidateTest()342 FramebufferInvalidateTest() : mFramebuffer(0), mRenderbuffer(0) {}
343
SetUp()344 void SetUp() override
345 {
346 ANGLETest::SetUp();
347
348 glGenFramebuffers(1, &mFramebuffer);
349 glGenRenderbuffers(1, &mRenderbuffer);
350 }
351
TearDown()352 void TearDown() override
353 {
354 glDeleteFramebuffers(1, &mFramebuffer);
355 glDeleteRenderbuffers(1, &mRenderbuffer);
356 ANGLETest::TearDown();
357 }
358
359 GLuint mFramebuffer;
360 GLuint mRenderbuffer;
361 };
362
363 // Covers invalidating an incomplete framebuffer. This should be a no-op, but should not error.
TEST_P(FramebufferInvalidateTest,Incomplete)364 TEST_P(FramebufferInvalidateTest, Incomplete)
365 {
366 glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
367 glBindRenderbuffer(GL_RENDERBUFFER, mRenderbuffer);
368 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, mRenderbuffer);
369 EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,
370 glCheckFramebufferStatus(GL_FRAMEBUFFER));
371
372 std::vector<GLenum> attachments;
373 attachments.push_back(GL_COLOR_ATTACHMENT0);
374
375 glInvalidateFramebuffer(GL_FRAMEBUFFER, 1, attachments.data());
376 EXPECT_GL_NO_ERROR();
377 }
378
379 ANGLE_INSTANTIATE_TEST(FramebufferInvalidateTest, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());
380