summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2010-12-18 10:40:33 +1000
committerDave Airlie <airlied@redhat.com>2010-12-24 07:19:58 +1000
commit4e52e8f746e3565bf3fe9ba8e4e3744ce0302478 (patch)
treedf021c5a0e71e52d2110af32435e12d3c41bf274 /src
parent07498075b5de14955958da44a90eb7ee203218a1 (diff)
r300g: add support for color0 writes to all bound color buffers.
Thanks to Marek Olšák for making my initial attempt actually work. Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'src')
-rw-r--r--src/gallium/drivers/r300/r300_context.h3
-rw-r--r--src/gallium/drivers/r300/r300_emit.c22
-rw-r--r--src/gallium/drivers/r300/r300_fs.c7
-rw-r--r--src/gallium/drivers/r300/r300_fs.h9
-rw-r--r--src/gallium/drivers/r300/r300_state.c22
5 files changed, 54 insertions, 9 deletions
diff --git a/src/gallium/drivers/r300/r300_context.h b/src/gallium/drivers/r300/r300_context.h
index 39dcde0610..247f26d7a7 100644
--- a/src/gallium/drivers/r300/r300_context.h
+++ b/src/gallium/drivers/r300/r300_context.h
@@ -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,
diff --git a/src/gallium/drivers/r300/r300_emit.c b/src/gallium/drivers/r300/r300_emit.c
index 9e0df30e52..de78c96f11 100644
--- a/src/gallium/drivers/r300/r300_emit.c
+++ b/src/gallium/drivers/r300/r300_emit.c
@@ -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++) {
diff --git a/src/gallium/drivers/r300/r300_fs.c b/src/gallium/drivers/r300/r300_fs.c
index 2936c3486e..6d4091dc87 100644
--- a/src/gallium/drivers/r300/r300_fs.c
+++ b/src/gallium/drivers/r300/r300_fs.c
@@ -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);
diff --git a/src/gallium/drivers/r300/r300_fs.h b/src/gallium/drivers/r300/r300_fs.h
index 51bfa88c5e..c86a90b85a 100644
--- a/src/gallium/drivers/r300/r300_fs.h
+++ b/src/gallium/drivers/r300/r300_fs.h
@@ -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 */
diff --git a/src/gallium/drivers/r300/r300_state.c b/src/gallium/drivers/r300/r300_state.c
index f902db54cc..62c4f8d85a 100644
--- a/src/gallium/drivers/r300/r300_state.c
+++ b/src/gallium/drivers/r300/r300_state.c
@@ -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. */
}