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 d42e8fd0e6979f2345e41f5df93c190eaaf74b0c..e177369dd10187a39993b8bdf4df36c4a5395c9e 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 7c8952ebb74f4265c11f097fb336d94c3e86a7d9..9143f53cee8673b27c197cb012dfa9018646eb79 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 6f3fa709616222b5fa7d5dfb32e12f4f7d733afb..9b24f12e7e9b85f0487a5e4ccb7a4d21a4210709 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 10abee4e8f68e7933f13ed55f7308772262ed0b2..e2f112328fc10b042cf916599006079fd0152d95 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 201813c69d6d2a164235ac9d3a75842107d4ced4..0d23ac6bb2d471209c9472c48fb8f9666c87d38e 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);