diff options
-rw-r--r-- | src/gallium/drivers/freedreno/freedreno_context.c | 18 | ||||
-rw-r--r-- | src/gallium/drivers/freedreno/freedreno_draw.c | 65 | ||||
-rw-r--r-- | src/gallium/drivers/freedreno/freedreno_resource.c | 19 | ||||
-rw-r--r-- | src/gallium/drivers/freedreno/freedreno_resource.h | 17 |
4 files changed, 71 insertions, 48 deletions
diff --git a/src/gallium/drivers/freedreno/freedreno_context.c b/src/gallium/drivers/freedreno/freedreno_context.c index 02613dcdbdb..8e6d43150ce 100644 --- a/src/gallium/drivers/freedreno/freedreno_context.c +++ b/src/gallium/drivers/freedreno/freedreno_context.c @@ -94,9 +94,7 @@ void fd_context_render(struct pipe_context *pctx) { struct fd_context *ctx = fd_context(pctx); - struct pipe_framebuffer_state *pfb = &ctx->framebuffer; struct fd_resource *rsc, *rsc_tmp; - int i; DBG("needs_flush: %d", ctx->needs_flush); @@ -118,21 +116,11 @@ fd_context_render(struct pipe_context *pctx) ctx->gmem_reason = 0; ctx->num_draws = 0; - for (i = 0; i < pfb->nr_cbufs; i++) - if (pfb->cbufs[i]) - fd_resource(pfb->cbufs[i]->texture)->dirty = false; - if (pfb->zsbuf) { - rsc = fd_resource(pfb->zsbuf->texture); - rsc->dirty = false; - if (rsc->stencil) - rsc->stencil->dirty = false; - } - /* go through all the used resources and clear their reading flag */ LIST_FOR_EACH_ENTRY_SAFE(rsc, rsc_tmp, &ctx->used_resources, list) { - assert(rsc->reading || rsc->writing); - rsc->reading = false; - rsc->writing = false; + debug_assert(rsc->status != 0); + rsc->status = 0; + rsc->pending_ctx = NULL; list_delinit(&rsc->list); } diff --git a/src/gallium/drivers/freedreno/freedreno_draw.c b/src/gallium/drivers/freedreno/freedreno_draw.c index f88654063fa..a04cc879630 100644 --- a/src/gallium/drivers/freedreno/freedreno_draw.c +++ b/src/gallium/drivers/freedreno/freedreno_draw.c @@ -40,7 +40,8 @@ #include "freedreno_util.h" static void -resource_used(struct fd_context *ctx, struct pipe_resource *prsc, boolean reading) +resource_used(struct fd_context *ctx, struct pipe_resource *prsc, + enum fd_resource_status status) { struct fd_resource *rsc; @@ -48,12 +49,29 @@ resource_used(struct fd_context *ctx, struct pipe_resource *prsc, boolean readin return; rsc = fd_resource(prsc); - if (reading) - rsc->reading = true; - else - rsc->writing = true; + rsc->status |= status; + if (rsc->stencil) + rsc->stencil->status |= status; + + /* TODO resources can actually be shared across contexts, + * so I'm not sure a single list-head will do the trick? + */ + debug_assert((rsc->pending_ctx == ctx) || !rsc->pending_ctx); list_delinit(&rsc->list); list_addtail(&rsc->list, &ctx->used_resources); + rsc->pending_ctx = ctx; +} + +static void +resource_read(struct fd_context *ctx, struct pipe_resource *prsc) +{ + resource_used(ctx, prsc, FD_PENDING_READ); +} + +static void +resource_written(struct fd_context *ctx, struct pipe_resource *prsc) +{ + resource_used(ctx, prsc, FD_PENDING_WRITE); } static void @@ -72,6 +90,8 @@ fd_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info) /* emulate unsupported primitives: */ if (!fd_supported_prim(ctx, info->mode)) { + if (ctx->streamout.num_targets > 0) + debug_error("stream-out with emulated prims"); util_primconvert_save_index_buffer(ctx->primconvert, &ctx->indexbuf); util_primconvert_save_rasterizer_state(ctx->primconvert, ctx->rasterizer); util_primconvert_draw_vbo(ctx->primconvert, info); @@ -86,17 +106,13 @@ fd_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info) if (fd_depth_enabled(ctx)) { buffers |= FD_BUFFER_DEPTH; - fd_resource(pfb->zsbuf->texture)->dirty = true; + resource_written(ctx, pfb->zsbuf->texture); ctx->gmem_reason |= FD_GMEM_DEPTH_ENABLED; } if (fd_stencil_enabled(ctx)) { - struct fd_resource *rsc = fd_resource(pfb->zsbuf->texture); buffers |= FD_BUFFER_STENCIL; - if (rsc->stencil) - rsc->stencil->dirty = true; - else - rsc->dirty = true; + resource_written(ctx, pfb->zsbuf->texture); ctx->gmem_reason |= FD_GMEM_STENCIL_ENABLED; } @@ -111,7 +127,7 @@ fd_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info) surf = pfb->cbufs[i]->texture; - fd_resource(surf)->dirty = true; + resource_written(ctx, surf); buffers |= PIPE_CLEAR_COLOR0 << i; if (surf->nr_samples > 1) @@ -123,31 +139,31 @@ fd_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info) /* Skip over buffer 0, that is sent along with the command stream */ for (i = 1; i < PIPE_MAX_CONSTANT_BUFFERS; i++) { - resource_used(ctx, ctx->constbuf[PIPE_SHADER_VERTEX].cb[i].buffer, true); - resource_used(ctx, ctx->constbuf[PIPE_SHADER_FRAGMENT].cb[i].buffer, true); + resource_read(ctx, ctx->constbuf[PIPE_SHADER_VERTEX].cb[i].buffer); + resource_read(ctx, ctx->constbuf[PIPE_SHADER_FRAGMENT].cb[i].buffer); } /* Mark VBOs as being read */ for (i = 0; i < ctx->vtx.vertexbuf.count; i++) { assert(!ctx->vtx.vertexbuf.vb[i].user_buffer); - resource_used(ctx, ctx->vtx.vertexbuf.vb[i].buffer, true); + resource_read(ctx, ctx->vtx.vertexbuf.vb[i].buffer); } /* Mark index buffer as being read */ - resource_used(ctx, ctx->indexbuf.buffer, true); + resource_read(ctx, ctx->indexbuf.buffer); /* Mark textures as being read */ for (i = 0; i < ctx->verttex.num_textures; i++) if (ctx->verttex.textures[i]) - resource_used(ctx, ctx->verttex.textures[i]->texture, true); + resource_read(ctx, ctx->verttex.textures[i]->texture); for (i = 0; i < ctx->fragtex.num_textures; i++) if (ctx->fragtex.textures[i]) - resource_used(ctx, ctx->fragtex.textures[i]->texture, true); + resource_read(ctx, ctx->fragtex.textures[i]->texture); - /* Mark streamout buffers as being read.. actually they are written.. */ + /* Mark streamout buffers as being written.. */ for (i = 0; i < ctx->streamout.num_targets; i++) if (ctx->streamout.targets[i]) - resource_used(ctx, ctx->streamout.targets[i]->buffer, false); + resource_written(ctx, ctx->streamout.targets[i]->buffer); ctx->num_draws++; @@ -228,15 +244,10 @@ fd_clear(struct pipe_context *pctx, unsigned buffers, if (buffers & PIPE_CLEAR_COLOR) for (i = 0; i < pfb->nr_cbufs; i++) if (buffers & (PIPE_CLEAR_COLOR0 << i)) - fd_resource(pfb->cbufs[i]->texture)->dirty = true; + resource_written(ctx, pfb->cbufs[i]->texture); if (buffers & (PIPE_CLEAR_DEPTH | PIPE_CLEAR_STENCIL)) { - struct fd_resource *rsc = fd_resource(pfb->zsbuf->texture); - if (rsc->stencil && buffers & PIPE_CLEAR_STENCIL) - rsc->stencil->dirty = true; - if (!rsc->stencil || buffers & PIPE_CLEAR_DEPTH) - rsc->dirty = true; - + resource_written(ctx, pfb->zsbuf->texture); ctx->gmem_reason |= FD_GMEM_CLEARS_DEPTH_STENCIL; } diff --git a/src/gallium/drivers/freedreno/freedreno_resource.c b/src/gallium/drivers/freedreno/freedreno_resource.c index d649925af48..709ad4eb55b 100644 --- a/src/gallium/drivers/freedreno/freedreno_resource.c +++ b/src/gallium/drivers/freedreno/freedreno_resource.c @@ -42,6 +42,14 @@ #include <errno.h> + +static bool +pending(struct fd_resource *rsc, enum fd_resource_status status) +{ + return (rsc->status & status) || + (rsc->stencil && (rsc->stencil->status & status)); +} + static void fd_invalidate_resource(struct fd_context *ctx, struct pipe_resource *prsc) { @@ -97,7 +105,8 @@ realloc_bo(struct fd_resource *rsc, uint32_t size) rsc->bo = fd_bo_new(screen->dev, size, flags); rsc->timestamp = 0; - rsc->dirty = rsc->reading = rsc->writing = false; + rsc->status = 0; + rsc->pending_ctx = NULL; list_delinit(&rsc->list); util_range_set_empty(&rsc->valid_buffer_range); } @@ -238,9 +247,9 @@ fd_resource_transfer_map(struct pipe_context *pctx, /* If the GPU is writing to the resource, or if it is reading from the * resource and we're trying to write to it, flush the renders. */ - if (rsc->dirty || (rsc->stencil && rsc->stencil->dirty) || - ((ptrans->usage & PIPE_TRANSFER_WRITE) && rsc->reading) || - ((ptrans->usage & PIPE_TRANSFER_READ) && rsc->writing)) + if (((ptrans->usage & PIPE_TRANSFER_WRITE) && + pending(rsc, FD_PENDING_READ | FD_PENDING_WRITE)) || + pending(rsc, FD_PENDING_WRITE)) fd_context_render(pctx); /* The GPU keeps track of how the various bo's are being used, and @@ -678,7 +687,7 @@ fd_flush_resource(struct pipe_context *pctx, struct pipe_resource *prsc) { struct fd_resource *rsc = fd_resource(prsc); - if (rsc->dirty || (rsc->stencil && rsc->stencil->dirty)) + if (pending(rsc, FD_PENDING_WRITE | FD_PENDING_READ)) fd_context_render(pctx); } diff --git a/src/gallium/drivers/freedreno/freedreno_resource.h b/src/gallium/drivers/freedreno/freedreno_resource.h index e7f127edca4..7549becaa1f 100644 --- a/src/gallium/drivers/freedreno/freedreno_resource.h +++ b/src/gallium/drivers/freedreno/freedreno_resource.h @@ -60,6 +60,15 @@ struct fd_resource_slice { uint32_t size0; /* size of first layer in slice */ }; +/* status of queued up but not flushed reads and write operations. + * In _transfer_map() we need to know if queued up rendering needs + * to be flushed to preserve the order of cpu and gpu access. + */ +enum fd_resource_status { + FD_PENDING_WRITE = 0x01, + FD_PENDING_READ = 0x02, +}; + struct fd_resource { struct u_resource base; struct fd_bo *bo; @@ -68,14 +77,20 @@ struct fd_resource { uint32_t layer_size; struct fd_resource_slice slices[MAX_MIP_LEVELS]; uint32_t timestamp; - bool dirty, reading, writing; /* buffer range that has been initialized */ struct util_range valid_buffer_range; /* reference to the resource holding stencil data for a z32_s8 texture */ + /* TODO rename to secondary or auxiliary? */ struct fd_resource *stencil; + /* pending read/write state: */ + enum fd_resource_status status; + /* resources accessed by queued but not flushed draws are tracked + * in the used_resources list. + */ struct list_head list; + struct fd_context *pending_ctx; }; static inline struct fd_resource * |