• 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 
10 using namespace angle;
11 
12 class DiscardFramebufferEXTTest : public ANGLETest
13 {
14   protected:
DiscardFramebufferEXTTest()15     DiscardFramebufferEXTTest()
16     {
17         setWindowWidth(256);
18         setWindowHeight(256);
19         setConfigRedBits(8);
20         setConfigGreenBits(8);
21         setConfigBlueBits(8);
22         setConfigAlphaBits(8);
23         setConfigDepthBits(24);
24         setConfigStencilBits(8);
25     }
26 };
27 
TEST_P(DiscardFramebufferEXTTest,DefaultFramebuffer)28 TEST_P(DiscardFramebufferEXTTest, DefaultFramebuffer)
29 {
30     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_discard_framebuffer"));
31 
32     // TODO: fix crash issue. http://anglebug.com/4141
33     ANGLE_SKIP_TEST_IF(IsD3D11());
34 
35     // These should succeed on the default framebuffer
36     const GLenum discards1[] = {GL_COLOR_EXT};
37     glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, discards1);
38     EXPECT_GL_NO_ERROR();
39 
40     const GLenum discards2[] = {GL_DEPTH_EXT};
41     glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, discards2);
42     EXPECT_GL_NO_ERROR();
43 
44     const GLenum discards3[] = {GL_STENCIL_EXT};
45     glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, discards3);
46     EXPECT_GL_NO_ERROR();
47 
48     const GLenum discards4[] = {GL_STENCIL_EXT, GL_COLOR_EXT, GL_DEPTH_EXT};
49     glDiscardFramebufferEXT(GL_FRAMEBUFFER, 3, discards4);
50     EXPECT_GL_NO_ERROR();
51 
52     // These should fail on the default framebuffer
53     const GLenum discards5[] = {GL_COLOR_ATTACHMENT0};
54     glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, discards5);
55     EXPECT_GL_ERROR(GL_INVALID_ENUM);
56 
57     const GLenum discards6[] = {GL_DEPTH_ATTACHMENT};
58     glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, discards6);
59     EXPECT_GL_ERROR(GL_INVALID_ENUM);
60 
61     const GLenum discards7[] = {GL_STENCIL_ATTACHMENT};
62     glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, discards7);
63     EXPECT_GL_ERROR(GL_INVALID_ENUM);
64 }
65 
TEST_P(DiscardFramebufferEXTTest,NonDefaultFramebuffer)66 TEST_P(DiscardFramebufferEXTTest, NonDefaultFramebuffer)
67 {
68     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_discard_framebuffer"));
69 
70     GLuint tex2D;
71     GLuint framebuffer;
72 
73     // Create a basic off-screen framebuffer
74     // Don't create a depth/stencil texture, to ensure that also works correctly
75     glGenTextures(1, &tex2D);
76     glGenFramebuffers(1, &framebuffer);
77     glBindTexture(GL_TEXTURE_2D, tex2D);
78     glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
79     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, getWindowWidth(), getWindowHeight(), 0, GL_RGB,
80                  GL_UNSIGNED_BYTE, nullptr);
81     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
82     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
83     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex2D, 0);
84     ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
85 
86     // These should fail on the non-default framebuffer
87     const GLenum discards1[] = {GL_COLOR_EXT};
88     glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, discards1);
89     EXPECT_GL_ERROR(GL_INVALID_ENUM);
90 
91     const GLenum discards2[] = {GL_DEPTH_EXT};
92     glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, discards2);
93     EXPECT_GL_ERROR(GL_INVALID_ENUM);
94 
95     const GLenum discards3[] = {GL_STENCIL_EXT};
96     glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, discards3);
97     EXPECT_GL_ERROR(GL_INVALID_ENUM);
98 
99     const GLenum discards4[] = {GL_STENCIL_EXT, GL_COLOR_EXT, GL_DEPTH_EXT};
100     glDiscardFramebufferEXT(GL_FRAMEBUFFER, 3, discards4);
101     EXPECT_GL_ERROR(GL_INVALID_ENUM);
102 
103     // These should succeed on the non-default framebuffer
104     const GLenum discards5[] = {GL_COLOR_ATTACHMENT0};
105     glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, discards5);
106     EXPECT_GL_NO_ERROR();
107 
108     const GLenum discards6[] = {GL_DEPTH_ATTACHMENT};
109     glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, discards6);
110     EXPECT_GL_NO_ERROR();
111 
112     const GLenum discards7[] = {GL_STENCIL_ATTACHMENT};
113     glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, discards7);
114     EXPECT_GL_NO_ERROR();
115 }
116 
117 // ANGLE implements an optimization that if depth stencil buffer has not been used and not stored in
118 // the renderpass, the depth buffer clear will be dropped.
TEST_P(DiscardFramebufferEXTTest,ClearDepthThenDrawWithoutDepthTestThenDiscard)119 TEST_P(DiscardFramebufferEXTTest, ClearDepthThenDrawWithoutDepthTestThenDiscard)
120 {
121     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_discard_framebuffer"));
122     // TODO: fix crash issue. http://anglebug.com/4141
123     ANGLE_SKIP_TEST_IF(IsD3D11());
124 
125     ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Passthrough(), essl1_shaders::fs::UniformColor());
126     glUseProgram(program);
127     GLint colorUniformLocation =
128         glGetUniformLocation(program, angle::essl1_shaders::ColorUniform());
129     ASSERT_NE(-1, colorUniformLocation);
130     ASSERT_GL_NO_ERROR();
131 
132     constexpr GLfloat kDepthClearValue = 0.5f;
133     // This depth value equals to kDepthClearValue after viewport transform
134     constexpr GLfloat depthDrawValue = kDepthClearValue * 2.0f - 1.0f;
135 
136     // This depth clear should be optimized out. We do not have a good way to verify that it
137     // actually gets dropped, but at least we will ensure rendering is still correct.
138     glBindFramebuffer(GL_FRAMEBUFFER, 0);
139     glEnable(GL_DEPTH_TEST);
140     glClearDepthf(kDepthClearValue);
141     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
142     glDisable(GL_DEPTH_TEST);
143     glUniform4fv(colorUniformLocation, 1, GLColor::cyan.toNormalizedVector().data());
144     glViewport(0, 0, getWindowWidth(), getWindowHeight());
145     drawQuad(program, essl1_shaders::PositionAttrib(), depthDrawValue + 0.05f);
146     GLenum discards = GL_DEPTH_EXT;
147     glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, &discards);
148     ASSERT_GL_NO_ERROR();
149     EXPECT_PIXEL_COLOR_EQ(1, 1, GLColor::cyan);
150 }
151 
152 // This test is try to ensure that if depth test has been used, depth clear does not get optimized
153 // out. It also tests that if the depth buffer has not been used, the rendering is still correct.
TEST_P(DiscardFramebufferEXTTest,ClearDepthThenDrawWithDepthTestThenDiscard)154 TEST_P(DiscardFramebufferEXTTest, ClearDepthThenDrawWithDepthTestThenDiscard)
155 {
156     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_discard_framebuffer"));
157     // http://anglebug.com/4914
158     ANGLE_SKIP_TEST_IF(IsVulkan() && IsIntel() && IsWindows());
159 
160     GLTexture texture;
161     GLRenderbuffer renderbuffer;
162     GLFramebuffer framebuffer;
163     GLint colorUniformLocation;
164     constexpr GLsizei kTexWidth  = 256;
165     constexpr GLsizei kTexHeight = 256;
166 
167     glBindTexture(GL_TEXTURE_2D, texture);
168     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, kTexWidth, kTexHeight, 0, GL_RGB, GL_UNSIGNED_BYTE,
169                  nullptr);
170     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
171     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
172     ASSERT_GL_NO_ERROR();
173     glBindTexture(GL_TEXTURE_2D, 0);
174 
175     glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
176     glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, kTexWidth, kTexWidth);
177     glBindRenderbuffer(GL_RENDERBUFFER, 0);
178     ASSERT_GL_NO_ERROR();
179 
180     glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
181     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
182     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, renderbuffer);
183     ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
184     ASSERT_GL_NO_ERROR();
185 
186     ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Passthrough(), essl1_shaders::fs::UniformColor());
187     glUseProgram(program);
188     colorUniformLocation = glGetUniformLocation(program, angle::essl1_shaders::ColorUniform());
189     ASSERT_NE(-1, colorUniformLocation);
190     ASSERT_GL_NO_ERROR();
191 
192     // Draw into FBO0
193     glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
194     glClearColor(0.0f, 1.0f, 0.0f, 1.0f);  // clear to green
195     constexpr GLfloat kDepthClearValue = 0.5f;
196     // This depth value equals to kDepthClearValue after viewport transform
197     constexpr GLfloat depthDrawValue = kDepthClearValue * 2.0f - 1.0f;
198     glClearDepthf(kDepthClearValue);
199     glEnable(GL_DEPTH_TEST);
200     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
201     // Draw bottom left with depth test disabled. DepthValue should remain 0.5f with blue color.
202     glDepthFunc(GL_LESS);
203     glDisable(GL_DEPTH_TEST);
204     glViewport(0, 0, kTexWidth / 2, kTexHeight / 2);
205     glUniform4fv(colorUniformLocation, 1, GLColor::blue.toNormalizedVector().data());
206     drawQuad(program, essl1_shaders::PositionAttrib(), depthDrawValue - 0.1f);
207     // Draw bottom right with depth test enabled. DepthValue should be 0.45f with blue color.
208     glEnable(GL_DEPTH_TEST);
209     glViewport(kTexWidth / 2, 0, kTexWidth / 2, kTexHeight / 2);
210     drawQuad(program, essl1_shaders::PositionAttrib(), depthDrawValue - 0.1f);
211     // Draw to top left with depth test disabled. DepthValue should remain 0.5f with blue color
212     glDisable(GL_DEPTH_TEST);
213     glViewport(0, kTexHeight / 2, kTexWidth / 2, kTexHeight / 2);
214     drawQuad(program, essl1_shaders::PositionAttrib(), depthDrawValue + 0.1f);
215     // Draw to top right with depth test enabled. DepthValue should remain 0.5f with green color
216     glEnable(GL_DEPTH_TEST);
217     glViewport(kTexWidth / 2, kTexHeight / 2, kTexWidth / 2, kTexHeight / 2);
218     drawQuad(program, essl1_shaders::PositionAttrib(), depthDrawValue + 0.1f);
219 
220     // Now draw the full quad with depth test enabled to verify the depth value is expected.
221     // It should fail depth test in bottom right which will keep it with blue color. All other
222     // quarters will pass depth test and draw a red quad.
223     glEnable(GL_DEPTH_TEST);
224     glUniform4fv(colorUniformLocation, 1, GLColor::red.toNormalizedVector().data());
225     glViewport(0, 0, kTexWidth, kTexHeight);
226     drawQuad(program, essl1_shaders::PositionAttrib(), depthDrawValue - 0.05f);
227 
228     // Invalidate depth buffer. This will trigger depth value not been written to buffer but the
229     // depth load/clear should not optimize out
230     GLenum discards = GL_DEPTH_ATTACHMENT;
231     glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, &discards);
232     ASSERT_GL_NO_ERROR();
233 
234     EXPECT_PIXEL_COLOR_EQ(1, 1, GLColor::red);
235     EXPECT_PIXEL_COLOR_EQ(kTexWidth / 2 + 1, 1, GLColor::blue);
236     EXPECT_PIXEL_COLOR_EQ(1, kTexHeight / 2 + 1, GLColor::red);
237     EXPECT_PIXEL_COLOR_EQ(kTexWidth / 2 + 1, kTexHeight / 2 + 1, GLColor::red);
238 }
239 
240 // Use this to select which configurations (e.g. which renderer, which GLES major version) these
241 // tests should be run against.
242 ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(DiscardFramebufferEXTTest);
243