X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fgallium%2Fdrivers%2Fr300%2Fr300_emit.c;h=b038a9719aebdede7476c2a15f6b8ef506e4f4ed;hb=5bbeae7a3d3be17d44b1bc851872a107a75c393b;hp=e1a3714aac7bcf3be6e9acbe9d86f86730926890;hpb=cd1cf788280a1eb10d54e1a2b8b069ed7b89c724;p=mesa.git diff --git a/src/gallium/drivers/r300/r300_emit.c b/src/gallium/drivers/r300/r300_emit.c index e1a3714aac7..b038a9719ae 100644 --- a/src/gallium/drivers/r300/r300_emit.c +++ b/src/gallium/drivers/r300/r300_emit.c @@ -45,7 +45,14 @@ void r300_emit_blend_state(struct r300_context* r300, CS_LOCALS(r300); if (fb->nr_cbufs) { - WRITE_CS_TABLE(blend->cb, size); + if (fb->cbufs[0]->format == PIPE_FORMAT_R16G16B16A16_FLOAT) { + WRITE_CS_TABLE(blend->cb_noclamp, size); + } else if (fb->cbufs[0]->format == PIPE_FORMAT_R16G16B16X16_FLOAT) { + WRITE_CS_TABLE(blend->cb_noclamp_noalpha, size); + } else { + unsigned swz = r300_surface(fb->cbufs[0])->colormask_swizzle; + WRITE_CS_TABLE(blend->cb_clamp[swz], size); + } } else { WRITE_CS_TABLE(blend->cb_no_readwrite, size); } @@ -74,13 +81,33 @@ void r300_emit_dsa_state(struct r300_context* r300, unsigned size, void* state) struct r300_dsa_state* dsa = (struct r300_dsa_state*)state; struct pipe_framebuffer_state* fb = (struct pipe_framebuffer_state*)r300->fb_state.state; + boolean is_r500 = r300->screen->caps.is_r500; CS_LOCALS(r300); + uint32_t alpha_func = dsa->alpha_function; + + /* Choose the alpha ref value between 8-bit (FG_ALPHA_FUNC.AM_VAL) and + * 16-bit (FG_ALPHA_VALUE). */ + if (is_r500 && (alpha_func & R300_FG_ALPHA_FUNC_ENABLE)) { + if (fb->nr_cbufs && + (fb->cbufs[0]->format == PIPE_FORMAT_R16G16B16A16_FLOAT || + fb->cbufs[0]->format == PIPE_FORMAT_R16G16B16X16_FLOAT)) { + alpha_func |= R500_FG_ALPHA_FUNC_FP16_ENABLE; + } else { + alpha_func |= R500_FG_ALPHA_FUNC_8BIT; + } + } - if (fb->zsbuf) { - WRITE_CS_TABLE(&dsa->cb_begin, size); - } else { - WRITE_CS_TABLE(dsa->cb_no_readwrite, size); + /* 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; } + + BEGIN_CS(size); + OUT_CS_REG(R300_FG_ALPHA_FUNC, alpha_func); + OUT_CS_TABLE(fb->zsbuf ? &dsa->cb_begin : dsa->cb_zb_no_readwrite, size-2); + END_CS; } static void get_rc_constant_state( @@ -89,7 +116,7 @@ static void get_rc_constant_state( struct rc_constant * constant) { struct r300_textures_state* texstate = r300->textures_state.state; - struct r300_texture *tex; + struct r300_resource *tex; assert(constant->Type == RC_CONSTANT_STATE); @@ -101,19 +128,19 @@ static void get_rc_constant_state( /* Factor for converting rectangle coords to * normalized coords. Should only show up on non-r500. */ case RC_STATE_R300_TEXRECT_FACTOR: - tex = r300_texture(texstate->sampler_views[constant->u.State[1]]->base.texture); - vec[0] = 1.0 / tex->desc.width0; - vec[1] = 1.0 / tex->desc.height0; + tex = r300_resource(texstate->sampler_views[constant->u.State[1]]->base.texture); + vec[0] = 1.0 / tex->tex.width0; + vec[1] = 1.0 / tex->tex.height0; vec[2] = 0; vec[3] = 1; break; case RC_STATE_R300_TEXSCALE_FACTOR: - tex = r300_texture(texstate->sampler_views[constant->u.State[1]]->base.texture); + tex = r300_resource(texstate->sampler_views[constant->u.State[1]]->base.texture); /* Add a small number to the texture size to work around rounding errors in hw. */ - vec[0] = tex->desc.b.b.width0 / (tex->desc.width0 + 0.001f); - vec[1] = tex->desc.b.b.height0 / (tex->desc.height0 + 0.001f); - vec[2] = tex->desc.b.b.depth0 / (tex->desc.depth0 + 0.001f); + vec[0] = tex->b.b.width0 / (tex->tex.width0 + 0.001f); + vec[1] = tex->b.b.height0 / (tex->tex.height0 + 0.001f); + vec[2] = tex->b.b.depth0 / (tex->tex.depth0 + 0.001f); vec[3] = 1; break; @@ -352,14 +379,16 @@ void r300_emit_aa_state(struct r300_context *r300, unsigned size, void *state) OUT_CS_REG(R300_GB_AA_CONFIG, aa->aa_config); if (aa->dest) { - OUT_CS_REG_SEQ(R300_RB3D_AARESOLVE_OFFSET, 1); - OUT_CS_RELOC(aa->dest->cs_buffer, aa->dest->offset, 0, aa->dest->domain); - - OUT_CS_REG_SEQ(R300_RB3D_AARESOLVE_PITCH, 1); - OUT_CS_RELOC(aa->dest->cs_buffer, aa->dest->pitch, 0, aa->dest->domain); + 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); + } else { + OUT_CS_REG(R300_RB3D_AARESOLVE_CTL, 0); } - OUT_CS_REG(R300_RB3D_AARESOLVE_CTL, aa->aaresolve_ctl); END_CS; } @@ -368,21 +397,23 @@ void r300_emit_fb_state(struct r300_context* r300, unsigned size, void* state) struct pipe_framebuffer_state* fb = (struct pipe_framebuffer_state*)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); - /* NUM_MULTIWRITES replicates COLOR[0] to all colorbuffers, which is not - * what we usually want. */ if (r300->screen->caps.is_r500) { rb3d_cctl = R300_RB3D_CCTL_INDEPENDENT_COLORFORMAT_ENABLE_ENABLE; } - if (r300_fragment_shader_writes_all(r300_fs(r300))) { + /* NUM_MULTIWRITES replicates COLOR[0] to all colorbuffers. */ + if (fb->nr_cbufs && r300->fb_multiwrite) { rb3d_cctl |= R300_RB3D_CCTL_NUM_MULTIWRITES(fb->nr_cbufs); } + if (r300->cmask_in_use) { + rb3d_cctl |= R300_RB3D_CCTL_AA_COMPRESSION_ENABLE | + R300_RB3D_CCTL_CMASK_ENABLE; + } OUT_CS_REG(R300_RB3D_CCTL, rb3d_cctl); @@ -390,11 +421,22 @@ void r300_emit_fb_state(struct r300_context* r300, unsigned size, void* state) for (i = 0; i < fb->nr_cbufs; i++) { surf = r300_surface(fb->cbufs[i]); - OUT_CS_REG_SEQ(R300_RB3D_COLOROFFSET0 + (4 * i), 1); - OUT_CS_RELOC(surf->cs_buffer, surf->offset, 0, surf->domain); + OUT_CS_REG(R300_RB3D_COLOROFFSET0 + (4 * i), surf->offset); + OUT_CS_RELOC(surf); + + OUT_CS_REG(R300_RB3D_COLORPITCH0 + (4 * i), surf->pitch); + OUT_CS_RELOC(surf); - OUT_CS_REG_SEQ(R300_RB3D_COLORPITCH0 + (4 * i), 1); - OUT_CS_RELOC(surf->cs_buffer, surf->pitch, 0, surf->domain); + if (r300->cmask_in_use && i == 0) { + OUT_CS_REG(R300_RB3D_CMASK_OFFSET0, 0); + OUT_CS_REG(R300_RB3D_CMASK_PITCH0, surf->pitch_cmask); + OUT_CS_REG(R300_RB3D_COLOR_CLEAR_VALUE, r300->color_clear_value); + if (r300->screen->caps.is_r500 && r300->screen->info.drm_minor >= 29) { + OUT_CS_REG_SEQ(R500_RB3D_COLOR_CLEAR_VALUE_AR, 2); + OUT_CS(r300->color_clear_value_ar); + OUT_CS(r300->color_clear_value_gb); + } + } } /* Set up the ZB part of the CBZB clear. */ @@ -403,11 +445,11 @@ void r300_emit_fb_state(struct r300_context* r300, unsigned size, void* state) OUT_CS_REG(R300_ZB_FORMAT, surf->cbzb_format); - OUT_CS_REG_SEQ(R300_ZB_DEPTHOFFSET, 1); - OUT_CS_RELOC(surf->cs_buffer, surf->cbzb_midpoint_offset, 0, surf->domain); + OUT_CS_REG(R300_ZB_DEPTHOFFSET, surf->cbzb_midpoint_offset); + OUT_CS_RELOC(surf); - OUT_CS_REG_SEQ(R300_ZB_DEPTHPITCH, 1); - OUT_CS_RELOC(surf->cs_buffer, surf->cbzb_pitch, 0, surf->domain); + OUT_CS_REG(R300_ZB_DEPTHPITCH, surf->cbzb_pitch); + OUT_CS_RELOC(surf); DBG(r300, DBG_CBZB, "CBZB clearing cbuf %08x %08x\n", surf->cbzb_format, @@ -419,37 +461,19 @@ void r300_emit_fb_state(struct r300_context* r300, unsigned size, void* state) OUT_CS_REG(R300_ZB_FORMAT, surf->format); - OUT_CS_REG_SEQ(R300_ZB_DEPTHOFFSET, 1); - OUT_CS_RELOC(surf->cs_buffer, surf->offset, 0, surf->domain); + OUT_CS_REG(R300_ZB_DEPTHOFFSET, surf->offset); + OUT_CS_RELOC(surf); - OUT_CS_REG_SEQ(R300_ZB_DEPTHPITCH, 1); - OUT_CS_RELOC(surf->cs_buffer, surf->pitch, 0, surf->domain); + OUT_CS_REG(R300_ZB_DEPTHPITCH, surf->pitch); + OUT_CS_RELOC(surf); - if (can_hyperz) { - uint32_t surf_pitch; - struct r300_texture *tex; - int level = surf->base.u.tex.level; - tex = r300_texture(surf->base.texture); - - surf_pitch = surf->pitch & R300_DEPTHPITCH_MASK; + if (r300->hyperz_enabled) { /* HiZ RAM. */ - if (r300->screen->caps.hiz_ram) { - if (tex->hiz_mem[level]) { - OUT_CS_REG(R300_ZB_HIZ_OFFSET, tex->hiz_mem[level]->ofs << 2); - OUT_CS_REG(R300_ZB_HIZ_PITCH, surf_pitch); - } else { - OUT_CS_REG(R300_ZB_HIZ_OFFSET, 0); - OUT_CS_REG(R300_ZB_HIZ_PITCH, 0); - } - } + OUT_CS_REG(R300_ZB_HIZ_OFFSET, 0); + OUT_CS_REG(R300_ZB_HIZ_PITCH, surf->pitch_hiz); /* Z Mask RAM. (compressed zbuffer) */ - if (tex->zmask_mem[level]) { - OUT_CS_REG(R300_ZB_ZMASK_OFFSET, tex->zmask_mem[level]->ofs << 2); - OUT_CS_REG(R300_ZB_ZMASK_PITCH, surf_pitch); - } else { - OUT_CS_REG(R300_ZB_ZMASK_OFFSET, 0); - OUT_CS_REG(R300_ZB_ZMASK_PITCH, 0); - } + OUT_CS_REG(R300_ZB_ZMASK_OFFSET, 0); + OUT_CS_REG(R300_ZB_ZMASK_PITCH, surf->pitch_zmask); } } @@ -461,6 +485,7 @@ void r300_emit_hyperz_state(struct r300_context *r300, { struct r300_hyperz_state *z = state; CS_LOCALS(r300); + if (z->flush) WRITE_CS_TABLE(&z->cb_flush_begin, size); else @@ -481,17 +506,91 @@ void r300_emit_hyperz_end(struct r300_context *r300) 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 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_fragment_shader_writes_all(r300_fs(r300))) { + if (r300->fb_multiwrite) { num_cbufs = MIN2(num_cbufs, 1); } @@ -503,45 +602,40 @@ void r300_emit_fb_state_pipelined(struct r300_context *r300, for (i = 0; i < num_cbufs; i++) { OUT_CS(r300_surface(fb->cbufs[i])->format); } + for (; i < 1; i++) { + OUT_CS(R300_US_OUT_FMT_C4_8 | + R300_C0_SEL_B | R300_C1_SEL_G | + R300_C2_SEL_R | R300_C3_SEL_A); + } 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. */ - if (r300->rws->get_value(r300->rws, R300_VID_DRM_2_3_0)) { - unsigned mspos0 = 0x66666666; - unsigned 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"); - } - } - - OUT_CS_REG_SEQ(R300_GB_MSPOS0, 2); - OUT_CS(mspos0); - OUT_CS(mspos1); + /* Set sample positions. It depends on the framebuffer sample count. + * These are pipelined regs and as such cannot be moved to the AA state. + */ + switch (r300->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; } @@ -554,7 +648,7 @@ void r300_emit_query_start(struct r300_context *r300, unsigned size, void*state) return; BEGIN_CS(size); - if (r300->screen->caps.family == CHIP_FAMILY_RV530) { + if (r300->screen->caps.family == CHIP_RV530) { OUT_CS_REG(RV530_FG_ZBREG_DEST, RV530_FG_ZBREG_DEST_PIPE_SELECT_ALL); } else { OUT_CS_REG(R300_SU_REG_DEST, R300_RASTER_PIPE_SELECT_ALL); @@ -562,19 +656,18 @@ void r300_emit_query_start(struct r300_context *r300, unsigned size, void*state) OUT_CS_REG(R300_ZB_ZPASS_DATA, 0); END_CS; query->begin_emitted = TRUE; - query->flushed = FALSE; } static void r300_emit_query_end_frag_pipes(struct r300_context *r300, struct r300_query *query) { struct r300_capabilities* caps = &r300->screen->caps; - struct r300_winsys_cs_buffer *buf = r300->query_current->cs_buffer; + uint32_t gb_pipes = r300->screen->info.r300_num_gb_pipes; CS_LOCALS(r300); - assert(caps->num_frag_pipes); + assert(gb_pipes); - BEGIN_CS(6 * caps->num_frag_pipes + 2); + BEGIN_CS(6 * gb_pipes + 2); /* I'm not so sure I like this switch, but it's hard to be elegant * when there's so many special cases... * @@ -583,37 +676,33 @@ static void r300_emit_query_end_frag_pipes(struct r300_context *r300, * 4-byte offset for each pipe. RV380 and older are special; they have * only two pipes, and the second pipe's enable is on bit 3, not bit 1, * so there's a chipset cap for that. */ - switch (caps->num_frag_pipes) { + switch (gb_pipes) { case 4: /* pipe 3 only */ OUT_CS_REG(R300_SU_REG_DEST, 1 << 3); - OUT_CS_REG_SEQ(R300_ZB_ZPASS_ADDR, 1); - OUT_CS_RELOC(buf, (query->num_results + 3) * 4, - 0, query->domain); + OUT_CS_REG(R300_ZB_ZPASS_ADDR, (query->num_results + 3) * 4); + OUT_CS_RELOC(r300->query_current); case 3: /* pipe 2 only */ OUT_CS_REG(R300_SU_REG_DEST, 1 << 2); - OUT_CS_REG_SEQ(R300_ZB_ZPASS_ADDR, 1); - OUT_CS_RELOC(buf, (query->num_results + 2) * 4, - 0, query->domain); + OUT_CS_REG(R300_ZB_ZPASS_ADDR, (query->num_results + 2) * 4); + OUT_CS_RELOC(r300->query_current); case 2: /* pipe 1 only */ /* As mentioned above, accomodate RV380 and older. */ OUT_CS_REG(R300_SU_REG_DEST, 1 << (caps->high_second_pipe ? 3 : 1)); - OUT_CS_REG_SEQ(R300_ZB_ZPASS_ADDR, 1); - OUT_CS_RELOC(buf, (query->num_results + 1) * 4, - 0, query->domain); + OUT_CS_REG(R300_ZB_ZPASS_ADDR, (query->num_results + 1) * 4); + OUT_CS_RELOC(r300->query_current); case 1: /* pipe 0 only */ OUT_CS_REG(R300_SU_REG_DEST, 1 << 0); - OUT_CS_REG_SEQ(R300_ZB_ZPASS_ADDR, 1); - OUT_CS_RELOC(buf, (query->num_results + 0) * 4, - 0, query->domain); + OUT_CS_REG(R300_ZB_ZPASS_ADDR, (query->num_results + 0) * 4); + OUT_CS_RELOC(r300->query_current); break; default: fprintf(stderr, "r300: Implementation error: Chipset reports %d" - " pixel pipes!\n", caps->num_frag_pipes); + " pixel pipes!\n", gb_pipes); abort(); } @@ -625,13 +714,12 @@ static void r300_emit_query_end_frag_pipes(struct r300_context *r300, static void rv530_emit_query_end_single_z(struct r300_context *r300, struct r300_query *query) { - struct r300_winsys_cs_buffer *buf = r300->query_current->cs_buffer; CS_LOCALS(r300); BEGIN_CS(8); OUT_CS_REG(RV530_FG_ZBREG_DEST, RV530_FG_ZBREG_DEST_PIPE_SELECT_0); - OUT_CS_REG_SEQ(R300_ZB_ZPASS_ADDR, 1); - OUT_CS_RELOC(buf, query->num_results * 4, 0, query->domain); + OUT_CS_REG(R300_ZB_ZPASS_ADDR, query->num_results * 4); + OUT_CS_RELOC(r300->query_current); OUT_CS_REG(RV530_FG_ZBREG_DEST, RV530_FG_ZBREG_DEST_PIPE_SELECT_ALL); END_CS; } @@ -639,16 +727,15 @@ static void rv530_emit_query_end_single_z(struct r300_context *r300, static void rv530_emit_query_end_double_z(struct r300_context *r300, struct r300_query *query) { - struct r300_winsys_cs_buffer *buf = r300->query_current->cs_buffer; CS_LOCALS(r300); BEGIN_CS(14); OUT_CS_REG(RV530_FG_ZBREG_DEST, RV530_FG_ZBREG_DEST_PIPE_SELECT_0); - OUT_CS_REG_SEQ(R300_ZB_ZPASS_ADDR, 1); - OUT_CS_RELOC(buf, (query->num_results + 0) * 4, 0, query->domain); + OUT_CS_REG(R300_ZB_ZPASS_ADDR, (query->num_results + 0) * 4); + OUT_CS_RELOC(r300->query_current); OUT_CS_REG(RV530_FG_ZBREG_DEST, RV530_FG_ZBREG_DEST_PIPE_SELECT_1); - OUT_CS_REG_SEQ(R300_ZB_ZPASS_ADDR, 1); - OUT_CS_RELOC(buf, (query->num_results + 1) * 4, 0, query->domain); + OUT_CS_REG(R300_ZB_ZPASS_ADDR, (query->num_results + 1) * 4); + OUT_CS_RELOC(r300->query_current); OUT_CS_REG(RV530_FG_ZBREG_DEST, RV530_FG_ZBREG_DEST_PIPE_SELECT_ALL); END_CS; } @@ -664,8 +751,8 @@ void r300_emit_query_end(struct r300_context* r300) if (query->begin_emitted == FALSE) return; - if (caps->family == CHIP_FAMILY_RV530) { - if (caps->num_z_pipes == 2) + if (caps->family == CHIP_RV530) { + if (r300->screen->info.r300_num_z_pipes == 2) rv530_emit_query_end_double_z(r300, query); else rv530_emit_query_end_single_z(r300, query); @@ -676,8 +763,8 @@ void r300_emit_query_end(struct r300_context* r300) query->num_results += query->num_pipes; /* XXX grab all the results and reset the counter. */ - if (query->num_results >= query->buffer_size / 4 - 4) { - query->num_results = (query->buffer_size / 4) / 2; + if (query->num_results >= query->buf->size / 4 - 4) { + query->num_results = (query->buf->size / 4) / 2; fprintf(stderr, "r300: Rewinding OQBO...\n"); } } @@ -760,6 +847,18 @@ void r300_emit_rs_block_state(struct r300_context* r300, 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) { @@ -787,8 +886,9 @@ void r300_emit_textures_state(struct r300_context *r300, { struct r300_textures_state *allstate = (struct r300_textures_state*)state; struct r300_texture_sampler_state *texstate; - struct r300_texture *tex; + struct r300_resource *tex; unsigned i; + boolean has_us_format = r300->screen->caps.has_us_format; CS_LOCALS(r300); BEGIN_CS(size); @@ -797,7 +897,7 @@ void r300_emit_textures_state(struct r300_context *r300, for (i = 0; i < allstate->count; i++) { if ((1 << i) & allstate->tx_enable) { texstate = &allstate->regs[i]; - tex = r300_texture(allstate->sampler_views[i]->base.texture); + tex = r300_resource(allstate->sampler_views[i]->base.texture); OUT_CS_REG(R300_TX_FILTER0_0 + (i * 4), texstate->filter0); OUT_CS_REG(R300_TX_FILTER1_0 + (i * 4), texstate->filter1); @@ -808,72 +908,38 @@ void r300_emit_textures_state(struct r300_context *r300, OUT_CS_REG(R300_TX_FORMAT1_0 + (i * 4), texstate->format.format1); OUT_CS_REG(R300_TX_FORMAT2_0 + (i * 4), texstate->format.format2); - OUT_CS_REG_SEQ(R300_TX_OFFSET_0 + (i * 4), 1); - OUT_CS_TEX_RELOC(tex, texstate->format.tile_config, tex->domain, - 0); + OUT_CS_REG(R300_TX_OFFSET_0 + (i * 4), texstate->format.tile_config); + OUT_CS_RELOC(tex); + + if (has_us_format) { + OUT_CS_REG(R500_US_FORMAT0_0 + (i * 4), + texstate->format.us_format0); + } } } END_CS; } -static void r300_update_vertex_arrays_cb(struct r300_context *r300, unsigned packet_size) -{ - struct pipe_vertex_buffer *vb1, *vb2, *vbuf = r300->vertex_buffer; - struct pipe_vertex_element *velem = r300->velems->velem; - unsigned *hw_format_size = r300->velems->hw_format_size; - unsigned size1, size2, vertex_array_count = r300->velems->count; - int i; - CB_LOCALS; - - BEGIN_CB(r300->vertex_arrays_cb, packet_size); - for (i = 0; i < vertex_array_count - 1; i += 2) { - vb1 = &vbuf[velem[i].vertex_buffer_index]; - vb2 = &vbuf[velem[i+1].vertex_buffer_index]; - size1 = hw_format_size[i]; - size2 = hw_format_size[i+1]; - - OUT_CB(R300_VBPNTR_SIZE0(size1) | R300_VBPNTR_STRIDE0(vb1->stride) | - R300_VBPNTR_SIZE1(size2) | R300_VBPNTR_STRIDE1(vb2->stride)); - OUT_CB(vb1->buffer_offset + velem[i].src_offset); - OUT_CB(vb2->buffer_offset + velem[i+1].src_offset); - } - - if (vertex_array_count & 1) { - vb1 = &vbuf[velem[i].vertex_buffer_index]; - size1 = hw_format_size[i]; - - OUT_CB(R300_VBPNTR_SIZE0(size1) | R300_VBPNTR_STRIDE0(vb1->stride)); - OUT_CB(vb1->buffer_offset + velem[i].src_offset); - } - END_CB; - - r300->vertex_arrays_dirty = FALSE; -} - -void r300_emit_vertex_arrays(struct r300_context* r300, int offset, boolean indexed) +void r300_emit_vertex_arrays(struct r300_context* r300, int offset, + boolean indexed, int instance_id) { struct pipe_vertex_buffer *vbuf = r300->vertex_buffer; struct pipe_vertex_element *velem = r300->velems->velem; - struct r300_buffer *buf; + struct r300_resource *buf; int i; unsigned vertex_array_count = r300->velems->count; unsigned packet_size = (vertex_array_count * 3 + 1) / 2; + struct pipe_vertex_buffer *vb1, *vb2; + unsigned *hw_format_size = r300->velems->format_size; + unsigned size1, size2, offset1, offset2, stride1, stride2; CS_LOCALS(r300); BEGIN_CS(2 + packet_size + vertex_array_count * 2); OUT_CS_PKT3(R300_PACKET3_3D_LOAD_VBPNTR, packet_size); OUT_CS(vertex_array_count | (!indexed ? R300_VC_FORCE_PREFETCH : 0)); - if (!offset) { - if (r300->vertex_arrays_dirty) { - r300_update_vertex_arrays_cb(r300, packet_size); - } - OUT_CS_TABLE(r300->vertex_arrays_cb, packet_size); - } else { - struct pipe_vertex_buffer *vb1, *vb2; - unsigned *hw_format_size = r300->velems->hw_format_size; - unsigned size1, size2; - + if (instance_id == -1) { + /* Non-instanced arrays. This ignores instance_divisor and instance_id. */ for (i = 0; i < vertex_array_count - 1; i += 2) { vb1 = &vbuf[velem[i].vertex_buffer_index]; vb2 = &vbuf[velem[i+1].vertex_buffer_index]; @@ -893,11 +959,63 @@ void r300_emit_vertex_arrays(struct r300_context* r300, int offset, boolean inde OUT_CS(R300_VBPNTR_SIZE0(size1) | R300_VBPNTR_STRIDE0(vb1->stride)); OUT_CS(vb1->buffer_offset + velem[i].src_offset + offset * vb1->stride); } - } - for (i = 0; i < vertex_array_count; i++) { - buf = r300_buffer(vbuf[velem[i].vertex_buffer_index].buffer); - OUT_CS_BUF_RELOC_NO_OFFSET(&buf->b.b, buf->domain, 0); + for (i = 0; i < vertex_array_count; i++) { + buf = r300_resource(vbuf[velem[i].vertex_buffer_index].buffer); + OUT_CS_RELOC(buf); + } + } else { + /* Instanced arrays. */ + for (i = 0; i < vertex_array_count - 1; i += 2) { + vb1 = &vbuf[velem[i].vertex_buffer_index]; + vb2 = &vbuf[velem[i+1].vertex_buffer_index]; + size1 = hw_format_size[i]; + size2 = hw_format_size[i+1]; + + if (velem[i].instance_divisor) { + stride1 = 0; + offset1 = vb1->buffer_offset + velem[i].src_offset + + (instance_id / velem[i].instance_divisor) * vb1->stride; + } else { + stride1 = vb1->stride; + offset1 = vb1->buffer_offset + velem[i].src_offset + offset * vb1->stride; + } + if (velem[i+1].instance_divisor) { + stride2 = 0; + offset2 = vb2->buffer_offset + velem[i+1].src_offset + + (instance_id / velem[i+1].instance_divisor) * vb2->stride; + } else { + stride2 = vb2->stride; + offset2 = vb2->buffer_offset + velem[i+1].src_offset + offset * vb2->stride; + } + + OUT_CS(R300_VBPNTR_SIZE0(size1) | R300_VBPNTR_STRIDE0(stride1) | + R300_VBPNTR_SIZE1(size2) | R300_VBPNTR_STRIDE1(stride2)); + OUT_CS(offset1); + OUT_CS(offset2); + } + + if (vertex_array_count & 1) { + vb1 = &vbuf[velem[i].vertex_buffer_index]; + size1 = hw_format_size[i]; + + if (velem[i].instance_divisor) { + stride1 = 0; + offset1 = vb1->buffer_offset + velem[i].src_offset + + (instance_id / velem[i].instance_divisor) * vb1->stride; + } else { + stride1 = vb1->stride; + offset1 = vb1->buffer_offset + velem[i].src_offset + offset * vb1->stride; + } + + OUT_CS(R300_VBPNTR_SIZE0(size1) | R300_VBPNTR_STRIDE0(stride1)); + OUT_CS(offset1); + } + + for (i = 0; i < vertex_array_count; i++) { + buf = r300_resource(vbuf[velem[i].vertex_buffer_index].buffer); + OUT_CS_RELOC(buf); + } } END_CS; } @@ -922,7 +1040,11 @@ void r300_emit_vertex_arrays_swtcl(struct r300_context *r300, boolean indexed) OUT_CS(r300->vertex_info.size | (r300->vertex_info.size << 8)); OUT_CS(r300->draw_vbo_offset); - OUT_CS_BUF_RELOC(r300->vbo, 0, r300_buffer(r300->vbo)->domain, 0); + OUT_CS(0); + + assert(r300->vbo_cs); + cs_winsys->cs_write_reloc(cs_copy, r300->vbo_cs); + CS_USED_DW(2); END_CS; } @@ -1011,20 +1133,18 @@ void r300_emit_vs_state(struct r300_context* r300, unsigned size, void* state) R300_PVS_VF_MAX_VTX_NUM(12) | (r300screen->caps.is_r500 ? R500_TCL_STATE_OPTIMIZATION : 0)); - /* Emit flow control instructions. */ - if (code->num_fc_ops) { - - OUT_CS_REG(R300_VAP_PVS_FLOW_CNTL_OPC, code->fc_ops); - if (r300screen->caps.is_r500) { - OUT_CS_REG_SEQ(R500_VAP_PVS_FLOW_CNTL_ADDRS_LW_0, code->num_fc_ops * 2); - OUT_CS_TABLE(code->fc_op_addrs.r500, code->num_fc_ops * 2); - } else { - OUT_CS_REG_SEQ(R300_VAP_PVS_FLOW_CNTL_ADDRS_0, code->num_fc_ops); - OUT_CS_TABLE(code->fc_op_addrs.r300, code->num_fc_ops); - } - OUT_CS_REG_SEQ(R300_VAP_PVS_FLOW_CNTL_LOOP_INDEX_0, code->num_fc_ops); - OUT_CS_TABLE(code->fc_loop_index, code->num_fc_ops); + /* Emit flow control instructions. Even if there are no fc instructions, + * we still need to write the registers to make sure they are cleared. */ + OUT_CS_REG(R300_VAP_PVS_FLOW_CNTL_OPC, code->fc_ops); + if (r300screen->caps.is_r500) { + OUT_CS_REG_SEQ(R500_VAP_PVS_FLOW_CNTL_ADDRS_LW_0, R300_VS_MAX_FC_OPS * 2); + OUT_CS_TABLE(code->fc_op_addrs.r500, R300_VS_MAX_FC_OPS * 2); + } else { + OUT_CS_REG_SEQ(R300_VAP_PVS_FLOW_CNTL_ADDRS_0, R300_VS_MAX_FC_OPS); + OUT_CS_TABLE(code->fc_op_addrs.r300, R300_VS_MAX_FC_OPS); } + OUT_CS_REG_SEQ(R300_VAP_PVS_FLOW_CNTL_LOOP_INDEX_0, R300_VS_MAX_FC_OPS); + OUT_CS_TABLE(code->fc_loop_index, R300_VS_MAX_FC_OPS); END_CS; } @@ -1089,109 +1209,68 @@ void r300_emit_viewport_state(struct r300_context* r300, END_CS; } -static void r300_emit_hiz_line_clear(struct r300_context *r300, int start, uint16_t count, uint32_t val) -{ - CS_LOCALS(r300); - BEGIN_CS(4); - OUT_CS_PKT3(R300_PACKET3_3D_CLEAR_HIZ, 2); - OUT_CS(start); - OUT_CS(count); - OUT_CS(val); - END_CS; -} - -static void r300_emit_zmask_line_clear(struct r300_context *r300, int start, uint16_t count, uint32_t val) -{ - CS_LOCALS(r300); - BEGIN_CS(4); - OUT_CS_PKT3(R300_PACKET3_3D_CLEAR_ZMASK, 2); - OUT_CS(start); - OUT_CS(count); - OUT_CS(val); - END_CS; -} - -#define ALIGN_DIVUP(x, y) (((x) + (y) - 1) / (y)) - void r300_emit_hiz_clear(struct r300_context *r300, unsigned size, void *state) { struct pipe_framebuffer_state *fb = (struct pipe_framebuffer_state*)r300->fb_state.state; - struct r300_hyperz_state *z = - (struct r300_hyperz_state*)r300->hyperz_state.state; - struct r300_screen* r300screen = r300->screen; - uint32_t stride, offset = 0, height, offset_shift; - struct r300_texture* tex; - int i; - - tex = r300_texture(fb->zsbuf->texture); - - offset = tex->hiz_mem[fb->zsbuf->u.tex.level]->ofs; - stride = tex->desc.stride_in_pixels[fb->zsbuf->u.tex.level]; - - /* convert from pixels to 4x4 blocks */ - stride = ALIGN_DIVUP(stride, 4); - - stride = ALIGN_DIVUP(stride, r300screen->caps.num_frag_pipes); - /* there are 4 blocks per dwords */ - stride = ALIGN_DIVUP(stride, 4); - - height = ALIGN_DIVUP(fb->zsbuf->height, 4); + struct r300_resource* tex; + CS_LOCALS(r300); - offset_shift = 2; - offset_shift += (r300screen->caps.num_frag_pipes / 2); + tex = r300_resource(fb->zsbuf->texture); - for (i = 0; i < height; i++) { - offset = i * stride; - offset <<= offset_shift; - r300_emit_hiz_line_clear(r300, offset, stride, 0xffffffff); - } - z->current_func = -1; + BEGIN_CS(size); + OUT_CS_PKT3(R300_PACKET3_3D_CLEAR_HIZ, 2); + OUT_CS(0); + OUT_CS(tex->tex.hiz_dwords[fb->zsbuf->u.tex.level]); + OUT_CS(r300->hiz_clear_value); + END_CS; /* Mark the current zbuffer's hiz ram as in use. */ - tex->hiz_in_use[fb->zsbuf->u.tex.level] = TRUE; + r300->hiz_in_use = TRUE; + r300->hiz_func = HIZ_FUNC_NONE; + r300_mark_atom_dirty(r300, &r300->hyperz_state); } void r300_emit_zmask_clear(struct r300_context *r300, unsigned size, void *state) { struct pipe_framebuffer_state *fb = (struct pipe_framebuffer_state*)r300->fb_state.state; - struct r300_screen* r300screen = r300->screen; - uint32_t stride, offset = 0; - struct r300_texture* tex; - uint32_t i, height; - int mult, offset_shift; - - tex = r300_texture(fb->zsbuf->texture); - stride = tex->desc.stride_in_pixels[fb->zsbuf->u.tex.level]; + struct r300_resource *tex; + CS_LOCALS(r300); - offset = tex->zmask_mem[fb->zsbuf->u.tex.level]->ofs; + tex = r300_resource(fb->zsbuf->texture); - if (r300->z_compression == RV350_Z_COMPRESS_88) - mult = 8; - else - mult = 4; + BEGIN_CS(size); + OUT_CS_PKT3(R300_PACKET3_3D_CLEAR_ZMASK, 2); + OUT_CS(0); + OUT_CS(tex->tex.zmask_dwords[fb->zsbuf->u.tex.level]); + OUT_CS(0); + END_CS; - height = ALIGN_DIVUP(fb->zsbuf->height, mult); + /* Mark the current zbuffer's zmask as in use. */ + r300->zmask_in_use = TRUE; + r300_mark_atom_dirty(r300, &r300->hyperz_state); +} - offset_shift = 4; - offset_shift += (r300screen->caps.num_frag_pipes / 2); - stride = ALIGN_DIVUP(stride, r300screen->caps.num_frag_pipes); +void r300_emit_cmask_clear(struct r300_context *r300, unsigned size, void *state) +{ + struct pipe_framebuffer_state *fb = + (struct pipe_framebuffer_state*)r300->fb_state.state; + struct r300_resource *tex; + CS_LOCALS(r300); - /* okay have width in pixels - divide by block width */ - stride = ALIGN_DIVUP(stride, mult); - /* have width in blocks - divide by number of fragment pipes screen width */ - /* 16 blocks per dword */ - stride = ALIGN_DIVUP(stride, 16); + tex = r300_resource(fb->cbufs[0]->texture); - for (i = 0; i < height; i++) { - offset = i * stride; - offset <<= offset_shift; - r300_emit_zmask_line_clear(r300, offset, stride, 0x0);//0xffffffff); - } + BEGIN_CS(size); + OUT_CS_PKT3(R300_PACKET3_3D_CLEAR_CMASK, 2); + OUT_CS(0); + OUT_CS(tex->tex.cmask_dwords); + OUT_CS(0); + END_CS; /* Mark the current zbuffer's zmask as in use. */ - tex->zmask_in_use[fb->zsbuf->u.tex.level] = TRUE; + r300->cmask_in_use = TRUE; + r300_mark_fb_state_dirty(r300, R300_CHANGED_CMASK_ENABLE); } void r300_emit_ztop_state(struct r300_context* r300, @@ -1218,68 +1297,93 @@ 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 *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_texture* tex; - struct pipe_vertex_buffer *vbuf = r300->vertex_buffer; - struct pipe_vertex_element *velem = r300->velems->velem; - struct pipe_resource *pbuf; + struct r300_resource *tex; unsigned i; - - /* Clean out BOs. */ - r300->rws->cs_reset_buffers(r300->cs); - - /* Color buffers... */ - for (i = 0; i < fb->nr_cbufs; i++) { - tex = r300_texture(fb->cbufs[i]->texture); - assert(tex && tex->buffer && "cbuf is marked, but NULL!"); - r300->rws->cs_add_buffer(r300->cs, tex->cs_buffer, 0, - r300_surface(fb->cbufs[i])->domain); - } - /* ...depth buffer... */ - if (fb->zsbuf) { - tex = r300_texture(fb->zsbuf->texture); - assert(tex && tex->buffer && "zsbuf is marked, but NULL!"); - r300->rws->cs_add_buffer(r300->cs, tex->cs_buffer, 0, - r300_surface(fb->zsbuf)->domain); + boolean flushed = FALSE; + +validate: + if (r300->fb_state.dirty) { + /* Color buffers... */ + for (i = 0; i < fb->nr_cbufs; i++) { + tex = r300_resource(fb->cbufs[i]->texture); + assert(tex && tex->buf && "cbuf is marked, but NULL!"); + r300->rws->cs_add_reloc(r300->cs, tex->cs_buf, + RADEON_USAGE_READWRITE, + r300_surface(fb->cbufs[i])->domain); + } + /* ...depth buffer... */ + if (fb->zsbuf) { + tex = r300_resource(fb->zsbuf->texture); + 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); + } } - /* ...textures... */ - for (i = 0; i < texstate->count; i++) { - if (!(texstate->tx_enable & (1 << i))) { - continue; + /* 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; + } - tex = r300_texture(texstate->sampler_views[i]->base.texture); - r300->rws->cs_add_buffer(r300->cs, tex->cs_buffer, tex->domain, 0); + tex = r300_resource(texstate->sampler_views[i]->base.texture); + r300->rws->cs_add_reloc(r300->cs, tex->cs_buf, RADEON_USAGE_READ, + tex->domain); + } } /* ...occlusion query buffer... */ if (r300->query_current) - r300->rws->cs_add_buffer(r300->cs, r300->query_current->cs_buffer, - 0, r300->query_current->domain); + r300->rws->cs_add_reloc(r300->cs, r300->query_current->cs_buf, + RADEON_USAGE_WRITE, RADEON_DOMAIN_GTT); /* ...vertex buffer for SWTCL path... */ - if (r300->vbo) - r300->rws->cs_add_buffer(r300->cs, r300_buffer(r300->vbo)->cs_buf, - r300_buffer(r300->vbo)->domain, 0); + if (r300->vbo_cs) + r300->rws->cs_add_reloc(r300->cs, r300->vbo_cs, + RADEON_USAGE_READ, RADEON_DOMAIN_GTT); /* ...vertex buffers for HWTCL path... */ - if (do_validate_vertex_buffers) { - for (i = 0; i < r300->velems->count; i++) { - pbuf = vbuf[velem[i].vertex_buffer_index].buffer; - if (!pbuf) + if (do_validate_vertex_buffers && r300->vertex_arrays_dirty) { + struct pipe_vertex_buffer *vbuf = r300->vertex_buffer; + struct pipe_vertex_buffer *last = r300->vertex_buffer + + r300->nr_vertex_buffers; + struct pipe_resource *buf; + + for (; vbuf != last; vbuf++) { + buf = vbuf->buffer; + if (!buf) continue; - r300->rws->cs_add_buffer(r300->cs, r300_buffer(pbuf)->cs_buf, - r300_buffer(pbuf)->domain, 0); + r300->rws->cs_add_reloc(r300->cs, r300_resource(buf)->cs_buf, + RADEON_USAGE_READ, + r300_resource(buf)->domain); } } /* ...and index buffer for HWTCL path. */ if (index_buffer) - r300->rws->cs_add_buffer(r300->cs, r300_buffer(index_buffer)->cs_buf, - r300_buffer(index_buffer)->domain, 0); + r300->rws->cs_add_reloc(r300->cs, r300_resource(index_buffer)->cs_buf, + RADEON_USAGE_READ, + r300_resource(index_buffer)->domain); + /* Now do the validation (flush is called inside cs_validate on failure). */ if (!r300->rws->cs_validate(r300->cs)) { - return FALSE; + /* Ooops, an infinite loop, give up. */ + if (flushed) + return FALSE; + + flushed = TRUE; + goto validate; } return TRUE; @@ -1309,8 +1413,10 @@ unsigned r300_get_num_cs_end_dwords(struct r300_context *r300) /* Emitted in flush. */ dwords += 26; /* emit_query_end */ dwords += r300->hyperz_state.size + 2; /* emit_hyperz_end + zcache flush */ - if (r300->screen->caps.index_bias_supported) - dwords += 2; + if (r300->screen->caps.is_r500) + dwords += 2; /* emit_index_bias */ + if (r300->screen->info.drm_minor >= 6) + dwords += 3; /* MSPOS */ return dwords; }