1 /*
2 * Copyright (c) 2011 VMware, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * on the rights to use, copy, modify, merge, publish, distribute, sub
8 * license, and/or sell copies of the Software, and to permit persons to whom
9 * the Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NON-INFRINGEMENT. IN NO EVENT SHALL VMWARE AND/OR THEIR SUPPLIERS
19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24
25 /**
26 * Tests glPolygonMode wrt facing.
27 * Roland Scheidegger
28 * December 2015
29 */
30
31 #include "piglit-util-gl.h"
32
33 PIGLIT_GL_TEST_CONFIG_BEGIN
34
35 config.supports_gl_compat_version = 20;
36
37 config.window_width = 400;
38 config.window_height = 100;
39 config.window_visual = PIGLIT_GL_VISUAL_RGB | PIGLIT_GL_VISUAL_DOUBLE;
40 config.khr_no_error_support = PIGLIT_NO_ERRORS;
41
42 PIGLIT_GL_TEST_CONFIG_END
43
44 static const char *TestName = "polygon-mode-facing";
45
46 static const char *vstext =
47 "#version 130\n"
48 "\n"
49 "void main()\n"
50 "{\n"
51 " gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
52 "}\n";
53
54 static const char *fstext =
55 "#version 130\n"
56 "\n"
57 "void main()\n"
58 "{\n"
59 " vec4 color = gl_FrontFacing ? vec4(1.0, 0.0, 0.0, 1.0)\n"
60 " : vec4(0.0, 1.0, 0.0, 1.0);\n"
61 " gl_FragColor = color;\n"
62 "}\n";
63
64
65 static const GLfloat Colors[2][4] = {
66 /* back color */
67 {0, 1, 0, 1},
68 /* front color */
69 {1, 0, 0, 1},
70 };
71
72 static const GLfloat Positions[4][4][2] = {
73 {{10, 10},
74 {90, 10},
75 {90, 90},
76 {10, 90}},
77
78 {{190, 10},
79 {110, 10},
80 {110, 90},
81 {190, 90}},
82
83 {{290, 10},
84 {210, 10},
85 {210, 90},
86 {290, 90}},
87
88 {{310, 10},
89 {390, 10},
90 {390, 90},
91 {310, 90}},
92 };
93
94 static GLenum
get_prim_mode(GLenum mode)95 get_prim_mode(GLenum mode)
96 {
97 switch (mode) {
98 case GL_POINT:
99 return GL_POINTS;
100 case GL_LINE:
101 return GL_LINE_LOOP;
102 case GL_FILL:
103 return GL_QUADS;
104 default:
105 return 0;
106 }
107 }
108
109
110 /**
111 * Probe a 3x3 pixel region to see if any of the pixels matches the
112 * expected color.
113 */
114 static GLboolean
probe_region(float px,float py,const GLfloat expectedColor[4])115 probe_region(float px, float py, const GLfloat expectedColor[4])
116 {
117 GLfloat img[3][3][4];
118 int i, j;
119
120 glReadPixels(px-1, py-1, 3, 3, GL_RGBA, GL_FLOAT, img);
121
122 /* see if any of the pixels matches the expected color */
123 for (i = 0; i < 3; i++) {
124 for (j = 0; j < 3; j++) {
125 if (img[i][j][0] == expectedColor[0] &&
126 img[i][j][1] == expectedColor[1] &&
127 img[i][j][2] == expectedColor[2]) {
128 return GL_TRUE;
129 }
130 }
131 }
132
133 return GL_FALSE;
134 }
135
136
137 /**
138 * Examine the pixels drawn by a rect using the four vertex positions
139 * and determine if it was drawn filled, outlined, or as four points.
140 * \return GL_FILL, GL_LINE, GL_POINT or GL_NONE
141 */
142 static GLenum
identify_primitive(const GLfloat positions[4][2],const GLfloat expectedColor[4])143 identify_primitive(const GLfloat positions[4][2],
144 const GLfloat expectedColor[4])
145 {
146 /* center */
147 float cx = (positions[0][0] + positions[2][0]) / 2.0;
148 float cy = (positions[0][1] + positions[2][1]) / 2.0;
149 /* left edge */
150 float lx = MIN2(positions[0][0], positions[2][0]);
151 float ly = cy;
152 /* right edge */
153 float rx = MAX2(positions[0][0], positions[2][0]);
154 float ry = cy;
155 /* bottom edge */
156 float bx = cx;
157 float by = positions[0][1];
158 /* top edge */
159 float tx = cx;
160 float ty = positions[1][1];
161
162 /* probe center */
163 if (probe_region(cx, cy, expectedColor))
164 return GL_FILL;
165
166 /* probe left edge */
167 if (probe_region(lx, ly, expectedColor)) {
168 /* and bottom edge */
169 if (probe_region(bx, by, expectedColor)) {
170 /* and right edge */
171 if (probe_region(rx, ry, expectedColor)) {
172 /* and top edge */
173 if (probe_region(tx, ty, expectedColor)) {
174 return GL_LINE;
175 }
176 }
177 }
178 }
179
180 /* probe lower-left corner */
181 if (probe_region(lx, by, expectedColor)) {
182 /* probe lower-right corner */
183 if (probe_region(rx, by, expectedColor)) {
184 /* probe top-left corner */
185 if (probe_region(lx, ty, expectedColor)) {
186 /* probe top-right corner */
187 if (probe_region(rx, ty, expectedColor)) {
188 return GL_POINT;
189 }
190 }
191 }
192 }
193
194 return GL_NONE;
195 }
196
197
198
199 static GLboolean
test_combo(GLenum frontMode,GLenum backMode)200 test_combo(GLenum frontMode, GLenum backMode)
201 {
202 GLenum frontPrim = get_prim_mode(frontMode);
203 GLenum backPrim = get_prim_mode(backMode);
204 GLboolean pass = GL_TRUE;
205 GLenum expectedPrims[4];
206 int i;
207 int expectFrontColorRef[4] = {1,1,1,1};
208
209 glClear(GL_COLOR_BUFFER_BIT);
210
211 /*
212 * Drawing 4 quads. The first and 3rd should always be red (front facing).
213 * The 2nd and 4th are green with FILL backMode (lines/points are always
214 * front facing).
215 */
216 if (backMode == GL_FILL) {
217 expectFrontColorRef[1] = expectFrontColorRef[3] = 0;
218 }
219
220 /* Draw reference image */
221 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
222 glFrontFace(GL_CCW);
223 glDrawArrays(frontPrim, 0, 4);
224 glDrawArrays(backPrim, 4, 4);
225 glFrontFace(GL_CW);
226 glDrawArrays(frontPrim, 8, 4);
227 glDrawArrays(backPrim, 12, 4);
228
229 /* determine what kind of primitives were drawn */
230 for (i = 0; i < 4; i++) {
231 bool err = false;
232 expectedPrims[i] = identify_primitive(Positions[i], Colors[expectFrontColorRef[i]]);
233 if (i & 1) {
234 if (expectedPrims[i] != backMode) {
235 err = true;
236 }
237 }
238 else {
239 if (expectedPrims[i] != frontMode) {
240 err = true;
241 }
242 }
243 if (err) {
244 /* we didn't get the expected reference primitive */
245 fprintf(stderr,
246 "%s: reference drawing failed for frontPrim=%s, backPrim=%s\n",
247 TestName, piglit_get_gl_enum_name(frontMode),
248 piglit_get_gl_enum_name(backMode));
249 return GL_FALSE;
250 }
251 }
252
253 /* Draw test image */
254 glClear(GL_COLOR_BUFFER_BIT);
255 glPolygonMode(GL_FRONT, frontMode);
256 glPolygonMode(GL_BACK, backMode);
257 glFrontFace(GL_CCW);
258 glDrawArrays(GL_QUADS, 0, 8);
259 glFrontFace(GL_CW);
260 glDrawArrays(GL_QUADS, 8, 8);
261
262 /* check that these prims match expectations */
263 /*
264 * The first and 3rd should always be red (front-facing), the 2nd and 4th
265 * green (back-facing).
266 */
267 for (i = 0; i < 4; i++) {
268 GLenum prim = identify_primitive(Positions[i], Colors[!(i % 2)]);
269 if (prim != expectedPrims[i]) {
270 fprintf(stderr, "%s: glPolygonMode(front=%s, back=%s) failed\n",
271 TestName, piglit_get_gl_enum_name(frontMode),
272 piglit_get_gl_enum_name(backMode));
273 pass = GL_FALSE;
274 }
275 }
276
277 piglit_present_results();
278
279 return pass;
280 }
281
282
283 static GLboolean
test_polygonmode(void)284 test_polygonmode(void)
285 {
286 GLenum pass = GL_TRUE;
287
288 glVertexPointer(2, GL_FLOAT, 0, Positions);
289 glEnableClientState(GL_VERTEX_ARRAY);
290
291 /*
292 * First test with same front/back mode.
293 * Those are probably more important to get right...
294 */
295 if (!test_combo(GL_FILL, GL_FILL))
296 pass = GL_FALSE;
297
298 if (!test_combo(GL_POINT, GL_POINT))
299 pass = GL_FALSE;
300
301 /*
302 * Be extra mean to mesa draw stage interactions turning lines back
303 * to tris...
304 */
305 glEnable(GL_LINE_SMOOTH);
306
307 if (!test_combo(GL_LINE, GL_LINE))
308 pass = GL_FALSE;
309
310 glDisable(GL_LINE_SMOOTH);
311
312 if (!test_combo(GL_FILL, GL_POINT))
313 pass = GL_FALSE;
314
315 if (!test_combo(GL_POINT, GL_LINE))
316 pass = GL_FALSE;
317
318 if (!test_combo(GL_POINT, GL_FILL))
319 pass = GL_FALSE;
320
321 if (!test_combo(GL_LINE, GL_FILL))
322 pass = GL_FALSE;
323
324 if (!test_combo(GL_LINE, GL_POINT))
325 pass = GL_FALSE;
326
327
328 /*
329 * Be really mean to mesa draw stage interactions turning lines back
330 * to tris...
331 */
332 glEnable(GL_LINE_SMOOTH);
333
334 if (!test_combo(GL_FILL, GL_LINE))
335 pass = GL_FALSE;
336
337 if (!test_combo(GL_POINT, GL_LINE))
338 pass = GL_FALSE;
339
340 if (!test_combo(GL_LINE, GL_FILL))
341 pass = GL_FALSE;
342
343 if (!test_combo(GL_LINE, GL_POINT))
344 pass = GL_FALSE;
345
346 return pass;
347 }
348
349
350 enum piglit_result
piglit_display(void)351 piglit_display(void)
352 {
353 if (!test_polygonmode())
354 return PIGLIT_FAIL;
355
356 return PIGLIT_PASS;
357 }
358
359
360 void
piglit_init(int argc,char ** argv)361 piglit_init(int argc, char **argv)
362 {
363 GLuint prog;
364 piglit_require_GLSL_version(130);
365 piglit_ortho_projection(piglit_width, piglit_height, false);
366 prog = piglit_build_simple_program(vstext, fstext);
367 glUseProgram(prog);
368 }
369