From 9f7e2d1eed474a1fcec54663ac543f114231805f Mon Sep 17 00:00:00 2001 From: Martin Peres Date: Fri, 8 May 2015 09:16:43 -0400 Subject: [PATCH] shaders: add a test counting builtin active uniforms The test will almost-always pass but it is a nice way to catch bugs in our implementation... More information inside the test! Signed-off-by: Martin Peres --- tests/all.py | 1 + tests/shaders/CMakeLists.gl.txt | 1 + tests/shaders/getuniform-03.c | 299 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 301 insertions(+) create mode 100755 tests/shaders/getuniform-03.c diff --git a/tests/all.py b/tests/all.py index 9411b10..bef4af0 100755 --- a/tests/all.py +++ b/tests/all.py @@ -484,6 +484,7 @@ with profile.group_manager(PiglitGLTest, 'shaders') as g: g(['glsl-getattriblocation']) g(['getuniform-01']) g(['getuniform-02']) + g(['getuniform-03']) g(['glsl-invalid-asm-01']) g(['glsl-invalid-asm-02']) g(['glsl-novertexdata']) diff --git a/tests/shaders/CMakeLists.gl.txt b/tests/shaders/CMakeLists.gl.txt index 3efc6bf..f3cd007 100644 --- a/tests/shaders/CMakeLists.gl.txt +++ b/tests/shaders/CMakeLists.gl.txt @@ -59,6 +59,7 @@ piglit_add_executable (glsl-getactiveuniform-count glsl-getactiveuniform-count.c piglit_add_executable (glsl-getactiveuniform-length glsl-getactiveuniform-length.c) piglit_add_executable (getuniform-01 getuniform-01.c) piglit_add_executable (getuniform-02 getuniform-02.c) +piglit_add_executable (getuniform-03 getuniform-03.c) piglit_add_executable (glsl-invalid-asm-01 glsl-invalid-asm-01.c) piglit_add_executable (glsl-invalid-asm-02 glsl-invalid-asm-02.c) piglit_add_executable (glsl-novertexdata glsl-novertexdata.c) diff --git a/tests/shaders/getuniform-03.c b/tests/shaders/getuniform-03.c new file mode 100755 index 0000000..f5f352c --- /dev/null +++ b/tests/shaders/getuniform-03.c @@ -0,0 +1,299 @@ +/* + * Copyright 2015 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. + */ + +#include "piglit-util-gl.h" + +PIGLIT_GL_TEST_CONFIG_BEGIN + + config.supports_gl_compat_version = 10; + + config.window_visual = PIGLIT_GL_VISUAL_RGB | PIGLIT_GL_VISUAL_DOUBLE; + +PIGLIT_GL_TEST_CONFIG_END + +struct builtin_uniform_t { + const char *name; + GLenum type; + bool is_array; + bool found; +} uniforms[] = { + { "gl_DepthRange.near", GL_FLOAT, false , false }, + { "gl_DepthRange.far", GL_FLOAT, false , false }, + { "gl_DepthRange.diff", GL_FLOAT, false , false }, + /* { "gl_NumSamples", GL_INT, false , false }, requires OGL 4.0 */ + { "gl_ModelViewMatrix", GL_FLOAT_MAT4, false , false }, + { "gl_ProjectionMatrix", GL_FLOAT_MAT4, false , false }, + { "gl_ModelViewProjectionMatrix", GL_FLOAT_MAT4, false , false }, + { "gl_TextureMatrix", GL_FLOAT_MAT4, true , false }, + { "gl_NormalMatrix", GL_FLOAT_MAT3, false , false }, + { "gl_ModelViewMatrixInverse", GL_FLOAT_MAT4, false , false }, + { "gl_ProjectionMatrixInverse", GL_FLOAT_MAT4, false , false }, + { "gl_TextureMatrixInverse", GL_FLOAT_MAT4, true , false }, + { "gl_ModelViewMatrixTranspose", GL_FLOAT_MAT4, false , false }, + { "gl_ProjectionMatrixTranspose", GL_FLOAT_MAT4, false , false }, + { "gl_ModelViewProjectionMatrixTranspose", GL_FLOAT_MAT4, false , false }, + { "gl_TextureMatrixTranspose", GL_FLOAT_MAT4, true , false }, + { "gl_ModelViewMatrixInverseTranspose", GL_FLOAT_MAT4, false , false }, + { "gl_ProjectionMatrixInverseTranspose", GL_FLOAT_MAT4, false , false }, + { "gl_ModelViewProjectionMatrixInverseTranspose", GL_FLOAT_MAT4, false }, + { "gl_TextureMatrixInverseTranspose", GL_FLOAT_MAT4, true , false }, + { "gl_NormalScale", GL_FLOAT, false , false }, + { "gl_ClipPlane", GL_FLOAT_VEC4, true , false }, + { "gl_Point.size", GL_FLOAT, false , false }, + { "gl_Point.sizeMin", GL_FLOAT, false , false }, + { "gl_Point.sizeMax", GL_FLOAT, false , false }, + { "gl_Point.fadeThresholdSize", GL_FLOAT, false , false }, + { "gl_Point.distanceConstantAttenuation", GL_FLOAT, false , false }, + { "gl_Point.distanceLinearAttenuation", GL_FLOAT, false , false }, + { "gl_Point.distanceQuadraticAttenuation", GL_FLOAT, false , false }, + { "gl_FrontMaterial.emission", GL_FLOAT_VEC4, false , false }, + { "gl_FrontMaterial.ambient", GL_FLOAT_VEC4, false , false }, + { "gl_FrontMaterial.diffuse", GL_FLOAT_VEC4, false , false }, + { "gl_FrontMaterial.specular", GL_FLOAT_VEC4, false , false }, + { "gl_FrontMaterial.shininess", GL_FLOAT, false , false }, + { "gl_BackMaterial.emission", GL_FLOAT_VEC4, false , false }, + { "gl_BackMaterial.ambient", GL_FLOAT_VEC4, false , false }, + { "gl_BackMaterial.diffuse", GL_FLOAT_VEC4, false , false }, + { "gl_BackMaterial.specular", GL_FLOAT_VEC4, false , false }, + { "gl_BackMaterial.shininess", GL_FLOAT, false , false }, + { "gl_LightSource[0].ambient", GL_FLOAT_VEC4, false , false }, + { "gl_LightSource[0].diffuse", GL_FLOAT_VEC4, false , false }, + { "gl_LightSource[0].specular", GL_FLOAT_VEC4, false , false }, + { "gl_LightSource[0].position", GL_FLOAT_VEC4, false , false }, + { "gl_LightSource[0].halfVector", GL_FLOAT_VEC4, false , false }, + { "gl_LightSource[0].spotDirection", GL_FLOAT_VEC3, false , false }, + { "gl_LightSource[0].spotExponent", GL_FLOAT, false , false }, + { "gl_LightSource[0].spotCutoff", GL_FLOAT, false , false }, + { "gl_LightSource[0].spotCosCutoff", GL_FLOAT, false , false }, + { "gl_LightSource[0].constantAttenuation", GL_FLOAT, false , false }, + { "gl_LightSource[0].linearAttenuation", GL_FLOAT, false , false }, + { "gl_LightSource[0].quadraticAttenuation", GL_FLOAT, false , false }, + { "gl_LightModel.ambient", GL_FLOAT_VEC4, false , false }, + { "gl_FrontLightModelProduct.sceneColor", GL_FLOAT_VEC4, false , false }, + { "gl_BackLightModelProduct.sceneColor", GL_FLOAT_VEC4, false , false }, + { "gl_FrontLightProduct[0].ambient", GL_FLOAT_VEC4, true , false }, + { "gl_FrontLightProduct[0].diffuse", GL_FLOAT_VEC4, true , false }, + { "gl_FrontLightProduct[0].specular", GL_FLOAT_VEC4, true , false }, + { "gl_BackLightProduct[0].ambient", GL_FLOAT_VEC4, true , false }, + { "gl_BackLightProduct[0].diffuse", GL_FLOAT_VEC4, true , false }, + { "gl_BackLightProduct[0].specular", GL_FLOAT_VEC4, true , false }, + { "gl_TextureEnvColor", GL_FLOAT_VEC4, true , false }, + { "gl_EyePlaneS", GL_FLOAT_VEC4, true , false }, + { "gl_EyePlaneT", GL_FLOAT_VEC4, true , false }, + { "gl_EyePlaneR", GL_FLOAT_VEC4, true , false }, + { "gl_EyePlaneQ", GL_FLOAT_VEC4, true , false }, + { "gl_ObjectPlaneS", GL_FLOAT_VEC4, true , false }, + { "gl_ObjectPlaneT", GL_FLOAT_VEC4, true , false }, + { "gl_ObjectPlaneR", GL_FLOAT_VEC4, true , false }, + { "gl_ObjectPlaneQ", GL_FLOAT_VEC4, true , false }, + { "gl_Fog.color", GL_FLOAT_VEC4, false , false }, + { "gl_Fog.density", GL_FLOAT, false , false }, + { "gl_Fog.start", GL_FLOAT, false , false }, + { "gl_Fog.end", GL_FLOAT, false , false }, + { "gl_Fog.scale", GL_FLOAT, false , false }, +}; + +static const char vs_header[] = + "void main()\n" + "{\n" + " gl_Position = vec4(1);\n"; + +static const char vs_footer[] = + "}\n"; + +char * +gen_vs_shader_all() +{ + /* " gl_Position += vec4(gl_ModelViewProjectionMatrixInverseTranspose[0]);\n" */ + size_t max_line_size = 64; + size_t uniforms_count = ARRAY_SIZE(uniforms); + size_t shader_len = strlen(vs_header) + + uniforms_count * max_line_size + + strlen(vs_footer) + 1; + size_t i; + + /* allocate the shader */ + char *vs_text = malloc(shader_len); + memset(vs_text, 0, shader_len); + + /* add the header */ + strcat(vs_text, vs_header); + + /* add a reference to every uniform */ + for (i = 0; i < uniforms_count; i++) { + strcat(vs_text, " gl_Position += "); + switch(uniforms[i].type) { + case GL_FLOAT_VEC3: + strcat(vs_text, "vec4("); + strcat(vs_text, uniforms[i].name); + strcat(vs_text, ", 1)"); + break; + case GL_FLOAT_MAT4: + strcat(vs_text, "vec4("); + strcat(vs_text, uniforms[i].name); + strcat(vs_text, "[0])"); + break; + case GL_FLOAT_MAT3: + strcat(vs_text, "vec4("); + strcat(vs_text, uniforms[i].name); + strcat(vs_text, ")"); + break; + default: + strcat(vs_text, uniforms[i].name); + if (uniforms[i].is_array) + strcat(vs_text, "[0]"); + } + strcat(vs_text, ";\n"); + } + + /* add the footer */ + strcat(vs_text, vs_footer); + + fprintf(stderr, "shader = '%s'\n", vs_text); + + return vs_text; +} + +enum piglit_result +piglit_display(void) +{ + /* never called */ + return PIGLIT_FAIL; +} + +static struct builtin_uniform_t * +find_uniform(const char *name) +{ + size_t i; + + for (i = 0; i < ARRAY_SIZE(uniforms); i++) { + /* OpenGL ES 3.0 and OpenGL 4.2 require that the "[0]" be + * appended to the name. Earlier versions of the spec are + * ambiguous. Accept either name. + */ + if (strcmp(uniforms[i].name, name) == 0 || + strncmp(uniforms[i].name, name, strlen(name) - 3) == 0) + return &uniforms[i]; + } + + return NULL; +} + +void +piglit_init(int argc, char **argv) +{ + GLint numUniforms, i; + bool pass = true; + GLuint vs, prog; + char *vs_text; + + piglit_require_vertex_shader(); + piglit_require_fragment_shader(); + + vs_text = gen_vs_shader_all(); + + vs = piglit_compile_shader_text(GL_VERTEX_SHADER, vs_text); + prog = piglit_link_simple_program(vs, 0); + if (!prog) { + printf("Compilation error. Aborting...\n"); + piglit_report_result(PIGLIT_FAIL); + } + + glUseProgram(prog); + free(vs_text); + + glGetProgramiv(prog, GL_ACTIVE_UNIFORMS, &numUniforms); + if (numUniforms != ARRAY_SIZE(uniforms)) { + printf("Unexpected number of uniforms (found %d, expected " + "%lu)\n", numUniforms, ARRAY_SIZE(uniforms)); + } + + /* check the types of the active uniforms and check which ones got + * references by glGetActiveUniform for later comparaison. */ + for (i = 0; i < numUniforms; i++) { + struct builtin_uniform_t *uniform; + GLcharARB name[100]; + GLsizei len; + GLint size; + GLenum type; + + glGetActiveUniform(prog, i, sizeof(name), &len, &size, &type, name); + + uniform = find_uniform(name); + + if (!uniform) { + fprintf(stderr, "Cannot find uniform '%s'\n", name); + pass = false; + } + + uniform->found = true; + + if (type != uniform->type) { + printf("Wrong type for '%s' (found %s(0x%x)), expected %s(0x%x))\n", + name, piglit_get_gl_enum_name(type), type, + piglit_get_gl_enum_name(uniform->type), + uniform->type); + pass = false; + } + } + + /* check that no uniform got forgotten as there is the possibility that + * one got referenced twice! + */ + for (i = 0; i < ARRAY_SIZE(uniforms); i++) { + if (uniforms[i].found == false) { + fprintf(stderr, "uniform '%s' is missing from the " + "active uniform list!\n", + uniforms[i].name); + + /* A missing builtin is legal, as stated by page 80 + * (page 94 of the PDF) of the OpenGL 2.1 spec: + * + * "The returned uniform name can be the name of + * built-in uniform state as well." + */ + + /* FIXME: verify that the missing uniform as not been + * forgotten by the implementation. One way could have + * been to count the number of components used by the + * uniforms and add more components until reaching + * shader then adding other uniforms to reach + * GL_MAX_VERTEX_UNIFORM_COMPONENTS. If the shader still + * compiles, and assuming that + * GL_MAX_VERTEX_UNIFORM_COMPONENTS reports a good value + * then we can assume that the compiler just replaced + * the uniform with something else. If it does not + * compile, then it probably lied somewhere! + * + * The problem with this approach is that counting the + * number of components used for some types such as + * matrices is implementation-dependent... + * + * Until we have such a way to verify, let's not fail + * the test! + */ + } + } + + piglit_report_result(pass ? PIGLIT_PASS : PIGLIT_FAIL); +} -- 2.1.0