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

Kyriazis, George george.kyriazis at intel.com
Fri Mar 11 15:56:55 UTC 2016


Reviewed-By: George Kyriazis

> -----Original Message-----
> From: mesa-dev [mailto:mesa-dev-bounces at lists.freedesktop.org] On
> Behalf Of BruceCherniak
> Sent: Wednesday, March 9, 2016 7:30 PM
> To: mesa-dev at lists.freedesktop.org
> Subject: [Mesa-dev] [PATCH] gallium/swr: Resource management
> 
> 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
> 
> _______________________________________________
> mesa-dev mailing list
> mesa-dev at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/mesa-dev


More information about the mesa-dev mailing list