2 * Copyright © 2011 Intel Corporation
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
27 * Confirm that the order of vertices output by transform feedback
28 * matches the order of vertices supplied to the GL pipeline.
30 * On OpenGL implementations that execute multiple vertex shader
31 * threads in parallel, it's possible that the threads won't complete
32 * in the same order that they were invoked. When this happens, it's
33 * critical that transform feedback records the vertices in the order
34 * that they were inserted into the GL pipeline, not the order of
37 * This test verifies that transform feedback records vertices in the
38 * correct order by using a vertex shader whose execution time is
39 * dramatically different for different vertices.
41 * The test requries two command line arguments:
43 * - drawcall indicates which drawing function should be called. A
44 * value of "arrays" causes DrawArrays() to be used. A value of
45 * "elements" causes DrawElemeents() to be used. When
46 * DrawElements() is used, we supply an indices array that scrambles
47 * the order in which vertices are sent to the shader, and verify
48 * that the scrambling is reflected in the transform feedback
51 * - mode indiceates which drawing mode should be used. It may be
52 * "triangles", "lines", or "points".
55 #include "piglit-util-gl.h"
57 #define NUM_POINTS 10002
58 #define SHIFT_COUNT 64
60 PIGLIT_GL_TEST_CONFIG_BEGIN
62 config
.supports_gl_compat_version
= 10;
64 config
.window_visual
= PIGLIT_GL_VISUAL_DOUBLE
| PIGLIT_GL_VISUAL_RGBA
;
65 config
.khr_no_error_support
= PIGLIT_NO_ERRORS
;
67 PIGLIT_GL_TEST_CONFIG_END
69 static GLenum draw_mode
;
70 static GLboolean use_draw_elements
;
72 static GLuint xfb_buf
;
73 static unsigned *verts
;
74 static unsigned *indices
;
76 /* This vertex shader computes the hailstone sequence, which is
80 * x[n+1] = x[n]/2 if x[n] is even
81 * = 3*x[n]+1 if x[n] is odd
83 * The shader measures, for different values of starting_x, the
84 * minimum n such that x[n] = 1. This value is output in
85 * iteration_count. The shader outputs a copy of starting_x in
88 * To prevent an infinite loop, if starting_x is 0, it is changed to
91 * In addition, to consume more execution time, the shader maintains a
92 * 31-bit shift register whose value starts at 1, and at each
93 * iteration of the algorithm, shifts it left, in circular fashion,
94 * shift_count times. shift_count can be adjusted as necessary to
95 * ensure that vertex shader threads complete out of order, but the
96 * entire test doesn't take too long to finish.
98 * All of this pointless mathematics serves one purpose: to ensure
99 * that different invocations of the vertex shader take dramatically
100 * different amounts of time to execute.
102 static const char *vstext
=
104 "in uint starting_x;\n"
105 "flat out uint starting_x_copy;\n"
106 "flat out uint iteration_count;\n"
107 "flat out uint shift_reg_final;\n"
108 "uniform uint shift_count;\n"
112 " gl_Position = vec4(0.0);\n"
113 " uint x = starting_x;\n"
116 " uint count = 0u;\n"
117 " uint shift_reg = 1u;\n"
118 " starting_x_copy = starting_x;\n"
119 " while (x != 1u) {\n"
121 " if (x % 2u == 0u)\n"
124 " x = 3u * x + 1u;\n"
126 " for (i = 0u; i < shift_count; ++i)\n"
127 " shift_reg = (shift_reg * 2u) % 0x7fffffffu;\n"
129 " iteration_count = count;\n"
130 " shift_reg_final = shift_reg;\n"
133 static const char *varyings
[] = {
134 "starting_x_copy", "iteration_count", "shift_reg_final"
138 initialize_shader_and_xfb()
142 piglit_require_gl_version(30);
143 piglit_require_GLSL_version(130);
144 piglit_require_transform_feedback();
145 vs
= piglit_compile_shader_text(GL_VERTEX_SHADER
, vstext
);
146 prog
= glCreateProgram();
147 glAttachShader(prog
, vs
);
148 glTransformFeedbackVaryings(prog
, 3, varyings
, GL_INTERLEAVED_ATTRIBS
);
150 if (!piglit_link_check_status(prog
)) {
151 glDeleteProgram(prog
);
152 piglit_report_result(PIGLIT_FAIL
);
154 glGenBuffers(1, &xfb_buf
);
155 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER
, xfb_buf
);
156 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER
,
157 3*NUM_POINTS
*sizeof(unsigned), NULL
, GL_STREAM_READ
);
158 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER
, 0, xfb_buf
);
160 if (!piglit_check_gl_error(0))
161 piglit_report_result(PIGLIT_FAIL
);
165 initialize_vertex_shader_inputs()
167 GLint starting_x_index
= glGetAttribLocation(prog
, "starting_x");
170 verts
= malloc(NUM_POINTS
*sizeof(unsigned));
171 indices
= malloc(NUM_POINTS
*sizeof(unsigned));
173 for (i
= 0; i
< NUM_POINTS
; ++i
)
175 for (i
= 0; i
< NUM_POINTS
/2; ++i
) {
177 indices
[i
+ NUM_POINTS
/2] = 2*i
+1;
180 glUniform1ui(glGetUniformLocation(prog
, "shift_count"),
182 glVertexAttribIPointer(starting_x_index
, 1, GL_UNSIGNED_INT
, sizeof(unsigned),
184 glEnableVertexAttribArray(starting_x_index
);
185 if (!piglit_check_gl_error(0))
186 piglit_report_result(PIGLIT_FAIL
);
190 * Compute the value of iteration_count that we expect the vertex
191 * shader to output for the given starting_x.
194 compute_iteration_count(unsigned starting_x
)
197 unsigned x
= starting_x
;
211 * Compute the value of shift_reg_final that we expect the vertex
212 * shader to output for the given iteration_count.
215 compute_shift_reg_final(unsigned iteration_count
)
217 /* shift_reg starts at 1 and is shifted left
218 * SHIFT_COUNT*iteration_count times. After every 31 shifts,
221 return ((unsigned) 1) << ((SHIFT_COUNT
* iteration_count
) % 31);
227 glEnable(GL_RASTERIZER_DISCARD
);
228 glBeginTransformFeedback(draw_mode
);
229 glBindBuffer(GL_ARRAY_BUFFER
, 0);
230 if (use_draw_elements
) {
231 glDrawElements(draw_mode
, NUM_POINTS
, GL_UNSIGNED_INT
,
234 glDrawArrays(draw_mode
, 0, NUM_POINTS
);
236 glEndTransformFeedback();
237 if (!piglit_check_gl_error(0))
238 piglit_report_result(PIGLIT_FAIL
);
242 check_results_and_exit()
246 GLboolean pass
= GL_TRUE
;
248 readback
= glMapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER
, GL_READ_ONLY
);
249 pass
= piglit_check_gl_error(0) && pass
;
251 for (i
= 0; i
< NUM_POINTS
; ++i
) {
252 unsigned expected_starting_x
=
253 use_draw_elements
? indices
[i
] : i
;
254 unsigned expected_iteration_count
=
255 compute_iteration_count(expected_starting_x
);
256 unsigned expected_shift_reg_final
=
257 compute_shift_reg_final(expected_iteration_count
);
258 if (readback
[3*i
] != expected_starting_x
) {
259 printf("Order changed at vertex %u\n", i
);
263 if (readback
[3*i
+1] != expected_iteration_count
) {
264 printf("Incorrect iteration_count at vertex %u\n", i
);
268 if (readback
[3*i
+2] != expected_shift_reg_final
) {
269 printf("Incorrect shift_reg_final at vertex %u\n", i
);
274 glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER
);
276 piglit_report_result(pass
? PIGLIT_PASS
: PIGLIT_FAIL
);
280 print_usage_and_exit(char *prog_name
)
282 printf("Usage: %s <drawcall> <mode>\n"
283 " where <drawcall is one of:\n"
286 " and <mode> is one of:\n"
289 " points\n", prog_name
);
294 piglit_init(int argc
, char **argv
)
296 /* Interpret command line args */
298 print_usage_and_exit(argv
[0]);
299 if (strcmp(argv
[1], "arrays") == 0)
300 use_draw_elements
= GL_FALSE
;
301 else if (strcmp(argv
[1], "elements") == 0)
302 use_draw_elements
= GL_TRUE
;
304 print_usage_and_exit(argv
[0]);
305 if (strcmp(argv
[2], "triangles") == 0)
306 draw_mode
= GL_TRIANGLES
;
307 else if (strcmp(argv
[2], "lines") == 0)
308 draw_mode
= GL_LINES
;
309 else if (strcmp(argv
[2], "points") == 0)
310 draw_mode
= GL_POINTS
;
312 print_usage_and_exit(argv
[0]);
314 initialize_shader_and_xfb();
315 initialize_vertex_shader_inputs();
317 check_results_and_exit();
320 enum piglit_result
piglit_display(void)
322 /* Test should finish before we reach here. */