r300g: add support for color0 writes to all bound color buffers.
authorDave Airlie <airlied@redhat.com>
Sat, 18 Dec 2010 00:40:33 +0000 (10:40 +1000)
committerDave Airlie <airlied@redhat.com>
Thu, 23 Dec 2010 21:19:58 +0000 (07:19 +1000)
Thanks to Marek Olšák for making my initial attempt actually work.

Signed-off-by: Dave Airlie <airlied@redhat.com>
src/gallium/drivers/r300/r300_context.h
src/gallium/drivers/r300/r300_emit.c
src/gallium/drivers/r300/r300_fs.c
src/gallium/drivers/r300/r300_fs.h
src/gallium/drivers/r300/r300_state.c

index 39dcde0610690ab6ecfc5ff5813956c76272e35a..247f26d7a766f038af9dbfe5f4ebc1f9d4f75b1f 100644 (file)
@@ -697,7 +697,8 @@ void r500_emit_index_bias(struct r300_context *r300, int index_bias);
 enum r300_fb_state_change {
     R300_CHANGED_FB_STATE = 0,
     R300_CHANGED_CBZB_FLAG,
-    R300_CHANGED_ZCLEAR_FLAG
+    R300_CHANGED_ZCLEAR_FLAG,
+    R300_CHANGED_MULTIWRITE
 };
 
 void r300_mark_fb_state_dirty(struct r300_context *r300,
index 9e0df30e5274e50b549802096097caf03a4cec1b..de78c96f11a4bfe0d6426d784425b4d9e4c84b80 100644 (file)
@@ -369,6 +369,8 @@ void r300_emit_fb_state(struct r300_context* r300, unsigned size, void* state)
     struct r300_surface* surf;
     unsigned i;
     boolean can_hyperz = r300->rws->get_value(r300->rws, R300_CAN_HYPERZ);
+    uint32_t rb3d_cctl = 0;
+
     CS_LOCALS(r300);
 
     BEGIN_CS(size);
@@ -376,11 +378,13 @@ void r300_emit_fb_state(struct r300_context* r300, unsigned size, void* state)
     /* NUM_MULTIWRITES replicates COLOR[0] to all colorbuffers, which is not
      * what we usually want. */
     if (r300->screen->caps.is_r500) {
-        OUT_CS_REG(R300_RB3D_CCTL,
-            R300_RB3D_CCTL_INDEPENDENT_COLORFORMAT_ENABLE_ENABLE);
-    } else {
-        OUT_CS_REG(R300_RB3D_CCTL, 0);
+        rb3d_cctl = R300_RB3D_CCTL_INDEPENDENT_COLORFORMAT_ENABLE_ENABLE;
     }
+    if (r300_fragment_shader_writes_all(r300_fs(r300))) {
+        rb3d_cctl |= R300_RB3D_CCTL_NUM_MULTIWRITES(fb->nr_cbufs);
+    }
+
+    OUT_CS_REG(R300_RB3D_CCTL, rb3d_cctl);
 
     /* Set up colorbuffers. */
     for (i = 0; i < fb->nr_cbufs; i++) {
@@ -482,15 +486,21 @@ void r300_emit_fb_state_pipelined(struct r300_context *r300,
 {
     struct pipe_framebuffer_state* fb =
             (struct pipe_framebuffer_state*)r300->fb_state.state;
-    unsigned i;
+    unsigned i, num_cbufs = fb->nr_cbufs;
     CS_LOCALS(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))) {
+        num_cbufs = MIN2(num_cbufs, 1);
+    }
+
     BEGIN_CS(size);
 
     /* Colorbuffer format in the US block.
      * (must be written after unpipelined regs) */
     OUT_CS_REG_SEQ(R300_US_OUT_FMT_0, 4);
-    for (i = 0; i < fb->nr_cbufs; i++) {
+    for (i = 0; i < num_cbufs; i++) {
         OUT_CS(r300_surface(fb->cbufs[i])->format);
     }
     for (; i < 4; i++) {
index 2936c3486e2e0183c743b0edd4808ca3730d7fd5..6d4091dc87da2180f4c1de8fa56d962a6ff718ef 100644 (file)
@@ -395,6 +395,13 @@ static void r300_translate_fragment_shader(
 
     find_output_registers(&compiler, shader);
 
+    shader->write_all = FALSE;
+    for (i = 0; i < shader->info.num_properties; i++) {
+        if (shader->info.properties[i].name == TGSI_PROPERTY_FS_COLOR0_WRITES_ALL_CBUFS) {
+            shader->write_all = TRUE;
+        }
+    }
+
     if (compiler.Base.Debug & RC_DBG_LOG) {
         DBG(r300, DBG_FP, "r300: Initial fragment program\n");
         tgsi_dump(tokens, 0);
index 51bfa88c5ef221bb731864385fbed90c62218357..c86a90b85ae40059ff5fec747d066d3673bebc3c 100644 (file)
@@ -54,6 +54,9 @@ struct r300_fragment_shader_code {
     uint32_t *cb_code;
 
     struct r300_fragment_shader_code* next;
+
+    boolean write_all;
+
 };
 
 struct r300_fragment_shader {
@@ -81,4 +84,10 @@ static INLINE boolean r300_fragment_shader_writes_depth(struct r300_fragment_sha
     return (fs->shader->code.writes_depth) ? TRUE : FALSE;
 }
 
+static INLINE boolean r300_fragment_shader_writes_all(struct r300_fragment_shader *fs)
+{
+    if (!fs)
+        return FALSE;
+    return (fs->shader->write_all) ? TRUE : FALSE;
+}
 #endif /* R300_FS_H */
index f902db54cc1693a397c8d58c907de6c4d6c06b16..62c4f8d85a37cb1d67ab04b345cf4a8f2f28b287 100644 (file)
@@ -686,13 +686,22 @@ void r300_mark_fb_state_dirty(struct r300_context *r300,
     struct pipe_framebuffer_state *state = r300->fb_state.state;
     boolean can_hyperz = r300->rws->get_value(r300->rws, R300_CAN_HYPERZ);
 
-    /* What is marked as dirty depends on the enum r300_fb_state_change. */
     r300_mark_atom_dirty(r300, &r300->gpu_flush);
     r300_mark_atom_dirty(r300, &r300->fb_state);
-    r300_mark_atom_dirty(r300, &r300->hyperz_state);
 
+    /* What is marked as dirty depends on the enum r300_fb_state_change. */
     if (change == R300_CHANGED_FB_STATE) {
         r300_mark_atom_dirty(r300, &r300->aa_state);
+    }
+
+    if (change == R300_CHANGED_FB_STATE ||
+        change == R300_CHANGED_CBZB_FLAG ||
+        change == R300_CHANGED_ZCLEAR_FLAG) {
+        r300_mark_atom_dirty(r300, &r300->hyperz_state);
+    }
+
+    if (change == R300_CHANGED_FB_STATE ||
+        change == R300_CHANGED_MULTIWRITE) {
         r300_mark_atom_dirty(r300, &r300->fb_state_pipelined);
     }
 
@@ -876,16 +885,25 @@ 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_mark_atom_dirty(r300, &r300->rs_block_state); /* Will be updated before the emission. */
 }