From 90e5a37d128efaca9e89434ab103826ee82cb911 Mon Sep 17 00:00:00 2001 From: Marek Olšák Date: Thu, 27 May 2010 19:11:56 +0200 Subject: r300g/swtcl: fix secondary color and back-face color outputs These piglit tests have been fixed: - bgra-sec-color-pointer - glsl-routing See comments at the beginning of r300_vs_draw.c WPOS is implemented too but it doesn't work yet. I'm still working on it. --- src/gallium/drivers/r300/Makefile | 1 + src/gallium/drivers/r300/SConscript | 1 + src/gallium/drivers/r300/r300_state.c | 5 +- src/gallium/drivers/r300/r300_state_derived.c | 18 +- src/gallium/drivers/r300/r300_vs.h | 4 + src/gallium/drivers/r300/r300_vs_draw.c | 358 ++++++++++++++++++++++++++ 6 files changed, 382 insertions(+), 5 deletions(-) create mode 100644 src/gallium/drivers/r300/r300_vs_draw.c (limited to 'src/gallium/drivers/r300') diff --git a/src/gallium/drivers/r300/Makefile b/src/gallium/drivers/r300/Makefile index d3cd6bef96..6bb82e5ed0 100644 --- a/src/gallium/drivers/r300/Makefile +++ b/src/gallium/drivers/r300/Makefile @@ -21,6 +21,7 @@ C_SOURCES = \ r300_state_derived.c \ r300_state_invariant.c \ r300_vs.c \ + r300_vs_draw.c \ r300_texture.c \ r300_tgsi_to_rc.c \ r300_transfer.c diff --git a/src/gallium/drivers/r300/SConscript b/src/gallium/drivers/r300/SConscript index 3921085d76..eb3e1d365e 100644 --- a/src/gallium/drivers/r300/SConscript +++ b/src/gallium/drivers/r300/SConscript @@ -31,6 +31,7 @@ r300 = env.ConvenienceLibrary( 'r300_state_derived.c', 'r300_state_invariant.c', 'r300_vs.c', + 'r300_vs_draw.c', 'r300_texture.c', 'r300_tgsi_to_rc.c', 'r300_transfer.c', diff --git a/src/gallium/drivers/r300/r300_state.c b/src/gallium/drivers/r300/r300_state.c index 80346e0c79..d765721827 100644 --- a/src/gallium/drivers/r300/r300_state.c +++ b/src/gallium/drivers/r300/r300_state.c @@ -1412,12 +1412,11 @@ static void* r300_create_vs_state(struct pipe_context* pipe, vs->state = *shader; vs->state.tokens = tgsi_dup_tokens(shader->tokens); - r300_init_vs_outputs(vs); - if (r300->screen->caps.has_tcl) { + r300_init_vs_outputs(vs); r300_translate_vertex_shader(r300, vs); } else { - vs->draw_vs = draw_create_vertex_shader(r300->draw, shader); + r300_draw_init_vertex_shader(r300->draw, vs); } return vs; diff --git a/src/gallium/drivers/r300/r300_state_derived.c b/src/gallium/drivers/r300/r300_state_derived.c index 7583862a1a..20f24e8b04 100644 --- a/src/gallium/drivers/r300/r300_state_derived.c +++ b/src/gallium/drivers/r300/r300_state_derived.c @@ -90,7 +90,13 @@ static void r300_draw_emit_all_attribs(struct r300_context* r300) } } - /* XXX Back-face colors. */ + /* Back-face colors. */ + for (i = 0; i < ATTR_COLOR_COUNT; i++) { + if (vs_outputs->bcolor[i] != ATTR_UNUSED) { + r300_draw_emit_attrib(r300, EMIT_4F, INTERP_LINEAR, + vs_outputs->bcolor[i]); + } + } /* Texture coordinates. */ /* Only 8 generic vertex attributes can be used. If there are more, @@ -110,6 +116,14 @@ static void r300_draw_emit_all_attribs(struct r300_context* r300) vs_outputs->fog); gen_count++; } + + /* WPOS. */ + if (r300_fs(r300)->shader->inputs.wpos != ATTR_UNUSED && gen_count < 8) { + DBG(r300, DBG_DRAW, "draw_emit_attrib: WPOS, index: %i\n", + vs_outputs->wpos); + r300_draw_emit_attrib(r300, EMIT_4F, INTERP_PERSPECTIVE, + vs_outputs->wpos); + } } /* Update the PSC tables for SW TCL, using Draw. */ @@ -129,7 +143,7 @@ static void r300_swtcl_vertex_psc(struct r300_context *r300) attrib_count = vinfo->num_attribs; DBG(r300, DBG_DRAW, "r300: attrib count: %d\n", attrib_count); for (i = 0; i < attrib_count; i++) { - DBG(r300, DBG_DRAW, "r300: attrib: offset %d, interp %d, size %d," + DBG(r300, DBG_DRAW, "r300: attrib: index %d, interp %d, emit %d," " vs_output_tab %d\n", vinfo->attrib[i].src_index, vinfo->attrib[i].interp_mode, vinfo->attrib[i].emit, vs_output_tab[i]); diff --git a/src/gallium/drivers/r300/r300_vs.h b/src/gallium/drivers/r300/r300_vs.h index 31890d78ca..170de6c79d 100644 --- a/src/gallium/drivers/r300/r300_vs.h +++ b/src/gallium/drivers/r300/r300_vs.h @@ -60,4 +60,8 @@ void r300_init_vs_outputs(struct r300_vertex_shader *vs); void r300_translate_vertex_shader(struct r300_context *r300, struct r300_vertex_shader *vs); + +void r300_draw_init_vertex_shader(struct draw_context *draw, + struct r300_vertex_shader *vs); + #endif /* R300_VS_H */ diff --git a/src/gallium/drivers/r300/r300_vs_draw.c b/src/gallium/drivers/r300/r300_vs_draw.c new file mode 100644 index 0000000000..5858492a0a --- /dev/null +++ b/src/gallium/drivers/r300/r300_vs_draw.c @@ -0,0 +1,358 @@ +/************************************************************************** + * + * Copyright 2009 Marek Olšák + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/* This file contains the vertex shader tranformations for SW TCL needed + * to overcome the limitations of the r300 rasterizer. + * + * Transformations: + * 1) If the secondary color output is present, the primary color must be + * inserted before it. + * 2) If any back-face color output is present, there must be all 4 color + * outputs and missing ones must be inserted. + * 3) Insert a trailing texcoord output containing a copy of POS, for WPOS. + * + * I know this code is cumbersome, but I don't know of any nicer way + * of transforming TGSI shaders. ~ M. + */ + +#include "r300_vs.h" + +#include + +#include "tgsi/tgsi_transform.h" +#include "tgsi/tgsi_dump.h" + +#include "draw/draw_context.h" + +struct vs_transform_context { + struct tgsi_transform_context base; + + boolean color_used[2]; + boolean bcolor_used[2]; + boolean temp_used[128]; + + /* Index of the pos output, typically 0. */ + unsigned pos_output; + /* Index of the pos temp where all writes of pos are redirected to. */ + unsigned pos_temp; + /* The index of the last generic output, after which we insert a new + * output for WPOS. */ + int last_generic; + + unsigned num_outputs; + /* Used to shift output decl. indices when inserting new ones. */ + unsigned decl_shift; + /* Used to remap writes to output decls if their indices changed. */ + unsigned out_remap[32]; + + /* First instruction processed? */ + boolean first_instruction; + /* End instruction processed? */ + boolean end_instruction; +}; + +static void emit_temp(struct tgsi_transform_context *ctx, unsigned reg) +{ + struct tgsi_full_declaration decl; + + decl = tgsi_default_full_declaration(); + decl.Declaration.File = TGSI_FILE_TEMPORARY; + decl.Range.First = decl.Range.Last = reg; + ctx->emit_declaration(ctx, &decl); +} + +static void emit_output(struct tgsi_transform_context *ctx, + unsigned name, unsigned index, unsigned interp, + unsigned reg) +{ + struct vs_transform_context *vsctx = (struct vs_transform_context *)ctx; + struct tgsi_full_declaration decl; + + decl = tgsi_default_full_declaration(); + decl.Declaration.File = TGSI_FILE_OUTPUT; + decl.Declaration.Interpolate = interp; + decl.Declaration.Semantic = TRUE; + decl.Semantic.Name = name; + decl.Semantic.Index = index; + decl.Range.First = decl.Range.Last = reg; + ctx->emit_declaration(ctx, &decl); + ++vsctx->num_outputs; +} + +static void insert_output(struct tgsi_transform_context *ctx, + struct tgsi_full_declaration *before, + unsigned name, unsigned index, unsigned interp) +{ + struct vs_transform_context *vsctx = (struct vs_transform_context *)ctx; + unsigned i; + + /* Make a place for the new output. */ + for (i = before->Range.First; i < Elements(vsctx->out_remap); i++) { + ++vsctx->out_remap[i]; + } + + /* Insert the new output. */ + emit_output(ctx, name, index, interp, before->Range.First); + + ++vsctx->decl_shift; +} + +static void insert_trailing_bcolor(struct tgsi_transform_context *ctx, + struct tgsi_full_declaration *before) +{ + struct vs_transform_context *vsctx = (struct vs_transform_context *)ctx; + + /* If BCOLOR0 is used, make sure BCOLOR1 is present too. Otherwise + * the rasterizer doesn't do the color selection correctly. */ + if (vsctx->bcolor_used[0] && !vsctx->bcolor_used[1]) { + if (before) { + insert_output(ctx, before, TGSI_SEMANTIC_BCOLOR, 1, + TGSI_INTERPOLATE_LINEAR); + } else { + emit_output(ctx, TGSI_SEMANTIC_BCOLOR, 1, + TGSI_INTERPOLATE_LINEAR, vsctx->num_outputs); + } + vsctx->bcolor_used[1] = TRUE; + } +} + +static void transform_decl(struct tgsi_transform_context *ctx, + struct tgsi_full_declaration *decl) +{ + struct vs_transform_context *vsctx = (struct vs_transform_context *)ctx; + unsigned i; + + if (decl->Declaration.File == TGSI_FILE_OUTPUT) { + switch (decl->Semantic.Name) { + case TGSI_SEMANTIC_POSITION: + vsctx->pos_output = decl->Range.First; + break; + + case TGSI_SEMANTIC_COLOR: + assert(decl->Semantic.Index < 2); + vsctx->color_used[decl->Semantic.Index] = TRUE; + + /* We must rasterize the first color if the second one is + * used, otherwise the rasterizer doesn't do the color + * selection correctly. Declare it, but don't write to it. */ + if (decl->Semantic.Index == 1 && !vsctx->color_used[0]) { + insert_output(ctx, decl, TGSI_SEMANTIC_COLOR, 0, + TGSI_INTERPOLATE_LINEAR); + vsctx->color_used[0] = TRUE; + } + break; + + case TGSI_SEMANTIC_BCOLOR: + assert(decl->Semantic.Index < 2); + vsctx->bcolor_used[decl->Semantic.Index] = TRUE; + + /* We must rasterize all 4 colors if back-face colors are + * used, otherwise the rasterizer doesn't do the color + * selection correctly. Declare it, but don't write to it. */ + if (!vsctx->color_used[0]) { + insert_output(ctx, decl, TGSI_SEMANTIC_COLOR, 0, + TGSI_INTERPOLATE_LINEAR); + vsctx->color_used[0] = TRUE; + } + if (!vsctx->color_used[1]) { + insert_output(ctx, decl, TGSI_SEMANTIC_COLOR, 1, + TGSI_INTERPOLATE_LINEAR); + vsctx->color_used[1] = TRUE; + } + if (decl->Semantic.Index == 1 && !vsctx->bcolor_used[0]) { + insert_output(ctx, decl, TGSI_SEMANTIC_BCOLOR, 0, + TGSI_INTERPOLATE_LINEAR); + vsctx->color_used[2] = TRUE; + } + /* One more case is handled in insert_trailing_bcolor. */ + break; + + case TGSI_SEMANTIC_GENERIC: + vsctx->last_generic = MAX2(vsctx->last_generic, decl->Semantic.Index); + break; + } + + if (decl->Semantic.Name != TGSI_SEMANTIC_BCOLOR) { + /* Insert it as soon as possible. */ + insert_trailing_bcolor(ctx, decl); + } + + /* Since we're inserting new outputs in between, the following outputs + * should be moved to the right so that they don't overlap with + * the newly added ones. */ + decl->Range.First += vsctx->decl_shift; + decl->Range.Last += vsctx->decl_shift; + + ++vsctx->num_outputs; + } else if (decl->Declaration.File == TGSI_FILE_TEMPORARY) { + for (i = decl->Range.First; i <= decl->Range.Last; i++) { + vsctx->temp_used[i] = TRUE; + } + } + + ctx->emit_declaration(ctx, decl); +} + +static void transform_inst(struct tgsi_transform_context *ctx, + struct tgsi_full_instruction *inst) +{ + struct vs_transform_context *vsctx = (struct vs_transform_context *) ctx; + struct tgsi_full_instruction new_inst; + unsigned i; + + if (!vsctx->first_instruction) { + vsctx->first_instruction = TRUE; + + /* The trailing BCOLOR should be inserted before the code + * if it hasn't already been done so. */ + insert_trailing_bcolor(ctx, NULL); + + /* Insert the generic output for WPOS. */ + emit_output(ctx, TGSI_SEMANTIC_GENERIC, vsctx->last_generic + 1, + TGSI_INTERPOLATE_PERSPECTIVE, vsctx->num_outputs); + + /* Find a free temp for POSITION. */ + for (i = 0; i < Elements(vsctx->temp_used); i++) { + if (!vsctx->temp_used[i]) { + emit_temp(ctx, i); + vsctx->pos_temp = i; + break; + } + } + } + + if (inst->Instruction.Opcode == TGSI_OPCODE_END) { + /* MOV OUT[pos_output], TEMP[pos_temp]; */ + new_inst = tgsi_default_full_instruction(); + new_inst.Instruction.Opcode = TGSI_OPCODE_MOV; + new_inst.Instruction.NumDstRegs = 1; + new_inst.Dst[0].Register.File = TGSI_FILE_OUTPUT; + new_inst.Dst[0].Register.Index = vsctx->pos_output; + new_inst.Dst[0].Register.WriteMask = TGSI_WRITEMASK_XYZW; + new_inst.Instruction.NumSrcRegs = 1; + new_inst.Src[0].Register.File = TGSI_FILE_TEMPORARY; + new_inst.Src[0].Register.Index = vsctx->pos_temp; + ctx->emit_instruction(ctx, &new_inst); + + /* MOV OUT[n-1], TEMP[pos_temp]; */ + new_inst = tgsi_default_full_instruction(); + new_inst.Instruction.Opcode = TGSI_OPCODE_MOV; + new_inst.Instruction.NumDstRegs = 1; + new_inst.Dst[0].Register.File = TGSI_FILE_OUTPUT; + new_inst.Dst[0].Register.Index = vsctx->num_outputs - 1; + new_inst.Dst[0].Register.WriteMask = TGSI_WRITEMASK_XYZW; + new_inst.Instruction.NumSrcRegs = 1; + new_inst.Src[0].Register.File = TGSI_FILE_TEMPORARY; + new_inst.Src[0].Register.Index = vsctx->pos_temp; + ctx->emit_instruction(ctx, &new_inst); + + vsctx->end_instruction = TRUE; + } else { + /* Not an END instruction. */ + /* Fix writes to outputs. */ + for (i = 0; i < inst->Instruction.NumDstRegs; i++) { + struct tgsi_full_dst_register *dst = &inst->Dst[i]; + if (dst->Register.File == TGSI_FILE_OUTPUT) { + if (dst->Register.Index == vsctx->pos_output) { + /* Replace writes to OUT[pos_output] with TEMP[pos_temp]. */ + dst->Register.File = TGSI_FILE_TEMPORARY; + dst->Register.Index = vsctx->pos_temp; + } else { + /* Not a position, good... + * Since we were changing the indices of output decls, + * we must redirect writes into them too. */ + dst->Register.Index = vsctx->out_remap[dst->Register.Index]; + } + } + } + + /* Inserting 2 instructions before the END opcode moves all following + * labels by 2. Subroutines are always after the END opcode so + * they're always moved. */ + if (inst->Instruction.Opcode == TGSI_OPCODE_CAL) { + inst->Label.Label += 2; + } + /* The labels of the following opcodes are moved only after + * the END opcode. */ + if (vsctx->end_instruction && + (inst->Instruction.Opcode == TGSI_OPCODE_IF || + inst->Instruction.Opcode == TGSI_OPCODE_ELSE || + inst->Instruction.Opcode == TGSI_OPCODE_BGNLOOP || + inst->Instruction.Opcode == TGSI_OPCODE_ENDLOOP)) { + inst->Label.Label += 2; + } + } + + ctx->emit_instruction(ctx, inst); +} + +void r300_draw_init_vertex_shader(struct draw_context *draw, + struct r300_vertex_shader *vs) +{ + struct pipe_shader_state new_vs; + struct vs_transform_context transform; + const uint newLen = tgsi_num_tokens(vs->state.tokens) + 100 /* XXX */; + unsigned i; + + new_vs.tokens = tgsi_alloc_tokens(newLen); + if (new_vs.tokens == NULL) + return; + + memset(&transform, 0, sizeof(transform)); + for (i = 0; i < Elements(transform.out_remap); i++) { + transform.out_remap[i] = i; + } + transform.last_generic = -1; + transform.base.transform_instruction = transform_inst; + transform.base.transform_declaration = transform_decl; + + tgsi_transform_shader(vs->state.tokens, + (struct tgsi_token*)new_vs.tokens, + newLen, &transform.base); + +#if 0 + printf("----------------------------------------------\norig shader:\n"); + tgsi_dump(vs->state.tokens, 0); + printf("----------------------------------------------\nnew shader:\n"); + tgsi_dump(new_vs.tokens, 0); + printf("----------------------------------------------\n"); +#endif + + /* Free old tokens. */ + FREE((void*)vs->state.tokens); + + vs->draw_vs = draw_create_vertex_shader(draw, &new_vs); + + /* Instead of duplicating and freeing the tokens, copy the pointer directly. */ + vs->state.tokens = new_vs.tokens; + + /* Init the VS output table for the rasterizer. */ + r300_init_vs_outputs(vs); + + /**/ + vs->outputs.generic[transform.last_generic + 1] = ATTR_UNUSED; + vs->outputs.wpos -= 1; +} -- cgit v1.2.3