xref: /aosp_15_r20/external/angle/src/tests/gl_tests/PolygonOffsetClampTest.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1 //
2 // Copyright 2023 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 // PolygonOffsetClampTest.cpp: Test cases for GL_EXT_polygon_offset_clamp
7 //
8 
9 #include "test_utils/ANGLETest.h"
10 #include "test_utils/gl_raii.h"
11 #include "util/EGLWindow.h"
12 #include "util/test_utils.h"
13 
14 using namespace angle;
15 
16 class PolygonOffsetClampTest : public ANGLETest<>
17 {
18   protected:
PolygonOffsetClampTest()19     PolygonOffsetClampTest()
20     {
21         setConfigRedBits(8);
22         setConfigGreenBits(8);
23         setConfigBlueBits(8);
24         setConfigAlphaBits(8);
25         setConfigDepthBits(24);
26         setExtensionsEnabled(false);
27     }
28 };
29 
30 // Test state queries and updates
TEST_P(PolygonOffsetClampTest,State)31 TEST_P(PolygonOffsetClampTest, State)
32 {
33     // New state query fails without the extension
34     {
35         GLfloat clamp = -1.0f;
36         glGetFloatv(GL_POLYGON_OFFSET_CLAMP_EXT, &clamp);
37         EXPECT_GL_ERROR(GL_INVALID_ENUM);
38         EXPECT_EQ(clamp, -1.0f);
39 
40         ASSERT_GL_NO_ERROR();
41     }
42 
43     // New function does nothing without enabling the extension
44     {
45         glPolygonOffsetClampEXT(1.0f, 2.0f, 3.0f);
46         EXPECT_GL_ERROR(GL_INVALID_OPERATION);
47 
48         GLfloat factor = -1.0f;
49         glGetFloatv(GL_POLYGON_OFFSET_FACTOR, &factor);
50         EXPECT_EQ(factor, 0.0f);
51 
52         GLfloat units = -1.0f;
53         glGetFloatv(GL_POLYGON_OFFSET_UNITS, &units);
54         EXPECT_EQ(units, 0.0f);
55 
56         ASSERT_GL_NO_ERROR();
57     }
58 
59     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_polygon_offset_clamp"));
60 
61     // Default state
62     {
63         GLfloat factor = -1.0f;
64         glGetFloatv(GL_POLYGON_OFFSET_FACTOR, &factor);
65         EXPECT_EQ(factor, 0.0f);
66 
67         GLfloat units = -1.0f;
68         glGetFloatv(GL_POLYGON_OFFSET_UNITS, &units);
69         EXPECT_EQ(units, 0.0f);
70 
71         GLfloat clamp = -1.0f;
72         glGetFloatv(GL_POLYGON_OFFSET_CLAMP_EXT, &clamp);
73         EXPECT_EQ(clamp, 0.0f);
74 
75         ASSERT_GL_NO_ERROR();
76     }
77 
78     // Full state update using the new function
79     {
80         glPolygonOffsetClampEXT(1.0f, 2.0f, 3.0f);
81 
82         GLfloat factor = -1.0f;
83         glGetFloatv(GL_POLYGON_OFFSET_FACTOR, &factor);
84         EXPECT_EQ(factor, 1.0f);
85 
86         GLfloat units = -1.0f;
87         glGetFloatv(GL_POLYGON_OFFSET_UNITS, &units);
88         EXPECT_EQ(units, 2.0f);
89 
90         GLfloat clamp = -1.0f;
91         glGetFloatv(GL_POLYGON_OFFSET_CLAMP_EXT, &clamp);
92         EXPECT_EQ(clamp, 3.0f);
93 
94         ASSERT_GL_NO_ERROR();
95     }
96 
97     // Core function resets the clamp value to zero
98     {
99         glPolygonOffset(4.0f, 5.0f);
100 
101         GLfloat factor = -1.0f;
102         glGetFloatv(GL_POLYGON_OFFSET_FACTOR, &factor);
103         EXPECT_EQ(factor, 4.0f);
104 
105         GLfloat units = -1.0f;
106         glGetFloatv(GL_POLYGON_OFFSET_UNITS, &units);
107         EXPECT_EQ(units, 5.0f);
108 
109         GLfloat clamp = -1.0f;
110         glGetFloatv(GL_POLYGON_OFFSET_CLAMP_EXT, &clamp);
111         EXPECT_EQ(clamp, 0.0f);
112 
113         ASSERT_GL_NO_ERROR();
114     }
115 
116     // NaNs must be accepted and replaced with zeros
117     {
118         glPolygonOffsetClampEXT(6.0f, 7.0f, 8.0f);
119 
120         float nan = std::numeric_limits<float>::quiet_NaN();
121         glPolygonOffsetClampEXT(nan, nan, nan);
122 
123         GLfloat factor = -1.0f;
124         glGetFloatv(GL_POLYGON_OFFSET_FACTOR, &factor);
125         EXPECT_EQ(factor, 0.0f);
126 
127         GLfloat units = -1.0f;
128         glGetFloatv(GL_POLYGON_OFFSET_UNITS, &units);
129         EXPECT_EQ(units, 0.0f);
130 
131         GLfloat clamp = -1.0f;
132         glGetFloatv(GL_POLYGON_OFFSET_CLAMP_EXT, &clamp);
133         EXPECT_EQ(clamp, 0.0f);
134 
135         ASSERT_GL_NO_ERROR();
136     }
137 }
138 
139 // Test polygon offset clamping behavior. Ported from dEQP.
TEST_P(PolygonOffsetClampTest,Operation)140 TEST_P(PolygonOffsetClampTest, Operation)
141 {
142     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_polygon_offset_clamp"));
143     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_ANGLE_depth_texture"));
144 
145     GLTexture depthTexture;
146     glBindTexture(GL_TEXTURE_2D, depthTexture);
147     glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, 64, 64, 0, GL_DEPTH_COMPONENT,
148                  GL_UNSIGNED_SHORT, nullptr);
149     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
150     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
151 
152     GLTexture colorTexture;
153     glBindTexture(GL_TEXTURE_2D, colorTexture);
154     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
155     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
156     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
157 
158     GLFramebuffer fbo;
159     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
160     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthTexture, 0);
161     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTexture, 0);
162 
163     GLTexture colorReadbackTexture;
164     glBindTexture(GL_TEXTURE_2D, colorReadbackTexture);
165     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
166     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
167     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
168 
169     GLFramebuffer fboReadback;
170     glBindFramebuffer(GL_FRAMEBUFFER, fboReadback);
171     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
172                            colorReadbackTexture, 0);
173 
174     ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
175 
176     constexpr char kFS[] = R"(
177 varying highp vec2 v_texCoord;
178 uniform highp sampler2D tex;
179 void main()
180 {
181     // Store as unorm24
182     highp float d = floor(texture2D(tex, v_texCoord).r * 16777215.0);
183     highp float r = floor(d / 65536.0);
184     highp float g = floor(mod(d, 65536.0) / 256.0);
185     highp float b = mod(d, 256.0);
186     gl_FragColor = vec4(r, g, b, 1.0) / 255.0;
187 })";
188 
189     ANGLE_GL_PROGRAM(readDepthProgram, essl1_shaders::vs::Texture2D(), kFS);
190 
191     // Setup depth testing
192     glEnable(GL_DEPTH_TEST);
193     glDepthFunc(GL_ALWAYS);
194 
195     // Bind framebuffer for drawing
196     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
197 
198     // Offset units and clamp values. Should work with all depth buffer formats.
199     const std::vector<std::array<GLfloat, 2>> testValues = {
200         {-5000.0f, -0.0001f},
201         {+5000.0f, +0.0001f},
202         {-5000.0f, 0.0f},
203         {+5000.0f, 0.0f},
204         {-5000.0f, -std::numeric_limits<float>::infinity()},
205         {+5000.0f, +std::numeric_limits<float>::infinity()}};
206 
207     auto readDepthValue = [&]() {
208         glBindFramebuffer(GL_FRAMEBUFFER, fboReadback);
209         glDisable(GL_DEPTH_TEST);
210         glUseProgram(readDepthProgram);
211         glUniform1i(glGetUniformLocation(readDepthProgram, "tex"), 0);
212 
213         glBindTexture(GL_TEXTURE_2D, depthTexture);
214         drawQuad(readDepthProgram, "a_position", 0.5);
215 
216         GLubyte pixels[4];
217         glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
218 
219         // Convert read depth value to GLfloat normalized
220         GLfloat depthValue = (GLfloat)(pixels[0] * 65536 + pixels[1] * 256 + pixels[2]) / 0xFFFFFF;
221 
222         // Restore state
223         glBindFramebuffer(GL_FRAMEBUFFER, fbo);
224         glEnable(GL_DEPTH_TEST);
225         glUseProgram(testProgram);
226 
227         return depthValue;
228     };
229 
230     for (auto testValue : testValues)
231     {
232         const GLfloat units = testValue[0];
233         const GLfloat clamp = testValue[1];
234 
235         // Draw reference polygon
236         glDisable(GL_POLYGON_OFFSET_FILL);
237         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
238         drawQuad(testProgram, "a_position", 0.0);
239 
240         // Get reference depth value
241         const GLfloat depthValue = readDepthValue();
242 
243         // Draw polygon with depth offset
244         glEnable(GL_POLYGON_OFFSET_FILL);
245         glPolygonOffset(0.0f, units);
246         drawQuad(testProgram, "a_position", 0.0);
247 
248         // Get depth value with offset
249         const GLfloat depthValueOffset = readDepthValue();
250 
251         // Draw reference polygon
252         glDisable(GL_POLYGON_OFFSET_FILL);
253         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
254         drawQuad(testProgram, "a_position", 0.0);
255 
256         // Draw polygon with depth offset
257         glEnable(GL_POLYGON_OFFSET_FILL);
258         glPolygonOffsetClampEXT(0.0f, units, clamp);
259         drawQuad(testProgram, "a_position", 0.0);
260 
261         // Get depth value with clamped offset
262         const GLfloat depthValueOffsetClamp = readDepthValue();
263 
264         // Check depth values
265         {
266             if (clamp == 0.0f || isinf(clamp))
267             {
268                 ASSERT_NE(units, 0.0f);
269 
270                 // Ensure that offset works
271                 if (units > 0.0f)
272                 {
273                     EXPECT_LT(depthValue, depthValueOffset);
274                     EXPECT_LT(depthValue, depthValueOffsetClamp);
275                 }
276                 else if (units < 0.0f)
277                 {
278                     EXPECT_GT(depthValue, depthValueOffset);
279                     EXPECT_GT(depthValue, depthValueOffsetClamp);
280                 }
281 
282                 // Clamping must have no effect
283                 EXPECT_EQ(depthValueOffset, depthValueOffsetClamp);
284             }
285             else if (clamp < 0.0f)
286             {
287                 ASSERT_LT(units, 0);
288 
289                 // Negative clamp value sets effective offset to max(offset, clamp)
290                 EXPECT_GT(depthValue, depthValueOffset);
291                 EXPECT_GT(depthValue, depthValueOffsetClamp);
292                 EXPECT_LT(depthValueOffset, depthValueOffsetClamp);
293             }
294             else if (clamp > 0.0f)
295             {
296                 ASSERT_GT(units, 0);
297 
298                 // Positive clamp value sets effective offset to min(offset, clamp)
299                 EXPECT_LT(depthValue, depthValueOffset);
300                 EXPECT_LT(depthValue, depthValueOffsetClamp);
301                 EXPECT_GT(depthValueOffset, depthValueOffsetClamp);
302             }
303         }
304     }
305 }
306 
307 ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(PolygonOffsetClampTest);
308