Mesa (main): r300: Precompile the FS at shader creation time.

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Wed Dec 8 02:46:11 UTC 2021


Module: Mesa
Branch: main
Commit: 141302e61f4f2f6b0e148baae31e36a740abf337
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=141302e61f4f2f6b0e148baae31e36a740abf337

Author: Emma Anholt <emma at anholt.net>
Date:   Tue Dec  7 09:51:35 2021 -0800

r300: Precompile the FS at shader creation time.

This should reduce jank at first draw, and is also good prep for doing
shader-db.

Reviewed-by: Marek Olšák <marek.olsak at amd.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/14117>

---

 src/gallium/drivers/r300/r300_fs.c            | 20 ++++++++------------
 src/gallium/drivers/r300/r300_fs.h            |  6 +++++-
 src/gallium/drivers/r300/r300_state.c         | 13 ++++++++++++-
 src/gallium/drivers/r300/r300_state_derived.c |  6 +++++-
 4 files changed, 30 insertions(+), 15 deletions(-)

diff --git a/src/gallium/drivers/r300/r300_fs.c b/src/gallium/drivers/r300/r300_fs.c
index d1904c5dafc..382f39b006c 100644
--- a/src/gallium/drivers/r300/r300_fs.c
+++ b/src/gallium/drivers/r300/r300_fs.c
@@ -142,7 +142,7 @@ static void allocate_hardware_inputs(
     }
 }
 
-static void get_external_state(
+void r300_fragment_program_get_external_state(
     struct r300_context* r300,
     struct r300_fragment_program_external_state* state)
 {
@@ -559,32 +559,28 @@ static void r300_translate_fragment_shader(
     r300_emit_fs_code_to_buffer(r300, shader);
 }
 
-boolean r300_pick_fragment_shader(struct r300_context* r300)
+boolean r300_pick_fragment_shader(struct r300_context *r300,
+                                  struct r300_fragment_shader* fs,
+                                  struct r300_fragment_program_external_state *state)
 {
-    struct r300_fragment_shader* fs = r300_fs(r300);
-    struct r300_fragment_program_external_state state;
     struct r300_fragment_shader_code* ptr;
 
-    memset(&state, 0, sizeof(state));
-    get_external_state(r300, &state);
-
     if (!fs->first) {
         /* Build the fragment shader for the first time. */
         fs->first = fs->shader = CALLOC_STRUCT(r300_fragment_shader_code);
 
-        memcpy(&fs->shader->compare_state, &state,
-            sizeof(struct r300_fragment_program_external_state));
+        memcpy(&fs->shader->compare_state, state, sizeof(*state));
         r300_translate_fragment_shader(r300, fs->shader, fs->state.tokens);
         return TRUE;
 
     } else {
         /* Check if the currently-bound shader has been compiled
          * with the texture-compare state we need. */
-        if (memcmp(&fs->shader->compare_state, &state, sizeof(state)) != 0) {
+        if (memcmp(&fs->shader->compare_state, state, sizeof(*state)) != 0) {
             /* Search for the right shader. */
             ptr = fs->first;
             while (ptr) {
-                if (memcmp(&ptr->compare_state, &state, sizeof(state)) == 0) {
+                if (memcmp(&ptr->compare_state, state, sizeof(*state)) == 0) {
                     if (fs->shader != ptr) {
                         fs->shader = ptr;
                         return TRUE;
@@ -600,7 +596,7 @@ boolean r300_pick_fragment_shader(struct r300_context* r300)
             ptr->next = fs->first;
             fs->first = fs->shader = ptr;
 
-            ptr->compare_state = state;
+            memcpy(&ptr->compare_state, state, sizeof(*state));
             r300_translate_fragment_shader(r300, ptr, fs->state.tokens);
             return TRUE;
         }
diff --git a/src/gallium/drivers/r300/r300_fs.h b/src/gallium/drivers/r300/r300_fs.h
index b39624dad5f..30284f3e12f 100644
--- a/src/gallium/drivers/r300/r300_fs.h
+++ b/src/gallium/drivers/r300/r300_fs.h
@@ -75,7 +75,11 @@ void r300_shader_read_fs_inputs(struct tgsi_shader_info* info,
                                 struct r300_shader_semantics* fs_inputs);
 
 /* Return TRUE if the shader was switched and should be re-emitted. */
-boolean r300_pick_fragment_shader(struct r300_context* r300);
+boolean r300_pick_fragment_shader(struct r300_context *r300,
+                                  struct r300_fragment_shader* fs,
+                                  struct r300_fragment_program_external_state *state);
+void r300_fragment_program_get_external_state(struct r300_context *r300,
+                                              struct r300_fragment_program_external_state *state);
 
 static inline boolean r300_fragment_shader_writes_depth(struct r300_fragment_shader *fs)
 {
diff --git a/src/gallium/drivers/r300/r300_state.c b/src/gallium/drivers/r300/r300_state.c
index 3e1096b6e86..39c442802af 100644
--- a/src/gallium/drivers/r300/r300_state.c
+++ b/src/gallium/drivers/r300/r300_state.c
@@ -1034,6 +1034,7 @@ r300_set_framebuffer_state(struct pipe_context* pipe,
 static void* r300_create_fs_state(struct pipe_context* pipe,
                                   const struct pipe_shader_state* shader)
 {
+    struct r300_context* r300 = r300_context(pipe);
     struct r300_fragment_shader* fs = NULL;
 
     fs = (struct r300_fragment_shader*)CALLOC_STRUCT(r300_fragment_shader);
@@ -1042,7 +1043,17 @@ static void* r300_create_fs_state(struct pipe_context* pipe,
     fs->state = *shader;
     fs->state.tokens = tgsi_dup_tokens(shader->tokens);
 
-    return (void*)fs;
+    /* Precompile the fragment shader at creation time to avoid jank at runtime.
+     * In most cases we won't have anything in the key at draw time.
+     *
+     * TODO: precompile state for shadow samplers (but this needs a decision for
+     * the default shadow compare and texture swizzle values).
+     */
+    struct r300_fragment_program_external_state precompile_state;
+    memset(&precompile_state, 0, sizeof(precompile_state));
+    r300_pick_fragment_shader(r300, fs, &precompile_state);
+
+    return (void *)fs;
 }
 
 void r300_mark_fs_code_dirty(struct r300_context *r300)
diff --git a/src/gallium/drivers/r300/r300_state_derived.c b/src/gallium/drivers/r300/r300_state_derived.c
index 0e1ab4c940f..d9c2aba70a3 100644
--- a/src/gallium/drivers/r300/r300_state_derived.c
+++ b/src/gallium/drivers/r300/r300_state_derived.c
@@ -1034,10 +1034,14 @@ static void r300_validate_fragment_shader(struct r300_context *r300)
     struct pipe_framebuffer_state *fb = r300->fb_state.state;
 
     if (r300->fs.state && r300->fs_status != FRAGMENT_SHADER_VALID) {
+        struct r300_fragment_program_external_state state;
+        memset(&state, 0, sizeof(state));
+        r300_fragment_program_get_external_state(r300, &state);
+
         /* Pick the fragment shader based on external states.
          * Then mark the state dirty if the fragment shader is either dirty
          * or the function r300_pick_fragment_shader changed the shader. */
-        if (r300_pick_fragment_shader(r300) ||
+        if (r300_pick_fragment_shader(r300, r300_fs(r300), &state) ||
             r300->fs_status == FRAGMENT_SHADER_DIRTY) {
             /* Mark the state atom as dirty. */
             r300_mark_fs_code_dirty(r300);



More information about the mesa-commit mailing list