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
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.
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!
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";
53 VBO_SEPARATE_VERTEX_AND_INDEX
,
54 VBO_COMBINED_VERTEX_AND_INDEX
,
58 static char* vbo_cfg_names
[] = {
62 "VBO_SEPARATE_VERTEX_AND_INDEX",
63 "VBO_COMBINED_VERTEX_AND_INDEX",
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};
79 enable_restart(GLuint restart_index
);
81 disable_restart(void);
86 const GLfloat x0
= 0.0, x1
= piglit_width
- 10.0, dx
= 20.0;
87 const GLint iy
= piglit_height
/ 2;
91 if (!piglit_probe_pixel_rgb(0, 0, black
)) {
95 for (x
= x0
+ 0.5 * dx
; x
< x1
; x
+= dx
) {
97 const int ix
= (int) x
;
100 /* there should be triangle drawing here */
101 pass
= piglit_probe_pixel_rgb(ix
, iy
, green
);
104 /* there should not be triangle drawing here */
105 pass
= piglit_probe_pixel_rgb(ix
, iy
, black
);
110 glWindowPos2i(ix
, iy
);
111 glDrawPixels(1, 1, GL_RGBA
, GL_FLOAT
, red
);
126 * Test glBegin(GL_TRIANGLE/LINE_STRIP), glPrimitiveRestartNV(), glEnd().
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;
137 piglit_ortho_projection(piglit_width
, piglit_height
, GL_FALSE
);
139 glClear(GL_COLOR_BUFFER_BIT
);
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
);
149 for (x
= x0
; x
<= x1
; x
+= dx
) {
150 for (y
= y0
; y
<= y1
; y
+= dy
) {
156 glPrimitiveRestartNV();
161 /* Draw a line strip across the window, using restart to actually render
162 * a series of disconnected lines.
165 glBegin(GL_LINE_STRIP
);
167 for (x
= x0
; x
<= x1
; x
+= dx
) {
168 y
= 0.5 * piglit_height
;
174 glPrimitiveRestartNV();
181 pass
= check_rendering();
183 fprintf(stderr
, "%s: failure drawing with glBegin(%s) / glEnd()\n",
184 TestName
, piglit_get_prim_name(primMode
));
187 piglit_present_results();
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
204 test_shared_ib_restart()
207 GLfloat verts
[256 * 2];
208 memset(&verts
, 0, sizeof(verts
));
210 write_vec2_value(verts
, 0, 0.0f
, 0.0f
);
212 write_vec2_value(verts
, 1, piglit_width
, 0.0f
);
214 write_vec2_value(verts
, 2, 0.0f
, piglit_height
);
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
};
222 piglit_ortho_projection(piglit_width
, piglit_height
, GL_FALSE
);
224 glClear(GL_COLOR_BUFFER_BIT
);
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);
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
);
253 pass
= (piglit_probe_rect_rgb(0, 0, piglit_width
, piglit_height
, expected
) != 0) && pass
;
254 piglit_present_results();
260 enable_restart(GLuint restart_index
)
263 glEnable(GL_PRIMITIVE_RESTART
);
264 glPrimitiveRestartIndex(restart_index
);
267 glEnableClientState(GL_PRIMITIVE_RESTART_NV
);
268 glPrimitiveRestartIndexNV(restart_index
);
274 disable_restart(void)
277 glDisable(GL_PRIMITIVE_RESTART
);
280 glDisableClientState(GL_PRIMITIVE_RESTART_NV
);
285 static GLuint
type_size(GLenum 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
);
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
)
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
];
323 static void write_index_value(const GLvoid
*indices
, GLenum type
, GLuint index
, GLuint value
)
326 case GL_UNSIGNED_BYTE
:
327 ((GLubyte
*)indices
)[index
] = (GLubyte
) value
;
329 case GL_UNSIGNED_SHORT
:
330 ((GLushort
*)indices
)[index
] = (GLushort
) value
;
332 case GL_UNSIGNED_INT
:
333 ((GLuint
*)indices
)[index
] = value
;
341 static void do_ArrayElement(GLenum mode
, GLsizei count
,
342 GLenum type
, const GLvoid
*indices
)
347 for (index
= 0; index
< count
; index
++) {
348 glArrayElement(read_index_value(indices
, type
, index
));
355 * Test glDrawElements() with glPrimitiveRestartIndexNV().
358 test_draw_by_index(VBO_CFG vbo_cfg
, bool one_by_one
, GLenum primMode
, GLenum indexType
)
361 #define NUM_ELEMS (NUM_VERTS * 5 / 4)
362 GLfloat verts
[NUM_VERTS
+2][2];
363 GLubyte indices
[sizeof(GLuint
) * NUM_ELEMS
];
365 GLuint restart_index
;
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
);
375 if ((vbo_cfg
!= DISABLE_VBO
) && (vbo_cfg
!= VBO_INDEX_ONLY
)) {
379 if ((vbo_cfg
== VBO_INDEX_ONLY
) || (vbo_cfg
== VBO_SEPARATE_VERTEX_AND_INDEX
)) {
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
);
392 case GL_UNSIGNED_BYTE
:
395 case GL_UNSIGNED_SHORT
:
396 restart_index
= 1000;
398 case GL_UNSIGNED_INT
:
399 restart_index
= 1000 * 1000;
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
++) {
415 verts
[i
*2+1][1] = y
+ dy
;
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
);
423 if (i
> 0 && i
% 4 == 3) {
424 write_index_value(indices
, indexType
, j
, restart_index
);
432 const GLfloat y
= 0.5 * piglit_height
;
434 assert(primMode
== GL_LINE_STRIP
);
438 for (i
= 0; i
< NUM_VERTS
; i
++) {
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
);
448 if (i
> 0 && i
% 2 == 1) {
449 write_index_value(indices
, indexType
, j
, restart_index
);
457 assert(num_elems
<= NUM_ELEMS
);
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
);
472 glGenBuffers(1, &vbo1
);
473 glBindBuffer(GL_ARRAY_BUFFER
, vbo1
);
474 glBufferData(GL_ARRAY_BUFFER
, vbo_data_size
, NULL
, GL_STATIC_DRAW
);
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
) {
486 /* Load vertex data into VBO */
487 glBindBuffer(GL_ARRAY_BUFFER
, vbo1
);
488 glBufferSubData(GL_ARRAY_BUFFER
,
491 glVertexPointer(2, GL_FLOAT
, 0, (void *)0);
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
),
504 glEnableClientState(GL_VERTEX_ARRAY
);
505 pass
= piglit_check_gl_error(GL_NO_ERROR
) && pass
;
507 enable_restart(restart_index
);
511 do_ArrayElement(primMode
, num_elems
, indexType
, indices
);
513 glDrawElements(primMode
, num_elems
, indexType
, (void*) index_offset
);
518 glDisableClientState(GL_VERTEX_ARRAY
);
520 if (vbo_cfg
!= DISABLE_VBO
) {
521 glBindBuffer(GL_ARRAY_BUFFER
, 0);
522 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER
, 0);
526 glDeleteBuffers(1, &vbo1
);
530 glDeleteBuffers(1, &vbo2
);
533 if (!check_rendering()) {
534 fprintf(stderr
, "%s: failure drawing with %s(%s, %s), %s\n",
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
]);
543 piglit_present_results();
551 * Test glDrawElements() with glPrimitiveRestartIndexNV().
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().
564 test_array_element(VBO_CFG vbo_cfg
, GLenum primMode
, GLenum indexType
)
566 return test_draw_by_index(vbo_cfg
, true, primMode
, indexType
);
571 primitive_restart_test(VBO_CFG vbo_cfg
)
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
;
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
;
612 if (vbo_init_cfg
== ALL_TESTS
) {
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
)) {
621 return primitive_restart_test(vbo_init_cfg
) ? PIGLIT_PASS
: PIGLIT_FAIL
;
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;
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
;
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
);
653 glClearColor(0, 0, 0, 0);