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); + /* If the resource has been drawn to, store tiles. */ + swr_store_dirty_resource(pipe, resource, 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; - } - } - - 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); + struct pipe_surface *cb = ctx->framebuffer.cbufs[0]; /* 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); + * 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); + struct swr_resource *spr = swr_resource(pt); + struct pipe_context *pipe = spr->bound_to_context; - /* - * 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); + /* 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); + if (pipe) { + swr_fence_finish(p_screen, screen->flush_fence, 0); + swr_resource_unused(pipe, spr); + SwrEndFrame(swr_context(pipe)->swrContext); + } - SwrEndFrame(swr_context((pipe_context *)res->bound_to_context)); - - 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); /*