fix the spelling in whole piglit
[piglit.git] / tests / general / triangle-rasterization-overdraw.cpp
blobabeaf226c066c7b747822574635fa897fe77b0be
1 /**************************************************************************
3 * Copyright 2012 VMware, Inc.
4 * All Rights Reserved.
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
16 * of the Software.
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 **************************************************************************/
28 /**
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"
47 #include <time.h>
48 #include <vector>
49 #include <algorithm>
51 /* Data structures */
52 struct Vector
54 Vector()
55 : x(0), y(0)
59 Vector(float x, float y)
60 : x(x), y(y)
64 float x, y;
67 /* Command line arguments */
68 bool rect = false;
69 bool clips = false;
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
86 /* Globals */
87 int test_id = 0;
88 Mersenne mersenne;
91 /* Random floating point number between 0 and 1. */
92 static inline float
93 random_float(void)
95 const int float_range = 1 << 23;
96 return (mersenne.value() % float_range) * (1.0 / float_range);
99 /* Random float from [a to b) */
100 static inline float
101 random_float(float a, float b)
103 return a + (b - a - 1) * random_float();
107 struct TestCase
109 Vector mid;
110 std::vector<Vector> triangle_fan;
112 struct {
113 int x;
114 int y;
115 int w;
116 int h;
117 } probe_rect;
119 void generate(void);
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 */
128 if (clips) {
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);
131 } else {
132 mid.x = random_float(0, piglit_width);
133 mid.y = random_float(0, piglit_height);
136 if (clips) {
137 probe_rect.x = 0;
138 probe_rect.y = 0;
139 probe_rect.w = piglit_width;
140 probe_rect.h = piglit_height;
141 } else {
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);
151 if (rect) {
152 /* Step around the window perimeter adding triangles */
153 double perimeter = probe_rect.w*2 + probe_rect.h*2;
154 double pos = 0.0;
156 while (pos < perimeter) {
157 Vector vertex;
159 if (pos < probe_rect.w) {
160 /* bottom */
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) {
164 /* right */
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) {
168 /* top */
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;
171 } else {
172 /* left */
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();
180 } else {
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;
184 double pos = 0.0;
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));
199 ++test_id;
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 */
209 float colour[4];
210 glEnable(GL_BLEND);
211 glBlendEquation(GL_FUNC_ADD);
212 if (rect) {
213 glBlendFunc(GL_ONE, GL_ONE);
214 colour[0] = colour[1] = colour[2] = 127.0f / 255.0f;
215 } else {
216 /* Invert.
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.
221 * */
222 glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ZERO);
223 colour[0] = colour[1] = colour[2] = 1.0f;
226 colour[3] = 1.0f;
227 glColor4fv(colour);
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 */
239 glDisable(GL_BLEND);
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);
245 fflush(stdout);
246 return false;
249 return true;
252 /* Render */
253 enum piglit_result
254 piglit_display(void)
256 /* Perform test */
257 GLboolean pass = GL_TRUE;
259 TestCase test_case;
261 if (piglit_automatic) {
262 int fail_count = 0;
264 printf("Running %d random tests\n", random_test_count);
265 fflush(stdout);
267 for (int i = 0; i < random_test_count && !(fail_count && break_on_fail); ++i) {
268 test_case.generate();
269 if (!test_case.run())
270 fail_count++;
273 printf("Failed %d random tests\n", fail_count);
274 fflush(stdout);
276 if (fail_count)
277 pass = GL_FALSE;
278 } else {
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! */
291 void
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){
301 rect = true;
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){
306 clips = true;
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);
318 mersenne.init(seed);