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