summaryrefslogtreecommitdiffstats
path: root/src/gallium
diff options
context:
space:
mode:
authorBruce Cherniak <[email protected]>2016-03-09 19:30:00 -0600
committerTim Rowley <[email protected]>2016-03-14 14:07:48 -0500
commite9d68cc3da07c4b566799bbaec2434bfc21d3e0c (patch)
treee84d07138133a29b1398de4355cebecf4fae3b1d /src/gallium
parent7a2333e4efbaefe6bd6db87b9b2443737c89f01e (diff)
gallium/swr: Resource management
Better tracking of resource state and synchronization. A follow on commit will clean up resource functions into a new swr_resource.cpp file. Reviewed-By: George Kyriazis <[email protected]>
Diffstat (limited to 'src/gallium')
-rw-r--r--src/gallium/drivers/swr/swr_clear.cpp4
-rw-r--r--src/gallium/drivers/swr/swr_context.cpp103
-rw-r--r--src/gallium/drivers/swr/swr_draw.cpp64
-rw-r--r--src/gallium/drivers/swr/swr_fence.cpp29
-rw-r--r--src/gallium/drivers/swr/swr_fence.h6
-rw-r--r--src/gallium/drivers/swr/swr_query.cpp6
-rw-r--r--src/gallium/drivers/swr/swr_resource.h54
-rw-r--r--src/gallium/drivers/swr/swr_screen.cpp57
-rw-r--r--src/gallium/drivers/swr/swr_state.cpp83
-rw-r--r--src/gallium/drivers/swr/swr_state.h2
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 9027f84f6ea..103bca99441 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 0e7ebb74d92..c8cb145d334 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 a775bd2467f..428bf78cb55 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 e80faeef06e..2e95b3936a6 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 257b2408820..df3776e8989 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 2510b3ae39c..810c50b2f8f 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 87a27acfbce..2fdc7683cb8 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 89de17aacb8..e46df47570f 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 706bf10f265..47ee3cb2664 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 a2b4d808aa3..f0a7ff3b185 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);
/*