b8c54aec8dfb4bd3c2252f5b6708cfed201eb19b
[mesa.git] / progs / gallium / unit / u_format_test.c
1 /**************************************************************************
2 *
3 * Copyright 2009-2010 VMware, Inc.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <float.h>
32
33 #include "util/u_format.h"
34 #include "util/u_format_tests.h"
35 #include "util/u_format_s3tc.h"
36
37
38 static boolean
39 compare_float(float x, float y)
40 {
41 float error = y - x;
42
43 if (error < 0.0f)
44 error = -error;
45
46 if (error > FLT_EPSILON) {
47 return FALSE;
48 }
49
50 return TRUE;
51 }
52
53
54 static void
55 print_packed(const struct util_format_description *format_desc,
56 const char *prefix,
57 const uint8_t *packed,
58 const char *suffix)
59 {
60 unsigned i;
61 const char *sep = "";
62
63 printf("%s", prefix);
64 for (i = 0; i < format_desc->block.bits/8; ++i) {
65 printf("%s%02x", sep, packed[i]);
66 sep = " ";
67 }
68 printf("%s", suffix);
69 }
70
71
72 static void
73 print_unpacked_doubl(const struct util_format_description *format_desc,
74 const char *prefix,
75 const double unpacked[UTIL_FORMAT_MAX_UNPACKED_HEIGHT][UTIL_FORMAT_MAX_UNPACKED_WIDTH][4],
76 const char *suffix)
77 {
78 unsigned i, j;
79 const char *sep = "";
80
81 printf("%s", prefix);
82 for (i = 0; i < format_desc->block.height; ++i) {
83 for (j = 0; j < format_desc->block.width; ++j) {
84 printf("%s{%f, %f, %f, %f}", sep, unpacked[i][j][0], unpacked[i][j][1], unpacked[i][j][2], unpacked[i][j][3]);
85 sep = ", ";
86 }
87 sep = ",\n";
88 }
89 printf("%s", suffix);
90 }
91
92
93 static void
94 print_unpacked_float(const struct util_format_description *format_desc,
95 const char *prefix,
96 const float unpacked[UTIL_FORMAT_MAX_UNPACKED_HEIGHT][UTIL_FORMAT_MAX_UNPACKED_WIDTH][4],
97 const char *suffix)
98 {
99 unsigned i, j;
100 const char *sep = "";
101
102 printf("%s", prefix);
103 for (i = 0; i < format_desc->block.height; ++i) {
104 for (j = 0; j < format_desc->block.width; ++j) {
105 printf("%s{%f, %f, %f, %f}", sep, unpacked[i][j][0], unpacked[i][j][1], unpacked[i][j][2], unpacked[i][j][3]);
106 sep = ", ";
107 }
108 sep = ",\n";
109 }
110 printf("%s", suffix);
111 }
112
113
114 static void
115 print_unpacked_8unorm(const struct util_format_description *format_desc,
116 const char *prefix,
117 const uint8_t unpacked[][UTIL_FORMAT_MAX_UNPACKED_WIDTH][4],
118 const char *suffix)
119 {
120 unsigned i, j;
121 const char *sep = "";
122
123 printf("%s", prefix);
124 for (i = 0; i < format_desc->block.height; ++i) {
125 for (j = 0; j < format_desc->block.width; ++j) {
126 printf("%s{0x%02x, 0x%02x, 0x%02x, 0x%02x}", sep, unpacked[i][j][0], unpacked[i][j][1], unpacked[i][j][2], unpacked[i][j][3]);
127 sep = ", ";
128 }
129 }
130 printf("%s", suffix);
131 }
132
133
134 static boolean
135 test_format_fetch_float(const struct util_format_description *format_desc,
136 const struct util_format_test_case *test)
137 {
138 float unpacked[UTIL_FORMAT_MAX_UNPACKED_HEIGHT][UTIL_FORMAT_MAX_UNPACKED_WIDTH][4];
139 unsigned i, j, k;
140 boolean success;
141
142 success = TRUE;
143 for (i = 0; i < format_desc->block.height; ++i) {
144 for (j = 0; j < format_desc->block.width; ++j) {
145 format_desc->fetch_float(unpacked[i][j], test->packed, j, i);
146 for (k = 0; k < 4; ++k) {
147 if (!compare_float(test->unpacked[i][j][k], unpacked[i][j][k])) {
148 success = FALSE;
149 }
150 }
151 }
152 }
153
154 if (!success) {
155 print_unpacked_float(format_desc, "FAILED: ", unpacked, " obtained\n");
156 print_unpacked_doubl(format_desc, " ", test->unpacked, " expected\n");
157 }
158
159 return success;
160 }
161
162
163 static boolean
164 test_format_unpack_float(const struct util_format_description *format_desc,
165 const struct util_format_test_case *test)
166 {
167 float unpacked[UTIL_FORMAT_MAX_UNPACKED_HEIGHT][UTIL_FORMAT_MAX_UNPACKED_WIDTH][4];
168 unsigned i, j, k;
169 boolean success;
170
171 format_desc->unpack_float(&unpacked[0][0][0], sizeof unpacked[0], test->packed, 0, format_desc->block.width, format_desc->block.height);
172
173 success = TRUE;
174 for (i = 0; i < format_desc->block.height; ++i) {
175 for (j = 0; j < format_desc->block.width; ++j) {
176 for (k = 0; k < 4; ++k) {
177 if (!compare_float(test->unpacked[i][j][k], unpacked[i][j][k])) {
178 success = FALSE;
179 }
180 }
181 }
182 }
183
184 if (!success) {
185 print_unpacked_float(format_desc, "FAILED: ", unpacked, " obtained\n");
186 print_unpacked_doubl(format_desc, " ", test->unpacked, " expected\n");
187 }
188
189 return success;
190 }
191
192
193 static boolean
194
195 test_format_pack_float(const struct util_format_description *format_desc,
196 const struct util_format_test_case *test)
197 {
198 float unpacked[UTIL_FORMAT_MAX_UNPACKED_HEIGHT][UTIL_FORMAT_MAX_UNPACKED_WIDTH][4];
199 uint8_t packed[UTIL_FORMAT_MAX_PACKED_BYTES];
200 unsigned i, j, k;
201 boolean success;
202
203 if (test->format == PIPE_FORMAT_DXT1_RGBA) {
204 /*
205 * Skip S3TC as packed representation is not canonical.
206 *
207 * TODO: Do a round trip conversion.
208 */
209 return TRUE;
210 }
211
212 memset(packed, 0, sizeof packed);
213 for (i = 0; i < format_desc->block.height; ++i) {
214 for (j = 0; j < format_desc->block.width; ++j) {
215 for (k = 0; k < 4; ++k) {
216 unpacked[i][j][k] = (float) test->unpacked[i][j][k];
217 }
218 }
219 }
220
221 format_desc->pack_float(packed, 0, &unpacked[0][0][0], sizeof unpacked[0], format_desc->block.width, format_desc->block.height);
222
223 success = TRUE;
224 for (i = 0; i < format_desc->block.bits/8; ++i)
225 if ((test->packed[i] & test->mask[i]) != (packed[i] & test->mask[i]))
226 success = FALSE;
227
228 if (!success) {
229 print_packed(format_desc, "FAILED: ", packed, " obtained\n");
230 print_packed(format_desc, " ", test->packed, " expected\n");
231 }
232
233 return success;
234 }
235
236
237 static boolean
238 convert_float_to_8unorm(uint8_t *dst, const double *src)
239 {
240 unsigned i;
241 boolean accurate = TRUE;
242
243 for (i = 0; i < UTIL_FORMAT_MAX_UNPACKED_HEIGHT*UTIL_FORMAT_MAX_UNPACKED_WIDTH*4; ++i) {
244 if (src[i] < 0.0) {
245 accurate = FALSE;
246 dst[i] = 0;
247 }
248 else if (src[i] > 1.0) {
249 accurate = FALSE;
250 dst[i] = 255;
251 }
252 else {
253 dst[i] = src[i] * 255.0;
254 }
255 }
256
257 return accurate;
258 }
259
260
261 static boolean
262 test_format_unpack_8unorm(const struct util_format_description *format_desc,
263 const struct util_format_test_case *test)
264 {
265 uint8_t unpacked[UTIL_FORMAT_MAX_UNPACKED_HEIGHT][UTIL_FORMAT_MAX_UNPACKED_WIDTH][4];
266 uint8_t expected[UTIL_FORMAT_MAX_UNPACKED_HEIGHT][UTIL_FORMAT_MAX_UNPACKED_WIDTH][4];
267 unsigned i, j, k;
268 boolean success;
269
270 format_desc->unpack_8unorm(&unpacked[0][0][0], sizeof unpacked[0], test->packed, 0, 1, 1);
271
272 convert_float_to_8unorm(&expected[0][0][0], &test->unpacked[0][0][0]);
273
274 success = TRUE;
275 for (i = 0; i < format_desc->block.height; ++i) {
276 for (j = 0; j < format_desc->block.width; ++j) {
277 for (k = 0; k < 4; ++k) {
278 if (expected[i][j][k] != unpacked[i][j][k]) {
279 success = FALSE;
280 }
281 }
282 }
283 }
284
285 if (!success) {
286 print_unpacked_8unorm(format_desc, "FAILED: ", unpacked, " obtained\n");
287 print_unpacked_8unorm(format_desc, " ", expected, " expected\n");
288 }
289
290 return success;
291 }
292
293
294 static boolean
295 test_format_pack_8unorm(const struct util_format_description *format_desc,
296 const struct util_format_test_case *test)
297 {
298 uint8_t unpacked[UTIL_FORMAT_MAX_UNPACKED_HEIGHT][UTIL_FORMAT_MAX_UNPACKED_WIDTH][4];
299 uint8_t packed[UTIL_FORMAT_MAX_PACKED_BYTES];
300 unsigned i;
301 boolean success;
302
303 if (test->format == PIPE_FORMAT_DXT1_RGBA) {
304 /*
305 * Skip S3TC as packed representation is not canonical.
306 *
307 * TODO: Do a round trip conversion.
308 */
309 return TRUE;
310 }
311
312 if (!convert_float_to_8unorm(&unpacked[0][0][0], &test->unpacked[0][0][0])) {
313 /*
314 * Skip test cases which cannot be represented by four unorm bytes.
315 */
316 return TRUE;
317 }
318
319 memset(packed, 0, sizeof packed);
320
321 format_desc->pack_8unorm(packed, 0, &unpacked[0][0][0], sizeof unpacked[0], 1, 1);
322
323 success = TRUE;
324 for (i = 0; i < format_desc->block.bits/8; ++i)
325 if ((test->packed[i] & test->mask[i]) != (packed[i] & test->mask[i]))
326 success = FALSE;
327
328 if (!success) {
329 print_packed(format_desc, "FAILED: ", packed, " obtained\n");
330 print_packed(format_desc, " ", test->packed, " expected\n");
331 }
332
333 return success;
334 }
335
336
337 typedef boolean
338 (*test_func_t)(const struct util_format_description *format_desc,
339 const struct util_format_test_case *test);
340
341
342 static boolean
343 test_one(test_func_t func, const char *suffix)
344 {
345 enum pipe_format last_format = PIPE_FORMAT_NONE;
346 unsigned i;
347 bool success = TRUE;
348
349 for (i = 0; i < util_format_nr_test_cases; ++i) {
350 const struct util_format_test_case *test = &util_format_test_cases[i];
351 const struct util_format_description *format_desc;
352 bool skip = FALSE;
353
354 format_desc = util_format_description(test->format);
355
356 if (format_desc->layout == UTIL_FORMAT_LAYOUT_S3TC &&
357 !util_format_s3tc_enabled) {
358 skip = TRUE;
359 }
360
361 if (test->format != last_format) {
362 printf("%s util_format_%s_%s ...\n",
363 skip ? "Skipping" : "Testing", format_desc->short_name, suffix);
364 last_format = test->format;
365 }
366
367 if (!skip) {
368 if (!func(format_desc, &util_format_test_cases[i])) {
369 success = FALSE;
370 }
371 }
372 }
373
374 return success;
375 }
376
377
378 static boolean
379 test_all(void)
380 {
381 bool success = TRUE;
382
383 if (!test_one(&test_format_fetch_float, "fetch_float"))
384 success = FALSE;
385
386 if (!test_one(&test_format_pack_float, "pack_float"))
387 success = FALSE;
388
389 if (!test_one(&test_format_unpack_float, "unpack_float"))
390 success = FALSE;
391
392 if (!test_one(&test_format_pack_8unorm, "pack_8unorm"))
393 success = FALSE;
394
395 if (!test_one(&test_format_unpack_8unorm, "unpack_8unorm"))
396 success = FALSE;
397
398 return success;
399 }
400
401
402 int main(int argc, char **argv)
403 {
404 boolean success;
405
406 util_format_s3tc_init();
407
408 success = test_all();
409
410 return success ? 0 : 1;
411 }