[Mesa-dev] [PATCH] gallium/swr: Resource management

BruceCherniak bruce.cherniak at intel.com
Thu Mar 10 01:30:00 UTC 2016


From: Bruce Cherniak <bruce.cherniak at intel.com>

Better tracking of resource state and synchronization.
A follow on commit will clean up resource functions into a new
swr_resource.cpp file.
---
 src/gallium/drivers/swr/swr_clear.cpp   |    4 +-
 src/gallium/drivers/swr/swr_context.cpp |  103 ++++++++++++-------------------
 src/gallium/drivers/swr/swr_draw.cpp    |   64 +++++++++++++------
 src/gallium/drivers/swr/swr_fence.cpp   |   29 ++++++---
 src/gallium/drivers/swr/swr_fence.h     |    6 +-
 src/gallium/drivers/swr/swr_query.cpp   |    6 +-
 src/gallium/drivers/swr/swr_resource.h  |   54 +++++++++++++++-
 src/gallium/drivers/swr/swr_screen.cpp  |   57 ++++++++---------
 src/gallium/drivers/swr/swr_state.cpp   |   83 ++++++++++++++++++++++---
 src/gallium/drivers/swr/swr_state.h     |    2 +-
 10 files changed, 265 insertions(+), 143 deletions(-)

diff --git a/src/gallium/drivers/swr/swr_clear.cpp b/src/gallium/drivers/swr/swr_clear.cpp
index 9027f84..103bca9 100644
--- a/src/gallium/drivers/swr/swr_clear.cpp
+++ b/src/gallium/drivers/swr/swr_clear.cpp
@@ -40,7 +40,7 @@ swr_clear(struct pipe_context *pipe,
       return;
 
    if (ctx->dirty)
-      swr_update_derived(ctx);
+      swr_update_derived(pipe);
 
 /* Update clearMask/targetMask */
 #if 0 /* XXX SWR currently only clears SWR_ATTACHMENT_COLOR0, don't bother   \
@@ -76,7 +76,7 @@ swr_clear(struct pipe_context *pipe,
    vp.height = ctx->framebuffer.height;
    SwrSetViewports(ctx->swrContext, 1, &vp, NULL);
 
-	swr_update_draw_context(ctx);
+   swr_update_draw_context(ctx);
    SwrClearRenderTarget(ctx->swrContext, clearMask, color->f, depth, stencil);
 }
 
diff --git a/src/gallium/drivers/swr/swr_context.cpp b/src/gallium/drivers/swr/swr_context.cpp
index 0e7ebb7..c8cb145 100644
--- a/src/gallium/drivers/swr/swr_context.cpp
+++ b/src/gallium/drivers/swr/swr_context.cpp
@@ -36,6 +36,7 @@ extern "C" {
 #include "swr_resource.h"
 #include "swr_scratch.h"
 #include "swr_query.h"
+#include "swr_fence.h"
 
 #include "api.h"
 #include "backend.h"
@@ -85,36 +86,10 @@ swr_surface_destroy(struct pipe_context *pipe, struct pipe_surface *surf)
    assert(surf->texture);
    struct pipe_resource *resource = surf->texture;
 
-   /* If the surface being destroyed is a current render target,
-    * call StoreTiles to resolve the hotTile state then set attachment
-    * to NULL.
-    */
-   if (resource->bind & (PIPE_BIND_RENDER_TARGET | PIPE_BIND_DEPTH_STENCIL
-                         | PIPE_BIND_DISPLAY_TARGET)) {
-      struct swr_context *ctx = swr_context(pipe);
-      struct swr_resource *spr = swr_resource(resource);
-		swr_draw_context *pDC = &ctx->swrDC;
-		SWR_SURFACE_STATE *renderTargets = pDC->renderTargets;
-      for (uint32_t i = 0; i < SWR_NUM_ATTACHMENTS; i++)
-         if (renderTargets[i].pBaseAddress == spr->swr.pBaseAddress) {
-            swr_store_render_target(ctx, i, SWR_TILE_RESOLVED);
-
-            /*
-             * Mesa thinks depth/stencil are fused, so we'll never get an
-             * explicit resource for stencil.  So, if checking depth, then
-             * also check for stencil.
-             */
-            if (spr->has_stencil && (i == SWR_ATTACHMENT_DEPTH)) {
-               swr_store_render_target(
-                  ctx, SWR_ATTACHMENT_STENCIL, SWR_TILE_RESOLVED);
-            }
-
-            SwrWaitForIdle(ctx->swrContext);
-            break;
-         }
-   }
+   /* If the resource has been drawn to, store tiles. */
+   swr_store_dirty_resource(pipe, resource, SWR_TILE_RESOLVED);
 
-   pipe_resource_reference(&surf->texture, NULL);
+   pipe_resource_reference(&resource, NULL);
    FREE(surf);
 }
 
@@ -127,6 +102,7 @@ swr_transfer_map(struct pipe_context *pipe,
                  const struct pipe_box *box,
                  struct pipe_transfer **transfer)
 {
+   struct swr_screen *screen = swr_screen(pipe->screen);
    struct swr_resource *spr = swr_resource(resource);
    struct pipe_transfer *pt;
    enum pipe_format format = resource->format;
@@ -134,30 +110,28 @@ swr_transfer_map(struct pipe_context *pipe,
    assert(resource);
    assert(level <= resource->last_level);
 
-   /*
-    * If mapping any attached rendertarget, store tiles and wait for idle
-    * before giving CPU access to the surface.
-    * (set postStoreTileState to SWR_TILE_INVALID so tiles are reloaded)
-    */
-   if (resource->bind & (PIPE_BIND_RENDER_TARGET | PIPE_BIND_DEPTH_STENCIL
-                         | PIPE_BIND_DISPLAY_TARGET)) {
-      struct swr_context *ctx = swr_context(pipe);
-      swr_draw_context *pDC = &ctx->swrDC;
-      SWR_SURFACE_STATE *renderTargets = pDC->renderTargets;
-      for (uint32_t i = 0; i < SWR_NUM_ATTACHMENTS; i++)
-         if (renderTargets[i].pBaseAddress == spr->swr.pBaseAddress) {
-            swr_store_render_target(ctx, i, SWR_TILE_INVALID);
-            /*
-             * Mesa thinks depth/stencil are fused, so we'll never get an
-             * explicit map for stencil.  So, if mapping depth, then also
-             * store tile for stencil.
-             */
-            if (spr->has_stencil && (i == SWR_ATTACHMENT_DEPTH))
-               swr_store_render_target(
-                  ctx, SWR_ATTACHMENT_STENCIL, SWR_TILE_INVALID);
-            SwrWaitForIdle(ctx->swrContext);
-            break;
+   /* If mapping an attached rendertarget, store tiles to surface and set
+    * postStoreTileState to SWR_TILE_INVALID so tiles get reloaded on next use
+    * and nothing needs to be done at unmap. */
+   swr_store_dirty_resource(pipe, resource, SWR_TILE_INVALID);
+
+   if (!(usage & PIPE_TRANSFER_UNSYNCHRONIZED)) {
+      /* If resource is in use, finish fence before mapping.
+       * Unless requested not to block, then if not done return NULL map */
+      if (usage & PIPE_TRANSFER_DONTBLOCK) {
+         if (swr_is_fence_pending(screen->flush_fence))
+            return NULL;
+      } else {
+         if (spr->status) {
+            /* But, if there's no fence pending, submit one.
+             * XXX: Remove once draw timestamps are finished. */
+            if (!swr_is_fence_pending(screen->flush_fence))
+               swr_fence_submit(swr_context(pipe), screen->flush_fence);
+
+            swr_fence_finish(pipe->screen, screen->flush_fence, 0);
+            swr_resource_unused(pipe, spr);
          }
+      }
    }
 
    pt = CALLOC_STRUCT(pipe_transfer);
@@ -195,16 +169,7 @@ swr_transfer_unmap(struct pipe_context *pipe, struct pipe_transfer *transfer)
 {
    assert(transfer->resource);
 
-   /*
-    * XXX TODO: use fences and come up with a real resource manager.
-    *
-    * If this resource has been mapped/unmapped, it's probably in use.  Tag it
-    *with this context so
-    * we'll know to check dependencies when it's deleted.
-    */
    struct swr_resource *res = swr_resource(transfer->resource);
-   res->bound_to_context = (void *)pipe;
-
    /* if we're mapping the depth/stencil, copy out stencil */
    if (res->base.format == PIPE_FORMAT_Z24_UNORM_S8_UINT
        && res->has_stencil) {
@@ -234,6 +199,16 @@ swr_resource_copy(struct pipe_context *pipe,
                   unsigned src_level,
                   const struct pipe_box *src_box)
 {
+   struct swr_screen *screen = swr_screen(pipe->screen);
+
+   /* If either the src or dst is a renderTarget, store tiles before copy */
+   swr_store_dirty_resource(pipe, src, SWR_TILE_RESOLVED);
+   swr_store_dirty_resource(pipe, dst, SWR_TILE_RESOLVED);
+
+   swr_fence_finish(pipe->screen, screen->flush_fence, 0);
+   swr_resource_unused(pipe, swr_resource(src));
+   swr_resource_unused(pipe, swr_resource(dst));
+
    if ((dst->target == PIPE_BUFFER && src->target == PIPE_BUFFER)
        || (dst->target != PIPE_BUFFER && src->target != PIPE_BUFFER)) {
       util_resource_copy_region(
@@ -322,6 +297,8 @@ swr_destroy(struct pipe_context *pipe)
    if (ctx->blitter)
       util_blitter_destroy(ctx->blitter);
 
+   /* Idle core before deleting context */
+   SwrWaitForIdle(ctx->swrContext);
    if (ctx->swrContext)
       SwrDestroyContext(ctx->swrContext);
 
@@ -346,7 +323,6 @@ swr_render_condition(struct pipe_context *pipe,
    ctx->render_cond_cond = condition;
 }
 
-
 struct pipe_context *
 swr_create_context(struct pipe_screen *screen, void *priv, unsigned flags)
 {
@@ -392,9 +368,8 @@ swr_create_context(struct pipe_screen *screen, void *priv, unsigned flags)
 
    ctx->pipe.blit = swr_blit;
    ctx->blitter = util_blitter_create(&ctx->pipe);
-   if (!ctx->blitter) {
+   if (!ctx->blitter)
       goto fail;
-   }
 
    swr_init_scratch_buffers(ctx);
 
diff --git a/src/gallium/drivers/swr/swr_draw.cpp b/src/gallium/drivers/swr/swr_draw.cpp
index a775bd2..428bf78 100644
--- a/src/gallium/drivers/swr/swr_draw.cpp
+++ b/src/gallium/drivers/swr/swr_draw.cpp
@@ -91,7 +91,7 @@ swr_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info)
 
    /* Update derived state, pass draw info to update function */
    if (ctx->dirty)
-      swr_update_derived(ctx, info);
+      swr_update_derived(pipe, info);
 
    swr_update_draw_context(ctx);
 
@@ -184,20 +184,14 @@ swr_flush(struct pipe_context *pipe,
 {
    struct swr_context *ctx = swr_context(pipe);
    struct swr_screen *screen = swr_screen(pipe->screen);
-
-   /* If the current renderTarget is the display surface, store tiles back to
-    * the surface, in
-    * preparation for present (swr_flush_frontbuffer)
-    */
    struct pipe_surface *cb = ctx->framebuffer.cbufs[0];
-   if (cb && swr_resource(cb->texture)->display_target) {
-      swr_store_render_target(ctx, SWR_ATTACHMENT_COLOR0, SWR_TILE_RESOLVED);
-      swr_resource(cb->texture)->bound_to_context = (void*)pipe;
-   }
 
-   // SwrStoreTiles is asynchronous, always submit the "flush" fence.
-   // flush_frontbuffer needs it.
-   swr_fence_submit(ctx, screen->flush_fence);
+   /* If the current renderTarget is the display surface, store tiles back to
+    * the surface, in preparation for present (swr_flush_frontbuffer).
+    * Other renderTargets get stored back when attachment changes or
+    * swr_surface_destroy */
+   if (cb && swr_resource(cb->texture)->display_target)
+      swr_store_dirty_resource(pipe, cb->texture, SWR_TILE_RESOLVED);
 
    if (fence)
       swr_fence_reference(pipe->screen, fence, screen->flush_fence);
@@ -206,23 +200,23 @@ swr_flush(struct pipe_context *pipe,
 void
 swr_finish(struct pipe_context *pipe)
 {
-   struct swr_screen *screen = swr_screen(pipe->screen);
-   struct pipe_fence_handle *fence = NULL;
+   struct pipe_fence_handle *fence = nullptr;
 
    swr_flush(pipe, &fence, 0);
-   swr_fence_finish(&screen->base, fence, 0);
-   swr_fence_reference(&screen->base, &fence, NULL);
+   swr_fence_finish(pipe->screen, fence, 0);
+   swr_fence_reference(pipe->screen, &fence, NULL);
 }
 
 
 /*
- * Store SWR HotTiles back to RenderTarget surface.
+ * Store SWR HotTiles back to renderTarget surface.
  */
 void
-swr_store_render_target(struct swr_context *ctx,
+swr_store_render_target(struct pipe_context *pipe,
                         uint32_t attachment,
                         enum SWR_TILE_STATE post_tile_state)
 {
+   struct swr_context *ctx = swr_context(pipe);
    struct swr_draw_context *pDC = &ctx->swrDC;
    struct SWR_SURFACE_STATE *renderTarget = &pDC->renderTargets[attachment];
 
@@ -262,6 +256,38 @@ swr_store_render_target(struct swr_context *ctx,
    }
 }
 
+void
+swr_store_dirty_resource(struct pipe_context *pipe,
+                         struct pipe_resource *resource,
+                         enum SWR_TILE_STATE post_tile_state)
+{
+   /* Only store resource if it has been written to */
+   if (swr_resource(resource)->status & SWR_RESOURCE_WRITE) {
+      struct swr_context *ctx = swr_context(pipe);
+      struct swr_screen *screen = swr_screen(pipe->screen);
+      struct swr_resource *spr = swr_resource(resource);
+
+      swr_draw_context *pDC = &ctx->swrDC;
+      SWR_SURFACE_STATE *renderTargets = pDC->renderTargets;
+      for (uint32_t i = 0; i < SWR_NUM_ATTACHMENTS; i++)
+         if (renderTargets[i].pBaseAddress == spr->swr.pBaseAddress) {
+            swr_store_render_target(pipe, i, post_tile_state);
+
+            /* Mesa thinks depth/stencil are fused, so we'll never get an
+             * explicit resource for stencil.  So, if checking depth, then
+             * also check for stencil. */
+            if (spr->has_stencil && (i == SWR_ATTACHMENT_DEPTH)) {
+               swr_store_render_target(
+                  pipe, SWR_ATTACHMENT_STENCIL, post_tile_state);
+            }
+
+            /* This fence signals StoreTiles completion */
+            swr_fence_submit(ctx, screen->flush_fence);
+
+            break;
+         }
+   }
+}
 
 void
 swr_draw_init(struct pipe_context *pipe)
diff --git a/src/gallium/drivers/swr/swr_fence.cpp b/src/gallium/drivers/swr/swr_fence.cpp
index e80faee..2e95b39 100644
--- a/src/gallium/drivers/swr/swr_fence.cpp
+++ b/src/gallium/drivers/swr/swr_fence.cpp
@@ -30,8 +30,9 @@
 #include "swr_fence.h"
 
 #if defined(PIPE_CC_MSVC) // portable thread yield
-   #define sched_yield SwitchToThread  
+   #define sched_yield SwitchToThread
 #endif
+
 /*
  * Fence callback, called by back-end thread on completion of all rendering up
  * to SwrSync call.
@@ -41,7 +42,8 @@ swr_sync_cb(uint64_t userData, uint64_t userData2, uint64_t userData3)
 {
    struct swr_fence *fence = (struct swr_fence *)userData;
 
-   fence->read = fence->write;
+   /* Correct value is in SwrSync data, and not the fence write field. */
+   fence->read = userData2;
 }
 
 /*
@@ -53,7 +55,8 @@ swr_fence_submit(struct swr_context *ctx, struct pipe_fence_handle *fh)
    struct swr_fence *fence = swr_fence(fh);
 
    fence->write++;
-   SwrSync(ctx->swrContext, swr_sync_cb, (uint64_t)fence, 0, 0);
+   fence->pending = TRUE;
+   SwrSync(ctx->swrContext, swr_sync_cb, (uint64_t)fence, fence->write, 0);
 }
 
 /*
@@ -67,7 +70,6 @@ swr_fence_create()
    if (!fence)
       return NULL;
 
-   memset(fence, 0, sizeof(*fence));
    pipe_reference_init(&fence->reference, 1);
    fence->id = fence_id++;
 
@@ -103,6 +105,13 @@ swr_fence_reference(struct pipe_screen *screen,
       swr_fence_destroy(old);
 }
 
+static INLINE boolean
+swr_is_fence_done(struct pipe_fence_handle *fence_handle)
+{
+   struct swr_fence *fence = swr_fence(fence_handle);
+   return (fence->read == fence->write);
+}
+
 /*
  * Wait for the fence to finish.
  */
@@ -111,11 +120,11 @@ swr_fence_finish(struct pipe_screen *screen,
                  struct pipe_fence_handle *fence_handle,
                  uint64_t timeout)
 {
-   struct swr_fence *fence = swr_fence(fence_handle);
-
-   while (!swr_is_fence_done(fence))
+   while (!swr_is_fence_done(fence_handle))
       sched_yield();
 
+   swr_fence(fence_handle)->pending = FALSE;
+
    return TRUE;
 }
 
@@ -132,12 +141,10 @@ swr_fence_init(struct pipe_screen *p_screen)
 {
    p_screen->fence_reference = swr_fence_reference;
    p_screen->fence_finish = swr_fence_finish;
-
    p_screen->get_timestamp = swr_get_timestamp;
 
-   /*
-    * Create persistant "flush" fence, submitted when swr_flush is called.
-    */
+   /* Create persistant StoreTiles "flush" fence, used to signal completion
+    * of flushing tile state back to resource texture, via StoreTiles. */
    struct swr_screen *screen = swr_screen(p_screen);
    screen->flush_fence = swr_fence_create();
 }
diff --git a/src/gallium/drivers/swr/swr_fence.h b/src/gallium/drivers/swr/swr_fence.h
index 257b240..df3776e 100644
--- a/src/gallium/drivers/swr/swr_fence.h
+++ b/src/gallium/drivers/swr/swr_fence.h
@@ -33,6 +33,8 @@ struct swr_fence {
    uint64_t read;
    uint64_t write;
 
+   unsigned pending;
+
    unsigned id; /* Just for reference */
 };
 
@@ -44,9 +46,9 @@ swr_fence(struct pipe_fence_handle *fence)
 }
 
 static INLINE boolean
-swr_is_fence_done(struct swr_fence *fence)
+swr_is_fence_pending(struct pipe_fence_handle *fence_handle)
 {
-   return (fence->read == fence->write);
+   return swr_fence(fence_handle)->pending;
 }
 
 
diff --git a/src/gallium/drivers/swr/swr_query.cpp b/src/gallium/drivers/swr/swr_query.cpp
index 2510b3a..810c50b 100644
--- a/src/gallium/drivers/swr/swr_query.cpp
+++ b/src/gallium/drivers/swr/swr_query.cpp
@@ -62,7 +62,7 @@ swr_destroy_query(struct pipe_context *pipe, struct pipe_query *q)
    struct swr_query *pq = swr_query(q);
 
    if (pq->fence) {
-      if (!swr_is_fence_done(swr_fence(pq->fence))) {
+      if (!swr_is_fence_pending(pq->fence)) {
          swr_fence_submit(swr_context(pipe), pq->fence);
          swr_fence_finish(pipe->screen, pq->fence, 0);
       }
@@ -85,7 +85,7 @@ swr_gather_stats(struct pipe_context *pipe, struct swr_query *pq)
    SWR_STATS swr_stats = {0};
 
    if (pq->fence) {
-      if (!swr_is_fence_done(swr_fence(pq->fence))) {
+      if (!swr_is_fence_pending(pq->fence)) {
          swr_fence_submit(ctx, pq->fence);
          swr_fence_finish(pipe->screen, pq->fence, 0);
       }
@@ -180,7 +180,7 @@ swr_get_query_result(struct pipe_context *pipe,
    struct swr_query *pq = swr_query(q);
 
    if (pq->fence) {
-      if (!swr_is_fence_done(swr_fence(pq->fence))) {
+      if (!swr_is_fence_pending(pq->fence)) {
          swr_fence_submit(ctx, pq->fence);
          if (!wait)
             return FALSE;
diff --git a/src/gallium/drivers/swr/swr_resource.h b/src/gallium/drivers/swr/swr_resource.h
index 87a27ac..2fdc768 100644
--- a/src/gallium/drivers/swr/swr_resource.h
+++ b/src/gallium/drivers/swr/swr_resource.h
@@ -29,6 +29,12 @@
 
 struct sw_displaytarget;
 
+enum swr_resource_status {
+   SWR_RESOURCE_UNUSED = 0x0,
+   SWR_RESOURCE_READ = 0x1,
+   SWR_RESOURCE_WRITE = 0x2,
+};
+
 struct swr_resource {
    struct pipe_resource base;
 
@@ -39,7 +45,7 @@ struct swr_resource {
    UINT alignedHeight;
 
    SWR_SURFACE_STATE swr;
-   SWR_SURFACE_STATE secondary; // for faking depth/stencil merged formats
+   SWR_SURFACE_STATE secondary; /* for faking depth/stencil merged formats */
 
    struct sw_displaytarget *display_target;
 
@@ -47,8 +53,10 @@ struct swr_resource {
    unsigned img_stride[PIPE_MAX_TEXTURE_LEVELS];
    unsigned mip_offsets[PIPE_MAX_TEXTURE_LEVELS];
 
-   /* Opaque pointer to swr_context to mark resource in use */
-   void *bound_to_context;
+   enum swr_resource_status status;
+
+   /* pipe_context to which resource is currently bound. */
+   struct pipe_context *bound_to_context;
 };
 
 
@@ -91,7 +99,45 @@ swr_resource_data(struct pipe_resource *resource)
 }
 
 
-void swr_store_render_target(struct swr_context *ctx,
+void swr_store_render_target(struct pipe_context *pipe,
                              uint32_t attachment,
                              enum SWR_TILE_STATE post_tile_state);
+
+void swr_store_dirty_resource(struct pipe_context *pipe,
+                              struct pipe_resource *resource,
+                              enum SWR_TILE_STATE post_tile_state);
+
+void swr_update_resource_status(struct pipe_context *,
+                                const struct pipe_draw_info *);
+
+/*
+ * Functions to indicate a resource's in-use status.
+ */
+static INLINE enum
+swr_resource_status & operator|=(enum swr_resource_status & a,
+                                 enum swr_resource_status  b) {
+   return (enum swr_resource_status &)((int&)a |= (int)b);
+}
+
+static INLINE void
+swr_resource_read(struct pipe_context *pipe, struct swr_resource *resource)
+{
+   resource->status |= SWR_RESOURCE_READ;
+   resource->bound_to_context = pipe;
+}
+
+static INLINE void
+swr_resource_write(struct pipe_context *pipe, struct swr_resource *resource)
+{
+   resource->status |= SWR_RESOURCE_WRITE;
+   resource->bound_to_context = pipe;
+}
+
+static INLINE void
+swr_resource_unused(struct pipe_context *pipe, struct swr_resource *resource)
+{
+   resource->status = SWR_RESOURCE_UNUSED;
+   resource->bound_to_context = nullptr;
+}
+
 #endif
diff --git a/src/gallium/drivers/swr/swr_screen.cpp b/src/gallium/drivers/swr/swr_screen.cpp
index f0d48cd..7c95c58 100644
--- a/src/gallium/drivers/swr/swr_screen.cpp
+++ b/src/gallium/drivers/swr/swr_screen.cpp
@@ -47,7 +47,7 @@ extern "C" {
 
 /* MSVC case instensitive compare */
 #if defined(PIPE_CC_MSVC)
-   #define strcasecmp lstrcmpiA  
+   #define strcasecmp lstrcmpiA
 #endif
 
 /*
@@ -619,37 +619,34 @@ static void
 swr_resource_destroy(struct pipe_screen *p_screen, struct pipe_resource *pt)
 {
    struct swr_screen *screen = swr_screen(p_screen);
-   struct swr_resource *res = swr_resource(pt);
-
-   /*
-    * If this resource is attached to a context it may still be in use, check
-    * dependencies before freeing
-    * XXX TODO: don't use SwrWaitForIdle, use fences and come up with a real
-    * resource manager.
-    * XXX It's happened that we get a swr_destroy prior to freeing the
-    * framebuffer resource.  Don't wait on it.
-    */
-   if (res->bound_to_context && !res->display_target) {
-      struct swr_context *ctx =
-         swr_context((pipe_context *)res->bound_to_context);
-      // XXX, don't SwrWaitForIdle!!! Use a fence.
-      SwrWaitForIdle(ctx->swrContext);
+   struct swr_resource *spr = swr_resource(pt);
+   struct pipe_context *pipe = spr->bound_to_context;
+
+   /* Only wait on fence if the resource is being used */
+   if (pipe && spr->status) {
+      /* But, if there's no fence pending, submit one.
+       * XXX: Remove once draw timestamps are implmented. */
+      if (!swr_is_fence_pending(screen->flush_fence))
+         swr_fence_submit(swr_context(pipe), screen->flush_fence);
+
+      swr_fence_finish(p_screen, screen->flush_fence, 0);
+      swr_resource_unused(pipe, spr);
    }
 
    /*
     * Free resource primary surface.  If resource is display target, winsys
     * manages the buffer and will free it on displaytarget_destroy.
     */
-   if (res->display_target) {
+   if (spr->display_target) {
       /* display target */
       struct sw_winsys *winsys = screen->winsys;
-      winsys->displaytarget_destroy(winsys, res->display_target);
+      winsys->displaytarget_destroy(winsys, spr->display_target);
    } else
-      _aligned_free(res->swr.pBaseAddress);
+      _aligned_free(spr->swr.pBaseAddress);
 
-   _aligned_free(res->secondary.pBaseAddress);
+   _aligned_free(spr->secondary.pBaseAddress);
 
-   FREE(res);
+   FREE(spr);
 }
 
 
@@ -663,17 +660,19 @@ swr_flush_frontbuffer(struct pipe_screen *p_screen,
 {
    struct swr_screen *screen = swr_screen(p_screen);
    struct sw_winsys *winsys = screen->winsys;
-   struct swr_resource *res = swr_resource(resource);
+   struct swr_resource *spr = swr_resource(resource);
+   struct pipe_context *pipe = spr->bound_to_context;
 
-   /* Ensure fence set at flush is finished, before reading frame buffer */
-   swr_fence_finish(p_screen, screen->flush_fence, 0);
-
-   SwrEndFrame(swr_context((pipe_context *)res->bound_to_context));
+   if (pipe) {
+      swr_fence_finish(p_screen, screen->flush_fence, 0);
+      swr_resource_unused(pipe, spr);
+      SwrEndFrame(swr_context(pipe)->swrContext);
+   }
 
-   assert(res->display_target);
-   if (res->display_target)
+   debug_assert(spr->display_target);
+   if (spr->display_target)
       winsys->displaytarget_display(
-         winsys, res->display_target, context_private, sub_box);
+         winsys, spr->display_target, context_private, sub_box);
 }
 
 
diff --git a/src/gallium/drivers/swr/swr_state.cpp b/src/gallium/drivers/swr/swr_state.cpp
index 49035b5..92245d8 100644
--- a/src/gallium/drivers/swr/swr_state.cpp
+++ b/src/gallium/drivers/swr/swr_state.cpp
@@ -42,6 +42,7 @@
 #include "swr_tex_sample.h"
 #include "swr_scratch.h"
 #include "swr_shader.h"
+#include "swr_fence.h"
 
 /* These should be pulled out into separate files as necessary
  * Just initializing everything here to get going. */
@@ -629,11 +630,58 @@ swr_set_sample_mask(struct pipe_context *pipe, unsigned sample_mask)
    }
 }
 
+/*
+ * Update resource in-use status
+ * All resources bound to color or depth targets marked as WRITE resources.
+ * VBO Vertex/index buffers and texture views marked as READ resources.
+ */
+void
+swr_update_resource_status(struct pipe_context *pipe,
+                           const struct pipe_draw_info *p_draw_info)
+{
+   struct swr_context *ctx = swr_context(pipe);
+   struct pipe_framebuffer_state *fb = &ctx->framebuffer;
+
+   /* colorbuffer targets */
+   if (fb->nr_cbufs)
+      for (uint32_t i = 0; i < fb->nr_cbufs; ++i)
+         if (fb->cbufs[i])
+            swr_resource_write(pipe, swr_resource(fb->cbufs[i]->texture));
+
+   /* depth/stencil target */
+   if (fb->zsbuf)
+      swr_resource_write(pipe, swr_resource(fb->zsbuf->texture));
+
+   /* VBO vertex buffers */
+   for (uint32_t i = 0; i < ctx->num_vertex_buffers; i++) {
+      struct pipe_vertex_buffer *vb = &ctx->vertex_buffer[i];
+      if (!vb->user_buffer)
+         swr_resource_read(pipe, swr_resource(vb->buffer));
+   }
+
+   /* VBO index buffer */
+   if (p_draw_info && p_draw_info->indexed) {
+      struct pipe_index_buffer *ib = &ctx->index_buffer;
+      if (!ib->user_buffer)
+         swr_resource_read(pipe, swr_resource(ib->buffer));
+   }
+
+   /* texture sampler views */
+   for (uint32_t i = 0; i < PIPE_MAX_SHADER_SAMPLER_VIEWS; i++) {
+      struct pipe_sampler_view *view =
+         ctx->sampler_views[PIPE_SHADER_FRAGMENT][i];
+      if (view)
+         swr_resource_read(pipe, swr_resource(view->texture));
+   }
+}
 
 void
-swr_update_derived(struct swr_context *ctx,
+swr_update_derived(struct pipe_context *pipe,
                    const struct pipe_draw_info *p_draw_info)
 {
+   struct swr_context *ctx = swr_context(pipe);
+   struct swr_screen *screen = swr_screen(ctx->pipe.screen);
+
    /* Any state that requires dirty flags to be re-triggered sets this mask */
    /* For example, user_buffer vertex and index buffers. */
    unsigned post_update_dirty_flags = 0;
@@ -671,17 +719,24 @@ swr_update_derived(struct swr_context *ctx,
       /* Make the attachment updates */
       swr_draw_context *pDC = &ctx->swrDC;
       SWR_SURFACE_STATE *renderTargets = pDC->renderTargets;
+      unsigned need_fence = FALSE;
       for (i = 0; i < SWR_NUM_ATTACHMENTS; i++) {
          void *new_base = nullptr;
          if (new_attachment[i])
             new_base = new_attachment[i]->pBaseAddress;
-         
+
          /* StoreTile for changed target */
          if (renderTargets[i].pBaseAddress != new_base) {
             if (renderTargets[i].pBaseAddress) {
+               /* If changing attachment to a new target, mark tiles as
+                * INVALID so they are reloaded from surface.
+                * If detaching attachment, mark tiles as RESOLVED so core
+                * won't try to load from non-existent target. */
                enum SWR_TILE_STATE post_state = (new_attachment[i]
                   ? SWR_TILE_INVALID : SWR_TILE_RESOLVED);
-               swr_store_render_target(ctx, i, post_state);
+               swr_store_render_target(pipe, i, post_state);
+
+               need_fence |= TRUE;
             }
 
             /* Make new attachment */
@@ -692,6 +747,11 @@ swr_update_derived(struct swr_context *ctx,
                   renderTargets[i] = {0};
          }
       }
+
+      /* This fence ensures any attachment changes are resolved before the
+       * next draw */
+      if (need_fence)
+         swr_fence_submit(ctx, screen->flush_fence);
    }
 
    /* Raster state */
@@ -793,8 +853,7 @@ swr_update_derived(struct swr_context *ctx,
       vpm->m32 = state->translate[2];
 
       /* Now that the matrix is calculated, clip the view coords to screen
-       * size.  OpenGL allows for -ve x,y in the viewport.
-       */
+       * size.  OpenGL allows for -ve x,y in the viewport. */
       vp->x = std::max(vp->x, 0.0f);
       vp->y = std::max(vp->y, 0.0f);
       vp->width = std::min(vp->width, (float)fb->width);
@@ -817,7 +876,7 @@ swr_update_derived(struct swr_context *ctx,
       /* vertex buffers */
       SWR_VERTEX_BUFFER_STATE swrVertexBuffers[PIPE_MAX_ATTRIBS];
       for (UINT i = 0; i < ctx->num_vertex_buffers; i++) {
-         pipe_vertex_buffer *vb = &ctx->vertex_buffer[i];
+         struct pipe_vertex_buffer *vb = &ctx->vertex_buffer[i];
 
          pitch = vb->stride;
          if (!vb->user_buffer) {
@@ -871,7 +930,7 @@ swr_update_derived(struct swr_context *ctx,
       /* index buffer, if required (info passed in by swr_draw_vbo) */
       SWR_FORMAT index_type = R32_UINT; /* Default for non-indexed draws */
       if (info.indexed) {
-         pipe_index_buffer *ib = &ctx->index_buffer;
+         struct pipe_index_buffer *ib = &ctx->index_buffer;
 
          pitch = ib->index_size ? ib->index_size : sizeof(uint32_t);
          index_type = swr_convert_index_type(pitch);
@@ -1195,7 +1254,7 @@ swr_update_derived(struct swr_context *ctx,
             if (search != ctx->blendJIT->end()) {
                func = search->second;
             } else {
-               HANDLE hJitMgr = swr_screen(ctx->pipe.screen)->hJitMgr;
+               HANDLE hJitMgr = screen->hJitMgr;
                func = JitCompileBlend(hJitMgr, compileState);
                debug_printf("BLEND shader %p\n", func);
                assert(func && "Error: BlendShader = NULL");
@@ -1253,9 +1312,17 @@ swr_update_derived(struct swr_context *ctx,
 
    SwrSetBackendState(ctx->swrContext, &backendState);
 
+   /* Ensure that any in-progress attachment change StoreTiles finish */
+   if (swr_is_fence_pending(screen->flush_fence))
+      swr_fence_finish(pipe->screen, screen->flush_fence, 0);
+
+   /* Finally, update the in-use status of all resources involved in draw */
+   swr_update_resource_status(pipe, p_draw_info);
+
    ctx->dirty = post_update_dirty_flags;
 }
 
+
 static struct pipe_stream_output_target *
 swr_create_so_target(struct pipe_context *pipe,
                      struct pipe_resource *buffer,
diff --git a/src/gallium/drivers/swr/swr_state.h b/src/gallium/drivers/swr/swr_state.h
index a2b4d80..f0a7ff3 100644
--- a/src/gallium/drivers/swr/swr_state.h
+++ b/src/gallium/drivers/swr/swr_state.h
@@ -76,7 +76,7 @@ struct swr_derived_state {
    SWR_VIEWPORT_MATRIX vpm;
 };
 
-void swr_update_derived(struct swr_context *,
+void swr_update_derived(struct pipe_context *,
                         const struct pipe_draw_info * = nullptr);
 
 /*
-- 
1.7.1



More information about the mesa-dev mailing list