[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