r300g: decouple drawing code and two-sided stencil refvalue fallback

It's now more separate from the rest of the driver and it can be disabled
by commenting out just 1 line. Well, I couldn't make the previous version
work with SW TCL reliably, that's the reason of this little rework.
This commit is contained in:
Marek Olšák 2010-05-26 23:47:27 +02:00
parent 1345c5bf94
commit 76034aaf65
3 changed files with 160 additions and 211 deletions

View File

@ -36,9 +36,9 @@
struct u_upload_mgr;
struct r300_context;
struct r300_fragment_shader;
struct r300_vertex_shader;
struct r300_stencilref_context;
struct r300_atom {
/* List pointers. */
@ -86,7 +86,7 @@ struct r300_dsa_state {
/* Whether a two-sided stencil is enabled. */
boolean two_sided;
/* Whether a fallback should be used for a two-sided stencil ref value. */
boolean stencil_ref_bf_fallback;
boolean two_sided_stencil_ref;
};
struct r300_rs_state {
@ -331,21 +331,6 @@ struct r300_context {
/* Parent class */
struct pipe_context context;
/* Emission of drawing packets. */
void (*emit_draw_arrays_immediate)(
struct r300_context *r300,
unsigned mode, unsigned start, unsigned count);
void (*emit_draw_arrays)(
struct r300_context *r300,
unsigned mode, unsigned count);
void (*emit_draw_elements)(
struct r300_context *r300, struct pipe_resource* indexBuffer,
unsigned indexSize, unsigned minIndex, unsigned maxIndex,
unsigned mode, unsigned start, unsigned count);
/* The interface to the windowing system, etc. */
struct r300_winsys_screen *rws;
/* Screen. */
@ -354,6 +339,8 @@ struct r300_context {
struct draw_context* draw;
/* Accelerated blit support. */
struct blitter_context* blitter;
/* Stencil two-sided reference value fallback. */
struct r300_stencilref_context *stencilref_fallback;
/* Vertex buffer for rendering. */
struct pipe_resource* vbo;
@ -441,9 +428,6 @@ struct r300_context {
uint32_t zbuffer_bpp;
/* Whether rendering is conditional and should be skipped. */
boolean skip_rendering;
/* Whether the two-sided stencil ref value is different for front and
* back faces, and fallback should be used for r3xx-r4xx. */
boolean stencil_ref_bf_fallback;
/* Point sprites texcoord index, 1 bit per texcoord */
int sprite_coord_enable;
/* Whether two-sided color selection is enabled (AKA light_twoside). */

View File

@ -157,11 +157,6 @@ static void r300_prepare_for_rendering(struct r300_context *r300,
boolean emit_aos_swtcl = flags & PREP_EMIT_AOS_SWTCL;
unsigned end_dwords = 0;
/* Stencil ref fallback. */
if (r300->stencil_ref_bf_fallback) {
cs_dwords = cs_dwords * 2 + 10;
}
/* Add dirty state, index offset, and AOS. */
if (first_draw) {
cs_dwords += r300_get_num_dirty_dwords(r300);
@ -250,7 +245,7 @@ static boolean immd_is_good_idea(struct r300_context *r300,
* after resolving fallback issues (e.g. stencil ref two-sided). *
****************************************************************************/
static void r500_emit_draw_arrays_immediate(struct r300_context *r300,
static void r300_emit_draw_arrays_immediate(struct r300_context *r300,
unsigned mode,
unsigned start,
unsigned count)
@ -340,7 +335,7 @@ static void r500_emit_draw_arrays_immediate(struct r300_context *r300,
}
}
static void r500_emit_draw_arrays(struct r300_context *r300,
static void r300_emit_draw_arrays(struct r300_context *r300,
unsigned mode,
unsigned count)
{
@ -369,7 +364,7 @@ static void r500_emit_draw_arrays(struct r300_context *r300,
END_CS;
}
static void r500_emit_draw_elements(struct r300_context *r300,
static void r300_emit_draw_elements(struct r300_context *r300,
struct pipe_resource* indexBuffer,
unsigned indexSize,
unsigned minIndex,
@ -432,104 +427,6 @@ static void r500_emit_draw_elements(struct r300_context *r300,
END_CS;
}
/*****************************************************************************
* The emission of draw packets for r300 which take care of the two-sided *
* stencil ref fallback and call r500's functions. *
****************************************************************************/
/* Set drawing for front faces. */
static void r300_begin_stencil_ref_fallback(struct r300_context *r300)
{
struct r300_rs_state *rs = (struct r300_rs_state*)r300->rs_state.state;
CS_LOCALS(r300);
BEGIN_CS(2);
OUT_CS_REG(R300_SU_CULL_MODE, rs->cull_mode | R300_CULL_BACK);
END_CS;
}
/* Set drawing for back faces. */
static void r300_switch_stencil_ref_side(struct r300_context *r300)
{
struct r300_rs_state *rs = (struct r300_rs_state*)r300->rs_state.state;
struct r300_dsa_state *dsa = (struct r300_dsa_state*)r300->dsa_state.state;
CS_LOCALS(r300);
BEGIN_CS(4);
OUT_CS_REG(R300_SU_CULL_MODE, rs->cull_mode | R300_CULL_FRONT);
OUT_CS_REG(R300_ZB_STENCILREFMASK,
dsa->stencil_ref_bf | r300->stencil_ref.ref_value[1]);
END_CS;
}
/* Restore the original state. */
static void r300_end_stencil_ref_fallback(struct r300_context *r300)
{
struct r300_rs_state *rs = (struct r300_rs_state*)r300->rs_state.state;
struct r300_dsa_state *dsa = (struct r300_dsa_state*)r300->dsa_state.state;
CS_LOCALS(r300);
BEGIN_CS(4);
OUT_CS_REG(R300_SU_CULL_MODE, rs->cull_mode);
OUT_CS_REG(R300_ZB_STENCILREFMASK,
dsa->stencil_ref_mask | r300->stencil_ref.ref_value[0]);
END_CS;
}
static void r300_emit_draw_arrays_immediate(struct r300_context *r300,
unsigned mode,
unsigned start,
unsigned count)
{
if (!r300->stencil_ref_bf_fallback) {
r500_emit_draw_arrays_immediate(r300, mode, start, count);
} else {
r300_begin_stencil_ref_fallback(r300);
r500_emit_draw_arrays_immediate(r300, mode, start, count);
r300_switch_stencil_ref_side(r300);
r500_emit_draw_arrays_immediate(r300, mode, start, count);
r300_end_stencil_ref_fallback(r300);
}
}
static void r300_emit_draw_arrays(struct r300_context *r300,
unsigned mode,
unsigned count)
{
if (!r300->stencil_ref_bf_fallback) {
r500_emit_draw_arrays(r300, mode, count);
} else {
r300_begin_stencil_ref_fallback(r300);
r500_emit_draw_arrays(r300, mode, count);
r300_switch_stencil_ref_side(r300);
r500_emit_draw_arrays(r300, mode, count);
r300_end_stencil_ref_fallback(r300);
}
}
static void r300_emit_draw_elements(struct r300_context *r300,
struct pipe_resource* indexBuffer,
unsigned indexSize,
unsigned minIndex,
unsigned maxIndex,
unsigned mode,
unsigned start,
unsigned count)
{
if (!r300->stencil_ref_bf_fallback) {
r500_emit_draw_elements(r300, indexBuffer, indexSize,
minIndex, maxIndex, mode, start, count);
} else {
r300_begin_stencil_ref_fallback(r300);
r500_emit_draw_elements(r300, indexBuffer, indexSize,
minIndex, maxIndex, mode, start, count);
r300_switch_stencil_ref_side(r300);
r500_emit_draw_elements(r300, indexBuffer, indexSize,
minIndex, maxIndex, mode, start, count);
r300_end_stencil_ref_fallback(r300);
}
}
static void r300_shorten_ubyte_elts(struct r300_context* r300,
struct pipe_resource** elts,
unsigned start,
@ -638,12 +535,12 @@ static void r300_draw_range_elements(struct pipe_context* pipe,
u_upload_flush(r300->upload_vb);
u_upload_flush(r300->upload_ib);
if (alt_num_verts || count <= 65535) {
r300->emit_draw_elements(r300, indexBuffer, indexSize,
r300_emit_draw_elements(r300, indexBuffer, indexSize,
minIndex, maxIndex, mode, start, count);
} else {
do {
short_count = MIN2(count, 65534);
r300->emit_draw_elements(r300, indexBuffer, indexSize,
r300_emit_draw_elements(r300, indexBuffer, indexSize,
minIndex, maxIndex,
mode, start, short_count);
@ -697,18 +594,18 @@ static void r300_draw_arrays(struct pipe_context* pipe, unsigned mode,
r300_update_derived_state(r300);
if (immd_is_good_idea(r300, count)) {
r300->emit_draw_arrays_immediate(r300, mode, start, count);
r300_emit_draw_arrays_immediate(r300, mode, start, count);
} else {
/* 9 spare dwords for emit_draw_arrays. */
r300_prepare_for_rendering(r300, PREP_FIRST_DRAW | PREP_VALIDATE_VBOS | PREP_EMIT_AOS,
NULL, 9, start, 0, NULL);
if (alt_num_verts || count <= 65535) {
r300->emit_draw_arrays(r300, mode, count);
r300_emit_draw_arrays(r300, mode, count);
} else {
do {
short_count = MIN2(count, 65535);
r300->emit_draw_arrays(r300, mode, short_count);
r300_emit_draw_arrays(r300, mode, short_count);
start += short_count;
count -= short_count;
@ -945,7 +842,7 @@ static boolean r300_render_set_primitive(struct vbuf_render* render,
return TRUE;
}
static void r500_render_draw_arrays(struct vbuf_render* render,
static void r300_render_draw_arrays(struct vbuf_render* render,
unsigned start,
unsigned count)
{
@ -991,7 +888,7 @@ static void r500_render_draw_arrays(struct vbuf_render* render,
END_CS;
}
static void r500_render_draw_elements(struct vbuf_render* render,
static void r300_render_draw_elements(struct vbuf_render* render,
const ushort* indices,
uint count)
{
@ -1047,40 +944,6 @@ static void r500_render_draw_elements(struct vbuf_render* render,
}
}
static void r300_render_draw_arrays(struct vbuf_render* render,
unsigned start,
unsigned count)
{
struct r300_context* r300 = r300_render(render)->r300;
if (!r300->stencil_ref_bf_fallback) {
r500_render_draw_arrays(render, start, count);
} else {
r300_begin_stencil_ref_fallback(r300);
r500_render_draw_arrays(render, start, count);
r300_switch_stencil_ref_side(r300);
r500_render_draw_arrays(render, start, count);
r300_end_stencil_ref_fallback(r300);
}
}
static void r300_render_draw_elements(struct vbuf_render* render,
const ushort* indices,
uint count)
{
struct r300_context* r300 = r300_render(render)->r300;
if (!r300->stencil_ref_bf_fallback) {
r500_render_draw_elements(render, indices, count);
} else {
r300_begin_stencil_ref_fallback(r300);
r500_render_draw_elements(render, indices, count);
r300_switch_stencil_ref_side(r300);
r500_render_draw_elements(render, indices, count);
r300_end_stencil_ref_fallback(r300);
}
}
static void r300_render_destroy(struct vbuf_render* render)
{
FREE(render);
@ -1101,13 +964,8 @@ static struct vbuf_render* r300_render_create(struct r300_context* r300)
r300render->base.map_vertices = r300_render_map_vertices;
r300render->base.unmap_vertices = r300_render_unmap_vertices;
r300render->base.set_primitive = r300_render_set_primitive;
if (r300->screen->caps.is_r500) {
r300render->base.draw_elements = r500_render_draw_elements;
r300render->base.draw_arrays = r500_render_draw_arrays;
} else {
r300render->base.draw_elements = r300_render_draw_elements;
r300render->base.draw_arrays = r300_render_draw_arrays;
}
r300render->base.draw_elements = r300_render_draw_elements;
r300render->base.draw_arrays = r300_render_draw_arrays;
r300render->base.release_vertices = r300_render_release_vertices;
r300render->base.destroy = r300_render_destroy;
@ -1141,25 +999,150 @@ struct draw_stage* r300_draw_stage(struct r300_context* r300)
return stage;
}
void r300_init_render_functions(struct r300_context *r300)
{
if (r300->screen->caps.has_tcl) {
r300->context.draw_arrays = r300_draw_arrays;
r300->context.draw_elements = r300_draw_elements;
r300->context.draw_range_elements = r300_draw_range_elements;
/****************************************************************************
* Two-sided stencil reference value fallback. It's designed to be as much
* separate from rest of the driver as possible.
***************************************************************************/
if (r300->screen->caps.is_r500) {
r300->emit_draw_arrays_immediate = r500_emit_draw_arrays_immediate;
r300->emit_draw_arrays = r500_emit_draw_arrays;
r300->emit_draw_elements = r500_emit_draw_elements;
} else {
r300->emit_draw_arrays_immediate = r300_emit_draw_arrays_immediate;
r300->emit_draw_arrays = r300_emit_draw_arrays;
r300->emit_draw_elements = r300_emit_draw_elements;
}
struct r300_stencilref_context {
void (*draw_arrays)(struct pipe_context *pipe,
unsigned mode, unsigned start, unsigned count);
void (*draw_range_elements)(
struct pipe_context *pipe, struct pipe_resource *indexBuffer,
unsigned indexSize, int indexBias, unsigned minIndex, unsigned maxIndex,
unsigned mode, unsigned start, unsigned count);
uint32_t rs_cull_mode;
uint32_t zb_stencilrefmask;
ubyte ref_value_front;
};
static boolean r300_stencilref_needed(struct r300_context *r300)
{
struct r300_dsa_state *dsa = (struct r300_dsa_state*)r300->dsa_state.state;
return dsa->two_sided_stencil_ref ||
(dsa->two_sided &&
r300->stencil_ref.ref_value[0] != r300->stencil_ref.ref_value[1]);
}
/* Set drawing for front faces. */
static void r300_stencilref_begin(struct r300_context *r300)
{
struct r300_stencilref_context *sr = r300->stencilref_fallback;
struct r300_rs_state *rs = (struct r300_rs_state*)r300->rs_state.state;
struct r300_dsa_state *dsa = (struct r300_dsa_state*)r300->dsa_state.state;
/* Save state. */
sr->rs_cull_mode = rs->cull_mode;
sr->zb_stencilrefmask = dsa->stencil_ref_mask;
sr->ref_value_front = r300->stencil_ref.ref_value[0];
/* We *cull* pixels, therefore no need to mask out the bits. */
rs->cull_mode |= R300_CULL_BACK;
r300->rs_state.dirty = TRUE;
}
/* Set drawing for back faces. */
static void r300_stencilref_switch_side(struct r300_context *r300)
{
struct r300_stencilref_context *sr = r300->stencilref_fallback;
struct r300_rs_state *rs = (struct r300_rs_state*)r300->rs_state.state;
struct r300_dsa_state *dsa = (struct r300_dsa_state*)r300->dsa_state.state;
rs->cull_mode = sr->rs_cull_mode | R300_CULL_FRONT;
dsa->stencil_ref_mask = dsa->stencil_ref_bf;
r300->stencil_ref.ref_value[0] = r300->stencil_ref.ref_value[1];
r300->rs_state.dirty = TRUE;
r300->dsa_state.dirty = TRUE;
}
/* Restore the original state. */
static void r300_stencilref_end(struct r300_context *r300)
{
struct r300_stencilref_context *sr = r300->stencilref_fallback;
struct r300_rs_state *rs = (struct r300_rs_state*)r300->rs_state.state;
struct r300_dsa_state *dsa = (struct r300_dsa_state*)r300->dsa_state.state;
/* Restore state. */
rs->cull_mode = sr->rs_cull_mode;
dsa->stencil_ref_mask = sr->zb_stencilrefmask;
r300->stencil_ref.ref_value[0] = sr->ref_value_front;
r300->rs_state.dirty = TRUE;
r300->dsa_state.dirty = TRUE;
}
static void r300_stencilref_draw_arrays(struct pipe_context *pipe, unsigned mode,
unsigned start, unsigned count)
{
struct r300_context *r300 = r300_context(pipe);
struct r300_stencilref_context *sr = r300->stencilref_fallback;
if (!r300_stencilref_needed(r300)) {
sr->draw_arrays(pipe, mode, start, count);
} else {
r300->context.draw_arrays = r300_swtcl_draw_arrays;
r300->context.draw_elements = r300_draw_elements;
r300->context.draw_range_elements = r300_swtcl_draw_range_elements;
r300_stencilref_begin(r300);
sr->draw_arrays(pipe, mode, start, count);
r300_stencilref_switch_side(r300);
sr->draw_arrays(pipe, mode, start, count);
r300_stencilref_end(r300);
}
}
static void r300_stencilref_draw_range_elements(
struct pipe_context *pipe, struct pipe_resource *indexBuffer,
unsigned indexSize, int indexBias, unsigned minIndex, unsigned maxIndex,
unsigned mode, unsigned start, unsigned count)
{
struct r300_context *r300 = r300_context(pipe);
struct r300_stencilref_context *sr = r300->stencilref_fallback;
if (!r300_stencilref_needed(r300)) {
sr->draw_range_elements(pipe, indexBuffer, indexSize, indexBias,
minIndex, maxIndex, mode, start, count);
} else {
r300_stencilref_begin(r300);
sr->draw_range_elements(pipe, indexBuffer, indexSize, indexBias,
minIndex, maxIndex, mode, start, count);
r300_stencilref_switch_side(r300);
sr->draw_range_elements(pipe, indexBuffer, indexSize, indexBias,
minIndex, maxIndex, mode, start, count);
r300_stencilref_end(r300);
}
}
static void r300_plug_in_stencil_ref_fallback(struct r300_context *r300)
{
r300->stencilref_fallback = CALLOC_STRUCT(r300_stencilref_context);
/* Save original draw functions. */
r300->stencilref_fallback->draw_arrays = r300->context.draw_arrays;
r300->stencilref_fallback->draw_range_elements = r300->context.draw_range_elements;
/* Override the draw functions. */
r300->context.draw_arrays = r300_stencilref_draw_arrays;
r300->context.draw_range_elements = r300_stencilref_draw_range_elements;
}
void r300_init_render_functions(struct r300_context *r300)
{
/* Set generic functions. */
r300->context.draw_elements = r300_draw_elements;
/* Set draw functions based on presence of HW TCL. */
if (r300->screen->caps.has_tcl) {
r300->context.draw_arrays = r300_draw_arrays;
r300->context.draw_range_elements = r300_draw_range_elements;
} else {
r300->context.draw_arrays = r300_swtcl_draw_arrays;
r300->context.draw_range_elements = r300_swtcl_draw_range_elements;
}
/* Plug in two-sided stencil reference value fallback if needed. */
if (!r300->screen->caps.is_r500)
r300_plug_in_stencil_ref_fallback(r300);
}

View File

@ -474,7 +474,7 @@ static void*
if (caps->is_r500) {
dsa->z_buffer_control |= R500_STENCIL_REFMASK_FRONT_BACK;
} else {
dsa->stencil_ref_bf_fallback =
dsa->two_sided_stencil_ref =
(state->stencil[0].valuemask != state->stencil[1].valuemask ||
state->stencil[0].writemask != state->stencil[1].writemask);
}
@ -497,20 +497,6 @@ static void*
return (void*)dsa;
}
static void r300_update_stencil_ref_fallback_status(struct r300_context *r300)
{
struct r300_dsa_state *dsa = (struct r300_dsa_state*)r300->dsa_state.state;
if (r300->screen->caps.is_r500) {
return;
}
r300->stencil_ref_bf_fallback =
dsa->stencil_ref_bf_fallback ||
(dsa->two_sided &&
r300->stencil_ref.ref_value[0] != r300->stencil_ref.ref_value[1]);
}
/* Bind DSA state. */
static void r300_bind_dsa_state(struct pipe_context* pipe,
void* state)
@ -522,8 +508,6 @@ static void r300_bind_dsa_state(struct pipe_context* pipe,
}
UPDATE_STATE(state, r300->dsa_state);
r300_update_stencil_ref_fallback_status(r300);
}
/* Free DSA state. */
@ -540,8 +524,6 @@ static void r300_set_stencil_ref(struct pipe_context* pipe,
r300->stencil_ref = *sr;
r300->dsa_state.dirty = TRUE;
r300_update_stencil_ref_fallback_status(r300);
}
/* This switcheroo is needed just because of goddamned MACRO_SWITCH. */