Home | History | Annotate | Download | only in drm
      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_framebuffer_iface *stfbi,
     46                             const enum st_attachment_type *statts,
     47                             unsigned count,
     48                             struct pipe_resource **out)
     49 {
     50    struct dri_drawable *drawable =
     51       (struct dri_drawable *) stfbi->st_manager_private;
     52    struct dri_screen *screen = dri_screen(drawable->sPriv);
     53    unsigned statt_mask, new_mask;
     54    boolean new_stamp;
     55    int i;
     56    unsigned int lastStamp;
     57 
     58    statt_mask = 0x0;
     59    for (i = 0; i < count; i++)
     60       statt_mask |= (1 << statts[i]);
     61 
     62    /* record newly allocated textures */
     63    new_mask = (statt_mask & ~drawable->texture_mask);
     64 
     65    /*
     66     * dPriv->dri2.stamp is the server stamp.  dPriv->lastStamp is the
     67     * client stamp.  It has the value of the server stamp when last
     68     * checked.
     69     */
     70    do {
     71       lastStamp = drawable->dPriv->lastStamp;
     72       new_stamp = (drawable->texture_stamp != lastStamp);
     73 
     74       if (new_stamp || new_mask || screen->broken_invalidate) {
     75          if (new_stamp && drawable->update_drawable_info)
     76             drawable->update_drawable_info(drawable);
     77 
     78          drawable->allocate_textures(drawable, statts, count);
     79 
     80          /* add existing textures */
     81          for (i = 0; i < ST_ATTACHMENT_COUNT; i++) {
     82             if (drawable->textures[i])
     83                statt_mask |= (1 << i);
     84          }
     85 
     86          drawable->texture_stamp = lastStamp;
     87          drawable->texture_mask = statt_mask;
     88       }
     89    } while (lastStamp != drawable->dPriv->lastStamp);
     90 
     91    if (!out)
     92       return TRUE;
     93 
     94    for (i = 0; i < count; i++) {
     95       out[i] = NULL;
     96       pipe_resource_reference(&out[i], drawable->textures[statts[i]]);
     97    }
     98 
     99    return TRUE;
    100 }
    101 
    102 static boolean
    103 dri_st_framebuffer_flush_front(struct st_framebuffer_iface *stfbi,
    104                                enum st_attachment_type statt)
    105 {
    106    struct dri_drawable *drawable =
    107       (struct dri_drawable *) stfbi->st_manager_private;
    108 
    109    /* XXX remove this and just set the correct one on the framebuffer */
    110    drawable->flush_frontbuffer(drawable, statt);
    111 
    112    return TRUE;
    113 }
    114 
    115 /**
    116  * This is called when we need to set up GL rendering to a new X window.
    117  */
    118 boolean
    119 dri_create_buffer(__DRIscreen * sPriv,
    120 		  __DRIdrawable * dPriv,
    121 		  const struct gl_config * visual, boolean isPixmap)
    122 {
    123    struct dri_screen *screen = sPriv->driverPrivate;
    124    struct dri_drawable *drawable = NULL;
    125 
    126    if (isPixmap)
    127       goto fail;		       /* not implemented */
    128 
    129    drawable = CALLOC_STRUCT(dri_drawable);
    130    if (drawable == NULL)
    131       goto fail;
    132 
    133    dri_fill_st_visual(&drawable->stvis, screen, visual);
    134 
    135    /* setup the st_framebuffer_iface */
    136    drawable->base.visual = &drawable->stvis;
    137    drawable->base.flush_front = dri_st_framebuffer_flush_front;
    138    drawable->base.validate = dri_st_framebuffer_validate;
    139    drawable->base.st_manager_private = (void *) drawable;
    140 
    141    drawable->screen = screen;
    142    drawable->sPriv = sPriv;
    143    drawable->dPriv = dPriv;
    144    drawable->desired_fences = screen->default_throttle_frames;
    145    if (drawable->desired_fences > DRI_SWAP_FENCES_MAX)
    146       drawable->desired_fences = DRI_SWAP_FENCES_MAX;
    147 
    148    dPriv->driverPrivate = (void *)drawable;
    149    p_atomic_set(&drawable->base.stamp, 1);
    150 
    151    return GL_TRUE;
    152 fail:
    153    FREE(drawable);
    154    return GL_FALSE;
    155 }
    156 
    157 void
    158 dri_destroy_buffer(__DRIdrawable * dPriv)
    159 {
    160    struct dri_drawable *drawable = dri_drawable(dPriv);
    161    int i;
    162 
    163    pipe_surface_reference(&drawable->drisw_surface, NULL);
    164 
    165    for (i = 0; i < ST_ATTACHMENT_COUNT; i++)
    166       pipe_resource_reference(&drawable->textures[i], NULL);
    167 
    168    swap_fences_unref(drawable);
    169 
    170    FREE(drawable);
    171 }
    172 
    173 /**
    174  * Validate the texture at an attachment.  Allocate the texture if it does not
    175  * exist.  Used by the TFP extension.
    176  */
    177 static void
    178 dri_drawable_validate_att(struct dri_drawable *drawable,
    179                           enum st_attachment_type statt)
    180 {
    181    enum st_attachment_type statts[ST_ATTACHMENT_COUNT];
    182    unsigned i, count = 0;
    183 
    184    /* check if buffer already exists */
    185    if (drawable->texture_mask & (1 << statt))
    186       return;
    187 
    188    /* make sure DRI2 does not destroy existing buffers */
    189    for (i = 0; i < ST_ATTACHMENT_COUNT; i++) {
    190       if (drawable->texture_mask & (1 << i)) {
    191          statts[count++] = i;
    192       }
    193    }
    194    statts[count++] = statt;
    195 
    196    drawable->texture_stamp = drawable->dPriv->lastStamp - 1;
    197 
    198    drawable->base.validate(&drawable->base, statts, count, NULL);
    199 }
    200 
    201 /**
    202  * These are used for GLX_EXT_texture_from_pixmap
    203  */
    204 static void
    205 dri_set_tex_buffer2(__DRIcontext *pDRICtx, GLint target,
    206                     GLint format, __DRIdrawable *dPriv)
    207 {
    208    struct dri_context *ctx = dri_context(pDRICtx);
    209    struct dri_drawable *drawable = dri_drawable(dPriv);
    210    struct pipe_resource *pt;
    211 
    212    dri_drawable_validate_att(drawable, ST_ATTACHMENT_FRONT_LEFT);
    213 
    214    /* Use the pipe resource associated with the X drawable */
    215    pt = drawable->textures[ST_ATTACHMENT_FRONT_LEFT];
    216 
    217    if (pt) {
    218       enum pipe_format internal_format = pt->format;
    219 
    220       if (format == __DRI_TEXTURE_FORMAT_RGB)  {
    221          /* only need to cover the formats recognized by dri_fill_st_visual */
    222          switch (internal_format) {
    223          case PIPE_FORMAT_B8G8R8A8_UNORM:
    224             internal_format = PIPE_FORMAT_B8G8R8X8_UNORM;
    225             break;
    226          case PIPE_FORMAT_A8R8G8B8_UNORM:
    227             internal_format = PIPE_FORMAT_X8R8G8B8_UNORM;
    228             break;
    229          default:
    230             break;
    231          }
    232       }
    233 
    234       drawable->update_tex_buffer(drawable, ctx, pt);
    235 
    236       ctx->st->teximage(ctx->st,
    237             (target == GL_TEXTURE_2D) ? ST_TEXTURE_2D : ST_TEXTURE_RECT,
    238             0, internal_format, pt, FALSE);
    239    }
    240 }
    241 
    242 static void
    243 dri_set_tex_buffer(__DRIcontext *pDRICtx, GLint target,
    244                    __DRIdrawable *dPriv)
    245 {
    246    dri_set_tex_buffer2(pDRICtx, target, __DRI_TEXTURE_FORMAT_RGBA, dPriv);
    247 }
    248 
    249 const __DRItexBufferExtension driTexBufferExtension = {
    250     { __DRI_TEX_BUFFER, __DRI_TEX_BUFFER_VERSION },
    251    dri_set_tex_buffer,
    252    dri_set_tex_buffer2,
    253    NULL,
    254 };
    255 
    256 /**
    257  * Get the format and binding of an attachment.
    258  */
    259 void
    260 dri_drawable_get_format(struct dri_drawable *drawable,
    261                         enum st_attachment_type statt,
    262                         enum pipe_format *format,
    263                         unsigned *bind)
    264 {
    265    switch (statt) {
    266    case ST_ATTACHMENT_FRONT_LEFT:
    267    case ST_ATTACHMENT_BACK_LEFT:
    268    case ST_ATTACHMENT_FRONT_RIGHT:
    269    case ST_ATTACHMENT_BACK_RIGHT:
    270       *format = drawable->stvis.color_format;
    271       *bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW;
    272       break;
    273    case ST_ATTACHMENT_DEPTH_STENCIL:
    274       *format = drawable->stvis.depth_stencil_format;
    275       *bind = PIPE_BIND_DEPTH_STENCIL; /* XXX sampler? */
    276       break;
    277    default:
    278       *format = PIPE_FORMAT_NONE;
    279       *bind = 0;
    280       break;
    281    }
    282 }
    283 
    284 
    285 /**
    286  * swap_fences_pop_front - pull a fence from the throttle queue
    287  *
    288  * If the throttle queue is filled to the desired number of fences,
    289  * pull fences off the queue until the number is less than the desired
    290  * number of fences, and return the last fence pulled.
    291  */
    292 static struct pipe_fence_handle *
    293 swap_fences_pop_front(struct dri_drawable *draw)
    294 {
    295    struct pipe_screen *screen = draw->screen->base.screen;
    296    struct pipe_fence_handle *fence = NULL;
    297 
    298    if (draw->desired_fences == 0)
    299       return NULL;
    300 
    301    if (draw->cur_fences >= draw->desired_fences) {
    302       screen->fence_reference(screen, &fence, draw->swap_fences[draw->tail]);
    303       screen->fence_reference(screen, &draw->swap_fences[draw->tail++], NULL);
    304       draw->tail &= DRI_SWAP_FENCES_MASK;
    305       --draw->cur_fences;
    306    }
    307    return fence;
    308 }
    309 
    310 
    311 /**
    312  * swap_fences_push_back - push a fence onto the throttle queue
    313  *
    314  * push a fence onto the throttle queue and pull fences of the queue
    315  * so that the desired number of fences are on the queue.
    316  */
    317 static void
    318 swap_fences_push_back(struct dri_drawable *draw,
    319 		      struct pipe_fence_handle *fence)
    320 {
    321    struct pipe_screen *screen = draw->screen->base.screen;
    322 
    323    if (!fence || draw->desired_fences == 0)
    324       return;
    325 
    326    while(draw->cur_fences == draw->desired_fences)
    327       swap_fences_pop_front(draw);
    328 
    329    draw->cur_fences++;
    330    screen->fence_reference(screen, &draw->swap_fences[draw->head++],
    331 			   fence);
    332    draw->head &= DRI_SWAP_FENCES_MASK;
    333 }
    334 
    335 
    336 /**
    337  * swap_fences_unref - empty the throttle queue
    338  *
    339  * pulls fences of the throttle queue until it is empty.
    340  */
    341 static void
    342 swap_fences_unref(struct dri_drawable *draw)
    343 {
    344    struct pipe_screen *screen = draw->screen->base.screen;
    345 
    346    while(draw->cur_fences) {
    347       screen->fence_reference(screen, &draw->swap_fences[draw->tail++], NULL);
    348       draw->tail &= DRI_SWAP_FENCES_MASK;
    349       --draw->cur_fences;
    350    }
    351 }
    352 
    353 
    354 /**
    355  * dri_throttle - A DRI2ThrottleExtension throttling function.
    356  *
    357  * pulls a fence off the throttling queue and waits for it if the
    358  * number of fences on the throttling queue has reached the desired
    359  * number.
    360  *
    361  * Then flushes to insert a fence at the current rendering position, and
    362  * pushes that fence on the queue. This requires that the st_context_iface
    363  * flush method returns a fence even if there are no commands to flush.
    364  */
    365 static void
    366 dri_throttle(__DRIcontext *driCtx, __DRIdrawable *dPriv,
    367 	     enum __DRI2throttleReason reason)
    368 {
    369     struct dri_drawable *draw = dri_drawable(dPriv);
    370     struct st_context_iface *ctxi;
    371     struct pipe_screen *screen = draw->screen->base.screen;
    372     struct pipe_fence_handle *fence;
    373 
    374     if (reason != __DRI2_THROTTLE_SWAPBUFFER &&
    375 	reason != __DRI2_THROTTLE_FLUSHFRONT)
    376 	return;
    377 
    378     fence = swap_fences_pop_front(draw);
    379     if (fence) {
    380 	(void) screen->fence_finish(screen, fence, PIPE_TIMEOUT_INFINITE);
    381 	screen->fence_reference(screen, &fence, NULL);
    382     }
    383 
    384     if (driCtx == NULL)
    385 	return;
    386 
    387     ctxi = dri_context(driCtx)->st;
    388     ctxi->flush(ctxi, 0, &fence);
    389     if (fence) {
    390 	swap_fences_push_back(draw, fence);
    391 	screen->fence_reference(screen, &fence, NULL);
    392     }
    393 }
    394 
    395 
    396 const __DRI2throttleExtension dri2ThrottleExtension = {
    397     .base = { __DRI2_THROTTLE, __DRI2_THROTTLE_VERSION },
    398     .throttle = dri_throttle,
    399 };
    400 
    401 
    402 /* vim: set sw=3 ts=8 sts=3 expandtab: */
    403