1 /**************************************************************************
3 * Copyright 2012 VMware, Inc.
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 **************************************************************************/
29 * Triangle Rasterization Overdraw Test
31 * Draws a triangle fan to fill the screen and ensures every pixel was drawn only once
32 * Based on idea from Brian Paul
35 * Contains two methods of drawing to cover both clipped and unclipped triangles:
37 * 1. No-Clip: Picks a random point in the window and walks the perimeter of the window
38 * adding vertices to the triangle fan at non integer steps.
40 * 2. Clip: Picks a random point in the window and adds vertices to the triangle fan
41 * around a circle that contains the entire window, thus going off screen.
44 #include "piglit-util-gl.h"
45 #include "mersenne.hpp"
59 Vector(float x
, float y
)
67 /* Command line arguments */
70 bool break_on_fail
= false;
71 int random_test_count
= 10;
73 /* Piglit variables */
75 PIGLIT_GL_TEST_CONFIG_BEGIN
77 config
.supports_gl_compat_version
= 10;
79 config
.window_width
= 1000;
80 config
.window_height
= 1000;
81 config
.window_visual
= PIGLIT_GL_VISUAL_RGB
| PIGLIT_GL_VISUAL_DOUBLE
;
82 config
.khr_no_error_support
= PIGLIT_NO_ERRORS
;
84 PIGLIT_GL_TEST_CONFIG_END
91 /* Random floating point number between 0 and 1. */
95 const int float_range
= 1 << 23;
96 return (mersenne
.value() % float_range
) * (1.0 / float_range
);
99 /* Random float from [a to b) */
101 random_float(float a
, float b
)
103 return a
+ (b
- a
- 1) * random_float();
110 std::vector
<Vector
> triangle_fan
;
120 bool run(void) const;
124 /* Generates a random triangle fan with a random origin, and contouring a rectangle or circle */
125 void TestCase::generate(void)
127 /* Random center point */
129 mid
.x
= random_float(-0.5*piglit_width
, 1.5*piglit_width
);
130 mid
.y
= random_float(-0.5*piglit_height
, 1.5*piglit_height
);
132 mid
.x
= random_float(0, piglit_width
);
133 mid
.y
= random_float(0, piglit_height
);
139 probe_rect
.w
= piglit_width
;
140 probe_rect
.h
= piglit_height
;
142 probe_rect
.x
= piglit_width
/4;
143 probe_rect
.y
= piglit_height
/4;
144 probe_rect
.w
= piglit_width
/2;
145 probe_rect
.h
= piglit_height
/2;
148 triangle_fan
.clear();
149 triangle_fan
.push_back(mid
);
152 /* Step around the window perimeter adding triangles */
153 double perimeter
= probe_rect
.w
*2 + probe_rect
.h
*2;
156 while (pos
< perimeter
) {
159 if (pos
< probe_rect
.w
) {
161 vertex
.x
= probe_rect
.x
+ pos
;
162 vertex
.y
= probe_rect
.y
+ 0.0f
;
163 } else if (pos
< probe_rect
.w
+ probe_rect
.h
) {
165 vertex
.x
= probe_rect
.x
+ probe_rect
.w
;
166 vertex
.y
= probe_rect
.y
+ pos
- probe_rect
.w
;
167 } else if(pos
< probe_rect
.w
*2 + probe_rect
.h
) {
169 vertex
.x
= probe_rect
.x
+ probe_rect
.w
- (pos
- (probe_rect
.w
+ probe_rect
.h
));
170 vertex
.y
= probe_rect
.y
+ probe_rect
.h
;
173 vertex
.x
= probe_rect
.x
+ 0.0f
;
174 vertex
.y
= probe_rect
.y
+ probe_rect
.h
- (pos
- (probe_rect
.w
*2 + probe_rect
.h
));
177 triangle_fan
.push_back(vertex
);
178 pos
+= random_float();
181 /* Step around a circle that contains the window */
182 double radius
= (sqrt((double)(probe_rect
.w
*probe_rect
.w
+ probe_rect
.h
*probe_rect
.h
)) / 2.0) + 5.0;
183 double perimeter
= 2.0 * M_PI
* radius
;
186 while (pos
< perimeter
) {
187 double theta
= pos
/ radius
;
189 float x
= probe_rect
.x
+ 0.5 * probe_rect
.w
+ cos(theta
) * radius
;
190 float y
= probe_rect
.y
+ 0.5 * probe_rect
.h
+ sin(theta
) * radius
;
192 triangle_fan
.push_back(Vector(x
, y
));
193 pos
+= random_float();
197 /* Complete the fan! */
198 triangle_fan
.push_back(triangle_fan
.at(1));
202 /* Tests a triangle fan */
203 bool TestCase::run(void) const
205 glViewport(0, 0, piglit_width
, piglit_height
);
206 piglit_ortho_projection(piglit_width
, piglit_height
, GL_FALSE
);
208 /* Set render state */
211 glBlendEquation(GL_FUNC_ADD
);
213 glBlendFunc(GL_ONE
, GL_ONE
);
214 colour
[0] = colour
[1] = colour
[2] = 127.0f
/ 255.0f
;
218 * When contouring a circle with very small steps, some overdraw occurs
219 * naturally, but it should cancel itself out, i.e., there should be an
220 * odd number of overdraw inside the shape, and an even number outside.
222 glBlendFunc(GL_ONE_MINUS_DST_COLOR
, GL_ZERO
);
223 colour
[0] = colour
[1] = colour
[2] = 1.0f
;
229 glClearColor(0.0f
, 0.0f
, 0.0f
, 0.0f
);
230 glClear(GL_COLOR_BUFFER_BIT
);
232 /* Draw triangle fan */
233 glEnableClientState(GL_VERTEX_ARRAY
);
234 glVertexPointer(2, GL_FLOAT
, 0, &triangle_fan
.front());
235 glDrawArrays(GL_TRIANGLE_FAN
, 0, triangle_fan
.size());
236 glDisableClientState(GL_VERTEX_ARRAY
);
238 /* Reset draw state */
241 if (!piglit_probe_rect_rgb(probe_rect
.x
, probe_rect
.y
, probe_rect
.w
, probe_rect
.y
, colour
)) {
242 printf("%d. Triangle Fan with %d triangles around (%f, %f)\n",
243 test_id
, (int)triangle_fan
.size(), mid
.x
, mid
.y
);
257 GLboolean pass
= GL_TRUE
;
261 if (piglit_automatic
) {
264 printf("Running %d random tests\n", random_test_count
);
267 for (int i
= 0; i
< random_test_count
&& !(fail_count
&& break_on_fail
); ++i
) {
268 test_case
.generate();
269 if (!test_case
.run())
273 printf("Failed %d random tests\n", fail_count
);
279 test_case
.generate();
280 pass
= pass
&& test_case
.run();
282 piglit_present_results();
285 if (!piglit_check_gl_error(GL_NO_ERROR
))
286 piglit_report_result(PIGLIT_FAIL
);
287 return pass
? PIGLIT_PASS
: PIGLIT_FAIL
;
290 /* Read command line arguments! */
292 piglit_init(int argc
, char **argv
)
294 uint32_t seed
= 0xfacebeef ^ time(NULL
);
296 for (int i
= 1; i
< argc
; ++i
) {
297 if (strcmp(argv
[i
], "-break_on_fail") == 0){
298 break_on_fail
= true;
299 printf("Execution will stop on first fail\n");
300 } else if (strcmp(argv
[i
], "-rect") == 0){
302 } else if (strcmp(argv
[i
], "-max_size") == 0){
303 glGetIntegerv(GL_MAX_TEXTURE_SIZE
, &piglit_width
);
304 piglit_height
= piglit_width
;
305 } else if (strcmp(argv
[i
], "-clip") == 0){
307 printf("Clipped triangles are being tested\n");
308 } else if (i
+ 1 < argc
) {
309 if (strcmp(argv
[i
], "-count") == 0) {
310 random_test_count
= strtoul(argv
[++i
], NULL
, 0);
311 } else if (strcmp(argv
[i
], "-seed") == 0) {
312 seed
= strtoul(argv
[++i
], NULL
, 0);
317 printf("Random seed: 0x%08X\n", seed
);