Home | History | Annotate | Download | only in dri
      1 /**************************************************************************
      2  *
      3  * Copyright 2009, 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  * Author: Keith Whitwell <keithw (at) vmware.com>
     29  * Author: Jakob Bornecrantz <wallbraker (at) gmail.com>
     30  */
     31 
     32 #include "dri_screen.h"
     33 #include "dri_context.h"
     34 #include "dri_drawable.h"
     35 
     36 #include "pipe/p_screen.h"
     37 #include "util/u_format.h"
     38 #include "util/u_memory.h"
     39 #include "util/u_inlines.h"
     40 
     41 static void
     42 swap_fences_unref(struct dri_drawable *draw);
     43 
     44 static boolean
     45 dri_st_framebuffer_validate(struct st_context_iface *stctx,
     46                             struct st_framebuffer_iface *stfbi,
     47                             const enum st_attachment_type *statts,
     48                             unsigned count,
     49                             struct pipe_resource **out)
     50 {
     51    struct dri_context *ctx = (struct dri_context *)stctx->st_manager_private;
     52    struct dri_drawable *drawable =
     53       (struct dri_drawable *) stfbi->st_manager_private;
     54    struct dri_screen *screen = dri_screen(drawable->sPriv);
     55    unsigned statt_mask, new_mask;
     56    boolean new_stamp;
     57    int i;
     58    unsigned int lastStamp;
     59    struct pipe_resource **textures =
     60       drawable->stvis.samples > 1 ? drawable->msaa_textures
     61                                   : drawable->textures;
     62 
     63    statt_mask = 0x0;
     64    for (i = 0; i < count; i++)
     65       statt_mask |= (1 << statts[i]);
     66 
     67    /* record newly allocated textures */
     68    new_mask = (statt_mask & ~drawable->texture_mask);
     69 
     70    /*
     71     * dPriv->dri2.stamp is the server stamp.  dPriv->lastStamp is the
     72     * client stamp.  It has the value of the server stamp when last
     73     * checked.
     74     */
     75    do {
     76       lastStamp = drawable->dPriv->lastStamp;
     77       new_stamp = (drawable->texture_stamp != lastStamp);
     78 
     79       if (new_stamp || new_mask || screen->broken_invalidate) {
     80          if (new_stamp && drawable->update_drawable_info)
     81             drawable->update_drawable_info(drawable);
     82 
     83          drawable->allocate_textures(ctx, drawable, statts, count);
     84 
     85          /* add existing textures */
     86          for (i = 0; i < ST_ATTACHMENT_COUNT; i++) {
     87             if (textures[i])
     88                statt_mask |= (1 << i);
     89          }
     90 
     91          drawable->texture_stamp = lastStamp;
     92          drawable->texture_mask = statt_mask;
     93       }
     94    } while (lastStamp != drawable->dPriv->lastStamp);
     95 
     96    if (!out)
     97       return TRUE;
     98 
     99    /* Set the window-system buffers for the state tracker. */
    100    for (i = 0; i < count; i++) {
    101       out[i] = NULL;
    102       pipe_resource_reference(&out[i], textures[statts[i]]);
    103    }
    104 
    105    return TRUE;
    106 }
    107 
    108 static boolean
    109 dri_st_framebuffer_flush_front(struct st_context_iface *stctx,
    110                                struct st_framebuffer_iface *stfbi,
    111                                enum st_attachment_type statt)
    112 {
    113    struct dri_context *ctx = (struct dri_context *)stctx->st_manager_private;
    114    struct dri_drawable *drawable =
    115       (struct dri_drawable *) stfbi->st_manager_private;
    116 
    117    /* XXX remove this and just set the correct one on the framebuffer */
    118    drawable->flush_frontbuffer(ctx, drawable, statt);
    119 
    120    return TRUE;
    121 }
    122 
    123 /**
    124  * This is called when we need to set up GL rendering to a new X window.
    125  */
    126 boolean
    127 dri_create_buffer(__DRIscreen * sPriv,
    128 		  __DRIdrawable * dPriv,
    129 		  const struct gl_config * visual, boolean isPixmap)
    130 {
    131    struct dri_screen *screen = sPriv->driverPrivate;
    132    struct dri_drawable *drawable = NULL;
    133 
    134    if (isPixmap)
    135       goto fail;		       /* not implemented */
    136 
    137    drawable = CALLOC_STRUCT(dri_drawable);
    138    if (drawable == NULL)
    139       goto fail;
    140 
    141    dri_fill_st_visual(&drawable->stvis, screen, visual);
    142 
    143    /* setup the st_framebuffer_iface */
    144    drawable->base.visual = &drawable->stvis;
    145    drawable->base.flush_front = dri_st_framebuffer_flush_front;
    146    drawable->base.validate = dri_st_framebuffer_validate;
    147    drawable->base.st_manager_private = (void *) drawable;
    148 
    149    drawable->screen = screen;
    150    drawable->sPriv = sPriv;
    151    drawable->dPriv = dPriv;
    152    drawable->desired_fences = screen->default_throttle_frames;
    153    if (drawable->desired_fences > DRI_SWAP_FENCES_MAX)
    154       drawable->desired_fences = DRI_SWAP_FENCES_MAX;
    155 
    156    dPriv->driverPrivate = (void *)drawable;
    157    p_atomic_set(&drawable->base.stamp, 1);
    158 
    159    return GL_TRUE;
    160 fail:
    161    FREE(drawable);
    162    return GL_FALSE;
    163 }
    164 
    165 void
    166 dri_destroy_buffer(__DRIdrawable * dPriv)
    167 {
    168    struct dri_drawable *drawable = dri_drawable(dPriv);
    169    int i;
    170 
    171    pipe_surface_reference(&drawable->drisw_surface, NULL);
    172 
    173    for (i = 0; i < ST_ATTACHMENT_COUNT; i++)
    174       pipe_resource_reference(&drawable->textures[i], NULL);
    175    for (i = 0; i < ST_ATTACHMENT_COUNT; i++)
    176       pipe_resource_reference(&drawable->msaa_textures[i], NULL);
    177 
    178    swap_fences_unref(drawable);
    179 
    180    FREE(drawable);
    181 }
    182 
    183 /**
    184  * Validate the texture at an attachment.  Allocate the texture if it does not
    185  * exist.  Used by the TFP extension.
    186  */
    187 static void
    188 dri_drawable_validate_att(struct dri_context *ctx,
    189                           struct dri_drawable *drawable,
    190                           enum st_attachment_type statt)
    191 {
    192    enum st_attachment_type statts[ST_ATTACHMENT_COUNT];
    193    unsigned i, count = 0;
    194 
    195    /* check if buffer already exists */
    196    if (drawable->texture_mask & (1 << statt))
    197       return;
    198 
    199    /* make sure DRI2 does not destroy existing buffers */
    200    for (i = 0; i < ST_ATTACHMENT_COUNT; i++) {
    201       if (drawable->texture_mask & (1 << i)) {
    202          statts[count++] = i;
    203       }
    204    }
    205    statts[count++] = statt;
    206 
    207    drawable->texture_stamp = drawable->dPriv->lastStamp - 1;
    208 
    209    drawable->base.validate(ctx->st, &drawable->base, statts, count, NULL);
    210 }
    211 
    212 /**
    213  * These are used for GLX_EXT_texture_from_pixmap
    214  */
    215 static void
    216 dri_set_tex_buffer2(__DRIcontext *pDRICtx, GLint target,
    217                     GLint format, __DRIdrawable *dPriv)
    218 {
    219    struct dri_context *ctx = dri_context(pDRICtx);
    220    struct dri_drawable *drawable = dri_drawable(dPriv);
    221    struct pipe_resource *pt;
    222 
    223    dri_drawable_validate_att(ctx, drawable, ST_ATTACHMENT_FRONT_LEFT);
    224 
    225    /* Use the pipe resource associated with the X drawable */
    226    pt = drawable->textures[ST_ATTACHMENT_FRONT_LEFT];
    227 
    228    if (pt) {
    229       enum pipe_format internal_format = pt->format;
    230 
    231       if (format == __DRI_TEXTURE_FORMAT_RGB)  {
    232          /* only need to cover the formats recognized by dri_fill_st_visual */
    233          switch (internal_format) {
    234          case PIPE_FORMAT_BGRA8888_UNORM:
    235             internal_format = PIPE_FORMAT_BGRX8888_UNORM;
    236             break;
    237          case PIPE_FORMAT_ARGB8888_UNORM:
    238             internal_format = PIPE_FORMAT_XRGB8888_UNORM;
    239             break;
    240          default:
    241             break;
    242          }
    243       }
    244 
    245       drawable->update_tex_buffer(drawable, ctx, pt);
    246 
    247       ctx->st->teximage(ctx->st,
    248             (target == GL_TEXTURE_2D) ? ST_TEXTURE_2D : ST_TEXTURE_RECT,
    249             0, internal_format, pt, FALSE);
    250    }
    251 }
    252 
    253 static void
    254 dri_set_tex_buffer(__DRIcontext *pDRICtx, GLint target,
    255                    __DRIdrawable *dPriv)
    256 {
    257    dri_set_tex_buffer2(pDRICtx, target, __DRI_TEXTURE_FORMAT_RGBA, dPriv);
    258 }
    259 
    260 const __DRItexBufferExtension driTexBufferExtension = {
    261    .base = { __DRI_TEX_BUFFER, 2 },
    262 
    263    .setTexBuffer       = dri_set_tex_buffer,
    264    .setTexBuffer2      = dri_set_tex_buffer2,
    265    .releaseTexBuffer   = NULL,
    266 };
    267 
    268 /**
    269  * Get the format and binding of an attachment.
    270  */
    271 void
    272 dri_drawable_get_format(struct dri_drawable *drawable,
    273                         enum st_attachment_type statt,
    274                         enum pipe_format *format,
    275                         unsigned *bind)
    276 {
    277    switch (statt) {
    278    case ST_ATTACHMENT_FRONT_LEFT:
    279    case ST_ATTACHMENT_BACK_LEFT:
    280    case ST_ATTACHMENT_FRONT_RIGHT:
    281    case ST_ATTACHMENT_BACK_RIGHT:
    282       /* Other pieces of the driver stack get confused and behave incorrectly
    283        * when they get an sRGB drawable. st/mesa receives "drawable->stvis"
    284        * though other means and handles it correctly, so we don't really need
    285        * to use an sRGB format here.
    286        */
    287       *format = util_format_linear(drawable->stvis.color_format);
    288       *bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW;
    289       break;
    290    case ST_ATTACHMENT_DEPTH_STENCIL:
    291       *format = drawable->stvis.depth_stencil_format;
    292       *bind = PIPE_BIND_DEPTH_STENCIL; /* XXX sampler? */
    293       break;
    294    default:
    295       *format = PIPE_FORMAT_NONE;
    296       *bind = 0;
    297       break;
    298    }
    299 }
    300 
    301 
    302 /**
    303  * swap_fences_pop_front - pull a fence from the throttle queue
    304  *
    305  * If the throttle queue is filled to the desired number of fences,
    306  * pull fences off the queue until the number is less than the desired
    307  * number of fences, and return the last fence pulled.
    308  */
    309 static struct pipe_fence_handle *
    310 swap_fences_pop_front(struct dri_drawable *draw)
    311 {
    312    struct pipe_screen *screen = draw->screen->base.screen;
    313    struct pipe_fence_handle *fence = NULL;
    314 
    315    if (draw->desired_fences == 0)
    316       return NULL;
    317 
    318    if (draw->cur_fences >= draw->desired_fences) {
    319       screen->fence_reference(screen, &fence, draw->swap_fences[draw->tail]);
    320       screen->fence_reference(screen, &draw->swap_fences[draw->tail++], NULL);
    321       draw->tail &= DRI_SWAP_FENCES_MASK;
    322       --draw->cur_fences;
    323    }
    324    return fence;
    325 }
    326 
    327 
    328 /**
    329  * swap_fences_push_back - push a fence onto the throttle queue
    330  *
    331  * push a fence onto the throttle queue and pull fences of the queue
    332  * so that the desired number of fences are on the queue.
    333  */
    334 static void
    335 swap_fences_push_back(struct dri_drawable *draw,
    336 		      struct pipe_fence_handle *fence)
    337 {
    338    struct pipe_screen *screen = draw->screen->base.screen;
    339 
    340    if (!fence || draw->desired_fences == 0)
    341       return;
    342 
    343    while(draw->cur_fences == draw->desired_fences)
    344       swap_fences_pop_front(draw);
    345 
    346    draw->cur_fences++;
    347    screen->fence_reference(screen, &draw->swap_fences[draw->head++],
    348 			   fence);
    349    draw->head &= DRI_SWAP_FENCES_MASK;
    350 }
    351 
    352 
    353 /**
    354  * swap_fences_unref - empty the throttle queue
    355  *
    356  * pulls fences of the throttle queue until it is empty.
    357  */
    358 static void
    359 swap_fences_unref(struct dri_drawable *draw)
    360 {
    361    struct pipe_screen *screen = draw->screen->base.screen;
    362 
    363    while(draw->cur_fences) {
    364       screen->fence_reference(screen, &draw->swap_fences[draw->tail++], NULL);
    365       draw->tail &= DRI_SWAP_FENCES_MASK;
    366       --draw->cur_fences;
    367    }
    368 }
    369 
    370 void
    371 dri_pipe_blit(struct pipe_context *pipe,
    372               struct pipe_resource *dst,
    373               struct pipe_resource *src)
    374 {
    375    struct pipe_blit_info blit;
    376 
    377    if (!dst || !src)
    378       return;
    379 
    380    /* From the GL spec, version 4.2, section 4.1.11 (Additional Multisample
    381     *  Fragment Operations):
    382     *
    383     *      If a framebuffer object is not bound, after all operations have
    384     *      been completed on the multisample buffer, the sample values for
    385     *      each color in the multisample buffer are combined to produce a
    386     *      single color value, and that value is written into the
    387     *      corresponding color buffers selected by DrawBuffer or
    388     *      DrawBuffers. An implementation may defer the writing of the color
    389     *      buffers until a later time, but the state of the framebuffer must
    390     *      behave as if the color buffers were updated as each fragment was
    391     *      processed. The method of combination is not specified. If the
    392     *      framebuffer contains sRGB values, then it is recommended that the
    393     *      an average of sample values is computed in a linearized space, as
    394     *      for blending (see section 4.1.7).
    395     *
    396     * In other words, to do a resolve operation in a linear space, we have
    397     * to set sRGB formats if the original resources were sRGB, so don't use
    398     * util_format_linear.
    399     */
    400 
    401    memset(&blit, 0, sizeof(blit));
    402    blit.dst.resource = dst;
    403    blit.dst.box.width = dst->width0;
    404    blit.dst.box.height = dst->height0;
    405    blit.dst.box.depth = 1;
    406    blit.dst.format = dst->format;
    407    blit.src.resource = src;
    408    blit.src.box.width = src->width0;
    409    blit.src.box.height = src->height0;
    410    blit.src.box.depth = 1;
    411    blit.src.format = src->format;
    412    blit.mask = PIPE_MASK_RGBA;
    413    blit.filter = PIPE_TEX_FILTER_NEAREST;
    414 
    415    pipe->blit(pipe, &blit);
    416 }
    417 
    418 static void
    419 dri_postprocessing(struct dri_context *ctx,
    420                    struct dri_drawable *drawable,
    421                    enum st_attachment_type att)
    422 {
    423    struct pipe_resource *src = drawable->textures[att];
    424    struct pipe_resource *zsbuf = drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL];
    425 
    426    if (ctx->pp && src)
    427       pp_run(ctx->pp, src, src, zsbuf);
    428 }
    429 
    430 /**
    431  * DRI2 flush extension, the flush_with_flags function.
    432  *
    433  * \param context           the context
    434  * \param drawable          the drawable to flush
    435  * \param flags             a combination of _DRI2_FLUSH_xxx flags
    436  * \param throttle_reason   the reason for throttling, 0 = no throttling
    437  */
    438 void
    439 dri_flush(__DRIcontext *cPriv,
    440           __DRIdrawable *dPriv,
    441           unsigned flags,
    442           enum __DRI2throttleReason reason)
    443 {
    444    struct dri_context *ctx = dri_context(cPriv);
    445    struct dri_drawable *drawable = dri_drawable(dPriv);
    446    unsigned flush_flags;
    447    boolean swap_msaa_buffers = FALSE;
    448 
    449    if (!ctx) {
    450       assert(0);
    451       return;
    452    }
    453 
    454    if (drawable) {
    455       /* prevent recursion */
    456       if (drawable->flushing)
    457          return;
    458 
    459       drawable->flushing = TRUE;
    460    }
    461    else {
    462       flags &= ~__DRI2_FLUSH_DRAWABLE;
    463    }
    464 
    465    /* Flush the drawable. */
    466    if ((flags & __DRI2_FLUSH_DRAWABLE) &&
    467        drawable->textures[ST_ATTACHMENT_BACK_LEFT]) {
    468       struct pipe_context *pipe = ctx->st->pipe;
    469 
    470       if (drawable->stvis.samples > 1 &&
    471           reason == __DRI2_THROTTLE_SWAPBUFFER) {
    472          /* Resolve the MSAA back buffer. */
    473          dri_pipe_blit(ctx->st->pipe,
    474                        drawable->textures[ST_ATTACHMENT_BACK_LEFT],
    475                        drawable->msaa_textures[ST_ATTACHMENT_BACK_LEFT]);
    476 
    477          if (drawable->msaa_textures[ST_ATTACHMENT_FRONT_LEFT] &&
    478              drawable->msaa_textures[ST_ATTACHMENT_BACK_LEFT]) {
    479             swap_msaa_buffers = TRUE;
    480          }
    481 
    482          /* FRONT_LEFT is resolved in drawable->flush_frontbuffer. */
    483       }
    484 
    485       dri_postprocessing(ctx, drawable, ST_ATTACHMENT_BACK_LEFT);
    486 
    487       if (ctx->hud) {
    488          hud_draw(ctx->hud, drawable->textures[ST_ATTACHMENT_BACK_LEFT]);
    489       }
    490 
    491       pipe->flush_resource(pipe, drawable->textures[ST_ATTACHMENT_BACK_LEFT]);
    492 
    493       if (pipe->invalidate_resource &&
    494           (flags & __DRI2_FLUSH_INVALIDATE_ANCILLARY)) {
    495          if (drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL])
    496             pipe->invalidate_resource(pipe, drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL]);
    497          if (drawable->msaa_textures[ST_ATTACHMENT_DEPTH_STENCIL])
    498             pipe->invalidate_resource(pipe, drawable->msaa_textures[ST_ATTACHMENT_DEPTH_STENCIL]);
    499       }
    500    }
    501 
    502    flush_flags = 0;
    503    if (flags & __DRI2_FLUSH_CONTEXT)
    504       flush_flags |= ST_FLUSH_FRONT;
    505    if (reason == __DRI2_THROTTLE_SWAPBUFFER)
    506       flush_flags |= ST_FLUSH_END_OF_FRAME;
    507 
    508    /* Flush the context and throttle if needed. */
    509    if (dri_screen(ctx->sPriv)->throttling_enabled &&
    510        drawable &&
    511        (reason == __DRI2_THROTTLE_SWAPBUFFER ||
    512         reason == __DRI2_THROTTLE_FLUSHFRONT)) {
    513       /* Throttle.
    514        *
    515        * This pulls a fence off the throttling queue and waits for it if the
    516        * number of fences on the throttling queue has reached the desired
    517        * number.
    518        *
    519        * Then flushes to insert a fence at the current rendering position, and
    520        * pushes that fence on the queue. This requires that the st_context_iface
    521        * flush method returns a fence even if there are no commands to flush.
    522        */
    523       struct pipe_screen *screen = drawable->screen->base.screen;
    524       struct pipe_fence_handle *fence;
    525 
    526       fence = swap_fences_pop_front(drawable);
    527       if (fence) {
    528          (void) screen->fence_finish(screen, NULL, fence, PIPE_TIMEOUT_INFINITE);
    529          screen->fence_reference(screen, &fence, NULL);
    530       }
    531 
    532       ctx->st->flush(ctx->st, flush_flags, &fence);
    533 
    534       if (fence) {
    535          swap_fences_push_back(drawable, fence);
    536          screen->fence_reference(screen, &fence, NULL);
    537       }
    538    }
    539    else if (flags & (__DRI2_FLUSH_DRAWABLE | __DRI2_FLUSH_CONTEXT)) {
    540       ctx->st->flush(ctx->st, flush_flags, NULL);
    541    }
    542 
    543    if (drawable) {
    544       drawable->flushing = FALSE;
    545    }
    546 
    547    /* Swap the MSAA front and back buffers, so that reading
    548     * from the front buffer after SwapBuffers returns what was
    549     * in the back buffer.
    550     */
    551    if (swap_msaa_buffers) {
    552       struct pipe_resource *tmp =
    553          drawable->msaa_textures[ST_ATTACHMENT_FRONT_LEFT];
    554 
    555       drawable->msaa_textures[ST_ATTACHMENT_FRONT_LEFT] =
    556          drawable->msaa_textures[ST_ATTACHMENT_BACK_LEFT];
    557       drawable->msaa_textures[ST_ATTACHMENT_BACK_LEFT] = tmp;
    558 
    559       /* Now that we have swapped the buffers, this tells the state
    560        * tracker to revalidate the framebuffer.
    561        */
    562       p_atomic_inc(&drawable->base.stamp);
    563    }
    564 }
    565 
    566 /**
    567  * dri_throttle - A DRI2ThrottleExtension throttling function.
    568  */
    569 static void
    570 dri_throttle(__DRIcontext *cPriv, __DRIdrawable *dPriv,
    571              enum __DRI2throttleReason reason)
    572 {
    573    dri_flush(cPriv, dPriv, 0, reason);
    574 }
    575 
    576 
    577 const __DRI2throttleExtension dri2ThrottleExtension = {
    578     .base = { __DRI2_THROTTLE, 1 },
    579 
    580     .throttle          = dri_throttle,
    581 };
    582 
    583 
    584 /* vim: set sw=3 ts=8 sts=3 expandtab: */
    585