2 * Copyright © 2017 Fabian Bieler
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
25 * @file built-in-matrix-state.c: Access uniform matrix derived state in GLSL
27 * Set coordinate transformation matrices with the OpenGL API and access them
28 * and their derived uniforms in a GLSL shader.
31 #include "piglit-util-gl.h"
32 #include "piglit-matrix.h"
34 PIGLIT_GL_TEST_CONFIG_BEGIN
36 config
.supports_gl_compat_version
= 20;
37 config
.window_visual
= PIGLIT_GL_VISUAL_RGB
;
38 config
.khr_no_error_support
= PIGLIT_NO_ERRORS
;
40 PIGLIT_GL_TEST_CONFIG_END
43 #define SRAND(x) srand(x)
44 #define DRAND() ((float)rand() / RAND_MAX)
46 #define SRAND(x) srand48(x)
47 #define DRAND() drand48()
51 * Compute the transpose inverse of the 4x4 matrix \m and return the upper
52 * left 3x3 block matrix in \out.
55 compute_normal_matrix(float out
[9], const float m
[16])
57 float m_inv
[16], m_inv_T
[16];
58 piglit_matrix_inverse(m_inv
, m
);
59 piglit_matrix_transpose(m_inv_T
, m_inv
);
71 static const char *vs_text
=
73 " gl_Position = gl_Vertex;\n"
75 static const char *fs_mat4
=
77 " vec4 epsilon = vec4(1.0 / 256.0);\n"
78 " vec4 green = vec4(0.0, 1.0, 0.0, 1.0);\n"
79 " vec4 red = vec4(1.0, 0.0, 0.0, 1.0);\n"
81 " mat4 b = mat4(%f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, "
83 " bool pass = true;\n"
84 " pass = pass && all(lessThan(abs(a[0] - b[0]), epsilon));\n"
85 " pass = pass && all(lessThan(abs(a[1] - b[1]), epsilon));\n"
86 " pass = pass && all(lessThan(abs(a[2] - b[2]), epsilon));\n"
87 " pass = pass && all(lessThan(abs(a[3] - b[3]), epsilon));\n"
88 " gl_FragColor = pass ? green : red;\n"
90 static const char *fs_mat3
=
92 " vec3 epsilon = vec3(1.0 / 256.0);\n"
93 " vec4 green = vec4(0.0, 1.0, 0.0, 1.0);\n"
94 " vec4 red = vec4(1.0, 0.0, 0.0, 1.0);\n"
96 " mat3 b = mat3(%f, %f, %f, %f, %f, %f, %f, %f, %f);\n"
97 " bool pass = true;\n"
98 " pass = pass && all(lessThan(abs(a[0] - b[0]), epsilon));\n"
99 " pass = pass && all(lessThan(abs(a[1] - b[1]), epsilon));\n"
100 " pass = pass && all(lessThan(abs(a[2] - b[2]), epsilon));\n"
101 " gl_FragColor = pass ? green : red;\n"
103 static const char *fs_float
=
105 " float epsilon = (1.0 / 256.0);\n"
106 " vec4 green = vec4(0.0, 1.0, 0.0, 1.0);\n"
107 " vec4 red = vec4(1.0, 0.0, 0.0, 1.0);\n"
108 " gl_FragColor = abs(%s - %f) < epsilon ? green : red;\n"
112 * Check that the built-in shader uniform \name of type \type is equal to \m.
114 * Since we also test for derived state involving floating point computation
115 * don't test for strict equality but rather only check if the uniform's
116 * components are within and espilon of their expected values.
119 check_shader_builtin(const GLenum type
, const float *m
, const char *name
)
122 const float green
[3] = {0.0, 1.0, 0.0};
126 asprintf(&fs_text
, fs_float
, name
, m
[0]);
129 asprintf(&fs_text
, fs_mat4
, name
, m
[0], m
[1], m
[2], m
[3],
130 m
[4], m
[5], m
[6], m
[7], m
[8], m
[9], m
[10], m
[11],
131 m
[12], m
[13], m
[14], m
[15]);
134 asprintf(&fs_text
, fs_mat3
, name
, m
[0], m
[1], m
[2], m
[3],
135 m
[4], m
[5], m
[6], m
[7], m
[8], m
[9]);
141 const GLuint program
= piglit_build_simple_program(vs_text
, fs_text
);
143 glUseProgram(program
);
144 glDeleteProgram(program
);
145 glClear(GL_COLOR_BUFFER_BIT
);
146 piglit_draw_rect(-1, -1, 2, 2);
148 if (piglit_probe_pixel_rgb_silent(piglit_width
/ 2, piglit_height
/ 2,
151 printf("Failed uniform: '%s'.\n", name
);
156 * Load random 16 floats between 0 and 1 int matrix \pname
157 * and return them in \m.
160 load_matrix(float m
[16], const GLenum pname
)
163 for (int i
= 0; i
< 16; ++i
)
169 * Check that matrix \pname contains the values \m.
170 * if \idx is zero or positive add it as and index to the matrix array.
171 * Also check the matrix' transpose, inverse and transpose inverse.
174 check_matrix_variants(const char *prefix
, const float m
[16], const int idx
)
177 char *name
, *name_T
, *name_inv
, *name_inv_T
;
178 float m_T
[16], m_inv
[16], m_inv_T
[16];
181 asprintf(&name
, "%s[%d]", prefix
, idx
);
182 asprintf(&name_T
, "%sTranspose[%d]", prefix
, idx
);
183 asprintf(&name_inv
, "%sInverse[%d]", prefix
, idx
);
184 asprintf(&name_inv_T
, "%sInverseTranspose[%d]", prefix
, idx
);
186 asprintf(&name
, "%s", prefix
);
187 asprintf(&name_T
, "%sTranspose", prefix
);
188 asprintf(&name_inv
, "%sInverse", prefix
);
189 asprintf(&name_inv_T
, "%sInverseTranspose", prefix
);
192 piglit_matrix_transpose(m_T
, m
);
193 piglit_matrix_inverse(m_inv
, m
);
194 piglit_matrix_transpose(m_inv_T
, m_inv
);
196 pass
= check_shader_builtin(GL_FLOAT_MAT4
, m
, name
) && pass
;
197 pass
= check_shader_builtin(GL_FLOAT_MAT4
, m_T
, name_T
) && pass
;
198 pass
= check_shader_builtin(GL_FLOAT_MAT4
, m_inv
, name_inv
) && pass
;
199 pass
= check_shader_builtin(GL_FLOAT_MAT4
, m_inv_T
, name_inv_T
) &&
211 * Load random data in matrix \pname and check it by it's shader name \name
212 * with (optional) index \idx.
215 load_and_test_matrix(const char *name
, const GLenum pname
, const int idx
)
219 load_matrix(mat
, pname
);
220 return check_matrix_variants(name
, mat
, idx
);
228 /* Test modelview and projection matrices. */
229 pass
= load_and_test_matrix("gl_ModelViewMatrix", GL_MODELVIEW
, -1) &&
232 pass
= load_and_test_matrix("gl_ProjectionMatrix", GL_PROJECTION
, -1)
235 /* Test modelview-projection matrix. */
236 float mvp
[16], proj
[16], mview
[16];
237 load_matrix(mview
, GL_MODELVIEW
);
238 load_matrix(proj
, GL_PROJECTION
);
239 piglit_matrix_mul_matrix(mvp
, proj
, mview
);
240 pass
= check_matrix_variants("gl_ModelViewProjectionMatrix", mvp
, -1)
243 /* Test texture matrices. */
244 int max_texture_coords
;
245 glGetIntegerv(GL_MAX_TEXTURE_COORDS
, &max_texture_coords
);
246 for (int t
= 0; t
< max_texture_coords
; ++t
) {
247 glActiveTexture(GL_TEXTURE0
+ t
);
248 pass
= load_and_test_matrix("gl_TextureMatrix",
249 GL_TEXTURE
, t
) && pass
;
253 /* Test normal matrix. */
254 float norm
[9] = { 0 };
255 load_matrix(mview
, GL_MODELVIEW
);
256 compute_normal_matrix(norm
, mview
);
257 pass
= check_shader_builtin(GL_FLOAT_MAT3
, norm
, "gl_NormalMatrix")
260 /* Test normal scale factor.
261 * Page 49 (63 of the PDF) of the OpenGL 2.0 spec says:
263 * "Rescale multiplies the transformed normals by a scale factor
264 * [f] [...] If rescaling is disabled, then f = 1."
266 * I'm unsure if this affacts the shader's built-in uniform, but
267 * enable normal rescaling just in case.
269 glEnable(GL_RESCALE_NORMAL
);
270 float ns
= norm
[6] * norm
[6] + norm
[7] * norm
[7] + norm
[8] * norm
[8];
272 pass
= check_shader_builtin(GL_FLOAT
, &ns
, "gl_NormalScale") && pass
;
274 return pass
? PIGLIT_PASS
: PIGLIT_FAIL
;
278 piglit_init(int argc
, char **argv
)