/* * Copyright © 2014 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 active-sampler-conflict.c * Verify results of program pipeline validation when a conflicting sampler * configuration is used. * * Section 2.11.11 (Shader Execution), subheading "Validation," of the OpenGL * 4.1 spec says: * * "[INVALID_OPERATION] is generated by any command that transfers * vertices to the GL if: * * ... * * - Any two active samplers in the current program object are of * different types, but refer to the same texture image unit." * * This test verifies this behavior several ways. First, an invalid * configuration is constructed. When the pipeline is in the invalid * configuration, glValidateProgramPipeline is used to determine the status. * * The pipeline is then transitioned to a valid configuration, and * glValidateProgramPipeline is called again. * * The pipeline is then transitioned back to the invalid configuration. * Without calling glValidateProgramPipeline, glDrawArrays is called. This * should generate the aforementioned error. While still in the invalid state * glValidateProgramPipeline is called a third time. * * Finally, the pipeline is transitioned back to the valid configuration. * Without calling glValidateProgramPipeline, glDrawArrays is called. This * should not generate any error. * * All of the state flip-flopping is done in an attempt to catch * implementations that latch state in glValidateProgramPipeline and do not * re-validate in glDrawArrays. */ #include "piglit-util-gl.h" PIGLIT_GL_TEST_CONFIG_BEGIN config.supports_gl_compat_version = 30; config.supports_gl_core_version = 31; PIGLIT_GL_TEST_CONFIG_END static const char *fs_code = "#version 130\n" "#extension GL_ARB_separate_shader_objects: require\n" "\n" "out vec4 out_color;\n" "\n" "uniform sampler2D s2;\n" "uniform sampler3D s3;\n" "\n" "void main()\n" "{\n" " out_color = texture(s2, vec2(0)) + texture(s3, vec3(0));\n" "}\n" ; static const char *fs_arrays_code = "#version 130\n" "#extension GL_ARB_separate_shader_objects: require\n" "\n" "out vec4 out_color;\n" "\n" "uniform sampler2D s2[2];\n" "uniform sampler3D s3[2];\n" "\n" "void main()\n" "{\n" " out_color = texture(s2[1], vec2(0)) + texture(s3[1], vec3(0));\n" "}\n" ; static const char *fs_arrays_of_arrays_code = "#version 130\n" "#extension GL_ARB_separate_shader_objects: require\n" "#extension GL_ARB_arrays_of_arrays: require\n" "\n" "out vec4 out_color;\n" "\n" "uniform sampler2D s2[2][2];\n" "uniform sampler3D s3[2][2];\n" "\n" "void main()\n" "{\n" " out_color = texture(s2[1][1], vec2(0)) + texture(s3[1][1], vec3(0));\n" "}\n" ; static const float vert[2] = { 0.0, 0.0 }; static bool setup_program(GLuint *prog, GLuint *pipe, GLuint *vao, GLuint *bo, const char **fs_code) { bool pass = true; *prog = glCreateShaderProgramv(GL_FRAGMENT_SHADER, 1, (const GLchar *const *) fs_code); pass = piglit_link_check_status(*prog) && pass; glGenProgramPipelines(1, pipe); glUseProgramStages(*pipe, GL_FRAGMENT_SHADER_BIT, *prog); glActiveShaderProgram(*pipe, *prog); glBindProgramPipeline(*pipe); glGenVertexArrays(1, vao); glBindVertexArray(*vao); /* Configure a vertex array object and buffer object that will * be used for drawing later. */ glGenBuffers(1, bo); glBindBuffer(GL_ARRAY_BUFFER, *bo); glBufferData(GL_ARRAY_BUFFER, sizeof(vert), vert, GL_STATIC_DRAW); return piglit_check_gl_error(GL_NO_ERROR) && pass; } static void cleanup(GLuint prog, GLuint *pipe, GLuint *vao, GLuint *bo) { glBindProgramPipeline(0); glDeleteProgram(prog); glDeleteProgramPipelines(1, pipe); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); glDeleteBuffers(1, bo); glDeleteVertexArrays(1, vao); } static bool get_uniform_location(GLuint prog, GLint *loc, char *uni_name) { bool pass = true; *loc = glGetUniformLocation(prog, uni_name); if (*loc == -1) { fprintf(stderr, "Failed to get uniform location for %s.\n", uni_name); pass = false; } return pass; } static bool test_sampler_conflict(GLuint prog, GLuint pipe, char *s2_uni_name, char *s3_uni_name) { GLint s2_loc; GLint s3_loc; bool pass = true; pass = get_uniform_location(prog, &s2_loc, s2_uni_name); pass = get_uniform_location(prog, &s3_loc, s3_uni_name); /* First, try an invalid configuration. */ glUniform1i(s2_loc, 1); glUniform1i(s3_loc, 1); if (piglit_program_pipeline_check_status_quiet(pipe)) { fprintf(stderr, "Pipeline was validated with conflicting " "sampler configuration.\n"); pass = false; } /* Now try a valid configuration. */ glUniform1i(s2_loc, 1); glUniform1i(s3_loc, 2); if (!piglit_program_pipeline_check_status_quiet(pipe)) { fprintf(stderr, "Pipeline was not validated with non-conflicting " "sampler configuration.\n"); pass = false; } /* Switch back to the invalid configuration. Without first calling * glValidateProgramPipeline, try to draw something. Verify that * GL_INVALID_OPERATION is generated. */ glUniform1i(s2_loc, 1); glUniform1i(s3_loc, 1); glDrawArrays(GL_POINTS, 0, 1); pass = piglit_check_gl_error(GL_INVALID_OPERATION) && pass; /* Re-validate the program. */ if (piglit_program_pipeline_check_status_quiet(pipe)) { fprintf(stderr, "Pipeline was validated with conflicting " "sampler configuration (second attempt).\n"); pass = false; } /* Switch back to the valid configuration. Without first calling * glValidateProgramPipeline, try to draw something. Verify that * no error is generated. */ glUniform1i(s2_loc, 1); glUniform1i(s3_loc, 2); glDrawArrays(GL_POINTS, 0, 1); pass = piglit_check_gl_error(GL_NO_ERROR) && pass; return pass; } void piglit_init(int argc, char **argv) { GLuint prog; GLuint pipe; GLuint vao; GLuint bo; char *s2_uni_name = "s2"; char *s3_uni_name = "s3"; char *s2_uni_array_name = "s2[1]"; char *s3_uni_array_name = "s3[1]"; bool pass; piglit_require_extension("GL_ARB_separate_shader_objects"); pass = setup_program(&prog, &pipe, &vao, &bo, &fs_code); pass = test_sampler_conflict(prog, pipe, s2_uni_name, s3_uni_name) && pass; cleanup(prog, &pipe, &vao, &bo); pass = setup_program(&prog, &pipe, &vao, &bo, &fs_arrays_code); pass = test_sampler_conflict(prog, pipe, s2_uni_array_name, s3_uni_array_name) && pass; cleanup(prog, &pipe, &vao, &bo); if (piglit_is_extension_supported("GL_ARB_arrays_of_arrays")) { char *s2_uni_aoa_name = "s2[1][1]"; char *s3_uni_aoa_name = "s3[1][1]"; pass = setup_program(&prog, &pipe, &vao, &bo, &fs_arrays_of_arrays_code); pass = test_sampler_conflict(prog, pipe, s2_uni_aoa_name, s3_uni_aoa_name) && pass; cleanup(prog, &pipe, &vao, &bo); } piglit_report_result(pass ? PIGLIT_PASS : PIGLIT_FAIL); } enum piglit_result piglit_display(void) { /* Not reached */ return PIGLIT_FAIL; }