Rendering in two-sided mode is performed in separate passes for front and back faces, corresponding colors are selected by semantic ids.
Signed-off-by: Vadim Girlin <[email protected]> --- Tested on evergreen: no regressions, fixes two-side tests. src/gallium/drivers/r600/evergreen_state.c | 9 ++- src/gallium/drivers/r600/r600_pipe.h | 3 + src/gallium/drivers/r600/r600_shader.c | 6 -- src/gallium/drivers/r600/r600_state.c | 9 ++- src/gallium/drivers/r600/r600_state_common.c | 82 +++++++++++++++++++++++++- 5 files changed, 96 insertions(+), 13 deletions(-) diff --git a/src/gallium/drivers/r600/evergreen_state.c b/src/gallium/drivers/r600/evergreen_state.c index ed75ae3..b0999c4 100644 --- a/src/gallium/drivers/r600/evergreen_state.c +++ b/src/gallium/drivers/r600/evergreen_state.c @@ -902,6 +902,7 @@ static void *evergreen_create_rs_state(struct pipe_context *ctx, rs->clamp_fragment_color = state->clamp_fragment_color; rs->flatshade = state->flatshade; rs->sprite_coord_enable = state->sprite_coord_enable; + rs->two_side = state->light_twoside; clip_rule = state->scissor ? 0xAAAA : 0xFFFF; @@ -927,10 +928,14 @@ static void *evergreen_create_rs_state(struct pipe_context *ctx, polygon_dual_mode = (state->fill_front != PIPE_POLYGON_MODE_FILL || state->fill_back != PIPE_POLYGON_MODE_FILL); + + rs->cull_front = state->rasterizer_discard || (state->cull_face & PIPE_FACE_FRONT) ? 1 : 0; + rs->cull_back = state->rasterizer_discard || (state->cull_face & PIPE_FACE_BACK) ? 1 : 0; + r600_pipe_state_add_reg(rstate, R_028814_PA_SU_SC_MODE_CNTL, S_028814_PROVOKING_VTX_LAST(prov_vtx) | - S_028814_CULL_FRONT(state->rasterizer_discard || (state->cull_face & PIPE_FACE_FRONT) ? 1 : 0) | - S_028814_CULL_BACK(state->rasterizer_discard || (state->cull_face & PIPE_FACE_BACK) ? 1 : 0) | + S_028814_CULL_FRONT(rs->cull_front) | + S_028814_CULL_BACK(rs->cull_back) | S_028814_FACE(!state->front_ccw) | S_028814_POLY_OFFSET_FRONT_ENABLE(state->offset_tri) | S_028814_POLY_OFFSET_BACK_ENABLE(state->offset_tri) | diff --git a/src/gallium/drivers/r600/r600_pipe.h b/src/gallium/drivers/r600/r600_pipe.h index 447b9dc..30cc6d9 100644 --- a/src/gallium/drivers/r600/r600_pipe.h +++ b/src/gallium/drivers/r600/r600_pipe.h @@ -108,6 +108,9 @@ struct r600_pipe_rasterizer { boolean clamp_vertex_color; boolean clamp_fragment_color; boolean flatshade; + boolean two_side; + boolean cull_front; + boolean cull_back; unsigned sprite_coord_enable; float offset_units; float offset_scale; diff --git a/src/gallium/drivers/r600/r600_shader.c b/src/gallium/drivers/r600/r600_shader.c index ad4aded..bade11e 100644 --- a/src/gallium/drivers/r600/r600_shader.c +++ b/src/gallium/drivers/r600/r600_shader.c @@ -374,12 +374,6 @@ static int r600_spi_sid(struct r600_shader_io * io) /* For generic params simply use sid from tgsi */ index = io->sid; } else { - - /* FIXME: two-side rendering is broken in r600g, this will - * keep old functionality */ - if (name == TGSI_SEMANTIC_BCOLOR) - name = TGSI_SEMANTIC_COLOR; - /* For non-generic params - pack name and sid into 8 bits */ index = 0x80 | (name<<3) | (io->sid); } diff --git a/src/gallium/drivers/r600/r600_state.c b/src/gallium/drivers/r600/r600_state.c index 12157ff..df1d3c0 100644 --- a/src/gallium/drivers/r600/r600_state.c +++ b/src/gallium/drivers/r600/r600_state.c @@ -954,6 +954,7 @@ static void *r600_create_rs_state(struct pipe_context *ctx, rs->clamp_fragment_color = state->clamp_fragment_color; rs->flatshade = state->flatshade; rs->sprite_coord_enable = state->sprite_coord_enable; + rs->two_side = state->light_twoside; clip_rule = state->scissor ? 0xAAAA : 0xFFFF; /* offset */ @@ -978,10 +979,14 @@ static void *r600_create_rs_state(struct pipe_context *ctx, polygon_dual_mode = (state->fill_front != PIPE_POLYGON_MODE_FILL || state->fill_back != PIPE_POLYGON_MODE_FILL); + + rs->cull_front = state->rasterizer_discard || (state->cull_face & PIPE_FACE_FRONT) ? 1 : 0; + rs->cull_back = state->rasterizer_discard || (state->cull_face & PIPE_FACE_BACK) ? 1 : 0; + r600_pipe_state_add_reg(rstate, R_028814_PA_SU_SC_MODE_CNTL, S_028814_PROVOKING_VTX_LAST(prov_vtx) | - S_028814_CULL_FRONT(state->rasterizer_discard || (state->cull_face & PIPE_FACE_FRONT) ? 1 : 0) | - S_028814_CULL_BACK(state->rasterizer_discard || (state->cull_face & PIPE_FACE_BACK) ? 1 : 0) | + S_028814_CULL_FRONT(rs->cull_front) | + S_028814_CULL_BACK(rs->cull_back) | S_028814_FACE(!state->front_ccw) | S_028814_POLY_OFFSET_FRONT_ENABLE(state->offset_tri) | S_028814_POLY_OFFSET_BACK_ENABLE(state->offset_tri) | diff --git a/src/gallium/drivers/r600/r600_state_common.c b/src/gallium/drivers/r600/r600_state_common.c index 9f6f514..f1abf41 100644 --- a/src/gallium/drivers/r600/r600_state_common.c +++ b/src/gallium/drivers/r600/r600_state_common.c @@ -586,6 +586,55 @@ static void r600_update_derived_state(struct r600_pipe_context *rctx) } + +/* Prepare/restore the state for two-sided rendering. + * Front/back faces are rendered in separate passes, + * required color from vertex shader is selected by semantic id + * + * stage defines the current mode: + * 0 - rendering front faces only with front colors + * 1 - rendering back faces only with back colors + * 2 - restore normal state + */ +static void r600_prepare_two_side_mode(struct r600_pipe_context * rctx, unsigned stage) +{ + struct r600_shader * rshader = &rctx->ps_shader->shader; + struct r600_pipe_state rstate; + unsigned i, idx = 0, sid, tmp; + boolean eg_mode = (rctx->chip_class >= EVERGREEN); + + rstate.nregs = 0; + + if (stage>0) { + + for (i = 0; i < rshader->ninput; i++) { + + sid = rshader->input[i].spi_sid; + + if (rshader->input[i].name == TGSI_SEMANTIC_COLOR) { + + /* switch between front/back colors semantic ids from vertex shader */ + sid += (stage == 1 ? 1<<3 : 0 ); + + tmp = S_028644_SEMANTIC(sid); + r600_pipe_state_add_reg(&rstate, R_028644_SPI_PS_INPUT_CNTL_0 + idx * 4, + tmp, S_028644_SEMANTIC(0xFF), NULL, 0); + } + + if (sid || !eg_mode) + idx++; + } + + } + + r600_pipe_state_add_reg(&rstate, R_028814_PA_SU_SC_MODE_CNTL, + S_028814_CULL_FRONT(stage==1 ? 1 : rctx->rasterizer->cull_front) | + S_028814_CULL_BACK (stage==0 ? 1 : rctx->rasterizer->cull_back), + S_028814_CULL_FRONT(1) | S_028814_CULL_BACK(1), NULL, 0); + + r600_context_pipe_state_set(&rctx->ctx, &rstate); +} + void r600_draw_vbo(struct pipe_context *ctx, const struct pipe_draw_info *dinfo) { struct r600_pipe_context *rctx = (struct r600_pipe_context *)ctx; @@ -692,10 +741,37 @@ void r600_draw_vbo(struct pipe_context *ctx, const struct pipe_draw_info *dinfo) r600_context_pipe_state_set(&rctx->ctx, &rctx->vgt); - if (rctx->chip_class >= EVERGREEN) { - evergreen_context_draw(&rctx->ctx, &rdraw); + if (unlikely(rctx->rasterizer->two_side)) { + + /* front faces */ + r600_prepare_two_side_mode(rctx, 0); + + if (rctx->chip_class >= EVERGREEN) { + evergreen_context_draw(&rctx->ctx, &rdraw); + } else { + r600_context_draw(&rctx->ctx, &rdraw); + } + + /* back faces */ + r600_prepare_two_side_mode(rctx, 1); + + if (rctx->chip_class >= EVERGREEN) { + evergreen_context_draw(&rctx->ctx, &rdraw); + } else { + r600_context_draw(&rctx->ctx, &rdraw); + } + + /* restore normal state */ + r600_prepare_two_side_mode(rctx, 2); + } else { - r600_context_draw(&rctx->ctx, &rdraw); + + if (rctx->chip_class >= EVERGREEN) { + evergreen_context_draw(&rctx->ctx, &rdraw); + } else { + r600_context_draw(&rctx->ctx, &rdraw); + } + } if (rctx->framebuffer.zsbuf) -- 1.7.7.5 _______________________________________________ mesa-dev mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/mesa-dev
