v3d: do not flush jobs that are synced with 'Wait for transform feedback'
authorIago Toral Quiroga <itoral@igalia.com>
Thu, 20 Jun 2019 11:46:02 +0000 (13:46 +0200)
committerIago Toral Quiroga <itoral@igalia.com>
Tue, 2 Jul 2019 06:57:20 +0000 (08:57 +0200)
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 <eric@anholt.net>
src/gallium/drivers/v3d/v3d_blit.c
src/gallium/drivers/v3d/v3d_context.h
src/gallium/drivers/v3d/v3d_job.c
src/gallium/drivers/v3d/v3d_resource.c
src/gallium/drivers/v3d/v3dx_draw.c

index d42e8fd..e177369 100644 (file)
@@ -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);
 }
index 7c8952e..9143f53 100644 (file)
@@ -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);
index 6f3fa70..9b24f12 100644 (file)
@@ -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;
index 10abee4..e2f1123 100644 (file)
@@ -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) {
index 201813c..0d23ac6 100644 (file)
@@ -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);