nir/scheduler: Add an option to specify what stages share memory for I/O
authorNeil Roberts <nroberts@igalia.com>
Wed, 17 Jun 2020 13:18:06 +0000 (15:18 +0200)
committerNeil Roberts <nroberts@igalia.com>
Mon, 22 Jun 2020 06:23:06 +0000 (08:23 +0200)
The scheduler has code to handle hardware that shares the same memory
for inputs and outputs. Seeing as the specific stages that need this is
probably hardware-dependent, this patch makes it a configurable option
instead of hard-coding it to everything but fragment shaders.

Reviewed-by: Eric Anholt <eric@anholt.net>
Reviewed-by: Iago Toral Quiroga <itoral@igalia.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/5561>

src/broadcom/compiler/vir.c
src/compiler/nir/nir.h
src/compiler/nir/nir_schedule.c

index adfd587d53401a27b60644f91fc07a84a62f3657..4c9e99cfd77cf7015e97a33da21a6bf6119ce6e7 100644 (file)
@@ -1072,10 +1072,20 @@ uint64_t *v3d_compile(const struct v3d_compiler *compiler,
         NIR_PASS_V(c->s, nir_lower_bool_to_int32);
         NIR_PASS_V(c->s, nir_convert_from_ssa, true);
 
-        /* Schedule for about half our register space, to enable more shaders
-         * to hit 4 threads.
-         */
-        NIR_PASS_V(c->s, nir_schedule, 24);
+        static const struct nir_schedule_options schedule_options = {
+                /* Schedule for about half our register space, to enable more
+                 * shaders to hit 4 threads.
+                 */
+                .threshold = 24,
+
+                /* Vertex shaders share the same memory for inputs and outputs,
+                 * fragement and geometry shaders do not.
+                 */
+                .stages_with_shared_io_memory =
+                (((1 << MESA_ALL_SHADER_STAGES) - 1) &
+                 ~(1 << MESA_SHADER_FRAGMENT)),
+        };
+        NIR_PASS_V(c->s, nir_schedule, &schedule_options);
 
         v3d_nir_to_vir(c);
 
index b0316df4ffa8f66978b3153a5ead65174e94cfbb..463e5468fc243645bc1d826c5f4fb4031e5ead6b 100644 (file)
@@ -4579,7 +4579,20 @@ bool nir_opt_load_store_vectorize(nir_shader *shader, nir_variable_mode modes,
                                   nir_should_vectorize_mem_func callback,
                                   nir_variable_mode robust_modes);
 
-void nir_schedule(nir_shader *shader, int threshold);
+typedef struct nir_schedule_options {
+   /* On some hardware with some stages the inputs and outputs to the shader
+    * share the same memory. In that case scheduler needs to ensure that all
+    * output writes are scheduled after all of the input writes to avoid
+    * overwriting them. This is a bitmask of stages that need that.
+    */
+   unsigned stages_with_shared_io_memory;
+   /* The approximate amount of register pressure at which point the scheduler
+    * will try to reduce register usage.
+    */
+   int threshold;
+} nir_schedule_options;
+
+void nir_schedule(nir_shader *shader, const nir_schedule_options *options);
 
 void nir_strip(nir_shader *shader);
 
index 469ec95c946d220e3dd37866f6ef3bc32a9e7439..9fa02547dc16d6eb5bcf5eede0521c7bf3285b96 100644 (file)
@@ -114,6 +114,9 @@ typedef struct {
     * pressure-prioritizing scheduling heuristic.
     */
    int threshold;
+
+   /* Mask of stages that share memory for inputs and outputs */
+   unsigned stages_with_shared_io_memory;
 } nir_schedule_scoreboard;
 
 /* When walking the instructions in reverse, we use this flag to swap
@@ -323,10 +326,11 @@ nir_schedule_intrinsic_deps(nir_deps_state *state,
       break;
 
    case nir_intrinsic_store_output:
-      /* For some non-FS shader stages, or for some hardware, output stores
-       * affect the same shared memory as input loads.
+      /* For some hardware and stages, output stores affect the same shared
+       * memory as input loads.
        */
-      if (state->scoreboard->shader->info.stage != MESA_SHADER_FRAGMENT)
+      if ((state->scoreboard->stages_with_shared_io_memory &
+           (1 << state->scoreboard->shader->info.stage)))
          add_write_dep(state, &state->load_input, n);
 
       /* Make sure that preceding discards stay before the store_output */
@@ -979,14 +983,17 @@ nir_schedule_ssa_def_init_scoreboard(nir_ssa_def *def, void *state)
 }
 
 static nir_schedule_scoreboard *
-nir_schedule_get_scoreboard(nir_shader *shader, int threshold)
+nir_schedule_get_scoreboard(nir_shader *shader,
+                            const nir_schedule_options *options)
 {
    nir_schedule_scoreboard *scoreboard = rzalloc(NULL, nir_schedule_scoreboard);
 
    scoreboard->shader = shader;
    scoreboard->live_values = _mesa_pointer_set_create(scoreboard);
    scoreboard->remaining_uses = _mesa_pointer_hash_table_create(scoreboard);
-   scoreboard->threshold = threshold;
+   scoreboard->threshold = options->threshold;
+   scoreboard->stages_with_shared_io_memory =
+      options->stages_with_shared_io_memory;
    scoreboard->pressure = 0;
 
    nir_foreach_function(function, shader) {
@@ -1063,10 +1070,11 @@ nir_schedule_validate_uses(nir_schedule_scoreboard *scoreboard)
  * tune.
  */
 void
-nir_schedule(nir_shader *shader, int threshold)
+nir_schedule(nir_shader *shader,
+             const nir_schedule_options *options)
 {
    nir_schedule_scoreboard *scoreboard = nir_schedule_get_scoreboard(shader,
-                                                                     threshold);
+                                                                     options);
 
    if (debug) {
       fprintf(stderr, "NIR shader before scheduling:\n");