/**************************************************************************
*
- * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * Copyright 2007-2008 Tungsten Graphics, Inc., Cedar Park, Texas.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* Michal Krol
*/
-
-#include "tgsi_platform.h"
-#include "pipe/tgsi/exec/tgsi_core.h"
+#include "pipe/p_compiler.h"
+#include "pipe/p_shader_tokens.h"
+#include "tgsi/tgsi_parse.h"
+#include "tgsi/tgsi_build.h"
+#include "tgsi/tgsi_util.h"
+#include "tgsi/tgsi_dump.h"
+#include "tgsi/tgsi_sanity.h"
#include "st_mesa_to_tgsi.h"
+#include "shader/prog_instruction.h"
#include "shader/prog_parameter.h"
-
-#define TGSI_DEBUG 0
-
-#define EMIT_IMMEDIATES 0
-
+#include "shader/prog_print.h"
+#include "pipe/p_debug.h"
/*
* Map mesa register file to TGSI register file.
*/
static GLuint
map_register_file(
- enum register_file file )
+ enum register_file file,
+ GLuint index,
+ const GLuint immediateMapping[],
+ GLboolean indirectAccess )
{
switch( file ) {
case PROGRAM_UNDEFINED:
return TGSI_FILE_NULL;
case PROGRAM_TEMPORARY:
return TGSI_FILE_TEMPORARY;
- //case PROGRAM_LOCAL_PARAM:
- //case PROGRAM_ENV_PARAM:
+ /*case PROGRAM_LOCAL_PARAM:*/
+ /*case PROGRAM_ENV_PARAM:*/
+
+ /* Because of the longstanding problem with mesa arb shaders
+ * where constants, immediates and state variables are all
+ * bundled together as PROGRAM_STATE_VAR, we can't tell from the
+ * mesa register file whether this is a CONSTANT or an
+ * IMMEDIATE, hence we need all the other information.
+ */
case PROGRAM_STATE_VAR:
case PROGRAM_NAMED_PARAM:
case PROGRAM_UNIFORM:
- return TGSI_FILE_CONSTANT;
+ if (!indirectAccess && immediateMapping && immediateMapping[index] != ~0)
+ return TGSI_FILE_IMMEDIATE;
+ else
+ return TGSI_FILE_CONSTANT;
case PROGRAM_CONSTANT:
-#if EMIT_IMMEDIATES
+ if (indirectAccess)
+ return TGSI_FILE_CONSTANT;
+ assert(immediateMapping[index] != ~0);
return TGSI_FILE_IMMEDIATE;
-#else
- return TGSI_FILE_CONSTANT;
-#endif
case PROGRAM_INPUT:
return TGSI_FILE_INPUT;
case PROGRAM_OUTPUT:
GLuint index,
const GLuint inputMapping[],
const GLuint outputMapping[],
- const GLuint immediateMapping[])
+ const GLuint immediateMapping[],
+ GLboolean indirectAccess )
{
switch( file ) {
case TGSI_FILE_INPUT:
case TGSI_FILE_OUTPUT:
return outputMapping[index];
-#if EMIT_IMMEDIATES
case TGSI_FILE_IMMEDIATE:
+ if (indirectAccess)
+ return index;
+ assert(immediateMapping[index] != ~0);
return immediateMapping[index];
-#endif
default:
return index;
return writemask;
}
-#if EMIT_IMMEDIATES
static struct tgsi_full_immediate
make_immediate(const float *value, uint size)
{
struct tgsi_full_immediate imm;
- imm.Immediate.Type = TGSI_TOKEN_TYPE_IMMEDIATE;
- imm.Immediate.Size = 1 + size; /* one for the token itself */
+
+ imm = tgsi_default_full_immediate();
+ imm.Immediate.Size += size;
imm.Immediate.DataType = TGSI_IMM_FLOAT32;
- imm.u.ImmediateFloat32 = (struct tgsi_immediate_float32 *) value;
+ imm.u.Pointer = value;
return imm;
}
-#endif
static void
compile_instruction(
const GLuint inputMapping[],
const GLuint outputMapping[],
const GLuint immediateMapping[],
+ GLboolean indirectAccess,
GLuint preamble_size,
- GLuint processor )
+ GLuint processor,
+ GLboolean *insideSubroutine)
{
GLuint i;
struct tgsi_full_dst_register *fulldst;
fullinst->Instruction.NumSrcRegs = _mesa_num_inst_src_regs( inst->Opcode );
fulldst = &fullinst->FullDstRegisters[0];
- fulldst->DstRegister.File = map_register_file( inst->DstReg.File );
+ fulldst->DstRegister.File = map_register_file( inst->DstReg.File, 0, NULL, GL_FALSE );
fulldst->DstRegister.Index = map_register_file_index(
fulldst->DstRegister.File,
inst->DstReg.Index,
inputMapping,
outputMapping,
- NULL
- );
+ NULL,
+ GL_FALSE );
fulldst->DstRegister.WriteMask = convert_writemask( inst->DstReg.WriteMask );
- for( i = 0; i < fullinst->Instruction.NumSrcRegs; i++ ) {
+ for (i = 0; i < fullinst->Instruction.NumSrcRegs; i++) {
GLuint j;
fullsrc = &fullinst->FullSrcRegisters[i];
- fullsrc->SrcRegister.File = map_register_file( inst->SrcReg[i].File );
+ fullsrc->SrcRegister.File = map_register_file(
+ inst->SrcReg[i].File,
+ inst->SrcReg[i].Index,
+ immediateMapping,
+ indirectAccess );
fullsrc->SrcRegister.Index = map_register_file_index(
fullsrc->SrcRegister.File,
inst->SrcReg[i].Index,
inputMapping,
outputMapping,
- immediateMapping);
-
- for( j = 0; j < 4; j++ ) {
- GLuint swz;
-
- swz = GET_SWZ( inst->SrcReg[i].Swizzle, j );
- if( swz > SWIZZLE_W ) {
- tgsi_util_set_src_register_extswizzle(
- &fullsrc->SrcRegisterExtSwz,
- swz,
- j );
+ immediateMapping,
+ indirectAccess );
+
+
+ /* swizzle (ext swizzle also depends on negation) */
+ {
+ GLuint swz[4];
+ GLboolean extended = (inst->SrcReg[i].NegateBase != NEGATE_NONE &&
+ inst->SrcReg[i].NegateBase != NEGATE_XYZW);
+ for( j = 0; j < 4; j++ ) {
+ swz[j] = GET_SWZ( inst->SrcReg[i].Swizzle, j );
+ if (swz[j] > SWIZZLE_W)
+ extended = GL_TRUE;
+ }
+ if (extended) {
+ for (j = 0; j < 4; j++) {
+ tgsi_util_set_src_register_extswizzle(&fullsrc->SrcRegisterExtSwz,
+ swz[j], j);
+ }
}
else {
- tgsi_util_set_src_register_swizzle(
- &fullsrc->SrcRegister,
- swz,
- j );
+ for (j = 0; j < 4; j++) {
+ tgsi_util_set_src_register_swizzle(&fullsrc->SrcRegister,
+ swz[j], j);
+ }
}
}
break;
case OPCODE_BGNSUB:
fullinst->Instruction.Opcode = TGSI_OPCODE_BGNSUB;
+ *insideSubroutine = GL_TRUE;
break;
case OPCODE_BRA:
fullinst->Instruction.Opcode = TGSI_OPCODE_BRA;
break;
case OPCODE_ENDSUB:
fullinst->Instruction.Opcode = TGSI_OPCODE_ENDSUB;
+ *insideSubroutine = GL_FALSE;
break;
case OPCODE_EX2:
fullinst->Instruction.Opcode = TGSI_OPCODE_EX2;
fullinst->Instruction.Opcode = TGSI_OPCODE_INT;
break;
case OPCODE_KIL:
- /* predicated w/ a register */
- fullinst->Instruction.Opcode = TGSI_OPCODE_KILP;
+ /* conditional */
+ fullinst->Instruction.Opcode = TGSI_OPCODE_KIL;
break;
case OPCODE_KIL_NV:
- /* unpredicated */
+ /* predicated */
assert(inst->DstReg.CondMask == COND_TR);
- fullinst->Instruction.Opcode = TGSI_OPCODE_KIL;
+ fullinst->Instruction.Opcode = TGSI_OPCODE_KILP;
break;
case OPCODE_LG2:
fullinst->Instruction.Opcode = TGSI_OPCODE_LG2;
fullinst->Instruction.Opcode = TGSI_OPCODE_RCP;
break;
case OPCODE_RET:
- fullinst->Instruction.Opcode = TGSI_OPCODE_RET;
+ /* If RET is used inside main (not a real subroutine) we may want
+ * to execute END instead of RET. TBD...
+ */
+ if (1 /* *insideSubroutine */) {
+ fullinst->Instruction.Opcode = TGSI_OPCODE_RET;
+ }
+ else {
+ /* inside main() pseudo-function */
+ fullinst->Instruction.Opcode = TGSI_OPCODE_END;
+ }
break;
case OPCODE_RSQ:
fullinst->Instruction.Opcode = TGSI_OPCODE_RSQ;
case OPCODE_TXP:
/* texture lookup with divide by Q component */
/* convert to TEX w/ special flag for division */
- fullinst->Instruction.Opcode = TGSI_OPCODE_TEX;
+ fullinst->Instruction.Opcode = TGSI_OPCODE_TXP;
fullinst->Instruction.NumSrcRegs = 2;
fullinst->InstructionExtTexture.Texture = map_texture_target( inst->TexSrcTarget );
- fullinst->FullSrcRegisters[0].SrcRegisterExtSwz.ExtDivide = TGSI_EXTSWIZZLE_W;
fullinst->FullSrcRegisters[1].SrcRegister.File = TGSI_FILE_SAMPLER;
fullinst->FullSrcRegisters[1].SrcRegister.Index = inst->TexSrcUnit;
break;
fulldst->DstRegister.WriteMask &= TGSI_WRITEMASK_XYZ;
break;
case OPCODE_END:
- fullinst->Instruction.Opcode = TGSI_OPCODE_RET;
+ fullinst->Instruction.Opcode = TGSI_OPCODE_END;
break;
default:
assert( 0 );
static struct tgsi_full_declaration
make_input_decl(
GLuint index,
+ GLboolean interpolate_info,
GLuint interpolate,
GLuint usage_mask,
GLboolean semantic_info,
decl = tgsi_default_full_declaration();
decl.Declaration.File = TGSI_FILE_INPUT;
- decl.Declaration.Declare = TGSI_DECLARE_RANGE;
decl.Declaration.UsageMask = usage_mask;
decl.Declaration.Semantic = semantic_info;
- decl.Declaration.Interpolate = 1;
- decl.u.DeclarationRange.First = index;
- decl.u.DeclarationRange.Last = index;
+ decl.DeclarationRange.First = index;
+ decl.DeclarationRange.Last = index;
if (semantic_info) {
decl.Semantic.SemanticName = semantic_name;
decl.Semantic.SemanticIndex = semantic_index;
}
- decl.Interpolation.Interpolate = interpolate;
+ if (interpolate_info) {
+ decl.Declaration.Interpolate = interpolate;
+ }
return decl;
}
decl = tgsi_default_full_declaration();
decl.Declaration.File = TGSI_FILE_OUTPUT;
- decl.Declaration.Declare = TGSI_DECLARE_RANGE;
decl.Declaration.UsageMask = usage_mask;
decl.Declaration.Semantic = 1;
- decl.u.DeclarationRange.First = index;
- decl.u.DeclarationRange.Last = index;
+ decl.DeclarationRange.First = index;
+ decl.DeclarationRange.Last = index;
decl.Semantic.SemanticName = semantic_name;
decl.Semantic.SemanticIndex = semantic_index;
struct tgsi_full_declaration decl;
decl = tgsi_default_full_declaration();
decl.Declaration.File = TGSI_FILE_TEMPORARY;
- decl.Declaration.Declare = TGSI_DECLARE_RANGE;
- decl.u.DeclarationRange.First = start_index;
- decl.u.DeclarationRange.Last = end_index;
+ decl.DeclarationRange.First = start_index;
+ decl.DeclarationRange.Last = end_index;
+ return decl;
+}
+
+static struct tgsi_full_declaration
+make_addr_decl(
+ GLuint start_index,
+ GLuint end_index )
+{
+ struct tgsi_full_declaration decl;
+
+ decl = tgsi_default_full_declaration();
+ decl.Declaration.File = TGSI_FILE_ADDRESS;
+ decl.DeclarationRange.First = start_index;
+ decl.DeclarationRange.Last = end_index;
+ return decl;
+}
+
+static struct tgsi_full_declaration
+make_sampler_decl(GLuint index)
+{
+ struct tgsi_full_declaration decl;
+ decl = tgsi_default_full_declaration();
+ decl.Declaration.File = TGSI_FILE_SAMPLER;
+ decl.DeclarationRange.First = index;
+ decl.DeclarationRange.Last = index;
+ return decl;
+}
+
+/** Reference into a constant buffer */
+static struct tgsi_full_declaration
+make_constant_decl(GLuint first, GLuint last)
+{
+ struct tgsi_full_declaration decl;
+ decl = tgsi_default_full_declaration();
+ decl.Declaration.File = TGSI_FILE_CONSTANT;
+ decl.DeclarationRange.First = first;
+ decl.DeclarationRange.Last = last;
return decl;
}
+
/**
* Find the temporaries which are used in the given program.
*/
* \param tokens array to store translated tokens in
* \param maxTokens size of the tokens array
*
+ * \return number of tokens placed in 'tokens' buffer, or zero if error
*/
-GLboolean
-tgsi_translate_mesa_program(
+GLuint
+st_translate_mesa_program(
uint procType,
const struct gl_program *program,
GLuint numInputs,
struct tgsi_full_instruction fullinst;
GLuint preamble_size = 0;
GLuint immediates[1000];
-#if EMIT_IMMEDIATES
GLuint numImmediates = 0;
-#endif
+ GLboolean insideSubroutine = GL_FALSE;
+ GLboolean indirectAccess = GL_FALSE;
assert(procType == TGSI_PROCESSOR_FRAGMENT ||
procType == TGSI_PROCESSOR_VERTEX);
if (procType == TGSI_PROCESSOR_FRAGMENT) {
for (i = 0; i < numInputs; i++) {
struct tgsi_full_declaration fulldecl;
- switch (inputSemanticName[i]) {
- case TGSI_SEMANTIC_POSITION:
- /* Fragment XY pos */
- fulldecl = make_input_decl(i,
- TGSI_INTERPOLATE_CONSTANT,
- TGSI_WRITEMASK_XY,
- GL_TRUE, TGSI_SEMANTIC_POSITION, 0 );
- ti += tgsi_build_full_declaration(
- &fulldecl,
- &tokens[ti],
- header,
- maxTokens - ti );
- /* Fragment ZW pos */
- fulldecl = make_input_decl(i,
- TGSI_INTERPOLATE_LINEAR,
- TGSI_WRITEMASK_ZW,
- GL_TRUE, TGSI_SEMANTIC_POSITION, 0 );
- ti += tgsi_build_full_declaration(&fulldecl,
- &tokens[ti],
- header,
- maxTokens - ti );
- break;
- default:
- fulldecl = make_input_decl(i,
- interpMode[i],
- TGSI_WRITEMASK_XYZW,
- GL_TRUE, inputSemanticName[i],
- inputSemanticIndex[i]);
- ti += tgsi_build_full_declaration(&fulldecl,
- &tokens[ti],
- header,
- maxTokens - ti );
- break;
- }
+ fulldecl = make_input_decl(i,
+ GL_TRUE, interpMode[i],
+ TGSI_WRITEMASK_XYZW,
+ GL_TRUE, inputSemanticName[i],
+ inputSemanticIndex[i]);
+ ti += tgsi_build_full_declaration(&fulldecl,
+ &tokens[ti],
+ header,
+ maxTokens - ti );
}
}
else {
/* vertex prog */
+ /* XXX: this could probaby be merged with the clause above.
+ * the only difference is the semantic tags.
+ */
for (i = 0; i < numInputs; i++) {
struct tgsi_full_declaration fulldecl;
fulldecl = make_input_decl(i,
- TGSI_INTERPOLATE_ATTRIB,
+ GL_FALSE, 0,
TGSI_WRITEMASK_XYZW,
- GL_FALSE, inputSemanticName[i],
- inputSemanticIndex[i]);
+ GL_FALSE, 0, 0);
ti += tgsi_build_full_declaration(&fulldecl,
&tokens[ti],
header,
switch (outputSemanticName[i]) {
case TGSI_SEMANTIC_POSITION:
fulldecl = make_output_decl(i,
- TGSI_SEMANTIC_POSITION, 0, /* Z / Depth */
+ TGSI_SEMANTIC_POSITION, /* Z / Depth */
+ outputSemanticIndex[i],
TGSI_WRITEMASK_Z );
break;
case TGSI_SEMANTIC_COLOR:
fulldecl = make_output_decl(i,
- TGSI_SEMANTIC_COLOR, 0,
+ TGSI_SEMANTIC_COLOR,
+ outputSemanticIndex[i],
TGSI_WRITEMASK_XYZW );
break;
default:
- abort();
+ assert(0);
+ return 0;
}
ti += tgsi_build_full_declaration(&fulldecl,
&tokens[ti],
{
GLboolean tempsUsed[MAX_PROGRAM_TEMPS + 1];
GLboolean inside_range = GL_FALSE;
- GLuint start_range;
+ GLuint start_range = 0;
find_temporaries(program, tempsUsed);
tempsUsed[MAX_PROGRAM_TEMPS] = GL_FALSE;
inside_range = GL_FALSE;
fulldecl = make_temp_decl( start_range, i - 1 );
ti += tgsi_build_full_declaration(
- &fulldecl,
- &tokens[ti],
- header,
- maxTokens - ti );
+ &fulldecl,
+ &tokens[ti],
+ header,
+ maxTokens - ti );
}
}
}
+ /* Declare address register.
+ */
+ if (program->NumAddressRegs > 0) {
+ struct tgsi_full_declaration fulldecl;
+
+ assert( program->NumAddressRegs == 1 );
+
+ fulldecl = make_addr_decl( 0, 0 );
+ ti += tgsi_build_full_declaration(
+ &fulldecl,
+ &tokens[ti],
+ header,
+ maxTokens - ti );
+
+ indirectAccess = GL_TRUE;
+ }
+
/* immediates/literals */
-#if EMIT_IMMEDIATES
- for (i = 0; i < program->Parameters->NumParameters; i++) {
- if (program->Parameters->Parameters[i].Type == PROGRAM_CONSTANT) {
- struct tgsi_full_immediate fullimm
- = make_immediate(program->Parameters->ParameterValues[i],
- program->Parameters->Parameters[i].Size);
- ti += tgsi_build_full_immediate(&fullimm,
- &tokens[ti],
- header,
- maxTokens - ti);
- immediates[i] = numImmediates;
- numImmediates++;
+ memset(immediates, ~0, sizeof(immediates));
+
+ /* Emit immediates only when there is no address register in use.
+ * FIXME: Be smarter and recognize param arrays -- indirect addressing is
+ * only valid within the referenced array.
+ */
+ if (program->Parameters && !indirectAccess) {
+ for (i = 0; i < program->Parameters->NumParameters; i++) {
+ if (program->Parameters->Parameters[i].Type == PROGRAM_CONSTANT) {
+ struct tgsi_full_immediate fullimm;
+
+ fullimm = make_immediate( program->Parameters->ParameterValues[i], 4 );
+ ti += tgsi_build_full_immediate(
+ &fullimm,
+ &tokens[ti],
+ header,
+ maxTokens - ti );
+ immediates[i] = numImmediates;
+ numImmediates++;
+ }
}
}
-#endif
- for( i = 0; i < program->NumInstructions; i++ ) {
+ /* constant buffer refs */
+ if (program->Parameters) {
+ GLint start = -1, end = -1;
+
+ for (i = 0; i < program->Parameters->NumParameters; i++) {
+ GLboolean emit = (i == program->Parameters->NumParameters - 1);
+ GLboolean matches;
+
+ switch (program->Parameters->Parameters[i].Type) {
+ case PROGRAM_ENV_PARAM:
+ case PROGRAM_STATE_VAR:
+ case PROGRAM_NAMED_PARAM:
+ case PROGRAM_UNIFORM:
+ matches = GL_TRUE;
+ break;
+ case PROGRAM_CONSTANT:
+ matches = indirectAccess;
+ break;
+ default:
+ matches = GL_FALSE;
+ }
+
+ if (matches) {
+ if (start == -1) {
+ /* begin a sequence */
+ start = i;
+ end = i;
+ }
+ else {
+ /* continue sequence */
+ end = i;
+ }
+ }
+ else {
+ if (start != -1) {
+ /* end of sequence */
+ emit = GL_TRUE;
+ }
+ }
+
+ if (emit && start >= 0) {
+ struct tgsi_full_declaration fulldecl;
+
+ fulldecl = make_constant_decl( start, end );
+ ti += tgsi_build_full_declaration(
+ &fulldecl,
+ &tokens[ti],
+ header,
+ maxTokens - ti );
+ start = end = -1;
+ }
+ }
+ }
+
+ /* texture samplers */
+ for (i = 0; i < 8; i++) {
+ if (program->SamplersUsed & (1 << i)) {
+ struct tgsi_full_declaration fulldecl;
+
+ fulldecl = make_sampler_decl( i );
+ ti += tgsi_build_full_declaration(
+ &fulldecl,
+ &tokens[ti],
+ header,
+ maxTokens - ti );
+ }
+ }
+
+ for (i = 0; i < program->NumInstructions; i++) {
compile_instruction(
- &program->Instructions[i],
- &fullinst,
- inputMapping,
- outputMapping,
- immediates,
- preamble_size,
- procType );
+ &program->Instructions[i],
+ &fullinst,
+ inputMapping,
+ outputMapping,
+ immediates,
+ indirectAccess,
+ preamble_size,
+ procType,
+ &insideSubroutine );
ti += tgsi_build_full_instruction(
&fullinst,
maxTokens - ti );
}
- return GL_TRUE;
-}
+#if DEBUG
+ if(!tgsi_sanity_check(tokens)) {
+ debug_printf("Due to sanity check failure(s) above the following shader program is invalid:\n");
+ debug_printf("\nOriginal program:\n%s", program->String);
+ debug_printf("\nMesa program:\n");
+ _mesa_print_program(program);
+ debug_printf("\nTGSI program:\n");
+ tgsi_dump(tokens, 0);
+ assert(0);
+ }
+#endif
+ return ti;
+}