st/mesa: add a faster path for uploading state parameters into constant buffers
authorMarek Olšák <marek.olsak@amd.com>
Mon, 28 Sep 2020 03:00:22 +0000 (23:00 -0400)
committerMarge Bot <eric+marge@anholt.net>
Tue, 1 Dec 2020 11:52:10 +0000 (11:52 +0000)
The old path copies state parameters into the parameter list, and then
the driver copies them into a buffer.

The optional new path loads state parameters into a buffer directly.
This increases performance by 5% in one subtest of viewperf.

Acked-by: Pierre-Eric Pelloux-Prayer <pierre-eric.pelloux-prayer@amd.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/6946>

src/mesa/state_tracker/st_atom_constbuf.c
src/mesa/state_tracker/st_context.c
src/mesa/state_tracker/st_context.h
src/mesa/state_tracker/st_draw_feedback.c

index 5612bb5f79623c76476b1fc7701a27e6a446ca10..f67772d33c4055576e6fba66cfaf0864aa6bf290 100644 (file)
@@ -94,21 +94,8 @@ st_upload_constants(struct st_context *st, struct gl_program *prog)
       struct pipe_constant_buffer cb;
       const uint paramBytes = params->NumParameterValues * sizeof(GLfloat);
 
-      /* Update the constants which come from fixed-function state, such as
-       * transformation matrices, fog factors, etc.  The rest of the values in
-       * the parameters list are explicitly set by the user with glUniform,
-       * glProgramParameter(), etc.
-       */
-      if (params->StateFlags)
-         _mesa_load_state_parameters(st->ctx, params);
-
       _mesa_shader_write_subroutine_indices(st->ctx, stage);
 
-      cb.buffer = NULL;
-      cb.user_buffer = params->ParameterValues;
-      cb.buffer_offset = 0;
-      cb.buffer_size = paramBytes;
-
       if (ST_DEBUG & DEBUG_CONSTANTS) {
          debug_printf("%s(shader=%d, numParams=%d, stateFlags=0x%x)\n",
                       __func__, shader_type, params->NumParameters,
@@ -116,22 +103,86 @@ st_upload_constants(struct st_context *st, struct gl_program *prog)
          _mesa_print_parameter_list(params);
       }
 
-      cso_set_constant_buffer(st->cso_context, shader_type, 0, &cb);
-      pipe_resource_reference(&cb.buffer, NULL);
+      cb.buffer = NULL;
+      cb.user_buffer = NULL;
+      cb.buffer_offset = 0;
+      cb.buffer_size = paramBytes;
+
+      if (st->prefer_real_buffer_in_constbuf0) {
+         uint32_t *ptr;
+         /* fetch_state always stores 4 components (16 bytes) per matrix row,
+          * but matrix rows are sometimes allocated partially, so add 12
+          * to compensate for the fetch_state defect.
+          */
+         u_upload_alloc(st->pipe->const_uploader, 0, paramBytes + 12, 64,
+                        &cb.buffer_offset, &cb.buffer, (void**)&ptr);
+
+         int uniform_bytes = params->UniformBytes;
+         if (uniform_bytes)
+            memcpy(ptr, params->ParameterValues, uniform_bytes);
+
+         /* Upload the constants which come from fixed-function state, such as
+          * transformation matrices, fog factors, etc.
+          */
+         if (params->StateFlags)
+            _mesa_upload_state_parameters(st->ctx, params, ptr);
+
+         u_upload_unmap(st->pipe->const_uploader);
+         cso_set_constant_buffer(st->cso_context, shader_type, 0, &cb);
+         pipe_resource_reference(&cb.buffer, NULL);
+
+         /* Set inlinable constants. This is more involved because state
+          * parameters are uploaded directly above instead of being loaded
+          * into gl_program_parameter_list. The easiest way to get their values
+          * is to load them.
+          */
+         unsigned num_inlinable_uniforms = prog->info.num_inlinable_uniforms;
+         if (num_inlinable_uniforms) {
+            struct pipe_context *pipe = st->pipe;
+            uint32_t values[MAX_INLINABLE_UNIFORMS];
+            gl_constant_value *constbuf = params->ParameterValues;
+            bool loaded_state_vars = false;
+
+            for (unsigned i = 0; i < num_inlinable_uniforms; i++) {
+               unsigned dw_offset = prog->info.inlinable_uniform_dw_offsets[i];
+
+               if (dw_offset * 4 >= uniform_bytes && !loaded_state_vars) {
+                  _mesa_load_state_parameters(st->ctx, params);
+                  loaded_state_vars = true;
+               }
+
+               values[i] = constbuf[prog->info.inlinable_uniform_dw_offsets[i]].u;
+            }
+
+            pipe->set_inlinable_constants(pipe, shader_type,
+                                          prog->info.num_inlinable_uniforms,
+                                          values);
+         }
+      } else {
+         cb.user_buffer = params->ParameterValues;
+
+         /* Update the constants which come from fixed-function state, such as
+          * transformation matrices, fog factors, etc.
+          */
+         if (params->StateFlags)
+            _mesa_load_state_parameters(st->ctx, params);
+
+         cso_set_constant_buffer(st->cso_context, shader_type, 0, &cb);
 
-      /* Set inlinable constants. */
-      unsigned num_inlinable_uniforms = prog->info.num_inlinable_uniforms;
-      if (num_inlinable_uniforms) {
-         struct pipe_context *pipe = st->pipe;
-         uint32_t values[MAX_INLINABLE_UNIFORMS];
-         gl_constant_value *constbuf = params->ParameterValues;
+         /* Set inlinable constants. */
+         unsigned num_inlinable_uniforms = prog->info.num_inlinable_uniforms;
+         if (num_inlinable_uniforms) {
+            struct pipe_context *pipe = st->pipe;
+            uint32_t values[MAX_INLINABLE_UNIFORMS];
+            gl_constant_value *constbuf = params->ParameterValues;
 
-         for (unsigned i = 0; i < num_inlinable_uniforms; i++)
-            values[i] = constbuf[prog->info.inlinable_uniform_dw_offsets[i]].u;
+            for (unsigned i = 0; i < num_inlinable_uniforms; i++)
+               values[i] = constbuf[prog->info.inlinable_uniform_dw_offsets[i]].u;
 
-         pipe->set_inlinable_constants(pipe, shader_type,
-                                       prog->info.num_inlinable_uniforms,
-                                       values);
+            pipe->set_inlinable_constants(pipe, shader_type,
+                                          prog->info.num_inlinable_uniforms,
+                                          values);
+         }
       }
 
       st->state.constants[shader_type].ptr = params->ParameterValues;
index 1605e4682e80f9e974dc44554d8cd10fdeafe27f..bd5581a19aa39545d0a015bab56a91f067e79926 100644 (file)
@@ -700,6 +700,8 @@ st_create_context_priv(struct gl_context *ctx, struct pipe_context *pipe,
       !screen->get_param(screen, PIPE_CAP_TWO_SIDED_COLOR);
    st->lower_ucp =
       !screen->get_param(screen, PIPE_CAP_CLIP_PLANES);
+   st->prefer_real_buffer_in_constbuf0 =
+      screen->get_param(screen, PIPE_CAP_PREFER_REAL_BUFFER_IN_CONSTBUF0);
    st->allow_st_finalize_nir_twice = screen->finalize_nir != NULL;
 
    st->has_hw_atomics =
index d467dee50e853445dd12ff1c68040067a80cc495..8f2a109ab090a862acc1e7a9f6dfbcc1ed1bf152 100644 (file)
@@ -153,6 +153,7 @@ struct st_context
    boolean lower_point_size;
    boolean lower_two_sided_color;
    boolean lower_ucp;
+   boolean prefer_real_buffer_in_constbuf0;
 
    /* There are consequences for drivers wanting to call st_finalize_nir
     * twice, once before shader caching and once after lowering for shader
index 174a0f77e98ed27f2b3626a46fb11955987f2288..adfdffb39bd2445ce467cf1b96013171f9399d74 100644 (file)
@@ -223,11 +223,24 @@ st_feedback_draw_vbo(struct gl_context *ctx,
       info.has_user_indices = false;
    }
 
-   /* set constant buffers */
+   /* set constant buffer 0 */
+   struct gl_program_parameter_list *params = st->vp->Base.Parameters;
+
+   /* Update the constants which come from fixed-function state, such as
+    * transformation matrices, fog factors, etc.
+    *
+    * It must be done here if the state tracker doesn't update state vars
+    * in gl_program_parameter_list because allow_constbuf0_as_real_buffer
+    * is set.
+    */
+   if (st->prefer_real_buffer_in_constbuf0 && params->StateFlags)
+      _mesa_load_state_parameters(st->ctx, params);
+
    draw_set_mapped_constant_buffer(draw, PIPE_SHADER_VERTEX, 0,
                                    st->state.constants[PIPE_SHADER_VERTEX].ptr,
                                    st->state.constants[PIPE_SHADER_VERTEX].size);
 
+   /* set uniform buffers */
    const struct gl_program *prog = &vp->Base.Base;
    struct pipe_transfer *ubo_transfer[PIPE_MAX_CONSTANT_BUFFERS] = {0};
    assert(prog->info.num_ubos <= ARRAY_SIZE(ubo_transfer));