diff options
Diffstat (limited to 'src/gallium/auxiliary/tgsi')
22 files changed, 2362 insertions, 270 deletions
diff --git a/src/gallium/auxiliary/tgsi/Makefile b/src/gallium/auxiliary/tgsi/Makefile index b4900e8dba..5f0a580b09 100644 --- a/src/gallium/auxiliary/tgsi/Makefile +++ b/src/gallium/auxiliary/tgsi/Makefile @@ -16,6 +16,7 @@ C_SOURCES = \ tgsi_sse2.c \ tgsi_text.c \ tgsi_transform.c \ + tgsi_ureg.c \ tgsi_util.c include ../../Makefile.template diff --git a/src/gallium/auxiliary/tgsi/SConscript b/src/gallium/auxiliary/tgsi/SConscript index 8200cce42f..b6bc2924f0 100644 --- a/src/gallium/auxiliary/tgsi/SConscript +++ b/src/gallium/auxiliary/tgsi/SConscript @@ -16,6 +16,7 @@ tgsi = env.ConvenienceLibrary( 'tgsi_sse2.c', 'tgsi_text.c', 'tgsi_transform.c', + 'tgsi_ureg.c', 'tgsi_util.c', ]) diff --git a/src/gallium/auxiliary/tgsi/tgsi-instruction-set.txt b/src/gallium/auxiliary/tgsi/tgsi-instruction-set.txt index a3f4947c73..eb492076b7 100644 --- a/src/gallium/auxiliary/tgsi/tgsi-instruction-set.txt +++ b/src/gallium/auxiliary/tgsi/tgsi-instruction-set.txt @@ -187,11 +187,7 @@ TGSI Instruction Specification 1.2.6 CND0 - Condition Zero - dst.x = (src2.x >= 0.0) ? src0.x : src1.x - dst.y = (src2.y >= 0.0) ? src0.y : src1.y - dst.z = (src2.z >= 0.0) ? src0.z : src1.z - dst.w = (src2.w >= 0.0) ? src0.w : src1.w - + Removed. Use (CMP src2, src1, src0) instead. 1.2.7 DOT2ADD - 2-component Dot Product And Add @@ -665,9 +661,18 @@ TGSI Instruction Specification TBD -1.9.8 LOOP - Loop +1.9.8 BGNFOR - Begin a For-Loop - TBD + dst.x = floor(src.x) + dst.y = floor(src.y) + dst.z = floor(src.z) + + if (dst.y <= 0) + pc = [matching ENDFOR] + 1 + endif + + Note: The destination must be a loop register. + The source must be a constant register. 1.9.9 REP - Repeat @@ -685,9 +690,16 @@ TGSI Instruction Specification TBD -1.9.12 ENDLOOP - End Loop +1.9.12 ENDFOR - End a For-Loop - TBD + dst.x = dst.x + dst.z + dst.y = dst.y - 1.0 + + if (dst.y > 0) + pc = [matching BGNFOR instruction] + 1 + endif + + Note: The destination must be a loop register. 1.9.13 ENDREP - End Repeat @@ -840,7 +852,7 @@ TGSI Instruction Specification ---------- -1.13.1 BGNLOOP2 - Begin Loop +1.13.1 BGNLOOP - Begin a Loop TBD @@ -850,7 +862,7 @@ TGSI Instruction Specification TBD -1.13.3 ENDLOOP2 - End Loop +1.13.3 ENDLOOP - End a Loop TBD @@ -1015,12 +1027,12 @@ TGSI Instruction Specification 1.18.1 EXPP - Approximate Exponential Base 2 - Alias for EXP. + Use EXP. See also 1.19.3. 1.18.2 LOGP - Logarithm Base 2 - Alias for LG2. + Use LOG. See also 1.19.4. 1.19 vs_2_0 @@ -1037,6 +1049,16 @@ TGSI Instruction Specification Alias for ARR. +1.19.3 EXPP - Approximate Exponential Base 2 + + Use EX2. + + +1.19.4 LOGP - Logarithm Base 2 + + Use LG2. + + 2 Explanation of symbols used ============================== diff --git a/src/gallium/auxiliary/tgsi/tgsi_build.c b/src/gallium/auxiliary/tgsi/tgsi_build.c index 010d501c60..e0cfc54420 100644 --- a/src/gallium/auxiliary/tgsi/tgsi_build.c +++ b/src/gallium/auxiliary/tgsi/tgsi_build.c @@ -482,6 +482,8 @@ tgsi_default_full_instruction( void ) full_instruction.FullSrcRegisters[i] = tgsi_default_full_src_register(); } + full_instruction.Flags = 0x0; + return full_instruction; } diff --git a/src/gallium/auxiliary/tgsi/tgsi_dump.c b/src/gallium/auxiliary/tgsi/tgsi_dump.c index e1cd8479cb..111d95b666 100644 --- a/src/gallium/auxiliary/tgsi/tgsi_dump.c +++ b/src/gallium/auxiliary/tgsi/tgsi_dump.c @@ -33,12 +33,20 @@ #include "tgsi_info.h" #include "tgsi_iterate.h" + +/** Number of spaces to indent for IF/LOOP/etc */ +static const int indent_spaces = 3; + + struct dump_ctx { struct tgsi_iterate_context iter; uint instno; + int indent; + uint indentation; + void (*printf)(struct dump_ctx *ctx, const char *format, ...); }; @@ -82,7 +90,7 @@ static const char *processor_type_names[] = "GEOM" }; -static const char *file_names[] = +static const char *file_names[TGSI_FILE_COUNT] = { "NULL", "CONST", @@ -91,7 +99,8 @@ static const char *file_names[] = "TEMP", "SAMP", "ADDR", - "IMM" + "IMM", + "LOOP" }; static const char *interpolate_names[] = @@ -334,13 +343,19 @@ iter_instruction( { struct dump_ctx *ctx = (struct dump_ctx *) iter; uint instno = ctx->instno++; - + const struct tgsi_opcode_info *info = tgsi_get_opcode_info( inst->Instruction.Opcode ); uint i; boolean first_reg = TRUE; INSTID( instno ); TXT( ": " ); - TXT( tgsi_get_opcode_info( inst->Instruction.Opcode )->mnemonic ); + + ctx->indent -= info->pre_dedent; + for(i = 0; (int)i < ctx->indent; ++i) + TXT( " " ); + ctx->indent += info->post_indent; + + TXT( info->mnemonic ); switch (inst->Instruction.Saturate) { case TGSI_SAT_NONE: @@ -472,14 +487,22 @@ iter_instruction( switch (inst->Instruction.Opcode) { case TGSI_OPCODE_IF: case TGSI_OPCODE_ELSE: - case TGSI_OPCODE_BGNLOOP2: - case TGSI_OPCODE_ENDLOOP2: + case TGSI_OPCODE_BGNLOOP: + case TGSI_OPCODE_ENDLOOP: case TGSI_OPCODE_CAL: TXT( " :" ); UID( inst->InstructionExtLabel.Label ); break; } + /* update indentation */ + if (inst->Instruction.Opcode == TGSI_OPCODE_IF || + inst->Instruction.Opcode == TGSI_OPCODE_ELSE || + inst->Instruction.Opcode == TGSI_OPCODE_BGNFOR || + inst->Instruction.Opcode == TGSI_OPCODE_BGNLOOP) { + ctx->indentation += indent_spaces; + } + EOL(); return TRUE; @@ -493,7 +516,9 @@ tgsi_dump_instruction( struct dump_ctx ctx; ctx.instno = instno; + ctx.indent = 0; ctx.printf = dump_ctx_printf; + ctx.indentation = 0; iter_instruction( &ctx.iter, (struct tgsi_full_instruction *)inst ); } @@ -525,7 +550,9 @@ tgsi_dump( ctx.iter.epilog = NULL; ctx.instno = 0; + ctx.indent = 0; ctx.printf = dump_ctx_printf; + ctx.indentation = 0; tgsi_iterate_shader( tokens, &ctx.iter ); } @@ -577,7 +604,9 @@ tgsi_dump_str( ctx.base.iter.epilog = NULL; ctx.base.instno = 0; + ctx.base.indent = 0; ctx.base.printf = &str_dump_ctx_printf; + ctx.base.indentation = 0; ctx.str = str; ctx.str[0] = 0; diff --git a/src/gallium/auxiliary/tgsi/tgsi_dump_c.c b/src/gallium/auxiliary/tgsi/tgsi_dump_c.c index c944760ca6..4a9c02b141 100644 --- a/src/gallium/auxiliary/tgsi/tgsi_dump_c.c +++ b/src/gallium/auxiliary/tgsi/tgsi_dump_c.c @@ -69,7 +69,7 @@ static const char *TGSI_TOKEN_TYPES[] = "TOKEN_TYPE_INSTRUCTION" }; -static const char *TGSI_FILES[] = +static const char *TGSI_FILES[TGSI_FILE_COUNT] = { "FILE_NULL", "FILE_CONSTANT", @@ -78,7 +78,8 @@ static const char *TGSI_FILES[] = "FILE_TEMPORARY", "FILE_SAMPLER", "FILE_ADDRESS", - "FILE_IMMEDIATE" + "FILE_IMMEDIATE", + "FILE_LOOP" }; static const char *TGSI_INTERPOLATES[] = diff --git a/src/gallium/auxiliary/tgsi/tgsi_exec.c b/src/gallium/auxiliary/tgsi/tgsi_exec.c index b193fd7a0a..c79c56debd 100644 --- a/src/gallium/auxiliary/tgsi/tgsi_exec.c +++ b/src/gallium/auxiliary/tgsi/tgsi_exec.c @@ -62,6 +62,9 @@ #define FAST_MATH 1 +/** for tgsi_full_instruction::Flags */ +#define SOA_DEPENDENCY_FLAG 0x1 + #define TILE_TOP_LEFT 0 #define TILE_TOP_RIGHT 1 #define TILE_BOTTOM_LEFT 2 @@ -182,7 +185,7 @@ print_temp(const struct tgsi_exec_machine *mach, uint index) * MOV t3, t2; * The second instruction will have the wrong value for t0 if executed as-is. */ -static boolean +boolean tgsi_check_soa_dependencies(const struct tgsi_full_instruction *inst) { uint i, chan; @@ -328,19 +331,24 @@ tgsi_exec_machine_bind_shader( * sizeof(struct tgsi_full_instruction)); maxInstructions += 10; } - memcpy(instructions + numInstructions, - &parse.FullToken.FullInstruction, - sizeof(instructions[0])); -#if 0 if (tgsi_check_soa_dependencies(&parse.FullToken.FullInstruction)) { - debug_printf("SOA dependency in instruction:\n"); - tgsi_dump_instruction(&parse.FullToken.FullInstruction, - numInstructions); + uint opcode = parse.FullToken.FullInstruction.Instruction.Opcode; + parse.FullToken.FullInstruction.Flags = SOA_DEPENDENCY_FLAG; + /* XXX we only handle SOA dependencies properly for MOV/SWZ + * at this time! + */ + if (opcode != TGSI_OPCODE_MOV && opcode != TGSI_OPCODE_SWZ) { + debug_printf("Warning: SOA dependency in instruction" + " is not handled:\n"); + tgsi_dump_instruction(&parse.FullToken.FullInstruction, + numInstructions); + } } -#else - (void) tgsi_check_soa_dependencies; -#endif + + memcpy(instructions + numInstructions, + &parse.FullToken.FullInstruction, + sizeof(instructions[0])); numInstructions++; break; @@ -375,15 +383,9 @@ tgsi_exec_machine_create( void ) if (!mach) goto fail; - mach->Addrs = &mach->Temps[TGSI_EXEC_TEMP_ADDR]; + memset(mach, 0, sizeof(*mach)); - mach->Samplers = NULL; - mach->Consts = NULL; - mach->Tokens = NULL; - mach->Primitives = NULL; - mach->InterpCoefs = NULL; - mach->Instructions = NULL; - mach->Declarations = NULL; + mach->Addrs = &mach->Temps[TGSI_EXEC_TEMP_ADDR]; /* Setup constants. */ for( i = 0; i < 4; i++ ) { @@ -2030,9 +2032,23 @@ exec_instruction( case TGSI_OPCODE_MOV: case TGSI_OPCODE_SWZ: - FOR_EACH_ENABLED_CHANNEL( *inst, chan_index ) { - FETCH( &r[0], 0, chan_index ); - STORE( &r[0], 0, chan_index ); + if (inst->Flags & SOA_DEPENDENCY_FLAG) { + /* Do all fetches into temp regs, then do all stores to avoid + * intermediate/accidental clobbering. This could be done all the + * time for MOV but for other instructions we'll need more temps... + */ + FOR_EACH_ENABLED_CHANNEL( *inst, chan_index ) { + FETCH( &r[chan_index], 0, chan_index ); + } + FOR_EACH_ENABLED_CHANNEL( *inst, chan_index ) { + STORE( &r[chan_index], 0, chan_index ); + } + } + else { + FOR_EACH_ENABLED_CHANNEL( *inst, chan_index ) { + FETCH( &r[0], 0, chan_index ); + STORE( &r[0], 0, chan_index ); + } } break; @@ -2313,16 +2329,6 @@ exec_instruction( } break; - case TGSI_OPCODE_CND0: - FOR_EACH_ENABLED_CHANNEL(*inst, chan_index) { - FETCH(&r[0], 0, chan_index); - FETCH(&r[1], 1, chan_index); - FETCH(&r[2], 2, chan_index); - micro_le(&r[0], &mach->Temps[TEMP_0_I].xyzw[TEMP_0_C], &r[2], &r[0], &r[1]); - STORE(&r[0], 0, chan_index); - } - break; - case TGSI_OPCODE_DP2A: FETCH( &r[0], 0, CHAN_X ); FETCH( &r[1], 1, CHAN_X ); @@ -2341,16 +2347,6 @@ exec_instruction( } break; - case TGSI_OPCODE_INDEX: - /* XXX: considered for removal */ - assert (0); - break; - - case TGSI_OPCODE_NEGATE: - /* XXX: considered for removal */ - assert (0); - break; - case TGSI_OPCODE_FRC: FOR_EACH_ENABLED_CHANNEL( *inst, chan_index ) { FETCH( &r[0], 0, chan_index ); @@ -2454,11 +2450,6 @@ exec_instruction( } break; - case TGSI_OPCODE_MULTIPLYMATRIX: - /* XXX: considered for removal */ - assert (0); - break; - case TGSI_OPCODE_ABS: FOR_EACH_ENABLED_CHANNEL( *inst, chan_index ) { FETCH(&r[0], 0, chan_index); @@ -2765,19 +2756,32 @@ exec_instruction( if (mach->ExecMask) { /* do the call */ - /* push the Cond, Loop, Cont stacks */ + /* First, record the depths of the execution stacks. + * This is important for deeply nested/looped return statements. + * We have to unwind the stacks by the correct amount. For a + * real code generator, we could determine the number of entries + * to pop off each stack with simple static analysis and avoid + * implementing this data structure at run time. + */ + mach->CallStack[mach->CallStackTop].CondStackTop = mach->CondStackTop; + mach->CallStack[mach->CallStackTop].LoopStackTop = mach->LoopStackTop; + mach->CallStack[mach->CallStackTop].ContStackTop = mach->ContStackTop; + /* note that PC was already incremented above */ + mach->CallStack[mach->CallStackTop].ReturnAddr = *pc; + + mach->CallStackTop++; + + /* Second, push the Cond, Loop, Cont, Func stacks */ assert(mach->CondStackTop < TGSI_EXEC_MAX_COND_NESTING); mach->CondStack[mach->CondStackTop++] = mach->CondMask; assert(mach->LoopStackTop < TGSI_EXEC_MAX_LOOP_NESTING); mach->LoopStack[mach->LoopStackTop++] = mach->LoopMask; assert(mach->ContStackTop < TGSI_EXEC_MAX_LOOP_NESTING); mach->ContStack[mach->ContStackTop++] = mach->ContMask; - assert(mach->FuncStackTop < TGSI_EXEC_MAX_CALL_NESTING); mach->FuncStack[mach->FuncStackTop++] = mach->FuncMask; - /* note that PC was already incremented above */ - mach->CallStack[mach->CallStackTop++] = *pc; + /* Finally, jump to the subroutine */ *pc = inst->InstructionExtLabel.Label; } break; @@ -2794,18 +2798,24 @@ exec_instruction( *pc = -1; return; } - *pc = mach->CallStack[--mach->CallStackTop]; - /* pop the Cond, Loop, Cont stacks */ - assert(mach->CondStackTop > 0); - mach->CondMask = mach->CondStack[--mach->CondStackTop]; - assert(mach->LoopStackTop > 0); - mach->LoopMask = mach->LoopStack[--mach->LoopStackTop]; - assert(mach->ContStackTop > 0); - mach->ContMask = mach->ContStack[--mach->ContStackTop]; + assert(mach->CallStackTop > 0); + mach->CallStackTop--; + + mach->CondStackTop = mach->CallStack[mach->CallStackTop].CondStackTop; + mach->CondMask = mach->CondStack[mach->CondStackTop]; + + mach->LoopStackTop = mach->CallStack[mach->CallStackTop].LoopStackTop; + mach->LoopMask = mach->LoopStack[mach->LoopStackTop]; + + mach->ContStackTop = mach->CallStack[mach->CallStackTop].ContStackTop; + mach->ContMask = mach->ContStack[mach->ContStackTop]; + assert(mach->FuncStackTop > 0); mach->FuncMask = mach->FuncStack[--mach->FuncStackTop]; + *pc = mach->CallStack[mach->CallStackTop].ReturnAddr; + UPDATE_EXEC_MASK(mach); } break; @@ -3102,26 +3112,81 @@ exec_instruction( mach->Primitives[mach->Temps[TEMP_PRIMITIVE_I].xyzw[TEMP_PRIMITIVE_C].u[0]] = 0; break; - case TGSI_OPCODE_LOOP: + case TGSI_OPCODE_BGNFOR: + assert(mach->LoopCounterStackTop < TGSI_EXEC_MAX_LOOP_NESTING); + for (chan_index = 0; chan_index < 3; chan_index++) { + FETCH( &mach->LoopCounterStack[mach->LoopCounterStackTop].xyzw[chan_index], 0, chan_index ); + } + STORE( &mach->LoopCounterStack[mach->LoopCounterStackTop].xyzw[CHAN_Y], 0, CHAN_X ); + ++mach->LoopCounterStackTop; /* fall-through (for now) */ - case TGSI_OPCODE_BGNLOOP2: + case TGSI_OPCODE_BGNLOOP: /* push LoopMask and ContMasks */ assert(mach->LoopStackTop < TGSI_EXEC_MAX_LOOP_NESTING); mach->LoopStack[mach->LoopStackTop++] = mach->LoopMask; assert(mach->ContStackTop < TGSI_EXEC_MAX_LOOP_NESTING); mach->ContStack[mach->ContStackTop++] = mach->ContMask; + assert(mach->LoopLabelStackTop < TGSI_EXEC_MAX_LOOP_NESTING); + mach->LoopLabelStack[mach->LoopLabelStackTop++] = *pc - 1; + break; + + case TGSI_OPCODE_ENDFOR: + assert(mach->LoopCounterStackTop > 0); + micro_sub( &mach->LoopCounterStack[mach->LoopCounterStackTop - 1].xyzw[CHAN_X], + &mach->LoopCounterStack[mach->LoopCounterStackTop - 1].xyzw[CHAN_X], + &mach->Temps[TEMP_1_I].xyzw[TEMP_1_C] ); + /* update LoopMask */ + if( mach->LoopCounterStack[mach->LoopCounterStackTop - 1].xyzw[CHAN_X].f[0] <= 0) { + mach->LoopMask &= ~0x1; + } + if( mach->LoopCounterStack[mach->LoopCounterStackTop - 1].xyzw[CHAN_X].f[1] <= 0 ) { + mach->LoopMask &= ~0x2; + } + if( mach->LoopCounterStack[mach->LoopCounterStackTop - 1].xyzw[CHAN_X].f[2] <= 0 ) { + mach->LoopMask &= ~0x4; + } + if( mach->LoopCounterStack[mach->LoopCounterStackTop - 1].xyzw[CHAN_X].f[3] <= 0 ) { + mach->LoopMask &= ~0x8; + } + micro_add( &mach->LoopCounterStack[mach->LoopCounterStackTop - 1].xyzw[CHAN_Y], + &mach->LoopCounterStack[mach->LoopCounterStackTop - 1].xyzw[CHAN_Y], + &mach->LoopCounterStack[mach->LoopCounterStackTop - 1].xyzw[CHAN_Z]); + assert(mach->LoopLabelStackTop > 0); + inst = mach->Instructions + mach->LoopLabelStack[mach->LoopLabelStackTop - 1]; + STORE( &mach->LoopCounterStack[mach->LoopCounterStackTop].xyzw[CHAN_Y], 0, CHAN_X ); + /* Restore ContMask, but don't pop */ + assert(mach->ContStackTop > 0); + mach->ContMask = mach->ContStack[mach->ContStackTop - 1]; + UPDATE_EXEC_MASK(mach); + if (mach->ExecMask) { + /* repeat loop: jump to instruction just past BGNLOOP */ + assert(mach->LoopLabelStackTop > 0); + *pc = mach->LoopLabelStack[mach->LoopLabelStackTop - 1] + 1; + } + else { + /* exit loop: pop LoopMask */ + assert(mach->LoopStackTop > 0); + mach->LoopMask = mach->LoopStack[--mach->LoopStackTop]; + /* pop ContMask */ + assert(mach->ContStackTop > 0); + mach->ContMask = mach->ContStack[--mach->ContStackTop]; + assert(mach->LoopLabelStackTop > 0); + --mach->LoopLabelStackTop; + assert(mach->LoopCounterStackTop > 0); + --mach->LoopCounterStackTop; + } + UPDATE_EXEC_MASK(mach); break; - + case TGSI_OPCODE_ENDLOOP: - /* fall-through (for now at least) */ - case TGSI_OPCODE_ENDLOOP2: /* Restore ContMask, but don't pop */ assert(mach->ContStackTop > 0); mach->ContMask = mach->ContStack[mach->ContStackTop - 1]; UPDATE_EXEC_MASK(mach); if (mach->ExecMask) { /* repeat loop: jump to instruction just past BGNLOOP */ - *pc = inst->InstructionExtLabel.Label + 1; + assert(mach->LoopLabelStackTop > 0); + *pc = mach->LoopLabelStack[mach->LoopLabelStackTop - 1] + 1; } else { /* exit loop: pop LoopMask */ @@ -3130,6 +3195,8 @@ exec_instruction( /* pop ContMask */ assert(mach->ContStackTop > 0); mach->ContMask = mach->ContStack[--mach->ContStackTop]; + assert(mach->LoopLabelStackTop > 0); + --mach->LoopLabelStackTop; } UPDATE_EXEC_MASK(mach); break; @@ -3197,7 +3264,6 @@ tgsi_exec_machine_run( struct tgsi_exec_machine *mach ) mach->FuncMask = 0xf; mach->ExecMask = 0xf; - mach->CondStackTop = 0; /* temporarily subvert this assertion */ assert(mach->CondStackTop == 0); assert(mach->LoopStackTop == 0); assert(mach->ContStackTop == 0); diff --git a/src/gallium/auxiliary/tgsi/tgsi_exec.h b/src/gallium/auxiliary/tgsi/tgsi_exec.h index 8a9100f4c3..c72f76809d 100644 --- a/src/gallium/auxiliary/tgsi/tgsi_exec.h +++ b/src/gallium/auxiliary/tgsi/tgsi_exec.h @@ -186,6 +186,17 @@ struct tgsi_exec_labels */ #define TGSI_EXEC_MAX_CONST_BUFFER 4096 + +/** function call/activation record */ +struct tgsi_call_record +{ + uint CondStackTop; + uint LoopStackTop; + uint ContStackTop; + uint ReturnAddr; +}; + + /** * Run-time virtual machine state for executing TGSI shader. */ @@ -232,6 +243,14 @@ struct tgsi_exec_machine uint LoopStack[TGSI_EXEC_MAX_LOOP_NESTING]; int LoopStackTop; + /** Loop label stack */ + uint LoopLabelStack[TGSI_EXEC_MAX_LOOP_NESTING]; + int LoopLabelStackTop; + + /** Loop counter stack (x = count, y = current, z = step) */ + struct tgsi_exec_vector LoopCounterStack[TGSI_EXEC_MAX_LOOP_NESTING]; + int LoopCounterStackTop; + /** Loop continue mask stack (see comments in tgsi_exec.c) */ uint ContStack[TGSI_EXEC_MAX_LOOP_NESTING]; int ContStackTop; @@ -241,7 +260,7 @@ struct tgsi_exec_machine int FuncStackTop; /** Function call stack for saving/restoring the program counter */ - uint CallStack[TGSI_EXEC_MAX_CALL_NESTING]; + struct tgsi_call_record CallStack[TGSI_EXEC_MAX_CALL_NESTING]; int CallStackTop; struct tgsi_full_instruction *Instructions; @@ -272,6 +291,14 @@ tgsi_exec_machine_run( struct tgsi_exec_machine *mach ); +void +tgsi_exec_machine_free_data(struct tgsi_exec_machine *mach); + + +boolean +tgsi_check_soa_dependencies(const struct tgsi_full_instruction *inst); + + static INLINE void tgsi_set_kill_mask(struct tgsi_exec_machine *mach, unsigned mask) { diff --git a/src/gallium/auxiliary/tgsi/tgsi_info.c b/src/gallium/auxiliary/tgsi/tgsi_info.c index 29b8115560..17af4cb7ad 100644 --- a/src/gallium/auxiliary/tgsi/tgsi_info.c +++ b/src/gallium/auxiliary/tgsi/tgsi_info.c @@ -31,125 +31,125 @@ static const struct tgsi_opcode_info opcode_info[TGSI_OPCODE_LAST] = { - { 1, 1, 0, 0, "ARL", TGSI_OPCODE_ARL }, - { 1, 1, 0, 0, "MOV", TGSI_OPCODE_MOV }, - { 1, 1, 0, 0, "LIT", TGSI_OPCODE_LIT }, - { 1, 1, 0, 0, "RCP", TGSI_OPCODE_RCP }, - { 1, 1, 0, 0, "RSQ", TGSI_OPCODE_RSQ }, - { 1, 1, 0, 0, "EXP", TGSI_OPCODE_EXP }, - { 1, 1, 0, 0, "LOG", TGSI_OPCODE_LOG }, - { 1, 2, 0, 0, "MUL", TGSI_OPCODE_MUL }, - { 1, 2, 0, 0, "ADD", TGSI_OPCODE_ADD }, - { 1, 2, 0, 0, "DP3", TGSI_OPCODE_DP3 }, - { 1, 2, 0, 0, "DP4", TGSI_OPCODE_DP4 }, - { 1, 2, 0, 0, "DST", TGSI_OPCODE_DST }, - { 1, 2, 0, 0, "MIN", TGSI_OPCODE_MIN }, - { 1, 2, 0, 0, "MAX", TGSI_OPCODE_MAX }, - { 1, 2, 0, 0, "SLT", TGSI_OPCODE_SLT }, - { 1, 2, 0, 0, "SGE", TGSI_OPCODE_SGE }, - { 1, 3, 0, 0, "MAD", TGSI_OPCODE_MAD }, - { 1, 2, 0, 0, "SUB", TGSI_OPCODE_SUB }, - { 1, 3, 0, 0, "LRP", TGSI_OPCODE_LRP }, - { 1, 3, 0, 0, "CND", TGSI_OPCODE_CND }, - { 1, 3, 0, 0, "CND0", TGSI_OPCODE_CND0 }, - { 1, 3, 0, 0, "DP2A", TGSI_OPCODE_DP2A }, - { 1, 2, 0, 0, "INDEX", TGSI_OPCODE_INDEX }, - { 1, 1, 0, 0, "NEGATE", TGSI_OPCODE_NEGATE }, - { 1, 1, 0, 0, "FRC", TGSI_OPCODE_FRC }, - { 1, 3, 0, 0, "CLAMP", TGSI_OPCODE_CLAMP }, - { 1, 1, 0, 0, "FLR", TGSI_OPCODE_FLR }, - { 1, 1, 0, 0, "ROUND", TGSI_OPCODE_ROUND }, - { 1, 1, 0, 0, "EX2", TGSI_OPCODE_EX2 }, - { 1, 1, 0, 0, "LG2", TGSI_OPCODE_LG2 }, - { 1, 2, 0, 0, "POW", TGSI_OPCODE_POW }, - { 1, 2, 0, 0, "XPD", TGSI_OPCODE_XPD }, - { 1, 2, 0, 0, "M4X4", TGSI_OPCODE_MULTIPLYMATRIX }, - { 1, 1, 0, 0, "ABS", TGSI_OPCODE_ABS }, - { 1, 1, 0, 0, "RCC", TGSI_OPCODE_RCC }, - { 1, 2, 0, 0, "DPH", TGSI_OPCODE_DPH }, - { 1, 1, 0, 0, "COS", TGSI_OPCODE_COS }, - { 1, 1, 0, 0, "DDX", TGSI_OPCODE_DDX }, - { 1, 1, 0, 0, "DDY", TGSI_OPCODE_DDY }, - { 0, 0, 0, 0, "KILP", TGSI_OPCODE_KILP }, - { 1, 1, 0, 0, "PK2H", TGSI_OPCODE_PK2H }, - { 1, 1, 0, 0, "PK2US", TGSI_OPCODE_PK2US }, - { 1, 1, 0, 0, "PK4B", TGSI_OPCODE_PK4B }, - { 1, 1, 0, 0, "PK4UB", TGSI_OPCODE_PK4UB }, - { 1, 2, 0, 0, "RFL", TGSI_OPCODE_RFL }, - { 1, 2, 0, 0, "SEQ", TGSI_OPCODE_SEQ }, - { 1, 2, 0, 0, "SFL", TGSI_OPCODE_SFL }, - { 1, 2, 0, 0, "SGT", TGSI_OPCODE_SGT }, - { 1, 1, 0, 0, "SIN", TGSI_OPCODE_SIN }, - { 1, 2, 0, 0, "SLE", TGSI_OPCODE_SLE }, - { 1, 2, 0, 0, "SNE", TGSI_OPCODE_SNE }, - { 1, 2, 0, 0, "STR", TGSI_OPCODE_STR }, - { 1, 2, 1, 0, "TEX", TGSI_OPCODE_TEX }, - { 1, 4, 1, 0, "TXD", TGSI_OPCODE_TXD }, - { 1, 2, 1, 0, "TXP", TGSI_OPCODE_TXP }, - { 1, 1, 0, 0, "UP2H", TGSI_OPCODE_UP2H }, - { 1, 1, 0, 0, "UP2US", TGSI_OPCODE_UP2US }, - { 1, 1, 0, 0, "UP4B", TGSI_OPCODE_UP4B }, - { 1, 1, 0, 0, "UP4UB", TGSI_OPCODE_UP4UB }, - { 1, 3, 0, 0, "X2D", TGSI_OPCODE_X2D }, - { 1, 1, 0, 0, "ARA", TGSI_OPCODE_ARA }, - { 1, 1, 0, 0, "ARR", TGSI_OPCODE_ARR }, - { 0, 1, 0, 0, "BRA", TGSI_OPCODE_BRA }, - { 0, 0, 0, 1, "CAL", TGSI_OPCODE_CAL }, - { 0, 0, 0, 0, "RET", TGSI_OPCODE_RET }, - { 1, 1, 0, 0, "SSG", TGSI_OPCODE_SSG }, - { 1, 3, 0, 0, "CMP", TGSI_OPCODE_CMP }, - { 1, 1, 0, 0, "SCS", TGSI_OPCODE_SCS }, - { 1, 2, 1, 0, "TXB", TGSI_OPCODE_TXB }, - { 1, 1, 0, 0, "NRM", TGSI_OPCODE_NRM }, - { 1, 2, 0, 0, "DIV", TGSI_OPCODE_DIV }, - { 1, 2, 0, 0, "DP2", TGSI_OPCODE_DP2 }, - { 1, 2, 1, 0, "TXL", TGSI_OPCODE_TXL }, - { 0, 0, 0, 0, "BRK", TGSI_OPCODE_BRK }, - { 0, 1, 0, 1, "IF", TGSI_OPCODE_IF }, - { 0, 0, 0, 0, "LOOP", TGSI_OPCODE_LOOP }, - { 0, 1, 0, 0, "REP", TGSI_OPCODE_REP }, - { 0, 0, 0, 1, "ELSE", TGSI_OPCODE_ELSE }, - { 0, 0, 0, 0, "ENDIF", TGSI_OPCODE_ENDIF }, - { 0, 0, 0, 0, "ENDLOOP", TGSI_OPCODE_ENDLOOP }, - { 0, 0, 0, 0, "ENDREP", TGSI_OPCODE_ENDREP }, - { 0, 1, 0, 0, "PUSHA", TGSI_OPCODE_PUSHA }, - { 1, 0, 0, 0, "POPA", TGSI_OPCODE_POPA }, - { 1, 1, 0, 0, "CEIL", TGSI_OPCODE_CEIL }, - { 1, 1, 0, 0, "I2F", TGSI_OPCODE_I2F }, - { 1, 1, 0, 0, "NOT", TGSI_OPCODE_NOT }, - { 1, 1, 0, 0, "TRUNC", TGSI_OPCODE_TRUNC }, - { 1, 2, 0, 0, "SHL", TGSI_OPCODE_SHL }, - { 1, 2, 0, 0, "SHR", TGSI_OPCODE_SHR }, - { 1, 2, 0, 0, "AND", TGSI_OPCODE_AND }, - { 1, 2, 0, 0, "OR", TGSI_OPCODE_OR }, - { 1, 2, 0, 0, "MOD", TGSI_OPCODE_MOD }, - { 1, 2, 0, 0, "XOR", TGSI_OPCODE_XOR }, - { 1, 3, 0, 0, "SAD", TGSI_OPCODE_SAD }, - { 1, 2, 1, 0, "TXF", TGSI_OPCODE_TXF }, - { 1, 2, 1, 0, "TXQ", TGSI_OPCODE_TXQ }, - { 0, 0, 0, 0, "CONT", TGSI_OPCODE_CONT }, - { 0, 0, 0, 0, "EMIT", TGSI_OPCODE_EMIT }, - { 0, 0, 0, 0, "ENDPRIM", TGSI_OPCODE_ENDPRIM }, - { 0, 0, 0, 1, "BGNLOOP2", TGSI_OPCODE_BGNLOOP2 }, - { 0, 0, 0, 0, "BGNSUB", TGSI_OPCODE_BGNSUB }, - { 0, 0, 0, 1, "ENDLOOP2", TGSI_OPCODE_ENDLOOP2 }, - { 0, 0, 0, 0, "ENDSUB", TGSI_OPCODE_ENDSUB }, - { 1, 1, 0, 0, "NOISE1", TGSI_OPCODE_NOISE1 }, - { 1, 1, 0, 0, "NOISE2", TGSI_OPCODE_NOISE2 }, - { 1, 1, 0, 0, "NOISE3", TGSI_OPCODE_NOISE3 }, - { 1, 1, 0, 0, "NOISE4", TGSI_OPCODE_NOISE4 }, - { 0, 0, 0, 0, "NOP", TGSI_OPCODE_NOP }, - { 1, 2, 0, 0, "M4X3", TGSI_OPCODE_M4X3 }, - { 1, 2, 0, 0, "M3X4", TGSI_OPCODE_M3X4 }, - { 1, 2, 0, 0, "M3X3", TGSI_OPCODE_M3X3 }, - { 1, 2, 0, 0, "M3X2", TGSI_OPCODE_M3X2 }, - { 1, 1, 0, 0, "NRM4", TGSI_OPCODE_NRM4 }, - { 0, 1, 0, 0, "CALLNZ", TGSI_OPCODE_CALLNZ }, - { 0, 1, 0, 0, "IFC", TGSI_OPCODE_IFC }, - { 0, 1, 0, 0, "BREAKC", TGSI_OPCODE_BREAKC }, - { 0, 1, 0, 0, "KIL", TGSI_OPCODE_KIL }, - { 0, 0, 0, 0, "END", TGSI_OPCODE_END }, - { 1, 1, 0, 0, "SWZ", TGSI_OPCODE_SWZ } + { 1, 1, 0, 0, 0, 0, "ARL", TGSI_OPCODE_ARL }, + { 1, 1, 0, 0, 0, 0, "MOV", TGSI_OPCODE_MOV }, + { 1, 1, 0, 0, 0, 0, "LIT", TGSI_OPCODE_LIT }, + { 1, 1, 0, 0, 0, 0, "RCP", TGSI_OPCODE_RCP }, + { 1, 1, 0, 0, 0, 0, "RSQ", TGSI_OPCODE_RSQ }, + { 1, 1, 0, 0, 0, 0, "EXP", TGSI_OPCODE_EXP }, + { 1, 1, 0, 0, 0, 0, "LOG", TGSI_OPCODE_LOG }, + { 1, 2, 0, 0, 0, 0, "MUL", TGSI_OPCODE_MUL }, + { 1, 2, 0, 0, 0, 0, "ADD", TGSI_OPCODE_ADD }, + { 1, 2, 0, 0, 0, 0, "DP3", TGSI_OPCODE_DP3 }, + { 1, 2, 0, 0, 0, 0, "DP4", TGSI_OPCODE_DP4 }, + { 1, 2, 0, 0, 0, 0, "DST", TGSI_OPCODE_DST }, + { 1, 2, 0, 0, 0, 0, "MIN", TGSI_OPCODE_MIN }, + { 1, 2, 0, 0, 0, 0, "MAX", TGSI_OPCODE_MAX }, + { 1, 2, 0, 0, 0, 0, "SLT", TGSI_OPCODE_SLT }, + { 1, 2, 0, 0, 0, 0, "SGE", TGSI_OPCODE_SGE }, + { 1, 3, 0, 0, 0, 0, "MAD", TGSI_OPCODE_MAD }, + { 1, 2, 0, 0, 0, 0, "SUB", TGSI_OPCODE_SUB }, + { 1, 3, 0, 0, 0, 0, "LRP", TGSI_OPCODE_LRP }, + { 1, 3, 0, 0, 0, 0, "CND", TGSI_OPCODE_CND }, + { 0, 0, 0, 0, 0, 0, "", 20 }, /* removed */ + { 1, 3, 0, 0, 0, 0, "DP2A", TGSI_OPCODE_DP2A }, + { 0, 0, 0, 0, 0, 0, "", 22 }, /* removed */ + { 0, 0, 0, 0, 0, 0, "", 23 }, /* removed */ + { 1, 1, 0, 0, 0, 0, "FRC", TGSI_OPCODE_FRC }, + { 1, 3, 0, 0, 0, 0, "CLAMP", TGSI_OPCODE_CLAMP }, + { 1, 1, 0, 0, 0, 0, "FLR", TGSI_OPCODE_FLR }, + { 1, 1, 0, 0, 0, 0, "ROUND", TGSI_OPCODE_ROUND }, + { 1, 1, 0, 0, 0, 0, "EX2", TGSI_OPCODE_EX2 }, + { 1, 1, 0, 0, 0, 0, "LG2", TGSI_OPCODE_LG2 }, + { 1, 2, 0, 0, 0, 0, "POW", TGSI_OPCODE_POW }, + { 1, 2, 0, 0, 0, 0, "XPD", TGSI_OPCODE_XPD }, + { 0, 0, 0, 0, 0, 0, "", 32 }, /* removed */ + { 1, 1, 0, 0, 0, 0, "ABS", TGSI_OPCODE_ABS }, + { 1, 1, 0, 0, 0, 0, "RCC", TGSI_OPCODE_RCC }, + { 1, 2, 0, 0, 0, 0, "DPH", TGSI_OPCODE_DPH }, + { 1, 1, 0, 0, 0, 0, "COS", TGSI_OPCODE_COS }, + { 1, 1, 0, 0, 0, 0, "DDX", TGSI_OPCODE_DDX }, + { 1, 1, 0, 0, 0, 0, "DDY", TGSI_OPCODE_DDY }, + { 0, 0, 0, 0, 0, 0, "KILP", TGSI_OPCODE_KILP }, + { 1, 1, 0, 0, 0, 0, "PK2H", TGSI_OPCODE_PK2H }, + { 1, 1, 0, 0, 0, 0, "PK2US", TGSI_OPCODE_PK2US }, + { 1, 1, 0, 0, 0, 0, "PK4B", TGSI_OPCODE_PK4B }, + { 1, 1, 0, 0, 0, 0, "PK4UB", TGSI_OPCODE_PK4UB }, + { 1, 2, 0, 0, 0, 0, "RFL", TGSI_OPCODE_RFL }, + { 1, 2, 0, 0, 0, 0, "SEQ", TGSI_OPCODE_SEQ }, + { 1, 2, 0, 0, 0, 0, "SFL", TGSI_OPCODE_SFL }, + { 1, 2, 0, 0, 0, 0, "SGT", TGSI_OPCODE_SGT }, + { 1, 1, 0, 0, 0, 0, "SIN", TGSI_OPCODE_SIN }, + { 1, 2, 0, 0, 0, 0, "SLE", TGSI_OPCODE_SLE }, + { 1, 2, 0, 0, 0, 0, "SNE", TGSI_OPCODE_SNE }, + { 1, 2, 0, 0, 0, 0, "STR", TGSI_OPCODE_STR }, + { 1, 2, 1, 0, 0, 0, "TEX", TGSI_OPCODE_TEX }, + { 1, 4, 1, 0, 0, 0, "TXD", TGSI_OPCODE_TXD }, + { 1, 2, 1, 0, 0, 0, "TXP", TGSI_OPCODE_TXP }, + { 1, 1, 0, 0, 0, 0, "UP2H", TGSI_OPCODE_UP2H }, + { 1, 1, 0, 0, 0, 0, "UP2US", TGSI_OPCODE_UP2US }, + { 1, 1, 0, 0, 0, 0, "UP4B", TGSI_OPCODE_UP4B }, + { 1, 1, 0, 0, 0, 0, "UP4UB", TGSI_OPCODE_UP4UB }, + { 1, 3, 0, 0, 0, 0, "X2D", TGSI_OPCODE_X2D }, + { 1, 1, 0, 0, 0, 0, "ARA", TGSI_OPCODE_ARA }, + { 1, 1, 0, 0, 0, 0, "ARR", TGSI_OPCODE_ARR }, + { 0, 1, 0, 0, 0, 0, "BRA", TGSI_OPCODE_BRA }, + { 0, 0, 0, 1, 0, 0, "CAL", TGSI_OPCODE_CAL }, + { 0, 0, 0, 0, 0, 0, "RET", TGSI_OPCODE_RET }, + { 1, 1, 0, 0, 0, 0, "SSG", TGSI_OPCODE_SSG }, + { 1, 3, 0, 0, 0, 0, "CMP", TGSI_OPCODE_CMP }, + { 1, 1, 0, 0, 0, 0, "SCS", TGSI_OPCODE_SCS }, + { 1, 2, 1, 0, 0, 0, "TXB", TGSI_OPCODE_TXB }, + { 1, 1, 0, 0, 0, 0, "NRM", TGSI_OPCODE_NRM }, + { 1, 2, 0, 0, 0, 0, "DIV", TGSI_OPCODE_DIV }, + { 1, 2, 0, 0, 0, 0, "DP2", TGSI_OPCODE_DP2 }, + { 1, 2, 1, 0, 0, 0, "TXL", TGSI_OPCODE_TXL }, + { 0, 0, 0, 0, 0, 0, "BRK", TGSI_OPCODE_BRK }, + { 0, 1, 0, 1, 0, 1, "IF", TGSI_OPCODE_IF }, + { 1, 1, 0, 0, 0, 1, "BGNFOR", TGSI_OPCODE_BGNFOR }, + { 0, 1, 0, 0, 0, 1, "REP", TGSI_OPCODE_REP }, + { 0, 0, 0, 1, 1, 1, "ELSE", TGSI_OPCODE_ELSE }, + { 0, 0, 0, 0, 1, 0, "ENDIF", TGSI_OPCODE_ENDIF }, + { 1, 0, 0, 0, 1, 0, "ENDFOR", TGSI_OPCODE_ENDFOR }, + { 0, 0, 0, 0, 1, 0, "ENDREP", TGSI_OPCODE_ENDREP }, + { 0, 1, 0, 0, 0, 0, "PUSHA", TGSI_OPCODE_PUSHA }, + { 1, 0, 0, 0, 0, 0, "POPA", TGSI_OPCODE_POPA }, + { 1, 1, 0, 0, 0, 0, "CEIL", TGSI_OPCODE_CEIL }, + { 1, 1, 0, 0, 0, 0, "I2F", TGSI_OPCODE_I2F }, + { 1, 1, 0, 0, 0, 0, "NOT", TGSI_OPCODE_NOT }, + { 1, 1, 0, 0, 0, 0, "TRUNC", TGSI_OPCODE_TRUNC }, + { 1, 2, 0, 0, 0, 0, "SHL", TGSI_OPCODE_SHL }, + { 1, 2, 0, 0, 0, 0, "SHR", TGSI_OPCODE_SHR }, + { 1, 2, 0, 0, 0, 0, "AND", TGSI_OPCODE_AND }, + { 1, 2, 0, 0, 0, 0, "OR", TGSI_OPCODE_OR }, + { 1, 2, 0, 0, 0, 0, "MOD", TGSI_OPCODE_MOD }, + { 1, 2, 0, 0, 0, 0, "XOR", TGSI_OPCODE_XOR }, + { 1, 3, 0, 0, 0, 0, "SAD", TGSI_OPCODE_SAD }, + { 1, 2, 1, 0, 0, 0, "TXF", TGSI_OPCODE_TXF }, + { 1, 2, 1, 0, 0, 0, "TXQ", TGSI_OPCODE_TXQ }, + { 0, 0, 0, 0, 0, 0, "CONT", TGSI_OPCODE_CONT }, + { 0, 0, 0, 0, 0, 0, "EMIT", TGSI_OPCODE_EMIT }, + { 0, 0, 0, 0, 0, 0, "ENDPRIM", TGSI_OPCODE_ENDPRIM }, + { 0, 0, 0, 1, 0, 1, "BGNLOOP", TGSI_OPCODE_BGNLOOP }, + { 0, 0, 0, 0, 0, 1, "BGNSUB", TGSI_OPCODE_BGNSUB }, + { 0, 0, 0, 1, 1, 0, "ENDLOOP", TGSI_OPCODE_ENDLOOP }, + { 0, 0, 0, 0, 1, 0, "ENDSUB", TGSI_OPCODE_ENDSUB }, + { 1, 1, 0, 0, 0, 0, "NOISE1", TGSI_OPCODE_NOISE1 }, + { 1, 1, 0, 0, 0, 0, "NOISE2", TGSI_OPCODE_NOISE2 }, + { 1, 1, 0, 0, 0, 0, "NOISE3", TGSI_OPCODE_NOISE3 }, + { 1, 1, 0, 0, 0, 0, "NOISE4", TGSI_OPCODE_NOISE4 }, + { 0, 0, 0, 0, 0, 0, "NOP", TGSI_OPCODE_NOP }, + { 0, 0, 0, 0, 0, 0, "", 108 }, /* removed */ + { 0, 0, 0, 0, 0, 0, "", 109 }, /* removed */ + { 0, 0, 0, 0, 0, 0, "", 110 }, /* removed */ + { 0, 0, 0, 0, 0, 0, "", 111 }, /* removed */ + { 1, 1, 0, 0, 0, 0, "NRM4", TGSI_OPCODE_NRM4 }, + { 0, 1, 0, 0, 0, 0, "CALLNZ", TGSI_OPCODE_CALLNZ }, + { 0, 1, 0, 0, 0, 0, "IFC", TGSI_OPCODE_IFC }, + { 0, 1, 0, 0, 0, 0, "BREAKC", TGSI_OPCODE_BREAKC }, + { 0, 1, 0, 0, 0, 0, "KIL", TGSI_OPCODE_KIL }, + { 0, 0, 0, 0, 0, 0, "END", TGSI_OPCODE_END }, + { 1, 1, 0, 0, 0, 0, "SWZ", TGSI_OPCODE_SWZ } }; const struct tgsi_opcode_info * @@ -170,3 +170,12 @@ tgsi_get_opcode_info( uint opcode ) assert( 0 ); return NULL; } + + +const char * +tgsi_get_opcode_name( uint opcode ) +{ + const struct tgsi_opcode_info *info = tgsi_get_opcode_info(opcode); + return info->mnemonic; +} + diff --git a/src/gallium/auxiliary/tgsi/tgsi_info.h b/src/gallium/auxiliary/tgsi/tgsi_info.h index 16577598bb..74713c3b98 100644 --- a/src/gallium/auxiliary/tgsi/tgsi_info.h +++ b/src/gallium/auxiliary/tgsi/tgsi_info.h @@ -36,10 +36,12 @@ extern "C" { struct tgsi_opcode_info { - uint num_dst; - uint num_src; - boolean is_tex; - boolean is_branch; + unsigned num_dst:3; + unsigned num_src:3; + unsigned is_tex:1; + unsigned is_branch:1; + int pre_dedent:2; + int post_indent:2; const char *mnemonic; uint opcode; }; @@ -47,6 +49,10 @@ struct tgsi_opcode_info const struct tgsi_opcode_info * tgsi_get_opcode_info( uint opcode ); +const char * +tgsi_get_opcode_name( uint opcode ); + + #if defined __cplusplus } #endif diff --git a/src/gallium/auxiliary/tgsi/tgsi_opcode_tmp.h b/src/gallium/auxiliary/tgsi/tgsi_opcode_tmp.h new file mode 100644 index 0000000000..e7bcf4bf75 --- /dev/null +++ b/src/gallium/auxiliary/tgsi/tgsi_opcode_tmp.h @@ -0,0 +1,172 @@ +/************************************************************************** + * + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * 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. + * + **************************************************************************/ +#ifndef OP12_TEX +#define OP12_TEX(a) OP12(a) +#endif + +#ifndef OP14_TEX +#define OP14_TEX(a) OP14(a) +#endif + +#ifndef OP00_LBL +#define OP00_LBL(a) OP00(a) +#endif + +#ifndef OP01_LBL +#define OP01_LBL(a) OP01(a) +#endif + +OP11(ARL) +OP11(MOV) +OP11(LIT) +OP11(RCP) +OP11(RSQ) +OP11(EXP) +OP11(LOG) +OP12(MUL) +OP12(ADD) +OP12(DP3) +OP12(DP4) +OP12(DST) +OP12(MIN) +OP12(MAX) +OP12(SLT) +OP12(SGE) +OP13(MAD) +OP12(SUB) +OP13(LRP) +OP13(CND) +OP13(DP2A) +OP11(FRC) +OP13(CLAMP) +OP11(FLR) +OP11(ROUND) +OP11(EX2) +OP11(LG2) +OP12(POW) +OP12(XPD) +OP11(ABS) +OP11(RCC) +OP12(DPH) +OP11(COS) +OP11(DDX) +OP11(DDY) +OP00(KILP) +OP11(PK2H) +OP11(PK2US) +OP11(PK4B) +OP11(PK4UB) +OP12(RFL) +OP12(SEQ) +OP12(SFL) +OP12(SGT) +OP11(SIN) +OP12(SLE) +OP12(SNE) +OP12(STR) +OP12_TEX(TEX) +OP14_TEX(TXD) +OP12_TEX(TXP) +OP11(UP2H) +OP11(UP2US) +OP11(UP4B) +OP11(UP4UB) +OP13(X2D) +OP11(ARA) +OP11(ARR) +OP01(BRA) +OP00_LBL(CAL) +OP00(RET) +OP11(SSG) +OP13(CMP) +OP11(SCS) +OP12_TEX(TXB) +OP11(NRM) +OP12(DIV) +OP12(DP2) +OP12_TEX(TXL) +OP00(BRK) +OP01_LBL(IF) +OP11(BGNFOR) +OP01(REP) +OP00_LBL(ELSE) +OP00(ENDIF) +OP10(ENDFOR) +OP00(ENDREP) +OP01(PUSHA) +OP10(POPA) +OP11(CEIL) +OP11(I2F) +OP11(NOT) +OP11(TRUNC) +OP12(SHL) +OP12(SHR) +OP12(AND) +OP12(OR) +OP12(MOD) +OP12(XOR) +OP13(SAD) +OP12_TEX(TXF) +OP12_TEX(TXQ) +OP00(CONT) +OP00(EMIT) +OP00(ENDPRIM) +OP00_LBL(BGNLOOP) +OP00(BGNSUB) +OP00_LBL(ENDLOOP) +OP00(ENDSUB) +OP11(NOISE1) +OP11(NOISE2) +OP11(NOISE3) +OP11(NOISE4) +OP00(NOP) +OP11(NRM4) +OP01(CALLNZ) +OP01(IFC) +OP01(BREAKC) +OP01(KIL) +OP00(END) +OP11(SWZ) + + +#undef OP00 +#undef OP01 +#undef OP10 +#undef OP11 +#undef OP12 +#undef OP13 + +#ifdef OP14 +#undef OP14 +#endif + +#undef OP00_LBL +#undef OP01_LBL + +#undef OP12_TEX +#undef OP14_TEX + diff --git a/src/gallium/auxiliary/tgsi/tgsi_parse.h b/src/gallium/auxiliary/tgsi/tgsi_parse.h index 1035bda1a8..a26ee5ba86 100644 --- a/src/gallium/auxiliary/tgsi/tgsi_parse.h +++ b/src/gallium/auxiliary/tgsi/tgsi_parse.h @@ -87,6 +87,7 @@ struct tgsi_full_instruction struct tgsi_instruction_ext_texture InstructionExtTexture; struct tgsi_full_dst_register FullDstRegisters[TGSI_FULL_MAX_DST_REGISTERS]; struct tgsi_full_src_register FullSrcRegisters[TGSI_FULL_MAX_SRC_REGISTERS]; + uint Flags; /**< user-defined usage */ }; union tgsi_full_token diff --git a/src/gallium/auxiliary/tgsi/tgsi_ppc.c b/src/gallium/auxiliary/tgsi/tgsi_ppc.c index fddf54460a..4b1c7d4e01 100644 --- a/src/gallium/auxiliary/tgsi/tgsi_ppc.c +++ b/src/gallium/auxiliary/tgsi/tgsi_ppc.c @@ -38,6 +38,7 @@ #include "util/u_math.h" #include "util/u_memory.h" #include "util/u_sse.h" +#include "tgsi/tgsi_info.h" #include "tgsi/tgsi_parse.h" #include "tgsi/tgsi_util.h" #include "tgsi_dump.h" @@ -619,17 +620,17 @@ emit_unaryop(struct gen_context *gen, struct tgsi_full_instruction *inst) ppc_vandc(gen->f, v1, v0, bit31_vec); /* v1 = v0 & ~bit31 */ } break; - case TGSI_OPCODE_FLOOR: + case TGSI_OPCODE_FLR: ppc_vrfim(gen->f, v1, v0); /* v1 = floor(v0) */ break; - case TGSI_OPCODE_FRAC: + case TGSI_OPCODE_FRC: ppc_vrfim(gen->f, v1, v0); /* tmp = floor(v0) */ ppc_vsubfp(gen->f, v1, v0, v1); /* v1 = v0 - v1 */ break; - case TGSI_OPCODE_EXPBASE2: + case TGSI_OPCODE_EX2: ppc_vexptefp(gen->f, v1, v0); /* v1 = 2^v0 */ break; - case TGSI_OPCODE_LOGBASE2: + case TGSI_OPCODE_LG2: /* XXX this may be broken! */ ppc_vlogefp(gen->f, v1, v0); /* v1 = log2(v0) */ break; @@ -1107,14 +1108,23 @@ static int emit_instruction(struct gen_context *gen, struct tgsi_full_instruction *inst) { + + /* we don't handle saturation/clamping yet */ + if (inst->Instruction.Saturate != TGSI_SAT_NONE) + return 0; + + /* need to use extra temps to fix SOA dependencies : */ + if (tgsi_check_soa_dependencies(inst)) + return FALSE; + switch (inst->Instruction.Opcode) { case TGSI_OPCODE_MOV: case TGSI_OPCODE_SWZ: case TGSI_OPCODE_ABS: - case TGSI_OPCODE_FLOOR: - case TGSI_OPCODE_FRAC: - case TGSI_OPCODE_EXPBASE2: - case TGSI_OPCODE_LOGBASE2: + case TGSI_OPCODE_FLR: + case TGSI_OPCODE_FRC: + case TGSI_OPCODE_EX2: + case TGSI_OPCODE_LG2: emit_unaryop(gen, inst); break; case TGSI_OPCODE_RSQ: @@ -1317,8 +1327,10 @@ tgsi_emit_ppc(const struct tgsi_token *tokens, ok = emit_instruction(&gen, &parse.FullToken.FullInstruction); if (!ok) { - debug_printf("failed to translate tgsi opcode %d to PPC (%s)\n", - parse.FullToken.FullInstruction.Instruction.Opcode, + uint opcode = parse.FullToken.FullInstruction.Instruction.Opcode; + debug_printf("failed to translate tgsi opcode %d (%s) to PPC (%s)\n", + opcode, + tgsi_get_opcode_name(opcode), parse.FullHeader.Processor.Processor == TGSI_PROCESSOR_VERTEX ? "vertex shader" : "fragment shader"); } diff --git a/src/gallium/auxiliary/tgsi/tgsi_sanity.c b/src/gallium/auxiliary/tgsi/tgsi_sanity.c index 6f1f5c2b4b..53e13b30e6 100644 --- a/src/gallium/auxiliary/tgsi/tgsi_sanity.c +++ b/src/gallium/auxiliary/tgsi/tgsi_sanity.c @@ -131,7 +131,7 @@ is_register_used( return (ctx->regs_used[file][index / BITS_IN_REG_FLAG] & (1 << (index % BITS_IN_REG_FLAG))) ? TRUE : FALSE; } -static const char *file_names[] = +static const char *file_names[TGSI_FILE_COUNT] = { "NULL", "CONST", @@ -140,7 +140,8 @@ static const char *file_names[] = "TEMP", "SAMP", "ADDR", - "IMM" + "IMM", + "LOOP" }; static boolean @@ -198,10 +199,10 @@ iter_instruction( } if (info->num_dst != inst->Instruction.NumDstRegs) { - report_error( ctx, "Invalid number of destination operands, should be %u", info->num_dst ); + report_error( ctx, "%s: Invalid number of destination operands, should be %u", info->mnemonic, info->num_dst ); } if (info->num_src != inst->Instruction.NumSrcRegs) { - report_error( ctx, "Invalid number of source operands, should be %u", info->num_src ); + report_error( ctx, "%s: Invalid number of source operands, should be %u", info->mnemonic, info->num_src ); } /* Check destination and source registers' validity. @@ -234,9 +235,29 @@ iter_instruction( index, "indirect", FALSE ); - if (file != TGSI_FILE_ADDRESS || index != 0) - report_warning( ctx, "Indirect register not ADDR[0]" ); + if (!(file == TGSI_FILE_ADDRESS || file == TGSI_FILE_LOOP) || index != 0) { + report_warning(ctx, "Indirect register neither ADDR[0] nor LOOP[0]"); + } + } + } + + switch (inst->Instruction.Opcode) { + case TGSI_OPCODE_BGNFOR: + case TGSI_OPCODE_ENDFOR: + if (inst->FullDstRegisters[0].DstRegister.File != TGSI_FILE_LOOP || + inst->FullDstRegisters[0].DstRegister.Index != 0) { + report_error(ctx, "Destination register must be LOOP[0]"); + } + break; + } + + switch (inst->Instruction.Opcode) { + case TGSI_OPCODE_BGNFOR: + if (inst->FullSrcRegisters[0].SrcRegister.File != TGSI_FILE_CONSTANT && + inst->FullSrcRegisters[0].SrcRegister.File != TGSI_FILE_IMMEDIATE) { + report_error(ctx, "Source register file must be either CONST or IMM"); } + break; } ctx->num_instructions++; @@ -337,7 +358,7 @@ epilog( boolean tgsi_sanity_check( - struct tgsi_token *tokens ) + const struct tgsi_token *tokens ) { struct sanity_check_ctx ctx; diff --git a/src/gallium/auxiliary/tgsi/tgsi_sanity.h b/src/gallium/auxiliary/tgsi/tgsi_sanity.h index ca45e94c7a..52263ff883 100644 --- a/src/gallium/auxiliary/tgsi/tgsi_sanity.h +++ b/src/gallium/auxiliary/tgsi/tgsi_sanity.h @@ -40,7 +40,7 @@ extern "C" { */ boolean tgsi_sanity_check( - struct tgsi_token *tokens ); + const struct tgsi_token *tokens ); #if defined __cplusplus } diff --git a/src/gallium/auxiliary/tgsi/tgsi_scan.c b/src/gallium/auxiliary/tgsi/tgsi_scan.c index c535788819..0db4481a3d 100644 --- a/src/gallium/auxiliary/tgsi/tgsi_scan.c +++ b/src/gallium/auxiliary/tgsi/tgsi_scan.c @@ -132,6 +132,7 @@ tgsi_scan_shader(const struct tgsi_token *tokens, if (file == TGSI_FILE_INPUT) { info->input_semantic_name[reg] = (ubyte)fulldecl->Semantic.SemanticName; info->input_semantic_index[reg] = (ubyte)fulldecl->Semantic.SemanticIndex; + info->input_interpolate[reg] = (ubyte)fulldecl->Declaration.Interpolate; info->num_inputs++; } else if (file == TGSI_FILE_OUTPUT) { diff --git a/src/gallium/auxiliary/tgsi/tgsi_scan.h b/src/gallium/auxiliary/tgsi/tgsi_scan.h index 2c1a75bc81..8a7ee0c7e4 100644 --- a/src/gallium/auxiliary/tgsi/tgsi_scan.h +++ b/src/gallium/auxiliary/tgsi/tgsi_scan.h @@ -45,6 +45,7 @@ struct tgsi_shader_info ubyte num_outputs; ubyte input_semantic_name[PIPE_MAX_SHADER_INPUTS]; /**< TGSI_SEMANTIC_x */ ubyte input_semantic_index[PIPE_MAX_SHADER_INPUTS]; + ubyte input_interpolate[PIPE_MAX_SHADER_INPUTS]; ubyte output_semantic_name[PIPE_MAX_SHADER_OUTPUTS]; /**< TGSI_SEMANTIC_x */ ubyte output_semantic_index[PIPE_MAX_SHADER_OUTPUTS]; diff --git a/src/gallium/auxiliary/tgsi/tgsi_sse2.c b/src/gallium/auxiliary/tgsi/tgsi_sse2.c index a2d4627da9..501fc05e72 100644 --- a/src/gallium/auxiliary/tgsi/tgsi_sse2.c +++ b/src/gallium/auxiliary/tgsi/tgsi_sse2.c @@ -36,10 +36,12 @@ #if defined(PIPE_ARCH_SSE) #include "util/u_sse.h" #endif +#include "tgsi/tgsi_info.h" #include "tgsi/tgsi_parse.h" #include "tgsi/tgsi_util.h" -#include "tgsi_exec.h" -#include "tgsi_sse2.h" +#include "tgsi/tgsi_dump.h" +#include "tgsi/tgsi_exec.h" +#include "tgsi/tgsi_sse2.h" #include "rtasm/rtasm_x86sse.h" @@ -1359,6 +1361,32 @@ emit_store( const struct tgsi_full_instruction *inst, unsigned chan_index ) { + switch( inst->Instruction.Saturate ) { + case TGSI_SAT_NONE: + break; + + case TGSI_SAT_ZERO_ONE: + sse_maxps( + func, + make_xmm( xmm ), + get_temp( + TGSI_EXEC_TEMP_00000000_I, + TGSI_EXEC_TEMP_00000000_C ) ); + + sse_minps( + func, + make_xmm( xmm ), + get_temp( + TGSI_EXEC_TEMP_ONE_I, + TGSI_EXEC_TEMP_ONE_C ) ); + break; + + case TGSI_SAT_MINUS_PLUS_ONE: + assert( 0 ); + break; + } + + switch( reg->DstRegister.File ) { case TGSI_FILE_OUTPUT: emit_output( @@ -1387,19 +1415,6 @@ emit_store( default: assert( 0 ); } - - switch( inst->Instruction.Saturate ) { - case TGSI_SAT_NONE: - break; - - case TGSI_SAT_ZERO_ONE: - /* assert( 0 ); */ - break; - - case TGSI_SAT_MINUS_PLUS_ONE: - assert( 0 ); - break; - } } #define STORE( FUNC, INST, XMM, INDEX, CHAN )\ @@ -1467,15 +1482,15 @@ emit_tex( struct x86_function *func, switch (inst->InstructionExtTexture.Texture) { case TGSI_TEXTURE_1D: - case TGSI_TEXTURE_SHADOW1D: count = 1; break; case TGSI_TEXTURE_2D: case TGSI_TEXTURE_RECT: - case TGSI_TEXTURE_SHADOW2D: - case TGSI_TEXTURE_SHADOWRECT: count = 2; break; + case TGSI_TEXTURE_SHADOW1D: + case TGSI_TEXTURE_SHADOW2D: + case TGSI_TEXTURE_SHADOWRECT: case TGSI_TEXTURE_3D: case TGSI_TEXTURE_CUBE: count = 3; @@ -1759,8 +1774,10 @@ emit_instruction( case TGSI_OPCODE_MOV: case TGSI_OPCODE_SWZ: FOR_EACH_DST0_ENABLED_CHANNEL( *inst, chan_index ) { - FETCH( func, *inst, 0, 0, chan_index ); - STORE( func, *inst, 0, 0, chan_index ); + FETCH( func, *inst, 4 + chan_index, 0, chan_index ); + } + FOR_EACH_DST0_ENABLED_CHANNEL( *inst, chan_index ) { + STORE( func, *inst, 4 + chan_index, 0, chan_index ); } break; @@ -2080,10 +2097,6 @@ emit_instruction( return 0; break; - case TGSI_OPCODE_CND0: - return 0; - break; - case TGSI_OPCODE_DP2A: FETCH( func, *inst, 0, 0, CHAN_X ); /* xmm0 = src[0].x */ FETCH( func, *inst, 1, 1, CHAN_X ); /* xmm1 = src[1].x */ @@ -2099,14 +2112,6 @@ emit_instruction( } break; - case TGSI_OPCODE_INDEX: - return 0; - break; - - case TGSI_OPCODE_NEGATE: - return 0; - break; - case TGSI_OPCODE_FRC: FOR_EACH_DST0_ENABLED_CHANNEL( *inst, chan_index ) { FETCH( func, *inst, 0, 0, chan_index ); @@ -2206,10 +2211,6 @@ emit_instruction( } break; - case TGSI_OPCODE_MULTIPLYMATRIX: - return 0; - break; - case TGSI_OPCODE_ABS: FOR_EACH_DST0_ENABLED_CHANNEL( *inst, chan_index ) { FETCH( func, *inst, 0, 0, chan_index ); @@ -2543,7 +2544,7 @@ emit_instruction( return 0; break; - case TGSI_OPCODE_LOOP: + case TGSI_OPCODE_BGNFOR: return 0; break; @@ -2559,7 +2560,7 @@ emit_instruction( return 0; break; - case TGSI_OPCODE_ENDLOOP: + case TGSI_OPCODE_ENDFOR: return 0; break; @@ -2929,11 +2930,29 @@ tgsi_emit_sse2( &parse.FullToken.FullInstruction ); if (!ok) { - debug_printf("failed to translate tgsi opcode %d to SSE (%s)\n", - parse.FullToken.FullInstruction.Instruction.Opcode, + uint opcode = parse.FullToken.FullInstruction.Instruction.Opcode; + debug_printf("failed to translate tgsi opcode %d (%s) to SSE (%s)\n", + opcode, + tgsi_get_opcode_name(opcode), parse.FullHeader.Processor.Processor == TGSI_PROCESSOR_VERTEX ? "vertex shader" : "fragment shader"); } + + if (tgsi_check_soa_dependencies(&parse.FullToken.FullInstruction)) { + uint opcode = parse.FullToken.FullInstruction.Instruction.Opcode; + + /* XXX: we only handle src/dst aliasing in a few opcodes + * currently. Need to use an additional temporay to hold + * the result in the cases where the code is too opaque to + * fix. + */ + if (opcode != TGSI_OPCODE_MOV && + opcode != TGSI_OPCODE_SWZ) { + debug_printf("Warning: src/dst aliasing in instruction" + " is not handled:\n"); + tgsi_dump_instruction(&parse.FullToken.FullInstruction, 1); + } + } break; case TGSI_TOKEN_TYPE_IMMEDIATE: diff --git a/src/gallium/auxiliary/tgsi/tgsi_text.c b/src/gallium/auxiliary/tgsi/tgsi_text.c index bfcbc40982..d438450b1e 100644 --- a/src/gallium/auxiliary/tgsi/tgsi_text.c +++ b/src/gallium/auxiliary/tgsi/tgsi_text.c @@ -231,7 +231,8 @@ static const char *file_names[TGSI_FILE_COUNT] = "TEMP", "SAMP", "ADDR", - "IMM" + "IMM", + "LOOP" }; static boolean diff --git a/src/gallium/auxiliary/tgsi/tgsi_ureg.c b/src/gallium/auxiliary/tgsi/tgsi_ureg.c new file mode 100644 index 0000000000..654426a903 --- /dev/null +++ b/src/gallium/auxiliary/tgsi/tgsi_ureg.c @@ -0,0 +1,1077 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. + * All Rights Reserved. + * + * 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 VMWARE, INC 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. + * + **************************************************************************/ + + +#include "pipe/p_context.h" +#include "pipe/p_state.h" +#include "tgsi/tgsi_ureg.h" +#include "tgsi/tgsi_info.h" +#include "tgsi/tgsi_dump.h" +#include "tgsi/tgsi_sanity.h" +#include "util/u_memory.h" +#include "util/u_math.h" + +union tgsi_any_token { + struct tgsi_version version; + struct tgsi_header header; + struct tgsi_processor processor; + struct tgsi_token token; + struct tgsi_declaration decl; + struct tgsi_declaration_range decl_range; + struct tgsi_declaration_semantic decl_semantic; + struct tgsi_immediate imm; + union tgsi_immediate_data imm_data; + struct tgsi_instruction insn; + struct tgsi_instruction_ext_nv insn_ext_nv; + struct tgsi_instruction_ext_label insn_ext_label; + struct tgsi_instruction_ext_texture insn_ext_texture; + struct tgsi_instruction_ext_predicate insn_ext_predicate; + struct tgsi_src_register src; + struct tgsi_src_register_ext_swz src_ext_swz; + struct tgsi_src_register_ext_mod src_ext_mod; + struct tgsi_dimension dim; + struct tgsi_dst_register dst; + struct tgsi_dst_register_ext_concode dst_ext_code; + struct tgsi_dst_register_ext_modulate dst_ext_mod; + struct tgsi_dst_register_ext_predicate dst_ext_pred; + unsigned value; +}; + + +struct ureg_tokens { + union tgsi_any_token *tokens; + unsigned size; + unsigned order; + unsigned count; +}; + +#define UREG_MAX_INPUT PIPE_MAX_ATTRIBS +#define UREG_MAX_OUTPUT PIPE_MAX_ATTRIBS +#define UREG_MAX_CONSTANT_RANGE 32 +#define UREG_MAX_IMMEDIATE 32 +#define UREG_MAX_TEMP 256 +#define UREG_MAX_ADDR 2 + +#define DOMAIN_DECL 0 +#define DOMAIN_INSN 1 + +struct ureg_program +{ + unsigned processor; + struct pipe_context *pipe; + + struct { + unsigned semantic_name; + unsigned semantic_index; + unsigned interp; + } fs_input[UREG_MAX_INPUT]; + unsigned nr_fs_inputs; + + unsigned vs_inputs[UREG_MAX_INPUT/32]; + + struct { + unsigned semantic_name; + unsigned semantic_index; + } output[UREG_MAX_OUTPUT]; + unsigned nr_outputs; + + struct { + float v[4]; + unsigned nr; + } immediate[UREG_MAX_IMMEDIATE]; + unsigned nr_immediates; + + struct ureg_src sampler[PIPE_MAX_SAMPLERS]; + unsigned nr_samplers; + + unsigned temps_active[UREG_MAX_TEMP / 32]; + unsigned nr_temps; + + struct { + unsigned first; + unsigned last; + } constant_range[UREG_MAX_CONSTANT_RANGE]; + unsigned nr_constant_ranges; + + unsigned nr_addrs; + unsigned nr_instructions; + + struct ureg_tokens domain[2]; +}; + +static union tgsi_any_token error_tokens[32]; + +static void tokens_error( struct ureg_tokens *tokens ) +{ + if (tokens->tokens && tokens->tokens != error_tokens) + FREE(tokens->tokens); + + tokens->tokens = error_tokens; + tokens->size = Elements(error_tokens); + tokens->count = 0; +} + + +static void tokens_expand( struct ureg_tokens *tokens, + unsigned count ) +{ + unsigned old_size = tokens->size * sizeof(unsigned); + + if (tokens->tokens == error_tokens) + goto fail; + + while (tokens->count + count > tokens->size) { + tokens->size = (1 << ++tokens->order); + } + + tokens->tokens = REALLOC(tokens->tokens, + old_size, + tokens->size * sizeof(unsigned)); + if (tokens->tokens == NULL) + goto fail; + + return; + +fail: + tokens_error(tokens); +} + +static void set_bad( struct ureg_program *ureg ) +{ + tokens_error(&ureg->domain[0]); +} + + + +static union tgsi_any_token *get_tokens( struct ureg_program *ureg, + unsigned domain, + unsigned count ) +{ + struct ureg_tokens *tokens = &ureg->domain[domain]; + union tgsi_any_token *result; + + if (tokens->count + count > tokens->size) + tokens_expand(tokens, count); + + result = &tokens->tokens[tokens->count]; + tokens->count += count; + return result; +} + + +static union tgsi_any_token *retrieve_token( struct ureg_program *ureg, + unsigned domain, + unsigned nr ) +{ + if (ureg->domain[domain].tokens == error_tokens) + return &error_tokens[0]; + + return &ureg->domain[domain].tokens[nr]; +} + + + +static INLINE struct ureg_dst +ureg_dst_register( unsigned file, + unsigned index ) +{ + struct ureg_dst dst; + + dst.File = file; + dst.WriteMask = TGSI_WRITEMASK_XYZW; + dst.Indirect = 0; + dst.IndirectIndex = 0; + dst.IndirectSwizzle = 0; + dst.Saturate = 0; + dst.Index = index; + dst.Pad1 = 0; + dst.Pad2 = 0; + + return dst; +} + +static INLINE struct ureg_src +ureg_src_register( unsigned file, + unsigned index ) +{ + struct ureg_src src; + + src.File = file; + src.SwizzleX = TGSI_SWIZZLE_X; + src.SwizzleY = TGSI_SWIZZLE_Y; + src.SwizzleZ = TGSI_SWIZZLE_Z; + src.SwizzleW = TGSI_SWIZZLE_W; + src.Pad = 0; + src.Indirect = 0; + src.IndirectIndex = 0; + src.IndirectSwizzle = 0; + src.Absolute = 0; + src.Index = index; + src.Negate = 0; + + return src; +} + + + + +struct ureg_src +ureg_DECL_fs_input( struct ureg_program *ureg, + unsigned name, + unsigned index, + unsigned interp_mode ) +{ + unsigned i; + + for (i = 0; i < ureg->nr_fs_inputs; i++) { + if (ureg->fs_input[i].semantic_name == name && + ureg->fs_input[i].semantic_index == index) + goto out; + } + + if (ureg->nr_fs_inputs < UREG_MAX_INPUT) { + ureg->fs_input[i].semantic_name = name; + ureg->fs_input[i].semantic_index = index; + ureg->fs_input[i].interp = interp_mode; + ureg->nr_fs_inputs++; + } + else { + set_bad( ureg ); + } + +out: + return ureg_src_register( TGSI_FILE_INPUT, i ); +} + + +struct ureg_src +ureg_DECL_vs_input( struct ureg_program *ureg, + unsigned index ) +{ + assert(ureg->processor == TGSI_PROCESSOR_VERTEX); + + ureg->vs_inputs[index/32] |= 1 << (index % 32); + return ureg_src_register( TGSI_FILE_INPUT, index ); +} + + +struct ureg_dst +ureg_DECL_output( struct ureg_program *ureg, + unsigned name, + unsigned index ) +{ + unsigned i; + + for (i = 0; i < ureg->nr_outputs; i++) { + if (ureg->output[i].semantic_name == name && + ureg->output[i].semantic_index == index) + goto out; + } + + if (ureg->nr_outputs < UREG_MAX_OUTPUT) { + ureg->output[i].semantic_name = name; + ureg->output[i].semantic_index = index; + ureg->nr_outputs++; + } + else { + set_bad( ureg ); + } + +out: + return ureg_dst_register( TGSI_FILE_OUTPUT, i ); +} + + +/* Returns a new constant register. Keep track of which have been + * referred to so that we can emit decls later. + * + * There is nothing in this code to bind this constant to any tracked + * value or manage any constant_buffer contents -- that's the + * resposibility of the calling code. + */ +struct ureg_src ureg_DECL_constant(struct ureg_program *ureg, + unsigned index ) +{ + unsigned minconst = index, maxconst = index; + unsigned i; + + /* Inside existing range? + */ + for (i = 0; i < ureg->nr_constant_ranges; i++) { + if (ureg->constant_range[i].first <= index && + ureg->constant_range[i].last >= index) + goto out; + } + + /* Extend existing range? + */ + for (i = 0; i < ureg->nr_constant_ranges; i++) { + if (ureg->constant_range[i].last == index - 1) { + ureg->constant_range[i].last = index; + goto out; + } + + if (ureg->constant_range[i].first == index + 1) { + ureg->constant_range[i].first = index; + goto out; + } + + minconst = MIN2(minconst, ureg->constant_range[i].first); + maxconst = MAX2(maxconst, ureg->constant_range[i].last); + } + + /* Create new range? + */ + if (ureg->nr_constant_ranges < UREG_MAX_CONSTANT_RANGE) { + i = ureg->nr_constant_ranges++; + ureg->constant_range[i].first = index; + ureg->constant_range[i].last = index; + } + + /* Collapse all ranges down to one: + */ + i = 0; + ureg->constant_range[0].first = minconst; + ureg->constant_range[0].last = maxconst; + ureg->nr_constant_ranges = 1; + +out: + assert(i < ureg->nr_constant_ranges); + assert(ureg->constant_range[i].first <= index); + assert(ureg->constant_range[i].last >= index); + return ureg_src_register( TGSI_FILE_CONSTANT, index ); +} + + +/* Allocate a new temporary. Temporaries greater than UREG_MAX_TEMP + * are legal, but will not be released. + */ +struct ureg_dst ureg_DECL_temporary( struct ureg_program *ureg ) +{ + unsigned i; + + for (i = 0; i < UREG_MAX_TEMP; i += 32) { + int bit = ffs(~ureg->temps_active[i/32]); + if (bit != 0) { + i += bit - 1; + goto out; + } + } + + /* No reusable temps, so allocate a new one: + */ + i = ureg->nr_temps++; + +out: + if (i < UREG_MAX_TEMP) + ureg->temps_active[i/32] |= 1 << (i % 32); + + if (i >= ureg->nr_temps) + ureg->nr_temps = i + 1; + + return ureg_dst_register( TGSI_FILE_TEMPORARY, i ); +} + + +void ureg_release_temporary( struct ureg_program *ureg, + struct ureg_dst tmp ) +{ + if(tmp.File == TGSI_FILE_TEMPORARY) + if (tmp.Index < UREG_MAX_TEMP) + ureg->temps_active[tmp.Index/32] &= ~(1 << (tmp.Index % 32)); +} + + +/* Allocate a new address register. + */ +struct ureg_dst ureg_DECL_address( struct ureg_program *ureg ) +{ + if (ureg->nr_addrs < UREG_MAX_ADDR) + return ureg_dst_register( TGSI_FILE_ADDRESS, ureg->nr_addrs++ ); + + assert( 0 ); + return ureg_dst_register( TGSI_FILE_ADDRESS, 0 ); +} + +/* Allocate a new sampler. + */ +struct ureg_src ureg_DECL_sampler( struct ureg_program *ureg, + unsigned nr ) +{ + unsigned i; + + for (i = 0; i < ureg->nr_samplers; i++) + if (ureg->sampler[i].Index == nr) + return ureg->sampler[i]; + + if (i < PIPE_MAX_SAMPLERS) { + ureg->sampler[i] = ureg_src_register( TGSI_FILE_SAMPLER, nr ); + ureg->nr_samplers++; + return ureg->sampler[i]; + } + + assert( 0 ); + return ureg->sampler[0]; +} + + + + +static int match_or_expand_immediate( const float *v, + unsigned nr, + float *v2, + unsigned *nr2, + unsigned *swizzle ) +{ + unsigned i, j; + + *swizzle = 0; + + for (i = 0; i < nr; i++) { + boolean found = FALSE; + + for (j = 0; j < *nr2 && !found; j++) { + if (v[i] == v2[j]) { + *swizzle |= j << (i * 2); + found = TRUE; + } + } + + if (!found) { + if (*nr2 >= 4) + return FALSE; + + v2[*nr2] = v[i]; + *swizzle |= *nr2 << (i * 2); + (*nr2)++; + } + } + + return TRUE; +} + + + + +struct ureg_src ureg_DECL_immediate( struct ureg_program *ureg, + const float *v, + unsigned nr ) +{ + unsigned i, j; + unsigned swizzle; + + /* Could do a first pass where we examine all existing immediates + * without expanding. + */ + + for (i = 0; i < ureg->nr_immediates; i++) { + if (match_or_expand_immediate( v, + nr, + ureg->immediate[i].v, + &ureg->immediate[i].nr, + &swizzle )) + goto out; + } + + if (ureg->nr_immediates < UREG_MAX_IMMEDIATE) { + i = ureg->nr_immediates++; + if (match_or_expand_immediate( v, + nr, + ureg->immediate[i].v, + &ureg->immediate[i].nr, + &swizzle )) + goto out; + } + + set_bad( ureg ); + +out: + /* Make sure that all referenced elements are from this immediate. + * Has the effect of making size-one immediates into scalars. + */ + for (j = nr; j < 4; j++) + swizzle |= (swizzle & 0x3) << (j * 2); + + return ureg_swizzle( ureg_src_register( TGSI_FILE_IMMEDIATE, i ), + (swizzle >> 0) & 0x3, + (swizzle >> 2) & 0x3, + (swizzle >> 4) & 0x3, + (swizzle >> 6) & 0x3); +} + + +void +ureg_emit_src( struct ureg_program *ureg, + struct ureg_src src ) +{ + unsigned size = (1 + + (src.Absolute ? 1 : 0) + + (src.Indirect ? 1 : 0)); + + union tgsi_any_token *out = get_tokens( ureg, DOMAIN_INSN, size ); + unsigned n = 0; + + assert(src.File != TGSI_FILE_NULL); + assert(src.File != TGSI_FILE_OUTPUT); + assert(src.File < TGSI_FILE_COUNT); + + out[n].value = 0; + out[n].src.File = src.File; + out[n].src.SwizzleX = src.SwizzleX; + out[n].src.SwizzleY = src.SwizzleY; + out[n].src.SwizzleZ = src.SwizzleZ; + out[n].src.SwizzleW = src.SwizzleW; + out[n].src.Index = src.Index; + out[n].src.Negate = src.Negate; + n++; + + if (src.Absolute) { + out[0].src.Extended = 1; + out[0].src.Negate = 0; + out[n].value = 0; + out[n].src_ext_mod.Type = TGSI_SRC_REGISTER_EXT_TYPE_MOD; + out[n].src_ext_mod.Absolute = 1; + out[n].src_ext_mod.Negate = src.Negate; + n++; + } + + if (src.Indirect) { + out[0].src.Indirect = 1; + out[n].value = 0; + out[n].src.File = TGSI_FILE_ADDRESS; + out[n].src.SwizzleX = src.IndirectSwizzle; + out[n].src.SwizzleY = src.IndirectSwizzle; + out[n].src.SwizzleZ = src.IndirectSwizzle; + out[n].src.SwizzleW = src.IndirectSwizzle; + out[n].src.Index = src.IndirectIndex; + n++; + } + + assert(n == size); +} + + +void +ureg_emit_dst( struct ureg_program *ureg, + struct ureg_dst dst ) +{ + unsigned size = (1 + + (dst.Indirect ? 1 : 0)); + + union tgsi_any_token *out = get_tokens( ureg, DOMAIN_INSN, size ); + unsigned n = 0; + + assert(dst.File != TGSI_FILE_NULL); + assert(dst.File != TGSI_FILE_CONSTANT); + assert(dst.File != TGSI_FILE_INPUT); + assert(dst.File != TGSI_FILE_SAMPLER); + assert(dst.File != TGSI_FILE_IMMEDIATE); + assert(dst.File < TGSI_FILE_COUNT); + + out[n].value = 0; + out[n].dst.File = dst.File; + out[n].dst.WriteMask = dst.WriteMask; + out[n].dst.Indirect = dst.Indirect; + out[n].dst.Index = dst.Index; + n++; + + if (dst.Indirect) { + out[n].value = 0; + out[n].src.File = TGSI_FILE_ADDRESS; + out[n].src.SwizzleX = dst.IndirectSwizzle; + out[n].src.SwizzleY = dst.IndirectSwizzle; + out[n].src.SwizzleZ = dst.IndirectSwizzle; + out[n].src.SwizzleW = dst.IndirectSwizzle; + out[n].src.Index = dst.IndirectIndex; + n++; + } + + assert(n == size); +} + + +static void validate( unsigned opcode, + unsigned nr_dst, + unsigned nr_src ) +{ +#ifdef DEBUG + const struct tgsi_opcode_info *info = tgsi_get_opcode_info( opcode ); + assert(info); + if(info) { + assert(nr_dst == info->num_dst); + assert(nr_src == info->num_src); + } +#endif +} + +unsigned +ureg_emit_insn(struct ureg_program *ureg, + unsigned opcode, + boolean saturate, + unsigned num_dst, + unsigned num_src ) +{ + union tgsi_any_token *out; + + validate( opcode, num_dst, num_src ); + + out = get_tokens( ureg, DOMAIN_INSN, 1 ); + out[0].value = 0; + out[0].insn.Type = TGSI_TOKEN_TYPE_INSTRUCTION; + out[0].insn.NrTokens = 0; + out[0].insn.Opcode = opcode; + out[0].insn.Saturate = saturate; + out[0].insn.NumDstRegs = num_dst; + out[0].insn.NumSrcRegs = num_src; + out[0].insn.Padding = 0; + out[0].insn.Extended = 0; + + ureg->nr_instructions++; + + return ureg->domain[DOMAIN_INSN].count - 1; +} + + +void +ureg_emit_label(struct ureg_program *ureg, + unsigned insn_token, + unsigned *label_token ) +{ + union tgsi_any_token *out, *insn; + + if(!label_token) + return; + + out = get_tokens( ureg, DOMAIN_INSN, 1 ); + insn = retrieve_token( ureg, DOMAIN_INSN, insn_token ); + + insn->insn.Extended = 1; + + out[0].value = 0; + out[0].insn_ext_label.Type = TGSI_INSTRUCTION_EXT_TYPE_LABEL; + + *label_token = ureg->domain[DOMAIN_INSN].count - 1; +} + +/* Will return a number which can be used in a label to point to the + * next instruction to be emitted. + */ +unsigned +ureg_get_instruction_number( struct ureg_program *ureg ) +{ + return ureg->nr_instructions; +} + +/* Patch a given label (expressed as a token number) to point to a + * given instruction (expressed as an instruction number). + */ +void +ureg_fixup_label(struct ureg_program *ureg, + unsigned label_token, + unsigned instruction_number ) +{ + union tgsi_any_token *out = retrieve_token( ureg, DOMAIN_INSN, label_token ); + + assert(out->insn_ext_label.Type == TGSI_INSTRUCTION_EXT_TYPE_LABEL); + out->insn_ext_label.Label = instruction_number; +} + + +void +ureg_emit_texture(struct ureg_program *ureg, + unsigned insn_token, + unsigned target ) +{ + union tgsi_any_token *out, *insn; + + out = get_tokens( ureg, DOMAIN_INSN, 1 ); + insn = retrieve_token( ureg, DOMAIN_INSN, insn_token ); + + insn->insn.Extended = 1; + + out[0].value = 0; + out[0].insn_ext_texture.Type = TGSI_INSTRUCTION_EXT_TYPE_TEXTURE; + out[0].insn_ext_texture.Texture = target; +} + + +void +ureg_fixup_insn_size(struct ureg_program *ureg, + unsigned insn ) +{ + union tgsi_any_token *out = retrieve_token( ureg, DOMAIN_INSN, insn ); + + assert(out->insn.Type == TGSI_TOKEN_TYPE_INSTRUCTION); + out->insn.NrTokens = ureg->domain[DOMAIN_INSN].count - insn - 1; +} + + +void +ureg_insn(struct ureg_program *ureg, + unsigned opcode, + const struct ureg_dst *dst, + unsigned nr_dst, + const struct ureg_src *src, + unsigned nr_src ) +{ + unsigned insn, i; + boolean saturate; + + saturate = nr_dst ? dst[0].Saturate : FALSE; + + insn = ureg_emit_insn( ureg, opcode, saturate, nr_dst, nr_src ); + + for (i = 0; i < nr_dst; i++) + ureg_emit_dst( ureg, dst[i] ); + + for (i = 0; i < nr_src; i++) + ureg_emit_src( ureg, src[i] ); + + ureg_fixup_insn_size( ureg, insn ); +} + +void +ureg_tex_insn(struct ureg_program *ureg, + unsigned opcode, + const struct ureg_dst *dst, + unsigned nr_dst, + unsigned target, + const struct ureg_src *src, + unsigned nr_src ) +{ + unsigned insn, i; + boolean saturate; + + saturate = nr_dst ? dst[0].Saturate : FALSE; + + insn = ureg_emit_insn( ureg, opcode, saturate, nr_dst, nr_src ); + + ureg_emit_texture( ureg, insn, target ); \ + + for (i = 0; i < nr_dst; i++) + ureg_emit_dst( ureg, dst[i] ); + + for (i = 0; i < nr_src; i++) + ureg_emit_src( ureg, src[i] ); + + ureg_fixup_insn_size( ureg, insn ); +} + + +void +ureg_label_insn(struct ureg_program *ureg, + unsigned opcode, + const struct ureg_src *src, + unsigned nr_src, + unsigned *label_token ) +{ + unsigned insn, i; + + insn = ureg_emit_insn( ureg, opcode, FALSE, 0, nr_src ); + + ureg_emit_label( ureg, insn, label_token ); \ + + for (i = 0; i < nr_src; i++) + ureg_emit_src( ureg, src[i] ); + + ureg_fixup_insn_size( ureg, insn ); +} + + + +static void emit_decl( struct ureg_program *ureg, + unsigned file, + unsigned index, + unsigned semantic_name, + unsigned semantic_index, + unsigned interp ) +{ + union tgsi_any_token *out = get_tokens( ureg, DOMAIN_DECL, 3 ); + + out[0].value = 0; + out[0].decl.Type = TGSI_TOKEN_TYPE_DECLARATION; + out[0].decl.NrTokens = 3; + out[0].decl.File = file; + out[0].decl.UsageMask = TGSI_WRITEMASK_XYZW; /* FIXME! */ + out[0].decl.Interpolate = interp; + out[0].decl.Semantic = 1; + + out[1].value = 0; + out[1].decl_range.First = + out[1].decl_range.Last = index; + + out[2].value = 0; + out[2].decl_semantic.SemanticName = semantic_name; + out[2].decl_semantic.SemanticIndex = semantic_index; + +} + + +static void emit_decl_range( struct ureg_program *ureg, + unsigned file, + unsigned first, + unsigned count ) +{ + union tgsi_any_token *out = get_tokens( ureg, DOMAIN_DECL, 2 ); + + out[0].value = 0; + out[0].decl.Type = TGSI_TOKEN_TYPE_DECLARATION; + out[0].decl.NrTokens = 2; + out[0].decl.File = file; + out[0].decl.UsageMask = 0xf; + out[0].decl.Interpolate = TGSI_INTERPOLATE_CONSTANT; + out[0].decl.Semantic = 0; + + out[1].value = 0; + out[1].decl_range.First = first; + out[1].decl_range.Last = first + count - 1; +} + +static void emit_immediate( struct ureg_program *ureg, + const float *v ) +{ + union tgsi_any_token *out = get_tokens( ureg, DOMAIN_DECL, 5 ); + + out[0].value = 0; + out[0].imm.Type = TGSI_TOKEN_TYPE_IMMEDIATE; + out[0].imm.NrTokens = 5; + out[0].imm.DataType = TGSI_IMM_FLOAT32; + out[0].imm.Padding = 0; + out[0].imm.Extended = 0; + + out[1].imm_data.Float = v[0]; + out[2].imm_data.Float = v[1]; + out[3].imm_data.Float = v[2]; + out[4].imm_data.Float = v[3]; +} + + + + +static void emit_decls( struct ureg_program *ureg ) +{ + unsigned i; + + if (ureg->processor == TGSI_PROCESSOR_VERTEX) { + for (i = 0; i < UREG_MAX_INPUT; i++) { + if (ureg->vs_inputs[i/32] & (1 << (i%32))) { + emit_decl_range( ureg, TGSI_FILE_INPUT, i, 1 ); + } + } + } + else { + for (i = 0; i < ureg->nr_fs_inputs; i++) { + emit_decl( ureg, + TGSI_FILE_INPUT, + i, + ureg->fs_input[i].semantic_name, + ureg->fs_input[i].semantic_index, + ureg->fs_input[i].interp ); + } + } + + for (i = 0; i < ureg->nr_outputs; i++) { + emit_decl( ureg, + TGSI_FILE_OUTPUT, + i, + ureg->output[i].semantic_name, + ureg->output[i].semantic_index, + TGSI_INTERPOLATE_CONSTANT ); + } + + for (i = 0; i < ureg->nr_samplers; i++) { + emit_decl_range( ureg, + TGSI_FILE_SAMPLER, + ureg->sampler[i].Index, 1 ); + } + + if (ureg->nr_constant_ranges) { + for (i = 0; i < ureg->nr_constant_ranges; i++) + emit_decl_range( ureg, + TGSI_FILE_CONSTANT, + ureg->constant_range[i].first, + (ureg->constant_range[i].last + 1 - + ureg->constant_range[i].first) ); + } + + if (ureg->nr_temps) { + emit_decl_range( ureg, + TGSI_FILE_TEMPORARY, + 0, ureg->nr_temps ); + } + + if (ureg->nr_addrs) { + emit_decl_range( ureg, + TGSI_FILE_ADDRESS, + 0, ureg->nr_addrs ); + } + + for (i = 0; i < ureg->nr_immediates; i++) { + emit_immediate( ureg, + ureg->immediate[i].v ); + } +} + +/* Append the instruction tokens onto the declarations to build a + * contiguous stream suitable to send to the driver. + */ +static void copy_instructions( struct ureg_program *ureg ) +{ + unsigned nr_tokens = ureg->domain[DOMAIN_INSN].count; + union tgsi_any_token *out = get_tokens( ureg, + DOMAIN_DECL, + nr_tokens ); + + memcpy(out, + ureg->domain[DOMAIN_INSN].tokens, + nr_tokens * sizeof out[0] ); +} + + +static void +fixup_header_size(struct ureg_program *ureg) +{ + union tgsi_any_token *out = retrieve_token( ureg, DOMAIN_DECL, 1 ); + + out->header.BodySize = ureg->domain[DOMAIN_DECL].count - 3; +} + + +static void +emit_header( struct ureg_program *ureg ) +{ + union tgsi_any_token *out = get_tokens( ureg, DOMAIN_DECL, 3 ); + + out[0].version.MajorVersion = 1; + out[0].version.MinorVersion = 1; + out[0].version.Padding = 0; + + out[1].header.HeaderSize = 2; + out[1].header.BodySize = 0; + + out[2].processor.Processor = ureg->processor; + out[2].processor.Padding = 0; +} + + +const struct tgsi_token *ureg_finalize( struct ureg_program *ureg ) +{ + const struct tgsi_token *tokens; + + emit_header( ureg ); + emit_decls( ureg ); + copy_instructions( ureg ); + fixup_header_size( ureg ); + + if (ureg->domain[0].tokens == error_tokens || + ureg->domain[1].tokens == error_tokens) { + debug_printf("%s: error in generated shader\n", __FUNCTION__); + assert(0); + return NULL; + } + + tokens = &ureg->domain[DOMAIN_DECL].tokens[0].token; + + if (0) { + debug_printf("%s: emitted shader %d tokens:\n", __FUNCTION__, + ureg->domain[DOMAIN_DECL].count); + tgsi_dump( tokens, 0 ); + } + +#if DEBUG + if (tokens && !tgsi_sanity_check(tokens)) { + debug_printf("tgsi_ureg.c, sanity check failed on generated tokens:\n"); + tgsi_dump(tokens, 0); + assert(0); + } +#endif + + + return tokens; +} + + +void *ureg_create_shader( struct ureg_program *ureg, + struct pipe_context *pipe ) +{ + struct pipe_shader_state state; + + state.tokens = ureg_finalize(ureg); + if(!state.tokens) + return NULL; + + if (ureg->processor == TGSI_PROCESSOR_VERTEX) + return pipe->create_vs_state( pipe, &state ); + else + return pipe->create_fs_state( pipe, &state ); +} + + +const struct tgsi_token *ureg_get_tokens( struct ureg_program *ureg, + unsigned *nr_tokens ) +{ + const struct tgsi_token *tokens; + + ureg_finalize(ureg); + + tokens = &ureg->domain[DOMAIN_DECL].tokens[0].token; + + if (nr_tokens) + *nr_tokens = ureg->domain[DOMAIN_DECL].size; + + ureg->domain[DOMAIN_DECL].tokens = 0; + ureg->domain[DOMAIN_DECL].size = 0; + ureg->domain[DOMAIN_DECL].order = 0; + ureg->domain[DOMAIN_DECL].count = 0; + + return tokens; +} + + +struct ureg_program *ureg_create( unsigned processor ) +{ + struct ureg_program *ureg = CALLOC_STRUCT( ureg_program ); + if (ureg == NULL) + return NULL; + + ureg->processor = processor; + return ureg; +} + + +void ureg_destroy( struct ureg_program *ureg ) +{ + unsigned i; + + for (i = 0; i < Elements(ureg->domain); i++) { + if (ureg->domain[i].tokens && + ureg->domain[i].tokens != error_tokens) + FREE(ureg->domain[i].tokens); + } + + FREE(ureg); +} diff --git a/src/gallium/auxiliary/tgsi/tgsi_ureg.h b/src/gallium/auxiliary/tgsi/tgsi_ureg.h new file mode 100644 index 0000000000..f04f443b9e --- /dev/null +++ b/src/gallium/auxiliary/tgsi/tgsi_ureg.h @@ -0,0 +1,619 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. + * All Rights Reserved. + * + * 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 VMWARE, INC 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. + * + **************************************************************************/ + +#ifndef TGSI_UREG_H +#define TGSI_UREG_H + +#include "pipe/p_compiler.h" +#include "pipe/p_shader_tokens.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct ureg_program; + +/* Almost a tgsi_src_register, but we need to pull in the Absolute + * flag from the _ext token. Indirect flag always implies ADDR[0]. + */ +struct ureg_src +{ + unsigned File : 4; /* TGSI_FILE_ */ + unsigned SwizzleX : 2; /* TGSI_SWIZZLE_ */ + unsigned SwizzleY : 2; /* TGSI_SWIZZLE_ */ + unsigned SwizzleZ : 2; /* TGSI_SWIZZLE_ */ + unsigned SwizzleW : 2; /* TGSI_SWIZZLE_ */ + unsigned Pad : 1; /* BOOL */ + unsigned Indirect : 1; /* BOOL */ + unsigned Absolute : 1; /* BOOL */ + int Index : 16; /* SINT */ + unsigned Negate : 1; /* BOOL */ + int IndirectIndex : 16; /* SINT */ + int IndirectSwizzle : 2; /* TGSI_SWIZZLE_ */ +}; + +/* Very similar to a tgsi_dst_register, removing unsupported fields + * and adding a Saturate flag. It's easier to push saturate into the + * destination register than to try and create a _SAT varient of each + * instruction function. + */ +struct ureg_dst +{ + unsigned File : 4; /* TGSI_FILE_ */ + unsigned WriteMask : 4; /* TGSI_WRITEMASK_ */ + unsigned Indirect : 1; /* BOOL */ + unsigned Saturate : 1; /* BOOL */ + int Index : 16; /* SINT */ + unsigned Pad1 : 5; + unsigned Pad2 : 1; /* BOOL */ + int IndirectIndex : 16; /* SINT */ + int IndirectSwizzle : 2; /* TGSI_SWIZZLE_ */ +}; + +struct pipe_context; + +struct ureg_program * +ureg_create( unsigned processor ); + +const struct tgsi_token * +ureg_finalize( struct ureg_program * ); + +/* Create and return a shader: + */ +void * +ureg_create_shader( struct ureg_program *, + struct pipe_context *pipe ); + + +/* Alternately, return the built token stream and hand ownership of + * that memory to the caller: + */ +const struct tgsi_token * +ureg_get_tokens( struct ureg_program *ureg, + unsigned *nr_tokens ); + + +void +ureg_destroy( struct ureg_program * ); + + +/*********************************************************************** + * Convenience routine: + */ +static INLINE void * +ureg_create_shader_and_destroy( struct ureg_program *p, + struct pipe_context *pipe ) +{ + void *result = ureg_create_shader( p, pipe ); + ureg_destroy( p ); + return result; +} + + + +/*********************************************************************** + * Build shader declarations: + */ + +struct ureg_src +ureg_DECL_fs_input( struct ureg_program *, + unsigned semantic_name, + unsigned semantic_index, + unsigned interp_mode ); + +struct ureg_src +ureg_DECL_vs_input( struct ureg_program *, + unsigned index ); + +struct ureg_dst +ureg_DECL_output( struct ureg_program *, + unsigned semantic_name, + unsigned semantic_index ); + +struct ureg_src +ureg_DECL_immediate( struct ureg_program *, + const float *v, + unsigned nr ); + +struct ureg_src +ureg_DECL_constant( struct ureg_program *, + unsigned index ); + +struct ureg_dst +ureg_DECL_temporary( struct ureg_program * ); + +void +ureg_release_temporary( struct ureg_program *ureg, + struct ureg_dst tmp ); + +struct ureg_dst +ureg_DECL_address( struct ureg_program * ); + +/* Supply an index to the sampler declaration as this is the hook to + * the external pipe_sampler state. Users of this function probably + * don't want just any sampler, but a specific one which they've set + * up state for in the context. + */ +struct ureg_src +ureg_DECL_sampler( struct ureg_program *, + unsigned index ); + + +static INLINE struct ureg_src +ureg_imm4f( struct ureg_program *ureg, + float a, float b, + float c, float d) +{ + float v[4]; + v[0] = a; + v[1] = b; + v[2] = c; + v[3] = d; + return ureg_DECL_immediate( ureg, v, 4 ); +} + +static INLINE struct ureg_src +ureg_imm3f( struct ureg_program *ureg, + float a, float b, + float c) +{ + float v[3]; + v[0] = a; + v[1] = b; + v[2] = c; + return ureg_DECL_immediate( ureg, v, 3 ); +} + +static INLINE struct ureg_src +ureg_imm2f( struct ureg_program *ureg, + float a, float b) +{ + float v[2]; + v[0] = a; + v[1] = b; + return ureg_DECL_immediate( ureg, v, 2 ); +} + +static INLINE struct ureg_src +ureg_imm1f( struct ureg_program *ureg, + float a) +{ + float v[1]; + v[0] = a; + return ureg_DECL_immediate( ureg, v, 1 ); +} + +/*********************************************************************** + * Functions for patching up labels + */ + + +/* Will return a number which can be used in a label to point to the + * next instruction to be emitted. + */ +unsigned +ureg_get_instruction_number( struct ureg_program *ureg ); + + +/* Patch a given label (expressed as a token number) to point to a + * given instruction (expressed as an instruction number). + * + * Labels are obtained from instruction emitters, eg ureg_CAL(). + * Instruction numbers are obtained from ureg_get_instruction_number(), + * above. + */ +void +ureg_fixup_label(struct ureg_program *ureg, + unsigned label_token, + unsigned instruction_number ); + + +/* Generic instruction emitter. Use if you need to pass the opcode as + * a parameter, rather than using the emit_OP() varients below. + */ +void +ureg_insn(struct ureg_program *ureg, + unsigned opcode, + const struct ureg_dst *dst, + unsigned nr_dst, + const struct ureg_src *src, + unsigned nr_src ); + + +void +ureg_tex_insn(struct ureg_program *ureg, + unsigned opcode, + const struct ureg_dst *dst, + unsigned nr_dst, + unsigned target, + const struct ureg_src *src, + unsigned nr_src ); + + +void +ureg_label_insn(struct ureg_program *ureg, + unsigned opcode, + const struct ureg_src *src, + unsigned nr_src, + unsigned *label); + + +/*********************************************************************** + * Internal instruction helpers, don't call these directly: + */ + +unsigned +ureg_emit_insn(struct ureg_program *ureg, + unsigned opcode, + boolean saturate, + unsigned num_dst, + unsigned num_src ); + +void +ureg_emit_label(struct ureg_program *ureg, + unsigned insn_token, + unsigned *label_token ); + +void +ureg_emit_texture(struct ureg_program *ureg, + unsigned insn_token, + unsigned target ); + +void +ureg_emit_dst( struct ureg_program *ureg, + struct ureg_dst dst ); + +void +ureg_emit_src( struct ureg_program *ureg, + struct ureg_src src ); + +void +ureg_fixup_insn_size(struct ureg_program *ureg, + unsigned insn ); + + +#define OP00( op ) \ +static INLINE void ureg_##op( struct ureg_program *ureg ) \ +{ \ + unsigned opcode = TGSI_OPCODE_##op; \ + unsigned insn = ureg_emit_insn( ureg, opcode, FALSE, 0, 0 ); \ + ureg_fixup_insn_size( ureg, insn ); \ +} + +#define OP01( op ) \ +static INLINE void ureg_##op( struct ureg_program *ureg, \ + struct ureg_src src ) \ +{ \ + unsigned opcode = TGSI_OPCODE_##op; \ + unsigned insn = ureg_emit_insn( ureg, opcode, FALSE, 0, 1 ); \ + ureg_emit_src( ureg, src ); \ + ureg_fixup_insn_size( ureg, insn ); \ +} + +#define OP00_LBL( op ) \ +static INLINE void ureg_##op( struct ureg_program *ureg, \ + unsigned *label_token ) \ +{ \ + unsigned opcode = TGSI_OPCODE_##op; \ + unsigned insn = ureg_emit_insn( ureg, opcode, FALSE, 0, 0 ); \ + ureg_emit_label( ureg, insn, label_token ); \ + ureg_fixup_insn_size( ureg, insn ); \ +} + +#define OP01_LBL( op ) \ +static INLINE void ureg_##op( struct ureg_program *ureg, \ + struct ureg_src src, \ + unsigned *label_token ) \ +{ \ + unsigned opcode = TGSI_OPCODE_##op; \ + unsigned insn = ureg_emit_insn( ureg, opcode, FALSE, 0, 1 ); \ + ureg_emit_label( ureg, insn, label_token ); \ + ureg_emit_src( ureg, src ); \ + ureg_fixup_insn_size( ureg, insn ); \ +} + +#define OP10( op ) \ +static INLINE void ureg_##op( struct ureg_program *ureg, \ + struct ureg_dst dst ) \ +{ \ + unsigned opcode = TGSI_OPCODE_##op; \ + unsigned insn = ureg_emit_insn( ureg, opcode, dst.Saturate, 1, 0 ); \ + ureg_emit_dst( ureg, dst ); \ + ureg_fixup_insn_size( ureg, insn ); \ +} + + +#define OP11( op ) \ +static INLINE void ureg_##op( struct ureg_program *ureg, \ + struct ureg_dst dst, \ + struct ureg_src src ) \ +{ \ + unsigned opcode = TGSI_OPCODE_##op; \ + unsigned insn = ureg_emit_insn( ureg, opcode, dst.Saturate, 1, 1 ); \ + ureg_emit_dst( ureg, dst ); \ + ureg_emit_src( ureg, src ); \ + ureg_fixup_insn_size( ureg, insn ); \ +} + +#define OP12( op ) \ +static INLINE void ureg_##op( struct ureg_program *ureg, \ + struct ureg_dst dst, \ + struct ureg_src src0, \ + struct ureg_src src1 ) \ +{ \ + unsigned opcode = TGSI_OPCODE_##op; \ + unsigned insn = ureg_emit_insn( ureg, opcode, dst.Saturate, 1, 2 ); \ + ureg_emit_dst( ureg, dst ); \ + ureg_emit_src( ureg, src0 ); \ + ureg_emit_src( ureg, src1 ); \ + ureg_fixup_insn_size( ureg, insn ); \ +} + +#define OP12_TEX( op ) \ +static INLINE void ureg_##op( struct ureg_program *ureg, \ + struct ureg_dst dst, \ + unsigned target, \ + struct ureg_src src0, \ + struct ureg_src src1 ) \ +{ \ + unsigned opcode = TGSI_OPCODE_##op; \ + unsigned insn = ureg_emit_insn( ureg, opcode, dst.Saturate, 1, 2 ); \ + ureg_emit_texture( ureg, insn, target ); \ + ureg_emit_dst( ureg, dst ); \ + ureg_emit_src( ureg, src0 ); \ + ureg_emit_src( ureg, src1 ); \ + ureg_fixup_insn_size( ureg, insn ); \ +} + +#define OP13( op ) \ +static INLINE void ureg_##op( struct ureg_program *ureg, \ + struct ureg_dst dst, \ + struct ureg_src src0, \ + struct ureg_src src1, \ + struct ureg_src src2 ) \ +{ \ + unsigned opcode = TGSI_OPCODE_##op; \ + unsigned insn = ureg_emit_insn( ureg, opcode, dst.Saturate, 1, 3 ); \ + ureg_emit_dst( ureg, dst ); \ + ureg_emit_src( ureg, src0 ); \ + ureg_emit_src( ureg, src1 ); \ + ureg_emit_src( ureg, src2 ); \ + ureg_fixup_insn_size( ureg, insn ); \ +} + +#define OP14_TEX( op ) \ +static INLINE void ureg_##op( struct ureg_program *ureg, \ + struct ureg_dst dst, \ + unsigned target, \ + struct ureg_src src0, \ + struct ureg_src src1, \ + struct ureg_src src2, \ + struct ureg_src src3 ) \ +{ \ + unsigned opcode = TGSI_OPCODE_##op; \ + unsigned insn = ureg_emit_insn( ureg, opcode, dst.Saturate, 1, 4 ); \ + ureg_emit_texture( ureg, insn, target ); \ + ureg_emit_dst( ureg, dst ); \ + ureg_emit_src( ureg, src0 ); \ + ureg_emit_src( ureg, src1 ); \ + ureg_emit_src( ureg, src2 ); \ + ureg_emit_src( ureg, src3 ); \ + ureg_fixup_insn_size( ureg, insn ); \ +} + + +/* Use a template include to generate a correctly-typed ureg_OP() + * function for each TGSI opcode: + */ +#include "tgsi_opcode_tmp.h" + + +/*********************************************************************** + * Inline helpers for manipulating register structs: + */ +static INLINE struct ureg_src +ureg_negate( struct ureg_src reg ) +{ + assert(reg.File != TGSI_FILE_NULL); + reg.Negate ^= 1; + return reg; +} + +static INLINE struct ureg_src +ureg_abs( struct ureg_src reg ) +{ + assert(reg.File != TGSI_FILE_NULL); + reg.Absolute = 1; + reg.Negate = 0; + return reg; +} + +static INLINE struct ureg_src +ureg_swizzle( struct ureg_src reg, + int x, int y, int z, int w ) +{ + unsigned swz = ( (reg.SwizzleX << 0) | + (reg.SwizzleY << 2) | + (reg.SwizzleZ << 4) | + (reg.SwizzleW << 6)); + + assert(reg.File != TGSI_FILE_NULL); + assert(x < 4); + assert(y < 4); + assert(z < 4); + assert(w < 4); + + reg.SwizzleX = (swz >> (x*2)) & 0x3; + reg.SwizzleY = (swz >> (y*2)) & 0x3; + reg.SwizzleZ = (swz >> (z*2)) & 0x3; + reg.SwizzleW = (swz >> (w*2)) & 0x3; + return reg; +} + +static INLINE struct ureg_src +ureg_scalar( struct ureg_src reg, int x ) +{ + return ureg_swizzle(reg, x, x, x, x); +} + +static INLINE struct ureg_dst +ureg_writemask( struct ureg_dst reg, + unsigned writemask ) +{ + assert(reg.File != TGSI_FILE_NULL); + reg.WriteMask &= writemask; + return reg; +} + +static INLINE struct ureg_dst +ureg_saturate( struct ureg_dst reg ) +{ + assert(reg.File != TGSI_FILE_NULL); + reg.Saturate = 1; + return reg; +} + +static INLINE struct ureg_dst +ureg_dst_indirect( struct ureg_dst reg, struct ureg_src addr ) +{ + assert(reg.File != TGSI_FILE_NULL); + assert(addr.File == TGSI_FILE_ADDRESS); + reg.Indirect = 1; + reg.IndirectIndex = addr.Index; + reg.IndirectSwizzle = addr.SwizzleX; + return reg; +} + +static INLINE struct ureg_src +ureg_src_indirect( struct ureg_src reg, struct ureg_src addr ) +{ + assert(reg.File != TGSI_FILE_NULL); + assert(addr.File == TGSI_FILE_ADDRESS); + reg.Indirect = 1; + reg.IndirectIndex = addr.Index; + reg.IndirectSwizzle = addr.SwizzleX; + return reg; +} + +static INLINE struct ureg_dst +ureg_dst( struct ureg_src src ) +{ + struct ureg_dst dst; + + dst.File = src.File; + dst.WriteMask = TGSI_WRITEMASK_XYZW; + dst.Indirect = src.Indirect; + dst.IndirectIndex = src.IndirectIndex; + dst.IndirectSwizzle = src.IndirectSwizzle; + dst.Saturate = 0; + dst.Index = src.Index; + dst.Pad1 = 0; + dst.Pad2 = 0; + + return dst; +} + +static INLINE struct ureg_src +ureg_src( struct ureg_dst dst ) +{ + struct ureg_src src; + + src.File = dst.File; + src.SwizzleX = TGSI_SWIZZLE_X; + src.SwizzleY = TGSI_SWIZZLE_Y; + src.SwizzleZ = TGSI_SWIZZLE_Z; + src.SwizzleW = TGSI_SWIZZLE_W; + src.Pad = 0; + src.Indirect = dst.Indirect; + src.IndirectIndex = dst.IndirectIndex; + src.IndirectSwizzle = dst.IndirectSwizzle; + src.Absolute = 0; + src.Index = dst.Index; + src.Negate = 0; + + return src; +} + + + +static INLINE struct ureg_dst +ureg_dst_undef( void ) +{ + struct ureg_dst dst; + + dst.File = TGSI_FILE_NULL; + dst.WriteMask = 0; + dst.Indirect = 0; + dst.IndirectIndex = 0; + dst.IndirectSwizzle = 0; + dst.Saturate = 0; + dst.Index = 0; + dst.Pad1 = 0; + dst.Pad2 = 0; + + return dst; +} + +static INLINE struct ureg_src +ureg_src_undef( void ) +{ + struct ureg_src src; + + src.File = TGSI_FILE_NULL; + src.SwizzleX = 0; + src.SwizzleY = 0; + src.SwizzleZ = 0; + src.SwizzleW = 0; + src.Pad = 0; + src.Indirect = 0; + src.IndirectIndex = 0; + src.IndirectSwizzle = 0; + src.Absolute = 0; + src.Index = 0; + src.Negate = 0; + + return src; +} + +static INLINE boolean +ureg_src_is_undef( struct ureg_src src ) +{ + return src.File == TGSI_FILE_NULL; +} + +static INLINE boolean +ureg_dst_is_undef( struct ureg_dst dst ) +{ + return dst.File == TGSI_FILE_NULL; +} + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/gallium/auxiliary/tgsi/tgsi_util.h b/src/gallium/auxiliary/tgsi/tgsi_util.h index 7877f34558..21eb656327 100644 --- a/src/gallium/auxiliary/tgsi/tgsi_util.h +++ b/src/gallium/auxiliary/tgsi/tgsi_util.h @@ -32,6 +32,10 @@ extern "C" { #endif +struct tgsi_src_register; +struct tgsi_src_register_ext_swz; +struct tgsi_full_src_register; + void * tgsi_align_128bit( void *unaligned ); |