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