diff options
| author | Michal Krol <michal@vmware.com> | 2010-01-01 23:44:00 +0100 | 
|---|---|---|
| committer | Michal Krol <michal@vmware.com> | 2010-01-05 09:28:25 +0100 | 
| commit | 062aab96e015021f3b83067848495a8ce2d92456 (patch) | |
| tree | b5cf9c12a7445c02eef2626f5924c65a9b93953f | |
| parent | 08a3efee10034d9bd8809eb6707a372b81ea3957 (diff) | |
gallium: Add SWITCH, CASE, DEFAULT and ENDSWITCH opcodes to TGSI.
Provide reference implementation of them in tgsi_exec.
Note that BREAK opcode is overloaded and can be used to break out
of either a loop or a switch-case statement.
| -rw-r--r-- | src/gallium/auxiliary/tgsi/tgsi_exec.c | 150 | ||||
| -rw-r--r-- | src/gallium/auxiliary/tgsi/tgsi_exec.h | 34 | ||||
| -rw-r--r-- | src/gallium/auxiliary/tgsi/tgsi_info.c | 6 | ||||
| -rw-r--r-- | src/gallium/include/pipe/p_shader_tokens.h | 6 | 
4 files changed, 184 insertions, 12 deletions
| diff --git a/src/gallium/auxiliary/tgsi/tgsi_exec.c b/src/gallium/auxiliary/tgsi/tgsi_exec.c index e2f69850c6..0a276483c4 100644 --- a/src/gallium/auxiliary/tgsi/tgsi_exec.c +++ b/src/gallium/auxiliary/tgsi/tgsi_exec.c @@ -123,7 +123,7 @@  /** The execution mask depends on the conditional mask and the loop mask */  #define UPDATE_EXEC_MASK(MACH) \ -      MACH->ExecMask = MACH->CondMask & MACH->LoopMask & MACH->ContMask & MACH->FuncMask +      MACH->ExecMask = MACH->CondMask & MACH->LoopMask & MACH->ContMask & MACH->Switch.mask & MACH->FuncMask  static const union tgsi_exec_channel ZeroVec = @@ -1796,6 +1796,90 @@ exec_vector_trinary(struct tgsi_exec_machine *mach,  }  static void +exec_break(struct tgsi_exec_machine *mach) +{ +   if (mach->BreakType == TGSI_EXEC_BREAK_INSIDE_LOOP) { +      /* turn off loop channels for each enabled exec channel */ +      mach->LoopMask &= ~mach->ExecMask; +      /* Todo: if mach->LoopMask == 0, jump to end of loop */ +      UPDATE_EXEC_MASK(mach); +   } else { +      assert(mach->BreakType == TGSI_EXEC_BREAK_INSIDE_SWITCH); + +      mach->Switch.mask = 0x0; + +      UPDATE_EXEC_MASK(mach); +   } +} + +static void +exec_switch(struct tgsi_exec_machine *mach, +            const struct tgsi_full_instruction *inst) +{ +   assert(mach->SwitchStackTop < TGSI_EXEC_MAX_SWITCH_NESTING); +   assert(mach->BreakStackTop < TGSI_EXEC_MAX_BREAK_STACK); + +   mach->SwitchStack[mach->SwitchStackTop++] = mach->Switch; +   fetch_source(mach, &mach->Switch.selector, &inst->Src[0], CHAN_X); +   mach->Switch.mask = 0x0; +   mach->Switch.defaultMask = 0x0; + +   mach->BreakStack[mach->BreakStackTop++] = mach->BreakType; +   mach->BreakType = TGSI_EXEC_BREAK_INSIDE_SWITCH; + +   UPDATE_EXEC_MASK(mach); +} + +static void +exec_case(struct tgsi_exec_machine *mach, +          const struct tgsi_full_instruction *inst) +{ +   uint prevMask = mach->SwitchStack[mach->SwitchStackTop - 1].mask; +   union tgsi_exec_channel src; +   uint mask = 0; + +   fetch_source(mach, &src, &inst->Src[0], CHAN_X); + +   if (mach->Switch.selector.u[0] == src.u[0]) { +      mask |= 0x1; +   } +   if (mach->Switch.selector.u[1] == src.u[1]) { +      mask |= 0x2; +   } +   if (mach->Switch.selector.u[2] == src.u[2]) { +      mask |= 0x4; +   } +   if (mach->Switch.selector.u[3] == src.u[3]) { +      mask |= 0x8; +   } + +   mach->Switch.defaultMask |= mask; + +   mach->Switch.mask |= mask & prevMask; + +   UPDATE_EXEC_MASK(mach); +} + +static void +exec_default(struct tgsi_exec_machine *mach) +{ +   uint prevMask = mach->SwitchStack[mach->SwitchStackTop - 1].mask; + +   mach->Switch.mask |= ~mach->Switch.defaultMask & prevMask; + +   UPDATE_EXEC_MASK(mach); +} + +static void +exec_endswitch(struct tgsi_exec_machine *mach) +{ +   mach->Switch = mach->SwitchStack[--mach->SwitchStackTop]; +   mach->BreakType = mach->BreakStack[--mach->BreakStackTop]; + +   UPDATE_EXEC_MASK(mach); +} + +static void  micro_i2f(union tgsi_exec_channel *dst,            const union tgsi_exec_channel *src)  { @@ -2841,6 +2925,8 @@ exec_instruction(           mach->CallStack[mach->CallStackTop].CondStackTop = mach->CondStackTop;           mach->CallStack[mach->CallStackTop].LoopStackTop = mach->LoopStackTop;           mach->CallStack[mach->CallStackTop].ContStackTop = mach->ContStackTop; +         mach->CallStack[mach->CallStackTop].SwitchStackTop = mach->SwitchStackTop; +         mach->CallStack[mach->CallStackTop].BreakStackTop = mach->BreakStackTop;           /* note that PC was already incremented above */           mach->CallStack[mach->CallStackTop].ReturnAddr = *pc; @@ -2848,12 +2934,17 @@ exec_instruction(           /* 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->SwitchStackTop < TGSI_EXEC_MAX_SWITCH_NESTING); +         assert(mach->BreakStackTop < TGSI_EXEC_MAX_BREAK_STACK);           assert(mach->FuncStackTop < TGSI_EXEC_MAX_CALL_NESTING); + +         mach->CondStack[mach->CondStackTop++] = mach->CondMask; +         mach->LoopStack[mach->LoopStackTop++] = mach->LoopMask; +         mach->ContStack[mach->ContStackTop++] = mach->ContMask; +         mach->SwitchStack[mach->SwitchStackTop++] = mach->Switch; +         mach->BreakStack[mach->BreakStackTop++] = mach->BreakType;           mach->FuncStack[mach->FuncStackTop++] = mach->FuncMask;           /* Finally, jump to the subroutine */ @@ -2886,6 +2977,12 @@ exec_instruction(           mach->ContStackTop = mach->CallStack[mach->CallStackTop].ContStackTop;           mach->ContMask = mach->ContStack[mach->ContStackTop]; +         mach->SwitchStackTop = mach->CallStack[mach->CallStackTop].SwitchStackTop; +         mach->Switch = mach->SwitchStack[mach->SwitchStackTop]; + +         mach->BreakStackTop = mach->CallStack[mach->CallStackTop].BreakStackTop; +         mach->BreakType = mach->BreakStack[mach->BreakStackTop]; +           assert(mach->FuncStackTop > 0);           mach->FuncMask = mach->FuncStack[--mach->FuncStackTop]; @@ -3180,11 +3277,15 @@ exec_instruction(     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); +      assert(mach->BreakStackTop < TGSI_EXEC_MAX_BREAK_STACK); + +      mach->LoopStack[mach->LoopStackTop++] = mach->LoopMask; +      mach->ContStack[mach->ContStackTop++] = mach->ContMask;        mach->LoopLabelStack[mach->LoopLabelStackTop++] = *pc - 1; +      mach->BreakStack[mach->BreakStackTop++] = mach->BreakType; +      mach->BreakType = TGSI_EXEC_BREAK_INSIDE_LOOP;        break;     case TGSI_OPCODE_ENDFOR: @@ -3231,6 +3332,8 @@ exec_instruction(           --mach->LoopLabelStackTop;           assert(mach->LoopCounterStackTop > 0);           --mach->LoopCounterStackTop; + +         mach->BreakType = mach->BreakStack[--mach->BreakStackTop];        }        UPDATE_EXEC_MASK(mach);        break; @@ -3254,15 +3357,14 @@ exec_instruction(           mach->ContMask = mach->ContStack[--mach->ContStackTop];           assert(mach->LoopLabelStackTop > 0);           --mach->LoopLabelStackTop; + +         mach->BreakType = mach->BreakStack[--mach->BreakStackTop];        }        UPDATE_EXEC_MASK(mach);        break;     case TGSI_OPCODE_BRK: -      /* turn off loop channels for each enabled exec channel */ -      mach->LoopMask &= ~mach->ExecMask; -      /* Todo: if mach->LoopMask == 0, jump to end of loop */ -      UPDATE_EXEC_MASK(mach); +      exec_break(mach);        break;     case TGSI_OPCODE_CONT: @@ -3293,6 +3395,12 @@ exec_instruction(        mach->ContStackTop = mach->CallStack[mach->CallStackTop].ContStackTop;        mach->ContMask = mach->ContStack[mach->ContStackTop]; +      mach->SwitchStackTop = mach->CallStack[mach->CallStackTop].SwitchStackTop; +      mach->Switch = mach->SwitchStack[mach->SwitchStackTop]; + +      mach->BreakStackTop = mach->CallStack[mach->CallStackTop].BreakStackTop; +      mach->BreakType = mach->BreakStack[mach->BreakStackTop]; +        assert(mach->FuncStackTop > 0);        mach->FuncMask = mach->FuncStack[--mach->FuncStackTop]; @@ -3407,6 +3515,22 @@ exec_instruction(        exec_vector_binary(mach, inst, micro_usne);        break; +   case TGSI_OPCODE_SWITCH: +      exec_switch(mach, inst); +      break; + +   case TGSI_OPCODE_CASE: +      exec_case(mach, inst); +      break; + +   case TGSI_OPCODE_DEFAULT: +      exec_default(mach); +      break; + +   case TGSI_OPCODE_ENDSWITCH: +      exec_endswitch(mach); +      break; +     default:        assert( 0 );     } @@ -3431,9 +3555,13 @@ tgsi_exec_machine_run( struct tgsi_exec_machine *mach )     mach->FuncMask = 0xf;     mach->ExecMask = 0xf; +   mach->Switch.mask = 0xf; +     assert(mach->CondStackTop == 0);     assert(mach->LoopStackTop == 0);     assert(mach->ContStackTop == 0); +   assert(mach->SwitchStackTop == 0); +   assert(mach->BreakStackTop == 0);     assert(mach->CallStackTop == 0);     mach->Temps[TEMP_KILMASK_I].xyzw[TEMP_KILMASK_C].u[0] = 0; @@ -3534,6 +3662,8 @@ tgsi_exec_machine_run( struct tgsi_exec_machine *mach )     assert(mach->CondStackTop == 0);     assert(mach->LoopStackTop == 0);     assert(mach->ContStackTop == 0); +   assert(mach->SwitchStackTop == 0); +   assert(mach->BreakStackTop == 0);     assert(mach->CallStackTop == 0);     return ~mach->Temps[TEMP_KILMASK_I].xyzw[TEMP_KILMASK_C].u[0]; diff --git a/src/gallium/auxiliary/tgsi/tgsi_exec.h b/src/gallium/auxiliary/tgsi/tgsi_exec.h index afaf5c39c4..aa3a98d7f1 100644 --- a/src/gallium/auxiliary/tgsi/tgsi_exec.h +++ b/src/gallium/auxiliary/tgsi/tgsi_exec.h @@ -179,6 +179,7 @@ struct tgsi_exec_labels  #define TGSI_EXEC_MAX_COND_NESTING  32  #define TGSI_EXEC_MAX_LOOP_NESTING  32 +#define TGSI_EXEC_MAX_SWITCH_NESTING 32  #define TGSI_EXEC_MAX_CALL_NESTING  32  /* The maximum number of input attributes per vertex. For 2D @@ -206,9 +207,29 @@ struct tgsi_call_record     uint CondStackTop;     uint LoopStackTop;     uint ContStackTop; +   int SwitchStackTop; +   int BreakStackTop;     uint ReturnAddr;  }; + +/* Switch-case block state. */ +struct tgsi_switch_record { +   uint mask;                          /**< execution mask */ +   union tgsi_exec_channel selector;   /**< a value case statements are compared to */ +   uint defaultMask;                   /**< non-execute mask for default case */ +}; + + +enum tgsi_break_type { +   TGSI_EXEC_BREAK_INSIDE_LOOP, +   TGSI_EXEC_BREAK_INSIDE_SWITCH +}; + + +#define TGSI_EXEC_MAX_BREAK_STACK (TGSI_EXEC_MAX_LOOP_NESTING + TGSI_EXEC_MAX_SWITCH_NESTING) + +  /**   * Run-time virtual machine state for executing TGSI shader.   */ @@ -251,6 +272,12 @@ struct tgsi_exec_machine     uint FuncMask;  /**< For function calls */     uint ExecMask;  /**< = CondMask & LoopMask */ +   /* Current switch-case state. */ +   struct tgsi_switch_record Switch; + +   /* Current break type. */ +   enum tgsi_break_type BreakType; +     /** Condition mask stack (for nested conditionals) */     uint CondStack[TGSI_EXEC_MAX_COND_NESTING];     int CondStackTop; @@ -271,6 +298,13 @@ struct tgsi_exec_machine     uint ContStack[TGSI_EXEC_MAX_LOOP_NESTING];     int ContStackTop; +   /** Switch case stack */ +   struct tgsi_switch_record SwitchStack[TGSI_EXEC_MAX_SWITCH_NESTING]; +   int SwitchStackTop; + +   enum tgsi_break_type BreakStack[TGSI_EXEC_MAX_BREAK_STACK]; +   int BreakStackTop; +     /** Function execution mask stack (for executing subroutine code) */     uint FuncStack[TGSI_EXEC_MAX_CALL_NESTING];     int FuncStackTop; diff --git a/src/gallium/auxiliary/tgsi/tgsi_info.c b/src/gallium/auxiliary/tgsi/tgsi_info.c index c7cdd163ec..8e0635677a 100644 --- a/src/gallium/auxiliary/tgsi/tgsi_info.c +++ b/src/gallium/auxiliary/tgsi/tgsi_info.c @@ -170,7 +170,11 @@ static const struct tgsi_opcode_info opcode_info[TGSI_OPCODE_LAST] =     { 1, 2, 0, 0, 0, 0, "USGE", TGSI_OPCODE_USGE },     { 1, 2, 0, 0, 0, 0, "USHR", TGSI_OPCODE_USHR },     { 1, 2, 0, 0, 0, 0, "USLT", TGSI_OPCODE_USLT }, -   { 1, 2, 0, 0, 0, 0, "USNE", TGSI_OPCODE_USNE } +   { 1, 2, 0, 0, 0, 0, "USNE", TGSI_OPCODE_USNE }, +   { 0, 1, 0, 0, 0, 0, "SWITCH", TGSI_OPCODE_SWITCH }, +   { 0, 1, 0, 0, 0, 0, "CASE", TGSI_OPCODE_CASE }, +   { 0, 0, 0, 0, 0, 0, "DEFAULT", TGSI_OPCODE_DEFAULT }, +   { 0, 0, 0, 0, 0, 0, "ENDSWITCH", TGSI_OPCODE_ENDSWITCH }  };  const struct tgsi_opcode_info * diff --git a/src/gallium/include/pipe/p_shader_tokens.h b/src/gallium/include/pipe/p_shader_tokens.h index a12afbcb5c..f8d4a45dfd 100644 --- a/src/gallium/include/pipe/p_shader_tokens.h +++ b/src/gallium/include/pipe/p_shader_tokens.h @@ -314,7 +314,11 @@ struct tgsi_property_data {  #define TGSI_OPCODE_USHR                137  #define TGSI_OPCODE_USLT                138  #define TGSI_OPCODE_USNE                139 -#define TGSI_OPCODE_LAST                140 +#define TGSI_OPCODE_SWITCH              140 +#define TGSI_OPCODE_CASE                141 +#define TGSI_OPCODE_DEFAULT             142 +#define TGSI_OPCODE_ENDSWITCH           143 +#define TGSI_OPCODE_LAST                144  #define TGSI_SAT_NONE            0  /* do not saturate */  #define TGSI_SAT_ZERO_ONE        1  /* clamp to [0,1] */ | 
