17ec681f3Smrg/**************************************************************************
27ec681f3Smrg *
37ec681f3Smrg * Copyright 2009, VMware, Inc.
47ec681f3Smrg * All Rights Reserved.
57ec681f3Smrg *
67ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a
77ec681f3Smrg * copy of this software and associated documentation files (the
87ec681f3Smrg * "Software"), to deal in the Software without restriction, including
97ec681f3Smrg * without limitation the rights to use, copy, modify, merge, publish,
107ec681f3Smrg * distribute, sub license, and/or sell copies of the Software, and to
117ec681f3Smrg * permit persons to whom the Software is furnished to do so, subject to
127ec681f3Smrg * the following conditions:
137ec681f3Smrg *
147ec681f3Smrg * The above copyright notice and this permission notice (including the
157ec681f3Smrg * next paragraph) shall be included in all copies or substantial portions
167ec681f3Smrg * of the Software.
177ec681f3Smrg *
187ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
197ec681f3Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
207ec681f3Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
217ec681f3Smrg * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
227ec681f3Smrg * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
237ec681f3Smrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
247ec681f3Smrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
257ec681f3Smrg *
267ec681f3Smrg **************************************************************************/
277ec681f3Smrg/*
287ec681f3Smrg * Author: Keith Whitwell <keithw@vmware.com>
297ec681f3Smrg * Author: Jakob Bornecrantz <wallbraker@gmail.com>
307ec681f3Smrg */
317ec681f3Smrg
327ec681f3Smrg#include "dri_screen.h"
337ec681f3Smrg#include "dri_context.h"
347ec681f3Smrg#include "dri_drawable.h"
357ec681f3Smrg
367ec681f3Smrg#include "pipe/p_screen.h"
377ec681f3Smrg#include "util/format/u_format.h"
387ec681f3Smrg#include "util/u_memory.h"
397ec681f3Smrg#include "util/u_inlines.h"
407ec681f3Smrg
417ec681f3Smrgstatic uint32_t drifb_ID = 0;
427ec681f3Smrg
437ec681f3Smrgstatic bool
447ec681f3Smrgdri_st_framebuffer_validate(struct st_context_iface *stctx,
457ec681f3Smrg                            struct st_framebuffer_iface *stfbi,
467ec681f3Smrg                            const enum st_attachment_type *statts,
477ec681f3Smrg                            unsigned count,
487ec681f3Smrg                            struct pipe_resource **out)
497ec681f3Smrg{
507ec681f3Smrg   struct dri_context *ctx = (struct dri_context *)stctx->st_manager_private;
517ec681f3Smrg   struct dri_drawable *drawable =
527ec681f3Smrg      (struct dri_drawable *) stfbi->st_manager_private;
537ec681f3Smrg   struct dri_screen *screen = dri_screen(drawable->sPriv);
547ec681f3Smrg   unsigned statt_mask, new_mask;
557ec681f3Smrg   bool new_stamp;
567ec681f3Smrg   int i;
577ec681f3Smrg   unsigned int lastStamp;
587ec681f3Smrg   struct pipe_resource **textures =
597ec681f3Smrg      drawable->stvis.samples > 1 ? drawable->msaa_textures
607ec681f3Smrg                                  : drawable->textures;
617ec681f3Smrg
627ec681f3Smrg   statt_mask = 0x0;
637ec681f3Smrg   for (i = 0; i < count; i++)
647ec681f3Smrg      statt_mask |= (1 << statts[i]);
657ec681f3Smrg
667ec681f3Smrg   /* record newly allocated textures */
677ec681f3Smrg   new_mask = (statt_mask & ~drawable->texture_mask);
687ec681f3Smrg
697ec681f3Smrg   /*
707ec681f3Smrg    * dPriv->dri2.stamp is the server stamp.  dPriv->lastStamp is the
717ec681f3Smrg    * client stamp.  It has the value of the server stamp when last
727ec681f3Smrg    * checked.
737ec681f3Smrg    */
747ec681f3Smrg   do {
757ec681f3Smrg      lastStamp = drawable->dPriv->lastStamp;
767ec681f3Smrg      new_stamp = (drawable->texture_stamp != lastStamp);
777ec681f3Smrg
787ec681f3Smrg      if (new_stamp || new_mask || screen->broken_invalidate) {
797ec681f3Smrg         if (new_stamp && drawable->update_drawable_info)
807ec681f3Smrg            drawable->update_drawable_info(drawable);
817ec681f3Smrg
827ec681f3Smrg         drawable->allocate_textures(ctx, drawable, statts, count);
837ec681f3Smrg
847ec681f3Smrg         /* add existing textures */
857ec681f3Smrg         for (i = 0; i < ST_ATTACHMENT_COUNT; i++) {
867ec681f3Smrg            if (textures[i])
877ec681f3Smrg               statt_mask |= (1 << i);
887ec681f3Smrg         }
897ec681f3Smrg
907ec681f3Smrg         drawable->texture_stamp = lastStamp;
917ec681f3Smrg         drawable->texture_mask = statt_mask;
927ec681f3Smrg      }
937ec681f3Smrg   } while (lastStamp != drawable->dPriv->lastStamp);
947ec681f3Smrg
957ec681f3Smrg   /* Flush the pending set_damage_region request. */
967ec681f3Smrg   struct pipe_screen *pscreen = screen->base.screen;
977ec681f3Smrg
987ec681f3Smrg   if (new_mask & (1 << ST_ATTACHMENT_BACK_LEFT) &&
997ec681f3Smrg       pscreen->set_damage_region) {
1007ec681f3Smrg      struct pipe_resource *resource = textures[ST_ATTACHMENT_BACK_LEFT];
1017ec681f3Smrg
1027ec681f3Smrg      pscreen->set_damage_region(pscreen, resource,
1037ec681f3Smrg                                 drawable->num_damage_rects,
1047ec681f3Smrg                                 drawable->damage_rects);
1057ec681f3Smrg   }
1067ec681f3Smrg
1077ec681f3Smrg   if (!out)
1087ec681f3Smrg      return true;
1097ec681f3Smrg
1107ec681f3Smrg   /* Set the window-system buffers for the gallium frontend. */
1117ec681f3Smrg   for (i = 0; i < count; i++)
1127ec681f3Smrg      pipe_resource_reference(&out[i], textures[statts[i]]);
1137ec681f3Smrg
1147ec681f3Smrg   return true;
1157ec681f3Smrg}
1167ec681f3Smrg
1177ec681f3Smrgstatic bool
1187ec681f3Smrgdri_st_framebuffer_flush_front(struct st_context_iface *stctx,
1197ec681f3Smrg                               struct st_framebuffer_iface *stfbi,
1207ec681f3Smrg                               enum st_attachment_type statt)
1217ec681f3Smrg{
1227ec681f3Smrg   struct dri_context *ctx = (struct dri_context *)stctx->st_manager_private;
1237ec681f3Smrg   struct dri_drawable *drawable =
1247ec681f3Smrg      (struct dri_drawable *) stfbi->st_manager_private;
1257ec681f3Smrg
1267ec681f3Smrg   /* XXX remove this and just set the correct one on the framebuffer */
1277ec681f3Smrg   return drawable->flush_frontbuffer(ctx, drawable, statt);
1287ec681f3Smrg}
1297ec681f3Smrg
1307ec681f3Smrg/**
1317ec681f3Smrg * The gallium frontend framebuffer interface flush_swapbuffers callback
1327ec681f3Smrg */
1337ec681f3Smrgstatic bool
1347ec681f3Smrgdri_st_framebuffer_flush_swapbuffers(struct st_context_iface *stctx,
1357ec681f3Smrg                                     struct st_framebuffer_iface *stfbi)
1367ec681f3Smrg{
1377ec681f3Smrg   struct dri_context *ctx = (struct dri_context *)stctx->st_manager_private;
1387ec681f3Smrg   struct dri_drawable *drawable =
1397ec681f3Smrg      (struct dri_drawable *) stfbi->st_manager_private;
1407ec681f3Smrg
1417ec681f3Smrg   if (drawable->flush_swapbuffers)
1427ec681f3Smrg      drawable->flush_swapbuffers(ctx, drawable);
1437ec681f3Smrg
1447ec681f3Smrg   return true;
1457ec681f3Smrg}
1467ec681f3Smrg
1477ec681f3Smrg/**
1487ec681f3Smrg * This is called when we need to set up GL rendering to a new X window.
1497ec681f3Smrg */
1507ec681f3Smrgbool
1517ec681f3Smrgdri_create_buffer(__DRIscreen * sPriv,
1527ec681f3Smrg		  __DRIdrawable * dPriv,
1537ec681f3Smrg		  const struct gl_config * visual, bool isPixmap)
1547ec681f3Smrg{
1557ec681f3Smrg   struct dri_screen *screen = sPriv->driverPrivate;
1567ec681f3Smrg   struct dri_drawable *drawable = NULL;
1577ec681f3Smrg
1587ec681f3Smrg   if (isPixmap)
1597ec681f3Smrg      goto fail;		       /* not implemented */
1607ec681f3Smrg
1617ec681f3Smrg   drawable = CALLOC_STRUCT(dri_drawable);
1627ec681f3Smrg   if (drawable == NULL)
1637ec681f3Smrg      goto fail;
1647ec681f3Smrg
1657ec681f3Smrg   dri_fill_st_visual(&drawable->stvis, screen, visual);
1667ec681f3Smrg
1677ec681f3Smrg   /* setup the st_framebuffer_iface */
1687ec681f3Smrg   drawable->base.visual = &drawable->stvis;
1697ec681f3Smrg   drawable->base.flush_front = dri_st_framebuffer_flush_front;
1707ec681f3Smrg   drawable->base.validate = dri_st_framebuffer_validate;
1717ec681f3Smrg   drawable->base.flush_swapbuffers = dri_st_framebuffer_flush_swapbuffers;
1727ec681f3Smrg   drawable->base.st_manager_private = (void *) drawable;
1737ec681f3Smrg
1747ec681f3Smrg   drawable->screen = screen;
1757ec681f3Smrg   drawable->sPriv = sPriv;
1767ec681f3Smrg   drawable->dPriv = dPriv;
1777ec681f3Smrg
1787ec681f3Smrg   dPriv->driverPrivate = (void *)drawable;
1797ec681f3Smrg   p_atomic_set(&drawable->base.stamp, 1);
1807ec681f3Smrg   drawable->base.ID = p_atomic_inc_return(&drifb_ID);
1817ec681f3Smrg   drawable->base.state_manager = &screen->base;
1827ec681f3Smrg
1837ec681f3Smrg   return true;
1847ec681f3Smrgfail:
1857ec681f3Smrg   FREE(drawable);
1867ec681f3Smrg   return false;
1877ec681f3Smrg}
1887ec681f3Smrg
1897ec681f3Smrgvoid
1907ec681f3Smrgdri_destroy_buffer(__DRIdrawable * dPriv)
1917ec681f3Smrg{
1927ec681f3Smrg   struct dri_drawable *drawable = dri_drawable(dPriv);
1937ec681f3Smrg   struct dri_screen *screen = drawable->screen;
1947ec681f3Smrg   struct st_api *stapi = screen->st_api;
1957ec681f3Smrg   int i;
1967ec681f3Smrg
1977ec681f3Smrg   for (i = 0; i < ST_ATTACHMENT_COUNT; i++)
1987ec681f3Smrg      pipe_resource_reference(&drawable->textures[i], NULL);
1997ec681f3Smrg   for (i = 0; i < ST_ATTACHMENT_COUNT; i++)
2007ec681f3Smrg      pipe_resource_reference(&drawable->msaa_textures[i], NULL);
2017ec681f3Smrg
2027ec681f3Smrg   screen->base.screen->fence_reference(screen->base.screen,
2037ec681f3Smrg         &drawable->throttle_fence, NULL);
2047ec681f3Smrg
2057ec681f3Smrg   /* Notify the st manager that this drawable is no longer valid */
2067ec681f3Smrg   stapi->destroy_drawable(stapi, &drawable->base);
2077ec681f3Smrg
2087ec681f3Smrg   FREE(drawable->damage_rects);
2097ec681f3Smrg   FREE(drawable);
2107ec681f3Smrg}
2117ec681f3Smrg
2127ec681f3Smrg/**
2137ec681f3Smrg * Validate the texture at an attachment.  Allocate the texture if it does not
2147ec681f3Smrg * exist.  Used by the TFP extension.
2157ec681f3Smrg */
2167ec681f3Smrgstatic void
2177ec681f3Smrgdri_drawable_validate_att(struct dri_context *ctx,
2187ec681f3Smrg                          struct dri_drawable *drawable,
2197ec681f3Smrg                          enum st_attachment_type statt)
2207ec681f3Smrg{
2217ec681f3Smrg   enum st_attachment_type statts[ST_ATTACHMENT_COUNT];
2227ec681f3Smrg   unsigned i, count = 0;
2237ec681f3Smrg
2247ec681f3Smrg   /* check if buffer already exists */
2257ec681f3Smrg   if (drawable->texture_mask & (1 << statt))
2267ec681f3Smrg      return;
2277ec681f3Smrg
2287ec681f3Smrg   /* make sure DRI2 does not destroy existing buffers */
2297ec681f3Smrg   for (i = 0; i < ST_ATTACHMENT_COUNT; i++) {
2307ec681f3Smrg      if (drawable->texture_mask & (1 << i)) {
2317ec681f3Smrg         statts[count++] = i;
2327ec681f3Smrg      }
2337ec681f3Smrg   }
2347ec681f3Smrg   statts[count++] = statt;
2357ec681f3Smrg
2367ec681f3Smrg   drawable->texture_stamp = drawable->dPriv->lastStamp - 1;
2377ec681f3Smrg
2387ec681f3Smrg   drawable->base.validate(ctx->st, &drawable->base, statts, count, NULL);
2397ec681f3Smrg}
2407ec681f3Smrg
2417ec681f3Smrg/**
2427ec681f3Smrg * These are used for GLX_EXT_texture_from_pixmap
2437ec681f3Smrg */
2447ec681f3Smrgstatic void
2457ec681f3Smrgdri_set_tex_buffer2(__DRIcontext *pDRICtx, GLint target,
2467ec681f3Smrg                    GLint format, __DRIdrawable *dPriv)
2477ec681f3Smrg{
2487ec681f3Smrg   struct dri_context *ctx = dri_context(pDRICtx);
2497ec681f3Smrg   struct st_context_iface *st = ctx->st;
2507ec681f3Smrg   struct dri_drawable *drawable = dri_drawable(dPriv);
2517ec681f3Smrg   struct pipe_resource *pt;
2527ec681f3Smrg
2537ec681f3Smrg   if (st->thread_finish)
2547ec681f3Smrg      st->thread_finish(st);
2557ec681f3Smrg
2567ec681f3Smrg   dri_drawable_validate_att(ctx, drawable, ST_ATTACHMENT_FRONT_LEFT);
2577ec681f3Smrg
2587ec681f3Smrg   /* Use the pipe resource associated with the X drawable */
2597ec681f3Smrg   pt = drawable->textures[ST_ATTACHMENT_FRONT_LEFT];
2607ec681f3Smrg
2617ec681f3Smrg   if (pt) {
2627ec681f3Smrg      enum pipe_format internal_format = pt->format;
2637ec681f3Smrg
2647ec681f3Smrg      if (format == __DRI_TEXTURE_FORMAT_RGB)  {
2657ec681f3Smrg         /* only need to cover the formats recognized by dri_fill_st_visual */
2667ec681f3Smrg         switch (internal_format) {
2677ec681f3Smrg         case PIPE_FORMAT_R16G16B16A16_FLOAT:
2687ec681f3Smrg            internal_format = PIPE_FORMAT_R16G16B16X16_FLOAT;
2697ec681f3Smrg            break;
2707ec681f3Smrg         case PIPE_FORMAT_B10G10R10A2_UNORM:
2717ec681f3Smrg            internal_format = PIPE_FORMAT_B10G10R10X2_UNORM;
2727ec681f3Smrg            break;
2737ec681f3Smrg         case PIPE_FORMAT_R10G10B10A2_UNORM:
2747ec681f3Smrg            internal_format = PIPE_FORMAT_R10G10B10X2_UNORM;
2757ec681f3Smrg            break;
2767ec681f3Smrg         case PIPE_FORMAT_BGRA8888_UNORM:
2777ec681f3Smrg            internal_format = PIPE_FORMAT_BGRX8888_UNORM;
2787ec681f3Smrg            break;
2797ec681f3Smrg         case PIPE_FORMAT_ARGB8888_UNORM:
2807ec681f3Smrg            internal_format = PIPE_FORMAT_XRGB8888_UNORM;
2817ec681f3Smrg            break;
2827ec681f3Smrg         default:
2837ec681f3Smrg            break;
2847ec681f3Smrg         }
2857ec681f3Smrg      }
2867ec681f3Smrg
2877ec681f3Smrg      drawable->update_tex_buffer(drawable, ctx, pt);
2887ec681f3Smrg
2897ec681f3Smrg      ctx->st->teximage(ctx->st,
2907ec681f3Smrg            (target == GL_TEXTURE_2D) ? ST_TEXTURE_2D : ST_TEXTURE_RECT,
2917ec681f3Smrg            0, internal_format, pt, false);
2927ec681f3Smrg   }
2937ec681f3Smrg}
2947ec681f3Smrg
2957ec681f3Smrgstatic void
2967ec681f3Smrgdri_set_tex_buffer(__DRIcontext *pDRICtx, GLint target,
2977ec681f3Smrg                   __DRIdrawable *dPriv)
2987ec681f3Smrg{
2997ec681f3Smrg   dri_set_tex_buffer2(pDRICtx, target, __DRI_TEXTURE_FORMAT_RGBA, dPriv);
3007ec681f3Smrg}
3017ec681f3Smrg
3027ec681f3Smrgconst __DRItexBufferExtension driTexBufferExtension = {
3037ec681f3Smrg   .base = { __DRI_TEX_BUFFER, 2 },
3047ec681f3Smrg
3057ec681f3Smrg   .setTexBuffer       = dri_set_tex_buffer,
3067ec681f3Smrg   .setTexBuffer2      = dri_set_tex_buffer2,
3077ec681f3Smrg   .releaseTexBuffer   = NULL,
3087ec681f3Smrg};
3097ec681f3Smrg
3107ec681f3Smrg/**
3117ec681f3Smrg * Get the format and binding of an attachment.
3127ec681f3Smrg */
3137ec681f3Smrgvoid
3147ec681f3Smrgdri_drawable_get_format(struct dri_drawable *drawable,
3157ec681f3Smrg                        enum st_attachment_type statt,
3167ec681f3Smrg                        enum pipe_format *format,
3177ec681f3Smrg                        unsigned *bind)
3187ec681f3Smrg{
3197ec681f3Smrg   switch (statt) {
3207ec681f3Smrg   case ST_ATTACHMENT_FRONT_LEFT:
3217ec681f3Smrg   case ST_ATTACHMENT_BACK_LEFT:
3227ec681f3Smrg   case ST_ATTACHMENT_FRONT_RIGHT:
3237ec681f3Smrg   case ST_ATTACHMENT_BACK_RIGHT:
3247ec681f3Smrg      /* Other pieces of the driver stack get confused and behave incorrectly
3257ec681f3Smrg       * when they get an sRGB drawable. st/mesa receives "drawable->stvis"
3267ec681f3Smrg       * though other means and handles it correctly, so we don't really need
3277ec681f3Smrg       * to use an sRGB format here.
3287ec681f3Smrg       */
3297ec681f3Smrg      *format = util_format_linear(drawable->stvis.color_format);
3307ec681f3Smrg      *bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW;
3317ec681f3Smrg      break;
3327ec681f3Smrg   case ST_ATTACHMENT_DEPTH_STENCIL:
3337ec681f3Smrg      *format = drawable->stvis.depth_stencil_format;
3347ec681f3Smrg      *bind = PIPE_BIND_DEPTH_STENCIL; /* XXX sampler? */
3357ec681f3Smrg      break;
3367ec681f3Smrg   default:
3377ec681f3Smrg      *format = PIPE_FORMAT_NONE;
3387ec681f3Smrg      *bind = 0;
3397ec681f3Smrg      break;
3407ec681f3Smrg   }
3417ec681f3Smrg}
3427ec681f3Smrg
3437ec681f3Smrgvoid
3447ec681f3Smrgdri_pipe_blit(struct pipe_context *pipe,
3457ec681f3Smrg              struct pipe_resource *dst,
3467ec681f3Smrg              struct pipe_resource *src)
3477ec681f3Smrg{
3487ec681f3Smrg   struct pipe_blit_info blit;
3497ec681f3Smrg
3507ec681f3Smrg   if (!dst || !src)
3517ec681f3Smrg      return;
3527ec681f3Smrg
3537ec681f3Smrg   /* From the GL spec, version 4.2, section 4.1.11 (Additional Multisample
3547ec681f3Smrg    *  Fragment Operations):
3557ec681f3Smrg    *
3567ec681f3Smrg    *      If a framebuffer object is not bound, after all operations have
3577ec681f3Smrg    *      been completed on the multisample buffer, the sample values for
3587ec681f3Smrg    *      each color in the multisample buffer are combined to produce a
3597ec681f3Smrg    *      single color value, and that value is written into the
3607ec681f3Smrg    *      corresponding color buffers selected by DrawBuffer or
3617ec681f3Smrg    *      DrawBuffers. An implementation may defer the writing of the color
3627ec681f3Smrg    *      buffers until a later time, but the state of the framebuffer must
3637ec681f3Smrg    *      behave as if the color buffers were updated as each fragment was
3647ec681f3Smrg    *      processed. The method of combination is not specified. If the
3657ec681f3Smrg    *      framebuffer contains sRGB values, then it is recommended that the
3667ec681f3Smrg    *      an average of sample values is computed in a linearized space, as
3677ec681f3Smrg    *      for blending (see section 4.1.7).
3687ec681f3Smrg    *
3697ec681f3Smrg    * In other words, to do a resolve operation in a linear space, we have
3707ec681f3Smrg    * to set sRGB formats if the original resources were sRGB, so don't use
3717ec681f3Smrg    * util_format_linear.
3727ec681f3Smrg    */
3737ec681f3Smrg
3747ec681f3Smrg   memset(&blit, 0, sizeof(blit));
3757ec681f3Smrg   blit.dst.resource = dst;
3767ec681f3Smrg   blit.dst.box.width = dst->width0;
3777ec681f3Smrg   blit.dst.box.height = dst->height0;
3787ec681f3Smrg   blit.dst.box.depth = 1;
3797ec681f3Smrg   blit.dst.format = dst->format;
3807ec681f3Smrg   blit.src.resource = src;
3817ec681f3Smrg   blit.src.box.width = src->width0;
3827ec681f3Smrg   blit.src.box.height = src->height0;
3837ec681f3Smrg   blit.src.box.depth = 1;
3847ec681f3Smrg   blit.src.format = src->format;
3857ec681f3Smrg   blit.mask = PIPE_MASK_RGBA;
3867ec681f3Smrg   blit.filter = PIPE_TEX_FILTER_NEAREST;
3877ec681f3Smrg
3887ec681f3Smrg   pipe->blit(pipe, &blit);
3897ec681f3Smrg}
3907ec681f3Smrg
3917ec681f3Smrgstatic void
3927ec681f3Smrgdri_postprocessing(struct dri_context *ctx,
3937ec681f3Smrg                   struct dri_drawable *drawable,
3947ec681f3Smrg                   enum st_attachment_type att)
3957ec681f3Smrg{
3967ec681f3Smrg   struct pipe_resource *src = drawable->textures[att];
3977ec681f3Smrg   struct pipe_resource *zsbuf = drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL];
3987ec681f3Smrg
3997ec681f3Smrg   if (ctx->pp && src)
4007ec681f3Smrg      pp_run(ctx->pp, src, src, zsbuf);
4017ec681f3Smrg}
4027ec681f3Smrg
4037ec681f3Smrgstruct notify_before_flush_cb_args {
4047ec681f3Smrg   struct dri_context *ctx;
4057ec681f3Smrg   struct dri_drawable *drawable;
4067ec681f3Smrg   unsigned flags;
4077ec681f3Smrg   enum __DRI2throttleReason reason;
4087ec681f3Smrg   bool swap_msaa_buffers;
4097ec681f3Smrg};
4107ec681f3Smrg
4117ec681f3Smrgstatic void
4127ec681f3Smrgnotify_before_flush_cb(void* _args)
4137ec681f3Smrg{
4147ec681f3Smrg   struct notify_before_flush_cb_args *args = (struct notify_before_flush_cb_args *) _args;
4157ec681f3Smrg   struct st_context_iface *st = args->ctx->st;
4167ec681f3Smrg   struct pipe_context *pipe = st->pipe;
4177ec681f3Smrg
4187ec681f3Smrg   if (args->drawable->stvis.samples > 1 &&
4197ec681f3Smrg       (args->reason == __DRI2_THROTTLE_SWAPBUFFER ||
4207ec681f3Smrg        args->reason == __DRI2_THROTTLE_COPYSUBBUFFER)) {
4217ec681f3Smrg      /* Resolve the MSAA back buffer. */
4227ec681f3Smrg      dri_pipe_blit(st->pipe,
4237ec681f3Smrg                    args->drawable->textures[ST_ATTACHMENT_BACK_LEFT],
4247ec681f3Smrg                    args->drawable->msaa_textures[ST_ATTACHMENT_BACK_LEFT]);
4257ec681f3Smrg
4267ec681f3Smrg      if (args->reason == __DRI2_THROTTLE_SWAPBUFFER &&
4277ec681f3Smrg          args->drawable->msaa_textures[ST_ATTACHMENT_FRONT_LEFT] &&
4287ec681f3Smrg          args->drawable->msaa_textures[ST_ATTACHMENT_BACK_LEFT]) {
4297ec681f3Smrg         args->swap_msaa_buffers = true;
4307ec681f3Smrg      }
4317ec681f3Smrg
4327ec681f3Smrg      /* FRONT_LEFT is resolved in drawable->flush_frontbuffer. */
4337ec681f3Smrg   }
4347ec681f3Smrg
4357ec681f3Smrg   dri_postprocessing(args->ctx, args->drawable, ST_ATTACHMENT_BACK_LEFT);
4367ec681f3Smrg
4377ec681f3Smrg   if (pipe->invalidate_resource &&
4387ec681f3Smrg       (args->flags & __DRI2_FLUSH_INVALIDATE_ANCILLARY)) {
4397ec681f3Smrg      if (args->drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL])
4407ec681f3Smrg         pipe->invalidate_resource(pipe, args->drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL]);
4417ec681f3Smrg      if (args->drawable->msaa_textures[ST_ATTACHMENT_DEPTH_STENCIL])
4427ec681f3Smrg         pipe->invalidate_resource(pipe, args->drawable->msaa_textures[ST_ATTACHMENT_DEPTH_STENCIL]);
4437ec681f3Smrg   }
4447ec681f3Smrg
4457ec681f3Smrg   if (args->ctx->hud) {
4467ec681f3Smrg      hud_run(args->ctx->hud, args->ctx->st->cso_context,
4477ec681f3Smrg              args->drawable->textures[ST_ATTACHMENT_BACK_LEFT]);
4487ec681f3Smrg   }
4497ec681f3Smrg
4507ec681f3Smrg   pipe->flush_resource(pipe, args->drawable->textures[ST_ATTACHMENT_BACK_LEFT]);
4517ec681f3Smrg}
4527ec681f3Smrg
4537ec681f3Smrg/**
4547ec681f3Smrg * DRI2 flush extension, the flush_with_flags function.
4557ec681f3Smrg *
4567ec681f3Smrg * \param context           the context
4577ec681f3Smrg * \param drawable          the drawable to flush
4587ec681f3Smrg * \param flags             a combination of _DRI2_FLUSH_xxx flags
4597ec681f3Smrg * \param throttle_reason   the reason for throttling, 0 = no throttling
4607ec681f3Smrg */
4617ec681f3Smrgvoid
4627ec681f3Smrgdri_flush(__DRIcontext *cPriv,
4637ec681f3Smrg          __DRIdrawable *dPriv,
4647ec681f3Smrg          unsigned flags,
4657ec681f3Smrg          enum __DRI2throttleReason reason)
4667ec681f3Smrg{
4677ec681f3Smrg   struct dri_context *ctx = dri_context(cPriv);
4687ec681f3Smrg   struct dri_drawable *drawable = dri_drawable(dPriv);
4697ec681f3Smrg   struct st_context_iface *st;
4707ec681f3Smrg   unsigned flush_flags;
4717ec681f3Smrg   struct notify_before_flush_cb_args args = { 0 };
4727ec681f3Smrg
4737ec681f3Smrg   if (!ctx) {
4747ec681f3Smrg      assert(0);
4757ec681f3Smrg      return;
4767ec681f3Smrg   }
4777ec681f3Smrg
4787ec681f3Smrg   st = ctx->st;
4797ec681f3Smrg   if (st->thread_finish)
4807ec681f3Smrg      st->thread_finish(st);
4817ec681f3Smrg
4827ec681f3Smrg   if (drawable) {
4837ec681f3Smrg      /* prevent recursion */
4847ec681f3Smrg      if (drawable->flushing)
4857ec681f3Smrg         return;
4867ec681f3Smrg
4877ec681f3Smrg      drawable->flushing = true;
4887ec681f3Smrg   }
4897ec681f3Smrg   else {
4907ec681f3Smrg      flags &= ~__DRI2_FLUSH_DRAWABLE;
4917ec681f3Smrg   }
4927ec681f3Smrg
4937ec681f3Smrg   if ((flags & __DRI2_FLUSH_DRAWABLE) &&
4947ec681f3Smrg       drawable->textures[ST_ATTACHMENT_BACK_LEFT]) {
4957ec681f3Smrg      /* We can't do operations on the back buffer here, because there
4967ec681f3Smrg       * may be some pending operations that will get flushed by the
4977ec681f3Smrg       * call to st->flush (eg: FLUSH_VERTICES).
4987ec681f3Smrg       * Instead we register a callback to be notified when all operations
4997ec681f3Smrg       * have been submitted but before the call to st_flush.
5007ec681f3Smrg       */
5017ec681f3Smrg      args.ctx = ctx;
5027ec681f3Smrg      args.drawable = drawable;
5037ec681f3Smrg      args.flags = flags;
5047ec681f3Smrg      args.reason = reason;
5057ec681f3Smrg   }
5067ec681f3Smrg
5077ec681f3Smrg   flush_flags = 0;
5087ec681f3Smrg   if (flags & __DRI2_FLUSH_CONTEXT)
5097ec681f3Smrg      flush_flags |= ST_FLUSH_FRONT;
5107ec681f3Smrg   if (reason == __DRI2_THROTTLE_SWAPBUFFER)
5117ec681f3Smrg      flush_flags |= ST_FLUSH_END_OF_FRAME;
5127ec681f3Smrg
5137ec681f3Smrg   /* Flush the context and throttle if needed. */
5147ec681f3Smrg   if (dri_screen(ctx->sPriv)->throttle &&
5157ec681f3Smrg       drawable &&
5167ec681f3Smrg       (reason == __DRI2_THROTTLE_SWAPBUFFER ||
5177ec681f3Smrg        reason == __DRI2_THROTTLE_FLUSHFRONT)) {
5187ec681f3Smrg
5197ec681f3Smrg      struct pipe_screen *screen = drawable->screen->base.screen;
5207ec681f3Smrg      struct pipe_fence_handle *new_fence = NULL;
5217ec681f3Smrg
5227ec681f3Smrg      st->flush(st, flush_flags, &new_fence, args.ctx ? notify_before_flush_cb : NULL, &args);
5237ec681f3Smrg
5247ec681f3Smrg      /* throttle on the previous fence */
5257ec681f3Smrg      if (drawable->throttle_fence) {
5267ec681f3Smrg         screen->fence_finish(screen, NULL, drawable->throttle_fence, PIPE_TIMEOUT_INFINITE);
5277ec681f3Smrg         screen->fence_reference(screen, &drawable->throttle_fence, NULL);
5287ec681f3Smrg      }
5297ec681f3Smrg      drawable->throttle_fence = new_fence;
5307ec681f3Smrg   }
5317ec681f3Smrg   else if (flags & (__DRI2_FLUSH_DRAWABLE | __DRI2_FLUSH_CONTEXT)) {
5327ec681f3Smrg      st->flush(st, flush_flags, NULL, args.ctx ? notify_before_flush_cb : NULL, &args);
5337ec681f3Smrg   }
5347ec681f3Smrg
5357ec681f3Smrg   if (drawable) {
5367ec681f3Smrg      drawable->flushing = false;
5377ec681f3Smrg   }
5387ec681f3Smrg
5397ec681f3Smrg   /* Swap the MSAA front and back buffers, so that reading
5407ec681f3Smrg    * from the front buffer after SwapBuffers returns what was
5417ec681f3Smrg    * in the back buffer.
5427ec681f3Smrg    */
5437ec681f3Smrg   if (args.swap_msaa_buffers) {
5447ec681f3Smrg      struct pipe_resource *tmp =
5457ec681f3Smrg         drawable->msaa_textures[ST_ATTACHMENT_FRONT_LEFT];
5467ec681f3Smrg
5477ec681f3Smrg      drawable->msaa_textures[ST_ATTACHMENT_FRONT_LEFT] =
5487ec681f3Smrg         drawable->msaa_textures[ST_ATTACHMENT_BACK_LEFT];
5497ec681f3Smrg      drawable->msaa_textures[ST_ATTACHMENT_BACK_LEFT] = tmp;
5507ec681f3Smrg
5517ec681f3Smrg      /* Now that we have swapped the buffers, this tells the gallium
5527ec681f3Smrg       * frontend to revalidate the framebuffer.
5537ec681f3Smrg       */
5547ec681f3Smrg      p_atomic_inc(&drawable->base.stamp);
5557ec681f3Smrg   }
5567ec681f3Smrg}
5577ec681f3Smrg
5587ec681f3Smrg/**
5597ec681f3Smrg * dri_throttle - A DRI2ThrottleExtension throttling function.
5607ec681f3Smrg */
5617ec681f3Smrgstatic void
5627ec681f3Smrgdri_throttle(__DRIcontext *cPriv, __DRIdrawable *dPriv,
5637ec681f3Smrg             enum __DRI2throttleReason reason)
5647ec681f3Smrg{
5657ec681f3Smrg   dri_flush(cPriv, dPriv, 0, reason);
5667ec681f3Smrg}
5677ec681f3Smrg
5687ec681f3Smrg
5697ec681f3Smrgconst __DRI2throttleExtension dri2ThrottleExtension = {
5707ec681f3Smrg    .base = { __DRI2_THROTTLE, 1 },
5717ec681f3Smrg
5727ec681f3Smrg    .throttle          = dri_throttle,
5737ec681f3Smrg};
5747ec681f3Smrg
5757ec681f3Smrg
5767ec681f3Smrg/* vim: set sw=3 ts=8 sts=3 expandtab: */
577