[Piglit] [PATCH] Test transform feedback with intervening glReadPixels.
Ian Romanick
idr at freedesktop.org
Fri Dec 23 15:54:40 PST 2011
On 12/23/2011 01:54 PM, Paul Berry wrote:
> This test verifies that transform feedback continues to work correctly
> if glReadPixels is executed while it is in progress.
>
> This is an important case to test on Mesa's i965 driver, because
> glReadPixels forces the driver to start a new batch buffer, and at the
> beginning of each batch buffer the driver needs to update the
> transform feedback buffer pointers (in case they were used by another
> process in between the two batches).
Man... transform feedback requires a lot of setup. At some point we may
want to refactor some of the common setup to utility functions. Until then,
Reviewed-by: Ian Romanick <ian.d.romanick at intel.com>
> ---
> tests/all.tests | 4 +
> .../spec/ext_transform_feedback/CMakeLists.gl.txt | 1 +
> .../spec/ext_transform_feedback/intervening-read.c | 266 ++++++++++++++++++++
> 3 files changed, 271 insertions(+), 0 deletions(-)
> create mode 100644 tests/spec/ext_transform_feedback/intervening-read.c
>
> diff --git a/tests/all.tests b/tests/all.tests
> index 5ec532e..0a353d1 100644
> --- a/tests/all.tests
> +++ b/tests/all.tests
> @@ -1382,6 +1382,10 @@ ext_transform_feedback['discard-copypixels'] = concurrent_test('ext_transform_fe
> ext_transform_feedback['discard-drawarrays'] = concurrent_test('ext_transform_feedback-discard-drawarrays')
> ext_transform_feedback['discard-drawpixels'] = concurrent_test('ext_transform_feedback-discard-drawpixels')
> ext_transform_feedback['immediate-reuse'] = concurrent_test('ext_transform_feedback-immediate-reuse')
> +for mode in ['output', 'prims_generated', 'prims_written']:
> + test_name = 'intervening-read {0}'.format(mode)
> + ext_transform_feedback[test_name] = PlainExecTest(
> + 'ext_transform_feedback-{0} -auto'.format(test_name))
> ext_transform_feedback['position-readback-bufferbase'] = PlainExecTest(['ext_transform_feedback-position', '-auto'])
> ext_transform_feedback['position-readback-bufferbase-discard'] = PlainExecTest(['ext_transform_feedback-position', '-auto', 'discard'])
> ext_transform_feedback['position-readback-bufferoffset'] = PlainExecTest(['ext_transform_feedback-position', '-auto', 'offset'])
> diff --git a/tests/spec/ext_transform_feedback/CMakeLists.gl.txt b/tests/spec/ext_transform_feedback/CMakeLists.gl.txt
> index 8582ef0..8334274 100644
> --- a/tests/spec/ext_transform_feedback/CMakeLists.gl.txt
> +++ b/tests/spec/ext_transform_feedback/CMakeLists.gl.txt
> @@ -23,6 +23,7 @@ add_executable (ext_transform_feedback-generatemipmap generatemipmap.c)
> add_executable (ext_transform_feedback-position position.c)
> add_executable (ext_transform_feedback-immediate-reuse immediate-reuse.c)
> add_executable (ext_transform_feedback-interleaved interleaved.c)
> +add_executable (ext_transform_feedback-intervening-read intervening-read.c)
> add_executable (ext_transform_feedback-separate separate.c)
> add_executable (ext_transform_feedback-output-type output-type.c)
> add_executable (ext_transform_feedback-order order.c)
> diff --git a/tests/spec/ext_transform_feedback/intervening-read.c b/tests/spec/ext_transform_feedback/intervening-read.c
> new file mode 100644
> index 0000000..c441df2
> --- /dev/null
> +++ b/tests/spec/ext_transform_feedback/intervening-read.c
> @@ -0,0 +1,266 @@
> +/*
> + * Copyright © 2011 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
> + * DEALINGS IN THE SOFTWARE.
> + */
> +
> +/**
> + * \file intervening-read.c
> + *
> + * Verify that transform feedback continues to work correctly if
> + * glReadPixels is executed while it is in progress.
> + *
> + * This test accepts a single command-line argument which determines
> + * what aspect of transform feedback is tested:
> + *
> + * - output: Verifies that correct transform feedback output is generated.
> + *
> + * - prims_generated: Verifies that the PRIMITIVES_GENERATED counter
> + * is updated correctly.
> + *
> + * - prims_written: Verifies that the PRIMITIVES_WRITTEN counter is
> + * updated correctly.
> + *
> + * The test draws two triangles before executing glReadPixels, and two
> + * triangles after executing glReadPixels. It uses a transform
> + * feedback buffer that is large enough to accommodate 12 vertices,
> + * but it requests that no more than 9 vertices be written to it.
> + * This allows us to verify that the intervening glReadPixels call
> + * doesn't interfere with overflow checking.
> + */
> +
> +#include "piglit-util.h"
> +
> +int piglit_width = 64;
> +int piglit_height = 32;
> +int piglit_window_mode = GLUT_DOUBLE | GLUT_RGB;
> +
> +static enum test_mode {
> + TEST_MODE_OUTPUT,
> + TEST_MODE_PRIMS_GENERATED,
> + TEST_MODE_PRIMS_WRITTEN
> +} test_mode;
> +
> +static const char *vstext =
> + "attribute vec4 in_position;\n"
> + "attribute vec4 in_color;\n"
> + "varying vec4 out_position;\n"
> + "varying vec4 out_color;\n"
> + "\n"
> + "void main()\n"
> + "{\n"
> + " gl_Position = in_position;\n"
> + " out_position = in_position;\n"
> + " out_color = in_color;\n"
> + "}\n";
> +
> +static const char *fstext =
> + "varying vec4 out_color;\n"
> + "\n"
> + "void main()\n"
> + "{\n"
> + " gl_FragColor = out_color;\n"
> + "}\n";
> +
> +static const char *varyings[] = { "out_position", "out_color" };
> +
> +static GLuint xfb_buf;
> +static GLuint prog;
> +static GLuint query;
> +
> +static void
> +print_usage_and_exit(char *prog_name)
> +{
> + printf("Usage: %s<mode>\n"
> + " where<mode> is one of:\n"
> + " output\n"
> + " prims_generated\n"
> + " prims_written\n", prog_name);
> + exit(1);
> +}
> +
> +void
> +piglit_init(int argc, char **argv)
> +{
> + GLuint vs, fs;
> +
> + /* Interpret command line args */
> + if (argc != 2)
> + print_usage_and_exit(argv[0]);
> + if (strcmp(argv[1], "output") == 0)
> + test_mode = TEST_MODE_OUTPUT;
> + else if (strcmp(argv[1], "prims_generated") == 0)
> + test_mode = TEST_MODE_PRIMS_GENERATED;
> + else if (strcmp(argv[1], "prims_written") == 0)
> + test_mode = TEST_MODE_PRIMS_WRITTEN;
> + else
> + print_usage_and_exit(argv[0]);
> +
> + piglit_require_GLSL();
> + piglit_require_transform_feedback();
> +
> + vs = piglit_compile_shader_text(GL_VERTEX_SHADER, vstext);
> + fs = piglit_compile_shader_text(GL_FRAGMENT_SHADER, fstext);
> + prog = piglit_CreateProgram();
> + piglit_AttachShader(prog, vs);
> + piglit_AttachShader(prog, fs);
> + piglit_BindAttribLocation(prog, 0, "in_position");
> + piglit_BindAttribLocation(prog, 1, "in_color");
> + piglit_TransformFeedbackVaryings(prog, 2, varyings, GL_INTERLEAVED_ATTRIBS);
> + piglit_LinkProgram(prog);
> + if (!piglit_link_check_status(prog)) {
> + piglit_DeleteProgram(prog);
> + piglit_report_result(PIGLIT_FAIL);
> + }
> +
> + glGenBuffers(1,&xfb_buf);
> + glGenQueries(1,&query);
> +}
> +
> +struct vertex_data {
> + float position[4];
> + float color[4];
> +};
> +
> +void
> +dump_vertex_data(const struct vertex_data *data)
> +{
> + printf("position=(%f, %f, %f, %f), color=(%f, %f, %f, %f)",
> + data->position[0], data->position[1], data->position[2], data->position[3],
> + data->color[0], data->color[1], data->color[2], data->color[3]);
> +}
> +
> +enum piglit_result
> +piglit_display(void)
> +{
> + int i, j;
> + GLboolean pass = GL_TRUE;
> + static const struct vertex_data vertex_input[12] = {
> + /* position XYZW color RGBA */
> + { { -1.0, -1.0, 0.0, 1.0 }, { 1.0, 1.0, 0.0, 1.0 } },
> + { { 0.0, -1.0, 0.0, 1.0 }, { 1.0, 1.0, 0.0, 1.0 } },
> + { { -1.0, 1.0, 0.0, 1.0 }, { 1.0, 1.0, 0.0, 1.0 } },
> + { { -1.0, 1.0, 0.0, 1.0 }, { 1.0, 1.0, 0.0, 1.0 } },
> + { { 0.0, -1.0, 0.0, 1.0 }, { 1.0, 1.0, 0.0, 1.0 } },
> + { { 0.0, 1.0, 0.0, 1.0 }, { 1.0, 1.0, 0.0, 1.0 } },
> + { { 0.0, -1.0, 0.0, 1.0 }, { 0.0, 0.0, 1.0, 1.0 } },
> + { { 1.0, -1.0, 0.0, 1.0 }, { 0.0, 0.0, 1.0, 1.0 } },
> + { { 0.0, 1.0, 0.0, 1.0 }, { 0.0, 0.0, 1.0, 1.0 } },
> + { { 0.0, 1.0, 0.0, 1.0 }, { 0.0, 0.0, 1.0, 1.0 } },
> + { { 1.0, -1.0, 0.0, 1.0 }, { 0.0, 0.0, 1.0, 1.0 } },
> + { { 1.0, 1.0, 0.0, 1.0 }, { 0.0, 0.0, 1.0, 1.0 } }
> + };
> + static struct vertex_data initial_xfb_data[12];
> + const struct vertex_data *readback;
> + GLuint query_result;
> +
> + glUseProgram(prog);
> +
> + /* Setup inputs */
> + glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE,
> + sizeof(struct vertex_data),
> + &vertex_input[0].position);
> + glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE,
> + sizeof(struct vertex_data),
> + &vertex_input[0].color);
> + glEnableVertexAttribArray(0);
> + glEnableVertexAttribArray(1);
> +
> + /* Setup transform feedback */
> + for (i = 0; i< ARRAY_SIZE(initial_xfb_data); ++i) {
> + for (j = 0; j< 4; ++j) {
> + initial_xfb_data[i].position[j] = 12345.0;
> + initial_xfb_data[i].color[j] = 12345.0;
> + }
> + }
> + glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_buf);
> + glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, sizeof(initial_xfb_data),
> + initial_xfb_data, GL_STREAM_READ);
> + piglit_BindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, xfb_buf, 0,
> + sizeof(float[9][8]));
> + piglit_BeginTransformFeedback(GL_TRIANGLES);
> + switch (test_mode) {
> + case TEST_MODE_PRIMS_GENERATED:
> + glBeginQuery(GL_PRIMITIVES_GENERATED, query);
> + break;
> + case TEST_MODE_PRIMS_WRITTEN:
> + glBeginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, query);
> + break;
> + default:
> + break;
> + }
> +
> + /* First draw call */
> + glDrawArrays(GL_TRIANGLES, 0, 6);
> +
> + /* Read pixels */
> + pass = piglit_probe_rect_rgba(0, 0, piglit_width / 2, piglit_height,
> + vertex_input[0].color)&& pass;
> +
> + /* Second draw call */
> + glDrawArrays(GL_TRIANGLES, 6, 6);
> +
> + /* Finish transform feedback and test correct behavior. */
> + piglit_EndTransformFeedback();
> + switch (test_mode) {
> + case TEST_MODE_OUTPUT:
> + readback = glMapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER,
> + GL_READ_ONLY);
> + for (i = 0; i< 12; ++i) {
> + const struct vertex_data *expected = i< 9
> + ?&vertex_input[i] :&initial_xfb_data[i];
> + if (memcmp(&readback[i], expected,
> + sizeof(struct vertex_data)) != 0) {
> + printf("Read incorrect data for vertex %i.\n",
> + i);
> + printf("Readback: ");
> + dump_vertex_data(&readback[i]);
> + printf("\nExpected: ");
> + dump_vertex_data(expected);
> + printf("\n");
> + pass = GL_FALSE;
> + }
> + }
> + glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
> + break;
> + case TEST_MODE_PRIMS_GENERATED:
> + glEndQuery(GL_PRIMITIVES_GENERATED);
> + glGetQueryObjectuiv(query, GL_QUERY_RESULT,&query_result);
> + if (query_result != 4) {
> + printf("Expected 4 primitives generated, got %u\n",
> + query_result);
> + pass = GL_FALSE;
> + }
> + break;
> + case TEST_MODE_PRIMS_WRITTEN:
> + glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
> + glGetQueryObjectuiv(query, GL_QUERY_RESULT,&query_result);
> + if (query_result != 3) {
> + printf("Expected 3 primitives written, got %u\n",
> + query_result);
> + pass = GL_FALSE;
> + }
> + break;
> + }
> +
> + piglit_present_results();
> +
> + return pass ? PIGLIT_PASS : PIGLIT_FAIL;
> +}
More information about the Piglit
mailing list