Add more structure constructor tests.
[piglit/hramrach.git] / tests / shaders / fp-unpack-01.c
blobdfaf369167e031c7fda4ecf62489f66152dc60cd
1 /*
2 * Copyright © 2009 Intel Corporation
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
13 * Software.
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
21 * IN THE SOFTWARE.
24 /**
25 * \file fp-unpack-01.c
26 * Validate the four unpack instructions in GL_NV_fragment_program_option.
28 * \author Ian Romanick <ian.d.romanick@intel.com>
31 #include "piglit-util.h"
32 #include "piglit-framework.h"
34 /* There are 128 possible values. These values a distributed into 3 color
35 * components. Ensure that all of the values are seen at least once.
37 #define TEST_COLS ((128 / 3) + 1)
39 /* One for the reference square and each of the 4 unpack instructions
41 #define TEST_ROWS 5
43 #define BOX_SIZE 16
45 int piglit_window_mode = GLUT_DOUBLE;
46 int piglit_width = (((BOX_SIZE+1)*TEST_COLS)+1);
47 int piglit_height = (((BOX_SIZE+1)*TEST_ROWS)+1);
49 #define ELEMENTS(x) (sizeof(x) / sizeof(x[0]))
50 #define MAX2(a, b) ((a) > (b) ? (a) : (b))
51 #define MIN2(a, b) ((a) > (b) ? (b) : (a))
52 #define CLAMP(x, h, l) MIN2(MAX2(x, l), h)
54 static char shader_source[64 * 1024];
55 static GLfloat colors[TEST_COLS][4];
57 union uif {
58 float f;
59 unsigned int ui;
63 #ifndef GL_HALF_FLOAT
64 #define GL_HALF_FLOAT 0x140B
65 #endif
67 static const GLenum types[4] = {
68 GL_BYTE,
69 GL_UNSIGNED_BYTE,
70 GL_UNSIGNED_SHORT,
71 GL_HALF_FLOAT
75 static const char *const opcodes[4] = {
76 "UP4B", "UP4UB", "UP2US", "UP2H"
80 /**
81 * Source for the fragment program to render the reference box.
83 static const char reference_shader_source[] =
84 "!!ARBfp1.0\n"
85 "MOV result.color, program.env[0];\n"
86 "END"
89 /**
90 * \name Handles to fragment programs.
92 /*@{*/
93 static GLint reference_prog;
94 static GLint progs[ELEMENTS(types)];
95 /*@}*/
98 double round(double x) {
99 return floor(x + 0.5);
103 void
104 generate_shader(GLenum type)
106 unsigned len;
107 char *swiz1;
108 char *swiz2 = NULL;
109 char *inst;
111 len = sprintf(& shader_source[0],
112 "!!ARBfp1.0\n"
113 "OPTION NV_fragment_program;\n"
114 "TEMP R0;\n"
115 "\n");
117 switch (type) {
118 case GL_HALF_FLOAT:
119 inst = "UP2H";
120 swiz1 = "xy";
121 swiz2 = "zw";
122 break;
123 case GL_UNSIGNED_SHORT:
124 inst = "UP2US";
125 swiz1 = "xy";
126 swiz2 = "zw";
127 break;
128 case GL_UNSIGNED_BYTE:
129 inst = "UP4UB";
130 swiz1 = "xyzw";
131 break;
132 case GL_BYTE:
133 default:
134 inst = "UP4B";
135 swiz1 = "xyzw";
136 break;
139 len += sprintf(& shader_source[len],
140 "\n"
141 "# Unpack the data in fragment.color into four\n"
142 "# components of color data.\n"
143 "%s R0.%s, program.env[0].x;\n",
144 inst, swiz1);
146 if (swiz2 != NULL) {
147 len += sprintf(& shader_source[len],
148 "%s R0.%s, program.env[0].y;\n",
149 inst, swiz2);
152 len += sprintf(& shader_source[len],
153 "MOV result.color, R0;\n"
154 "END\n");
158 /* Largest magnitued positive half-precision float value.
160 #define HALF_MAX 65504.0
162 static GLushort
163 float_to_half(float f)
165 union uif bits;
166 unsigned sign;
167 unsigned exponent;
168 unsigned mantissa;
171 /* Clamp the value to the range of values representable by a
172 * half precision float.
174 bits.f = CLAMP(f, HALF_MAX, -HALF_MAX);
176 sign = bits.ui & (1U << 31);
177 sign >>= 16;
179 /* Round denorms to zero, but keep the sign.
181 exponent = bits.ui & (0x0ff << 23);
182 if (exponent == 0) {
183 return sign;
186 exponent >>= 23;
187 exponent += -(127 - 15);
188 exponent <<= 10;
190 /* Instead of just truncating bits of the mantissa, round the value.
192 mantissa = bits.ui & ((1U << 23) - 1);
193 mantissa += (1U << (23 - 10)) >> 1;
194 mantissa >>= (23 - 10);
196 return (sign | exponent | mantissa);
200 void
201 pack(float *packed, const float *color, GLenum type)
203 unsigned *p = (unsigned *) packed;
204 GLubyte ub[4];
205 GLushort us[4];
206 unsigned i;
208 packed[0] = 0.0f;
209 packed[1] = 0.0f;
210 packed[2] = 0.0f;
211 packed[3] = 1.0f;
213 switch (type) {
214 case GL_HALF_FLOAT:
215 for (i = 0; i < 4; i++)
216 us[i] = float_to_half(color[i]);
218 p[0] = (us[0]) | (us[1] << 16);
219 p[1] = (us[2]) | (us[3] << 16);
220 break;
222 case GL_UNSIGNED_SHORT:
223 for (i = 0; i < 4; i++) {
224 const float tmp = CLAMP(color[i], 1.0, 0.0);
225 us[i] = (GLushort) round(65535.0 * tmp);
228 p[0] = (us[0]) | (us[1] << 16);
229 p[1] = (us[2]) | (us[3] << 16);
230 break;
232 case GL_UNSIGNED_BYTE:
233 for (i = 0; i < 4; i++) {
234 const float tmp = CLAMP(color[i], 1.0, 0.0);
235 ub[i] = (GLubyte) round(255.0 * tmp);
238 p[0] = (ub[0]) | (ub[1] << 8) | (ub[2] << 16) | (ub[3] << 24);
239 break;
241 case GL_BYTE:
242 for (i = 0; i < 4; i++) {
243 const float tmp =
244 CLAMP(color[i], 1.0, -(128.0 / 127.0));
245 ub[i] = (GLubyte) round(127.0 * tmp + 128.0);
248 p[0] = (ub[0]) | (ub[1] << 8) | (ub[2] << 16) | (ub[3] << 24);
249 break;
254 enum piglit_result
255 piglit_display(void)
257 unsigned i;
258 unsigned j;
259 enum piglit_result result = PIGLIT_SUCCESS;
262 glClear(GL_COLOR_BUFFER_BIT);
263 glEnable(GL_FRAGMENT_PROGRAM_ARB);
265 for (i = 0; i < TEST_COLS; i++) {
266 const int x = (i * (BOX_SIZE + 1)) + 1;
268 glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, reference_prog);
269 glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB,
270 0, colors[i]);
271 piglit_draw_rect(x, 1, BOX_SIZE, BOX_SIZE);
273 for (j = 0; j < ELEMENTS(types); j++) {
274 const int y = ((j + 1) * (BOX_SIZE + 1)) + 1;
275 GLfloat v[4];
277 pack(v, colors[i], types[j]);
278 glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB,
279 0, v);
281 glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, progs[j]);
282 piglit_draw_rect(x, y, BOX_SIZE, BOX_SIZE);
284 if (!piglit_probe_pixel_rgb(x + (BOX_SIZE / 2),
285 y + (BOX_SIZE / 2),
286 colors[i])) {
287 if (!piglit_automatic)
288 printf("%s failed on color { %f %f %f %f }\n",
289 opcodes[j],
290 colors[i][0], colors[i][1],
291 colors[i][2], colors[i][3]);
293 result = PIGLIT_FAILURE;
298 glutSwapBuffers();
299 return result;
304 * Shuffle values in-place using Fisher–Yates shuffle.
306 void shuffle(float *values, unsigned count)
308 srand(0xCAFEBEEF);
309 for (/* empty */; count > 1; count--) {
310 int32_t idx;
311 float tmp;
313 /* Generate a random index within the unshuffled portion of the
314 * array.
316 idx = rand();
317 idx = idx % count;
319 /* Exchange the randomly selected index and the list unshuffled
320 * element in the array.
322 tmp = values[idx];
323 values[idx] = values[count - 1];
324 values[count - 1] = tmp;
329 void
330 piglit_init(int argc, char **argv)
332 unsigned i;
333 float v[TEST_COLS * 3 ];
335 (void) argc;
336 (void) argv;
338 piglit_require_fragment_program();
339 piglit_require_extension("GL_NV_fragment_program_option");
340 piglit_ortho_projection(piglit_width, piglit_height, GL_FALSE);
342 reference_prog = piglit_compile_program(GL_FRAGMENT_PROGRAM_ARB,
343 reference_shader_source);
345 glClearColor(1.0, 1.0, 1.0, 1.0);
347 for (i = 0; i < ELEMENTS(types); i++) {
348 generate_shader(types[i]);
349 progs[i] = piglit_compile_program(GL_FRAGMENT_PROGRAM_ARB,
350 shader_source);
354 /* Generate the possible color values.
356 for (i = 0; i <= 127; i++) {
357 v[i] = ((float) i) / 127.0;
360 for (/* empty */; i < ELEMENTS(v); i++) {
361 v[i] = 0.5;
365 /* Shuffle the values into random order. Generate the color data
366 * used by the tests from the shuffled values.
368 shuffle(v, 128);
369 for (i = 0; i < TEST_COLS; i++) {
370 assert((i * 3) + 2 < ELEMENTS(v));
372 colors[i][0] = v[(i * 3) + 0];
373 colors[i][1] = v[(i * 3) + 1];
374 colors[i][2] = v[(i * 3) + 2];
375 colors[i][3] = 1.0;