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 property-bindings.c: Access GL state in ARB_vertex_program.
27 * Set constant parameter bindings with the OpenGL API and access it in
28 * ARB vertex programs.
30 * Matrix state is not tested.
33 #include "piglit-util-gl.h"
35 PIGLIT_GL_TEST_CONFIG_BEGIN
37 config
.supports_gl_compat_version
= 13;
38 config
.window_visual
= PIGLIT_GL_VISUAL_RGB
;
39 config
.khr_no_error_support
= PIGLIT_NO_ERRORS
;
41 PIGLIT_GL_TEST_CONFIG_END
44 #define SRAND(x) srand(x)
45 #define DRAND() ((float)rand() / RAND_MAX)
47 #define SRAND(x) srand48(x)
48 #define DRAND() drand48()
52 * This vertex program compares test_param against expected using epsilon
53 * as tolerance. On match result.color is set to green, red otherwise.
55 static const char *vp_template
=
57 "PARAM epsilon = 0.00390625;\n"
58 "PARAM expected = {%f, %f, %f, %f};\n"
59 "PARAM test_param = %s;\n"
61 "SUB temp, expected, test_param;\n"
63 "SLT temp, temp, epsilon;\n"
64 "DP4 temp, temp, temp;\n"
65 "SLT temp.x, temp.x, 4;\n"
66 "SGE temp.y, temp.y, 4;\n"
67 "SWZ result.color, temp, x, y, 0, 1;\n"
68 "MOV result.position, vertex.position;\n"
72 * Check that the constant parameter \name is equal to \val.
74 * Since we also test for derived state involving floating point computation
75 * don't test for strict equality but rather only check if the parameter's
76 * components are within and epsilon of their expected values.
79 check_prg_param_(const float *val
, const char *name
)
82 const float green
[3] = {0.0, 1.0, 0.0};
84 asprintf(&vp_text
, vp_template
, val
[0], val
[1], val
[2], val
[3], name
);
85 GLuint prog
= piglit_compile_program(GL_VERTEX_PROGRAM_ARB
, vp_text
);
87 glBindProgramARB(GL_VERTEX_PROGRAM_ARB
, prog
);
89 glClear(GL_COLOR_BUFFER_BIT
);
90 piglit_draw_rect(-1, -1, 2, 2);
92 glDeleteProgramsARB(1, &prog
);
94 if (piglit_probe_pixel_rgb_silent(piglit_width
/ 2, piglit_height
/ 2,
97 printf("Failed parameter: '%s'.\n", name
);
102 * printf-like version of function above.
105 check_prg_param(const float *val
, const char *format
, ...) PRINTFLIKE(2, 3);
107 check_prg_param(const float *val
, const char *format
, ...)
112 va_start(ap
, format
);
113 vasprintf(&name
, format
, ap
);
116 const bool r
= check_prg_param_(val
, name
);
124 const float norm
= sqrtf(v
[0] * v
[0] + v
[1] * v
[1] + v
[2] * v
[2]);
125 for (int i
= 0; i
< 3; ++i
)
130 random_vec4(float *v
)
132 for (int i
= 0; i
< 4; ++i
)
137 * Get name fragment used in ARB program for GLenum \pname.
140 enum2program(const GLenum pname
)
162 assert(!"unexpected state enum");
173 /* Material Property Bindings */
174 for (int s
= 0; s
< 2; ++s
) {
175 for (int p
= 0; p
< 4; ++p
) {
176 const GLenum pname
[] = {GL_EMISSION
, GL_AMBIENT
,
177 GL_DIFFUSE
, GL_SPECULAR
};
180 glMaterialfv(GL_FRONT
+ s
, pname
[p
], val
);
181 pass
= check_prg_param(val
, "state.material.%s.%s",
182 s
? "back" : "front",
183 enum2program(pname
[p
])) &&
186 /* The front material bindings are also accessible
190 pass
= check_prg_param(
191 val
, "state.material.%s",
192 enum2program(pname
[p
])) &&
200 glMaterialf(GL_FRONT
+ s
, GL_SHININESS
, val
[0]);
201 pass
= check_prg_param(val
, "state.material.%s.shininess",
202 s
? "back" : "front") && pass
;
205 pass
= check_prg_param(val
,
206 "state.material.shininess") &&
210 /* Light Property Bindings */
212 glGetIntegerv(GL_MAX_LIGHTS
, &max_lights
);
213 for (int l
= 0; l
< max_lights
; ++l
) {
214 for (int p
= 0; p
< 4; ++p
) {
215 const GLenum pname
[] = {GL_AMBIENT
, GL_DIFFUSE
,
216 GL_SPECULAR
, GL_POSITION
};
218 glLightfv(GL_LIGHT0
+ l
, pname
[p
], val
);
219 pass
= check_prg_param(val
, "state.light[%d].%s", l
,
220 enum2program(pname
[p
])) &&
225 glLightf(GL_LIGHT0
+ l
, GL_CONSTANT_ATTENUATION
, val
[0]);
226 glLightf(GL_LIGHT0
+ l
, GL_LINEAR_ATTENUATION
, val
[1]);
227 glLightf(GL_LIGHT0
+ l
, GL_QUADRATIC_ATTENUATION
, val
[2]);
228 glLightf(GL_LIGHT0
+ l
, GL_SPOT_EXPONENT
, val
[3]);
229 pass
= check_prg_param(val
, "state.light[%d].attenuation",
233 glLightfv(GL_LIGHT0
+ l
, GL_SPOT_DIRECTION
, val
);
234 glLightf(GL_LIGHT0
+ l
, GL_SPOT_CUTOFF
, val
[3]);
235 val
[3] = cosf(val
[3] / 180 * M_PI
);
236 pass
= check_prg_param(val
, "state.light[%d].spot.direction",
239 for (int c
= 0; c
< 3; ++c
)
242 glLightfv(GL_LIGHT0
+ l
, GL_POSITION
, val
);
246 pass
= check_prg_param(val
, "state.light[%d].half", l
) &&
251 glLightModelfv(GL_LIGHT_MODEL_AMBIENT
, val
);
252 pass
= check_prg_param(val
, "state.lightmodel.ambient") && pass
;
254 for (int s
= 0; s
< 2; ++s
) {
255 float scene_color
[4];
257 for (int c
= 0; c
< 4; ++c
)
258 scene_color
[c
] = val
[c
] = DRAND();
259 glMaterialfv(GL_FRONT
+ s
, GL_AMBIENT
, val
);
260 for (int c
= 0; c
< 4; ++c
)
261 scene_color
[c
] *= val
[c
] = DRAND();
262 glLightModelfv(GL_LIGHT_MODEL_AMBIENT
, val
);
263 for (int c
= 0; c
< 4; ++c
)
264 scene_color
[c
] += val
[c
] = DRAND();
265 glMaterialfv(GL_FRONT
+ s
, GL_EMISSION
, val
);
267 /* Page 63 (77 of the PDF) of the OpenGL 2.0 spec says:
269 * "The value of A produced by lighting is the alpha
270 * value associated with d_{cm}."
272 * I'm not sure if this applies to the scene color, but both
273 * Mesa and the NVIDIA driver do this.
276 glMaterialfv(GL_FRONT
+ s
, GL_DIFFUSE
, val
);
277 scene_color
[3] = val
[3];
279 pass
= check_prg_param(scene_color
,
280 "state.lightmodel.%s.scenecolor",
281 s
? "back" : "front") && pass
;
284 pass
= check_prg_param(
286 "state.lightmodel.scenecolor") && pass
;
289 for (int s
= 0; s
< 2; ++s
) {
290 for (int l
= 0; l
< max_lights
; ++l
) {
291 const GLenum pname
[] = {GL_AMBIENT
, GL_DIFFUSE
,
293 for (int p
= 0; p
< 3; ++p
) {
294 float light_product
[4];
295 for (int c
= 0; c
< 4; ++c
)
296 light_product
[c
] = val
[c
] = DRAND();
297 glLightfv(GL_LIGHT0
+ l
, pname
[p
], val
);
298 for (int c
= 0; c
< 4; ++c
)
299 light_product
[c
] *= val
[c
] = DRAND();
300 glMaterialfv(GL_FRONT
+ s
, pname
[p
], val
);
301 /* XXX: I have no Idea where the spec says the
302 * alpha value of the light product is the
303 * material's alpha value, but both Mesa and
304 * the NVIDIA driver do this.
306 light_product
[3] = val
[3];
308 pass
= check_prg_param(
310 "state.lightprod[%d].%s.%s", l
,
311 s
? "back" : "front",
312 enum2program(pname
[p
])) &&
316 pass
= check_prg_param(
318 "state.lightprod[%d]."
328 /* Texture Coordinate Generation Property Bindings */
329 int max_texture_coords
;
330 glGetIntegerv(GL_MAX_TEXTURE_COORDS
, &max_texture_coords
);
331 for (int t
= 0; t
< max_texture_coords
; ++t
) {
332 const GLenum coord
[] = {GL_S
, GL_T
, GL_R
, GL_Q
};
333 glActiveTexture(GL_TEXTURE0
+ t
);
335 for (int co
= 0; co
< 4; ++co
) {
336 const GLenum plane
[] = {GL_EYE_PLANE
,
338 const char *plane_name
[] = {"eye", "object"};
339 for (int pl
= 0; pl
< 2; ++pl
) {
341 glTexGenfv(coord
[co
], plane
[pl
], val
);
342 pass
= check_prg_param(
343 val
, "state.texgen[%d].%s.%s",
345 enum2program(coord
[co
])) &&
348 pass
= check_prg_param(
350 "state.texgen.%s.%s",
359 /* Fog Property Bindings */
361 glFogfv(GL_FOG_COLOR
, val
);
362 pass
= check_prg_param(val
, "state.fog.color") && pass
;
365 glFogf(GL_FOG_DENSITY
, val
[0]);
366 glFogf(GL_FOG_START
, val
[1]);
367 glFogf(GL_FOG_END
, val
[2]);
368 val
[3] = 1 / (val
[2] - val
[1]);
369 pass
= check_prg_param(val
, "state.fog.params") && pass
;
371 /* Clip Plane Property Bindings */
373 glGetIntegerv(GL_MAX_CLIP_PLANES
, &max_clip_planes
);
374 for (int cp
= 0; cp
< max_clip_planes
; ++cp
) {
376 for (int c
= 0; c
< 4; ++c
)
377 vald
[c
] = val
[c
] = DRAND();
378 glClipPlane(GL_CLIP_PLANE0
+ cp
, vald
);
379 pass
= check_prg_param(val
, "state.clip[%d].plane", cp
) &&
383 /* Point Property Bindings */
386 glPointParameterf(GL_POINT_SIZE_MIN
, val
[1]);
387 glPointParameterf(GL_POINT_SIZE_MAX
, val
[2]);
388 glPointParameterf(GL_POINT_FADE_THRESHOLD_SIZE
, val
[3]);
389 pass
= check_prg_param(val
, "state.point.size") && pass
;
393 glPointParameterfv(GL_POINT_DISTANCE_ATTENUATION
, val
);
394 pass
= check_prg_param(&val
[0], "state.point.attenuation") && pass
;
396 return pass
? PIGLIT_PASS
: PIGLIT_FAIL
;
400 piglit_init(int argc
, char **argv
)
402 piglit_require_extension("GL_ARB_vertex_program");
404 glEnable(GL_VERTEX_PROGRAM_ARB
);