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 // PolygonModeTest.cpp: Test cases for GL_NV_polygon_mode and GL_ANGLE_polygon_mode
7 //
8
9 #include "test_utils/ANGLETest.h"
10 #include "test_utils/gl_raii.h"
11
12 using namespace angle;
13
14 class PolygonModeTest : public ANGLETest<>
15 {
16 protected:
PolygonModeTest()17 PolygonModeTest()
18 {
19 setConfigRedBits(8);
20 setConfigGreenBits(8);
21 setConfigBlueBits(8);
22 setConfigAlphaBits(8);
23 setConfigDepthBits(24);
24 setExtensionsEnabled(false);
25 setWindowWidth(16);
26 setWindowHeight(16);
27 }
28 };
29
30 // New state queries and commands fail without the extension
TEST_P(PolygonModeTest,NoExtension)31 TEST_P(PolygonModeTest, NoExtension)
32 {
33 {
34 GLint mode = 0;
35 glGetIntegerv(GL_POLYGON_MODE_NV, &mode);
36 EXPECT_GL_ERROR(GL_INVALID_ENUM);
37 EXPECT_EQ(mode, 0);
38
39 glPolygonModeNV(GL_FRONT_AND_BACK, GL_FILL_NV);
40 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
41
42 glPolygonModeANGLE(GL_FRONT_AND_BACK, GL_FILL_NV);
43 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
44 }
45 for (GLenum state : {GL_POLYGON_OFFSET_POINT_NV, GL_POLYGON_OFFSET_LINE_NV})
46 {
47 EXPECT_FALSE(glIsEnabled(state));
48 EXPECT_GL_ERROR(GL_INVALID_ENUM);
49
50 GLboolean enabled = true;
51 glGetBooleanv(state, &enabled);
52 EXPECT_GL_ERROR(GL_INVALID_ENUM);
53 EXPECT_TRUE(enabled);
54
55 glEnable(state);
56 EXPECT_GL_ERROR(GL_INVALID_ENUM);
57
58 glDisable(state);
59 EXPECT_GL_ERROR(GL_INVALID_ENUM);
60 }
61 }
62
63 // Test NV_polygon_mode entrypoints
TEST_P(PolygonModeTest,ExtensionStateNV)64 TEST_P(PolygonModeTest, ExtensionStateNV)
65 {
66 ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_NV_polygon_mode"));
67
68 // Default state
69 {
70 GLint mode = 0;
71 glGetIntegerv(GL_POLYGON_MODE_NV, &mode);
72 EXPECT_GLENUM_EQ(GL_FILL_NV, mode);
73 EXPECT_GL_NO_ERROR();
74 }
75 for (GLenum state : {GL_POLYGON_OFFSET_POINT_NV, GL_POLYGON_OFFSET_LINE_NV})
76 {
77 EXPECT_FALSE(glIsEnabled(state));
78 EXPECT_GL_NO_ERROR();
79
80 GLboolean enabled = true;
81 glGetBooleanv(state, &enabled);
82 EXPECT_FALSE(enabled);
83 EXPECT_GL_NO_ERROR();
84 }
85
86 // Polygon mode state updates
87 for (GLenum mode : {GL_POINT_NV, GL_LINE_NV, GL_FILL_NV})
88 {
89 glPolygonModeNV(GL_FRONT_AND_BACK, mode);
90 EXPECT_GL_NO_ERROR();
91
92 GLint result = 0;
93 glGetIntegerv(GL_POLYGON_MODE_NV, &result);
94 EXPECT_GLENUM_EQ(mode, result);
95 EXPECT_GL_NO_ERROR();
96 }
97
98 // Polygon offset state updates
99 for (GLenum state : {GL_POLYGON_OFFSET_POINT_NV, GL_POLYGON_OFFSET_LINE_NV})
100 {
101 GLboolean enabled = false;
102
103 glEnable(state);
104 EXPECT_GL_NO_ERROR();
105
106 EXPECT_TRUE(glIsEnabled(state));
107 EXPECT_GL_NO_ERROR();
108
109 glGetBooleanv(state, &enabled);
110 EXPECT_GL_NO_ERROR();
111 EXPECT_TRUE(enabled);
112
113 glDisable(state);
114 EXPECT_GL_NO_ERROR();
115
116 EXPECT_FALSE(glIsEnabled(state));
117 EXPECT_GL_NO_ERROR();
118
119 glGetBooleanv(state, &enabled);
120 EXPECT_GL_NO_ERROR();
121 EXPECT_FALSE(enabled);
122 }
123
124 // Errors
125 {
126 glPolygonModeNV(GL_FRONT, GL_FILL_NV);
127 EXPECT_GL_ERROR(GL_INVALID_ENUM);
128
129 glPolygonModeNV(GL_BACK, GL_FILL_NV);
130 EXPECT_GL_ERROR(GL_INVALID_ENUM);
131
132 glPolygonModeNV(GL_FRONT_AND_BACK, 0);
133 EXPECT_GL_ERROR(GL_INVALID_ENUM);
134 }
135 }
136
137 // Test ANGLE_polygon_mode entrypoints
TEST_P(PolygonModeTest,ExtensionStateANGLE)138 TEST_P(PolygonModeTest, ExtensionStateANGLE)
139 {
140 ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_ANGLE_polygon_mode"));
141
142 // Default state
143 {
144 GLint mode = 0;
145 glGetIntegerv(GL_POLYGON_MODE_ANGLE, &mode);
146 EXPECT_GLENUM_EQ(GL_FILL_ANGLE, mode);
147 EXPECT_GL_NO_ERROR();
148 }
149 for (GLenum state : {GL_POLYGON_OFFSET_LINE_ANGLE})
150 {
151 EXPECT_FALSE(glIsEnabled(state));
152 EXPECT_GL_NO_ERROR();
153
154 GLboolean enabled = true;
155 glGetBooleanv(state, &enabled);
156 EXPECT_FALSE(enabled);
157 EXPECT_GL_NO_ERROR();
158 }
159
160 // Polygon mode state updates
161 for (GLenum mode : {GL_LINE_ANGLE, GL_FILL_ANGLE})
162 {
163 glPolygonModeANGLE(GL_FRONT_AND_BACK, mode);
164 EXPECT_GL_NO_ERROR();
165
166 GLint result = 0;
167 glGetIntegerv(GL_POLYGON_MODE_ANGLE, &result);
168 EXPECT_GLENUM_EQ(mode, result);
169 EXPECT_GL_NO_ERROR();
170 }
171
172 // Polygon offset state updates
173 for (GLenum state : {GL_POLYGON_OFFSET_LINE_ANGLE})
174 {
175 GLboolean enabled = false;
176
177 glEnable(state);
178 EXPECT_GL_NO_ERROR();
179
180 EXPECT_TRUE(glIsEnabled(state));
181 EXPECT_GL_NO_ERROR();
182
183 glGetBooleanv(state, &enabled);
184 EXPECT_GL_NO_ERROR();
185 EXPECT_TRUE(enabled);
186
187 glDisable(state);
188 EXPECT_GL_NO_ERROR();
189
190 EXPECT_FALSE(glIsEnabled(state));
191 EXPECT_GL_NO_ERROR();
192
193 glGetBooleanv(state, &enabled);
194 EXPECT_GL_NO_ERROR();
195 EXPECT_FALSE(enabled);
196 }
197
198 // Errors
199 {
200 glPolygonModeANGLE(GL_FRONT, GL_FILL_ANGLE);
201 EXPECT_GL_ERROR(GL_INVALID_ENUM);
202
203 glPolygonModeANGLE(GL_BACK, GL_FILL_ANGLE);
204 EXPECT_GL_ERROR(GL_INVALID_ENUM);
205
206 glPolygonModeANGLE(GL_FRONT_AND_BACK, 0);
207 EXPECT_GL_ERROR(GL_INVALID_ENUM);
208
209 glPolygonModeANGLE(GL_FRONT_AND_BACK, GL_POINT_NV);
210 EXPECT_GL_ERROR(GL_INVALID_ENUM);
211
212 glIsEnabled(GL_POLYGON_OFFSET_POINT_NV);
213 EXPECT_GL_ERROR(GL_INVALID_ENUM);
214
215 GLboolean enabled = true;
216 glGetBooleanv(GL_POLYGON_OFFSET_POINT_NV, &enabled);
217 EXPECT_GL_ERROR(GL_INVALID_ENUM);
218 }
219 }
220
221 // Test line rasterization mode
TEST_P(PolygonModeTest,DrawLines)222 TEST_P(PolygonModeTest, DrawLines)
223 {
224 const bool extensionNV = EnsureGLExtensionEnabled("GL_NV_polygon_mode");
225 const bool extensionANGLE = EnsureGLExtensionEnabled("GL_ANGLE_polygon_mode");
226 ANGLE_SKIP_TEST_IF(!extensionNV && !extensionANGLE);
227
228 ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor());
229 glUseProgram(program);
230 GLint colorLocation = glGetUniformLocation(program, essl1_shaders::ColorUniform());
231
232 const int w = getWindowWidth();
233 const int h = getWindowHeight();
234 ASSERT(w == h);
235
236 for (bool useNV : {true, false})
237 {
238 if (useNV && !extensionNV)
239 {
240 continue;
241 }
242
243 glClearColor(1, 0, 0, 1);
244 glClear(GL_COLOR_BUFFER_BIT);
245 EXPECT_PIXEL_RECT_EQ(0, 0, w, h, GLColor::red);
246
247 // Draw green quad with lines
248 if (useNV)
249 {
250 glPolygonModeNV(GL_FRONT_AND_BACK, GL_LINE_NV);
251 }
252 else
253 {
254 glPolygonModeANGLE(GL_FRONT_AND_BACK, GL_LINE_ANGLE);
255 }
256 glUniform4f(colorLocation, 0.0, 1.0, 0.0, 1.0);
257 drawQuad(program, essl1_shaders::PositionAttrib(), 0.0);
258
259 // Nothing was drawn inside triangles
260 EXPECT_PIXEL_RECT_EQ(1, 1, 5, 5, GLColor::red);
261 EXPECT_PIXEL_RECT_EQ(9, 9, 5, 5, GLColor::red);
262
263 // Main diagonal was drawn
264 std::vector<GLColor> colors(w * h);
265 glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, colors.data());
266 for (int i = 0; i < w; i++)
267 {
268 const int x = i;
269 const int y = w - 1 - i;
270 EXPECT_EQ(GLColor::green, colors[y * w + x]) << "x: " << x << " y: " << y;
271 }
272
273 // Draw blue quad with triangles
274 if (useNV)
275 {
276 glPolygonModeNV(GL_FRONT_AND_BACK, GL_FILL_NV);
277 }
278 else
279 {
280 glPolygonModeANGLE(GL_FRONT_AND_BACK, GL_FILL_ANGLE);
281 }
282 glUniform4f(colorLocation, 0.0, 0.0, 1.0, 1.0);
283 drawQuad(program, essl1_shaders::PositionAttrib(), 0.0);
284 EXPECT_PIXEL_RECT_EQ(0, 0, w, h, GLColor::blue);
285 }
286 }
287
288 // Test line rasterization mode with depth offset
TEST_P(PolygonModeTest,DrawLinesWithDepthOffset)289 TEST_P(PolygonModeTest, DrawLinesWithDepthOffset)
290 {
291 const bool extensionNV = EnsureGLExtensionEnabled("GL_NV_polygon_mode");
292 const bool extensionANGLE = EnsureGLExtensionEnabled("GL_ANGLE_polygon_mode");
293 ANGLE_SKIP_TEST_IF(!extensionNV && !extensionANGLE);
294
295 ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor());
296 glUseProgram(program);
297 GLint colorLocation = glGetUniformLocation(program, essl1_shaders::ColorUniform());
298
299 const int w = getWindowWidth();
300 const int h = getWindowHeight();
301 ASSERT(w == h);
302
303 glEnable(GL_DEPTH_TEST);
304
305 for (bool useNV : {true, false})
306 {
307 if (useNV && !extensionNV)
308 {
309 continue;
310 }
311
312 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
313
314 // Draw red quad filled
315 if (useNV)
316 {
317 glPolygonModeNV(GL_FRONT_AND_BACK, GL_FILL_NV);
318 }
319 else
320 {
321 glPolygonModeANGLE(GL_FRONT_AND_BACK, GL_FILL_ANGLE);
322 }
323 glUniform4f(colorLocation, 1.0, 0.0, 0.0, 1.0);
324 drawQuad(program, essl1_shaders::PositionAttrib(), 0.5);
325
326 // Draw green quad using lines with offset failing the depth test
327 if (useNV)
328 {
329 glEnable(GL_POLYGON_OFFSET_LINE_NV);
330 glPolygonModeNV(GL_FRONT_AND_BACK, GL_LINE_NV);
331 }
332 else
333 {
334 glEnable(GL_POLYGON_OFFSET_LINE_ANGLE);
335 glPolygonModeANGLE(GL_FRONT_AND_BACK, GL_LINE_ANGLE);
336 }
337 glPolygonOffset(0.0, 2.0);
338 glUniform4f(colorLocation, 0.0, 1.0, 0.0, 1.0);
339 drawQuad(program, essl1_shaders::PositionAttrib(), 0.5);
340
341 // Depth test must fail
342 EXPECT_PIXEL_RECT_EQ(0, 0, w, h, GLColor::red);
343
344 // Draw green quad with triangles
345 if (useNV)
346 {
347 glPolygonModeNV(GL_FRONT_AND_BACK, GL_FILL_NV);
348 }
349 else
350 {
351 glPolygonModeANGLE(GL_FRONT_AND_BACK, GL_FILL_ANGLE);
352 }
353 drawQuad(program, essl1_shaders::PositionAttrib(), 0.0);
354
355 // Change the offset so that depth test passes
356 glPolygonOffset(0.0, -2.0);
357
358 // Draw blue quad with lines
359 if (useNV)
360 {
361 glPolygonModeNV(GL_FRONT_AND_BACK, GL_LINE_NV);
362 }
363 else
364 {
365 glPolygonModeANGLE(GL_FRONT_AND_BACK, GL_LINE_ANGLE);
366 }
367 glUniform4f(colorLocation, 0.0, 0.0, 1.0, 1.0);
368 drawQuad(program, essl1_shaders::PositionAttrib(), 0.0);
369
370 // Main diagonal was drawn
371 std::vector<GLColor> colors(w * h);
372 glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, colors.data());
373 for (int i = 0; i < w; i++)
374 {
375 const int x = i;
376 const int y = w - 1 - i;
377 EXPECT_EQ(GLColor::blue, colors[y * w + x]) << "x: " << x << " y: " << y;
378 }
379 }
380 }
381
382 ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(PolygonModeTest);
383