shader_api.c revision 7ec3b29a
1/* Tests to validate fixes to various bugs in src/mesa/shader/shader_api.c 2 * 3 * Written by Bruce Merry 4 */ 5#include <string.h> 6#include <stdio.h> 7#include <stdlib.h> 8#include <GL/glew.h> 9#include "glut_wrap.h" 10 11static void assert_test(const char *file, int line, int cond, const char *msg) 12{ 13 if (!cond) 14 fprintf(stderr, "%s:%d assertion \"%s\" failed\n", file, line, msg); 15} 16 17#undef assert 18#define assert(x) assert_test(__FILE__, __LINE__, (x), #x) 19 20static void assert_no_error_test(const char *file, int line) 21{ 22 GLenum err; 23 24 err = glGetError(); 25 if (err != GL_NO_ERROR) 26 fprintf(stderr, "%s:%d received error %s\n", 27 file, line, gluErrorString(err)); 28} 29 30#define assert_no_error() assert_no_error_test(__FILE__, __LINE__) 31 32static void assert_error_test(const char *file, int line, GLenum expect) 33{ 34 GLenum err; 35 36 err = glGetError(); 37 if (err != expect) 38 fprintf(stderr, "%s:%d expected %s but received %s\n", 39 file, line, gluErrorString(expect), gluErrorString(err)); 40 while (glGetError()); /* consume any following errors */ 41} 42 43#define assert_error(err) assert_error_test(__FILE__, __LINE__, (err)) 44 45static void check_status(GLuint id, GLenum pname, void (GLAPIENTRY *query)(GLuint, GLenum, GLint *)) 46{ 47 GLint status; 48 49 query(id, pname, &status); 50 if (!status) 51 { 52 char info[65536]; 53 54 fprintf(stderr, "Compilation/link failure:\n"); 55 glGetInfoLogARB(id, sizeof(info), NULL, info); 56 fprintf(stderr, "%s\n", info); 57 exit(1); 58 } 59} 60 61static void check_compile_status(GLuint id) 62{ 63 check_status(id, GL_COMPILE_STATUS, glGetShaderiv); 64} 65 66static void check_link_status(GLuint id) 67{ 68 check_status(id, GL_LINK_STATUS, glGetProgramiv); 69} 70 71static GLuint make_shader(GLenum type, const char *src) 72{ 73 GLuint id; 74 75 assert_no_error(); 76 id = glCreateShader(type); 77 glShaderSource(id, 1, &src, NULL); 78 glCompileShader(id); 79 check_compile_status(id); 80 assert_no_error(); 81 return id; 82} 83 84static GLuint make_program(const char *vs_src, const char *fs_src) 85{ 86 GLuint id, vs, fs; 87 88 assert_no_error(); 89 id = glCreateProgram(); 90 if (vs_src) { 91 vs = make_shader(GL_VERTEX_SHADER, vs_src); 92 glAttachShader(id, vs); 93 glDeleteShader(vs); 94 } 95 if (fs_src) { 96 fs = make_shader(GL_FRAGMENT_SHADER, fs_src); 97 glAttachShader(id, fs); 98 glDeleteShader(fs); 99 } 100 glLinkProgram(id); 101 check_link_status(id); 102 glUseProgram(id); 103 glDeleteProgram(id); 104 assert_no_error(); 105 return id; 106} 107 108static void test_uniform_size_type1(const char *glslType, GLenum glType, const char *el) 109{ 110 char buffer[1024]; 111 GLuint program; 112 GLint active, i; 113 GLenum type; 114 GLint size; 115 116 printf(" Running subtest %s\n", glslType); 117 fflush(stdout); 118 sprintf(buffer, "#version 120\nuniform %s m[60];\nvoid main() { gl_Position[0] = m[59]%s; }\n", 119 glslType, el); 120 121 program = make_program(buffer, NULL); 122 glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &active); 123 assert_no_error(); 124 for (i = 0; i < active; i++) { 125 size = -1; 126 type = 0; 127 glGetActiveUniform(program, i, sizeof(buffer), NULL, &size, &type, buffer); 128 assert_no_error(); 129 if (strncmp(buffer, "m", 1) == 0) 130 break; 131 } 132 assert(i < active); /* Otherwise the compiler optimised it out */ 133 assert(type == glType); 134 assert(size == 60); 135} 136 137static void test_uniform_size_type(void) 138{ 139 test_uniform_size_type1("float", GL_FLOAT, ""); 140 test_uniform_size_type1("vec2", GL_FLOAT_VEC2, "[0]"); 141 test_uniform_size_type1("vec3", GL_FLOAT_VEC3, "[0]"); 142 test_uniform_size_type1("vec4", GL_FLOAT_VEC4, "[0]"); 143 144 test_uniform_size_type1("bool", GL_BOOL, " ? 1.0 : 0.0"); 145 test_uniform_size_type1("bvec2", GL_BOOL_VEC2, "[0] ? 1.0 : 0.0"); 146 test_uniform_size_type1("bvec3", GL_BOOL_VEC3, "[0] ? 1.0 : 0.0"); 147 test_uniform_size_type1("bvec4", GL_BOOL_VEC4, "[0] ? 1.0 : 0.0"); 148 149 test_uniform_size_type1("int", GL_INT, ""); 150 test_uniform_size_type1("ivec2", GL_INT_VEC2, "[0]"); 151 test_uniform_size_type1("ivec3", GL_INT_VEC3, "[0]"); 152 test_uniform_size_type1("ivec4", GL_INT_VEC4, "[0]"); 153 154 test_uniform_size_type1("mat2", GL_FLOAT_MAT2, "[0][0]"); 155 test_uniform_size_type1("mat3", GL_FLOAT_MAT3, "[0][0]"); 156 test_uniform_size_type1("mat4", GL_FLOAT_MAT4, "[0][0]"); 157 test_uniform_size_type1("mat2x3", GL_FLOAT_MAT2x3, "[0][0]"); 158 test_uniform_size_type1("mat2x4", GL_FLOAT_MAT2x4, "[0][0]"); 159 test_uniform_size_type1("mat3x2", GL_FLOAT_MAT3x2, "[0][0]"); 160 test_uniform_size_type1("mat3x4", GL_FLOAT_MAT3x4, "[0][0]"); 161 test_uniform_size_type1("mat4x2", GL_FLOAT_MAT4x2, "[0][0]"); 162 test_uniform_size_type1("mat4x3", GL_FLOAT_MAT4x3, "[0][0]"); 163} 164 165static void test_attrib_size_type1(const char *glslType, GLenum glType, const char *el) 166{ 167 char buffer[1024]; 168 GLuint program; 169 GLint active, i; 170 GLenum type; 171 GLint size; 172 173 printf(" Running subtest %s\n", glslType); 174 fflush(stdout); 175 sprintf(buffer, "#version 120\nattribute %s m;\nvoid main() { gl_Position[0] = m%s; }\n", 176 glslType, el); 177 178 program = make_program(buffer, NULL); 179 glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &active); 180 assert_no_error(); 181 for (i = 0; i < active; i++) { 182 size = -1; 183 type = -1; 184 glGetActiveAttrib(program, i, sizeof(buffer), NULL, &size, &type, buffer); 185 assert_no_error(); 186 if (strncmp(buffer, "m", 1) == 0) 187 break; 188 } 189 assert(i < active); /* Otherwise the compiler optimised it out */ 190 assert(type == glType); 191 assert(size == 1); 192} 193 194static void test_attrib_size_type(void) 195{ 196 test_attrib_size_type1("float", GL_FLOAT, ""); 197 test_attrib_size_type1("vec2", GL_FLOAT_VEC2, "[0]"); 198 test_attrib_size_type1("vec3", GL_FLOAT_VEC3, "[0]"); 199 test_attrib_size_type1("vec4", GL_FLOAT_VEC4, "[0]"); 200 201 test_attrib_size_type1("mat2", GL_FLOAT_MAT2, "[0][0]"); 202 test_attrib_size_type1("mat3", GL_FLOAT_MAT3, "[0][0]"); 203 test_attrib_size_type1("mat4", GL_FLOAT_MAT4, "[0][0]"); 204 test_attrib_size_type1("mat2x3", GL_FLOAT_MAT2x3, "[0][0]"); 205 test_attrib_size_type1("mat2x4", GL_FLOAT_MAT2x4, "[0][0]"); 206 test_attrib_size_type1("mat3x2", GL_FLOAT_MAT3x2, "[0][0]"); 207 test_attrib_size_type1("mat3x4", GL_FLOAT_MAT3x4, "[0][0]"); 208 test_attrib_size_type1("mat4x2", GL_FLOAT_MAT4x2, "[0][0]"); 209 test_attrib_size_type1("mat4x3", GL_FLOAT_MAT4x3, "[0][0]"); 210} 211 212static void test_uniform_array_overflow(void) 213{ 214 GLuint program; 215 GLint location; 216 GLfloat data[128]; 217 218 program = make_program("#version 120\nuniform vec2 x[10];\nvoid main() { gl_Position.xy = x[9]; }\n", NULL); 219 location = glGetUniformLocation(program, "x"); 220 assert_no_error(); 221 glUniform2fv(location, 64, data); 222 assert_no_error(); 223} 224 225static void test_uniform_scalar_count(void) 226{ 227 GLuint program; 228 GLint location; 229 GLfloat data[128]; 230 231 program = make_program("#version 110\nuniform vec2 x;\nvoid main() { gl_Position.xy = x; }\n", NULL); 232 location = glGetUniformLocation(program, "x"); 233 assert_no_error(); 234 glUniform2fv(location, 64, data); 235 assert_error(GL_INVALID_OPERATION); 236} 237 238static void test_uniform_query_matrix(void) 239{ 240 GLuint program; 241 GLfloat data[18]; 242 GLint i, r, c; 243 GLint location; 244 245 program = make_program("#version 110\nuniform mat3 m[2];\nvoid main() { gl_Position.xyz = m[1][2]; }\n", NULL); 246 location = glGetUniformLocation(program, "m"); 247 for (i = 0; i < 9; i++) 248 data[i] = i; 249 for (i = 9; i < 18; i++) 250 data[i] = 321.0; 251 glUniformMatrix3fv(location, 1, GL_TRUE, data); 252 253 for (i = 0; i < 18; i++) 254 data[i] = 123.0; 255 glGetUniformfv(program, location, data); 256 for (c = 0; c < 3; c++) 257 for (r = 0; r < 3; r++) 258 assert(data[c * 3 + r] == r * 3 + c); 259 for (i = 9; i < 18; i++) 260 assert(data[i] == 123.0); 261} 262 263static void test_uniform_neg_location(void) 264{ 265 GLuint program; 266 GLfloat data[4]; 267 268 program = make_program("#version 110\nvoid main() { gl_Position = vec4(1.0, 1.0, 1.0, 1.0); }\n", NULL); 269 assert_no_error(); 270 (void)program; 271 glUniform1i(-1, 1); 272 assert_no_error(); 273 glUniform1i(-200, 1); 274 assert_error(GL_INVALID_OPERATION); 275 glUniformMatrix2fv(-1, 1, GL_FALSE, data); 276 assert_no_error(); 277 glUniformMatrix2fv(-200, 1, GL_FALSE, data); 278 assert_error(GL_INVALID_OPERATION); 279} 280 281static void test_uniform_bool_conversion(void) 282{ 283 GLuint program; 284 GLint location; 285 GLint value[16]; /* in case glGetUniformiv goes nuts on the stack */ 286 287 assert_no_error(); 288 program = make_program("uniform bool b;\nvoid main() { gl_Position.x = b ? 1.5 : 0.5; }\n", NULL); 289 location = glGetUniformLocation(program, "b"); 290 assert(location != -1); 291 assert_no_error(); 292 glUniform1i(location, 5); 293 assert_no_error(); 294 glGetUniformiv(program, location, &value[0]); 295 assert_no_error(); 296 assert(value[0] == 1); 297} 298 299static void test_uniform_multiple_samplers(void) 300{ 301 GLuint program; 302 GLint location; 303 GLint values[2] = {0, 1}; 304 305 assert_no_error(); 306 program = make_program(NULL, "uniform sampler2D s[2];\nvoid main() { gl_FragColor = texture2D(s[1], vec2(0.0, 0.0)); }\n"); 307 location = glGetUniformLocation(program, "s[0]"); 308 assert(location != -1); 309 assert_no_error(); 310 glUniform1iv(location, 2, values); 311 assert_no_error(); 312} 313 314static void run_test(const char *name, void (*callback)(void)) 315{ 316 printf("Running %s\n", name); 317 fflush(stdout); 318 callback(); 319} 320 321#define RUN_TEST(name) run_test(#name, (name)) 322 323int main(int argc, char **argv) 324{ 325 glutInit(&argc, argv); 326 glutCreateWindow("Mesa bug demo"); 327 glewInit(); 328 329 if (!GLEW_VERSION_2_0) { 330 printf("Sorry, this test requires OpenGL 2.x GLSL support\n"); 331 exit(0); 332 } 333 334 RUN_TEST(test_uniform_size_type); 335 RUN_TEST(test_attrib_size_type); 336 RUN_TEST(test_uniform_array_overflow); 337 RUN_TEST(test_uniform_scalar_count); 338 RUN_TEST(test_uniform_query_matrix); 339 RUN_TEST(test_uniform_neg_location); 340 RUN_TEST(test_uniform_bool_conversion); 341 /* Leave this one at the end, since it crashes Mesa's shader compiler */ 342 RUN_TEST(test_uniform_multiple_samplers); 343 return 0; 344} 345