Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  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@vmware.com>
  29.  * Author: Jakob Bornecrantz <wallbraker@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_B8G8R8A8_UNORM:
  235.             internal_format = PIPE_FORMAT_B8G8R8X8_UNORM;
  236.             break;
  237.          case PIPE_FORMAT_A8R8G8B8_UNORM:
  238.             internal_format = PIPE_FORMAT_X8R8G8B8_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.     { __DRI_TEX_BUFFER, __DRI_TEX_BUFFER_VERSION },
  262.    dri_set_tex_buffer,
  263.    dri_set_tex_buffer2,
  264.    NULL,
  265. };
  266.  
  267. /**
  268.  * Get the format and binding of an attachment.
  269.  */
  270. void
  271. dri_drawable_get_format(struct dri_drawable *drawable,
  272.                         enum st_attachment_type statt,
  273.                         enum pipe_format *format,
  274.                         unsigned *bind)
  275. {
  276.    switch (statt) {
  277.    case ST_ATTACHMENT_FRONT_LEFT:
  278.    case ST_ATTACHMENT_BACK_LEFT:
  279.    case ST_ATTACHMENT_FRONT_RIGHT:
  280.    case ST_ATTACHMENT_BACK_RIGHT:
  281.       *format = drawable->stvis.color_format;
  282.       *bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW;
  283.       break;
  284.    case ST_ATTACHMENT_DEPTH_STENCIL:
  285.       *format = drawable->stvis.depth_stencil_format;
  286.       *bind = PIPE_BIND_DEPTH_STENCIL; /* XXX sampler? */
  287.       break;
  288.    default:
  289.       *format = PIPE_FORMAT_NONE;
  290.       *bind = 0;
  291.       break;
  292.    }
  293. }
  294.  
  295.  
  296. /**
  297.  * swap_fences_pop_front - pull a fence from the throttle queue
  298.  *
  299.  * If the throttle queue is filled to the desired number of fences,
  300.  * pull fences off the queue until the number is less than the desired
  301.  * number of fences, and return the last fence pulled.
  302.  */
  303. static struct pipe_fence_handle *
  304. swap_fences_pop_front(struct dri_drawable *draw)
  305. {
  306.    struct pipe_screen *screen = draw->screen->base.screen;
  307.    struct pipe_fence_handle *fence = NULL;
  308.  
  309.    if (draw->desired_fences == 0)
  310.       return NULL;
  311.  
  312.    if (draw->cur_fences >= draw->desired_fences) {
  313.       screen->fence_reference(screen, &fence, draw->swap_fences[draw->tail]);
  314.       screen->fence_reference(screen, &draw->swap_fences[draw->tail++], NULL);
  315.       draw->tail &= DRI_SWAP_FENCES_MASK;
  316.       --draw->cur_fences;
  317.    }
  318.    return fence;
  319. }
  320.  
  321.  
  322. /**
  323.  * swap_fences_push_back - push a fence onto the throttle queue
  324.  *
  325.  * push a fence onto the throttle queue and pull fences of the queue
  326.  * so that the desired number of fences are on the queue.
  327.  */
  328. static void
  329. swap_fences_push_back(struct dri_drawable *draw,
  330.                       struct pipe_fence_handle *fence)
  331. {
  332.    struct pipe_screen *screen = draw->screen->base.screen;
  333.  
  334.    if (!fence || draw->desired_fences == 0)
  335.       return;
  336.  
  337.    while(draw->cur_fences == draw->desired_fences)
  338.       swap_fences_pop_front(draw);
  339.  
  340.    draw->cur_fences++;
  341.    screen->fence_reference(screen, &draw->swap_fences[draw->head++],
  342.                            fence);
  343.    draw->head &= DRI_SWAP_FENCES_MASK;
  344. }
  345.  
  346.  
  347. /**
  348.  * swap_fences_unref - empty the throttle queue
  349.  *
  350.  * pulls fences of the throttle queue until it is empty.
  351.  */
  352. static void
  353. swap_fences_unref(struct dri_drawable *draw)
  354. {
  355.    struct pipe_screen *screen = draw->screen->base.screen;
  356.  
  357.    while(draw->cur_fences) {
  358.       screen->fence_reference(screen, &draw->swap_fences[draw->tail++], NULL);
  359.       draw->tail &= DRI_SWAP_FENCES_MASK;
  360.       --draw->cur_fences;
  361.    }
  362. }
  363.  
  364. void
  365. dri_pipe_blit(struct pipe_context *pipe,
  366.               struct pipe_resource *dst,
  367.               struct pipe_resource *src)
  368. {
  369.    struct pipe_blit_info blit;
  370.  
  371.    if (!dst || !src)
  372.       return;
  373.  
  374.    memset(&blit, 0, sizeof(blit));
  375.    blit.dst.resource = dst;
  376.    blit.dst.box.width = dst->width0;
  377.    blit.dst.box.height = dst->height0;
  378.    blit.dst.box.depth = 1;
  379.    blit.dst.format = util_format_linear(dst->format);
  380.    blit.src.resource = src;
  381.    blit.src.box.width = src->width0;
  382.    blit.src.box.height = src->height0;
  383.    blit.src.box.depth = 1;
  384.    blit.src.format = util_format_linear(src->format);
  385.    blit.mask = PIPE_MASK_RGBA;
  386.    blit.filter = PIPE_TEX_FILTER_NEAREST;
  387.  
  388.    pipe->blit(pipe, &blit);
  389. }
  390.  
  391. static void
  392. dri_postprocessing(struct dri_context *ctx,
  393.                    struct dri_drawable *drawable,
  394.                    enum st_attachment_type att)
  395. {
  396.    struct pipe_resource *src = drawable->textures[att];
  397.    struct pipe_resource *zsbuf = drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL];
  398.  
  399.    if (ctx->pp && src && zsbuf)
  400.       pp_run(ctx->pp, src, src, zsbuf);
  401. }
  402.  
  403. /**
  404.  * DRI2 flush extension, the flush_with_flags function.
  405.  *
  406.  * \param context           the context
  407.  * \param drawable          the drawable to flush
  408.  * \param flags             a combination of _DRI2_FLUSH_xxx flags
  409.  * \param throttle_reason   the reason for throttling, 0 = no throttling
  410.  */
  411. void
  412. dri_flush(__DRIcontext *cPriv,
  413.           __DRIdrawable *dPriv,
  414.           unsigned flags,
  415.           enum __DRI2throttleReason reason)
  416. {
  417.    struct dri_context *ctx = dri_context(cPriv);
  418.    struct dri_drawable *drawable = dri_drawable(dPriv);
  419.    unsigned flush_flags;
  420.    boolean swap_msaa_buffers = FALSE;
  421.  
  422.    if (!ctx) {
  423.       assert(0);
  424.       return;
  425.    }
  426.  
  427.    if (drawable) {
  428.       /* prevent recursion */
  429.       if (drawable->flushing)
  430.          return;
  431.  
  432.       drawable->flushing = TRUE;
  433.    }
  434.    else {
  435.       flags &= ~__DRI2_FLUSH_DRAWABLE;
  436.    }
  437.  
  438.    /* Flush the drawable. */
  439.    if ((flags & __DRI2_FLUSH_DRAWABLE) &&
  440.        drawable->textures[ST_ATTACHMENT_BACK_LEFT]) {
  441.       if (drawable->stvis.samples > 1 &&
  442.           reason == __DRI2_THROTTLE_SWAPBUFFER) {
  443.          /* Resolve the MSAA back buffer. */
  444.          dri_pipe_blit(ctx->st->pipe,
  445.                        drawable->textures[ST_ATTACHMENT_BACK_LEFT],
  446.                        drawable->msaa_textures[ST_ATTACHMENT_BACK_LEFT]);
  447.  
  448.          if (drawable->msaa_textures[ST_ATTACHMENT_FRONT_LEFT] &&
  449.              drawable->msaa_textures[ST_ATTACHMENT_BACK_LEFT]) {
  450.             swap_msaa_buffers = TRUE;
  451.          }
  452.  
  453.          /* FRONT_LEFT is resolved in drawable->flush_frontbuffer. */
  454.       }
  455.  
  456.       dri_postprocessing(ctx, drawable, ST_ATTACHMENT_BACK_LEFT);
  457.  
  458.       if (ctx->hud) {
  459.          hud_draw(ctx->hud, drawable->textures[ST_ATTACHMENT_BACK_LEFT]);
  460.       }
  461.    }
  462.  
  463.    flush_flags = 0;
  464.    if (flags & __DRI2_FLUSH_CONTEXT)
  465.       flush_flags |= ST_FLUSH_FRONT;
  466.    if (reason == __DRI2_THROTTLE_SWAPBUFFER)
  467.       flush_flags |= ST_FLUSH_END_OF_FRAME;
  468.  
  469.    /* Flush the context and throttle if needed. */
  470.    if (dri_screen(ctx->sPriv)->throttling_enabled &&
  471.        drawable &&
  472.        (reason == __DRI2_THROTTLE_SWAPBUFFER ||
  473.         reason == __DRI2_THROTTLE_FLUSHFRONT)) {
  474.       /* Throttle.
  475.        *
  476.        * This pulls a fence off the throttling queue and waits for it if the
  477.        * number of fences on the throttling queue has reached the desired
  478.        * number.
  479.        *
  480.        * Then flushes to insert a fence at the current rendering position, and
  481.        * pushes that fence on the queue. This requires that the st_context_iface
  482.        * flush method returns a fence even if there are no commands to flush.
  483.        */
  484.       struct pipe_screen *screen = drawable->screen->base.screen;
  485.       struct pipe_fence_handle *fence;
  486.  
  487.       fence = swap_fences_pop_front(drawable);
  488.       if (fence) {
  489.          (void) screen->fence_finish(screen, fence, PIPE_TIMEOUT_INFINITE);
  490.          screen->fence_reference(screen, &fence, NULL);
  491.       }
  492.  
  493.       ctx->st->flush(ctx->st, flush_flags, &fence);
  494.  
  495.       if (fence) {
  496.          swap_fences_push_back(drawable, fence);
  497.          screen->fence_reference(screen, &fence, NULL);
  498.       }
  499.    }
  500.    else if (flags & (__DRI2_FLUSH_DRAWABLE | __DRI2_FLUSH_CONTEXT)) {
  501.       ctx->st->flush(ctx->st, flush_flags, NULL);
  502.    }
  503.  
  504.    if (drawable) {
  505.       drawable->flushing = FALSE;
  506.    }
  507.  
  508.    /* Swap the MSAA front and back buffers, so that reading
  509.     * from the front buffer after SwapBuffers returns what was
  510.     * in the back buffer.
  511.     */
  512.    if (swap_msaa_buffers) {
  513.       struct pipe_resource *tmp =
  514.          drawable->msaa_textures[ST_ATTACHMENT_FRONT_LEFT];
  515.  
  516.       drawable->msaa_textures[ST_ATTACHMENT_FRONT_LEFT] =
  517.          drawable->msaa_textures[ST_ATTACHMENT_BACK_LEFT];
  518.       drawable->msaa_textures[ST_ATTACHMENT_BACK_LEFT] = tmp;
  519.  
  520.       /* Now that we have swapped the buffers, this tells the state
  521.        * tracker to revalidate the framebuffer.
  522.        */
  523.       p_atomic_inc(&drawable->base.stamp);
  524.    }
  525. }
  526.  
  527. /**
  528.  * dri_throttle - A DRI2ThrottleExtension throttling function.
  529.  */
  530. static void
  531. dri_throttle(__DRIcontext *cPriv, __DRIdrawable *dPriv,
  532.              enum __DRI2throttleReason reason)
  533. {
  534.    dri_flush(cPriv, dPriv, 0, reason);
  535. }
  536.  
  537.  
  538. const __DRI2throttleExtension dri2ThrottleExtension = {
  539.     .base = { __DRI2_THROTTLE, __DRI2_THROTTLE_VERSION },
  540.     .throttle = dri_throttle,
  541. };
  542.  
  543.  
  544. /* vim: set sw=3 ts=8 sts=3 expandtab: */
  545.