tgsi: add tgsi_ureg, a simplified tgsi shader builder
authorKeith Whitwell <keithw@vmware.com>
Thu, 13 Aug 2009 11:38:58 +0000 (12:38 +0100)
committerKeith Whitwell <keithw@vmware.com>
Thu, 13 Aug 2009 12:02:47 +0000 (13:02 +0100)
This is modelled on the nice & easy-to-use facilities we had
for building shaders in mesa, eg. in texenvprogram.c and friends.

Key points include pass-by-value register structs that can be manipulated
in a functional style, eg:

   negate(swizzle(reg, X,X,X,X))

and per-opcode instruction functions, eg:

   emit_MOV( p, writemask(dst, 0x1), negate(src));

and similar.

Additionally, the interface allows mixed emit of instructions and decls,
which are sorted out internally to obey TGSI ordering.

Immediates may be emitted at any time and are scanned against existing
immediates to try and reduce redundancy.

Not all TGSI functionality is accessible through this interface, but
most or all of what mesa uses should be.

src/gallium/auxiliary/tgsi/Makefile
src/gallium/auxiliary/tgsi/SConscript
src/gallium/auxiliary/tgsi/tgsi_opcode_tmp.h [new file with mode: 0644]
src/gallium/auxiliary/tgsi/tgsi_ureg.c [new file with mode: 0644]
src/gallium/auxiliary/tgsi/tgsi_ureg.h [new file with mode: 0644]

index b4900e8dbaa2f91e4a1ad942e1fd0700d075d22b..5f0a580b0966a1aed0d9d353701125aff78d92e2 100644 (file)
@@ -16,6 +16,7 @@ C_SOURCES = \
        tgsi_sse2.c \
        tgsi_text.c \
        tgsi_transform.c \
+       tgsi_ureg.c \
        tgsi_util.c
 
 include ../../Makefile.template
index 8200cce42f57cdd36d0717ea9176255f21ac9dd5..b6bc2924f06d6bfaa1a1ede85dcb757fe374eba5 100644 (file)
@@ -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_opcode_tmp.h b/src/gallium/auxiliary/tgsi/tgsi_opcode_tmp.h
new file mode 100644 (file)
index 0000000..ed594a3
--- /dev/null
@@ -0,0 +1,173 @@
+/**************************************************************************
+ * 
+ * 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(CND0)
+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_ureg.c b/src/gallium/auxiliary/tgsi/tgsi_ureg.c
new file mode 100644 (file)
index 0000000..00ae0e3
--- /dev/null
@@ -0,0 +1,771 @@
+/**************************************************************************
+ * 
+ * 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_dump.h"
+#include "util/u_memory.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_IMMEDIATE 32
+
+#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;
+   } input[UREG_MAX_INPUT];
+   unsigned nr_inputs;
+
+   struct {
+      unsigned semantic_name;
+      unsigned semantic_index;
+   } output[UREG_MAX_OUTPUT];
+   unsigned nr_outputs;
+
+   struct {
+      float v[4];
+      unsigned nr;
+   } immediate[UREG_MAX_OUTPUT];
+   unsigned nr_immediates;
+
+
+   unsigned nr_constants;
+   unsigned nr_temps;
+   unsigned nr_samplers;
+
+   struct ureg_tokens domain[2];
+};
+
+static union tgsi_any_token error_tokens[32];
+
+static void tokens_error( struct ureg_tokens *tokens )
+{
+   tokens->tokens = error_tokens;
+   tokens->size = Elements(error_tokens);
+   tokens->count = 0;
+}
+
+
+static void tokens_expand( struct ureg_tokens *tokens,
+                           unsigned count )
+{
+   union tgsi_any_token *tmp;
+
+   if (tokens->tokens == error_tokens)
+      goto fail;
+
+   while (tokens->count + count > tokens->size) {
+      tokens->size = (1 << ++tokens->order);
+   }
+
+   tmp = MALLOC(tokens->size * sizeof(unsigned));
+   if (tmp == NULL) {
+      FREE(tokens->tokens);
+      goto fail;
+   }
+
+   if (tokens->count) {
+      memcpy(tmp, tokens->tokens, tokens->count * sizeof tokens->tokens[0] );
+      FREE(tokens->tokens);
+   }
+
+   tokens->tokens = tmp;
+   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.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.Absolute = 0;
+   src.Index    = index;
+   src.Negate   = 0;
+
+   return src;
+}
+
+
+
+
+static struct ureg_src 
+ureg_DECL_input( struct ureg_program *ureg,
+                 unsigned name,
+                 unsigned index,
+                 unsigned interp_mode )
+{
+   unsigned i;
+
+   for (i = 0; i < ureg->nr_inputs; i++) {
+      if (ureg->input[i].semantic_name == name &&
+          ureg->input[i].semantic_index == index) 
+         goto out;
+   }
+
+   if (ureg->nr_inputs < UREG_MAX_INPUT) {
+      ureg->input[i].semantic_name = name;
+      ureg->input[i].semantic_index = index;
+      ureg->input[i].interp = interp_mode;
+      ureg->nr_inputs++;
+   }
+   else {
+      set_bad( ureg );
+   }
+
+out:
+   return ureg_src_register( TGSI_FILE_INPUT, i );
+}
+
+
+
+struct ureg_src 
+ureg_DECL_fs_input( struct ureg_program *ureg,
+                    unsigned name,
+                    unsigned index,
+                    unsigned interp )
+{
+   return ureg_DECL_input( ureg, name, index, interp );
+}
+
+
+struct ureg_src 
+ureg_DECL_vs_input( struct ureg_program *ureg,
+                    unsigned name,
+                    unsigned index )
+{
+   return ureg_DECL_input( ureg, name, index, TGSI_INTERPOLATE_CONSTANT );
+}
+
+
+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 )
+{
+   return ureg_src_register( TGSI_FILE_TEMPORARY, ureg->nr_constants++ );
+}
+
+
+/* Allocate a new temporary.  No way to release temporaries in this code. 
+ */
+struct ureg_dst ureg_DECL_temporary( struct ureg_program *ureg )
+{
+   return ureg_dst_register( TGSI_FILE_TEMPORARY, ureg->nr_temps++ );
+}
+
+
+/* Allocate a new sampler.
+ */
+struct ureg_src ureg_DECL_sampler( struct ureg_program *ureg )
+{
+   return ureg_src_register( TGSI_FILE_SAMPLER, ureg->nr_samplers++ );
+}
+
+
+
+
+static int match_or_expand_immediate( const float *v,
+                                      unsigned nr,
+                                      float *v2,
+                                      unsigned *nr2,
+                                      unsigned *swizzle )
+{
+   unsigned i, j;
+
+   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;
+   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:
+   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;
+
+   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.Indirect = src.Indirect;
+   out[n].src.Index = src.Index;
+   n++;
+   
+   if (src.Absolute) {
+      out[n].value = 0;
+      out[n].src_ext_mod.Absolute = 1;
+      n++;
+   }
+
+   if (src.Indirect) {
+      out[n].value = 0;
+      out[n].src.File = TGSI_FILE_ADDRESS;
+      out[n].src.SwizzleX = TGSI_SWIZZLE_X;
+      out[n].src.SwizzleY = TGSI_SWIZZLE_X;
+      out[n].src.SwizzleZ = TGSI_SWIZZLE_X;
+      out[n].src.SwizzleW = TGSI_SWIZZLE_X;
+      out[n].src.Indirect = 0;
+      out[n].src.Index = 0;
+      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;
+
+   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 = TGSI_SWIZZLE_X;
+      out[n].src.SwizzleY = TGSI_SWIZZLE_X;
+      out[n].src.SwizzleZ = TGSI_SWIZZLE_X;
+      out[n].src.SwizzleW = TGSI_SWIZZLE_X;
+      out[n].src.Indirect = 0;
+      out[n].src.Index = 0;
+      n++;
+   }
+
+   assert(n == size);
+}
+
+
+
+unsigned
+ureg_emit_insn(struct ureg_program *ureg,
+               unsigned opcode,
+               boolean saturate,
+               unsigned num_dst,
+               unsigned num_src )
+{
+   union tgsi_any_token *out;
+
+   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.NrTokens = 0;
+   out[0].insn.NumDstRegs = num_dst;
+   out[0].insn.NumSrcRegs = num_src;
+   out[0].insn.Padding = 0;
+   out[0].insn.Extended = 0;
+
+   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;
+
+   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;
+}
+
+
+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 );
+
+   out->insn.NrTokens = ureg->domain[DOMAIN_INSN].count - insn - 1;
+}
+
+
+
+
+
+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;
+
+   for (i = 0; i < ureg->nr_inputs; i++) {
+      emit_decl( ureg, 
+                 TGSI_FILE_INPUT, 
+                 i,
+                 ureg->input[i].semantic_name,
+                 ureg->input[i].semantic_index,
+                 ureg->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 );
+   }
+
+   if (ureg->nr_samplers) {
+      emit_decl_range( ureg, 
+                       TGSI_FILE_SAMPLER,
+                       0, ureg->nr_samplers );
+   }
+
+   if (ureg->nr_constants) {
+      emit_decl_range( ureg,
+                       TGSI_FILE_CONSTANT,
+                       0, ureg->nr_constants );
+   }
+
+   if (ureg->nr_temps) {
+      emit_decl_range( ureg,
+                       TGSI_FILE_TEMPORARY,
+                       0, ureg->nr_temps );
+   }
+
+   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,
+                     unsigned insn )
+{
+   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;
+}
+
+
+void *ureg_create_shader( struct ureg_program *ureg )
+{
+   struct pipe_shader_state state;
+   unsigned insn;
+
+   emit_header( ureg );
+   emit_decls( ureg );
+   copy_instructions( ureg );
+   fixup_header_size( ureg, insn );
+   
+   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;
+   }
+
+   state.tokens = (const struct tgsi_token *)ureg->domain[DOMAIN_DECL].tokens;
+
+   if (1) {
+      debug_printf("%s: emitted shader %d tokens:\n", __FUNCTION__, 
+                   ureg->domain[DOMAIN_DECL].count);
+      tgsi_dump( state.tokens, 0 );
+   }
+
+   if (ureg->processor == TGSI_PROCESSOR_VERTEX)
+      return ureg->pipe->create_vs_state( ureg->pipe, &state );
+   else
+      return ureg->pipe->create_fs_state( ureg->pipe, &state );
+}
+
+
+
+
+struct ureg_program *ureg_create( struct pipe_context *pipe,
+                                  unsigned processor )
+{
+   struct ureg_program *ureg = CALLOC_STRUCT( ureg_program );
+   if (ureg == NULL)
+      return NULL;
+
+   ureg->pipe = pipe;
+   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 (file)
index 0000000..fecfa81
--- /dev/null
@@ -0,0 +1,435 @@
+/**************************************************************************
+ * 
+ * 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"
+
+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 */
+};
+
+/* 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 */
+};
+
+struct pipe_context;
+
+struct ureg_program *
+ureg_create( struct pipe_context *pipe,
+             unsigned processor );
+
+void *
+ureg_create_shader( struct ureg_program * );
+
+void 
+ureg_destroy( struct ureg_program * );
+
+
+/***********************************************************************
+ * Convenience routine:
+ */
+static INLINE void *ureg_create_shader_and_destroy( struct ureg_program *p )
+{
+   void *result = ureg_create_shader( p );
+   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 semantic_name,
+                    unsigned semantic_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 * );
+
+struct ureg_dst
+ureg_DECL_temporary( struct ureg_program * );
+
+struct ureg_src
+ureg_DECL_sampler( struct ureg_program * );
+
+
+static INLINE struct ureg_src
+ureg_DECL_immediate4f( 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_DECL_immediate3f( 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_DECL_immediate2f( 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_DECL_immediate1f( struct ureg_program *ureg,
+                       float a)
+{
+   float v[1];
+   v[0] = a;
+   return ureg_DECL_immediate( ureg, v, 1 );
+}
+
+/***********************************************************************
+ * 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 )
+{
+   reg.Negate ^= 1;
+   return reg;
+}
+
+static INLINE struct ureg_src
+ureg_abs( struct ureg_src reg )
+{
+   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));
+
+   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 )
+{
+   reg.WriteMask &= writemask;
+   return reg;
+}
+
+static INLINE struct ureg_dst 
+ureg_saturate( struct ureg_dst reg )
+{
+   reg.Saturate = 1;
+   return reg;
+}
+
+static INLINE struct ureg_dst
+ureg_from_src( struct ureg_src src )
+{
+   struct ureg_dst dst;
+
+   dst.File      = src.File;
+   dst.WriteMask = TGSI_WRITEMASK_XYZW;
+   dst.Indirect  = src.Indirect;
+   dst.Saturate  = 0;
+   dst.Index     = src.Index;
+   dst.Pad1      = 0;
+   dst.Pad2      = 0;
+
+   return dst;
+}
+
+static INLINE struct ureg_src
+ureg_from_dst( 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.Absolute  = 0;
+   src.Index     = src.Index;
+   src.Negate    = 0;
+
+   return src;
+}
+
+
+
+#endif