Home | History | Annotate | Download | only in wgl
      1 /**************************************************************************
      2  *
      3  * Copyright 2008 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 #include "pipe/p_format.h"
     29 #include "pipe/p_defines.h"
     30 #include "pipe/p_screen.h"
     31 
     32 #include "util/u_format.h"
     33 #include "util/u_debug.h"
     34 #include "util/u_memory.h"
     35 
     36 #include "stw_icd.h"
     37 #include "stw_device.h"
     38 #include "stw_pixelformat.h"
     39 #include "stw_tls.h"
     40 
     41 
     42 struct stw_pf_color_info
     43 {
     44    enum pipe_format format;
     45    struct {
     46       unsigned char red;
     47       unsigned char green;
     48       unsigned char blue;
     49       unsigned char alpha;
     50    } bits;
     51    struct {
     52       unsigned char red;
     53       unsigned char green;
     54       unsigned char blue;
     55       unsigned char alpha;
     56    } shift;
     57 };
     58 
     59 struct stw_pf_depth_info
     60 {
     61    enum pipe_format format;
     62    struct {
     63       unsigned char depth;
     64       unsigned char stencil;
     65    } bits;
     66 };
     67 
     68 
     69 /* NOTE: order matters, since in otherwise equal circumstances the first
     70  * format listed will get chosen */
     71 
     72 static const struct stw_pf_color_info
     73 stw_pf_color[] = {
     74    /* no-alpha */
     75    { PIPE_FORMAT_B8G8R8X8_UNORM,    { 8,  8,  8,  0}, {16,  8,  0,  0} },
     76    { PIPE_FORMAT_X8R8G8B8_UNORM,    { 8,  8,  8,  0}, { 8, 16, 24,  0} },
     77    /* alpha */
     78    { PIPE_FORMAT_B8G8R8A8_UNORM,    { 8,  8,  8,  8}, {16,  8,  0, 24} },
     79    { PIPE_FORMAT_A8R8G8B8_UNORM,    { 8,  8,  8,  8}, { 8, 16, 24,  0} },
     80    /* shallow bit depths */
     81    { PIPE_FORMAT_B5G6R5_UNORM,      { 5,  6,  5,  0}, {11,  5,  0,  0} },
     82 #if 0
     83    { PIPE_FORMAT_R10G10B10A2_UNORM, {10, 10, 10,  2}, { 0, 10, 20, 30} },
     84 #endif
     85    { PIPE_FORMAT_B5G5R5A1_UNORM,    { 5,  5,  5,  1}, {10,  5,  0, 15} },
     86    { PIPE_FORMAT_B4G4R4A4_UNORM,    { 4,  4,  4,  4}, {16,  4,  0, 12} }
     87 };
     88 
     89 static const struct stw_pf_color_info
     90 stw_pf_color_extended[] = {
     91     { PIPE_FORMAT_R32G32B32A32_FLOAT, { 32,  32, 32,  32}, { 0,  32, 64, 96} }
     92 };
     93 
     94 static const struct stw_pf_depth_info
     95 stw_pf_depth_stencil[] = {
     96    /* pure depth */
     97    { PIPE_FORMAT_Z32_UNORM,   {32, 0} },
     98    { PIPE_FORMAT_X8Z24_UNORM, {24, 0} },
     99    { PIPE_FORMAT_Z24X8_UNORM, {24, 0} },
    100    { PIPE_FORMAT_Z16_UNORM,   {16, 0} },
    101    /* combined depth-stencil */
    102    { PIPE_FORMAT_Z24_UNORM_S8_UINT, {24, 8} },
    103    { PIPE_FORMAT_S8_UINT_Z24_UNORM, {24, 8} }
    104 };
    105 
    106 
    107 static const boolean
    108 stw_pf_doublebuffer[] = {
    109    FALSE,
    110    TRUE,
    111 };
    112 
    113 
    114 const unsigned
    115 stw_pf_multisample[] = {
    116    0,
    117    4,
    118    8,
    119    16
    120 };
    121 
    122 
    123 static void
    124 stw_pixelformat_add(
    125    struct stw_device *stw_dev,
    126    boolean extended,
    127    const struct stw_pf_color_info *color,
    128    const struct stw_pf_depth_info *depth,
    129    unsigned accum,
    130    boolean doublebuffer,
    131    unsigned samples )
    132 {
    133    struct stw_pixelformat_info *pfi;
    134 
    135    assert(stw_dev->pixelformat_extended_count < STW_MAX_PIXELFORMATS);
    136    if(stw_dev->pixelformat_extended_count >= STW_MAX_PIXELFORMATS)
    137       return;
    138 
    139    assert(util_format_get_component_bits(color->format, UTIL_FORMAT_COLORSPACE_RGB, 0) == color->bits.red);
    140    assert(util_format_get_component_bits(color->format, UTIL_FORMAT_COLORSPACE_RGB, 1) == color->bits.green);
    141    assert(util_format_get_component_bits(color->format, UTIL_FORMAT_COLORSPACE_RGB, 2) == color->bits.blue);
    142    assert(util_format_get_component_bits(color->format, UTIL_FORMAT_COLORSPACE_RGB, 3) == color->bits.alpha);
    143    assert(util_format_get_component_bits(depth->format, UTIL_FORMAT_COLORSPACE_ZS, 0) == depth->bits.depth);
    144    assert(util_format_get_component_bits(depth->format, UTIL_FORMAT_COLORSPACE_ZS, 1) == depth->bits.stencil);
    145 
    146    pfi = &stw_dev->pixelformats[stw_dev->pixelformat_extended_count];
    147 
    148    memset(pfi, 0, sizeof *pfi);
    149 
    150    pfi->pfd.nSize = sizeof pfi->pfd;
    151    pfi->pfd.nVersion = 1;
    152 
    153    pfi->pfd.dwFlags = PFD_SUPPORT_OPENGL;
    154 
    155    /* TODO: also support non-native pixel formats */
    156    if (!extended) {
    157       pfi->pfd.dwFlags |= PFD_DRAW_TO_WINDOW;
    158    }
    159 
    160    /* See http://www.opengl.org/pipeline/article/vol003_7/ */
    161    pfi->pfd.dwFlags |= PFD_SUPPORT_COMPOSITION;
    162 
    163    if (doublebuffer)
    164       pfi->pfd.dwFlags |= PFD_DOUBLEBUFFER | PFD_SWAP_EXCHANGE;
    165 
    166    pfi->pfd.iPixelType = PFD_TYPE_RGBA;
    167 
    168    pfi->pfd.cColorBits = color->bits.red + color->bits.green + color->bits.blue + color->bits.alpha;
    169    pfi->pfd.cRedBits = color->bits.red;
    170    pfi->pfd.cRedShift = color->shift.red;
    171    pfi->pfd.cGreenBits = color->bits.green;
    172    pfi->pfd.cGreenShift = color->shift.green;
    173    pfi->pfd.cBlueBits = color->bits.blue;
    174    pfi->pfd.cBlueShift = color->shift.blue;
    175    pfi->pfd.cAlphaBits = color->bits.alpha;
    176    pfi->pfd.cAlphaShift = color->shift.alpha;
    177    pfi->pfd.cAccumBits = 4*accum;
    178    pfi->pfd.cAccumRedBits = accum;
    179    pfi->pfd.cAccumGreenBits = accum;
    180    pfi->pfd.cAccumBlueBits = accum;
    181    pfi->pfd.cAccumAlphaBits = accum;
    182    pfi->pfd.cDepthBits = depth->bits.depth;
    183    pfi->pfd.cStencilBits = depth->bits.stencil;
    184    pfi->pfd.cAuxBuffers = 0;
    185    pfi->pfd.iLayerType = 0;
    186    pfi->pfd.bReserved = 0;
    187    pfi->pfd.dwLayerMask = 0;
    188    pfi->pfd.dwVisibleMask = 0;
    189    pfi->pfd.dwDamageMask = 0;
    190 
    191    /*
    192     * since state trackers can allocate depth/stencil/accum buffers, we provide
    193     * only color buffers here
    194     */
    195    pfi->stvis.buffer_mask = ST_ATTACHMENT_FRONT_LEFT_MASK;
    196    if (doublebuffer)
    197       pfi->stvis.buffer_mask |= ST_ATTACHMENT_BACK_LEFT_MASK;
    198 
    199    pfi->stvis.color_format = color->format;
    200    pfi->stvis.depth_stencil_format = depth->format;
    201 
    202    pfi->stvis.accum_format = (accum) ?
    203       PIPE_FORMAT_R16G16B16A16_SNORM : PIPE_FORMAT_NONE;
    204 
    205    pfi->stvis.samples = samples;
    206    pfi->stvis.render_buffer = ST_ATTACHMENT_INVALID;
    207 
    208    /* WGL_ARB_render_texture */
    209    if (color->bits.alpha)
    210       pfi->bindToTextureRGBA = TRUE;
    211    else
    212       pfi->bindToTextureRGB = TRUE;
    213 
    214    ++stw_dev->pixelformat_extended_count;
    215 
    216    if(!extended) {
    217       ++stw_dev->pixelformat_count;
    218       assert(stw_dev->pixelformat_count == stw_dev->pixelformat_extended_count);
    219    }
    220 }
    221 
    222 
    223 /**
    224  * Add the depth/stencil/accum/ms variants for a list of color formats.
    225  */
    226 static unsigned
    227 add_color_format_variants(const struct stw_pf_color_info *color_formats,
    228                           unsigned num_color_formats,
    229                           boolean extended)
    230 {
    231    struct pipe_screen *screen = stw_dev->screen;
    232    unsigned cfmt, ms, db, ds, acc;
    233    unsigned bind_flags = PIPE_BIND_RENDER_TARGET;
    234    unsigned num_added = 0;
    235    int force_samples = 0;
    236 
    237    /* Since GLUT for Windows doesn't support MSAA we have an env var
    238     * to force all pixel formats to have a particular number of samples.
    239     */
    240    {
    241       const char *samples= getenv("SVGA_FORCE_MSAA");
    242       if (samples)
    243          force_samples = atoi(samples);
    244    }
    245 
    246    if (!extended) {
    247       bind_flags |= PIPE_BIND_DISPLAY_TARGET;
    248    }
    249 
    250    for (ms = 0; ms < ARRAY_SIZE(stw_pf_multisample); ms++) {
    251       unsigned samples = stw_pf_multisample[ms];
    252 
    253       if (force_samples && samples != force_samples)
    254          continue;
    255 
    256       for (cfmt = 0; cfmt < num_color_formats; cfmt++) {
    257          if (!screen->is_format_supported(screen, color_formats[cfmt].format,
    258                                           PIPE_TEXTURE_2D, samples,
    259                                           bind_flags)) {
    260             continue;
    261          }
    262 
    263          for (db = 0; db < ARRAY_SIZE(stw_pf_doublebuffer); db++) {
    264             unsigned doublebuffer = stw_pf_doublebuffer[db];
    265 
    266             for (ds = 0; ds < ARRAY_SIZE(stw_pf_depth_stencil); ds++) {
    267                const struct stw_pf_depth_info *depth = &stw_pf_depth_stencil[ds];
    268 
    269                if (!screen->is_format_supported(screen, depth->format,
    270                                                 PIPE_TEXTURE_2D, samples,
    271                                                 PIPE_BIND_DEPTH_STENCIL)) {
    272                   continue;
    273                }
    274 
    275                for (acc = 0; acc < 2; acc++) {
    276                   stw_pixelformat_add(stw_dev, extended, &color_formats[cfmt],
    277                                       depth,
    278                                       acc * 16, doublebuffer, samples);
    279                   num_added++;
    280                }
    281             }
    282          }
    283       }
    284    }
    285 
    286    return num_added;
    287 }
    288 
    289 
    290 void
    291 stw_pixelformat_init( void )
    292 {
    293    unsigned num_formats;
    294 
    295    assert( !stw_dev->pixelformat_count );
    296    assert( !stw_dev->pixelformat_extended_count );
    297 
    298    /* normal, displayable formats */
    299    num_formats = add_color_format_variants(stw_pf_color,
    300                                            ARRAY_SIZE(stw_pf_color), FALSE);
    301    assert(num_formats > 0);
    302 
    303    /* extended, pbuffer-only formats */
    304    add_color_format_variants(stw_pf_color_extended,
    305                              ARRAY_SIZE(stw_pf_color_extended), TRUE);
    306 
    307    assert( stw_dev->pixelformat_count <= stw_dev->pixelformat_extended_count );
    308    assert( stw_dev->pixelformat_extended_count <= STW_MAX_PIXELFORMATS );
    309 }
    310 
    311 uint
    312 stw_pixelformat_get_count( void )
    313 {
    314    return stw_dev->pixelformat_count;
    315 }
    316 
    317 uint
    318 stw_pixelformat_get_extended_count( void )
    319 {
    320    return stw_dev->pixelformat_extended_count;
    321 }
    322 
    323 const struct stw_pixelformat_info *
    324 stw_pixelformat_get_info( int iPixelFormat )
    325 {
    326    unsigned index;
    327 
    328    if (iPixelFormat <= 0) {
    329       return NULL;
    330    }
    331 
    332    index = iPixelFormat - 1;
    333    if (index >= stw_dev->pixelformat_extended_count) {
    334       return NULL;
    335    }
    336 
    337    return &stw_dev->pixelformats[index];
    338 }
    339 
    340 
    341 LONG APIENTRY
    342 DrvDescribePixelFormat(
    343    HDC hdc,
    344    INT iPixelFormat,
    345    ULONG cjpfd,
    346    PIXELFORMATDESCRIPTOR *ppfd )
    347 {
    348    uint count;
    349    const struct stw_pixelformat_info *pfi;
    350 
    351    (void) hdc;
    352 
    353    if (!stw_dev)
    354       return 0;
    355 
    356    count = stw_pixelformat_get_count();
    357 
    358    if (ppfd == NULL)
    359       return count;
    360    if (cjpfd != sizeof( PIXELFORMATDESCRIPTOR ))
    361       return 0;
    362 
    363    pfi = stw_pixelformat_get_info( iPixelFormat );
    364    if (!pfi) {
    365       return 0;
    366    }
    367 
    368    memcpy(ppfd, &pfi->pfd, sizeof( PIXELFORMATDESCRIPTOR ));
    369 
    370    return count;
    371 }
    372 
    373 BOOL APIENTRY
    374 DrvDescribeLayerPlane(
    375    HDC hdc,
    376    INT iPixelFormat,
    377    INT iLayerPlane,
    378    UINT nBytes,
    379    LPLAYERPLANEDESCRIPTOR plpd )
    380 {
    381    assert(0);
    382    return FALSE;
    383 }
    384 
    385 int APIENTRY
    386 DrvGetLayerPaletteEntries(
    387    HDC hdc,
    388    INT iLayerPlane,
    389    INT iStart,
    390    INT cEntries,
    391    COLORREF *pcr )
    392 {
    393    assert(0);
    394    return 0;
    395 }
    396 
    397 int APIENTRY
    398 DrvSetLayerPaletteEntries(
    399    HDC hdc,
    400    INT iLayerPlane,
    401    INT iStart,
    402    INT cEntries,
    403    CONST COLORREF *pcr )
    404 {
    405    assert(0);
    406    return 0;
    407 }
    408 
    409 BOOL APIENTRY
    410 DrvRealizeLayerPalette(
    411    HDC hdc,
    412    INT iLayerPlane,
    413    BOOL bRealize )
    414 {
    415    assert(0);
    416    return FALSE;
    417 }
    418 
    419 /* Only used by the wgl code, but have it here to avoid exporting the
    420  * pixelformat.h functionality.
    421  */
    422 int stw_pixelformat_choose( HDC hdc,
    423                             CONST PIXELFORMATDESCRIPTOR *ppfd )
    424 {
    425    uint count;
    426    uint index;
    427    uint bestindex;
    428    uint bestdelta;
    429 
    430    (void) hdc;
    431 
    432    count = stw_pixelformat_get_extended_count();
    433    bestindex = 0;
    434    bestdelta = ~0U;
    435 
    436    for (index = 1; index <= count; index++) {
    437       uint delta = 0;
    438       const struct stw_pixelformat_info *pfi = stw_pixelformat_get_info( index );
    439 
    440       if (!(ppfd->dwFlags & PFD_DOUBLEBUFFER_DONTCARE) &&
    441           !!(ppfd->dwFlags & PFD_DOUBLEBUFFER) !=
    442           !!(pfi->pfd.dwFlags & PFD_DOUBLEBUFFER))
    443          continue;
    444 
    445       /* FIXME: Take in account individual channel bits */
    446       if (ppfd->cColorBits != pfi->pfd.cColorBits)
    447          delta += 8;
    448 
    449       if (ppfd->cDepthBits != pfi->pfd.cDepthBits)
    450          delta += 4;
    451 
    452       if (ppfd->cStencilBits != pfi->pfd.cStencilBits)
    453          delta += 2;
    454 
    455       if (ppfd->cAlphaBits != pfi->pfd.cAlphaBits)
    456          delta++;
    457 
    458       if (delta < bestdelta) {
    459          bestindex = index;
    460          bestdelta = delta;
    461          if (bestdelta == 0)
    462             break;
    463       }
    464    }
    465 
    466    return bestindex;
    467 }
    468