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