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
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 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
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];
64 #define GL_HALF_FLOAT 0x140B
67 static const GLenum types
[4] = {
75 static const char *const opcodes
[4] = {
76 "UP4B", "UP4UB", "UP2US", "UP2H"
81 * Source for the fragment program to render the reference box.
83 static const char reference_shader_source
[] =
85 "MOV result.color, program.env[0];\n"
90 * \name Handles to fragment programs.
93 static GLint reference_prog
;
94 static GLint progs
[ELEMENTS(types
)];
98 double round(double x
) {
99 return floor(x
+ 0.5);
104 generate_shader(GLenum type
)
111 len
= sprintf(& shader_source
[0],
113 "OPTION NV_fragment_program;\n"
123 case GL_UNSIGNED_SHORT
:
128 case GL_UNSIGNED_BYTE
:
139 len
+= sprintf(& shader_source
[len
],
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",
147 len
+= sprintf(& shader_source
[len
],
148 "%s R0.%s, program.env[0].y;\n",
152 len
+= sprintf(& shader_source
[len
],
153 "MOV result.color, R0;\n"
158 /* Largest magnitued positive half-precision float value.
160 #define HALF_MAX 65504.0
163 float_to_half(float f
)
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);
179 /* Round denorms to zero, but keep the sign.
181 exponent
= bits
.ui
& (0x0ff << 23);
187 exponent
+= -(127 - 15);
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
);
201 pack(float *packed
, const float *color
, GLenum type
)
203 unsigned *p
= (unsigned *) packed
;
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);
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);
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);
242 for (i
= 0; i
< 4; i
++) {
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);
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
,
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;
277 pack(v
, colors
[i
], types
[j
]);
278 glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB
,
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),
287 if (!piglit_automatic
)
288 printf("%s failed on color { %f %f %f %f }\n",
290 colors
[i
][0], colors
[i
][1],
291 colors
[i
][2], colors
[i
][3]);
293 result
= PIGLIT_FAILURE
;
304 * Shuffle values in-place using Fisher–Yates shuffle.
306 void shuffle(float *values
, unsigned count
)
309 for (/* empty */; count
> 1; count
--) {
313 /* Generate a random index within the unshuffled portion of the
319 /* Exchange the randomly selected index and the list unshuffled
320 * element in the array.
323 values
[idx
] = values
[count
- 1];
324 values
[count
- 1] = tmp
;
330 piglit_init(int argc
, char **argv
)
333 float v
[TEST_COLS
* 3 ];
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
,
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
++) {
365 /* Shuffle the values into random order. Generate the color data
366 * used by the tests from the shuffled values.
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];