[Piglit] [PATCH] Transform feedback: test buffer size change after binding.

Paul Berry stereotype441 at gmail.com
Tue Dec 18 12:14:31 PST 2012


On 18 December 2012 11:54, Ian Romanick <idr at freedesktop.org> wrote:

> On 12/17/2012 10:17 AM, Paul Berry wrote:
>
> This test looks good.  You should add the note about NVIDIA's driver to
> the commit message when you push.
>

Ok, will do.  Thanks.


>
> Reviewed-by: Ian Romanick <ian.d.romanick at intel.com>
>
>
>  ---
>>   tests/all.tests                                    |   6 +
>>   .../spec/ext_transform_**feedback/CMakeLists.gl.txt  |   1 +
>>   tests/spec/ext_transform_**feedback/change-size.c    | 320
>> +++++++++++++++++++++
>>   3 files changed, 327 insertions(+)
>>   create mode 100644 tests/spec/ext_transform_**feedback/change-size.c
>>
>> diff --git a/tests/all.tests b/tests/all.tests
>> index c823bcf..1cbbe98 100644
>> --- a/tests/all.tests
>> +++ b/tests/all.tests
>> @@ -1925,6 +1925,12 @@ for mode in ['discard', 'buffer',
>> 'prims_generated', 'prims_written']:
>>           ext_transform_feedback[test_**name] = concurrent_test(
>>                   'ext_transform_feedback-{0}'.**format(test_name))
>>
>> +for test_case in ['base-shrink', 'base-grow', 'offset-shrink',
>> 'offset-grow',
>> +                  'range-shrink', 'range-grow']:
>> +        test_name = 'change-size {0}'.format(test_case)
>> +        ext_transform_feedback[test_**name] = concurrent_test(
>> +                'ext_transform_feedback-{0}'.**format(test_name))
>> +
>>   arb_transform_feedback2 = Group()
>>   spec['ARB_transform_feedback2'**] = arb_transform_feedback2
>>   arb_transform_feedback2['draw-**auto'] = PlainExecTest(['arb_transform_
>> **feedback2-draw-auto', '-auto'])
>> diff --git a/tests/spec/ext_transform_**feedback/CMakeLists.gl.txt
>> b/tests/spec/ext_transform_**feedback/CMakeLists.gl.txt
>> index 9325091..63c3f4b 100644
>> --- a/tests/spec/ext_transform_**feedback/CMakeLists.gl.txt
>> +++ b/tests/spec/ext_transform_**feedback/CMakeLists.gl.txt
>> @@ -13,6 +13,7 @@ piglit_add_executable (ext_transform_feedback-**alignment
>> alignment.c)
>>   piglit_add_executable (ext_transform_feedback-api-**errors
>> api-errors.c)
>>   piglit_add_executable (ext_transform_feedback-**buffer-usage
>> buffer-usage.c)
>>   piglit_add_executable (ext_transform_feedback-**builtin-varyings
>> builtin-varyings.c)
>> +piglit_add_executable (ext_transform_feedback-**change-size
>> change-size.c)
>>   piglit_add_executable (ext_transform_feedback-**discard-api
>> discard-api.c)
>>   piglit_add_executable (ext_transform_feedback-**discard-bitmap
>> discard-bitmap.c)
>>   piglit_add_executable (ext_transform_feedback-**discard-clear
>> discard-clear.c)
>> diff --git a/tests/spec/ext_transform_**feedback/change-size.c
>> b/tests/spec/ext_transform_**feedback/change-size.c
>> new file mode 100644
>> index 0000000..ea6fe46
>> --- /dev/null
>> +++ b/tests/spec/ext_transform_**feedback/change-size.c
>> @@ -0,0 +1,320 @@
>> +/*
>> + * Copyright © 2012 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 change-size.c
>> + *
>> + * Confirm that transform feedback properly handles a change in the
>> + * size of a transform feedback buffer after it is bound but before it
>> + * is used.
>> + *
>> + * In particular, this test verifies the following behaviours, from
>> + * the GL 4.3 spec, section 6.1.1 ("Binding Buffer Objects to Indexed
>> + * Targets"):
>> + *
>> + *   BindBufferBase binds the entire buffer, even when the size of the
>> buffer
>> + *   is changed after the binding is established. It is equivalent to
>> calling
>> + *   BindBufferRange with offset zero, while size is determined by the
>> size of
>> + *   the bound buffer at the time the binding is used.
>> + *
>> + *   Regardless of the size specified with BindBufferRange, or
>> indirectly with
>> + *   BindBufferBase, the GL will never read or write beyond the end of a
>> bound
>> + *   buffer. In some cases this constraint may result in visibly
>> different
>> + *   behavior when a buffer overflow would otherwise result, such as
>> described
>> + *   for transform feedback operations in section 13.2.2.
>> + *
>> + * This test verifies that the expected number of primitives are
>> + * written after a change to the size of the transform feedback
>> + * buffer, using both a GL_TRANSFORM_FEEDBACK_**PRIMITIVES_WRITTEN query
>> + * and by looking at the contents of the buffer itself.  We run
>> + * transform feedback in GL_TRIANGLES mode and use a buffer size that
>> + * is not a multiple of 3, so that we can look at the last element in
>> + * the transform feedback buffer and verify that transform feedback
>> + * didn't overwrite it.
>> + *
>> + * The test performs the following operations:
>> + *
>> + * 1. Create a transform feedback buffer using glBufferData().
>> + *
>> + * 2. Bind the buffer for transform feedback using either
>> + *    glBindBufferBase, glBindBufferRange, or glBindBufferOffsetEXT
>> + *    (if supported).
>> + *
>> + * 3. Change the size of the bound buffer using glBufferData().  A
>> + *    non-null data pointer is passed to glBufferData() to store a
>> + *    known pattern in the buffer, so that in step 6 we'll be able to
>> + *    determine which parts of the buffer were overwritten.
>> + *
>> + * 4. Draw some triangles, feeding back a single float from each
>> + *    vertex.
>> + *
>> + * 5. Verify, using a GL_TRANSFORM_FEEDBACK_**PRIMITIVES_WRITTEN query,
>> + *    that the expected number of primitives were written to the
>> + *    buffer.
>> + *
>> + * 6. Verify, using glMapBuffer, that the expected data was written to
>> + *    the buffer.
>> + */
>> +
>> +#include "piglit-util-gl-common.h"
>> +
>> +PIGLIT_GL_TEST_CONFIG_BEGIN
>> +
>> +       config.supports_gl_compat_**version = 10;
>> +
>> +       config.window_visual = PIGLIT_GL_VISUAL_DOUBLE |
>> PIGLIT_GL_VISUAL_RGB | PIGLIT_GL_VISUAL_ALPHA;
>> +
>> +PIGLIT_GL_TEST_CONFIG_END
>> +
>> +/**
>> + * Maximum buffer size--used for declaraing static arrays.  Measured
>> + * in multiples of sizeof(GLfloat).
>> + */
>> +#define MAX_BUFFER_SIZE_FLOATS 10
>> +
>> +static GLuint prog;
>> +static GLuint xfb_buf;
>> +static GLuint query;
>> +
>> +const struct test_case
>> +{
>> +       /**
>> +        * Name of the test case.  NULL is used as a sentinel to mark
>> +        * the end of the list of test cases.
>> +        */
>> +       const char *name;
>> +
>> +       /**
>> +        * Size that the buffer should have before binding.  Measured
>> +        * in multiples of sizeof(GLfloat).
>> +        */
>> +       unsigned initial_size;
>> +
>> +       /**
>> +        * Offset to pass to glBindBufferRange/**glBindBufferOffsetEXT,
>> +        * or zero if glBindBufferBase should be used.  Measured in
>> +        * multiples of sizeof(GLfloat).
>> +        */
>> +       unsigned bind_offset;
>> +
>> +       /**
>> +        * Size to pass to glBindBufferRange, or zero if
>> +        * glBindBufferOffsetEXT/**glBindBufferBase should be used.
>> +        * Measured in multiples of sizeof(GLfloat).
>> +        */
>> +       unsigned bind_size;
>> +
>> +       /**
>> +        * Size of the buffer that should be passed to
>> +        * glBindBufferData after the buffer is bound.  Measured in
>> +        * multiples of sizeof(GLfloat).
>> +        */
>> +       unsigned new_size;
>> +
>> +       /**
>> +        * Number of triangles to draw.
>> +        */
>> +       unsigned num_draw_triangles;
>> +
>> +       /**
>> +        * Number of primitives that are expected to be written to the
>> +        * buffer.
>> +        */
>> +       unsigned num_feedback_triangles;
>> +} test_cases[] = {
>> +       /* name            initial  bind    bind  new   num tris:
>> +        *                 size     offset  size  size  draw  feedback */
>> +       { "base-shrink",   7,       0,      0,    4,    2,    1 },
>> +       { "base-grow",     4,       0,      0,    7,    2,    2 },
>> +       { "offset-shrink", 10,      3,      0,    7,    2,    1 },
>> +       { "offset-grow",   7,       3,      0,    10,   2,    2 },
>> +       { "range-shrink",  10,      3,      7,    7,    2,    1 },
>> +       { "range-grow",    7,       3,      4,    10,   2,    1 },
>> +       { NULL,            0,       0,      0,    0,    0,    0 }
>> +};
>> +
>> +const struct test_case *selected_test;
>> +
>> +/**
>> + * Vertex shader, which simply copies its input attribute to its
>> + * output varying, adding 100 in the process.
>> + */
>> +static const char *vstext =
>> +       "#version 120\n"
>> +       "attribute float input_value;\n"
>> +       "varying float output_value;\n"
>> +       "\n"
>> +       "void main()\n"
>> +       "{\n"
>> +       "  gl_Position = vec4(0.0);\n"
>> +       "  output_value = 100.0 + input_value;\n"
>> +       "}\n";
>> +
>> +static void
>> +print_usage_and_exit(const char *prog_name)
>> +{
>> +       unsigned i;
>> +       printf("Usage: %s <test_case>\n"
>> +              "  where <test_case> is one of the following:\n",
>> prog_name);
>> +       for (i = 0; test_cases[i].name != NULL; i++)
>> +               printf("    %s\n", test_cases[i].name);
>> +       exit(1);
>> +}
>> +
>> +static const struct test_case *
>> +interpret_test_case_arg(const char *arg)
>> +{
>> +       unsigned i;
>> +       for (i = 0; test_cases[i].name != NULL; i++) {
>> +               if (strcmp(test_cases[i].name, arg) == 0)
>> +                       return &test_cases[i];
>> +       }
>> +       return NULL;
>> +}
>> +
>> +void
>> +piglit_init(int argc, char **argv)
>> +{
>> +       GLuint vs;
>> +       const char *varying_name = "output_value";
>> +
>> +       /* Parse args */
>> +       if (argc != 2)
>> +               print_usage_and_exit(argv[0]);
>> +       selected_test = interpret_test_case_arg(argv[**1]);
>> +       if (selected_test == NULL)
>> +               print_usage_and_exit(argv[0]);
>> +
>> +       /* Make sure required GL features are present */
>> +       piglit_require_GLSL_version(**120);
>> +       piglit_require_transform_**feedback();
>> +       if (selected_test->bind_offset != 0 && selected_test->bind_size
>> == 0) {
>> +               /* Test requires glBindBufferOffsetEXT, which is in
>> +                * EXT_transform_feedback, but was never adopted into
>> +                * OpenGL.
>> +                */
>> +               piglit_require_extension("GL_**EXT_transform_feedback");
>> +       }
>> +
>> +       /* Create program and buffer */
>> +       vs = piglit_compile_shader_text(GL_**VERTEX_SHADER, vstext);
>> +       prog = glCreateProgram();
>> +       glAttachShader(prog, vs);
>> +       glTransformFeedbackVaryings(**prog, 1, &varying_name,
>> +                                   GL_INTERLEAVED_ATTRIBS);
>> +       glLinkProgram(prog);
>> +       if (!piglit_link_check_status(**prog))
>> +               piglit_report_result(PIGLIT_**FAIL);
>> +       glGenBuffers(1, &xfb_buf);
>> +       glGenQueries(1, &query);
>> +       if (!piglit_check_gl_error(GL_NO_**ERROR))
>> +               piglit_report_result(PIGLIT_**FAIL);
>> +}
>> +
>> +enum piglit_result
>> +piglit_display(void)
>> +{
>> +       GLint input_index = glGetAttribLocation(prog, "input_value");
>> +       GLfloat canary_data[MAX_BUFFER_SIZE_**FLOATS];
>> +       GLfloat input_data[MAX_BUFFER_SIZE_**FLOATS];
>> +       GLfloat expected_data[MAX_BUFFER_SIZE_**FLOATS];
>> +       GLfloat *output_data;
>> +       GLuint query_result;
>> +       GLboolean pass = GL_TRUE;
>> +       unsigned i;
>> +
>> +       glUseProgram(prog);
>> +
>> +       /* Create a transform feedback buffer. */
>> +       glBindBuffer(GL_TRANSFORM_**FEEDBACK_BUFFER, xfb_buf);
>> +       glBufferData(GL_TRANSFORM_**FEEDBACK_BUFFER,
>> +                    selected_test->initial_size * sizeof(GLfloat), NULL,
>> +                    GL_STREAM_READ);
>> +
>> +       /* Bind the buffer for transform feedback. */
>> +       if (selected_test->bind_size != 0) {
>> +               glBindBufferRange(GL_**TRANSFORM_FEEDBACK_BUFFER, 0,
>> xfb_buf,
>> +                                 selected_test->bind_offset *
>> sizeof(GLfloat),
>> +                                 selected_test->bind_size *
>> sizeof(GLfloat));
>> +       } else if (selected_test->bind_offset != 0) {
>> +               glBindBufferOffsetEXT(GL_**TRANSFORM_FEEDBACK_BUFFER, 0,
>> +                                     xfb_buf,
>> +                                     selected_test->bind_offset
>> +                                     * sizeof(GLfloat));
>> +       } else {
>> +               glBindBufferBase(GL_TRANSFORM_**FEEDBACK_BUFFER, 0,
>> xfb_buf);
>> +       }
>> +
>> +       /* Change the size of the bound buffer. */
>> +       for (i = 0; i < MAX_BUFFER_SIZE_FLOATS; i++)
>> +               canary_data[i] = -1;
>> +       glBufferData(GL_TRANSFORM_**FEEDBACK_BUFFER,
>> +                    selected_test->new_size * sizeof(GLfloat),
>> canary_data,
>> +                    GL_STREAM_READ);
>> +
>> +       /* Draw some triangles. */
>> +       for (i = 0; i < MAX_BUFFER_SIZE_FLOATS; i++)
>> +               input_data[i] = i + 1;
>> +       glBindBuffer(GL_ARRAY_BUFFER, 0);
>> +       glVertexAttribPointer(input_**index, 1, GL_FLOAT, GL_FALSE,
>> +                             sizeof(GLfloat), input_data);
>> +       glEnableVertexAttribArray(**input_index);
>> +       glBeginTransformFeedback(GL_**TRIANGLES);
>> +       glBeginQuery(GL_TRANSFORM_**FEEDBACK_PRIMITIVES_WRITTEN, query);
>> +       glDrawArrays(GL_TRIANGLES, 0, selected_test->num_draw_**triangles
>> * 3);
>> +       glEndQuery(GL_TRANSFORM_**FEEDBACK_PRIMITIVES_WRITTEN);
>> +       glEndTransformFeedback();
>> +
>> +       /* Verify that the expected number of primitives were
>> +        * written.
>> +        */
>> +       glGetQueryObjectuiv(query, GL_QUERY_RESULT, &query_result);
>> +       printf("PRIMITIVES_WRITTEN: expected=%u, actual=%u\n",
>> +              selected_test->num_feedback_**triangles, query_result);
>> +       if (query_result != selected_test->num_feedback_**triangles)
>> +               pass = GL_FALSE;
>> +
>> +       /* Verify that the expected data was written. */
>> +       for (i = 0; i < selected_test->new_size; i++) {
>> +               if (i >= selected_test->bind_offset &&
>> +                   i < (3 * selected_test->num_feedback_**triangles
>> +                        + selected_test->bind_offset)) {
>> +                       expected_data[i] = 100.0
>> +                               + input_data[i -
>> selected_test->bind_offset];
>> +               } else {
>> +                       expected_data[i] = canary_data[i];
>> +               }
>> +       }
>> +       output_data = glMapBuffer(GL_TRANSFORM_**FEEDBACK_BUFFER,
>> GL_READ_ONLY);
>> +       for (i = 0; i < selected_test->new_size; ++i) {
>> +               printf("data[%u]: expected=%f, actual=%f\n", i,
>> +                      expected_data[i], output_data[i]);
>> +               if (expected_data[i] != output_data[i])
>> +                       pass = GL_FALSE;
>> +       }
>> +       glUnmapBuffer(GL_TRANSFORM_**FEEDBACK_BUFFER);
>> +
>> +       piglit_present_results();
>> +
>> +       return pass ? PIGLIT_PASS : PIGLIT_FAIL;
>> +}
>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freedesktop.org/archives/piglit/attachments/20121218/73871e58/attachment-0001.html>


More information about the Piglit mailing list