Home | History | Annotate | Download | only in util
      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  */
     51 union 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  */
     62 static INLINE void
     63 util_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  */
    163 static INLINE void
    164 util_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  */
    333 static INLINE void
    334 util_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  */
    437 static INLINE uint32_t
    438 util_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 
    462 static INLINE uint64_t
    463 util_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 
    474 static INLINE uint32_t
    475 util_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 
    497 static INLINE uint64_t
    498 util_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  */
    516 static INLINE uint32_t
    517 util_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 
    558 static INLINE uint64_t
    559 util_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  */
    580 static INLINE uint32_t
    581 util_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 
    603 static INLINE uint64_t
    604 util_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  */
    624 static INLINE unsigned
    625 pack_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  */
    637 static INLINE unsigned
    638 pack_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