From 042aeffd5b2c8d0af8310bdd57515b4c71eb125e Mon Sep 17 00:00:00 2001 From: Iago Toral Quiroga Date: Thu, 20 Jun 2019 13:46:02 +0200 Subject: [PATCH] v3d: do not flush jobs that are synced with 'Wait for transform feedback' Generally, we achieve this by skipping the flush on calls to v3d_flush_jobs_writing_resource() when we detect that the resource is written in the current job from a transform feedback write. The exception to this is the case where the caller is about to map the resource, in which case we need to flush immediately since we can only emit 'Wait for transform feedback' commands on rendering jobs. We add a parameter to the function so the caller can identify that scenario. Reviewed-by: Eric Anholt --- src/gallium/drivers/v3d/v3d_blit.c | 4 +- src/gallium/drivers/v3d/v3d_context.h | 3 +- src/gallium/drivers/v3d/v3d_job.c | 51 +++++++++++++++++++++++--- src/gallium/drivers/v3d/v3d_resource.c | 2 +- src/gallium/drivers/v3d/v3dx_draw.c | 21 +++++------ 5 files changed, 61 insertions(+), 20 deletions(-) diff --git a/src/gallium/drivers/v3d/v3d_blit.c b/src/gallium/drivers/v3d/v3d_blit.c index d42e8fd0e69..e177369dd10 100644 --- a/src/gallium/drivers/v3d/v3d_blit.c +++ b/src/gallium/drivers/v3d/v3d_blit.c @@ -380,7 +380,7 @@ v3d_tfu(struct pipe_context *pctx, if (dst_base_slice->tiling == VC5_TILING_RASTER) return false; - v3d_flush_jobs_writing_resource(v3d, psrc); + v3d_flush_jobs_writing_resource(v3d, psrc, false); v3d_flush_jobs_reading_resource(v3d, pdst); struct drm_v3d_submit_tfu tfu = { @@ -537,5 +537,5 @@ v3d_blit(struct pipe_context *pctx, const struct pipe_blit_info *blit_info) * run into unexpected OOMs when blits are used for a large series of * texture uploads before using the textures. */ - v3d_flush_jobs_writing_resource(v3d, info.dst.resource); + v3d_flush_jobs_writing_resource(v3d, info.dst.resource, false); } diff --git a/src/gallium/drivers/v3d/v3d_context.h b/src/gallium/drivers/v3d/v3d_context.h index 7c8952ebb74..9143f53cee8 100644 --- a/src/gallium/drivers/v3d/v3d_context.h +++ b/src/gallium/drivers/v3d/v3d_context.h @@ -594,7 +594,8 @@ void v3d_job_add_tf_write_resource(struct v3d_job *job, struct pipe_resource *pr void v3d_job_submit(struct v3d_context *v3d, struct v3d_job *job); void v3d_flush_jobs_using_bo(struct v3d_context *v3d, struct v3d_bo *bo); void v3d_flush_jobs_writing_resource(struct v3d_context *v3d, - struct pipe_resource *prsc); + struct pipe_resource *prsc, + bool always_flush); void v3d_flush_jobs_reading_resource(struct v3d_context *v3d, struct pipe_resource *prsc); void v3d_update_compiled_shaders(struct v3d_context *v3d, uint8_t prim_mode); diff --git a/src/gallium/drivers/v3d/v3d_job.c b/src/gallium/drivers/v3d/v3d_job.c index 6f3fa709616..9b24f12e7e9 100644 --- a/src/gallium/drivers/v3d/v3d_job.c +++ b/src/gallium/drivers/v3d/v3d_job.c @@ -168,16 +168,51 @@ v3d_job_add_tf_write_resource(struct v3d_job *job, struct pipe_resource *prsc) _mesa_set_add(job->tf_write_prscs, prsc); } +static bool +v3d_job_writes_resource_from_tf(struct v3d_job *job, + struct pipe_resource *prsc) +{ + if (!job->tf_enabled) + return false; + + if (!job->tf_write_prscs) + return false; + + return _mesa_set_search(job->tf_write_prscs, prsc) != NULL; +} + void v3d_flush_jobs_writing_resource(struct v3d_context *v3d, - struct pipe_resource *prsc) + struct pipe_resource *prsc, + bool always_flush) { struct hash_entry *entry = _mesa_hash_table_search(v3d->write_jobs, prsc); - if (entry) { - struct v3d_job *job = entry->data; - v3d_job_submit(v3d, job); + if (!entry) + return; + + struct v3d_job *job = entry->data; + + /* For writes from TF in the same job we use the "Wait for TF" + * feature provided by the hardware so we don't want to flush. + * The exception to this is when the caller is about to map the + * resource since in that case we don't have a 'Wait for TF' command + * the in command stream. In this scenario the caller is expected + * to set 'always_flush' to True. + */ + bool needs_flush; + if (always_flush) { + needs_flush = true; + } else if (!v3d->job || v3d->job != job) { + /* Write from a different job: always flush */ + needs_flush = true; + } else { + /* Write from currrent job: flush if not TF */ + needs_flush = !v3d_job_writes_resource_from_tf(job, prsc); } + + if (needs_flush) + v3d_job_submit(v3d, job); } void @@ -186,7 +221,13 @@ v3d_flush_jobs_reading_resource(struct v3d_context *v3d, { struct v3d_resource *rsc = v3d_resource(prsc); - v3d_flush_jobs_writing_resource(v3d, prsc); + /* We only need to force the flush on TF writes, which is the only + * case where we might skip the flush to use the 'Wait for TF' + * command. Here we are flushing for a read, which means that the + * caller intends to write to the resource, so we don't care if + * there was a previous TF write to it. + */ + v3d_flush_jobs_writing_resource(v3d, prsc, false); hash_table_foreach(v3d->jobs, entry) { struct v3d_job *job = entry->data; diff --git a/src/gallium/drivers/v3d/v3d_resource.c b/src/gallium/drivers/v3d/v3d_resource.c index 10abee4e8f6..e2f112328fc 100644 --- a/src/gallium/drivers/v3d/v3d_resource.c +++ b/src/gallium/drivers/v3d/v3d_resource.c @@ -179,7 +179,7 @@ v3d_map_usage_prep(struct pipe_context *pctx, if (usage & PIPE_TRANSFER_WRITE) v3d_flush_jobs_reading_resource(v3d, prsc); else - v3d_flush_jobs_writing_resource(v3d, prsc); + v3d_flush_jobs_writing_resource(v3d, prsc, true); } if (usage & PIPE_TRANSFER_WRITE) { diff --git a/src/gallium/drivers/v3d/v3dx_draw.c b/src/gallium/drivers/v3d/v3dx_draw.c index 201813c69d6..0d23ac6bb2d 100644 --- a/src/gallium/drivers/v3d/v3dx_draw.c +++ b/src/gallium/drivers/v3d/v3dx_draw.c @@ -145,11 +145,6 @@ v3d_predraw_check_stage_inputs(struct pipe_context *pctx, { struct v3d_context *v3d = v3d_context(pctx); - /* XXX perf: If we're reading from the output of TF in this job, we - * should instead be using the wait for transform feedback - * functionality. - */ - /* Flush writes to textures we're sampling. */ for (int i = 0; i < v3d->tex[s].num_textures; i++) { struct pipe_sampler_view *pview = v3d->tex[s].textures[i]; @@ -161,21 +156,22 @@ v3d_predraw_check_stage_inputs(struct pipe_context *pctx, view->base.format != PIPE_FORMAT_X32_S8X24_UINT) v3d_update_shadow_texture(pctx, &view->base); - v3d_flush_jobs_writing_resource(v3d, view->texture); + v3d_flush_jobs_writing_resource(v3d, view->texture, false); } /* Flush writes to UBOs. */ foreach_bit(i, v3d->constbuf[s].enabled_mask) { struct pipe_constant_buffer *cb = &v3d->constbuf[s].cb[i]; if (cb->buffer) - v3d_flush_jobs_writing_resource(v3d, cb->buffer); + v3d_flush_jobs_writing_resource(v3d, cb->buffer, false); } /* Flush writes to our image views */ foreach_bit(i, v3d->shaderimg[s].enabled_mask) { struct v3d_image_view *view = &v3d->shaderimg[s].si[i]; - v3d_flush_jobs_writing_resource(v3d, view->base.resource); + v3d_flush_jobs_writing_resource(v3d, view->base.resource, + false); } /* Flush writes to our vertex buffers (i.e. from transform feedback) */ @@ -183,7 +179,8 @@ v3d_predraw_check_stage_inputs(struct pipe_context *pctx, foreach_bit(i, v3d->vertexbuf.enabled_mask) { struct pipe_vertex_buffer *vb = &v3d->vertexbuf.vb[i]; - v3d_flush_jobs_writing_resource(v3d, vb->buffer.resource); + v3d_flush_jobs_writing_resource(v3d, vb->buffer.resource, + false); } } } @@ -654,8 +651,10 @@ v3d_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info) for (int s = 0; s < PIPE_SHADER_COMPUTE; s++) v3d_predraw_check_stage_inputs(pctx, s); - if (info->indirect) - v3d_flush_jobs_writing_resource(v3d, info->indirect->buffer); + if (info->indirect) { + v3d_flush_jobs_writing_resource(v3d, info->indirect->buffer, + false); + } v3d_predraw_check_outputs(pctx); -- 2.30.2