ext_gpu_shader4: add compiler tests for everything
[piglit.git] / tests / spec / ext_transform_feedback / order.c
blobf0e69649f676bb07ff262d7a864b55a7365e2775
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 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
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_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);
149 glLinkProgram(prog);
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);
159 glUseProgram(prog);
160 if (!piglit_check_gl_error(0))
161 piglit_report_result(PIGLIT_FAIL);
164 static void
165 initialize_vertex_shader_inputs()
167 GLint starting_x_index = glGetAttribLocation(prog, "starting_x");
168 unsigned i;
170 verts = malloc(NUM_POINTS*sizeof(unsigned));
171 indices = malloc(NUM_POINTS*sizeof(unsigned));
173 for (i = 0; i < NUM_POINTS; ++i)
174 verts[i] = i;
175 for (i = 0; i < NUM_POINTS/2; ++i) {
176 indices[i] = 2*i;
177 indices[i + NUM_POINTS/2] = 2*i+1;
180 glUniform1ui(glGetUniformLocation(prog, "shift_count"),
181 SHIFT_COUNT);
182 glVertexAttribIPointer(starting_x_index, 1, GL_UNSIGNED_INT, sizeof(unsigned),
183 verts);
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.
193 static unsigned
194 compute_iteration_count(unsigned starting_x)
196 unsigned count = 0;
197 unsigned x = starting_x;
198 if (x == 0)
199 x = 1;
200 while (x != 1) {
201 ++count;
202 if (x % 2 == 0)
203 x /= 2;
204 else
205 x = 3 * x + 1;
207 return count;
211 * Compute the value of shift_reg_final that we expect the vertex
212 * shader to output for the given iteration_count.
214 static unsigned
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,
219 * it resets to 1.
221 return ((unsigned) 1) << ((SHIFT_COUNT * iteration_count) % 31);
224 static void
225 draw()
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,
232 indices);
233 } else {
234 glDrawArrays(draw_mode, 0, NUM_POINTS);
236 glEndTransformFeedback();
237 if (!piglit_check_gl_error(0))
238 piglit_report_result(PIGLIT_FAIL);
241 static void
242 check_results_and_exit()
244 unsigned *readback;
245 unsigned i;
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);
260 pass = GL_FALSE;
261 break;
263 if (readback[3*i+1] != expected_iteration_count) {
264 printf("Incorrect iteration_count at vertex %u\n", i);
265 pass = GL_FALSE;
266 break;
268 if (readback[3*i+2] != expected_shift_reg_final) {
269 printf("Incorrect shift_reg_final at vertex %u\n", i);
270 pass = GL_FALSE;
271 break;
274 glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
276 piglit_report_result(pass ? PIGLIT_PASS : PIGLIT_FAIL);
279 static void
280 print_usage_and_exit(char *prog_name)
282 printf("Usage: %s <drawcall> <mode>\n"
283 " where <drawcall is one of:\n"
284 " arrays\n"
285 " elements\n"
286 " and <mode> is one of:\n"
287 " triangles\n"
288 " lines\n"
289 " points\n", prog_name);
290 exit(1);
293 void
294 piglit_init(int argc, char **argv)
296 /* Interpret command line args */
297 if (argc != 3)
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;
303 else
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;
311 else
312 print_usage_and_exit(argv[0]);
314 initialize_shader_and_xfb();
315 initialize_vertex_shader_inputs();
316 draw();
317 check_results_and_exit();
320 enum piglit_result piglit_display(void)
322 /* Test should finish before we reach here. */
323 return PIGLIT_FAIL;