tgsi: Add tgsi_text utility module.
authorMichal Krol <michal@tungstengraphics.com>
Sat, 12 Jul 2008 15:06:37 +0000 (17:06 +0200)
committerMichal Krol <michal@tungstengraphics.com>
Sat, 12 Jul 2008 15:06:37 +0000 (17:06 +0200)
Translates textual shader into a binary token stream.
The syntax matches the tgsi_dump module, so it's possible to
simply copy-paste the shader dump and transform it back
to a binary form.

src/gallium/auxiliary/tgsi/util/tgsi_text.c [new file with mode: 0644]
src/gallium/auxiliary/tgsi/util/tgsi_text.h [new file with mode: 0644]

diff --git a/src/gallium/auxiliary/tgsi/util/tgsi_text.c b/src/gallium/auxiliary/tgsi/util/tgsi_text.c
new file mode 100644 (file)
index 0000000..bb365d1
--- /dev/null
@@ -0,0 +1,580 @@
+/**************************************************************************
+ * 
+ * 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.
+ * 
+ **************************************************************************/
+
+#include "pipe/p_debug.h"
+#include "tgsi_text.h"
+#include "tgsi_build.h"
+#include "tgsi_parse.h"
+#include "tgsi_util.h"
+
+static boolean is_alpha_underscore( const char *cur )
+{
+   return
+      (*cur >= 'a' && *cur <= 'z') ||
+      (*cur >= 'A' && *cur <= 'Z') ||
+      *cur == '_';
+}
+
+static boolean is_digit( const char *cur )
+{
+   return *cur >= '0' && *cur <= '9';
+}
+
+static boolean is_digit_alpha_underscore( const char *cur )
+{
+   return is_digit( cur ) || is_alpha_underscore( cur );
+}
+
+/* Eat zero or more whitespaces.
+ */
+static void eat_opt_white( const char **pcur )
+{
+   while (**pcur == ' ' || **pcur == '\t' || **pcur == '\n')
+      (*pcur)++;
+}
+
+/* Eat one or more whitespaces.
+ * Return TRUE if at least one whitespace eaten.
+ */
+static boolean eat_white( const char **pcur )
+{
+   const char *cur = *pcur;
+
+   eat_opt_white( pcur );
+   return *pcur > cur;
+}
+
+/* Parse unsigned integer.
+ * No checks for overflow.
+ */
+static boolean parse_uint( const char **pcur, uint *val )
+{
+   const char *cur = *pcur;
+
+   if (is_digit( cur )) {
+      *val = *cur++ - '0';
+      while (is_digit( cur ))
+         *val = *val * 10 + *cur++ - '0';
+      *pcur = cur;
+      return TRUE;
+   }
+   return FALSE;
+}
+
+struct translate_ctx
+{
+   const char *text;
+   const char *cur;
+   struct tgsi_token *tokens;
+   struct tgsi_token *tokens_cur;
+   struct tgsi_token *tokens_end;
+   struct tgsi_header *header;
+};
+
+static void report_error( struct translate_ctx *ctx, const char *msg )
+{
+   debug_printf( "\nError: %s", msg );
+}
+
+/* Parse shader header.
+ * Return TRUE for one of the following headers.
+ *    FRAG1.1
+ *    GEOM1.1
+ *    VERT1.1
+ */
+static boolean parse_header( struct translate_ctx *ctx )
+{
+   uint processor;
+
+   if (ctx->cur[0] == 'F' && ctx->cur[1] == 'R' && ctx->cur[2] == 'A' && ctx->cur[3] == 'G') {
+      ctx->cur += 4;
+      processor = TGSI_PROCESSOR_FRAGMENT;
+   }
+   else if (ctx->cur[0] == 'V' && ctx->cur[1] == 'E' && ctx->cur[2] == 'R' && ctx->cur[3] == 'T') {
+      ctx->cur += 4;
+      processor = TGSI_PROCESSOR_VERTEX;
+   }
+   else if (ctx->cur[0] == 'G' && ctx->cur[1] == 'E' && ctx->cur[2] == 'O' && ctx->cur[3] == 'M') {
+      ctx->cur += 4;
+      processor = TGSI_PROCESSOR_GEOMETRY;
+   }
+   else {
+      report_error( ctx, "Unknown processor type" );
+      return FALSE;
+   }
+
+   if (ctx->cur[0] == '1' && ctx->cur[1] == '.' && ctx->cur[2] == '1') {
+      ctx->cur += 3;
+   }
+   else {
+      report_error( ctx, "Unknown version" );
+      return FALSE;
+   }
+
+   if (ctx->tokens_cur >= ctx->tokens_end)
+      return FALSE;
+   *(struct tgsi_version *) ctx->tokens_cur++ = tgsi_build_version();
+
+   if (ctx->tokens_cur >= ctx->tokens_end)
+      return FALSE;
+   ctx->header = (struct tgsi_header *) ctx->tokens_cur++;
+   *ctx->header = tgsi_build_header();
+
+   if (ctx->tokens_cur >= ctx->tokens_end)
+      return FALSE;
+   *(struct tgsi_processor *) ctx->tokens_cur++ = tgsi_build_processor( processor, ctx->header );
+
+   return TRUE;
+}
+
+static boolean parse_label( struct translate_ctx *ctx, uint *val )
+{
+   const char *cur = ctx->cur;
+
+   if (parse_uint( &cur, val )) {
+      eat_opt_white( &cur );
+      if (*cur == ':') {
+         cur++;
+         ctx->cur = cur;
+         return TRUE;
+      }
+   }
+   return FALSE;
+}
+
+static const char *file_names[TGSI_FILE_COUNT] =
+{
+   "NULL",
+   "CONST",
+   "IN",
+   "OUT",
+   "TEMP",
+   "SAMP",
+   "ADDR",
+   "IMM"
+};
+
+static boolean
+parse_file(
+   struct translate_ctx *ctx,
+   uint *file )
+{
+   uint i;
+
+   for (i = 0; i < TGSI_FILE_COUNT; i++) {
+      const char *cur = ctx->cur;
+      const char *name = file_names[i];
+
+      while (*name != '\0' && *name == toupper( *cur )) {
+         name++;
+         cur++;
+      }
+      if (*name == '\0' && !is_digit_alpha_underscore( cur )) {
+         ctx->cur = cur;
+         *file = i;
+         return TRUE;
+      }
+   }
+   report_error( ctx, "Unknown register file" );
+   return FALSE;
+}
+
+static boolean
+parse_register(
+   struct translate_ctx *ctx,
+   uint *file,
+   uint *index )
+{
+   if (!parse_file( ctx, file ))
+      return FALSE;
+   eat_opt_white( &ctx->cur );
+   if (*ctx->cur != '[') {
+      report_error( ctx, "Expected `['" );
+      return FALSE;
+   }
+   ctx->cur++;
+   eat_opt_white( &ctx->cur );
+   if (!parse_uint( &ctx->cur, index )) {
+      report_error( ctx, "Expected literal integer" );
+      return FALSE;
+   }
+   eat_opt_white( &ctx->cur );
+   if (*ctx->cur != ']') {
+      report_error( ctx, "Expected `]'" );
+      return FALSE;
+   }
+   ctx->cur++;
+   /* TODO: Modulate suffix */
+   return TRUE;
+}
+
+static boolean
+parse_dst_operand(
+   struct translate_ctx *ctx,
+   struct tgsi_full_dst_register *dst )
+{
+   const char *cur;
+   uint file;
+   uint index;
+
+   if (!parse_register( ctx, &file, &index ))
+      return FALSE;
+   dst->DstRegister.File = file;
+   dst->DstRegister.Index = index;
+
+   /* Parse optional write mask.
+    */
+   cur = ctx->cur;
+   eat_opt_white( &cur );
+   if (*cur == '.') {
+      uint writemask = TGSI_WRITEMASK_NONE;
+
+      cur++;
+      eat_opt_white( &cur );
+      if (toupper( *cur ) == 'X') {
+         cur++;
+         writemask |= TGSI_WRITEMASK_X;
+      }
+      if (toupper( *cur ) == 'Y') {
+         cur++;
+         writemask |= TGSI_WRITEMASK_Y;
+      }
+      if (toupper( *cur ) == 'Z') {
+         cur++;
+         writemask |= TGSI_WRITEMASK_Z;
+      }
+      if (toupper( *cur ) == 'W') {
+         cur++;
+         writemask |= TGSI_WRITEMASK_W;
+      }
+
+      if (writemask == TGSI_WRITEMASK_NONE) {
+         report_error( ctx, "Writemask expected" );
+         return FALSE;
+      }
+
+      dst->DstRegister.WriteMask = writemask;
+      ctx->cur = cur;
+   }
+   return TRUE;
+}
+
+static boolean
+parse_src_operand(
+   struct translate_ctx *ctx,
+   struct tgsi_full_src_register *src )
+{
+   const char *cur;
+   uint file;
+   uint index;
+
+   /* TODO: Extended register modifiers */
+   if (*ctx->cur == '-') {
+      ctx->cur++;
+      src->SrcRegister.Negate = 1;
+      eat_opt_white( &ctx->cur );
+   }
+
+   if (!parse_register( ctx, &file, &index ))
+      return FALSE;
+   src->SrcRegister.File = file;
+   src->SrcRegister.Index = index;
+
+   /* Parse optional swizzle
+    */
+   cur = ctx->cur;
+   eat_opt_white( &cur );
+   if (*cur == '.') {
+      uint i;
+
+      cur++;
+      eat_opt_white( &cur );
+      for (i = 0; i < 4; i++) {
+         uint swizzle;
+
+         if (toupper( *cur ) == 'X')
+            swizzle = TGSI_SWIZZLE_X;
+         else if (toupper( *cur ) == 'Y')
+            swizzle = TGSI_SWIZZLE_Y;
+         else if (toupper( *cur ) == 'Z')
+            swizzle = TGSI_SWIZZLE_Z;
+         else if (toupper( *cur ) == 'W')
+            swizzle = TGSI_SWIZZLE_W;
+         else {
+            report_error( ctx, "Expected register swizzle component either `x', `y', `z' or `w'" );
+            return FALSE;
+         }
+         cur++;
+         tgsi_util_set_src_register_swizzle( &src->SrcRegister, swizzle, i );
+      }
+
+      ctx->cur = cur;
+   }
+   return TRUE;
+}
+
+struct opcode_info
+{
+   uint num_dst;
+   uint num_src;
+   const char *mnemonic;
+};
+
+static const struct opcode_info opcode_info[TGSI_OPCODE_LAST] =
+{
+{ 1, 1, "ARL" },
+   { 1, 1, "MOV" },
+{ 1, 1, "LIT" },
+   { 1, 1, "RCP" },
+   { 1, 1, "RSQ" },
+   { 1, 1, "EXP" },
+   { 1, 1, "LOG" },
+   { 1, 2, "MUL" },
+   { 1, 2, "ADD" },
+   { 1, 2, "DP3" },
+   { 1, 2, "DP4" },
+{ 1, 2, "DST" },
+   { 1, 2, "MIN" },
+   { 1, 2, "MAX" },
+{ 1, 2, "SLT" },
+{ 1, 2, "SGE" },
+   { 1, 3, "MAD" },
+   { 1, 2, "SUB" },
+{ 1, 3, "LERP" },
+{ 1, 2, "CND" },
+{ 1, 2, "CND0" },
+{ 1, 2, "DOT2ADD" },
+{ 1, 2, "INDEX" },
+{ 1, 2, "NEGATE" },
+{ 1, 2, "FRAC" },
+{ 1, 2, "CLAMP" },
+{ 1, 2, "FLOOR" },
+{ 1, 2, "ROUND" },
+{ 1, 2, "EXPBASE2" },
+{ 1, 2, "LOGBASE2" },
+{ 1, 2, "POWER" },
+{ 1, 2, "CROSSPRODUCT" },
+{ 1, 2, "MULTIPLYMATRIX" },
+   { 1, 2, "ABS" },
+{ 1, 2, "RCC" },
+{ 1, 2, "DPH" },
+{ 1, 2, "COS" },
+{ 1, 2, "DDX" },
+{ 1, 2, "DDY" },
+{ 1, 2, "KILP" },
+{ 1, 2, "PK2H" },
+{ 1, 2, "PK2US" },
+{ 1, 2, "PK4B" },
+{ 1, 2, "PK4UB" },
+{ 1, 2, "RFL" },
+{ 1, 2, "SEQ" },
+{ 1, 2, "SFL" },
+{ 1, 2, "SGT" },
+{ 1, 2, "SIN" },
+{ 1, 2, "SLE" },
+{ 1, 2, "SNE" },
+{ 1, 2, "STR" },
+{ 1, 2, "TEX" },
+{ 1, 2, "TXD" },
+{ 1, 2, "TXP" },
+{ 1, 2, "UP2H" },
+{ 1, 2, "UP2US" },
+{ 1, 2, "UP4B" },
+{ 1, 2, "UP4UB" },
+{ 1, 2, "X2D" },
+{ 1, 2, "ARA" },
+{ 1, 2, "ARR" },
+{ 1, 2, "BRA" },
+{ 1, 2, "CAL" },
+{ 1, 2, "RET" },
+{ 1, 2, "SSG" },
+{ 1, 2, "CMP" },
+{ 1, 2, "SCS" },
+{ 1, 2, "TXB" },
+{ 1, 2, "NRM" },
+{ 1, 2, "DIV" },
+{ 1, 2, "DP2" },
+{ 1, 2, "TXL" },
+{ 1, 2, "BRK" },
+{ 1, 2, "IF" },
+{ 1, 2, "LOOP" },
+{ 1, 2, "REP" },
+{ 1, 2, "ELSE" },
+{ 1, 2, "ENDIF" },
+{ 1, 2, "ENDLOOP" },
+{ 1, 2, "ENDREP" },
+{ 1, 2, "PUSHA" },
+{ 1, 2, "POPA" },
+{ 1, 2, "CEIL" },
+{ 1, 2, "I2F" },
+{ 1, 2, "NOT" },
+{ 1, 2, "TRUNC" },
+{ 1, 2, "SHL" },
+{ 1, 2, "SHR" },
+{ 1, 2, "AND" },
+{ 1, 2, "OR" },
+{ 1, 2, "MOD" },
+{ 1, 2, "XOR" },
+{ 1, 2, "SAD" },
+{ 1, 2, "TXF" },
+{ 1, 2, "TXQ" },
+{ 1, 2, "CONT" },
+{ 1, 2, "EMIT" },
+{ 1, 2, "ENDPRIM" },
+{ 1, 2, "BGNLOOP2" },
+{ 1, 2, "BGNSUB" },
+{ 1, 2, "ENDLOOP2" },
+{ 1, 2, "ENDSUB" },
+{ 1, 2, "NOISE1" },
+{ 1, 2, "NOISE2" },
+{ 1, 2, "NOISE3" },
+{ 1, 2, "NOISE4" },
+{ 1, 2, "NOP" },
+{ 1, 2, "M4X3" },
+{ 1, 2, "M3X4" },
+{ 1, 2, "M3X3" },
+{ 1, 2, "M3X2" },
+{ 1, 2, "NRM4" },
+{ 1, 2, "CALLNZ" },
+{ 1, 2, "IFC" },
+{ 1, 2, "BREAKC" },
+{ 1, 2, "KIL" },
+   { 0, 0, "END" }
+};
+
+static boolean parse_instruction( struct translate_ctx *ctx )
+{
+   uint i;
+   const struct opcode_info *info;
+   struct tgsi_full_instruction inst;
+   uint advance;
+
+   /* Parse instruction name.
+    */
+   eat_opt_white( &ctx->cur );
+   for (i = 0; i < TGSI_OPCODE_LAST; i++) {
+      const char *cur = ctx->cur;
+      const char *op = opcode_info[i].mnemonic;
+
+      while (*op != '\0' && *op == toupper( *cur )) {
+         op++;
+         cur++;
+      }
+      if (*op == '\0') {
+         /* TODO: _SAT suffix */
+         if (*cur == '\0' || eat_white( &cur )) {
+            ctx->cur = cur;
+            break;
+         }
+      }
+   }
+   if (i == TGSI_OPCODE_LAST) {
+      report_error( ctx, "Unknown opcode" );
+      return FALSE;
+   }
+   info = &opcode_info[i];
+
+   inst = tgsi_default_full_instruction();
+   inst.Instruction.Opcode = i;
+   inst.Instruction.NumDstRegs = info->num_dst;
+   inst.Instruction.NumSrcRegs = info->num_src;
+
+   /* Parse instruction operands.
+    */
+   for (i = 0; i < info->num_dst + info->num_src; i++) {
+      if (i > 0) {
+         eat_opt_white( &ctx->cur );
+         if (*ctx->cur != ',') {
+            report_error( ctx, "Expected `,'" );
+            return FALSE;
+         }
+         ctx->cur++;
+         eat_opt_white( &ctx->cur );
+      }
+
+      if (i < info->num_dst) {
+         if (!parse_dst_operand( ctx, &inst.FullDstRegisters[i] ))
+            return FALSE;
+      }
+      else {
+         if (!parse_src_operand( ctx, &inst.FullSrcRegisters[i - info->num_dst] ))
+            return FALSE;
+      }
+   }
+   eat_opt_white( &ctx->cur );
+
+   advance = tgsi_build_full_instruction(
+      &inst,
+      ctx->tokens_cur,
+      ctx->header,
+      (uint) (ctx->tokens_end - ctx->tokens_cur) );
+   if (advance == 0)
+      return FALSE;
+   ctx->tokens_cur += advance;
+
+   return TRUE;
+}
+
+static boolean translate( struct translate_ctx *ctx )
+{
+   eat_opt_white( &ctx->cur );
+   if (!parse_header( ctx ))
+      return FALSE;
+
+   eat_white( &ctx->cur );
+   while (*ctx->cur != '\0') {
+      uint label_val = 0;
+
+      if (parse_label( ctx, &label_val )) {
+         if (!parse_instruction( ctx ))
+            return FALSE;
+      }
+      else {
+         report_error( ctx, "Instruction expected" );
+         return FALSE;
+      }
+   }
+
+   return TRUE;
+}
+
+boolean
+tgsi_text_translate(
+   const char *text,
+   struct tgsi_token *tokens,
+   uint num_tokens )
+{
+   struct translate_ctx ctx;
+
+   ctx.text = text;
+   ctx.cur = text;
+   ctx.tokens = tokens;
+   ctx.tokens_cur = tokens;
+   ctx.tokens_end = tokens + num_tokens;
+
+   return translate( &ctx );
+}
diff --git a/src/gallium/auxiliary/tgsi/util/tgsi_text.h b/src/gallium/auxiliary/tgsi/util/tgsi_text.h
new file mode 100644 (file)
index 0000000..8eeeeef
--- /dev/null
@@ -0,0 +1,47 @@
+/**************************************************************************
+ * 
+ * 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 TGSI_TEXT_H
+#define TGSI_TEXT_H
+
+#include "pipe/p_shader_tokens.h"
+
+#if defined __cplusplus
+extern "C" {
+#endif
+
+boolean
+tgsi_text_translate(
+   const char *text,
+   struct tgsi_token *tokens,
+   uint num_tokens );
+
+#if defined __cplusplus
+}
+#endif
+
+#endif /* TGSI_TEXT_H */