Home | History | Annotate | Download | only in sw
      1 /**************************************************************************
      2  *
      3  * Copyright 2009, VMware, Inc.
      4  * All Rights Reserved.
      5  * Copyright 2010 George Sapountzis <gsapountzis (at) gmail.com>
      6  *
      7  * Permission is hereby granted, free of charge, to any person obtaining a
      8  * copy of this software and associated documentation files (the
      9  * "Software"), to deal in the Software without restriction, including
     10  * without limitation the rights to use, copy, modify, merge, publish,
     11  * distribute, sub license, and/or sell copies of the Software, and to
     12  * permit persons to whom the Software is furnished to do so, subject to
     13  * the following conditions:
     14  *
     15  * The above copyright notice and this permission notice (including the
     16  * next paragraph) shall be included in all copies or substantial portions
     17  * of the Software.
     18  *
     19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     20  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     21  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
     22  * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
     23  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
     24  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
     25  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     26  *
     27  **************************************************************************/
     28 
     29 /* TODO:
     30  *
     31  * xshm / EGLImage:
     32  *
     33  * Allow the loaders to use the XSHM extension. It probably requires callbacks
     34  * for createImage/destroyImage similar to DRI2 getBuffers.
     35  */
     36 
     37 #include "util/u_format.h"
     38 #include "util/u_memory.h"
     39 #include "util/u_inlines.h"
     40 #include "pipe/p_context.h"
     41 #include "state_tracker/drisw_api.h"
     42 #include "state_tracker/st_context.h"
     43 
     44 #include "dri_screen.h"
     45 #include "dri_context.h"
     46 #include "dri_drawable.h"
     47 
     48 DEBUG_GET_ONCE_BOOL_OPTION(swrast_no_present, "SWRAST_NO_PRESENT", FALSE);
     49 static boolean swrast_no_present = FALSE;
     50 
     51 static INLINE void
     52 get_drawable_info(__DRIdrawable *dPriv, int *x, int *y, int *w, int *h)
     53 {
     54    __DRIscreen *sPriv = dPriv->driScreenPriv;
     55    const __DRIswrastLoaderExtension *loader = sPriv->swrast_loader;
     56 
     57    loader->getDrawableInfo(dPriv,
     58                            x, y, w, h,
     59                            dPriv->loaderPrivate);
     60 }
     61 
     62 static INLINE void
     63 put_image(__DRIdrawable *dPriv, void *data, unsigned width, unsigned height)
     64 {
     65    __DRIscreen *sPriv = dPriv->driScreenPriv;
     66    const __DRIswrastLoaderExtension *loader = sPriv->swrast_loader;
     67 
     68    loader->putImage(dPriv, __DRI_SWRAST_IMAGE_OP_SWAP,
     69                     0, 0, width, height,
     70                     data, dPriv->loaderPrivate);
     71 }
     72 
     73 static INLINE void
     74 get_image(__DRIdrawable *dPriv, int x, int y, int width, int height, void *data)
     75 {
     76    __DRIscreen *sPriv = dPriv->driScreenPriv;
     77    const __DRIswrastLoaderExtension *loader = sPriv->swrast_loader;
     78 
     79    loader->getImage(dPriv,
     80                     x, y, width, height,
     81                     data, dPriv->loaderPrivate);
     82 }
     83 
     84 static void
     85 drisw_update_drawable_info(struct dri_drawable *drawable)
     86 {
     87    __DRIdrawable *dPriv = drawable->dPriv;
     88    int x, y;
     89 
     90    get_drawable_info(dPriv, &x, &y, &dPriv->w, &dPriv->h);
     91 }
     92 
     93 static void
     94 drisw_put_image(struct dri_drawable *drawable,
     95                 void *data, unsigned width, unsigned height)
     96 {
     97    __DRIdrawable *dPriv = drawable->dPriv;
     98 
     99    put_image(dPriv, data, width, height);
    100 }
    101 
    102 static INLINE void
    103 drisw_present_texture(__DRIdrawable *dPriv,
    104                       struct pipe_resource *ptex)
    105 {
    106    struct dri_drawable *drawable = dri_drawable(dPriv);
    107    struct dri_screen *screen = dri_screen(drawable->sPriv);
    108 
    109    if (swrast_no_present)
    110       return;
    111 
    112    screen->base.screen->flush_frontbuffer(screen->base.screen, ptex, 0, 0, drawable);
    113 }
    114 
    115 static INLINE void
    116 drisw_invalidate_drawable(__DRIdrawable *dPriv)
    117 {
    118    struct dri_drawable *drawable = dri_drawable(dPriv);
    119 
    120    drawable->texture_stamp = dPriv->lastStamp - 1;
    121 
    122    p_atomic_inc(&drawable->base.stamp);
    123 }
    124 
    125 static INLINE void
    126 drisw_copy_to_front(__DRIdrawable * dPriv,
    127                     struct pipe_resource *ptex)
    128 {
    129    drisw_present_texture(dPriv, ptex);
    130 
    131    drisw_invalidate_drawable(dPriv);
    132 }
    133 
    134 /*
    135  * Backend functions for st_framebuffer interface and swap_buffers.
    136  */
    137 
    138 static void
    139 drisw_swap_buffers(__DRIdrawable *dPriv)
    140 {
    141    struct dri_context *ctx = dri_get_current(dPriv->driScreenPriv);
    142    struct dri_drawable *drawable = dri_drawable(dPriv);
    143    struct pipe_resource *ptex;
    144 
    145    if (!ctx)
    146       return;
    147 
    148    ptex = drawable->textures[ST_ATTACHMENT_BACK_LEFT];
    149 
    150    if (ptex) {
    151       if (ctx->pp && drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL])
    152          pp_run(ctx->pp, ptex, ptex, drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL]);
    153 
    154       ctx->st->flush(ctx->st, ST_FLUSH_FRONT, NULL);
    155 
    156       drisw_copy_to_front(dPriv, ptex);
    157    }
    158 }
    159 
    160 static void
    161 drisw_flush_frontbuffer(struct dri_drawable *drawable,
    162                         enum st_attachment_type statt)
    163 {
    164    struct dri_context *ctx = dri_get_current(drawable->sPriv);
    165    struct pipe_resource *ptex;
    166 
    167    if (!ctx)
    168       return;
    169 
    170    ptex = drawable->textures[statt];
    171 
    172    if (ptex) {
    173       drisw_copy_to_front(ctx->dPriv, ptex);
    174    }
    175 }
    176 
    177 /**
    178  * Allocate framebuffer attachments.
    179  *
    180  * During fixed-size operation, the function keeps allocating new attachments
    181  * as they are requested. Unused attachments are not removed, not until the
    182  * framebuffer is resized or destroyed.
    183  */
    184 static void
    185 drisw_allocate_textures(struct dri_drawable *drawable,
    186                         const enum st_attachment_type *statts,
    187                         unsigned count)
    188 {
    189    struct dri_screen *screen = dri_screen(drawable->sPriv);
    190    struct pipe_resource templ;
    191    unsigned width, height;
    192    boolean resized;
    193    unsigned i;
    194 
    195    width  = drawable->dPriv->w;
    196    height = drawable->dPriv->h;
    197 
    198    resized = (drawable->old_w != width ||
    199               drawable->old_h != height);
    200 
    201    /* remove outdated textures */
    202    if (resized) {
    203       for (i = 0; i < ST_ATTACHMENT_COUNT; i++)
    204          pipe_resource_reference(&drawable->textures[i], NULL);
    205    }
    206 
    207    memset(&templ, 0, sizeof(templ));
    208    templ.target = screen->target;
    209    templ.width0 = width;
    210    templ.height0 = height;
    211    templ.depth0 = 1;
    212    templ.array_size = 1;
    213    templ.last_level = 0;
    214 
    215    for (i = 0; i < count; i++) {
    216       enum pipe_format format;
    217       unsigned bind;
    218 
    219       /* the texture already exists or not requested */
    220       if (drawable->textures[statts[i]])
    221          continue;
    222 
    223       dri_drawable_get_format(drawable, statts[i], &format, &bind);
    224 
    225       /* if we don't do any present, no need for display targets */
    226       if (statts[i] != ST_ATTACHMENT_DEPTH_STENCIL && !swrast_no_present)
    227          bind |= PIPE_BIND_DISPLAY_TARGET;
    228 
    229       if (format == PIPE_FORMAT_NONE)
    230          continue;
    231 
    232       templ.format = format;
    233       templ.bind = bind;
    234 
    235       drawable->textures[statts[i]] =
    236          screen->base.screen->resource_create(screen->base.screen, &templ);
    237    }
    238 
    239    drawable->old_w = width;
    240    drawable->old_h = height;
    241 }
    242 
    243 static void
    244 drisw_update_tex_buffer(struct dri_drawable *drawable,
    245                         struct dri_context *ctx,
    246                         struct pipe_resource *res)
    247 {
    248    __DRIdrawable *dPriv = drawable->dPriv;
    249 
    250    struct st_context *st_ctx = (struct st_context *)ctx->st;
    251    struct pipe_context *pipe = st_ctx->pipe;
    252    struct pipe_transfer *transfer;
    253    char *map;
    254    int x, y, w, h;
    255    int ximage_stride, line;
    256    int cpp = util_format_get_blocksize(res->format);
    257 
    258    get_drawable_info(dPriv, &x, &y, &w, &h);
    259 
    260    transfer = pipe_get_transfer(pipe, res,
    261                                 0, 0, // level, layer,
    262                                 PIPE_TRANSFER_WRITE,
    263                                 x, y, w, h);
    264    map = pipe_transfer_map(pipe, transfer);
    265 
    266    /* Copy the Drawable content to the mapped texture buffer */
    267    get_image(dPriv, x, y, w, h, map);
    268 
    269    /* The pipe transfer has a pitch rounded up to the nearest 64 pixels. */
    270    ximage_stride = w * cpp;
    271    for (line = h-1; line; --line) {
    272       memmove(&map[line * transfer->stride],
    273               &map[line * ximage_stride],
    274               ximage_stride);
    275    }
    276 
    277    pipe_transfer_unmap(pipe, transfer);
    278    pipe_transfer_destroy(pipe, transfer);
    279 }
    280 
    281 /*
    282  * Backend function for init_screen.
    283  */
    284 
    285 static const __DRIextension *drisw_screen_extensions[] = {
    286    &driTexBufferExtension.base,
    287    NULL
    288 };
    289 
    290 static struct drisw_loader_funcs drisw_lf = {
    291    .put_image = drisw_put_image
    292 };
    293 
    294 static const __DRIconfig **
    295 drisw_init_screen(__DRIscreen * sPriv)
    296 {
    297    const __DRIconfig **configs;
    298    struct dri_screen *screen;
    299    struct pipe_screen *pscreen;
    300 
    301    screen = CALLOC_STRUCT(dri_screen);
    302    if (!screen)
    303       return NULL;
    304 
    305    screen->sPriv = sPriv;
    306    screen->fd = -1;
    307 
    308    swrast_no_present = debug_get_option_swrast_no_present();
    309 
    310    sPriv->driverPrivate = (void *)screen;
    311    sPriv->extensions = drisw_screen_extensions;
    312 
    313    pscreen = drisw_create_screen(&drisw_lf);
    314    /* dri_init_screen_helper checks pscreen for us */
    315 
    316    configs = dri_init_screen_helper(screen, pscreen, 32);
    317    if (!configs)
    318       goto fail;
    319 
    320    return configs;
    321 fail:
    322    dri_destroy_screen_helper(screen);
    323    FREE(screen);
    324    return NULL;
    325 }
    326 
    327 static boolean
    328 drisw_create_buffer(__DRIscreen * sPriv,
    329                     __DRIdrawable * dPriv,
    330                     const struct gl_config * visual, boolean isPixmap)
    331 {
    332    struct dri_drawable *drawable = NULL;
    333 
    334    if (!dri_create_buffer(sPriv, dPriv, visual, isPixmap))
    335       return FALSE;
    336 
    337    drawable = dPriv->driverPrivate;
    338 
    339    drawable->allocate_textures = drisw_allocate_textures;
    340    drawable->update_drawable_info = drisw_update_drawable_info;
    341    drawable->flush_frontbuffer = drisw_flush_frontbuffer;
    342    drawable->update_tex_buffer = drisw_update_tex_buffer;
    343 
    344    return TRUE;
    345 }
    346 
    347 /**
    348  * DRI driver virtual function table.
    349  *
    350  * DRI versions differ in their implementation of init_screen and swap_buffers.
    351  */
    352 const struct __DriverAPIRec driDriverAPI = {
    353    .InitScreen = drisw_init_screen,
    354    .DestroyScreen = dri_destroy_screen,
    355    .CreateContext = dri_create_context,
    356    .DestroyContext = dri_destroy_context,
    357    .CreateBuffer = drisw_create_buffer,
    358    .DestroyBuffer = dri_destroy_buffer,
    359    .SwapBuffers = drisw_swap_buffers,
    360    .MakeCurrent = dri_make_current,
    361    .UnbindContext = dri_unbind_context,
    362 };
    363 
    364 /* This is the table of extensions that the loader will dlsym() for. */
    365 PUBLIC const __DRIextension *__driDriverExtensions[] = {
    366     &driCoreExtension.base,
    367     &driSWRastExtension.base,
    368     NULL
    369 };
    370 
    371 /* vim: set sw=3 ts=8 sts=3 expandtab: */
    372