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