Browse Source

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.
tags/mesa-7.9-rc1
Marek Olšák 15 years ago
parent
commit
90e5a37d12

+ 1
- 0
src/gallium/drivers/r300/Makefile View File

@@ -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

+ 1
- 0
src/gallium/drivers/r300/SConscript View File

@@ -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',

+ 2
- 3
src/gallium/drivers/r300/r300_state.c View File

@@ -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;

+ 16
- 2
src/gallium/drivers/r300/r300_state_derived.c View File

@@ -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]);

+ 4
- 0
src/gallium/drivers/r300/r300_vs.h View File

@@ -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 */

+ 358
- 0
src/gallium/drivers/r300/r300_vs_draw.c View File

@@ -0,0 +1,358 @@
/**************************************************************************
*
* Copyright 2009 Marek Olšák <maraeo@gmail.com>
*
* 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 <stdio.h>

#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;
}

Loading…
Cancel
Save