diff options
Diffstat (limited to 'src/gallium/drivers/r300/r300_emit.c')
-rw-r--r-- | src/gallium/drivers/r300/r300_emit.c | 165 |
1 files changed, 134 insertions, 31 deletions
diff --git a/src/gallium/drivers/r300/r300_emit.c b/src/gallium/drivers/r300/r300_emit.c index 1b9de40afaa..1700cbb4667 100644 --- a/src/gallium/drivers/r300/r300_emit.c +++ b/src/gallium/drivers/r300/r300_emit.c @@ -90,12 +90,19 @@ void r300_emit_dsa_state(struct r300_context* r300, unsigned size, void* state) alpha_func |= R500_FG_ALPHA_FUNC_FP16_ENABLE; } else { alpha_func |= R500_FG_ALPHA_FUNC_8BIT; } } + /* Setup alpha-to-coverage. */ + if (r300->alpha_to_coverage && r300->msaa_enable) { + /* Always set 3/6, it improves precision even for 2x and 4x MSAA. */ + alpha_func |= R300_FG_ALPHA_FUNC_MASK_ENABLE | + R300_FG_ALPHA_FUNC_CFG_3_OF_6; + } + OUT_CS_REG(R300_FG_ALPHA_FUNC, alpha_func); WRITE_CS_TABLE(fb->zsbuf ? &dsa->cb_begin : dsa->cb_zb_no_readwrite, size-2); } static void get_rc_constant_state( float vec[4], @@ -363,18 +370,22 @@ void r300_emit_aa_state(struct r300_context *r300, unsigned size, void *state) CS_LOCALS(r300); BEGIN_CS(size); OUT_CS_REG(R300_GB_AA_CONFIG, aa->aa_config); if (aa->dest) { - OUT_CS_REG(R300_RB3D_AARESOLVE_OFFSET, aa->dest->offset); + OUT_CS_REG_SEQ(R300_RB3D_AARESOLVE_OFFSET, 3); + OUT_CS(aa->dest->offset); + OUT_CS(aa->dest->pitch & R300_RB3D_AARESOLVE_PITCH_MASK); + OUT_CS(R300_RB3D_AARESOLVE_CTL_AARESOLVE_MODE_RESOLVE | + R300_RB3D_AARESOLVE_CTL_AARESOLVE_ALPHA_AVERAGE); OUT_CS_RELOC(aa->dest); - OUT_CS_REG(R300_RB3D_AARESOLVE_PITCH, aa->dest->pitch); + } else { + OUT_CS_REG(R300_RB3D_AARESOLVE_CTL, 0); } - OUT_CS_REG(R300_RB3D_AARESOLVE_CTL, aa->aaresolve_ctl); END_CS; } void r300_emit_fb_state(struct r300_context* r300, unsigned size, void* state) { struct pipe_framebuffer_state* fb = (struct pipe_framebuffer_state*)state; @@ -472,18 +483,91 @@ void r300_emit_hyperz_end(struct r300_context *r300) z.sc_hyperz = R300_SC_HYPERZ_ADJ_2; z.gb_z_peq_config = 0; r300_emit_hyperz_state(r300, r300->hyperz_state.size, &z); } +#define R300_NIBBLES(x0, y0, x1, y1, x2, y2, d0y, d0x) \ + (((x0) & 0xf) | (((y0) & 0xf) << 4) | \ + (((x1) & 0xf) << 8) | (((y1) & 0xf) << 12) | \ + (((x2) & 0xf) << 16) | (((y2) & 0xf) << 20) | \ + (((d0y) & 0xf) << 24) | (((d0x) & 0xf) << 28)) + +static unsigned r300_get_mspos(int index, unsigned *p) +{ + unsigned reg, i, distx, disty, dist; + + if (index == 0) { + /* MSPOS0 contains positions for samples 0,1,2 as (X,Y) pairs of nibbles, + * followed by a (Y,X) pair containing the minimum distance from the pixel + * edge: + * X0, Y0, X1, Y1, X2, Y2, D0_Y, D0_X + * + * There is a quirk when setting D0_X. The value represents the distance + * from the left edge of the pixel quad to the first sample in subpixels. + * All values less than eight should use the actual value, but „7‟ should + * be used for the distance „8‟. The hardware will convert 7 into 8 internally. + */ + distx = 11; + for (i = 0; i < 12; i += 2) { + if (p[i] < distx) + distx = p[i]; + } + + disty = 11; + for (i = 1; i < 12; i += 2) { + if (p[i] < disty) + disty = p[i]; + } + + if (distx == 8) + distx = 7; + + reg = R300_NIBBLES(p[0], p[1], p[2], p[3], p[4], p[5], disty, distx); + } else { + /* MSPOS1 contains positions for samples 3,4,5 as (X,Y) pairs of nibbles, + * followed by the minimum distance from the pixel edge (not sure if X or Y): + * X3, Y3, X4, Y4, X5, Y5, D1 + */ + dist = 11; + for (i = 0; i < 12; i++) { + if (p[i] < dist) + dist = p[i]; + } + + reg = R300_NIBBLES(p[6], p[7], p[8], p[9], p[10], p[11], dist, 0); + } + return reg; +} + void r300_emit_fb_state_pipelined(struct r300_context *r300, unsigned size, void *state) { + /* The sample coordinates are in the range [0,11], because + * GB_TILE_CONFIG.SUBPIXEL is set to the 1/12 subpixel precision. + * + * Some sample coordinates reach to neighboring pixels and should not be used. + * (e.g. Y=11) + * + * The unused samples must be set to the positions of other valid samples. */ + static unsigned sample_locs_1x[12] = { + 6,6, 6,6, 6,6, 6,6, 6,6, 6,6 + }; + static unsigned sample_locs_2x[12] = { + 3,9, 9,3, 9,3, 9,3, 9,3, 9,3 + }; + static unsigned sample_locs_4x[12] = { + 4,4, 8,8, 2,10, 10,2, 10,2, 10,2 + }; + static unsigned sample_locs_6x[12] = { + 3,1, 7,3, 11,5, 1,7, 5,9, 9,10 + }; + struct pipe_framebuffer_state* fb = (struct pipe_framebuffer_state*)r300->fb_state.state; - unsigned i, num_cbufs = fb->nr_cbufs; + unsigned i, num_samples, num_cbufs = fb->nr_cbufs; unsigned mspos0, mspos1; 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->fb_multiwrite) { @@ -506,38 +590,34 @@ void r300_emit_fb_state_pipelined(struct r300_context *r300, for (; i < 4; i++) { OUT_CS(R300_US_OUT_FMT_UNUSED); } /* Multisampling. Depends on framebuffer sample count. * These are pipelined regs and as such cannot be moved - * to the AA state. */ - mspos0 = 0x66666666; - mspos1 = 0x6666666; - - if (fb->nr_cbufs && fb->cbufs[0]->texture->nr_samples > 1) { - /* Subsample placement. These may not be optimal. */ - switch (fb->cbufs[0]->texture->nr_samples) { - case 2: - mspos0 = 0x33996633; - mspos1 = 0x6666663; - break; - case 3: - mspos0 = 0x33936933; - mspos1 = 0x6666663; - break; - case 4: - mspos0 = 0x33939933; - mspos1 = 0x3966663; - break; - case 6: - mspos0 = 0x22a2aa22; - mspos1 = 0x2a65672; - break; - default: - debug_printf("r300: Bad number of multisamples!\n"); - } + * to the AA state. + */ + num_samples = r300->msaa_enable ? r300->num_samples : 1; + + /* Sample positions. */ + switch (num_samples) { + default: + mspos0 = r300_get_mspos(0, sample_locs_1x); + mspos1 = r300_get_mspos(1, sample_locs_1x); + break; + case 2: + mspos0 = r300_get_mspos(0, sample_locs_2x); + mspos1 = r300_get_mspos(1, sample_locs_2x); + break; + case 4: + mspos0 = r300_get_mspos(0, sample_locs_4x); + mspos1 = r300_get_mspos(1, sample_locs_4x); + break; + case 6: + mspos0 = r300_get_mspos(0, sample_locs_6x); + mspos1 = r300_get_mspos(1, sample_locs_6x); + break; } OUT_CS_REG_SEQ(R300_GB_MSPOS0, 2); OUT_CS(mspos0); OUT_CS(mspos1); END_CS; @@ -748,12 +828,24 @@ void r300_emit_rs_block_state(struct r300_context* r300, OUT_CS_REG_SEQ(R300_RS_INST_0, count); } OUT_CS_TABLE(rs->inst, count); END_CS; } +void r300_emit_sample_mask(struct r300_context *r300, + unsigned size, void *state) +{ + unsigned mask = (*(unsigned*)state) & ((1 << 6)-1); + CS_LOCALS(r300); + + BEGIN_CS(size); + OUT_CS_REG(R300_SC_SCREENDOOR, + mask | (mask << 6) | (mask << 12) | (mask << 18)); + END_CS; +} + void r300_emit_scissor_state(struct r300_context* r300, unsigned size, void* state) { struct pipe_scissor_state* scissor = (struct pipe_scissor_state*)state; CS_LOCALS(r300); @@ -1173,12 +1265,13 @@ void r300_emit_texture_cache_inval(struct r300_context* r300, unsigned size, voi boolean r300_emit_buffer_validate(struct r300_context *r300, boolean do_validate_vertex_buffers, struct pipe_resource *index_buffer) { struct pipe_framebuffer_state *fb = (struct pipe_framebuffer_state*)r300->fb_state.state; + struct r300_aa_state *aa = (struct r300_aa_state*)r300->aa_state.state; struct r300_textures_state *texstate = (struct r300_textures_state*)r300->textures_state.state; struct r300_resource *tex; unsigned i; boolean flushed = FALSE; @@ -1198,12 +1291,20 @@ validate: assert(tex && tex->buf && "zsbuf is marked, but NULL!"); r300->rws->cs_add_reloc(r300->cs, tex->cs_buf, RADEON_USAGE_READWRITE, r300_surface(fb->zsbuf)->domain); } } + /* The AA resolve buffer. */ + if (r300->aa_state.dirty) { + if (aa->dest) { + r300->rws->cs_add_reloc(r300->cs, aa->dest->cs_buf, + RADEON_USAGE_WRITE, + aa->dest->domain); + } + } if (r300->textures_state.dirty) { /* ...textures... */ for (i = 0; i < texstate->count; i++) { if (!(texstate->tx_enable & (1 << i))) { continue; } @@ -1279,13 +1380,15 @@ unsigned r300_get_num_cs_end_dwords(struct r300_context *r300) unsigned dwords = 0; /* Emitted in flush. */ dwords += 26; /* emit_query_end */ dwords += r300->hyperz_state.size + 2; /* emit_hyperz_end + zcache flush */ if (r300->screen->caps.is_r500) - dwords += 2; + dwords += 2; /* emit_index_bias */ + if (r300->screen->info.drm_minor >= 6) + dwords += 3; /* MSPOS */ return dwords; } /* Emit all dirty state. */ void r300_emit_dirty_state(struct r300_context* r300) |