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_debug.h"
41#include "util/u_format.h"
42#include "util/u_math.h"
43
44
45/**
46 * Helper union for packing pixel values.
47 * Will often contain values in formats which are too complex to be described
48 * in simple terms, hence might just effectively contain a number of bytes.
49 * Must be big enough to hold data for all formats (currently 256 bits).
50 */
51union util_color {
52   ubyte ub;
53   ushort us;
54   uint ui;
55   float f[4];
56   double d[4];
57};
58
59/**
60 * Pack ubyte R,G,B,A into dest pixel.
61 */
62static INLINE void
63util_pack_color_ub(ubyte r, ubyte g, ubyte b, ubyte a,
64                   enum pipe_format format, union util_color *uc)
65{
66   switch (format) {
67   case PIPE_FORMAT_A8B8G8R8_UNORM:
68      {
69         uc->ui = (r << 24) | (g << 16) | (b << 8) | a;
70      }
71      return;
72   case PIPE_FORMAT_X8B8G8R8_UNORM:
73      {
74         uc->ui = (r << 24) | (g << 16) | (b << 8) | 0xff;
75      }
76      return;
77   case PIPE_FORMAT_B8G8R8A8_UNORM:
78      {
79         uc->ui = (a << 24) | (r << 16) | (g << 8) | b;
80      }
81      return;
82   case PIPE_FORMAT_B8G8R8X8_UNORM:
83      {
84         uc->ui = (0xff << 24) | (r << 16) | (g << 8) | b;
85      }
86      return;
87   case PIPE_FORMAT_A8R8G8B8_UNORM:
88      {
89         uc->ui = (b << 24) | (g << 16) | (r << 8) | a;
90      }
91      return;
92   case PIPE_FORMAT_X8R8G8B8_UNORM:
93      {
94         uc->ui = (b << 24) | (g << 16) | (r << 8) | 0xff;
95      }
96      return;
97   case PIPE_FORMAT_B5G6R5_UNORM:
98      {
99         uc->us = ((r & 0xf8) << 8) | ((g & 0xfc) << 3) | (b >> 3);
100      }
101      return;
102   case PIPE_FORMAT_B5G5R5X1_UNORM:
103      {
104         uc->us = ((0x80) << 8) | ((r & 0xf8) << 7) | ((g & 0xf8) << 2) | (b >> 3);
105      }
106      return;
107   case PIPE_FORMAT_B5G5R5A1_UNORM:
108      {
109         uc->us = ((a & 0x80) << 8) | ((r & 0xf8) << 7) | ((g & 0xf8) << 2) | (b >> 3);
110      }
111      return;
112   case PIPE_FORMAT_B4G4R4A4_UNORM:
113      {
114         uc->us = ((a & 0xf0) << 8) | ((r & 0xf0) << 4) | ((g & 0xf0) << 0) | (b >> 4);
115      }
116      return;
117   case PIPE_FORMAT_A8_UNORM:
118      {
119         uc->ub = a;
120      }
121      return;
122   case PIPE_FORMAT_L8_UNORM:
123   case PIPE_FORMAT_I8_UNORM:
124      {
125         uc->ub = r;
126      }
127      return;
128   case PIPE_FORMAT_R32G32B32A32_FLOAT:
129      {
130         uc->f[0] = (float)r / 255.0f;
131         uc->f[1] = (float)g / 255.0f;
132         uc->f[2] = (float)b / 255.0f;
133         uc->f[3] = (float)a / 255.0f;
134      }
135      return;
136   case PIPE_FORMAT_R32G32B32_FLOAT:
137      {
138         uc->f[0] = (float)r / 255.0f;
139         uc->f[1] = (float)g / 255.0f;
140         uc->f[2] = (float)b / 255.0f;
141      }
142      return;
143
144   /* Handle other cases with a generic function.
145    */
146   default:
147      {
148         ubyte src[4];
149
150         src[0] = r;
151         src[1] = g;
152         src[2] = b;
153         src[3] = a;
154         util_format_write_4ub(format, src, 0, uc, 0, 0, 0, 1, 1);
155      }
156   }
157}
158
159
160/**
161 * Unpack RGBA from a packed pixel, returning values as ubytes in [0,255].
162 */
163static INLINE void
164util_unpack_color_ub(enum pipe_format format, union util_color *uc,
165                     ubyte *r, ubyte *g, ubyte *b, ubyte *a)
166{
167   switch (format) {
168   case PIPE_FORMAT_A8B8G8R8_UNORM:
169      {
170         uint p = uc->ui;
171         *r = (ubyte) ((p >> 24) & 0xff);
172         *g = (ubyte) ((p >> 16) & 0xff);
173         *b = (ubyte) ((p >>  8) & 0xff);
174         *a = (ubyte) ((p >>  0) & 0xff);
175      }
176      return;
177   case PIPE_FORMAT_X8B8G8R8_UNORM:
178      {
179         uint p = uc->ui;
180         *r = (ubyte) ((p >> 24) & 0xff);
181         *g = (ubyte) ((p >> 16) & 0xff);
182         *b = (ubyte) ((p >>  8) & 0xff);
183         *a = (ubyte) 0xff;
184      }
185      return;
186   case PIPE_FORMAT_B8G8R8A8_UNORM:
187      {
188         uint p = uc->ui;
189         *r = (ubyte) ((p >> 16) & 0xff);
190         *g = (ubyte) ((p >>  8) & 0xff);
191         *b = (ubyte) ((p >>  0) & 0xff);
192         *a = (ubyte) ((p >> 24) & 0xff);
193      }
194      return;
195   case PIPE_FORMAT_B8G8R8X8_UNORM:
196      {
197         uint p = uc->ui;
198         *r = (ubyte) ((p >> 16) & 0xff);
199         *g = (ubyte) ((p >>  8) & 0xff);
200         *b = (ubyte) ((p >>  0) & 0xff);
201         *a = (ubyte) 0xff;
202      }
203      return;
204   case PIPE_FORMAT_A8R8G8B8_UNORM:
205      {
206         uint p = uc->ui;
207         *r = (ubyte) ((p >>  8) & 0xff);
208         *g = (ubyte) ((p >> 16) & 0xff);
209         *b = (ubyte) ((p >> 24) & 0xff);
210         *a = (ubyte) ((p >>  0) & 0xff);
211      }
212      return;
213   case PIPE_FORMAT_X8R8G8B8_UNORM:
214      {
215         uint p = uc->ui;
216         *r = (ubyte) ((p >>  8) & 0xff);
217         *g = (ubyte) ((p >> 16) & 0xff);
218         *b = (ubyte) ((p >> 24) & 0xff);
219         *a = (ubyte) 0xff;
220      }
221      return;
222   case PIPE_FORMAT_B5G6R5_UNORM:
223      {
224         ushort p = uc->us;
225         *r = (ubyte) (((p >> 8) & 0xf8) | ((p >> 13) & 0x7));
226         *g = (ubyte) (((p >> 3) & 0xfc) | ((p >>  9) & 0x3));
227         *b = (ubyte) (((p << 3) & 0xf8) | ((p >>  2) & 0x7));
228         *a = (ubyte) 0xff;
229      }
230      return;
231   case PIPE_FORMAT_B5G5R5X1_UNORM:
232      {
233         ushort p = uc->us;
234         *r = (ubyte) (((p >>  7) & 0xf8) | ((p >> 12) & 0x7));
235         *g = (ubyte) (((p >>  2) & 0xf8) | ((p >>  7) & 0x7));
236         *b = (ubyte) (((p <<  3) & 0xf8) | ((p >>  2) & 0x7));
237         *a = (ubyte) 0xff;
238      }
239      return;
240   case PIPE_FORMAT_B5G5R5A1_UNORM:
241      {
242         ushort p = uc->us;
243         *r = (ubyte) (((p >>  7) & 0xf8) | ((p >> 12) & 0x7));
244         *g = (ubyte) (((p >>  2) & 0xf8) | ((p >>  7) & 0x7));
245         *b = (ubyte) (((p <<  3) & 0xf8) | ((p >>  2) & 0x7));
246         *a = (ubyte) (0xff * (p >> 15));
247      }
248      return;
249   case PIPE_FORMAT_B4G4R4A4_UNORM:
250      {
251         ushort p = uc->us;
252         *r = (ubyte) (((p >> 4) & 0xf0) | ((p >>  8) & 0xf));
253         *g = (ubyte) (((p >> 0) & 0xf0) | ((p >>  4) & 0xf));
254         *b = (ubyte) (((p << 4) & 0xf0) | ((p >>  0) & 0xf));
255         *a = (ubyte) (((p >> 8) & 0xf0) | ((p >> 12) & 0xf));
256      }
257      return;
258   case PIPE_FORMAT_A8_UNORM:
259      {
260         ubyte p = uc->ub;
261         *r = *g = *b = (ubyte) 0xff;
262         *a = p;
263      }
264      return;
265   case PIPE_FORMAT_L8_UNORM:
266      {
267         ubyte p = uc->ub;
268         *r = *g = *b = p;
269         *a = (ubyte) 0xff;
270      }
271      return;
272   case PIPE_FORMAT_I8_UNORM:
273      {
274         ubyte p = uc->ub;
275         *r = *g = *b = *a = p;
276      }
277      return;
278   case PIPE_FORMAT_R32G32B32A32_FLOAT:
279      {
280         const float *p = &uc->f[0];
281         *r = float_to_ubyte(p[0]);
282         *g = float_to_ubyte(p[1]);
283         *b = float_to_ubyte(p[2]);
284         *a = float_to_ubyte(p[3]);
285      }
286      return;
287   case PIPE_FORMAT_R32G32B32_FLOAT:
288      {
289         const float *p = &uc->f[0];
290         *r = float_to_ubyte(p[0]);
291         *g = float_to_ubyte(p[1]);
292         *b = float_to_ubyte(p[2]);
293         *a = (ubyte) 0xff;
294      }
295      return;
296
297   case PIPE_FORMAT_R32G32_FLOAT:
298      {
299         const float *p = &uc->f[0];
300         *r = float_to_ubyte(p[0]);
301         *g = float_to_ubyte(p[1]);
302         *b = *a = (ubyte) 0xff;
303      }
304      return;
305
306   case PIPE_FORMAT_R32_FLOAT:
307      {
308         const float *p = &uc->f[0];
309         *r = float_to_ubyte(p[0]);
310         *g = *b = *a = (ubyte) 0xff;
311      }
312      return;
313
314   /* Handle other cases with a generic function.
315    */
316   default:
317      {
318         ubyte dst[4];
319
320         util_format_read_4ub(format, dst, 0, uc, 0, 0, 0, 1, 1);
321         *r = dst[0];
322         *g = dst[1];
323         *b = dst[2];
324         *a = dst[3];
325      }
326   }
327}
328
329
330/**
331 * Note rgba outside [0,1] will be clamped for int pixel formats.
332 */
333static INLINE void
334util_pack_color(const float rgba[4], enum pipe_format format, union util_color *uc)
335{
336   ubyte r = 0;
337   ubyte g = 0;
338   ubyte b = 0;
339   ubyte a = 0;
340
341   if (util_format_get_component_bits(format, UTIL_FORMAT_COLORSPACE_RGB, 0) <= 8) {
342      /* format uses 8-bit components or less */
343      r = float_to_ubyte(rgba[0]);
344      g = float_to_ubyte(rgba[1]);
345      b = float_to_ubyte(rgba[2]);
346      a = float_to_ubyte(rgba[3]);
347   }
348
349   switch (format) {
350   case PIPE_FORMAT_A8B8G8R8_UNORM:
351      {
352         uc->ui = (r << 24) | (g << 16) | (b << 8) | a;
353      }
354      return;
355   case PIPE_FORMAT_X8B8G8R8_UNORM:
356      {
357         uc->ui = (r << 24) | (g << 16) | (b << 8) | 0xff;
358      }
359      return;
360   case PIPE_FORMAT_B8G8R8A8_UNORM:
361      {
362         uc->ui = (a << 24) | (r << 16) | (g << 8) | b;
363      }
364      return;
365   case PIPE_FORMAT_B8G8R8X8_UNORM:
366      {
367         uc->ui = (0xff << 24) | (r << 16) | (g << 8) | b;
368      }
369      return;
370   case PIPE_FORMAT_A8R8G8B8_UNORM:
371      {
372         uc->ui = (b << 24) | (g << 16) | (r << 8) | a;
373      }
374      return;
375   case PIPE_FORMAT_X8R8G8B8_UNORM:
376      {
377         uc->ui = (b << 24) | (g << 16) | (r << 8) | 0xff;
378      }
379      return;
380   case PIPE_FORMAT_B5G6R5_UNORM:
381      {
382         uc->us = ((r & 0xf8) << 8) | ((g & 0xfc) << 3) | (b >> 3);
383      }
384      return;
385   case PIPE_FORMAT_B5G5R5X1_UNORM:
386      {
387         uc->us = ((0x80) << 8) | ((r & 0xf8) << 7) | ((g & 0xf8) << 2) | (b >> 3);
388      }
389      return;
390   case PIPE_FORMAT_B5G5R5A1_UNORM:
391      {
392         uc->us = ((a & 0x80) << 8) | ((r & 0xf8) << 7) | ((g & 0xf8) << 2) | (b >> 3);
393      }
394      return;
395   case PIPE_FORMAT_B4G4R4A4_UNORM:
396      {
397         uc->us = ((a & 0xf0) << 8) | ((r & 0xf0) << 4) | ((g & 0xf0) << 0) | (b >> 4);
398      }
399      return;
400   case PIPE_FORMAT_A8_UNORM:
401      {
402         uc->ub = a;
403      }
404      return;
405   case PIPE_FORMAT_L8_UNORM:
406   case PIPE_FORMAT_I8_UNORM:
407      {
408         uc->ub = r;
409      }
410      return;
411   case PIPE_FORMAT_R32G32B32A32_FLOAT:
412      {
413         uc->f[0] = rgba[0];
414         uc->f[1] = rgba[1];
415         uc->f[2] = rgba[2];
416         uc->f[3] = rgba[3];
417      }
418      return;
419   case PIPE_FORMAT_R32G32B32_FLOAT:
420      {
421         uc->f[0] = rgba[0];
422         uc->f[1] = rgba[1];
423         uc->f[2] = rgba[2];
424      }
425      return;
426
427   /* Handle other cases with a generic function.
428    */
429   default:
430      util_format_write_4f(format, rgba, 0, uc, 0, 0, 0, 1, 1);
431   }
432}
433
434/* Integer versions of util_pack_z and util_pack_z_stencil - useful for
435 * constructing clear masks.
436 */
437static INLINE uint32_t
438util_pack_mask_z(enum pipe_format format, uint32_t z)
439{
440   switch (format) {
441   case PIPE_FORMAT_Z16_UNORM:
442      return z & 0xffff;
443   case PIPE_FORMAT_Z32_UNORM:
444   case PIPE_FORMAT_Z32_FLOAT:
445      return z;
446   case PIPE_FORMAT_Z24_UNORM_S8_UINT:
447   case PIPE_FORMAT_Z24X8_UNORM:
448      return z & 0xffffff;
449   case PIPE_FORMAT_S8_UINT_Z24_UNORM:
450   case PIPE_FORMAT_X8Z24_UNORM:
451      return (z & 0xffffff) << 8;
452   case PIPE_FORMAT_S8_UINT:
453      return 0;
454   default:
455      debug_print_format("gallium: unhandled format in util_pack_mask_z()", format);
456      assert(0);
457      return 0;
458   }
459}
460
461
462static INLINE uint64_t
463util_pack64_mask_z(enum pipe_format format, uint32_t z)
464{
465   switch (format) {
466   case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT:
467      return z;
468   default:
469      return util_pack_mask_z(format, z);
470   }
471}
472
473
474static INLINE uint32_t
475util_pack_mask_z_stencil(enum pipe_format format, uint32_t z, uint8_t s)
476{
477   uint32_t packed = util_pack_mask_z(format, z);
478
479   switch (format) {
480   case PIPE_FORMAT_Z24_UNORM_S8_UINT:
481      packed |= (uint32_t)s << 24;
482      break;
483   case PIPE_FORMAT_S8_UINT_Z24_UNORM:
484      packed |= s;
485      break;
486   case PIPE_FORMAT_S8_UINT:
487      packed |= s;
488      break;
489   default:
490      break;
491   }
492
493   return packed;
494}
495
496
497static INLINE uint64_t
498util_pack64_mask_z_stencil(enum pipe_format format, uint32_t z, uint8_t s)
499{
500   uint64_t packed;
501
502   switch (format) {
503   case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT:
504      packed = util_pack64_mask_z(format, z);
505      packed |= (uint64_t)s << 32ull;
506      return packed;
507   default:
508      return util_pack_mask_z_stencil(format, z, s);
509   }
510}
511
512
513/**
514 * Note: it's assumed that z is in [0,1]
515 */
516static INLINE uint32_t
517util_pack_z(enum pipe_format format, double z)
518{
519   union fi fui;
520
521   if (z == 0.0)
522      return 0;
523
524   switch (format) {
525   case PIPE_FORMAT_Z16_UNORM:
526      if (z == 1.0)
527         return 0xffff;
528      return (uint32_t) (z * 0xffff);
529   case PIPE_FORMAT_Z32_UNORM:
530      /* special-case to avoid overflow */
531      if (z == 1.0)
532         return 0xffffffff;
533      return (uint32_t) (z * 0xffffffff);
534   case PIPE_FORMAT_Z32_FLOAT:
535      fui.f = (float)z;
536      return fui.ui;
537   case PIPE_FORMAT_Z24_UNORM_S8_UINT:
538   case PIPE_FORMAT_Z24X8_UNORM:
539      if (z == 1.0)
540         return 0xffffff;
541      return (uint32_t) (z * 0xffffff);
542   case PIPE_FORMAT_S8_UINT_Z24_UNORM:
543   case PIPE_FORMAT_X8Z24_UNORM:
544      if (z == 1.0)
545         return 0xffffff00;
546      return ((uint32_t) (z * 0xffffff)) << 8;
547   case PIPE_FORMAT_S8_UINT:
548      /* this case can get it via util_pack_z_stencil() */
549      return 0;
550   default:
551      debug_print_format("gallium: unhandled format in util_pack_z()", format);
552      assert(0);
553      return 0;
554   }
555}
556
557
558static INLINE uint64_t
559util_pack64_z(enum pipe_format format, double z)
560{
561   union fi fui;
562
563   if (z == 0)
564      return 0;
565
566   switch (format) {
567   case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT:
568      fui.f = (float)z;
569      return fui.ui;
570   default:
571      return util_pack_z(format, z);
572   }
573}
574
575
576/**
577 * Pack Z and/or stencil values into a 32-bit value described by format.
578 * Note: it's assumed that z is in [0,1] and s in [0,255]
579 */
580static INLINE uint32_t
581util_pack_z_stencil(enum pipe_format format, double z, uint8_t s)
582{
583   uint32_t packed = util_pack_z(format, z);
584
585   switch (format) {
586   case PIPE_FORMAT_Z24_UNORM_S8_UINT:
587      packed |= (uint32_t)s << 24;
588      break;
589   case PIPE_FORMAT_S8_UINT_Z24_UNORM:
590      packed |= s;
591      break;
592   case PIPE_FORMAT_S8_UINT:
593      packed |= s;
594      break;
595   default:
596      break;
597   }
598
599   return packed;
600}
601
602
603static INLINE uint64_t
604util_pack64_z_stencil(enum pipe_format format, double z, uint8_t s)
605{
606   uint64_t packed;
607
608   switch (format) {
609   case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT:
610      packed = util_pack64_z(format, z);
611      packed |= (uint64_t)s << 32ull;
612      break;
613   default:
614      return util_pack_z_stencil(format, z, s);
615   }
616
617   return packed;
618}
619
620
621/**
622 * Pack 4 ubytes into a 4-byte word
623 */
624static INLINE unsigned
625pack_ub4(ubyte b0, ubyte b1, ubyte b2, ubyte b3)
626{
627   return ((((unsigned int)b0) << 0) |
628	   (((unsigned int)b1) << 8) |
629	   (((unsigned int)b2) << 16) |
630	   (((unsigned int)b3) << 24));
631}
632
633
634/**
635 * Pack/convert 4 floats into one 4-byte word.
636 */
637static INLINE unsigned
638pack_ui32_float4(float a, float b, float c, float d)
639{
640   return pack_ub4( float_to_ubyte(a),
641		    float_to_ubyte(b),
642		    float_to_ubyte(c),
643		    float_to_ubyte(d) );
644}
645
646
647
648#endif /* U_PACK_COLOR_H */
649