Mesa (master): r300g: postpone fragment shader state validation until draw_vbo

Marek Olšák mareko at kemper.freedesktop.org
Tue Apr 5 10:34:31 PDT 2011


Module: Mesa
Branch: master
Commit: 4af3fe857dc07923af8786b434dee32d493b577e
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=4af3fe857dc07923af8786b434dee32d493b577e

Author: Marek Olšák <maraeo at gmail.com>
Date:   Tue Apr  5 17:57:02 2011 +0200

r300g: postpone fragment shader state validation until draw_vbo

---

 src/gallium/drivers/r300/r300_context.h       |   11 +++++++
 src/gallium/drivers/r300/r300_emit.c          |    5 +--
 src/gallium/drivers/r300/r300_state.c         |   19 +++---------
 src/gallium/drivers/r300/r300_state_derived.c |   39 +++++++++++++++++++++---
 4 files changed, 52 insertions(+), 22 deletions(-)

diff --git a/src/gallium/drivers/r300/r300_context.h b/src/gallium/drivers/r300/r300_context.h
index 3b6cb8f..550d3a7 100644
--- a/src/gallium/drivers/r300/r300_context.h
+++ b/src/gallium/drivers/r300/r300_context.h
@@ -447,6 +447,13 @@ enum r300_hiz_func {
     HIZ_FUNC_MIN,
 };
 
+/* For deferred fragment shader state validation. */
+enum r300_fs_validity_status {
+    FRAGMENT_SHADER_VALID,      /* No need to change/validate the FS. */
+    FRAGMENT_SHADER_MAYBE_DIRTY,/* Validate the FS if external state was changed. */
+    FRAGMENT_SHADER_DIRTY       /* Always validate the FS (if the FS was changed) */
+};
+
 struct r300_context {
     /* Parent class */
     struct pipe_context context;
@@ -598,6 +605,10 @@ struct r300_context {
     enum r300_hiz_func hiz_func;
     /* HiZ clear value. */
     uint32_t hiz_clear_value;
+    /* Whether fragment shader needs to be validated. */
+    enum r300_fs_validity_status fs_status;
+    /* Framebuffer multi-write. */
+    boolean fb_multiwrite;
 
     void *dsa_decompress_zmask;
 
diff --git a/src/gallium/drivers/r300/r300_emit.c b/src/gallium/drivers/r300/r300_emit.c
index 3b79b36..6b91f93 100644
--- a/src/gallium/drivers/r300/r300_emit.c
+++ b/src/gallium/drivers/r300/r300_emit.c
@@ -387,8 +387,7 @@ void r300_emit_fb_state(struct r300_context* r300, unsigned size, void* state)
     if (r300->screen->caps.is_r500) {
         rb3d_cctl = R300_RB3D_CCTL_INDEPENDENT_COLORFORMAT_ENABLE_ENABLE;
     }
-    if (fb->nr_cbufs &&
-        r300_fragment_shader_writes_all(r300_fs(r300))) {
+    if (fb->nr_cbufs && r300->fb_multiwrite) {
         rb3d_cctl |= R300_RB3D_CCTL_NUM_MULTIWRITES(fb->nr_cbufs);
     }
 
@@ -483,7 +482,7 @@ void r300_emit_fb_state_pipelined(struct r300_context *r300,
 
     /* If we use the multiwrite feature, the colorbuffers 2,3,4 must be
      * marked as UNUSED in the US block. */
-    if (r300_fragment_shader_writes_all(r300_fs(r300))) {
+    if (r300->fb_multiwrite) {
         num_cbufs = MIN2(num_cbufs, 1);
     }
 
diff --git a/src/gallium/drivers/r300/r300_state.c b/src/gallium/drivers/r300/r300_state.c
index 890e396..61d6751 100644
--- a/src/gallium/drivers/r300/r300_state.c
+++ b/src/gallium/drivers/r300/r300_state.c
@@ -969,24 +969,14 @@ static void r300_bind_fs_state(struct pipe_context* pipe, void* shader)
 {
     struct r300_context* r300 = r300_context(pipe);
     struct r300_fragment_shader* fs = (struct r300_fragment_shader*)shader;
-    struct pipe_framebuffer_state *fb = r300->fb_state.state;
-    boolean last_multi_write;
 
     if (fs == NULL) {
         r300->fs.state = NULL;
         return;
     }
 
-    last_multi_write = r300_fragment_shader_writes_all(r300_fs(r300));
-
     r300->fs.state = fs;
-    r300_pick_fragment_shader(r300);
-    r300_mark_fs_code_dirty(r300);
-
-    if (fb->nr_cbufs > 1 &&
-        last_multi_write != r300_fragment_shader_writes_all(fs)) {
-        r300_mark_fb_state_dirty(r300, R300_CHANGED_MULTIWRITE);
-    }
+    r300->fs_status = FRAGMENT_SHADER_DIRTY;
 
     r300_mark_atom_dirty(r300, &r300->rs_block_state); /* Will be updated before the emission. */
 }
@@ -1256,8 +1246,8 @@ static void r300_bind_rs_state(struct pipe_context* pipe, void* state)
     }
 
     if (last_frag_clamp != r300->frag_clamp &&
-        r300->fs.state && r300_pick_fragment_shader(r300)) {
-        r300_mark_fs_code_dirty(r300);
+        r300->fs_status == FRAGMENT_SHADER_VALID) {
+        r300->fs_status = FRAGMENT_SHADER_MAYBE_DIRTY;
     }
 }
 
@@ -1555,7 +1545,8 @@ static void r300_set_viewport_state(struct pipe_context* pipe,
     }
 
     r300_mark_atom_dirty(r300, &r300->viewport_state);
-    if (r300->fs.state && r300_fs(r300)->shader->inputs.wpos != ATTR_UNUSED) {
+    if (r300->fs.state && r300_fs(r300)->shader &&
+        r300_fs(r300)->shader->inputs.wpos != ATTR_UNUSED) {
         r300_mark_atom_dirty(r300, &r300->fs_rc_constant_state);
     }
 }
diff --git a/src/gallium/drivers/r300/r300_state_derived.c b/src/gallium/drivers/r300/r300_state_derived.c
index 02fc121..e943f1a 100644
--- a/src/gallium/drivers/r300/r300_state_derived.c
+++ b/src/gallium/drivers/r300/r300_state_derived.c
@@ -961,11 +961,10 @@ static void r300_merge_textures_and_samplers(struct r300_context* r300)
     r300->textures_state.size = size;
 
     /* Pick a fragment shader based on either the texture compare state
-     * or the uses_pitch flag. */
-    if (r300->fs.state && count) {
-        if (r300_pick_fragment_shader(r300)) {
-            r300_mark_fs_code_dirty(r300);
-        }
+     * or the uses_pitch flag or some other external state. */
+    if (count &&
+        r300->fs_status == FRAGMENT_SHADER_VALID) {
+        r300->fs_status = FRAGMENT_SHADER_MAYBE_DIRTY;
     }
 }
 
@@ -994,6 +993,34 @@ static void r300_decompress_depth_textures(struct r300_context *r300)
     }
 }
 
+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) {
+        /* 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) ||
+            r300->fs_status == FRAGMENT_SHADER_DIRTY) {
+            /* Mark the state atom as dirty. */
+            r300_mark_fs_code_dirty(r300);
+
+            /* Does Multiwrite need to be changed? */
+            if (fb->nr_cbufs > 1) {
+                boolean new_multiwrite =
+                    r300_fragment_shader_writes_all(r300_fs(r300));
+
+                if (r300->fb_multiwrite != new_multiwrite) {
+                    r300->fb_multiwrite = new_multiwrite;
+                    r300_mark_fb_state_dirty(r300, R300_CHANGED_MULTIWRITE);
+                }
+            }
+        }
+        r300->fs_status = FRAGMENT_SHADER_VALID;
+    }
+}
+
 void r300_update_derived_state(struct r300_context* r300)
 {
     if (r300->textures_state.dirty) {
@@ -1001,6 +1028,8 @@ void r300_update_derived_state(struct r300_context* r300)
         r300_merge_textures_and_samplers(r300);
     }
 
+    r300_validate_fragment_shader(r300);
+
     if (r300->rs_block_state.dirty) {
         r300_update_rs_block(r300);
 



More information about the mesa-commit mailing list