--- 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; +} -- 1.8.0.2 _______________________________________________ Piglit mailing list Piglit@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/piglit