gallium/util: fix util_color_[un]pack[-ub] to be strict aliasing safe
[mesa.git] / src / gallium / auxiliary / util / u_pack_color.h
1 /**************************************************************************
2 *
3 * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
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 TUNGSTEN GRAPHICS 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 * @file
30 * Functions to produce packed colors/Z from floats.
31 */
32
33
34 #ifndef U_PACK_COLOR_H
35 #define U_PACK_COLOR_H
36
37
38 #include "pipe/p_compiler.h"
39 #include "pipe/p_format.h"
40 #include "util/u_math.h"
41
42
43
44 union util_color {
45 ubyte ub;
46 ushort us;
47 uint ui;
48 float f[4];
49 };
50
51 /**
52 * Pack ubyte R,G,B,A into dest pixel.
53 */
54 static INLINE void
55 util_pack_color_ub(ubyte r, ubyte g, ubyte b, ubyte a,
56 enum pipe_format format, union util_color *uc)
57 {
58 switch (format) {
59 case PIPE_FORMAT_R8G8B8A8_UNORM:
60 {
61 uc->ui = (r << 24) | (g << 16) | (b << 8) | a;
62 }
63 return;
64 case PIPE_FORMAT_R8G8B8X8_UNORM:
65 {
66 uc->ui = (r << 24) | (g << 16) | (b << 8) | 0xff;
67 }
68 return;
69 case PIPE_FORMAT_A8R8G8B8_UNORM:
70 {
71 uc->ui = (a << 24) | (r << 16) | (g << 8) | b;
72 }
73 return;
74 case PIPE_FORMAT_X8R8G8B8_UNORM:
75 {
76 uc->ui = (0xff << 24) | (r << 16) | (g << 8) | b;
77 }
78 return;
79 case PIPE_FORMAT_B8G8R8A8_UNORM:
80 {
81 uc->ui = (b << 24) | (g << 16) | (r << 8) | a;
82 }
83 return;
84 case PIPE_FORMAT_B8G8R8X8_UNORM:
85 {
86 uc->ui = (b << 24) | (g << 16) | (r << 8) | 0xff;
87 }
88 return;
89 case PIPE_FORMAT_R5G6B5_UNORM:
90 {
91 uc->us = ((r & 0xf8) << 8) | ((g & 0xfc) << 3) | (b >> 3);
92 }
93 return;
94 case PIPE_FORMAT_A1R5G5B5_UNORM:
95 {
96 uc->us = ((a & 0x80) << 8) | ((r & 0xf8) << 7) | ((g & 0xf8) << 2) | (b >> 3);
97 }
98 return;
99 case PIPE_FORMAT_A4R4G4B4_UNORM:
100 {
101 uc->us = ((a & 0xf0) << 8) | ((r & 0xf0) << 4) | ((g & 0xf0) << 0) | (b >> 4);
102 }
103 return;
104 case PIPE_FORMAT_A8_UNORM:
105 {
106 uc->ub = a;
107 }
108 return;
109 case PIPE_FORMAT_L8_UNORM:
110 case PIPE_FORMAT_I8_UNORM:
111 {
112 uc->ub = a;
113 }
114 return;
115 case PIPE_FORMAT_R32G32B32A32_FLOAT:
116 {
117 uc->f[0] = (float)r / 255.0f;
118 uc->f[1] = (float)g / 255.0f;
119 uc->f[2] = (float)b / 255.0f;
120 uc->f[3] = (float)a / 255.0f;
121 }
122 return;
123 case PIPE_FORMAT_R32G32B32_FLOAT:
124 {
125 uc->f[0] = (float)r / 255.0f;
126 uc->f[1] = (float)g / 255.0f;
127 uc->f[2] = (float)b / 255.0f;
128 }
129 return;
130
131 /* XXX lots more cases to add */
132 default:
133 uc->ui = 0; /* keep compiler happy */
134 debug_print_format("gallium: unhandled format in util_pack_color_ub()", format);
135 assert(0);
136 }
137 }
138
139
140 /**
141 * Unpack RGBA from a packed pixel, returning values as ubytes in [0,255].
142 */
143 static INLINE void
144 util_unpack_color_ub(enum pipe_format format, union util_color *uc,
145 ubyte *r, ubyte *g, ubyte *b, ubyte *a)
146 {
147 switch (format) {
148 case PIPE_FORMAT_R8G8B8A8_UNORM:
149 {
150 uint p = uc->ui;
151 *r = (ubyte) ((p >> 24) & 0xff);
152 *g = (ubyte) ((p >> 16) & 0xff);
153 *b = (ubyte) ((p >> 8) & 0xff);
154 *a = (ubyte) ((p >> 0) & 0xff);
155 }
156 return;
157 case PIPE_FORMAT_R8G8B8X8_UNORM:
158 {
159 uint p = uc->ui;
160 *r = (ubyte) ((p >> 24) & 0xff);
161 *g = (ubyte) ((p >> 16) & 0xff);
162 *b = (ubyte) ((p >> 8) & 0xff);
163 *a = (ubyte) 0xff;
164 }
165 return;
166 case PIPE_FORMAT_A8R8G8B8_UNORM:
167 {
168 uint p = uc->ui;
169 *r = (ubyte) ((p >> 16) & 0xff);
170 *g = (ubyte) ((p >> 8) & 0xff);
171 *b = (ubyte) ((p >> 0) & 0xff);
172 *a = (ubyte) ((p >> 24) & 0xff);
173 }
174 return;
175 case PIPE_FORMAT_X8R8G8B8_UNORM:
176 {
177 uint p = uc->ui;
178 *r = (ubyte) ((p >> 16) & 0xff);
179 *g = (ubyte) ((p >> 8) & 0xff);
180 *b = (ubyte) ((p >> 0) & 0xff);
181 *a = (ubyte) 0xff;
182 }
183 return;
184 case PIPE_FORMAT_B8G8R8A8_UNORM:
185 {
186 uint p = uc->ui;
187 *r = (ubyte) ((p >> 8) & 0xff);
188 *g = (ubyte) ((p >> 16) & 0xff);
189 *b = (ubyte) ((p >> 24) & 0xff);
190 *a = (ubyte) ((p >> 0) & 0xff);
191 }
192 return;
193 case PIPE_FORMAT_B8G8R8X8_UNORM:
194 {
195 uint p = uc->ui;
196 *r = (ubyte) ((p >> 8) & 0xff);
197 *g = (ubyte) ((p >> 16) & 0xff);
198 *b = (ubyte) ((p >> 24) & 0xff);
199 *a = (ubyte) 0xff;
200 }
201 return;
202 case PIPE_FORMAT_R5G6B5_UNORM:
203 {
204 ushort p = uc->us;
205 *r = (ubyte) (((p >> 8) & 0xf8) | ((p >> 13) & 0x7));
206 *g = (ubyte) (((p >> 3) & 0xfc) | ((p >> 9) & 0x3));
207 *b = (ubyte) (((p << 3) & 0xf8) | ((p >> 2) & 0x7));
208 *a = (ubyte) 0xff;
209 }
210 return;
211 case PIPE_FORMAT_A1R5G5B5_UNORM:
212 {
213 ushort p = uc->us;
214 *r = (ubyte) (((p >> 7) & 0xf8) | ((p >> 12) & 0x7));
215 *g = (ubyte) (((p >> 2) & 0xf8) | ((p >> 7) & 0x7));
216 *b = (ubyte) (((p << 3) & 0xf8) | ((p >> 2) & 0x7));
217 *a = (ubyte) (0xff * (p >> 15));
218 }
219 return;
220 case PIPE_FORMAT_A4R4G4B4_UNORM:
221 {
222 ushort p = uc->us;
223 *r = (ubyte) (((p >> 4) & 0xf0) | ((p >> 8) & 0xf));
224 *g = (ubyte) (((p >> 0) & 0xf0) | ((p >> 4) & 0xf));
225 *b = (ubyte) (((p << 4) & 0xf0) | ((p >> 0) & 0xf));
226 *a = (ubyte) (((p >> 8) & 0xf0) | ((p >> 12) & 0xf));
227 }
228 return;
229 case PIPE_FORMAT_A8_UNORM:
230 {
231 ubyte p = uc->ub;
232 *r = *g = *b = (ubyte) 0xff;
233 *a = p;
234 }
235 return;
236 case PIPE_FORMAT_L8_UNORM:
237 {
238 ubyte p = uc->ub;
239 *r = *g = *b = p;
240 *a = (ubyte) 0xff;
241 }
242 return;
243 case PIPE_FORMAT_I8_UNORM:
244 {
245 ubyte p = uc->ub;
246 *r = *g = *b = *a = p;
247 }
248 return;
249 case PIPE_FORMAT_R32G32B32A32_FLOAT:
250 {
251 const float *p = &uc->f[0];
252 *r = float_to_ubyte(p[0]);
253 *g = float_to_ubyte(p[1]);
254 *b = float_to_ubyte(p[2]);
255 *a = float_to_ubyte(p[3]);
256 }
257 return;
258 case PIPE_FORMAT_R32G32B32_FLOAT:
259 {
260 const float *p = &uc->f[0];
261 *r = float_to_ubyte(p[0]);
262 *g = float_to_ubyte(p[1]);
263 *b = float_to_ubyte(p[2]);
264 *a = (ubyte) 0xff;
265 }
266 return;
267
268 case PIPE_FORMAT_R32G32_FLOAT:
269 {
270 const float *p = &uc->f[0];
271 *r = float_to_ubyte(p[0]);
272 *g = float_to_ubyte(p[1]);
273 *b = *a = (ubyte) 0xff;
274 }
275 return;
276
277 case PIPE_FORMAT_R32_FLOAT:
278 {
279 const float *p = &uc->f[0];
280 *r = float_to_ubyte(p[0]);
281 *g = *b = *a = (ubyte) 0xff;
282 }
283 return;
284
285 /* XXX lots more cases to add */
286 default:
287 debug_print_format("gallium: unhandled format in util_unpack_color_ub()",
288 format);
289 assert(0);
290 }
291 }
292
293
294 /**
295 * Note rgba outside [0,1] will be clamped for int pixel formats.
296 */
297 static INLINE void
298 util_pack_color(const float rgba[4], enum pipe_format format, union util_color *uc)
299 {
300 ubyte r = 0;
301 ubyte g = 0;
302 ubyte b = 0;
303 ubyte a = 0;
304
305 if (pf_size_x(format) <= 8) {
306 /* format uses 8-bit components or less */
307 r = float_to_ubyte(rgba[0]);
308 g = float_to_ubyte(rgba[1]);
309 b = float_to_ubyte(rgba[2]);
310 a = float_to_ubyte(rgba[3]);
311 }
312
313 switch (format) {
314 case PIPE_FORMAT_R8G8B8A8_UNORM:
315 {
316 uc->ui = (r << 24) | (g << 16) | (b << 8) | a;
317 }
318 return;
319 case PIPE_FORMAT_R8G8B8X8_UNORM:
320 {
321 uc->ui = (r << 24) | (g << 16) | (b << 8) | 0xff;
322 }
323 return;
324 case PIPE_FORMAT_A8R8G8B8_UNORM:
325 {
326 uc->ui = (a << 24) | (r << 16) | (g << 8) | b;
327 }
328 return;
329 case PIPE_FORMAT_X8R8G8B8_UNORM:
330 {
331 uc->ui = (0xff << 24) | (r << 16) | (g << 8) | b;
332 }
333 return;
334 case PIPE_FORMAT_B8G8R8A8_UNORM:
335 {
336 uc->ui = (b << 24) | (g << 16) | (r << 8) | a;
337 }
338 return;
339 case PIPE_FORMAT_B8G8R8X8_UNORM:
340 {
341 uc->ui = (b << 24) | (g << 16) | (r << 8) | 0xff;
342 }
343 return;
344 case PIPE_FORMAT_R5G6B5_UNORM:
345 {
346 uc->us = ((r & 0xf8) << 8) | ((g & 0xfc) << 3) | (b >> 3);
347 }
348 return;
349 case PIPE_FORMAT_A1R5G5B5_UNORM:
350 {
351 uc->us = ((a & 0x80) << 8) | ((r & 0xf8) << 7) | ((g & 0xf8) << 2) | (b >> 3);
352 }
353 return;
354 case PIPE_FORMAT_A4R4G4B4_UNORM:
355 {
356 uc->ub = ((a & 0xf0) << 8) | ((r & 0xf0) << 4) | ((g & 0xf0) << 0) | (b >> 4);
357 }
358 return;
359 case PIPE_FORMAT_A8_UNORM:
360 {
361 uc->ub = a;
362 }
363 return;
364 case PIPE_FORMAT_L8_UNORM:
365 case PIPE_FORMAT_I8_UNORM:
366 {
367 uc->ub = r;
368 }
369 return;
370 case PIPE_FORMAT_R32G32B32A32_FLOAT:
371 {
372 uc->f[0] = rgba[0];
373 uc->f[1] = rgba[1];
374 uc->f[2] = rgba[2];
375 uc->f[3] = rgba[3];
376 }
377 return;
378 case PIPE_FORMAT_R32G32B32_FLOAT:
379 {
380 uc->f[0] = rgba[0];
381 uc->f[1] = rgba[1];
382 uc->f[2] = rgba[2];
383 }
384 return;
385 /* XXX lots more cases to add */
386 default:
387 uc->ui = 0; /* keep compiler happy */
388 debug_print_format("gallium: unhandled format in util_pack_color()", format);
389 assert(0);
390 }
391 }
392
393
394 /**
395 * Note: it's assumed that z is in [0,1]
396 */
397 static INLINE uint
398 util_pack_z(enum pipe_format format, double z)
399 {
400 if (z == 0.0)
401 return 0;
402
403 switch (format) {
404 case PIPE_FORMAT_Z16_UNORM:
405 if (z == 1.0)
406 return 0xffff;
407 return (uint) (z * 0xffff);
408 case PIPE_FORMAT_Z32_UNORM:
409 /* special-case to avoid overflow */
410 if (z == 1.0)
411 return 0xffffffff;
412 return (uint) (z * 0xffffffff);
413 case PIPE_FORMAT_S8Z24_UNORM:
414 case PIPE_FORMAT_X8Z24_UNORM:
415 if (z == 1.0)
416 return 0xffffff;
417 return (uint) (z * 0xffffff);
418 case PIPE_FORMAT_Z24S8_UNORM:
419 case PIPE_FORMAT_Z24X8_UNORM:
420 if (z == 1.0)
421 return 0xffffff00;
422 return ((uint) (z * 0xffffff)) << 8;
423 case PIPE_FORMAT_S8_UNORM:
424 /* this case can get it via util_pack_z_stencil() */
425 return 0;
426 default:
427 debug_print_format("gallium: unhandled format in util_pack_z()", format);
428 assert(0);
429 return 0;
430 }
431 }
432
433
434 /**
435 * Pack Z and/or stencil values into a 32-bit value described by format.
436 * Note: it's assumed that z is in [0,1] and s in [0,255]
437 */
438 static INLINE uint
439 util_pack_z_stencil(enum pipe_format format, double z, uint s)
440 {
441 unsigned packed = util_pack_z(format, z);
442
443 switch (format) {
444 case PIPE_FORMAT_S8Z24_UNORM:
445 packed |= s << 24;
446 break;
447 case PIPE_FORMAT_Z24S8_UNORM:
448 packed |= s;
449 break;
450 case PIPE_FORMAT_S8_UNORM:
451 packed |= s;
452 break;
453 default:
454 break;
455 }
456
457 return packed;
458 }
459
460
461 /**
462 * Pack 4 ubytes into a 4-byte word
463 */
464 static INLINE unsigned
465 pack_ub4(ubyte b0, ubyte b1, ubyte b2, ubyte b3)
466 {
467 return ((((unsigned int)b0) << 0) |
468 (((unsigned int)b1) << 8) |
469 (((unsigned int)b2) << 16) |
470 (((unsigned int)b3) << 24));
471 }
472
473
474 /**
475 * Pack/convert 4 floats into one 4-byte word.
476 */
477 static INLINE unsigned
478 pack_ui32_float4(float a, float b, float c, float d)
479 {
480 return pack_ub4( float_to_ubyte(a),
481 float_to_ubyte(b),
482 float_to_ubyte(c),
483 float_to_ubyte(d) );
484 }
485
486
487
488 #endif /* U_PACK_COLOR_H */