arb_framebuffer_object: add missing MSAA alpha-to-coverage and alpha-to-one tests
[piglit.git] / tests / general / triangle-rasterization.cpp
blobc1e1be7e88a98d06a0718ee9af0e96a3d70a66d8
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 Test
31 * This tests OpenGL triangle rasterization by comparing it with a software rasteriser
33 * There are 2 components to the test;
34 * 1. Predefined sanity tests ensuring bounding box calculations are correct
35 * 2. Randomised triangle drawing to attempt to test all possible triangles
38 #include "piglit-util-gl.h"
39 #include "mersenne.hpp"
41 #include <time.h>
42 #include <vector>
43 #include <algorithm>
45 /* Data structures */
46 struct Vector
48 Vector()
49 : x(0), y(0)
53 Vector(float x, float y)
54 : x(x), y(y)
58 float x, y;
61 struct Triangle {
62 Triangle()
66 Triangle(const Vector& v0, const Vector& v1, const Vector& v2)
68 v[0] = v0;
69 v[1] = v1;
70 v[2] = v2;
73 Vector& operator[](int i)
75 return v[i];
78 const Vector& operator[](int i) const
80 return v[i];
83 Vector v[3];
87 /* Command line arguments */
88 bool use_fbo = false;
89 bool break_on_fail = false;
90 bool print_triangle = false;
91 int random_test_count = 100;
93 /* filling convention */
94 static enum filling_convention_t {
95 bottom_left = 0,
96 left_bottom,
97 right_bottom,
98 bottom_right,
99 top_right,
100 right_top,
101 left_top,
102 top_left,
103 } filling_convention;
105 /* Fixed point format */
106 static int FIXED_SHIFT;
107 static int FIXED_ONE;
109 /* Default test size */
110 int fbo_width = 256;
111 int fbo_height = 256;
113 /* Piglit variables */
115 PIGLIT_GL_TEST_CONFIG_BEGIN
117 config.supports_gl_compat_version = 10;
119 config.window_width = fbo_width;
120 config.window_height = fbo_height;
121 config.window_visual = PIGLIT_GL_VISUAL_RGBA | PIGLIT_GL_VISUAL_DOUBLE;
122 config.khr_no_error_support = PIGLIT_NO_ERRORS;
124 PIGLIT_GL_TEST_CONFIG_END
126 /* Globals */
127 int test_id = 0;
128 Mersenne mersenne;
129 std::vector<Triangle> fixed_tests;
132 /* std::algorithm min/max with 3 arguments! :D */
133 namespace std {
134 template<typename T>
135 T min(T& a, T& b, T& c)
137 return (a < b) ? std::min(a, c) : std::min(b, c);
140 template<typename T>
141 T max(T& a, T& b, T& c)
143 return (a > b) ? std::max(a, c) : std::max(b, c);
147 /* Proper rounding of float to integer */
148 int64_t iround(float v)
150 if (v > 0.0f)
151 v += 0.5f;
152 if (v < 0.0f)
153 v -= 0.5f;
154 return (int64_t)v;
157 /* Based on http://devmaster.net/forums/topic/1145-advanced-rasterization */
158 void rast_triangle(uint8_t* buffer, uint32_t stride, const Triangle& tri)
160 float center_offset = -0.5f;
162 /* fixed point coordinates */
163 int64_t x1 = iround(FIXED_ONE * (tri[0].x + center_offset));
164 int64_t x2 = iround(FIXED_ONE * (tri[1].x + center_offset));
165 int64_t x3 = iround(FIXED_ONE * (tri[2].x + center_offset));
167 int64_t y1 = iround(FIXED_ONE * (tri[0].y + center_offset));
168 int64_t y2 = iround(FIXED_ONE * (tri[1].y + center_offset));
169 int64_t y3 = iround(FIXED_ONE * (tri[2].y + center_offset));
171 /* Force correct vertex order */
172 const int64_t cross = (x2 - x1) * (y3 - y2) - (y2 - y1) * (x3 - x2);
173 if (cross > 0) {
174 std::swap(x1, x3);
175 std::swap(y1, y3);
178 /* Deltas */
179 const int64_t dx12 = x1 - x2;
180 const int64_t dx23 = x2 - x3;
181 const int64_t dx31 = x3 - x1;
183 const int64_t dy12 = y1 - y2;
184 const int64_t dy23 = y2 - y3;
185 const int64_t dy31 = y3 - y1;
187 /* Fixed-point deltas */
188 const int64_t fdx12 = dx12 << FIXED_SHIFT;
189 const int64_t fdx23 = dx23 << FIXED_SHIFT;
190 const int64_t fdx31 = dx31 << FIXED_SHIFT;
192 const int64_t fdy12 = dy12 << FIXED_SHIFT;
193 const int64_t fdy23 = dy23 << FIXED_SHIFT;
194 const int64_t fdy31 = dy31 << FIXED_SHIFT;
196 /* Bounding rectangle */
197 int64_t minx = std::min(x1, x2, x3) >> FIXED_SHIFT;
198 int64_t maxx = (std::max(x1, x2, x3)) >> FIXED_SHIFT;
200 int64_t miny = (std::min(y1, y2, y3)) >> FIXED_SHIFT;
201 int64_t maxy = std::max(y1, y2, y3) >> FIXED_SHIFT;
203 minx = std::max(minx, (int64_t)0);
204 maxx = std::min(maxx, (int64_t)fbo_width - 1);
206 miny = std::max(miny, (int64_t)0);
207 maxy = std::min(maxy, (int64_t)fbo_height - 1);
209 /* Half-edge constants */
210 int64_t c1 = dy12 * x1 - dx12 * y1;
211 int64_t c2 = dy23 * x2 - dx23 * y2;
212 int64_t c3 = dy31 * x3 - dx31 * y3;
214 /* Correct for filling convention */
215 switch (filling_convention) {
216 case bottom_right:
217 if (dy12 > 0 || (dy12 == 0 && dx12 > 0)) c1++;
218 if (dy23 > 0 || (dy23 == 0 && dx23 > 0)) c2++;
219 if (dy31 > 0 || (dy31 == 0 && dx31 > 0)) c3++;
220 break;
221 case right_bottom:
222 if (dx12 < 0 || (dx12 == 0 && dy12 < 0)) c1++;
223 if (dx23 < 0 || (dx23 == 0 && dy23 < 0)) c2++;
224 if (dx31 < 0 || (dx31 == 0 && dy31 < 0)) c3++;
225 break;
226 case left_bottom:
227 if (dx12 < 0 || (dx12 == 0 && dy12 > 0)) c1++;
228 if (dx23 < 0 || (dx23 == 0 && dy23 > 0)) c2++;
229 if (dx31 < 0 || (dx31 == 0 && dy31 > 0)) c3++;
230 break;
231 case bottom_left:
232 if (dy12 < 0 || (dy12 == 0 && dx12 > 0)) c1++;
233 if (dy23 < 0 || (dy23 == 0 && dx23 > 0)) c2++;
234 if (dy31 < 0 || (dy31 == 0 && dx31 > 0)) c3++;
235 break;
236 case top_left:
237 if (dy12 < 0 || (dy12 == 0 && dx12 < 0)) c1++;
238 if (dy23 < 0 || (dy23 == 0 && dx23 < 0)) c2++;
239 if (dy31 < 0 || (dy31 == 0 && dx31 < 0)) c3++;
240 break;
241 case left_top:
242 if (dx12 > 0 || (dx12 == 0 && dy12 > 0)) c1++;
243 if (dx23 > 0 || (dx23 == 0 && dy23 > 0)) c2++;
244 if (dx31 > 0 || (dx31 == 0 && dy31 > 0)) c3++;
245 break;
246 case right_top:
247 if (dx12 > 0 || (dx12 == 0 && dy12 < 0)) c1++;
248 if (dx23 > 0 || (dx23 == 0 && dy23 < 0)) c2++;
249 if (dx31 > 0 || (dx31 == 0 && dy31 < 0)) c3++;
250 break;
251 case top_right:
252 if (dy12 > 0 || (dy12 == 0 && dx12 < 0)) c1++;
253 if (dy23 > 0 || (dy23 == 0 && dx23 < 0)) c2++;
254 if (dy31 > 0 || (dy31 == 0 && dx31 < 0)) c3++;
255 break;
258 int64_t cy1 = c1 + dx12 * (miny << FIXED_SHIFT) - dy12 * (minx << FIXED_SHIFT);
259 int64_t cy2 = c2 + dx23 * (miny << FIXED_SHIFT) - dy23 * (minx << FIXED_SHIFT);
260 int64_t cy3 = c3 + dx31 * (miny << FIXED_SHIFT) - dy31 * (minx << FIXED_SHIFT);
262 /* Perform rasterization */
263 buffer += miny * stride;
264 for (int64_t y = miny; y <= maxy; y++) {
265 int64_t cx1 = cy1;
266 int64_t cx2 = cy2;
267 int64_t cx3 = cy3;
269 for (int64_t x = minx; x <= maxx; x++) {
270 if (cx1 > 0 && cx2 > 0 && cx3 > 0) {
271 ((uint32_t*)buffer)[x] = 0x00FF00FF;
274 cx1 -= fdy12;
275 cx2 -= fdy23;
276 cx3 -= fdy31;
279 cy1 += fdx12;
280 cy2 += fdx23;
281 cy3 += fdx31;
283 buffer += stride;
288 /* Prints an ascii representation of the triangle */
289 void triangle_art(uint32_t* buffer)
291 int minx = fbo_width - 1, miny = fbo_height - 1;
292 int maxx = 0, maxy = 0;
294 /* Find bounds so we dont have to print whole screen */
295 for (int y = 0; y < fbo_height; ++y) {
296 for (int x = 0; x < fbo_width; ++x) {
297 if (buffer[y*fbo_width + x] & 0xFFFFFF00) {
298 if (x < minx) minx = x;
299 if (y < miny) miny = y;
300 if (x > maxx) maxx = x;
301 if (y > maxy) maxy = y;
306 /* Nothing drawn */
307 if (minx > maxx || miny > maxy)
308 return;
310 --minx; --miny;
311 ++maxx; ++maxy;
313 /* Print an ascii representation of triangle */
314 for (int y = maxy; y >= miny; --y) {
315 for (int x = minx; x <= maxx; ++x) {
316 uint32_t val = buffer[y*fbo_width + x] & 0xFFFFFF00;
318 if (val == 0xFF000000) {
319 printf("+");
320 } else if (val == 0x00FF0000) {
321 printf("-");
322 } else if (val == 0xFFFF0000) {
323 printf("o");
324 } else if (val == 0) {
325 printf(".");
326 } else {
327 printf("?");
331 printf("\n");
334 printf("\n");
338 /* Reads buffer from OpenGL and checks for any colour other than black or yellow
339 * (black = background, yellow = both opengl AND software rast drew to that pixel)
341 uint32_t* check_triangle()
343 const float black[] = { 0, 0, 0 };
344 const float yellow[] = { 1, 1, 0 };
346 if (piglit_probe_rect_two_rgb(0, 0, fbo_width, fbo_height, black,
347 yellow))
348 return NULL;
350 static uint32_t* buffer = 0;
351 if (!buffer) buffer = new uint32_t[fbo_width * fbo_height];
353 glReadPixels(0, 0, fbo_width, fbo_height, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, buffer);
355 return buffer;
359 /* Performs test using tri */
360 GLboolean test_triangle(const Triangle& tri)
362 static uint32_t* buffer = 0;
363 if (!buffer) buffer = new uint32_t[fbo_width * fbo_height];
365 /* Clear OpenGL and software buffer */
366 glClear(GL_COLOR_BUFFER_BIT);
367 memset(buffer, 0, sizeof(uint32_t) * fbo_width * fbo_height);
369 /* Software rasterise triangle and blit it to OpenGL */
370 rast_triangle((uint8_t*)buffer, fbo_width * 4, tri);
371 glDrawPixels(fbo_width, fbo_height, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, buffer);
373 /* Draw OpenGL triangle */
374 glEnableClientState(GL_VERTEX_ARRAY);
375 glVertexPointer(2, GL_FLOAT, 0, tri.v);
376 glDrawArrays(GL_TRIANGLES, 0, 3);
377 glDisableClientState(GL_VERTEX_ARRAY);
379 /* Check the result and print relevant error messages */
380 if (uint32_t* result = check_triangle()) {
381 printf("FAIL: %d. (%f, %f), (%f, %f), (%f, %f)\n", test_id,
382 tri[0].x, tri[0].y, tri[1].x, tri[1].y, tri[2].x, tri[2].y);
384 if (print_triangle) {
385 triangle_art(result);
388 fflush(stdout);
389 return GL_FALSE;
392 return GL_TRUE;
396 /* Generate a random triangle */
397 void random_triangle(Triangle& tri)
399 int size = 1 << (mersenne.value() % (log2u(fbo_width) + 1));
401 for (int i = 0; i < 3; ++i) {
402 tri[i].x = (mersenne.value() % (size * FIXED_ONE)) * (1.0f / FIXED_ONE);
403 tri[i].y = (mersenne.value() % (size * FIXED_ONE)) * (1.0f / FIXED_ONE);
406 test_id++;
410 /* From the OpenGL 1.4 spec page 78 (page 91 of PDF):
411 * "Special treatment is given to a fragment whose center lies on a polygon
412 * boundary edge. In such a case we require that if two polygons lie on either
413 * side of a common edge (with identical endpoints) on which a fragment center
414 * lies, then exactly one of the polygons results in the production of the
415 * fragment during rasterization."
416 * Additionally rasterization is required to be invariant under translation
417 * along either axis by a multiple of the pixel size (page 63/76).
419 * We assume that the implementation adheres to a more stringent convention in
420 * which either top, left, bottom or right edges of a triangles 'belong' to it,
421 * that is, if one of those edges intersects with a fragment center, the
422 * fragment is produced. Additionally, for 'top' and 'bottom'-type triangles
423 * either left or right vertical edges 'belong' to it. Similarly the same is
424 * true with horizontal edges and 'left' and 'right'-type triangles.
426 * For example: consider these 8 triangles centered around a fragment center:
427 * _____
428 * |\2|1/|
429 * |3\|/0|
430 * |-- --|
431 * |4/|\7|
432 * |/5|6\|
434 * The rasterizer should produce exactly one fragment. If triangle no. 0
435 * produces the fragment, the rasterizer is said to follow the bottom-left
436 * convention (bottom because bottom horizontal edges 'belong' to the triangle
437 * and left because all left facing edges 'belong' to it).
439 * This function determines the convention by drawing the 8 triangles shown
440 * above in sub-pixel-size into 8 separate pixels and checks which
441 * pixel is filled.
443 void get_filling_convention(void)
445 Triangle tests[8];
447 const float mid = 0.5f;
448 const float size = 3.0f / FIXED_ONE;
450 const Vector v[] = {
451 Vector(mid + size, mid),
452 Vector(mid + size, mid + size),
453 Vector(mid, mid + size),
454 Vector(mid - size, mid + size),
455 Vector(mid - size, mid),
456 Vector(mid - size, mid - size),
457 Vector(mid, mid - size),
458 Vector(mid + size, mid - size),
459 Vector(mid + size, mid),
461 const Vector vm(mid, mid);
463 for (int i = 0; i < 8; ++i) {
464 tests[i][0] = v[i];
465 tests[i][1] = v[i+1];
466 tests[i][2] = vm;
469 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
470 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
471 glClear(GL_COLOR_BUFFER_BIT);
472 glEnableClientState(GL_VERTEX_ARRAY);
473 piglit_ortho_projection(1, 1, GL_FALSE);
475 assert(piglit_width >= 8);
476 for (int i = 0; i < 8; ++i) {
477 glViewport(i, 0, 1, 1);
479 /* Draw OpenGL triangle */
480 glVertexPointer(2, GL_FLOAT, 0, tests[i].v);
481 glDrawArrays(GL_TRIANGLES, 0, 3);
484 glDisableClientState(GL_VERTEX_ARRAY);
485 glViewport(0, 0, fbo_width, fbo_height);
486 piglit_ortho_projection(fbo_width, fbo_height, GL_FALSE);
488 uint32_t buffer[8];
489 glReadPixels(0, 0, 8, 1, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, buffer);
491 int produced_fragment_count = 0;
492 for (int i = 0; i < 8; ++i) {
493 if ((buffer[i] & 0xFFFFFF00) == 0xFFFFFF00) {
494 filling_convention = (filling_convention_t)i;
495 produced_fragment_count++;
499 if (produced_fragment_count != 1) {
500 printf("Unable to determine filling convention.\n");
501 piglit_report_result(PIGLIT_SKIP);
506 /* Render */
507 enum piglit_result
508 piglit_display(void)
510 GLuint fb, tex;
512 /* If using FBO, set it up */
513 if (use_fbo) {
514 glDisable(GL_CULL_FACE);
516 glGenTextures(1, &tex);
517 glBindTexture(GL_TEXTURE_2D, tex);
518 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
519 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
520 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, fbo_width, fbo_height, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
522 glGenFramebuffersEXT(1, &fb);
523 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb);
524 glViewport(0, 0, fbo_width, fbo_height);
526 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
527 GL_COLOR_ATTACHMENT0_EXT,
528 GL_TEXTURE_2D,
529 tex,
532 if (!piglit_check_gl_error(GL_NO_ERROR))
533 piglit_report_result(PIGLIT_FAIL);
534 assert(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT);
536 glBindTexture(GL_TEXTURE_2D, 0);
539 get_filling_convention();
541 /* Set render state */
542 glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
543 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
545 glEnable(GL_BLEND);
546 glBlendEquation(GL_FUNC_ADD);
547 glBlendFunc(GL_ONE, GL_ONE);
549 glViewport(0, 0, fbo_width, fbo_height);
550 piglit_ortho_projection(fbo_width, fbo_height, GL_FALSE);
552 /* Perform test */
553 GLboolean pass = GL_TRUE;
554 if (piglit_automatic) {
555 int fail_count = 0;
557 printf("Running %d fixed tests\n", (int)fixed_tests.size());
558 for (std::vector<Triangle>::iterator itr = fixed_tests.begin(); itr != fixed_tests.end() && !(fail_count && break_on_fail); ++itr) {
559 if (!test_triangle(*itr))
560 ++fail_count;
563 printf("Running %d random tests\n", random_test_count);
564 for (int i = 0; i < random_test_count && !(fail_count && break_on_fail); ++i) {
565 Triangle tri;
566 random_triangle(tri);
568 if (!test_triangle(tri))
569 ++fail_count;
572 printf("Failed %d tests\n", fail_count);
573 fflush(stdout);
575 if (fail_count)
576 pass = GL_FALSE;
577 } else {
578 Triangle tri;
579 random_triangle(tri);
580 pass &= test_triangle(tri);
582 glDisable(GL_BLEND);
584 /* If using FBO, draw the fbo to screen */
585 if (use_fbo) {
586 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, piglit_winsys_fbo);
587 glViewport(0, 0, piglit_width, piglit_height);
588 piglit_ortho_projection(piglit_width, piglit_height, GL_FALSE);
590 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
591 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE);
592 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
594 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
595 glEnable(GL_TEXTURE_2D);
596 glBindTexture(GL_TEXTURE_2D, tex);
598 piglit_draw_rect_tex(0, 0, piglit_width, piglit_height, 0, 0, 1, 1);
600 glDisable(GL_TEXTURE_2D);
603 piglit_present_results();
606 /* Cleanup FBO if necessary */
607 if (use_fbo) {
608 glDeleteTextures(1, &tex);
609 glDeleteFramebuffersEXT(1, &fb);
610 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, piglit_winsys_fbo);
613 if (!piglit_check_gl_error(GL_NO_ERROR))
614 piglit_report_result(PIGLIT_FAIL);
616 return pass ? PIGLIT_PASS : PIGLIT_FAIL;
620 /* Create some fixed tests to test bounding box in/exclusivity,
622 * /|\
623 * /_|_\ Tests these 4 triangles but shifting them from -1/16 to +1/16
624 * \ | / around the center point
625 * \|/
627 void init_fixed_tests()
629 const float mid = 0.5f;
630 const float shift = 1.0f / FIXED_ONE;
631 const float size = 3.0f / FIXED_ONE;
633 Vector vv[] = {
634 Vector(mid, mid + size),
635 Vector(mid, mid - size),
638 Vector vh[] = {
639 Vector(mid - size, mid),
640 Vector(mid + size, mid),
643 Vector vm(mid, mid);
645 /* Loop through the 4 possible triangles */
646 for (int vy = 0; vy < 2; ++vy) {
647 for (int vx = 0; vx < 2; ++vx) {
648 Triangle tri;
650 tri[0] = vh[vx];
651 tri[1] = vv[vy];
652 tri[2] = vm;
654 /* Loop through the x and y shifts */
655 for (int y = -1; y <= 1; ++y) {
656 for (int x = -1; x <= 1; ++x) {
657 Triangle shifted = tri;
659 for (int i = 0; i < 3; ++i) {
660 shifted[i].x += x * shift;
661 shifted[i].y += y * shift;
664 fixed_tests.push_back(shifted);
672 /* Read command line arguments! */
673 void
674 piglit_init(int argc, char **argv)
676 uint32_t seed = 0xfacebeef ^ time(NULL);
677 GLint gl_subpixel_bits, in_subpixel_bits;
678 glGetIntegerv(GL_SUBPIXEL_BITS, &gl_subpixel_bits);
679 in_subpixel_bits = gl_subpixel_bits;
681 for (int i = 1; i < argc; ++i) {
682 if (strcmp(argv[i], "-break_on_fail") == 0){
683 break_on_fail = true;
684 printf("Execution will stop on first fail\n");
685 } else if (strcmp(argv[i], "-print_triangle") == 0){
686 print_triangle = true;
687 } else if (strcmp(argv[i], "-max_size") == 0){
688 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &fbo_width);
690 fbo_height = fbo_width;
691 piglit_width = fbo_width;
692 piglit_height = fbo_height;
693 } else if (strcmp(argv[i], "-use_fbo") == 0){
694 use_fbo = true;
695 printf("FBOs are in use\n");
696 } else if (i + 1 < argc) {
697 if (strcmp(argv[i], "-count") == 0) {
698 random_test_count = strtoul(argv[++i], NULL, 0);
699 } else if (strcmp(argv[i], "-seed") == 0) {
700 seed = strtoul(argv[++i], NULL, 0);
701 } else if (strcmp(argv[i], "-subpixel_bits") == 0) {
702 in_subpixel_bits = strtoul(argv[++i], NULL, 0);
707 FIXED_SHIFT = in_subpixel_bits;
708 FIXED_ONE = 1 << FIXED_SHIFT;
710 printf("GL indicates %d subpixel bits, using %d subpixel bits\n",
711 gl_subpixel_bits, in_subpixel_bits);
712 printf("Random seed: 0x%08X\n", seed);
713 mersenne.init(seed);
715 init_fixed_tests();