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