st: add prototype for st_get_framebuffer_dimensions()
[mesa.git] / src / mesa / state_tracker / st_mesa_to_tgsi.c
index 578fd2ecb0527aee2c55a99378a6a6f0d64ba254..50e638df46b208ace6902e57612931782ac5fde8 100644 (file)
@@ -1,6 +1,6 @@
 /**************************************************************************
  * 
- * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * Copyright 2007-2008 Tungsten Graphics, Inc., Cedar Park, Texas.
  * All Rights Reserved.
  * 
  * Permission is hereby granted, free of charge, to any person obtaining a
 
 #include "pipe/p_compiler.h"
 #include "pipe/p_shader_tokens.h"
-#include "tgsi/util/tgsi_parse.h"
-#include "tgsi/util/tgsi_build.h"
-#include "tgsi/util/tgsi_util.h"
+#include "tgsi/tgsi_parse.h"
+#include "tgsi/tgsi_build.h"
+#include "tgsi/tgsi_util.h"
+#include "tgsi/tgsi_dump.h"
+#include "tgsi/tgsi_sanity.h"
 #include "st_mesa_to_tgsi.h"
 #include "shader/prog_instruction.h"
 #include "shader/prog_parameter.h"
-
-#define TGSI_DEBUG 0
-
+#include "shader/prog_print.h"
+#include "pipe/p_debug.h"
 
 /*
  * Map mesa register file to TGSI register file.
@@ -49,15 +50,16 @@ static GLuint
 map_register_file(
    enum register_file file,
    GLuint index,
-   const GLuint immediateMapping[] )
+   const GLuint immediateMapping[],
+   GLboolean indirectAccess )
 {
    switch( file ) {
    case PROGRAM_UNDEFINED:
       return TGSI_FILE_NULL;
    case PROGRAM_TEMPORARY:
       return TGSI_FILE_TEMPORARY;
-   //case PROGRAM_LOCAL_PARAM:
-   //case PROGRAM_ENV_PARAM:
+   /*case PROGRAM_LOCAL_PARAM:*/
+   /*case PROGRAM_ENV_PARAM:*/
 
       /* Because of the longstanding problem with mesa arb shaders
        * where constants, immediates and state variables are all
@@ -68,11 +70,14 @@ map_register_file(
    case PROGRAM_STATE_VAR:
    case PROGRAM_NAMED_PARAM:
    case PROGRAM_UNIFORM:
-      if (immediateMapping[index] != ~0) 
-        return TGSI_FILE_IMMEDIATE;
+      if (!indirectAccess && immediateMapping && immediateMapping[index] != ~0)
+         return TGSI_FILE_IMMEDIATE;
       else
         return TGSI_FILE_CONSTANT;
    case PROGRAM_CONSTANT:
+      if (indirectAccess)
+         return TGSI_FILE_CONSTANT;
+      assert(immediateMapping[index] != ~0);
       return TGSI_FILE_IMMEDIATE;
    case PROGRAM_INPUT:
       return TGSI_FILE_INPUT;
@@ -100,7 +105,8 @@ map_register_file_index(
    GLuint index,
    const GLuint inputMapping[],
    const GLuint outputMapping[],
-   const GLuint immediateMapping[])
+   const GLuint immediateMapping[],
+   GLboolean indirectAccess )
 {
    switch( file ) {
    case TGSI_FILE_INPUT:
@@ -111,6 +117,9 @@ map_register_file_index(
       return outputMapping[index];
 
    case TGSI_FILE_IMMEDIATE:
+      if (indirectAccess)
+         return index;
+      assert(immediateMapping[index] != ~0);
       return immediateMapping[index];
 
    default:
@@ -177,10 +186,11 @@ static struct tgsi_full_immediate
 make_immediate(const float *value, uint size)
 {
    struct tgsi_full_immediate imm;
-   imm.Immediate.Type = TGSI_TOKEN_TYPE_IMMEDIATE;
-   imm.Immediate.Size = 1 + size; /* one for the token itself */
+
+   imm = tgsi_default_full_immediate();
+   imm.Immediate.Size += size;
    imm.Immediate.DataType = TGSI_IMM_FLOAT32;
-   imm.u.ImmediateFloat32 = (struct tgsi_immediate_float32 *) value;
+   imm.u.Pointer = value;
    return imm;
 }
 
@@ -191,6 +201,7 @@ compile_instruction(
    const GLuint inputMapping[],
    const GLuint outputMapping[],
    const GLuint immediateMapping[],
+   GLboolean indirectAccess,
    GLuint preamble_size,
    GLuint processor,
    GLboolean *insideSubroutine)
@@ -206,45 +217,55 @@ compile_instruction(
    fullinst->Instruction.NumSrcRegs = _mesa_num_inst_src_regs( inst->Opcode );
 
    fulldst = &fullinst->FullDstRegisters[0];
-   fulldst->DstRegister.File = map_register_file( inst->DstReg.File, 0, NULL );
+   fulldst->DstRegister.File = map_register_file( inst->DstReg.File, 0, NULL, GL_FALSE );
    fulldst->DstRegister.Index = map_register_file_index(
       fulldst->DstRegister.File,
       inst->DstReg.Index,
       inputMapping,
       outputMapping,
-      NULL
-      );
+      NULL,
+      GL_FALSE );
    fulldst->DstRegister.WriteMask = convert_writemask( inst->DstReg.WriteMask );
 
-   for( i = 0; i < fullinst->Instruction.NumSrcRegs; i++ ) {
+   for (i = 0; i < fullinst->Instruction.NumSrcRegs; i++) {
       GLuint j;
 
       fullsrc = &fullinst->FullSrcRegisters[i];
-      fullsrc->SrcRegister.File = map_register_file( inst->SrcReg[i].File,
-                                                    inst->SrcReg[i].Index,
-                                                    immediateMapping );
+      fullsrc->SrcRegister.File = map_register_file(
+         inst->SrcReg[i].File,
+         inst->SrcReg[i].Index,
+         immediateMapping,
+         indirectAccess );
       fullsrc->SrcRegister.Index = map_register_file_index(
          fullsrc->SrcRegister.File,
          inst->SrcReg[i].Index,
          inputMapping,
          outputMapping,
-         immediateMapping);
-
-      for( j = 0; j < 4; j++ ) {
-         GLuint swz;
-
-         swz = GET_SWZ( inst->SrcReg[i].Swizzle, j );
-         if( swz > SWIZZLE_W ) {
-            tgsi_util_set_src_register_extswizzle(
-               &fullsrc->SrcRegisterExtSwz,
-               swz,
-               j );
+         immediateMapping,
+         indirectAccess );
+
+
+      /* swizzle (ext swizzle also depends on negation) */
+      {
+         GLuint swz[4];
+         GLboolean extended = (inst->SrcReg[i].NegateBase != NEGATE_NONE &&
+                               inst->SrcReg[i].NegateBase != NEGATE_XYZW);
+         for( j = 0; j < 4; j++ ) {
+            swz[j] = GET_SWZ( inst->SrcReg[i].Swizzle, j );
+            if (swz[j] > SWIZZLE_W)
+               extended = GL_TRUE;
+         }
+         if (extended) {
+            for (j = 0; j < 4; j++) {
+               tgsi_util_set_src_register_extswizzle(&fullsrc->SrcRegisterExtSwz,
+                                                     swz[j], j);
+            }
          }
          else {
-            tgsi_util_set_src_register_swizzle(
-               &fullsrc->SrcRegister,
-               swz,
-               j );
+            for (j = 0; j < 4; j++) {
+               tgsi_util_set_src_register_swizzle(&fullsrc->SrcRegister,
+                                                  swz[j], j);
+            }
          }
       }
 
@@ -372,13 +393,13 @@ compile_instruction(
       fullinst->Instruction.Opcode = TGSI_OPCODE_INT;
       break;
    case OPCODE_KIL:
-      /* predicated w/ a register */
-      fullinst->Instruction.Opcode = TGSI_OPCODE_KILP;
+      /* conditional */
+      fullinst->Instruction.Opcode = TGSI_OPCODE_KIL;
       break;
    case OPCODE_KIL_NV:
-      /* unpredicated */
+      /* predicated */
       assert(inst->DstReg.CondMask == COND_TR);
-      fullinst->Instruction.Opcode = TGSI_OPCODE_KIL;
+      fullinst->Instruction.Opcode = TGSI_OPCODE_KILP;
       break;
    case OPCODE_LG2:
       fullinst->Instruction.Opcode = TGSI_OPCODE_LG2;
@@ -550,18 +571,16 @@ make_input_decl(
 
    decl = tgsi_default_full_declaration();
    decl.Declaration.File = TGSI_FILE_INPUT;
-   decl.Declaration.Declare = TGSI_DECLARE_RANGE;
    decl.Declaration.UsageMask = usage_mask;
    decl.Declaration.Semantic = semantic_info;
-   decl.u.DeclarationRange.First = index;
-   decl.u.DeclarationRange.Last = index;
+   decl.DeclarationRange.First = index;
+   decl.DeclarationRange.Last = index;
    if (semantic_info) {
       decl.Semantic.SemanticName = semantic_name;
       decl.Semantic.SemanticIndex = semantic_index;
    }
    if (interpolate_info) {
-      decl.Declaration.Interpolate = 1;
-      decl.Interpolation.Interpolate = interpolate;
+      decl.Declaration.Interpolate = interpolate;
    }
 
    return decl;
@@ -583,11 +602,10 @@ make_output_decl(
 
    decl = tgsi_default_full_declaration();
    decl.Declaration.File = TGSI_FILE_OUTPUT;
-   decl.Declaration.Declare = TGSI_DECLARE_RANGE;
    decl.Declaration.UsageMask = usage_mask;
    decl.Declaration.Semantic = 1;
-   decl.u.DeclarationRange.First = index;
-   decl.u.DeclarationRange.Last = index;
+   decl.DeclarationRange.First = index;
+   decl.DeclarationRange.Last = index;
    decl.Semantic.SemanticName = semantic_name;
    decl.Semantic.SemanticIndex = semantic_index;
 
@@ -603,12 +621,24 @@ make_temp_decl(
    struct tgsi_full_declaration decl;
    decl = tgsi_default_full_declaration();
    decl.Declaration.File = TGSI_FILE_TEMPORARY;
-   decl.Declaration.Declare = TGSI_DECLARE_RANGE;
-   decl.u.DeclarationRange.First = start_index;
-   decl.u.DeclarationRange.Last = end_index;
+   decl.DeclarationRange.First = start_index;
+   decl.DeclarationRange.Last = end_index;
    return decl;
 }
 
+static struct tgsi_full_declaration
+make_addr_decl(
+   GLuint start_index,
+   GLuint end_index )
+{
+   struct tgsi_full_declaration decl;
+
+   decl = tgsi_default_full_declaration();
+   decl.Declaration.File = TGSI_FILE_ADDRESS;
+   decl.DeclarationRange.First = start_index;
+   decl.DeclarationRange.Last = end_index;
+   return decl;
+}
 
 static struct tgsi_full_declaration
 make_sampler_decl(GLuint index)
@@ -616,9 +646,8 @@ make_sampler_decl(GLuint index)
    struct tgsi_full_declaration decl;
    decl = tgsi_default_full_declaration();
    decl.Declaration.File = TGSI_FILE_SAMPLER;
-   decl.Declaration.Declare = TGSI_DECLARE_RANGE;
-   decl.u.DeclarationRange.First = index;
-   decl.u.DeclarationRange.Last = index;
+   decl.DeclarationRange.First = index;
+   decl.DeclarationRange.Last = index;
    return decl;
 }
 
@@ -629,9 +658,8 @@ make_constant_decl(GLuint first, GLuint last)
    struct tgsi_full_declaration decl;
    decl = tgsi_default_full_declaration();
    decl.Declaration.File = TGSI_FILE_CONSTANT;
-   decl.Declaration.Declare = TGSI_DECLARE_RANGE;
-   decl.u.DeclarationRange.First = first;
-   decl.u.DeclarationRange.Last = last;
+   decl.DeclarationRange.First = first;
+   decl.DeclarationRange.Last = last;
    return decl;
 }
 
@@ -685,7 +713,7 @@ find_temporaries(const struct gl_program *program,
  * \return number of tokens placed in 'tokens' buffer, or zero if error
  */
 GLuint
-tgsi_translate_mesa_program(
+st_translate_mesa_program(
    uint procType,
    const struct gl_program *program,
    GLuint numInputs,
@@ -709,6 +737,7 @@ tgsi_translate_mesa_program(
    GLuint immediates[1000];
    GLuint numImmediates = 0;
    GLboolean insideSubroutine = GL_FALSE;
+   GLboolean indirectAccess = GL_FALSE;
 
    assert(procType == TGSI_PROCESSOR_FRAGMENT ||
           procType == TGSI_PROCESSOR_VERTEX);
@@ -767,16 +796,19 @@ tgsi_translate_mesa_program(
          switch (outputSemanticName[i]) {
          case TGSI_SEMANTIC_POSITION:
             fulldecl = make_output_decl(i,
-                                        TGSI_SEMANTIC_POSITION, 0, /* Z / Depth */
+                                        TGSI_SEMANTIC_POSITION, /* Z / Depth */
+                                        outputSemanticIndex[i],
                                         TGSI_WRITEMASK_Z );
             break;
          case TGSI_SEMANTIC_COLOR:
             fulldecl = make_output_decl(i,
-                                        TGSI_SEMANTIC_COLOR, 0,
+                                        TGSI_SEMANTIC_COLOR,
+                                        outputSemanticIndex[i],
                                         TGSI_WRITEMASK_XYZW );
             break;
          default:
-            abort();
+            assert(0);
+            return 0;
          }
          ti += tgsi_build_full_declaration(&fulldecl,
                                            &tokens[ti],
@@ -803,7 +835,7 @@ tgsi_translate_mesa_program(
    {
       GLboolean tempsUsed[MAX_PROGRAM_TEMPS + 1];
       GLboolean inside_range = GL_FALSE;
-      GLuint start_range;
+      GLuint start_range = 0;
 
       find_temporaries(program, tempsUsed);
       tempsUsed[MAX_PROGRAM_TEMPS] = GL_FALSE;
@@ -818,45 +850,78 @@ tgsi_translate_mesa_program(
             inside_range = GL_FALSE;
             fulldecl = make_temp_decl( start_range, i - 1 );
             ti += tgsi_build_full_declaration(
-                                              &fulldecl,
-                                              &tokens[ti],
-                                              header,
-                                              maxTokens - ti );
+               &fulldecl,
+               &tokens[ti],
+               header,
+               maxTokens - ti );
          }
       }
    }
 
+   /* Declare address register.
+   */
+   if (program->NumAddressRegs > 0) {
+      struct tgsi_full_declaration fulldecl;
+
+      assert( program->NumAddressRegs == 1 );
+
+      fulldecl = make_addr_decl( 0, 0 );
+      ti += tgsi_build_full_declaration(
+         &fulldecl,
+         &tokens[ti],
+         header,
+         maxTokens - ti );
+
+      indirectAccess = GL_TRUE;
+   }
+
    /* immediates/literals */
    memset(immediates, ~0, sizeof(immediates));
 
-   for (i = 0; program->Parameters && i < program->Parameters->NumParameters;
-        i++) {
-      if (program->Parameters->Parameters[i].Type == PROGRAM_CONSTANT) {
-         struct tgsi_full_immediate fullimm
-            = make_immediate(program->Parameters->ParameterValues[i], 4);
-         ti += tgsi_build_full_immediate(&fullimm,
-                                         &tokens[ti],
-                                         header,
-                                         maxTokens - ti);
-         immediates[i] = numImmediates;
-         numImmediates++;
+   /* Emit immediates only when there is no address register in use.
+    * FIXME: Be smarter and recognize param arrays -- indirect addressing is
+    *        only valid within the referenced array.
+    */
+   if (program->Parameters && !indirectAccess) {
+      for (i = 0; i < program->Parameters->NumParameters; i++) {
+         if (program->Parameters->Parameters[i].Type == PROGRAM_CONSTANT) {
+            struct tgsi_full_immediate fullimm;
+
+            fullimm = make_immediate( program->Parameters->ParameterValues[i], 4 );
+            ti += tgsi_build_full_immediate(
+               &fullimm,
+               &tokens[ti],
+               header,
+               maxTokens - ti );
+            immediates[i] = numImmediates;
+            numImmediates++;
+         }
       }
    }
 
    /* constant buffer refs */
-   {
+   if (program->Parameters) {
       GLint start = -1, end = -1;
 
-      for (i = 0;
-           program->Parameters && i < program->Parameters->NumParameters;
-           i++) {
+      for (i = 0; i < program->Parameters->NumParameters; i++) {
          GLboolean emit = (i == program->Parameters->NumParameters - 1);
+         GLboolean matches;
 
          switch (program->Parameters->Parameters[i].Type) {
          case PROGRAM_ENV_PARAM:
          case PROGRAM_STATE_VAR:
          case PROGRAM_NAMED_PARAM:
          case PROGRAM_UNIFORM:
+            matches = GL_TRUE;
+            break;
+         case PROGRAM_CONSTANT:
+            matches = indirectAccess;
+            break;
+         default:
+            matches = GL_FALSE;
+         }
+
+         if (matches) {
             if (start == -1) {
                /* begin a sequence */
                start = i;
@@ -866,8 +931,8 @@ tgsi_translate_mesa_program(
                /* continue sequence */
                end = i;
             }
-            break;
-         default:
+         }
+         else {
             if (start != -1) {
                /* end of sequence */
                emit = GL_TRUE;
@@ -876,11 +941,13 @@ tgsi_translate_mesa_program(
 
          if (emit && start >= 0) {
             struct tgsi_full_declaration fulldecl;
+
             fulldecl = make_constant_decl( start, end );
-            ti += tgsi_build_full_declaration(&fulldecl,
-                                              &tokens[ti],
-                                              header,
-                                              maxTokens - ti);
+            ti += tgsi_build_full_declaration(
+               &fulldecl,
+               &tokens[ti],
+               header,
+               maxTokens - ti );
             start = end = -1;
          }
       }
@@ -890,25 +957,27 @@ tgsi_translate_mesa_program(
    for (i = 0; i < 8; i++) {
       if (program->SamplersUsed & (1 << i)) {
          struct tgsi_full_declaration fulldecl;
+
          fulldecl = make_sampler_decl( i );
-         ti += tgsi_build_full_declaration(&fulldecl,
-                                           &tokens[ti],
-                                           header,
-                                           maxTokens - ti );
+         ti += tgsi_build_full_declaration(
+            &fulldecl,
+            &tokens[ti],
+            header,
+            maxTokens - ti );
       }
    }
 
-
-   for( i = 0; i < program->NumInstructions; i++ ) {
+   for (i = 0; i < program->NumInstructions; i++) {
       compile_instruction(
-            &program->Instructions[i],
-            &fullinst,
-            inputMapping,
-            outputMapping,
-            immediates,
-            preamble_size,
-            procType,
-            &insideSubroutine);
+         &program->Instructions[i],
+         &fullinst,
+         inputMapping,
+         outputMapping,
+         immediates,
+         indirectAccess,
+         preamble_size,
+         procType,
+         &insideSubroutine );
 
       ti += tgsi_build_full_instruction(
          &fullinst,
@@ -917,6 +986,17 @@ tgsi_translate_mesa_program(
          maxTokens - ti );
    }
 
+#if DEBUG
+   if(!tgsi_sanity_check(tokens)) {
+      debug_printf("Due to sanity check failure(s) above the following shader program is invalid:\n");
+      debug_printf("\nOriginal program:\n%s", program->String);
+      debug_printf("\nMesa program:\n");
+      _mesa_print_program(program);
+      debug_printf("\nTGSI program:\n");
+      tgsi_dump(tokens, 0);
+      assert(0);
+   }
+#endif
+
    return ti;
 }
-