1 //
2 // Copyright 2022 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 // FragDepthTest:
7 // Tests the correctness of gl_FragDepth usage.
8 //
9
10 #include "test_utils/ANGLETest.h"
11 #include "test_utils/gl_raii.h"
12
13 using namespace angle;
14
15 class FragDepthTest : public ANGLETest<>
16 {
17 protected:
18 struct FragDepthTestResources
19 {
20 GLuint program;
21 GLint depthLocation;
22 GLTexture colorTexture;
23 GLTexture depthTexture;
24 GLFramebuffer framebuffer;
25 };
26
setupResources(FragDepthTestResources & resources)27 void setupResources(FragDepthTestResources &resources)
28 {
29
30 // Writes a fixed depth value and green.
31 constexpr char kFS[] =
32 R"(#version 300 es
33 precision highp float;
34 layout(location = 0) out vec4 fragColor;
35 uniform float u_depth;
36 void main(){
37 gl_FragDepth = u_depth;
38 fragColor = vec4(0.0, 1.0, 0.0, 1.0);
39 })";
40
41 resources.program = CompileProgram(essl3_shaders::vs::Simple(), kFS);
42 resources.depthLocation = glGetUniformLocation(resources.program, "u_depth");
43
44 glBindTexture(GL_TEXTURE_2D, resources.colorTexture);
45 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 1, 1);
46 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
47 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
48
49 glBindTexture(GL_TEXTURE_2D, resources.depthTexture);
50 glTexStorage2D(GL_TEXTURE_2D, 1, GL_DEPTH_COMPONENT32F, 1, 1);
51 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
52 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
53
54 glBindFramebuffer(GL_FRAMEBUFFER, resources.framebuffer);
55 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
56 resources.colorTexture, 0);
57 }
58
cleanupResources(FragDepthTestResources & resources)59 void cleanupResources(FragDepthTestResources &resources) { glDeleteProgram(resources.program); }
60
checkDepthWritten(float expectedDepth,float fsDepth,bool bindDepthBuffer)61 void checkDepthWritten(float expectedDepth, float fsDepth, bool bindDepthBuffer)
62 {
63 FragDepthTestResources resources;
64 setupResources(resources);
65 ASSERT_NE(0u, resources.program);
66 ASSERT_NE(-1, resources.depthLocation);
67 ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
68 ASSERT_GL_NO_ERROR();
69
70 glBindFramebuffer(GL_FRAMEBUFFER, resources.framebuffer);
71 if (bindDepthBuffer)
72 {
73 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D,
74 resources.depthTexture, 0);
75 EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
76
77 // Clear to the expected depth so it will be compared to the FS depth with
78 // DepthFunc(GL_EQUAL)
79 glClearDepthf(expectedDepth);
80 glDepthFunc(GL_EQUAL);
81 glEnable(GL_DEPTH_TEST);
82 }
83 else
84 {
85 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
86 EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
87 glDisable(GL_DEPTH_TEST);
88 }
89 glUseProgram(resources.program);
90
91 // Clear to red, the FS will write green on success
92 glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
93 // Clear to the expected depth so it will be compared to the FS depth with
94 // DepthFunc(GL_EQUAL)
95
96 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
97 glUniform1f(resources.depthLocation, fsDepth);
98
99 drawQuad(resources.program, "a_position", 0.0f);
100 EXPECT_GL_NO_ERROR();
101
102 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
103 cleanupResources(resources);
104 }
105 };
106
107 // Test that writing to gl_FragDepth works
TEST_P(FragDepthTest,DepthBufferBound)108 TEST_P(FragDepthTest, DepthBufferBound)
109 {
110 checkDepthWritten(0.5f, 0.5f, true);
111 }
112
113 // Test that writing to gl_FragDepth with no depth buffer works.
TEST_P(FragDepthTest,DepthBufferUnbound)114 TEST_P(FragDepthTest, DepthBufferUnbound)
115 {
116 // Depth test is disabled, so the expected depth should not matter.
117 checkDepthWritten(0.f, 0.5f, false);
118 }
119
120 // Test that fragment shader depth writes to a no-depth framebuffer do not fail
121 // after using a depth-enabled framebuffer with the same program.
TEST_P(FragDepthTest,SwitchToNoDepthFramebuffer)122 TEST_P(FragDepthTest, SwitchToNoDepthFramebuffer)
123 {
124 constexpr char kFS[] = R"(#version 300 es
125 out highp vec4 color;
126 void main() {
127 color = vec4(1.0, 0.0, 0.0, 1.0);
128 gl_FragDepth = 1.0;
129 })";
130
131 ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS);
132
133 // Draw to a depth-enabled framebuffer first
134 GLFramebuffer fbo1;
135 glBindFramebuffer(GL_FRAMEBUFFER, fbo1);
136
137 GLRenderbuffer rb10;
138 glBindRenderbuffer(GL_RENDERBUFFER, rb10);
139 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 128, 128);
140 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rb10);
141
142 GLRenderbuffer rb1d;
143 glBindRenderbuffer(GL_RENDERBUFFER, rb1d);
144 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT32F, 128, 128);
145 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rb1d);
146
147 EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
148
149 drawQuad(program, "a_position", 0.0f);
150 EXPECT_GL_NO_ERROR();
151
152 // Draw to a no-depth framebuffer using the same program
153 GLFramebuffer fbo2;
154 glBindFramebuffer(GL_FRAMEBUFFER, fbo2);
155
156 GLRenderbuffer rb20;
157 glBindRenderbuffer(GL_RENDERBUFFER, rb20);
158 glRenderbufferStorage(GL_RENDERBUFFER, GL_R8, 64, 64);
159 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rb20);
160
161 EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
162
163 drawQuad(program, "a_position", 0.0f);
164 EXPECT_GL_NO_ERROR();
165 }
166
167 class FragDepthRedeclarationTest : public ANGLETest<>
168 {};
169
170 // Test gl_FragDepth redeclared as vertex output
TEST_P(FragDepthRedeclarationTest,VSOutput)171 TEST_P(FragDepthRedeclarationTest, VSOutput)
172 {
173 constexpr char kVS[] = R"(#version 300 es
174 #extension GL_EXT_conservative_depth: enable
175 out highp float gl_FragDepth;
176 void main() {
177 gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
178 gl_FragDepth = 1.0;
179 })";
180
181 GLProgram prg;
182 prg.makeRaster(kVS, essl3_shaders::fs::Red());
183 EXPECT_FALSE(prg.valid());
184 }
185
186 // Test gl_FragDepth redeclared as fragment input
TEST_P(FragDepthRedeclarationTest,FSInput)187 TEST_P(FragDepthRedeclarationTest, FSInput)
188 {
189 constexpr char kFS[] = R"(#version 300 es
190 #extension GL_EXT_conservative_depth: enable
191 out highp vec4 color;
192 in highp float gl_FragDepth;
193 void main() {
194 color = vec4(gl_FragDepth, 0.0, 0.0, 1.0);
195 })";
196
197 GLProgram prg;
198 prg.makeRaster(essl3_shaders::vs::Simple(), kFS);
199 EXPECT_FALSE(prg.valid());
200 }
201
202 // Test gl_FragDepth redeclaration with no layout qualifier
TEST_P(FragDepthRedeclarationTest,NoLayout)203 TEST_P(FragDepthRedeclarationTest, NoLayout)
204 {
205 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_conservative_depth"));
206
207 constexpr char kFS[] = R"(#version 300 es
208 #extension GL_EXT_conservative_depth: require
209 out highp vec4 color;
210 out highp float gl_FragDepth;
211 void main() {
212 color = vec4(1.0, 0.0, 0.0, 1.0);
213 gl_FragDepth = 1.0;
214 })";
215
216 ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS);
217 }
218
219 // Test gl_FragDepth redeclaration with depth_any layout qualifier
TEST_P(FragDepthRedeclarationTest,Any)220 TEST_P(FragDepthRedeclarationTest, Any)
221 {
222 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_conservative_depth"));
223
224 constexpr char kFS[] = R"(#version 300 es
225 #extension GL_EXT_conservative_depth: require
226 out highp vec4 color;
227 layout (depth_any) out highp float gl_FragDepth;
228 void main() {
229 color = vec4(1.0, 0.0, 0.0, 1.0);
230 gl_FragDepth = 1.0;
231 })";
232
233 ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS);
234 }
235
236 // Test gl_FragDepth redeclaration with depth_greater layout qualifier
TEST_P(FragDepthRedeclarationTest,Greater)237 TEST_P(FragDepthRedeclarationTest, Greater)
238 {
239 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_conservative_depth"));
240
241 constexpr char kFS[] = R"(#version 300 es
242 #extension GL_EXT_conservative_depth: require
243 out highp vec4 color;
244 layout (depth_greater) out highp float gl_FragDepth;
245 void main() {
246 color = vec4(1.0, 0.0, 0.0, 1.0);
247 gl_FragDepth = 1.0;
248 })";
249
250 ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS);
251 }
252
253 // Test gl_FragDepth redeclaration with depth_less layout qualifier
TEST_P(FragDepthRedeclarationTest,Less)254 TEST_P(FragDepthRedeclarationTest, Less)
255 {
256 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_conservative_depth"));
257
258 constexpr char kFS[] = R"(#version 300 es
259 #extension GL_EXT_conservative_depth: require
260 out highp vec4 color;
261 layout (depth_less) out highp float gl_FragDepth;
262 void main() {
263 color = vec4(1.0, 0.0, 0.0, 1.0);
264 gl_FragDepth = 1.0;
265 })";
266
267 ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS);
268 }
269
270 // Test gl_FragDepth redeclaration with depth_unchanged layout qualifier
TEST_P(FragDepthRedeclarationTest,Unchanged)271 TEST_P(FragDepthRedeclarationTest, Unchanged)
272 {
273 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_conservative_depth"));
274
275 constexpr char kFS[] = R"(#version 300 es
276 #extension GL_EXT_conservative_depth: require
277 out highp vec4 color;
278 layout (depth_unchanged) out highp float gl_FragDepth;
279 void main() {
280 color = vec4(1.0, 0.0, 0.0, 1.0);
281 gl_FragDepth = 1.0;
282 })";
283
284 ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS);
285 }
286
287 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(FragDepthTest);
288 ANGLE_INSTANTIATE_TEST_ES3(FragDepthTest);
289
290 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(FragDepthRedeclarationTest);
291 ANGLE_INSTANTIATE_TEST_ES3(FragDepthRedeclarationTest);
292