Home | History | Annotate | Download | only in gdi
      1 /*
      2  * Mesa 3-D graphics library
      3  * Version:  7.9
      4  *
      5  * Copyright (C) 2010 LunarG Inc.
      6  *
      7  * Permission is hereby granted, free of charge, to any person obtaining a
      8  * copy of this software and associated documentation files (the "Software"),
      9  * to deal in the Software without restriction, including without limitation
     10  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     11  * and/or sell copies of the Software, and to permit persons to whom the
     12  * Software is furnished to do so, subject to the following conditions:
     13  *
     14  * The above copyright notice and this permission notice shall be included
     15  * in all copies or substantial portions of the Software.
     16  *
     17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     20  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     22  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
     23  * DEALINGS IN THE SOFTWARE.
     24  *
     25  * Authors:
     26  *    Chia-I Wu <olv (at) lunarg.com>
     27  */
     28 
     29 #include <windows.h>
     30 
     31 #include "pipe/p_compiler.h"
     32 #include "util/u_memory.h"
     33 #include "util/u_format.h"
     34 #include "util/u_inlines.h"
     35 #include "gdi/gdi_sw_winsys.h"
     36 
     37 #include "common/native_helper.h"
     38 #include "common/native.h"
     39 
     40 struct gdi_display {
     41    struct native_display base;
     42 
     43    HDC hDC;
     44    const struct native_event_handler *event_handler;
     45 
     46    struct native_config *configs;
     47    int num_configs;
     48 };
     49 
     50 struct gdi_surface {
     51    struct native_surface base;
     52 
     53    HWND hWnd;
     54    enum pipe_format color_format;
     55 
     56    struct gdi_display *gdpy;
     57 
     58    unsigned int server_stamp;
     59    unsigned int client_stamp;
     60 
     61    struct resource_surface *rsurf;
     62 };
     63 
     64 static INLINE struct gdi_display *
     65 gdi_display(const struct native_display *ndpy)
     66 {
     67    return (struct gdi_display *) ndpy;
     68 }
     69 
     70 static INLINE struct gdi_surface *
     71 gdi_surface(const struct native_surface *nsurf)
     72 {
     73    return (struct gdi_surface *) nsurf;
     74 }
     75 
     76 /**
     77  * Update the geometry of the surface.  This is a slow functions.
     78  */
     79 static void
     80 gdi_surface_update_geometry(struct native_surface *nsurf)
     81 {
     82    struct gdi_surface *gsurf = gdi_surface(nsurf);
     83    RECT rect;
     84    uint w, h;
     85 
     86    GetClientRect(gsurf->hWnd, &rect);
     87    w = rect.right - rect.left;
     88    h = rect.bottom - rect.top;
     89 
     90    if (resource_surface_set_size(gsurf->rsurf, w, h))
     91       gsurf->server_stamp++;
     92 }
     93 
     94 /**
     95  * Update the buffers of the surface.
     96  */
     97 static boolean
     98 gdi_surface_update_buffers(struct native_surface *nsurf, uint buffer_mask)
     99 {
    100    struct gdi_surface *gsurf = gdi_surface(nsurf);
    101 
    102    if (gsurf->client_stamp != gsurf->server_stamp) {
    103       gdi_surface_update_geometry(&gsurf->base);
    104       gsurf->client_stamp = gsurf->server_stamp;
    105    }
    106 
    107    return resource_surface_add_resources(gsurf->rsurf, buffer_mask);
    108 }
    109 
    110 /**
    111  * Emulate an invalidate event.
    112  */
    113 static void
    114 gdi_surface_invalidate(struct native_surface *nsurf)
    115 {
    116    struct gdi_surface *gsurf = gdi_surface(nsurf);
    117    struct gdi_display *gdpy = gsurf->gdpy;
    118 
    119    gsurf->server_stamp++;
    120    gdpy->event_handler->invalid_surface(&gdpy->base,
    121          &gsurf->base, gsurf->server_stamp);
    122 }
    123 
    124 static boolean
    125 gdi_surface_flush_frontbuffer(struct native_surface *nsurf)
    126 {
    127    struct gdi_surface *gsurf = gdi_surface(nsurf);
    128    HDC hDC;
    129    boolean ret;
    130 
    131    hDC = GetDC(gsurf->hWnd);
    132    ret = resource_surface_present(gsurf->rsurf,
    133          NATIVE_ATTACHMENT_FRONT_LEFT, (void *) hDC);
    134    ReleaseDC(gsurf->hWnd, hDC);
    135 
    136    /* force buffers to be updated in next validation call */
    137    gdi_surface_invalidate(&gsurf->base);
    138 
    139    return ret;
    140 }
    141 
    142 static boolean
    143 gdi_surface_swap_buffers(struct native_surface *nsurf)
    144 {
    145    struct gdi_surface *gsurf = gdi_surface(nsurf);
    146    HDC hDC;
    147    boolean ret;
    148 
    149    hDC = GetDC(gsurf->hWnd);
    150    ret = resource_surface_present(gsurf->rsurf,
    151          NATIVE_ATTACHMENT_BACK_LEFT, (void *) hDC);
    152    ReleaseDC(gsurf->hWnd, hDC);
    153 
    154    resource_surface_swap_buffers(gsurf->rsurf,
    155          NATIVE_ATTACHMENT_FRONT_LEFT, NATIVE_ATTACHMENT_BACK_LEFT, TRUE);
    156    /* the front/back buffers have been swapped */
    157    gdi_surface_invalidate(&gsurf->base);
    158 
    159    return ret;
    160 }
    161 
    162 static boolean
    163 gdi_surface_present(struct native_surface *nsurf,
    164                     const struct native_present_control *ctrl)
    165 {
    166    boolean ret;
    167 
    168    if (ctrl->preserve || ctrl->swap_interval)
    169       return FALSE;
    170 
    171    switch (ctrl->natt) {
    172    case NATIVE_ATTACHMENT_FRONT_LEFT:
    173       ret = gdi_surface_flush_frontbuffer(nsurf);
    174       break;
    175    case NATIVE_ATTACHMENT_BACK_LEFT:
    176       ret = gdi_surface_swap_buffers(nsurf);
    177       break;
    178    default:
    179       ret = FALSE;
    180       break;
    181    }
    182 
    183    return ret;
    184 }
    185 
    186 static boolean
    187 gdi_surface_validate(struct native_surface *nsurf, uint attachment_mask,
    188                         unsigned int *seq_num, struct pipe_resource **textures,
    189                         int *width, int *height)
    190 {
    191    struct gdi_surface *gsurf = gdi_surface(nsurf);
    192    uint w, h;
    193 
    194    if (!gdi_surface_update_buffers(&gsurf->base, attachment_mask))
    195       return FALSE;
    196 
    197    if (seq_num)
    198       *seq_num = gsurf->client_stamp;
    199 
    200    if (textures)
    201       resource_surface_get_resources(gsurf->rsurf, textures, attachment_mask);
    202 
    203    resource_surface_get_size(gsurf->rsurf, &w, &h);
    204    if (width)
    205       *width = w;
    206    if (height)
    207       *height = h;
    208 
    209    return TRUE;
    210 }
    211 
    212 static void
    213 gdi_surface_wait(struct native_surface *nsurf)
    214 {
    215    /* no-op */
    216 }
    217 
    218 static void
    219 gdi_surface_destroy(struct native_surface *nsurf)
    220 {
    221    struct gdi_surface *gsurf = gdi_surface(nsurf);
    222 
    223    resource_surface_destroy(gsurf->rsurf);
    224    FREE(gsurf);
    225 }
    226 
    227 static struct native_surface *
    228 gdi_display_create_window_surface(struct native_display *ndpy,
    229                                   EGLNativeWindowType win,
    230                                   const struct native_config *nconf)
    231 {
    232    struct gdi_display *gdpy = gdi_display(ndpy);
    233    struct gdi_surface *gsurf;
    234 
    235    gsurf = CALLOC_STRUCT(gdi_surface);
    236    if (!gsurf)
    237       return NULL;
    238 
    239    gsurf->gdpy = gdpy;
    240    gsurf->color_format = nconf->color_format;
    241    gsurf->hWnd = (HWND) win;
    242 
    243    gsurf->rsurf = resource_surface_create(gdpy->base.screen,
    244          gsurf->color_format,
    245          PIPE_BIND_RENDER_TARGET |
    246          PIPE_BIND_SAMPLER_VIEW |
    247          PIPE_BIND_DISPLAY_TARGET |
    248          PIPE_BIND_SCANOUT);
    249    if (!gsurf->rsurf) {
    250       FREE(gsurf);
    251       return NULL;
    252    }
    253 
    254    /* initialize the geometry */
    255    gdi_surface_update_geometry(&gsurf->base);
    256 
    257    gsurf->base.destroy = gdi_surface_destroy;
    258    gsurf->base.present = gdi_surface_present;
    259    gsurf->base.validate = gdi_surface_validate;
    260    gsurf->base.wait = gdi_surface_wait;
    261 
    262    return &gsurf->base;
    263 }
    264 
    265 static int
    266 fill_color_formats(struct native_display *ndpy, enum pipe_format formats[8])
    267 {
    268    struct pipe_screen *screen = ndpy->screen;
    269    int i, count = 0;
    270 
    271    enum pipe_format candidates[] = {
    272       /* 32-bit */
    273       PIPE_FORMAT_B8G8R8A8_UNORM,
    274       PIPE_FORMAT_A8R8G8B8_UNORM,
    275       /* 24-bit */
    276       PIPE_FORMAT_B8G8R8X8_UNORM,
    277       PIPE_FORMAT_X8R8G8B8_UNORM,
    278       /* 16-bit */
    279       PIPE_FORMAT_B5G6R5_UNORM
    280    };
    281 
    282    assert(Elements(candidates) <= 8);
    283 
    284    for (i = 0; i < Elements(candidates); i++) {
    285       if (screen->is_format_supported(screen, candidates[i],
    286                PIPE_TEXTURE_2D, 0, PIPE_BIND_RENDER_TARGET))
    287          formats[count++] = candidates[i];
    288    }
    289 
    290    return count;
    291 }
    292 
    293 static const struct native_config **
    294 gdi_display_get_configs(struct native_display *ndpy, int *num_configs)
    295 {
    296    struct gdi_display *gdpy = gdi_display(ndpy);
    297    const struct native_config **configs;
    298    int i;
    299 
    300    /* first time */
    301    if (!gdpy->configs) {
    302       enum pipe_format formats[8];
    303       int i, count;
    304 
    305       count = fill_color_formats(&gdpy->base, formats);
    306 
    307       gdpy->configs = CALLOC(count, sizeof(*gdpy->configs));
    308       if (!gdpy->configs)
    309          return NULL;
    310 
    311       for (i = 0; i < count; i++) {
    312          struct native_config *nconf = &gdpy->configs[i];
    313 
    314          nconf->buffer_mask =
    315             (1 << NATIVE_ATTACHMENT_FRONT_LEFT) |
    316             (1 << NATIVE_ATTACHMENT_BACK_LEFT);
    317          nconf->color_format = formats[i];
    318 
    319          nconf->window_bit = TRUE;
    320       }
    321 
    322       gdpy->num_configs = count;
    323    }
    324 
    325    configs = MALLOC(gdpy->num_configs * sizeof(*configs));
    326    if (configs) {
    327       for (i = 0; i < gdpy->num_configs; i++)
    328          configs[i] = (const struct native_config *) &gdpy->configs[i];
    329       if (num_configs)
    330          *num_configs = gdpy->num_configs;
    331    }
    332    return configs;
    333 }
    334 
    335 static int
    336 gdi_display_get_param(struct native_display *ndpy,
    337                          enum native_param_type param)
    338 {
    339    int val;
    340 
    341    switch (param) {
    342    case NATIVE_PARAM_USE_NATIVE_BUFFER:
    343       /* private buffers are allocated */
    344       val = FALSE;
    345       break;
    346    case NATIVE_PARAM_PRESERVE_BUFFER:
    347    case NATIVE_PARAM_MAX_SWAP_INTERVAL:
    348    default:
    349       val = 0;
    350       break;
    351    }
    352 
    353    return val;
    354 }
    355 
    356 static void
    357 gdi_display_destroy(struct native_display *ndpy)
    358 {
    359    struct gdi_display *gdpy = gdi_display(ndpy);
    360 
    361    if (gdpy->configs)
    362       FREE(gdpy->configs);
    363 
    364    ndpy_uninit(ndpy);
    365 
    366    FREE(gdpy);
    367 }
    368 
    369 static boolean
    370 gdi_display_init_screen(struct native_display *ndpy)
    371 {
    372    struct gdi_display *gdpy = gdi_display(ndpy);
    373    struct sw_winsys *winsys;
    374 
    375    winsys = gdi_create_sw_winsys();
    376    if (!winsys)
    377       return FALSE;
    378 
    379    gdpy->base.screen = gdpy->event_handler->new_sw_screen(&gdpy->base, winsys);
    380    if (!gdpy->base.screen) {
    381       if (winsys->destroy)
    382          winsys->destroy(winsys);
    383       return FALSE;
    384    }
    385 
    386    return TRUE;
    387 }
    388 
    389 static struct native_display *
    390 gdi_create_display(HDC hDC, const struct native_event_handler *event_handler)
    391 {
    392    struct gdi_display *gdpy;
    393 
    394    gdpy = CALLOC_STRUCT(gdi_display);
    395    if (!gdpy)
    396       return NULL;
    397 
    398    gdpy->hDC = hDC;
    399    gdpy->event_handler = event_handler;
    400 
    401    gdpy->base.init_screen = gdi_display_init_screen;
    402    gdpy->base.destroy = gdi_display_destroy;
    403    gdpy->base.get_param = gdi_display_get_param;
    404 
    405    gdpy->base.get_configs = gdi_display_get_configs;
    406    gdpy->base.create_window_surface = gdi_display_create_window_surface;
    407 
    408    return &gdpy->base;
    409 }
    410 
    411 static const struct native_event_handler *gdi_event_handler;
    412 
    413 static struct native_display *
    414 native_create_display(void *dpy, boolean use_sw)
    415 {
    416    return gdi_create_display((HDC) dpy, gdi_event_handler);
    417 }
    418 
    419 static const struct native_platform gdi_platform = {
    420    "GDI", /* name */
    421    native_create_display
    422 };
    423 
    424 const struct native_platform *
    425 native_get_gdi_platform(const struct native_event_handler *event_handler)
    426 {
    427    gdi_event_handler = event_handler;
    428    return &gdi_platform;
    429 }
    430