conversion-explicit: use a different value for normalized +/- min
[piglit.git] / tests / spec / nv_primitive_restart / primitive-restart.c
blobcba65384ba698e19d97b859269cfe84af8f4127b
1 /*
2 * Copyright 2010 VMware, Inc.
3 * Copyright © 2012 Intel Corporation
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
25 /**
26 * Test GL_NV_primitive_restart and/or GL 3.1 primitive restart.
27 * Note that these two extensions/features use different enum values
28 * and Enable/Disable functions!
30 * Authors:
31 * Brian Paul
34 #include "piglit-util-gl.h"
36 PIGLIT_GL_TEST_CONFIG_BEGIN
38 config.supports_gl_compat_version = 10;
40 config.window_width = 400;
41 config.window_height = 300;
42 config.window_visual = PIGLIT_GL_VISUAL_RGB | PIGLIT_GL_VISUAL_DOUBLE;
43 config.khr_no_error_support = PIGLIT_NO_ERRORS;
45 PIGLIT_GL_TEST_CONFIG_END
47 static const char *TestName = "primitive-restart";
49 typedef enum {
50 DISABLE_VBO,
51 VBO_VERTEX_ONLY,
52 VBO_INDEX_ONLY,
53 VBO_SEPARATE_VERTEX_AND_INDEX,
54 VBO_COMBINED_VERTEX_AND_INDEX,
55 ALL_TESTS,
56 } VBO_CFG;
58 static char* vbo_cfg_names[] = {
59 "DISABLE_VBO",
60 "VBO_VERTEX_ONLY",
61 "VBO_INDEX_ONLY",
62 "VBO_SEPARATE_VERTEX_AND_INDEX",
63 "VBO_COMBINED_VERTEX_AND_INDEX",
64 "all",
67 static VBO_CFG vbo_init_cfg = DISABLE_VBO;
69 static const GLfloat red[4] = {1.0, 0.0, 0.0, 1.0};
70 static const GLfloat green[4] = {0.0, 1.0, 0.0, 0.0};
71 static const GLfloat black[4] = {0.0, 0.0, 0.0, 0.0};
73 static bool Have_NV;
74 static bool Have_31;
75 static bool TestGL31;
78 static void
79 enable_restart(GLuint restart_index);
80 static void
81 disable_restart(void);
83 static bool
84 check_rendering(void)
86 const GLfloat x0 = 0.0, x1 = piglit_width - 10.0, dx = 20.0;
87 const GLint iy = piglit_height / 2;
88 bool draw = true;
89 GLfloat x;
91 if (!piglit_probe_pixel_rgb(0, 0, black)) {
92 return false;
95 for (x = x0 + 0.5 * dx; x < x1; x += dx) {
96 bool pass;
97 const int ix = (int) x;
99 if (draw) {
100 /* there should be triangle drawing here */
101 pass = piglit_probe_pixel_rgb(ix, iy, green);
103 else {
104 /* there should not be triangle drawing here */
105 pass = piglit_probe_pixel_rgb(ix, iy, black);
108 /* debug */
109 if (0) {
110 glWindowPos2i(ix, iy);
111 glDrawPixels(1, 1, GL_RGBA, GL_FLOAT, red);
114 if (!pass) {
115 return false;
118 draw = !draw;
121 return true;
126 * Test glBegin(GL_TRIANGLE/LINE_STRIP), glPrimitiveRestartNV(), glEnd().
128 static bool
129 test_begin_end(GLenum primMode)
131 const GLfloat x0 = 0.0, x1 = piglit_width - 10.0, dx = 20.0;
132 const GLfloat y0 = 0.5 * piglit_height - 10.0, y1 = y0 + 20.0, dy = 20.0;
133 GLfloat x, y;
134 GLint vert;
135 bool pass;
137 piglit_ortho_projection(piglit_width, piglit_height, GL_FALSE);
139 glClear(GL_COLOR_BUFFER_BIT);
141 glColor4fv(green);
143 if (primMode == GL_TRIANGLE_STRIP) {
144 /* Draw a tri-strip across the window, using restart to actually render
145 * a series of quads/boxes.
147 glBegin(GL_TRIANGLE_STRIP);
148 vert = 0;
149 for (x = x0; x <= x1; x += dx) {
150 for (y = y0; y <= y1; y += dy) {
151 glVertex2f(x, y);
154 vert++;
155 if (vert % 2 == 0)
156 glPrimitiveRestartNV();
158 glEnd();
160 else {
161 /* Draw a line strip across the window, using restart to actually render
162 * a series of disconnected lines.
164 glLineWidth(5.0);
165 glBegin(GL_LINE_STRIP);
166 vert = 0;
167 for (x = x0; x <= x1; x += dx) {
168 y = 0.5 * piglit_height;
170 glVertex2f(x, y);
172 vert++;
173 if (vert % 2 == 0)
174 glPrimitiveRestartNV();
176 glEnd();
179 glFinish();
181 pass = check_rendering();
182 if (!pass) {
183 fprintf(stderr, "%s: failure drawing with glBegin(%s) / glEnd()\n",
184 TestName, piglit_get_prim_name(primMode));
187 piglit_present_results();
189 return pass;
192 static void
193 write_vec2_value(GLfloat * verts, GLuint vidx, GLfloat x, GLfloat y)
195 verts[(vidx * 2) + 0] = x;
196 verts[(vidx * 2) + 1] = y;
198 /* This test should draw green rectangle if everything is ok.
199 * But in case of bug which makes us unable to disable
200 * the primitive restart option it should draw just one triangle.
201 * Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=109451
203 static bool
204 test_shared_ib_restart()
206 bool pass = true;
207 GLfloat verts[256 * 2];
208 memset(&verts, 0, sizeof(verts));
209 //left-bottom
210 write_vec2_value(verts, 0, 0.0f, 0.0f);
211 //right-bottom
212 write_vec2_value(verts, 1, piglit_width, 0.0f);
213 //left-top
214 write_vec2_value(verts, 2, 0.0f, piglit_height);
215 //right-top
216 write_vec2_value(verts, 255, piglit_width, piglit_height);
218 const GLubyte indices[] = { 0, 1, 2, 255, 0 };
219 const GLfloat expected[3] = { 0.0f, 1.0f, 0.0f };
220 GLuint vbo1, vbo2;
222 piglit_ortho_projection(piglit_width, piglit_height, GL_FALSE);
224 glClear(GL_COLOR_BUFFER_BIT);
226 glColor4fv(green);
228 glGenBuffers(1, &vbo1);
229 glBindBuffer(GL_ARRAY_BUFFER, vbo1);
230 glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_DYNAMIC_DRAW);
231 glVertexPointer(2, GL_FLOAT, 0, (void *)0);
233 glGenBuffers(1, &vbo2);
234 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo2);
235 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
236 glEnableClientState(GL_VERTEX_ARRAY);
238 //We should draw something with an enabled restart option to check that
239 //it could be correctly disabled
240 enable_restart(0xff);
241 glDrawElements(GL_LINE_STRIP, ARRAY_SIZE(indices), GL_UNSIGNED_BYTE, (void*)0);
242 disable_restart();
244 //Draw full screen rectangle
245 glDrawElements(GL_TRIANGLE_STRIP, ARRAY_SIZE(indices) - 1, GL_UNSIGNED_BYTE, (void*)0);
247 glDisableClientState(GL_VERTEX_ARRAY);
248 glBindBuffer(GL_ARRAY_BUFFER, 0);
249 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
250 glDeleteBuffers(1, &vbo1);
251 glDeleteBuffers(1, &vbo2);
252 glFinish();
253 pass = (piglit_probe_rect_rgb(0, 0, piglit_width, piglit_height, expected) != 0) && pass;
254 piglit_present_results();
255 return pass;
259 static void
260 enable_restart(GLuint restart_index)
262 if (TestGL31) {
263 glEnable(GL_PRIMITIVE_RESTART);
264 glPrimitiveRestartIndex(restart_index);
266 else {
267 glEnableClientState(GL_PRIMITIVE_RESTART_NV);
268 glPrimitiveRestartIndexNV(restart_index);
273 static void
274 disable_restart(void)
276 if (TestGL31) {
277 glDisable(GL_PRIMITIVE_RESTART);
279 else {
280 glDisableClientState(GL_PRIMITIVE_RESTART_NV);
285 static GLuint type_size(GLenum type)
287 switch (type) {
288 case GL_UNSIGNED_BYTE:
289 return sizeof(GLubyte);
290 case GL_UNSIGNED_SHORT:
291 return sizeof(GLushort);
292 case GL_UNSIGNED_INT:
293 return sizeof(GLuint);
294 default:
295 assert(0);
296 return 0;
301 static GLuint type_array_size(GLenum type, GLuint length)
303 return length * type_size(type);
307 static GLuint read_index_value(const GLvoid *indices, GLenum type, GLuint index)
309 switch (type) {
310 case GL_UNSIGNED_BYTE:
311 return (GLuint)((GLubyte*)indices)[index];
312 case GL_UNSIGNED_SHORT:
313 return (GLuint)((GLushort*)indices)[index];
314 case GL_UNSIGNED_INT:
315 return ((GLuint*)indices)[index];
316 default:
317 assert(0);
318 return 0;
323 static void write_index_value(const GLvoid *indices, GLenum type, GLuint index, GLuint value)
325 switch (type) {
326 case GL_UNSIGNED_BYTE:
327 ((GLubyte*)indices)[index] = (GLubyte) value;
328 break;
329 case GL_UNSIGNED_SHORT:
330 ((GLushort*)indices)[index] = (GLushort) value;
331 break;
332 case GL_UNSIGNED_INT:
333 ((GLuint*)indices)[index] = value;
334 break;
335 default:
336 assert(0);
341 static void do_ArrayElement(GLenum mode, GLsizei count,
342 GLenum type, const GLvoid *indices)
344 GLuint index;
346 glBegin(mode);
347 for (index = 0; index < count; index++) {
348 glArrayElement(read_index_value(indices, type, index));
350 glEnd();
355 * Test glDrawElements() with glPrimitiveRestartIndexNV().
357 static bool
358 test_draw_by_index(VBO_CFG vbo_cfg, bool one_by_one, GLenum primMode, GLenum indexType)
360 #define NUM_VERTS 48
361 #define NUM_ELEMS (NUM_VERTS * 5 / 4)
362 GLfloat verts[NUM_VERTS+2][2];
363 GLubyte indices[sizeof(GLuint) * NUM_ELEMS];
364 GLfloat x, dx;
365 GLuint restart_index;
366 GLuint num_elems;
367 bool pass = true;
368 GLuint vbo1, vbo2;
369 bool create_vbo1 = false;
370 bool create_vbo2 = false;
371 uintptr_t index_offset = 0;
372 uintptr_t vbo_data_size = sizeof(verts) + sizeof(indices);
373 GLuint i, j;
375 if ((vbo_cfg != DISABLE_VBO) && (vbo_cfg != VBO_INDEX_ONLY)) {
376 create_vbo1 = true;
379 if ((vbo_cfg == VBO_INDEX_ONLY) || (vbo_cfg == VBO_SEPARATE_VERTEX_AND_INDEX)) {
380 create_vbo2 = true;
383 if ((vbo_cfg == DISABLE_VBO) || (vbo_cfg == VBO_VERTEX_ONLY)) {
384 index_offset = (uintptr_t) indices;
385 } else if (vbo_cfg == VBO_COMBINED_VERTEX_AND_INDEX) {
386 index_offset = sizeof(verts);
387 } else {
388 index_offset = 0;
391 switch (indexType) {
392 case GL_UNSIGNED_BYTE:
393 restart_index = 255;
394 break;
395 case GL_UNSIGNED_SHORT:
396 restart_index = 1000;
397 break;
398 case GL_UNSIGNED_INT:
399 restart_index = 1000 * 1000;
400 break;
401 default:
402 assert(0);
403 restart_index = 0;
406 x = 0.0;
407 dx = 20.0;
409 if (primMode == GL_TRIANGLE_STRIP) {
410 const GLfloat y = 0.5 * piglit_height - 10.0, dy = 20.0;
411 for (i = 0; i < NUM_VERTS / 2; i++) {
412 verts[i*2+0][0] = x;
413 verts[i*2+0][1] = y;
414 verts[i*2+1][0] = x;
415 verts[i*2+1][1] = y + dy;
416 x += dx;
419 /* setup elements to draw series of squares w/ tri strip */
420 for (i = j = 0; i < NUM_VERTS; i++) {
421 write_index_value(indices, indexType, j, i);
422 j++;
423 if (i > 0 && i % 4 == 3) {
424 write_index_value(indices, indexType, j, restart_index);
425 j++;
429 num_elems = j;
431 else {
432 const GLfloat y = 0.5 * piglit_height;
434 assert(primMode == GL_LINE_STRIP);
436 glLineWidth(5.0);
438 for (i = 0; i < NUM_VERTS; i++) {
439 verts[i][0] = x;
440 verts[i][1] = y;
441 x += dx;
444 /* setup elements to draw series of disjoint lines w/ line strip */
445 for (i = j = 0; i < NUM_VERTS / 2; i++) {
446 write_index_value(indices, indexType, j, i);
447 j++;
448 if (i > 0 && i % 2 == 1) {
449 write_index_value(indices, indexType, j, restart_index);
450 j++;
454 num_elems = j;
457 assert(num_elems <= NUM_ELEMS);
459 /* debug */
460 if (0) {
461 for (i = 0; i < num_elems; i++)
462 printf("%2d: %d\n", i, read_index_value(indices, indexType, i));
465 piglit_ortho_projection(piglit_width, piglit_height, GL_FALSE);
467 glClear(GL_COLOR_BUFFER_BIT);
469 glColor4fv(green);
471 if (create_vbo1) {
472 glGenBuffers(1, &vbo1);
473 glBindBuffer(GL_ARRAY_BUFFER, vbo1);
474 glBufferData(GL_ARRAY_BUFFER, vbo_data_size, NULL, GL_STATIC_DRAW);
477 if (create_vbo2) {
478 glGenBuffers(1, &vbo2);
479 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo2);
480 glBufferData(GL_ELEMENT_ARRAY_BUFFER, vbo_data_size, NULL, GL_STATIC_DRAW);
481 } else if (create_vbo1) {
482 vbo2 = vbo1;
485 if (create_vbo1) {
486 /* Load vertex data into VBO */
487 glBindBuffer(GL_ARRAY_BUFFER, vbo1);
488 glBufferSubData(GL_ARRAY_BUFFER,
489 0, sizeof(verts),
490 verts);
491 glVertexPointer(2, GL_FLOAT, 0, (void *)0);
492 } else {
493 glVertexPointer(2, GL_FLOAT, 0, (void *)verts);
496 if ((vbo_cfg != DISABLE_VBO) && (vbo_cfg != VBO_VERTEX_ONLY)) {
497 /* Load index data into VBO */
498 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo2);
499 glBufferSubData(GL_ELEMENT_ARRAY_BUFFER,
500 index_offset, type_array_size(indexType, num_elems),
501 indices);
504 glEnableClientState(GL_VERTEX_ARRAY);
505 pass = piglit_check_gl_error(GL_NO_ERROR) && pass;
507 enable_restart(restart_index);
509 /* Draw */
510 if (one_by_one) {
511 do_ArrayElement(primMode, num_elems, indexType, indices);
512 } else {
513 glDrawElements(primMode, num_elems, indexType, (void*) index_offset);
516 disable_restart();
518 glDisableClientState(GL_VERTEX_ARRAY);
520 if (vbo_cfg != DISABLE_VBO) {
521 glBindBuffer(GL_ARRAY_BUFFER, 0);
522 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
525 if (create_vbo1) {
526 glDeleteBuffers(1, &vbo1);
529 if (create_vbo2) {
530 glDeleteBuffers(1, &vbo2);
533 if (!check_rendering()) {
534 fprintf(stderr, "%s: failure drawing with %s(%s, %s), %s\n",
535 TestName,
536 one_by_one ? "glArrayElement" : "glDrawElements",
537 piglit_get_prim_name(primMode),
538 piglit_get_gl_enum_name(indexType),
539 vbo_cfg_names[vbo_cfg]);
540 pass = false;
543 piglit_present_results();
545 return pass;
546 #undef NUM_VERTS
551 * Test glDrawElements() with glPrimitiveRestartIndexNV().
553 static bool
554 test_draw_elements(VBO_CFG vbo_cfg, GLenum primMode, GLenum indexType)
556 return test_draw_by_index(vbo_cfg, false, primMode, indexType);
561 * Test glArrayElement() with glPrimitiveRestartIndexNV().
563 static bool
564 test_array_element(VBO_CFG vbo_cfg, GLenum primMode, GLenum indexType)
566 return test_draw_by_index(vbo_cfg, true, primMode, indexType);
570 bool
571 primitive_restart_test(VBO_CFG vbo_cfg)
573 bool pass = true;
575 if (Have_NV) {
576 TestGL31 = false;
577 pass = test_shared_ib_restart() && pass;
578 pass = test_begin_end(GL_TRIANGLE_STRIP) && pass;
579 pass = test_begin_end(GL_LINE_STRIP) && pass;
580 pass = test_draw_elements(vbo_cfg, GL_TRIANGLE_STRIP, GL_UNSIGNED_BYTE) && pass;
581 pass = test_draw_elements(vbo_cfg, GL_TRIANGLE_STRIP, GL_UNSIGNED_SHORT) && pass;
582 pass = test_draw_elements(vbo_cfg, GL_TRIANGLE_STRIP, GL_UNSIGNED_INT) && pass;
583 pass = test_draw_elements(vbo_cfg, GL_LINE_STRIP, GL_UNSIGNED_BYTE) && pass;
584 pass = test_draw_elements(vbo_cfg, GL_LINE_STRIP, GL_UNSIGNED_SHORT) && pass;
585 pass = test_draw_elements(vbo_cfg, GL_LINE_STRIP, GL_UNSIGNED_INT) && pass;
586 pass = test_array_element(vbo_cfg, GL_TRIANGLE_STRIP, GL_UNSIGNED_BYTE) && pass;
587 pass = test_array_element(vbo_cfg, GL_TRIANGLE_STRIP, GL_UNSIGNED_SHORT) && pass;
588 pass = test_array_element(vbo_cfg, GL_TRIANGLE_STRIP, GL_UNSIGNED_INT) && pass;
589 pass = test_array_element(vbo_cfg, GL_LINE_STRIP, GL_UNSIGNED_BYTE) && pass;
590 pass = test_array_element(vbo_cfg, GL_LINE_STRIP, GL_UNSIGNED_SHORT) && pass;
591 pass = test_array_element(vbo_cfg, GL_LINE_STRIP, GL_UNSIGNED_INT) && pass;
594 if (Have_31) {
595 TestGL31 = true;
596 pass = test_shared_ib_restart() && pass;
597 pass = test_draw_elements(vbo_cfg, GL_TRIANGLE_STRIP, GL_UNSIGNED_BYTE) && pass;
598 pass = test_draw_elements(vbo_cfg, GL_TRIANGLE_STRIP, GL_UNSIGNED_SHORT) && pass;
599 pass = test_draw_elements(vbo_cfg, GL_TRIANGLE_STRIP, GL_UNSIGNED_INT) && pass;
600 pass = test_draw_elements(vbo_cfg, GL_LINE_STRIP, GL_UNSIGNED_BYTE) && pass;
601 pass = test_draw_elements(vbo_cfg, GL_LINE_STRIP, GL_UNSIGNED_SHORT) && pass;
602 pass = test_draw_elements(vbo_cfg, GL_LINE_STRIP, GL_UNSIGNED_INT) && pass;
605 return pass;
609 enum piglit_result
610 piglit_display(void)
612 if (vbo_init_cfg == ALL_TESTS) {
613 VBO_CFG vbo_cfg;
614 for (vbo_cfg = 0; vbo_cfg < ARRAY_SIZE(vbo_cfg_names); vbo_cfg++) {
615 if ((vbo_cfg != ALL_TESTS) && !primitive_restart_test(vbo_cfg)) {
616 return PIGLIT_FAIL;
619 return PIGLIT_PASS;
620 } else {
621 return primitive_restart_test(vbo_init_cfg) ? PIGLIT_PASS : PIGLIT_FAIL;
626 void
627 piglit_init(int argc, char **argv)
629 Have_NV = piglit_is_extension_supported("GL_NV_primitive_restart");
630 Have_31 = piglit_get_gl_version() >= 31;
632 if (argc >= 2) {
633 VBO_CFG vbo_cfg;
634 for (vbo_cfg = 0; vbo_cfg < ARRAY_SIZE(vbo_cfg_names); vbo_cfg++) {
635 if (strcmp(argv[1], vbo_cfg_names[vbo_cfg]) == 0) {
636 vbo_init_cfg = vbo_cfg;
637 break;
642 /* Debug */
643 if (0) {
644 printf("Have NV: %d\n", Have_NV);
645 printf("Have 31: %d\n", Have_31);
648 if (!Have_NV && !Have_31) {
649 piglit_report_result(PIGLIT_SKIP);
650 exit(1);
653 glClearColor(0, 0, 0, 0);