perf/pixel-rate: new pixel throughput microbenchmark
[piglit.git] / tests / spec / ext_transform_feedback / order.c
blob647c9b1119dedfccc376c6ef4b5a40b74002cbf9
1 /*
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
13 * Software.
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.
24 /**
25 * \file order.c
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
35 * shader completion.
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
49 * output.
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;
71 static GLuint prog;
72 static GLuint xfb_buf;
73 static unsigned *verts;
74 static unsigned *indices;
76 /* This vertex shader computes the hailstone sequence, which is
77 * defined as:
79 * x[0] = starting_x
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
86 * starting_x_copy.
88 * To prevent an infinite loop, if starting_x is 0, it is changed to
89 * 1.
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 =
103 "#version 130\n"
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"
109 "\n"
110 "void main()\n"
111 "{\n"
112 " gl_Position = vec4(0.0);\n"
113 " uint x = starting_x;\n"
114 " if (x == 0u)\n"
115 " x = 1u;\n"
116 " uint count = 0u;\n"
117 " uint shift_reg = 1u;\n"
118 " starting_x_copy = starting_x;\n"
119 " while (x != 1u) {\n"
120 " ++count;\n"
121 " if (x % 2u == 0u)\n"
122 " x /= 2u;\n"
123 " else\n"
124 " x = 3u * x + 1u;\n"
125 " uint i;\n"
126 " for (i = 0u; i < shift_count; ++i)\n"
127 " shift_reg = (shift_reg * 2u) % 0x7fffffffu;\n"
128 " }\n"
129 " iteration_count = count;\n"
130 " shift_reg_final = shift_reg;\n"
131 "}\n";
133 static const char *varyings[] = {
134 "starting_x_copy", "iteration_count", "shift_reg_final"
137 static void
138 initialize_shader_and_xfb()
140 GLuint vs;
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);
148 glLinkProgram(prog);
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);
158 glUseProgram(prog);
159 if (!piglit_check_gl_error(0))
160 piglit_report_result(PIGLIT_FAIL);
163 static void
164 initialize_vertex_shader_inputs()
166 GLint starting_x_index = glGetAttribLocation(prog, "starting_x");
167 unsigned i;
169 verts = malloc(NUM_POINTS*sizeof(unsigned));
170 indices = malloc(NUM_POINTS*sizeof(unsigned));
172 for (i = 0; i < NUM_POINTS; ++i)
173 verts[i] = i;
174 for (i = 0; i < NUM_POINTS/2; ++i) {
175 indices[i] = 2*i;
176 indices[i + NUM_POINTS/2] = 2*i+1;
179 glUniform1ui(glGetUniformLocation(prog, "shift_count"),
180 SHIFT_COUNT);
181 glVertexAttribIPointer(starting_x_index, 1, GL_UNSIGNED_INT, sizeof(unsigned),
182 verts);
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.
192 static unsigned
193 compute_iteration_count(unsigned starting_x)
195 unsigned count = 0;
196 unsigned x = starting_x;
197 if (x == 0)
198 x = 1;
199 while (x != 1) {
200 ++count;
201 if (x % 2 == 0)
202 x /= 2;
203 else
204 x = 3 * x + 1;
206 return count;
210 * Compute the value of shift_reg_final that we expect the vertex
211 * shader to output for the given iteration_count.
213 static unsigned
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,
218 * it resets to 1.
220 return ((unsigned) 1) << ((SHIFT_COUNT * iteration_count) % 31);
223 static void
224 draw()
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,
231 indices);
232 } else {
233 glDrawArrays(draw_mode, 0, NUM_POINTS);
235 glEndTransformFeedback();
236 if (!piglit_check_gl_error(0))
237 piglit_report_result(PIGLIT_FAIL);
240 static void
241 check_results_and_exit()
243 unsigned *readback;
244 unsigned i;
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);
259 pass = GL_FALSE;
260 break;
262 if (readback[3*i+1] != expected_iteration_count) {
263 printf("Incorrect iteration_count at vertex %u\n", i);
264 pass = GL_FALSE;
265 break;
267 if (readback[3*i+2] != expected_shift_reg_final) {
268 printf("Incorrect shift_reg_final at vertex %u\n", i);
269 pass = GL_FALSE;
270 break;
273 glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
275 piglit_report_result(pass ? PIGLIT_PASS : PIGLIT_FAIL);
278 static void
279 print_usage_and_exit(char *prog_name)
281 printf("Usage: %s <drawcall> <mode>\n"
282 " where <drawcall is one of:\n"
283 " arrays\n"
284 " elements\n"
285 " and <mode> is one of:\n"
286 " triangles\n"
287 " lines\n"
288 " points\n", prog_name);
289 exit(1);
292 void
293 piglit_init(int argc, char **argv)
295 /* Interpret command line args */
296 if (argc != 3)
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;
302 else
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;
310 else
311 print_usage_and_exit(argv[0]);
313 initialize_shader_and_xfb();
314 initialize_vertex_shader_inputs();
315 draw();
316 check_results_and_exit();
319 enum piglit_result piglit_display(void)
321 /* Test should finish before we reach here. */
322 return PIGLIT_FAIL;