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.
25 * \file intervening-read.c
27 * Verify that transform feedback continues to work correctly if
28 * glReadPixels is executed while it is in progress.
30 * This test accepts a single command-line argument which determines
31 * what aspect of transform feedback is tested:
33 * - output: Verifies that correct transform feedback output is generated.
35 * - prims_generated: Verifies that the PRIMITIVES_GENERATED counter
36 * is updated correctly.
38 * - prims_written: Verifies that the PRIMITIVES_WRITTEN counter is
41 * The test draws two triangles before executing glReadPixels, and two
42 * triangles after executing glReadPixels. It uses a transform
43 * feedback buffer that is large enough to accommodate 12 vertices,
44 * but it requests that no more than 9 vertices be written to it.
45 * This allows us to verify that the intervening glReadPixels call
46 * doesn't interfere with overflow checking.
48 * The optional argument "use_gs" causes the test to use a geometry
49 * shader. When this argument is given, the number of vertices output
50 * by the geometry shader is in general different from the number of
51 * vertices sent down the pipeline by the glDrawArrays() command.
52 * Thus, the test verifies that the implementation uses the
53 * post-geometry-shader vertex count to figure out where to resume
54 * transform feedback after the glReadPixels call.
57 #include "piglit-util-gl.h"
61 PIGLIT_GL_TEST_CONFIG_BEGIN
63 use_gs
= PIGLIT_STRIP_ARG("use_gs");
65 config
.supports_gl_compat_version
= 32;
66 config
.supports_gl_core_version
= 32;
68 config
.supports_gl_compat_version
= 10;
69 config
.supports_gl_core_version
= 31;
72 config
.window_visual
= PIGLIT_GL_VISUAL_DOUBLE
| PIGLIT_GL_VISUAL_RGB
;
73 config
.khr_no_error_support
= PIGLIT_NO_ERRORS
;
75 PIGLIT_GL_TEST_CONFIG_END
77 static enum test_mode
{
79 TEST_MODE_PRIMS_GENERATED
,
80 TEST_MODE_PRIMS_WRITTEN
84 * Vertex shader used when use_gs is false.
86 static const char *vstext_nogs
=
87 "attribute vec4 in_position;\n"
88 "attribute vec4 in_color;\n"
89 "varying vec4 out_position;\n"
90 "varying vec4 out_color;\n"
94 " gl_Position = in_position;\n"
95 " out_position = in_position;\n"
96 " out_color = in_color;\n"
100 * Fragment shader used when use_gs is false.
102 static const char *fstext_nogs
=
103 "varying vec4 out_color;\n"
107 " gl_FragColor = out_color;\n"
111 * Vertex shader used when use_gs is true.
113 static const char *vstext_gs
=
115 "in vec4 in_color;\n"
116 "out vec4 color_to_gs;\n"
120 " color_to_gs = in_color;\n"
124 * Geometry shader used when use_gs is true.
126 static const char *gstext_gs
=
128 "layout(points) in;\n"
129 "layout(triangle_strip, max_vertices=6) out;\n"
130 "uniform int start_index;\n"
131 "in vec4 color_to_gs[1];\n"
132 "out vec4 out_position;\n"
133 "out vec4 out_color;\n"
137 " const vec2 positions[12] = vec2[12](\n"
138 " vec2(-1.0, -1.0),\n"
139 " vec2( 0.0, -1.0),\n"
140 " vec2(-1.0, 1.0),\n"
141 " vec2(-1.0, 1.0),\n"
142 " vec2( 0.0, -1.0),\n"
143 " vec2( 0.0, 1.0),\n"
144 " vec2( 0.0, -1.0),\n"
145 " vec2( 1.0, -1.0),\n"
146 " vec2( 0.0, 1.0),\n"
147 " vec2( 0.0, 1.0),\n"
148 " vec2( 1.0, -1.0),\n"
151 " int index = start_index;\n"
152 " for (int i = 0; i < 2; i++) {\n"
153 " for (int j = 0; j < 3; j++) {\n"
154 " vec4 position = vec4(positions[index], 0.0, 1.0);\n"
155 " gl_Position = position;\n"
156 " out_position = position;\n"
157 " out_color = color_to_gs[0];\n"
166 * Fragment shader used when use_gs is false.
168 static const char *fstext_gs
=
170 "in vec4 out_color;\n"
174 " gl_FragColor = out_color;\n"
177 static const char *varyings
[] = { "out_position", "out_color" };
179 static GLuint xfb_buf
, vao
, array_buf
;
184 print_usage_and_exit(char *prog_name
)
186 printf("Usage: %s <mode>\n"
187 " where <mode> is one of:\n"
190 " prims_written\n", prog_name
);
195 piglit_init(int argc
, char **argv
)
199 /* Interpret command line args */
201 print_usage_and_exit(argv
[0]);
202 if (strcmp(argv
[1], "output") == 0)
203 test_mode
= TEST_MODE_OUTPUT
;
204 else if (strcmp(argv
[1], "prims_generated") == 0)
205 test_mode
= TEST_MODE_PRIMS_GENERATED
;
206 else if (strcmp(argv
[1], "prims_written") == 0)
207 test_mode
= TEST_MODE_PRIMS_WRITTEN
;
209 print_usage_and_exit(argv
[0]);
211 piglit_require_GLSL();
212 piglit_require_transform_feedback();
215 vs
= piglit_compile_shader_text(GL_VERTEX_SHADER
, vstext_gs
);
216 gs
= piglit_compile_shader_text(GL_GEOMETRY_SHADER
, gstext_gs
);
217 fs
= piglit_compile_shader_text(GL_FRAGMENT_SHADER
, fstext_gs
);
219 vs
= piglit_compile_shader_text(GL_VERTEX_SHADER
, vstext_nogs
);
221 fs
= piglit_compile_shader_text(GL_FRAGMENT_SHADER
,
224 prog
= glCreateProgram();
225 glAttachShader(prog
, vs
);
227 glAttachShader(prog
, gs
);
228 glAttachShader(prog
, fs
);
230 glBindAttribLocation(prog
, 0, "in_position");
231 glBindAttribLocation(prog
, 1, "in_color");
232 glTransformFeedbackVaryings(prog
, 2, varyings
, GL_INTERLEAVED_ATTRIBS
);
234 if (!piglit_link_check_status(prog
)) {
235 glDeleteProgram(prog
);
236 piglit_report_result(PIGLIT_FAIL
);
239 glGenBuffers(1, &xfb_buf
);
240 glGenBuffers(1, &array_buf
);
241 glGenQueries(1, &query
);
242 if (piglit_is_extension_supported("GL_ARB_vertex_array_object") ||
243 piglit_get_gl_version() >= 30) {
244 glGenVertexArrays(1, &vao
);
245 glBindVertexArray(vao
);
255 dump_vertex_data(const struct vertex_data
*data
)
257 printf("position=(%f, %f, %f, %f), color=(%f, %f, %f, %f)",
258 data
->position
[0], data
->position
[1], data
->position
[2], data
->position
[3],
259 data
->color
[0], data
->color
[1], data
->color
[2], data
->color
[3]);
266 GLboolean pass
= GL_TRUE
;
267 static const struct vertex_data vertex_input
[12] = {
268 /* position XYZW color RGBA */
269 { { -1.0, -1.0, 0.0, 1.0 }, { 1.0, 1.0, 0.0, 1.0 } },
270 { { 0.0, -1.0, 0.0, 1.0 }, { 1.0, 1.0, 0.0, 1.0 } },
271 { { -1.0, 1.0, 0.0, 1.0 }, { 1.0, 1.0, 0.0, 1.0 } },
272 { { -1.0, 1.0, 0.0, 1.0 }, { 1.0, 1.0, 0.0, 1.0 } },
273 { { 0.0, -1.0, 0.0, 1.0 }, { 1.0, 1.0, 0.0, 1.0 } },
274 { { 0.0, 1.0, 0.0, 1.0 }, { 1.0, 1.0, 0.0, 1.0 } },
275 { { 0.0, -1.0, 0.0, 1.0 }, { 0.0, 0.0, 1.0, 1.0 } },
276 { { 1.0, -1.0, 0.0, 1.0 }, { 0.0, 0.0, 1.0, 1.0 } },
277 { { 0.0, 1.0, 0.0, 1.0 }, { 0.0, 0.0, 1.0, 1.0 } },
278 { { 0.0, 1.0, 0.0, 1.0 }, { 0.0, 0.0, 1.0, 1.0 } },
279 { { 1.0, -1.0, 0.0, 1.0 }, { 0.0, 0.0, 1.0, 1.0 } },
280 { { 1.0, 1.0, 0.0, 1.0 }, { 0.0, 0.0, 1.0, 1.0 } }
282 static struct vertex_data initial_xfb_data
[12];
283 const struct vertex_data
*readback
;
289 glBindBuffer(GL_ARRAY_BUFFER
, array_buf
);
290 glBufferData(GL_ARRAY_BUFFER
, sizeof(vertex_input
), &vertex_input
,
292 glVertexAttribPointer(0, 4, GL_FLOAT
, GL_FALSE
,
293 sizeof(struct vertex_data
),
294 (void *) offsetof(struct vertex_data
, position
));
295 glVertexAttribPointer(1, 4, GL_FLOAT
, GL_FALSE
,
296 sizeof(struct vertex_data
),
297 (void *) offsetof(struct vertex_data
, color
));
298 glEnableVertexAttribArray(0);
299 glEnableVertexAttribArray(1);
301 /* Setup transform feedback */
302 for (i
= 0; i
< ARRAY_SIZE(initial_xfb_data
); ++i
) {
303 for (j
= 0; j
< 4; ++j
) {
304 initial_xfb_data
[i
].position
[j
] = 12345.0;
305 initial_xfb_data
[i
].color
[j
] = 12345.0;
308 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER
, xfb_buf
);
309 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER
, sizeof(initial_xfb_data
),
310 initial_xfb_data
, GL_STREAM_READ
);
311 glBindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER
, 0, xfb_buf
, 0,
312 sizeof(float[9][8]));
313 glBeginTransformFeedback(GL_TRIANGLES
);
315 case TEST_MODE_PRIMS_GENERATED
:
316 glBeginQuery(GL_PRIMITIVES_GENERATED
, query
);
318 case TEST_MODE_PRIMS_WRITTEN
:
319 glBeginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN
, query
);
325 /* First draw call */
327 glUniform1i(glGetUniformLocation(prog
, "start_index"), 0);
328 glDrawArrays(GL_POINTS
, 0, 1);
330 glDrawArrays(GL_TRIANGLES
, 0, 6);
334 pass
= piglit_probe_rect_rgba(0, 0, piglit_width
/ 2, piglit_height
,
335 vertex_input
[0].color
) && pass
;
337 /* Second draw call */
339 glUniform1i(glGetUniformLocation(prog
, "start_index"), 6);
340 glDrawArrays(GL_POINTS
, 6, 1);
342 glDrawArrays(GL_TRIANGLES
, 6, 6);
345 /* Finish transform feedback and test correct behavior. */
346 glEndTransformFeedback();
348 case TEST_MODE_OUTPUT
:
349 readback
= glMapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER
,
351 for (i
= 0; i
< 12; ++i
) {
352 const struct vertex_data
*expected
= i
< 9
353 ? &vertex_input
[i
] : &initial_xfb_data
[i
];
354 if (memcmp(&readback
[i
], expected
,
355 sizeof(struct vertex_data
)) != 0) {
356 printf("Read incorrect data for vertex %i.\n",
358 printf("Readback: ");
359 dump_vertex_data(&readback
[i
]);
360 printf("\nExpected: ");
361 dump_vertex_data(expected
);
366 glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER
);
368 case TEST_MODE_PRIMS_GENERATED
:
369 glEndQuery(GL_PRIMITIVES_GENERATED
);
370 glGetQueryObjectuiv(query
, GL_QUERY_RESULT
, &query_result
);
371 if (query_result
!= 4) {
372 printf("Expected 4 primitives generated, got %u\n",
377 case TEST_MODE_PRIMS_WRITTEN
:
378 glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN
);
379 glGetQueryObjectuiv(query
, GL_QUERY_RESULT
, &query_result
);
380 if (query_result
!= 3) {
381 printf("Expected 3 primitives written, got %u\n",
388 piglit_present_results();
390 return pass
? PIGLIT_PASS
: PIGLIT_FAIL
;