From 725a820b926575265e6790601a0defd9c30947dc Mon Sep 17 00:00:00 2001 From: Vadim Girlin Date: Fri, 6 Jan 2012 08:13:18 +0400 Subject: [PATCH] r600g: implement two-sided lighting (v3) v2: select the colors in the pixel shader v3: fix rs state creation for pre-evergreen Signed-off-by: Vadim Girlin Signed-off-by: Dave Airlie --- src/gallium/drivers/r600/evergreen_state.c | 1 + src/gallium/drivers/r600/r600_pipe.h | 2 + src/gallium/drivers/r600/r600_shader.c | 153 ++++++++++++++++--- src/gallium/drivers/r600/r600_shader.h | 1 + src/gallium/drivers/r600/r600_state.c | 1 + src/gallium/drivers/r600/r600_state_common.c | 2 + 6 files changed, 135 insertions(+), 25 deletions(-) diff --git a/src/gallium/drivers/r600/evergreen_state.c b/src/gallium/drivers/r600/evergreen_state.c index dd8b8300a09..59328b959cf 100644 --- a/src/gallium/drivers/r600/evergreen_state.c +++ b/src/gallium/drivers/r600/evergreen_state.c @@ -906,6 +906,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; diff --git a/src/gallium/drivers/r600/r600_pipe.h b/src/gallium/drivers/r600/r600_pipe.h index 45bb4da8c2a..87a710b9831 100644 --- a/src/gallium/drivers/r600/r600_pipe.h +++ b/src/gallium/drivers/r600/r600_pipe.h @@ -108,6 +108,7 @@ struct r600_pipe_rasterizer { boolean clamp_vertex_color; boolean clamp_fragment_color; boolean flatshade; + boolean two_side; unsigned sprite_coord_enable; float offset_units; float offset_scale; @@ -217,6 +218,7 @@ struct r600_pipe_context { /* shader information */ boolean clamp_vertex_color; boolean clamp_fragment_color; + boolean two_side; unsigned sprite_coord_enable; boolean export_16bpc; unsigned alpha_ref; diff --git a/src/gallium/drivers/r600/r600_shader.c b/src/gallium/drivers/r600/r600_shader.c index 0942aa10ec0..6b3d4ef436b 100644 --- a/src/gallium/drivers/r600/r600_shader.c +++ b/src/gallium/drivers/r600/r600_shader.c @@ -193,6 +193,8 @@ struct r600_shader_ctx { boolean input_linear; boolean input_perspective; int num_interp_gpr; + int face_gpr; + int colors_used; }; struct r600_shader_tgsi_instruction { @@ -376,12 +378,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); } @@ -395,6 +391,51 @@ static int r600_spi_sid(struct r600_shader_io * io) return index; }; +/* turn input into interpolate on EG */ +static int evergreen_interp_input(struct r600_shader_ctx *ctx, int index) +{ + int r = 0; + + if (ctx->shader->input[index].spi_sid) { + ctx->shader->input[index].lds_pos = ctx->shader->nlds++; + if (ctx->shader->input[index].interpolate > 0) { + r = evergreen_interp_alu(ctx, index); + } else { + r = evergreen_interp_flat(ctx, index); + } + } + return r; +} + +static int select_twoside_color(struct r600_shader_ctx *ctx, int front, int back) +{ + struct r600_bytecode_alu alu; + int i, r; + int gpr_front = ctx->shader->input[front].gpr; + int gpr_back = ctx->shader->input[back].gpr; + + for (i = 0; i < 4; i++) { + memset(&alu, 0, sizeof(alu)); + alu.inst = CTX_INST(V_SQ_ALU_WORD1_OP3_SQ_OP3_INST_CNDGT); + alu.is_op3 = 1; + alu.dst.write = 1; + alu.dst.sel = gpr_front; + alu.src[0].sel = ctx->face_gpr; + alu.src[1].sel = gpr_front; + alu.src[2].sel = gpr_back; + + alu.dst.chan = i; + alu.src[1].chan = i; + alu.src[2].chan = i; + alu.last = (i==3); + + if ((r = r600_bytecode_add_alu(ctx->bc, &alu))) + return r; + } + + return 0; +} + static int tgsi_declaration(struct r600_shader_ctx *ctx) { struct tgsi_full_declaration *d = &ctx->parse.FullToken.FullDeclaration; @@ -410,15 +451,15 @@ static int tgsi_declaration(struct r600_shader_ctx *ctx) ctx->shader->input[i].interpolate = d->Declaration.Interpolate; ctx->shader->input[i].centroid = d->Declaration.Centroid; ctx->shader->input[i].gpr = ctx->file_offset[TGSI_FILE_INPUT] + d->Range.First; - if (ctx->type == TGSI_PROCESSOR_FRAGMENT && ctx->bc->chip_class >= EVERGREEN) { - /* turn input into interpolate on EG */ - if (ctx->shader->input[i].spi_sid) { - ctx->shader->input[i].lds_pos = ctx->shader->nlds++; - if (ctx->shader->input[i].interpolate > 0) { - evergreen_interp_alu(ctx, i); - } else { - evergreen_interp_flat(ctx, i); - } + if (ctx->type == TGSI_PROCESSOR_FRAGMENT) { + if (ctx->shader->input[i].name == TGSI_SEMANTIC_FACE) + ctx->face_gpr = ctx->shader->input[i].gpr; + else if (ctx->shader->input[i].name == TGSI_SEMANTIC_COLOR) + ctx->colors_used++; + if (ctx->bc->chip_class >= EVERGREEN) { + r = evergreen_interp_input(ctx, i); + if (r) + return r; } } break; @@ -699,6 +740,47 @@ static int tgsi_split_literal_constant(struct r600_shader_ctx *ctx) return 0; } +static int process_twoside_color_inputs(struct r600_shader_ctx *ctx) +{ + int i, r, count = ctx->shader->ninput; + + /* additional inputs will be allocated right after the existing inputs, + * we won't need them after the color selection, so we don't need to + * reserve these gprs for the rest of the shader code and to adjust + * output offsets etc. */ + int gpr = ctx->file_offset[TGSI_FILE_INPUT] + + ctx->info.file_max[TGSI_FILE_INPUT] + 1; + + if (ctx->face_gpr == -1) { + i = ctx->shader->ninput++; + ctx->shader->input[i].name = TGSI_SEMANTIC_FACE; + ctx->shader->input[i].spi_sid = 0; + ctx->shader->input[i].gpr = gpr++; + ctx->face_gpr = ctx->shader->input[i].gpr; + } + + for (i = 0; i < count; i++) { + if (ctx->shader->input[i].name == TGSI_SEMANTIC_COLOR) { + int ni = ctx->shader->ninput++; + memcpy(&ctx->shader->input[ni],&ctx->shader->input[i], sizeof(struct r600_shader_io)); + ctx->shader->input[ni].name = TGSI_SEMANTIC_BCOLOR; + ctx->shader->input[ni].spi_sid = r600_spi_sid(&ctx->shader->input[ni]); + ctx->shader->input[ni].gpr = gpr++; + + if (ctx->bc->chip_class >= EVERGREEN) { + r = evergreen_interp_input(ctx, ni); + if (r) + return r; + } + + r = select_twoside_color(ctx, i, ni); + if (r) + return r; + } + } + return 0; +} + static int r600_shader_from_tgsi(struct r600_pipe_context * rctx, struct r600_pipe_shader *pipeshader) { struct r600_shader *shader = &pipeshader->shader; @@ -722,6 +804,11 @@ static int r600_shader_from_tgsi(struct r600_pipe_context * rctx, struct r600_pi shader->processor_type = ctx.type; ctx.bc->type = shader->processor_type; + ctx.face_gpr = -1; + ctx.colors_used = 0; + + shader->two_side = (ctx.type == TGSI_PROCESSOR_FRAGMENT) && rctx->two_side; + shader->clamp_color = (((ctx.type == TGSI_PROCESSOR_FRAGMENT) && rctx->clamp_fragment_color) || ((ctx.type == TGSI_PROCESSOR_VERTEX) && rctx->clamp_vertex_color)); @@ -800,6 +887,31 @@ static int r600_shader_from_tgsi(struct r600_pipe_context * rctx, struct r600_pi if (r) goto out_err; break; + case TGSI_TOKEN_TYPE_INSTRUCTION: + break; + case TGSI_TOKEN_TYPE_PROPERTY: + property = &ctx.parse.FullToken.FullProperty; + if (property->Property.PropertyName == TGSI_PROPERTY_FS_COLOR0_WRITES_ALL_CBUFS) { + if (property->u[0].Data == 1) + shader->fs_write_all = TRUE; + } + break; + default: + R600_ERR("unsupported token type %d\n", ctx.parse.FullToken.Token.Type); + r = -EINVAL; + goto out_err; + } + } + + if (shader->two_side && ctx.colors_used) { + if ((r = process_twoside_color_inputs(&ctx))) + return r; + } + + tgsi_parse_init(&ctx.parse, tokens); + while (!tgsi_parse_end_of_tokens(&ctx.parse)) { + tgsi_parse_token(&ctx.parse); + switch (ctx.parse.FullToken.Token.Type) { case TGSI_TOKEN_TYPE_INSTRUCTION: r = tgsi_is_supported(&ctx); if (r) @@ -823,17 +935,8 @@ static int r600_shader_from_tgsi(struct r600_pipe_context * rctx, struct r600_pi if (r) goto out_err; break; - case TGSI_TOKEN_TYPE_PROPERTY: - property = &ctx.parse.FullToken.FullProperty; - if (property->Property.PropertyName == TGSI_PROPERTY_FS_COLOR0_WRITES_ALL_CBUFS) { - if (property->u[0].Data == 1) - shader->fs_write_all = TRUE; - } - break; default: - R600_ERR("unsupported token type %d\n", ctx.parse.FullToken.Token.Type); - r = -EINVAL; - goto out_err; + break; } } diff --git a/src/gallium/drivers/r600/r600_shader.h b/src/gallium/drivers/r600/r600_shader.h index 9990ba646af..530a77604fe 100644 --- a/src/gallium/drivers/r600/r600_shader.h +++ b/src/gallium/drivers/r600/r600_shader.h @@ -47,6 +47,7 @@ struct r600_shader { boolean uses_kill; boolean fs_write_all; boolean clamp_color; + boolean two_side; unsigned nr_cbufs; }; diff --git a/src/gallium/drivers/r600/r600_state.c b/src/gallium/drivers/r600/r600_state.c index 39ab247ce5c..afe6fb0e8be 100644 --- a/src/gallium/drivers/r600/r600_state.c +++ b/src/gallium/drivers/r600/r600_state.c @@ -958,6 +958,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 */ diff --git a/src/gallium/drivers/r600/r600_state_common.c b/src/gallium/drivers/r600/r600_state_common.c index ac9bd27df24..eb32d5153a2 100644 --- a/src/gallium/drivers/r600/r600_state_common.c +++ b/src/gallium/drivers/r600/r600_state_common.c @@ -103,6 +103,7 @@ void r600_bind_rs_state(struct pipe_context *ctx, void *state) rctx->clamp_fragment_color = rs->clamp_fragment_color; rctx->sprite_coord_enable = rs->sprite_coord_enable; + rctx->two_side = rs->two_side; rctx->rasterizer = rs; @@ -568,6 +569,7 @@ static void r600_update_derived_state(struct r600_pipe_context *rctx) } if ((rctx->ps_shader->shader.clamp_color != rctx->clamp_fragment_color) || + (rctx->ps_shader->shader.two_side != rctx->two_side) || ((rctx->chip_class >= EVERGREEN) && rctx->ps_shader->shader.fs_write_all && (rctx->ps_shader->shader.nr_cbufs != rctx->nr_cbufs))) { r600_shader_rebuild(&rctx->context, rctx->ps_shader); -- 2.30.2