Path: blob/21.2-virgl/src/gallium/drivers/r300/r300_vs_draw.c
4570 views
/**************************************************************************1*2* Copyright 2009 Marek Olšák <[email protected]>3*4* Permission is hereby granted, free of charge, to any person obtaining a5* copy of this software and associated documentation files (the6* "Software"), to deal in the Software without restriction, including7* without limitation the rights to use, copy, modify, merge, publish,8* distribute, sub license, and/or sell copies of the Software, and to9* permit persons to whom the Software is furnished to do so, subject to10* the following conditions:11*12* The above copyright notice and this permission notice (including the13* next paragraph) shall be included in all copies or substantial portions14* of the Software.15*16* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS17* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF18* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.19* IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR20* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,21* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE22* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.23*24**************************************************************************/2526/* This file contains the vertex shader tranformations for SW TCL needed27* to overcome the limitations of the r300 rasterizer.28*29* Transformations:30* 1) If the secondary color output is present, the primary color must be31* present too.32* 2) If any back-face color output is present, there must be all 4 color33* outputs and missing ones must be inserted.34* 3) Insert a trailing texcoord output containing a copy of POS, for WPOS.35*36* I know this code is cumbersome, but I don't know of any nicer way37* of transforming TGSI shaders. ~ M.38*/3940#include "r300_vs.h"4142#include <stdio.h>4344#include "tgsi/tgsi_transform.h"45#include "tgsi/tgsi_dump.h"4647#include "draw/draw_context.h"4849struct vs_transform_context {50struct tgsi_transform_context base;5152boolean color_used[2];53boolean bcolor_used[2];5455/* Index of the pos output, typically 0. */56unsigned pos_output;57/* Index of the pos temp where all writes of pos are redirected to. */58unsigned pos_temp;59/* The index of the last generic output, after which we insert a new60* output for WPOS. */61int last_generic;6263unsigned num_outputs;64/* Used to shift output decl. indices when inserting new ones. */65unsigned decl_shift;66/* Used to remap writes to output decls if their indices changed. */67unsigned out_remap[32];6869/* First instruction processed? */70boolean first_instruction;71/* End instruction processed? */72boolean end_instruction;7374boolean temp_used[1024];75};7677static void emit_temp(struct tgsi_transform_context *ctx, unsigned reg)78{79struct tgsi_full_declaration decl;8081decl = tgsi_default_full_declaration();82decl.Declaration.File = TGSI_FILE_TEMPORARY;83decl.Range.First = decl.Range.Last = reg;84ctx->emit_declaration(ctx, &decl);85}8687static void emit_output(struct tgsi_transform_context *ctx,88unsigned name, unsigned index, unsigned interp,89unsigned reg)90{91struct vs_transform_context *vsctx = (struct vs_transform_context *)ctx;92struct tgsi_full_declaration decl;9394decl = tgsi_default_full_declaration();95decl.Declaration.File = TGSI_FILE_OUTPUT;96decl.Declaration.Interpolate = 1;97decl.Declaration.Semantic = TRUE;98decl.Semantic.Name = name;99decl.Semantic.Index = index;100decl.Range.First = decl.Range.Last = reg;101decl.Interp.Interpolate = interp;102ctx->emit_declaration(ctx, &decl);103++vsctx->num_outputs;104}105106static void insert_output_before(struct tgsi_transform_context *ctx,107struct tgsi_full_declaration *before,108unsigned name, unsigned index, unsigned interp)109{110struct vs_transform_context *vsctx = (struct vs_transform_context *)ctx;111unsigned i;112113/* Make a place for the new output. */114for (i = before->Range.First; i < ARRAY_SIZE(vsctx->out_remap); i++) {115++vsctx->out_remap[i];116}117118/* Insert the new output. */119emit_output(ctx, name, index, interp,120before->Range.First + vsctx->decl_shift);121122++vsctx->decl_shift;123}124125static void insert_output_after(struct tgsi_transform_context *ctx,126struct tgsi_full_declaration *after,127unsigned name, unsigned index, unsigned interp)128{129struct vs_transform_context *vsctx = (struct vs_transform_context *)ctx;130unsigned i;131132/* Make a place for the new output. */133for (i = after->Range.First+1; i < ARRAY_SIZE(vsctx->out_remap); i++) {134++vsctx->out_remap[i];135}136137/* Insert the new output. */138emit_output(ctx, name, index, interp,139after->Range.First + 1);140141++vsctx->decl_shift;142}143144static void transform_decl(struct tgsi_transform_context *ctx,145struct tgsi_full_declaration *decl)146{147struct vs_transform_context *vsctx = (struct vs_transform_context *)ctx;148unsigned i;149150if (decl->Declaration.File == TGSI_FILE_OUTPUT) {151switch (decl->Semantic.Name) {152case TGSI_SEMANTIC_POSITION:153vsctx->pos_output = decl->Range.First;154break;155156case TGSI_SEMANTIC_COLOR:157assert(decl->Semantic.Index < 2);158159/* We must rasterize the first color if the second one is160* used, otherwise the rasterizer doesn't do the color161* selection correctly. Declare it, but don't write to it. */162if (decl->Semantic.Index == 1 && !vsctx->color_used[0]) {163insert_output_before(ctx, decl, TGSI_SEMANTIC_COLOR, 0,164TGSI_INTERPOLATE_LINEAR);165vsctx->color_used[0] = TRUE;166}167break;168169case TGSI_SEMANTIC_BCOLOR:170assert(decl->Semantic.Index < 2);171172/* We must rasterize all 4 colors if back-face colors are173* used, otherwise the rasterizer doesn't do the color174* selection correctly. Declare it, but don't write to it. */175if (!vsctx->color_used[0]) {176insert_output_before(ctx, decl, TGSI_SEMANTIC_COLOR, 0,177TGSI_INTERPOLATE_LINEAR);178vsctx->color_used[0] = TRUE;179}180if (!vsctx->color_used[1]) {181insert_output_before(ctx, decl, TGSI_SEMANTIC_COLOR, 1,182TGSI_INTERPOLATE_LINEAR);183vsctx->color_used[1] = TRUE;184}185if (decl->Semantic.Index == 1 && !vsctx->bcolor_used[0]) {186insert_output_before(ctx, decl, TGSI_SEMANTIC_BCOLOR, 0,187TGSI_INTERPOLATE_LINEAR);188vsctx->bcolor_used[0] = TRUE;189}190break;191192case TGSI_SEMANTIC_GENERIC:193vsctx->last_generic = MAX2(vsctx->last_generic, decl->Semantic.Index);194break;195}196197/* Since we're inserting new outputs in between, the following outputs198* should be moved to the right so that they don't overlap with199* the newly added ones. */200decl->Range.First += vsctx->decl_shift;201decl->Range.Last += vsctx->decl_shift;202203++vsctx->num_outputs;204} else if (decl->Declaration.File == TGSI_FILE_TEMPORARY) {205for (i = decl->Range.First; i <= decl->Range.Last; i++) {206vsctx->temp_used[i] = TRUE;207}208}209210ctx->emit_declaration(ctx, decl);211212/* Insert BCOLOR1 if needed. */213if (decl->Declaration.File == TGSI_FILE_OUTPUT &&214decl->Semantic.Name == TGSI_SEMANTIC_BCOLOR &&215!vsctx->bcolor_used[1]) {216insert_output_after(ctx, decl, TGSI_SEMANTIC_BCOLOR, 1,217TGSI_INTERPOLATE_LINEAR);218}219}220221static void transform_inst(struct tgsi_transform_context *ctx,222struct tgsi_full_instruction *inst)223{224struct vs_transform_context *vsctx = (struct vs_transform_context *) ctx;225struct tgsi_full_instruction new_inst;226unsigned i;227228if (!vsctx->first_instruction) {229vsctx->first_instruction = TRUE;230231/* Insert the generic output for WPOS. */232emit_output(ctx, TGSI_SEMANTIC_GENERIC, vsctx->last_generic + 1,233TGSI_INTERPOLATE_PERSPECTIVE, vsctx->num_outputs);234235/* Find a free temp for POSITION. */236for (i = 0; i < ARRAY_SIZE(vsctx->temp_used); i++) {237if (!vsctx->temp_used[i]) {238emit_temp(ctx, i);239vsctx->pos_temp = i;240break;241}242}243}244245if (inst->Instruction.Opcode == TGSI_OPCODE_END) {246/* MOV OUT[pos_output], TEMP[pos_temp]; */247new_inst = tgsi_default_full_instruction();248new_inst.Instruction.Opcode = TGSI_OPCODE_MOV;249new_inst.Instruction.NumDstRegs = 1;250new_inst.Dst[0].Register.File = TGSI_FILE_OUTPUT;251new_inst.Dst[0].Register.Index = vsctx->pos_output;252new_inst.Dst[0].Register.WriteMask = TGSI_WRITEMASK_XYZW;253new_inst.Instruction.NumSrcRegs = 1;254new_inst.Src[0].Register.File = TGSI_FILE_TEMPORARY;255new_inst.Src[0].Register.Index = vsctx->pos_temp;256ctx->emit_instruction(ctx, &new_inst);257258/* MOV OUT[n-1], TEMP[pos_temp]; */259new_inst = tgsi_default_full_instruction();260new_inst.Instruction.Opcode = TGSI_OPCODE_MOV;261new_inst.Instruction.NumDstRegs = 1;262new_inst.Dst[0].Register.File = TGSI_FILE_OUTPUT;263new_inst.Dst[0].Register.Index = vsctx->num_outputs - 1;264new_inst.Dst[0].Register.WriteMask = TGSI_WRITEMASK_XYZW;265new_inst.Instruction.NumSrcRegs = 1;266new_inst.Src[0].Register.File = TGSI_FILE_TEMPORARY;267new_inst.Src[0].Register.Index = vsctx->pos_temp;268ctx->emit_instruction(ctx, &new_inst);269270vsctx->end_instruction = TRUE;271} else {272/* Not an END instruction. */273/* Fix writes to outputs. */274for (i = 0; i < inst->Instruction.NumDstRegs; i++) {275struct tgsi_full_dst_register *dst = &inst->Dst[i];276if (dst->Register.File == TGSI_FILE_OUTPUT) {277if (dst->Register.Index == vsctx->pos_output) {278/* Replace writes to OUT[pos_output] with TEMP[pos_temp]. */279dst->Register.File = TGSI_FILE_TEMPORARY;280dst->Register.Index = vsctx->pos_temp;281} else {282/* Not a position, good...283* Since we were changing the indices of output decls,284* we must redirect writes into them too. */285dst->Register.Index = vsctx->out_remap[dst->Register.Index];286}287}288}289290/* Inserting 2 instructions before the END opcode moves all following291* labels by 2. Subroutines are always after the END opcode so292* they're always moved. */293if (inst->Instruction.Opcode == TGSI_OPCODE_CAL) {294inst->Label.Label += 2;295}296/* The labels of the following opcodes are moved only after297* the END opcode. */298if (vsctx->end_instruction &&299(inst->Instruction.Opcode == TGSI_OPCODE_IF ||300inst->Instruction.Opcode == TGSI_OPCODE_ELSE ||301inst->Instruction.Opcode == TGSI_OPCODE_BGNLOOP ||302inst->Instruction.Opcode == TGSI_OPCODE_ENDLOOP)) {303inst->Label.Label += 2;304}305}306307ctx->emit_instruction(ctx, inst);308}309310void r300_draw_init_vertex_shader(struct r300_context *r300,311struct r300_vertex_shader *vs)312{313struct draw_context *draw = r300->draw;314struct pipe_shader_state new_vs;315struct tgsi_shader_info info;316struct vs_transform_context transform;317const uint newLen = tgsi_num_tokens(vs->state.tokens) + 100 /* XXX */;318unsigned i;319320tgsi_scan_shader(vs->state.tokens, &info);321322new_vs.tokens = tgsi_alloc_tokens(newLen);323if (new_vs.tokens == NULL)324return;325326memset(&transform, 0, sizeof(transform));327for (i = 0; i < ARRAY_SIZE(transform.out_remap); i++) {328transform.out_remap[i] = i;329}330transform.last_generic = -1;331transform.base.transform_instruction = transform_inst;332transform.base.transform_declaration = transform_decl;333334for (i = 0; i < info.num_outputs; i++) {335unsigned index = info.output_semantic_index[i];336337switch (info.output_semantic_name[i]) {338case TGSI_SEMANTIC_COLOR:339assert(index < 2);340transform.color_used[index] = TRUE;341break;342343case TGSI_SEMANTIC_BCOLOR:344assert(index < 2);345transform.bcolor_used[index] = TRUE;346break;347}348}349350tgsi_transform_shader(vs->state.tokens,351(struct tgsi_token*)new_vs.tokens,352newLen, &transform.base);353354#if 0355printf("----------------------------------------------\norig shader:\n");356tgsi_dump(vs->state.tokens, 0);357printf("----------------------------------------------\nnew shader:\n");358tgsi_dump(new_vs.tokens, 0);359printf("----------------------------------------------\n");360#endif361362/* Free old tokens. */363FREE((void*)vs->state.tokens);364365vs->draw_vs = draw_create_vertex_shader(draw, &new_vs);366367/* Instead of duplicating and freeing the tokens, copy the pointer directly. */368vs->state.tokens = new_vs.tokens;369370/* Init the VS output table for the rasterizer. */371r300_init_vs_outputs(r300, vs);372373/* Make the last generic be WPOS. */374vs->outputs.wpos = vs->outputs.generic[transform.last_generic + 1];375vs->outputs.generic[transform.last_generic + 1] = ATTR_UNUSED;376}377378379