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 requires 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_transform_feedback();
144 vs
= piglit_compile_shader_text(GL_VERTEX_SHADER
, vstext
);
145 prog
= glCreateProgram();
146 glAttachShader(prog
, vs
);
147 glTransformFeedbackVaryings(prog
, 3, varyings
, GL_INTERLEAVED_ATTRIBS
);
149 if (!piglit_link_check_status(prog
)) {
150 glDeleteProgram(prog
);
151 piglit_report_result(PIGLIT_FAIL
);
153 glGenBuffers(1, &xfb_buf
);
154 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER
, xfb_buf
);
155 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER
,
156 3*NUM_POINTS
*sizeof(unsigned), NULL
, GL_STREAM_READ
);
157 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER
, 0, xfb_buf
);
159 if (!piglit_check_gl_error(0))
160 piglit_report_result(PIGLIT_FAIL
);
164 initialize_vertex_shader_inputs()
166 GLint starting_x_index
= glGetAttribLocation(prog
, "starting_x");
169 verts
= malloc(NUM_POINTS
*sizeof(unsigned));
170 indices
= malloc(NUM_POINTS
*sizeof(unsigned));
172 for (i
= 0; i
< NUM_POINTS
; ++i
)
174 for (i
= 0; i
< NUM_POINTS
/2; ++i
) {
176 indices
[i
+ NUM_POINTS
/2] = 2*i
+1;
179 glUniform1ui(glGetUniformLocation(prog
, "shift_count"),
181 glVertexAttribIPointer(starting_x_index
, 1, GL_UNSIGNED_INT
, sizeof(unsigned),
183 glEnableVertexAttribArray(starting_x_index
);
184 if (!piglit_check_gl_error(0))
185 piglit_report_result(PIGLIT_FAIL
);
189 * Compute the value of iteration_count that we expect the vertex
190 * shader to output for the given starting_x.
193 compute_iteration_count(unsigned starting_x
)
196 unsigned x
= starting_x
;
210 * Compute the value of shift_reg_final that we expect the vertex
211 * shader to output for the given iteration_count.
214 compute_shift_reg_final(unsigned iteration_count
)
216 /* shift_reg starts at 1 and is shifted left
217 * SHIFT_COUNT*iteration_count times. After every 31 shifts,
220 return ((unsigned) 1) << ((SHIFT_COUNT
* iteration_count
) % 31);
226 glEnable(GL_RASTERIZER_DISCARD
);
227 glBeginTransformFeedback(draw_mode
);
228 glBindBuffer(GL_ARRAY_BUFFER
, 0);
229 if (use_draw_elements
) {
230 glDrawElements(draw_mode
, NUM_POINTS
, GL_UNSIGNED_INT
,
233 glDrawArrays(draw_mode
, 0, NUM_POINTS
);
235 glEndTransformFeedback();
236 if (!piglit_check_gl_error(0))
237 piglit_report_result(PIGLIT_FAIL
);
241 check_results_and_exit()
245 GLboolean pass
= GL_TRUE
;
247 readback
= glMapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER
, GL_READ_ONLY
);
248 pass
= piglit_check_gl_error(0) && pass
;
250 for (i
= 0; i
< NUM_POINTS
; ++i
) {
251 unsigned expected_starting_x
=
252 use_draw_elements
? indices
[i
] : i
;
253 unsigned expected_iteration_count
=
254 compute_iteration_count(expected_starting_x
);
255 unsigned expected_shift_reg_final
=
256 compute_shift_reg_final(expected_iteration_count
);
257 if (readback
[3*i
] != expected_starting_x
) {
258 printf("Order changed at vertex %u\n", i
);
262 if (readback
[3*i
+1] != expected_iteration_count
) {
263 printf("Incorrect iteration_count at vertex %u\n", i
);
267 if (readback
[3*i
+2] != expected_shift_reg_final
) {
268 printf("Incorrect shift_reg_final at vertex %u\n", i
);
273 glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER
);
275 piglit_report_result(pass
? PIGLIT_PASS
: PIGLIT_FAIL
);
279 print_usage_and_exit(char *prog_name
)
281 printf("Usage: %s <drawcall> <mode>\n"
282 " where <drawcall is one of:\n"
285 " and <mode> is one of:\n"
288 " points\n", prog_name
);
293 piglit_init(int argc
, char **argv
)
295 /* Interpret command line args */
297 print_usage_and_exit(argv
[0]);
298 if (strcmp(argv
[1], "arrays") == 0)
299 use_draw_elements
= GL_FALSE
;
300 else if (strcmp(argv
[1], "elements") == 0)
301 use_draw_elements
= GL_TRUE
;
303 print_usage_and_exit(argv
[0]);
304 if (strcmp(argv
[2], "triangles") == 0)
305 draw_mode
= GL_TRIANGLES
;
306 else if (strcmp(argv
[2], "lines") == 0)
307 draw_mode
= GL_LINES
;
308 else if (strcmp(argv
[2], "points") == 0)
309 draw_mode
= GL_POINTS
;
311 print_usage_and_exit(argv
[0]);
313 initialize_shader_and_xfb();
314 initialize_vertex_shader_inputs();
316 check_results_and_exit();
319 enum piglit_result
piglit_display(void)
321 /* Test should finish before we reach here. */