/* * Copyright (c) 2017 Advanced Micro Devices, Inc. * * 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 qbo-coherency.c * Test coherency of ARB_query_buffer_object results with pre-shader pipeline * stages: * 1. Indirect draw * Write the qbo result to the 'first' member of the indirect draw * structure, and write the gl_VertexID to a transform feedback buffer. * 2. Index buffer fetch * Write the qbo result to the index buffer, and write the gl_VertexID to * a transform feedback buffer. * 3. Indirect draw count * Write the qbo result to the 'drawcount' value for an * GL_ARB_indirect_parameters multi-draw, and increment an atomic counter * in the vertex shader. * 4. Indirect dispatch * Write the qbo result to the number of groups, and count the groups using * an atomic counter. */ #include "common.h" PIGLIT_GL_TEST_CONFIG_BEGIN config.supports_gl_compat_version = 32; config.supports_gl_core_version = 32; config.window_visual = PIGLIT_GL_VISUAL_RGBA | PIGLIT_GL_VISUAL_DOUBLE | PIGLIT_GL_VISUAL_DEPTH; PIGLIT_GL_TEST_CONFIG_END #define BUFFER_OFFSET(i) ((void *)((char *)NULL + i)) #define DRAW_COUNT_CLAMP_MAX 50 static GLuint prog_compute; static GLuint prog_xfb; static GLuint prog_vs_atomic; static GLuint empty_vao; static GLuint indirect_draw_count_data_bo; static const char *arg_consumer_mode; static const char *arg_query_type; struct consumer_mode { const char *name; unsigned (*run)(unsigned query); const char *extensions[2]; bool amplify; bool clamped; unsigned clamp_max; }; static unsigned indirect_draw(unsigned query) { static const GLuint indirect_data[] = { 1, /* count */ 1, /* instanceCount */ 999, /* first */ 0, /* baseInstance */ }; unsigned indirect_bo; unsigned xfb_bo; glGenBuffers(1, &indirect_bo); glBindBuffer(GL_QUERY_BUFFER, indirect_bo); glBufferData(GL_QUERY_BUFFER, sizeof(indirect_data), indirect_data, GL_STATIC_DRAW); glGetQueryObjectuivARB(query, GL_QUERY_RESULT, BUFFER_OFFSET(2 * sizeof(GLuint))); glUseProgram(prog_xfb); glBindVertexArray(empty_vao); glGenBuffers(1, &xfb_bo); glBindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, xfb_bo, 0, sizeof(GLuint)); glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, sizeof(GLuint), NULL, GL_STREAM_READ); glEnable(GL_RASTERIZER_DISCARD); glBeginTransformFeedback(GL_POINTS); glBindBuffer(GL_DRAW_INDIRECT_BUFFER, indirect_bo); glDrawArraysIndirect(GL_POINTS, BUFFER_OFFSET(0)); glEndTransformFeedback(); glDisable(GL_RASTERIZER_DISCARD); unsigned result; glGetBufferSubData(GL_TRANSFORM_FEEDBACK_BUFFER, 0, sizeof(result), &result); glDeleteBuffers(1, &indirect_bo); glDeleteBuffers(1, &xfb_bo); piglit_check_gl_error(GL_NO_ERROR); return result; } static unsigned index_buffer(unsigned query) { static const GLuint index_data[] = { 999, }; unsigned index_bo; unsigned xfb_bo; glGenBuffers(1, &index_bo); glBindBuffer(GL_QUERY_BUFFER, index_bo); glBufferData(GL_QUERY_BUFFER, sizeof(index_data), index_data, GL_STATIC_DRAW); glGetQueryObjectuivARB(query, GL_QUERY_RESULT, BUFFER_OFFSET(0)); glUseProgram(prog_xfb); glBindVertexArray(empty_vao); glGenBuffers(1, &xfb_bo); glBindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, xfb_bo, 0, sizeof(GLuint)); glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, sizeof(GLuint), NULL, GL_STREAM_READ); glEnable(GL_RASTERIZER_DISCARD); glBeginTransformFeedback(GL_POINTS); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_bo); glDrawElements(GL_POINTS, 1, GL_UNSIGNED_INT, BUFFER_OFFSET(0)); glEndTransformFeedback(); glDisable(GL_RASTERIZER_DISCARD); unsigned result; glGetBufferSubData(GL_TRANSFORM_FEEDBACK_BUFFER, 0, sizeof(result), &result); glDeleteBuffers(1, &index_bo); glDeleteBuffers(1, &xfb_bo); piglit_check_gl_error(GL_NO_ERROR); return result; } static unsigned indirect_draw_count(unsigned query) { static const unsigned zero = 0; static const unsigned count_default = 999; unsigned indirect_count_bo; unsigned atomic_bo; glGenBuffers(1, &indirect_count_bo); glBindBuffer(GL_QUERY_BUFFER, indirect_count_bo); glBufferData(GL_QUERY_BUFFER, sizeof(count_default), &count_default, GL_STATIC_DRAW); glGetQueryObjectuivARB(query, GL_QUERY_RESULT, BUFFER_OFFSET(0)); glUseProgram(prog_vs_atomic); glBindVertexArray(empty_vao); glGenBuffers(1, &atomic_bo); glBindBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, atomic_bo, 0, 4); glBufferData(GL_ATOMIC_COUNTER_BUFFER, 4, &zero, GL_STATIC_DRAW); glEnable(GL_RASTERIZER_DISCARD); glBindBuffer(GL_DRAW_INDIRECT_BUFFER, indirect_draw_count_data_bo); glBindBuffer(GL_PARAMETER_BUFFER_ARB, indirect_count_bo); glMultiDrawArraysIndirectCountARB(GL_POINTS, BUFFER_OFFSET(0), 0, DRAW_COUNT_CLAMP_MAX, 0); glDisable(GL_RASTERIZER_DISCARD); unsigned result; glGetBufferSubData(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(result), &result); glDeleteBuffers(1, &indirect_count_bo); glDeleteBuffers(1, &atomic_bo); piglit_check_gl_error(GL_NO_ERROR); return result; } static unsigned indirect_dispatch(unsigned query) { static const GLuint indirect_data[] = { 999, /* num_groups_x */ 1, /* num_groups_y */ 1, /* num_groups_z */ }; static const unsigned zero = 0; unsigned indirect_bo; unsigned atomic_bo; glGenBuffers(1, &indirect_bo); glBindBuffer(GL_QUERY_BUFFER, indirect_bo); glBufferData(GL_QUERY_BUFFER, sizeof(indirect_data), indirect_data, GL_STATIC_DRAW); glGetQueryObjectuivARB(query, GL_QUERY_RESULT, BUFFER_OFFSET(0)); glUseProgram(prog_compute); glGenBuffers(1, &atomic_bo); glBindBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, atomic_bo, 0, 4); glBufferData(GL_ATOMIC_COUNTER_BUFFER, 4, &zero, GL_STATIC_DRAW); glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, indirect_bo); glDispatchComputeIndirect(0); unsigned result; glGetBufferSubData(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(result), &result); glDeleteBuffers(1, &indirect_bo); glDeleteBuffers(1, &atomic_bo); piglit_check_gl_error(GL_NO_ERROR); return result; } static const struct consumer_mode consumer_modes[] = { { "indirect-draw", &indirect_draw, { "GL_ARB_draw_indirect", NULL } }, { "index-buffer", &index_buffer, { NULL, } }, { "indirect-draw-count", &indirect_draw_count, { "GL_ARB_indirect_parameters", "GL_ARB_shader_atomic_counters" }, .clamped = true, .clamp_max = DRAW_COUNT_CLAMP_MAX }, { "indirect-dispatch", &indirect_dispatch, { "GL_ARB_compute_shader", NULL }, .amplify = true }, }; static enum piglit_result run_subtest(const struct consumer_mode *cm, const struct query_type_desc *qdesc) { GLuint query; bool exact; unsigned expected, result; get_query_values(qdesc, &exact, &expected); glGenQueries(1, &query); run_query(query, qdesc); result = cm->run(query); glDeleteQueries(1, &query); piglit_check_gl_error(GL_NO_ERROR); if (cm->clamped) expected = MIN2(expected, cm->clamp_max); if (result != expected && (exact || result < expected)) { fprintf(stderr, "Result: %u\nExpected: %u\n", result, expected); return PIGLIT_FAIL; } return PIGLIT_PASS; } enum piglit_result piglit_display(void) { enum piglit_result result = PIGLIT_PASS; int vertex_counters; unsigned qnum_count = num_query_types(); for (unsigned cnum = 0; cnum < ARRAY_SIZE(consumer_modes); cnum++) { const struct consumer_mode *cm = &consumer_modes[cnum]; bool supported = true; if (arg_consumer_mode && strcmp(arg_consumer_mode, cm->name)) continue; for (unsigned i = 0; i < ARRAY_SIZE(cm->extensions); ++i) { if (cm->extensions[i] && !piglit_is_extension_supported(cm->extensions[i])) { supported = false; break; } } if (!strcmp(cm->name, "indirect-draw-count")) { glGetIntegerv(GL_MAX_VERTEX_ATOMIC_COUNTERS, &vertex_counters); if(vertex_counters < 1) supported = false; } for (unsigned qnum = 0; qnum < qnum_count; qnum++) { enum piglit_result subtest_result = PIGLIT_SKIP; const struct query_type_desc *qdesc = &query_types[qnum]; if (arg_query_type && strcmp(arg_query_type, piglit_get_gl_enum_name(qdesc->type))) continue; supported = supported && is_query_supported(qdesc); if (cm->amplify) { if (qdesc->type == GL_TIMESTAMP || qdesc->type == GL_TIME_ELAPSED) continue; } if (supported) { subtest_result = run_subtest(cm, qdesc); if (subtest_result != PIGLIT_PASS) result = subtest_result; } piglit_report_subtest_result( subtest_result, "%s-%s", cm->name, piglit_get_gl_enum_name(qdesc->type)); } } return result; } static void prepare_prog_xfb() { static const char *tf_out = "tf_out"; prog_xfb = piglit_build_simple_program_unlinked( "#version 130\n" "\n" "out int tf_out;\n" "\n" "void main() {\n" " tf_out = gl_VertexID;\n" " gl_Position = vec4(0);\n" "}\n", NULL); glTransformFeedbackVaryings(prog_xfb, 1, &tf_out, GL_INTERLEAVED_ATTRIBS); glLinkProgram(prog_xfb); if (!piglit_link_check_status(prog_xfb)) piglit_report_result(PIGLIT_FAIL); piglit_check_gl_error(GL_NO_ERROR); } static void prepare_indirect_draw_count() { prog_vs_atomic = piglit_build_simple_program( "#version 150\n" "#extension GL_ARB_shader_atomic_counters: require\n" "\n" "layout(binding = 0, offset = 0) uniform atomic_uint counter;\n" "\n" "void main() {\n" " atomicCounterIncrement(counter);\n" " gl_Position = vec4(0);\n" "}\n", NULL); static const GLuint indirect_draw_template[] = { 1, /* count */ 1, /* instanceCount */ 0, /* first */ 0, /* baseInstance */ }; char *indirect_draw_count_data = malloc(DRAW_COUNT_CLAMP_MAX * sizeof(indirect_draw_template)); char *dst = indirect_draw_count_data; for (unsigned i = 0; i < DRAW_COUNT_CLAMP_MAX; ++i) { memcpy(dst, indirect_draw_template, sizeof(indirect_draw_template)); dst += sizeof(indirect_draw_template); } glGenBuffers(1, &indirect_draw_count_data_bo); glBindBuffer(GL_DRAW_INDIRECT_BUFFER, indirect_draw_count_data_bo); glBufferData(GL_DRAW_INDIRECT_BUFFER, DRAW_COUNT_CLAMP_MAX * sizeof(indirect_draw_template), indirect_draw_count_data, GL_STATIC_DRAW); free(indirect_draw_count_data); piglit_check_gl_error(GL_NO_ERROR); } static void prepare_prog_compute() { GLuint shader = piglit_compile_shader_text(GL_COMPUTE_SHADER, "#version 150\n" "#extension GL_ARB_compute_shader: require\n" "#extension GL_ARB_shader_atomic_counters: require\n" "\n" "layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n" "\n" "layout(binding = 0, offset = 0) uniform atomic_uint counter;\n" "\n" "void main() {\n" " atomicCounterIncrement(counter);\n" "}\n"); prog_compute = glCreateProgram(); glAttachShader(prog_compute, shader); glLinkProgram(prog_compute); glDeleteShader(shader); if (!piglit_link_check_status(prog_compute)) piglit_report_result(PIGLIT_FAIL); piglit_check_gl_error(GL_NO_ERROR); } void piglit_init(int argc, char **argv) { piglit_require_extension("GL_ARB_query_buffer_object"); if (argc > 1) { if (argc != 3) { fprintf(stderr, "usage: %s \n", argv[0]); exit(1); } arg_consumer_mode = argv[1]; arg_query_type = argv[2]; } query_common_init(); prepare_prog_xfb(); if (piglit_is_extension_supported("GL_ARB_compute_shader")) prepare_prog_compute(); if (piglit_is_extension_supported("GL_ARB_indirect_parameters") && piglit_is_extension_supported("GL_ARB_shader_atomic_counters")) prepare_indirect_draw_count(); glGenVertexArrays(1, &empty_vao); }