Merge Jose's documentation and core Mesa changes from embedded branch
[mesa.git] / src / mesa / main / nvfragparse.c
index 0f75d6c36f6dfc9cc15c864e5b0c3113d6cfec4c..38da43319717e5cde711b0eb4c8a800ee36c9db2 100644 (file)
@@ -1,5 +1,3 @@
-/* $Id: nvfragparse.c,v 1.14 2003/03/15 17:33:26 brianp Exp $ */
-
 /*
  * Mesa 3-D graphics library
  * Version:  5.1
  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  */
 
-
 /**
  * \file nvfragparse.c
- * \brief NVIDIA fragment program parser.
+ * NVIDIA fragment program parser.
  * \author Brian Paul
  */
 
@@ -130,13 +127,84 @@ struct parse_state {
    const GLubyte *start;              /* start of program string */
    const GLubyte *pos;                /* current position */
    struct fragment_program *program;  /* current program */
+
+   GLuint numParameters;
+   struct program_parameter *parameters; /* DECLARE */
+
+   GLuint numConstants;
+   struct program_parameter *constants; /* DEFINE */
+
    GLuint numInst;                    /* number of instructions parsed */
    GLuint inputsRead;                 /* bitmask of input registers used */
-   GLuint outputsWritten;             /* 2 = depth register */
+   GLuint outputsWritten;             /* bitmask of 1 << FRAG_OUTPUT_* bits */
    GLuint texturesUsed[MAX_TEXTURE_IMAGE_UNITS];
 };
 
 
+/**
+ * Add a new program parameter (via DEFINE statement)
+ * \return index of the new entry in the parameter list
+ */
+static GLuint
+add_parameter(struct parse_state *parseState,
+              const char *name, const GLfloat values[4], GLboolean constant)
+{
+   const GLuint n = parseState->numParameters;
+
+   parseState->parameters = _mesa_realloc(parseState->parameters,
+                                   n * sizeof(struct program_parameter),
+                                   (n + 1) * sizeof(struct program_parameter));
+   parseState->numParameters = n + 1;
+   parseState->parameters[n].Name = _mesa_strdup(name);
+   COPY_4V(parseState->parameters[n].Values, values);
+   parseState->parameters[n].Constant = constant;
+   return n;
+}
+
+
+/**
+ * Add a new unnamed constant to the parameter lists.
+ * \param parseState  parsing state
+ * \param values  four float values
+ * \return index of the new parameter.
+ */
+static GLuint
+add_unnamed_constant(struct parse_state *parseState, const GLfloat values[4])
+{
+   /* generate a new dummy name */
+   static GLuint n = 0;
+   char name[20];
+   _mesa_sprintf(name, "constant%d", n);
+   n++;
+   /* store it */
+   return add_parameter(parseState, name, values, GL_TRUE);
+}
+
+
+static const GLfloat *
+lookup_parameter(struct parse_state *parseState, const char *name)
+{
+   GLuint i;
+   for (i = 0; i < parseState->numParameters; i++) {
+      if (_mesa_strcmp(parseState->parameters[i].Name, name) == 0)
+         return parseState->parameters[i].Values;
+   }
+   return NULL;
+}
+
+
+static const GLint
+lookup_parameter_index(struct parse_state *parseState, const char *name)
+{
+   GLint i;
+   for (i = 0; i < parseState->numParameters; i++) {
+      if (_mesa_strcmp(parseState->parameters[i].Name, name) == 0)
+         return i;
+   }
+   return -1;
+}
+
+
 /*
  * Called whenever we find an error during parsing.
  */
@@ -477,6 +545,7 @@ Parse_Identifier(struct parse_state *parseState, GLubyte *ident)
 /**
  * Parse a floating point constant, or a defined symbol name.
  * [+/-]N[.N[eN]]
+ * Output:  number[0 .. 3] will get the value.
  */
 static GLboolean
 Parse_ScalarConstant(struct parse_state *parseState, GLfloat *number)
@@ -488,18 +557,26 @@ Parse_ScalarConstant(struct parse_state *parseState, GLfloat *number)
    if (end && end > (char *) parseState->pos) {
       /* got a number */
       parseState->pos = (GLubyte *) end;
+      number[1] = *number;
+      number[2] = *number;
+      number[3] = *number;
       return GL_TRUE;
    }
    else {
       /* should be an identifier */
       GLubyte ident[100];
+      const GLfloat *constant;
       if (!Parse_Identifier(parseState, ident))
          RETURN_ERROR1("Expected an identifier");
-      if (!_mesa_lookup_symbol(&(parseState->program->SymbolTable),
-                               (const char *) ident, number)) {
+      constant = lookup_parameter(parseState, (const char *) ident);
+      /* XXX Check that it's a constant and not a parameter */
+      if (!constant) {
          RETURN_ERROR1("Undefined symbol");
       }
-      return GL_TRUE;
+      else {
+         COPY_4V(number, constant);
+         return GL_TRUE;
+      }
    }
 }
 
@@ -517,11 +594,12 @@ Parse_VectorConstant(struct parse_state *parseState, GLfloat *vec)
 {
    /* "{" was already consumed */
 
+   ASSIGN_4V(vec, 0.0, 0.0, 0.0, 1.0);
+
    if (!Parse_ScalarConstant(parseState, vec+0))  /* X */
       return GL_FALSE;
 
    if (Parse_String(parseState, "}")) {
-      vec[1] = vec[2] = vec[3] = vec[0];
       return GL_TRUE;
    }
 
@@ -532,7 +610,6 @@ Parse_VectorConstant(struct parse_state *parseState, GLfloat *vec)
       return GL_FALSE;
 
    if (Parse_String(parseState, "}")) {
-      vec[2] = vec[3] = vec[1];
       return GL_TRUE;
    }
 
@@ -543,7 +620,6 @@ Parse_VectorConstant(struct parse_state *parseState, GLfloat *vec)
       return GL_FALSE;
 
    if (Parse_String(parseState, "}")) {
-      vec[3] = vec[2];
       return GL_TRUE;
    }
 
@@ -853,9 +929,10 @@ Parse_OutputReg(struct parse_state *parseState, GLint *outputRegNum)
    /* try to match an output register name */
    for (j = 0; OutputRegisters[j]; j++) {
       if (_mesa_strcmp((const char *) token, OutputRegisters[j]) == 0) {
+         static GLuint bothColors = (1 << FRAG_OUTPUT_COLR) | (1 << FRAG_OUTPUT_COLH);
          *outputRegNum = FP_OUTPUT_REG_START + j;
          parseState->outputsWritten |= (1 << j);
-         if ((parseState->outputsWritten & 0x3) == 0x3) {
+         if ((parseState->outputsWritten & bothColors) == bothColors) {
             RETURN_ERROR1("Illegal to write to both o[COLR] and o[COLH]");
          }
          break;
@@ -1027,26 +1104,41 @@ Parse_VectorSrc(struct parse_state *parseState,
          RETURN_ERROR;
    }
    else if (IsLetter(token[0])){
-      /* XXX named constant */
       GLubyte ident[100];
+      GLint paramIndex;
       if (!Parse_Identifier(parseState, ident))
          RETURN_ERROR;
-      srcReg->Register = 0; /* XXX fix */
+      paramIndex = lookup_parameter_index(parseState, (const char *) ident);
+      if (paramIndex < 0) {
+         RETURN_ERROR2("Undefined constant or parameter: ", ident);
+      }
+      srcReg->IsParameter = GL_TRUE;
+      srcReg->Register = paramIndex;      
    }
-   else if (IsDigit(token[0]) || token[0] == '-' || token[0] == '+'){
-      /* XXX literal scalar constant */
+   else if (IsDigit(token[0]) || token[0] == '-' || token[0] == '+' || token[0] == '.'){
+      /* literal scalar constant */
       GLfloat values[4];
+      GLuint paramIndex;
       if (!Parse_ScalarConstant(parseState, values))
          RETURN_ERROR;
+#if 0
       srcReg->Register = 0; /* XXX fix */
+#else
+      paramIndex = add_unnamed_constant(parseState, values);
+      srcReg->IsParameter = GL_TRUE;
+      srcReg->Register = paramIndex;
+#endif
    }
    else if (token[0] == '{'){
-      /* XXX literal vector constant */
+      /* literal vector constant */
       GLfloat values[4];
+      GLuint paramIndex;
       (void) Parse_String(parseState, "{");
       if (!Parse_VectorConstant(parseState, values))
          RETURN_ERROR;
-      srcReg->Register = 0; /* XXX fix */
+      paramIndex = add_unnamed_constant(parseState, values);
+      srcReg->IsParameter = GL_TRUE;
+      srcReg->Register = paramIndex;      
    }
    else {
       RETURN_ERROR2("Invalid source register name", token);
@@ -1081,13 +1173,32 @@ Parse_ScalarSrcReg(struct parse_state *parseState,
                    struct fp_src_register *srcReg)
 {
    GLubyte token[100];
+   GLfloat sign = 1.0F;
+   GLboolean needSuffix = GL_TRUE;
 
-   /* check for '-' */
-   if (Parse_String(parseState, "-")) {
-      srcReg->NegateBase = GL_TRUE;
+   /*
+    * First, take care of +/- and absolute value stuff.
+    */
+   if (Parse_String(parseState, "-"))
+      sign = -1.0F;
+   else if (Parse_String(parseState, "+"))
+      sign = +1.0F;
+
+   if (Parse_String(parseState, "|")) {
+      srcReg->Abs = GL_TRUE;
+      srcReg->NegateAbs = (sign < 0.0F) ? GL_TRUE : GL_FALSE;
+
+      if (Parse_String(parseState, "-"))
+         srcReg->NegateBase = GL_TRUE;
+      else if (Parse_String(parseState, "+"))
+         srcReg->NegateBase = GL_FALSE;
+      else
+         srcReg->NegateBase = GL_FALSE;
    }
    else {
-      srcReg->NegateBase = GL_FALSE;
+      srcReg->Abs = GL_FALSE;
+      srcReg->NegateAbs = GL_FALSE;
+      srcReg->NegateBase = (sign < 0.0F) ? GL_TRUE : GL_FALSE;
    }
 
    if (!Peek_Token(parseState, token))
@@ -1102,34 +1213,66 @@ Parse_ScalarSrcReg(struct parse_state *parseState,
       if (!Parse_FragReg(parseState, &srcReg->Register))
          RETURN_ERROR;
    }
+   else if (token[0] == '{') {
+      /* vector literal */
+      GLfloat values[4];
+      GLuint paramIndex;
+      (void) Parse_String(parseState, "{");
+      if (!Parse_VectorConstant(parseState, values))
+         RETURN_ERROR;
+      paramIndex = add_unnamed_constant(parseState, values);
+      srcReg->IsParameter = GL_TRUE;
+      srcReg->Register = paramIndex;      
+   }
+   else if (IsDigit(token[0])) {
+      /* scalar literal */
+      GLfloat values[4];
+      GLuint paramIndex;
+      if (!Parse_ScalarConstant(parseState, values))
+         RETURN_ERROR;
+      paramIndex = add_unnamed_constant(parseState, values);
+      srcReg->IsParameter = GL_TRUE;
+      srcReg->Register = paramIndex;      
+      needSuffix = GL_FALSE;
+   }
    else {
-      RETURN_ERROR2("Invalid source register name", token);
+      RETURN_ERROR2("Invalid scalar source argument", token);
    }
 
-   /* Look for .[xyzw] suffix */
-   if (!Parse_String(parseState, "."))
-      RETURN_ERROR1("Expected .");
+   if (needSuffix) {
+      /* parse .[xyzw] suffix */
+      if (!Parse_String(parseState, "."))
+         RETURN_ERROR1("Expected .");
 
-   if (!Parse_Token(parseState, token))
-      RETURN_ERROR;
+      if (!Parse_Token(parseState, token))
+         RETURN_ERROR;
 
-   if (token[0] == 'x' && token[1] == 0) {
-      srcReg->Swizzle[0] = 0;
-   }
-   else if (token[0] == 'y' && token[1] == 0) {
-      srcReg->Swizzle[0] = 1;
-   }
-   else if (token[0] == 'z' && token[1] == 0) {
-      srcReg->Swizzle[0] = 2;
-   }
-   else if (token[0] == 'w' && token[1] == 0) {
-      srcReg->Swizzle[0] = 3;
+      if (token[0] == 'x' && token[1] == 0) {
+         srcReg->Swizzle[0] = 0;
+      }
+      else if (token[0] == 'y' && token[1] == 0) {
+         srcReg->Swizzle[0] = 1;
+      }
+      else if (token[0] == 'z' && token[1] == 0) {
+         srcReg->Swizzle[0] = 2;
+      }
+      else if (token[0] == 'w' && token[1] == 0) {
+         srcReg->Swizzle[0] = 3;
+      }
+      else {
+         RETURN_ERROR1("Invalid scalar source suffix");
+      }
    }
    else {
-      RETURN_ERROR1("Invalid scalar source suffix");
+      srcReg->Swizzle[0] = 0;
    }
    srcReg->Swizzle[1] = srcReg->Swizzle[2] = srcReg->Swizzle[3] = 0;
 
+   /* Finish absolute value */
+   if (srcReg->Abs && !Parse_String(parseState, "|")) {
+      RETURN_ERROR1("Expected |");
+   }
+
    return GL_TRUE;
 }
 
@@ -1148,7 +1291,14 @@ Parse_InstructionSequence(struct parse_state *parseState,
       inst->SrcReg[0].Register = -1;
       inst->SrcReg[1].Register = -1;
       inst->SrcReg[2].Register = -1;
+      inst->SrcReg[0].IsParameter = GL_FALSE;
+      inst->SrcReg[1].IsParameter = GL_FALSE;
+      inst->SrcReg[2].IsParameter = GL_FALSE;
       inst->DstReg.Register = -1;
+      inst->DstReg.CondSwizzle[0] = 0;
+      inst->DstReg.CondSwizzle[1] = 1;
+      inst->DstReg.CondSwizzle[2] = 2;
+      inst->DstReg.CondSwizzle[3] = 3;
 
       /* special instructions */
       if (Parse_String(parseState, "DEFINE")) {
@@ -1163,10 +1313,10 @@ Parse_InstructionSequence(struct parse_state *parseState,
             RETURN_ERROR;
          if (!Parse_String(parseState, ";"))
             RETURN_ERROR1("Expected ;");
-         printf("Parsed DEFINE %s = %f %f %f %f\n", id, value[0], value[1],
-                value[2], value[3]);
-         _mesa_add_symbol(&(parseState->program->SymbolTable),
-                          (const char *) id, Definition, value);
+         if (lookup_parameter(parseState, (const char *) id)) {
+            RETURN_ERROR2(id, "already defined");
+         }
+         add_parameter(parseState, (const char *) id, value, GL_TRUE);
       }
       else if (Parse_String(parseState, "DECLARE")) {
          GLubyte id[100];
@@ -1177,16 +1327,13 @@ Parse_InstructionSequence(struct parse_state *parseState,
          if (Parse_String(parseState, "=")) {
             if (!Parse_VectorOrScalarConstant(parseState, value))
                RETURN_ERROR;
-            printf("Parsed DECLARE %s = %f %f %f %f\n", id,
-                   value[0], value[1], value[2], value[3]);
-         }
-         else {
-            printf("Parsed DECLARE %s\n", id);
          }
          if (!Parse_String(parseState, ";"))
             RETURN_ERROR1("Expected ;");
-         _mesa_add_symbol(&(parseState->program->SymbolTable),
-                          (const char *) id, Declaration, value);
+         if (lookup_parameter(parseState, (const char *) id)) {
+            RETURN_ERROR2(id, "already declared");
+         }
+         add_parameter(parseState, (const char *) id, value, GL_FALSE);
       }
       else if (Parse_String(parseState, "END")) {
          inst->Opcode = FP_OPCODE_END;
@@ -1245,7 +1392,7 @@ Parse_InstructionSequence(struct parse_state *parseState,
                RETURN_ERROR;
          }
          else if (instMatch.inputs == INPUT_3V) {
-            if (!Parse_VectorSrc(parseState, &inst->SrcReg[1]))
+            if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
                RETURN_ERROR;
             if (!Parse_String(parseState, ","))
                RETURN_ERROR1("Expected ,");
@@ -1253,11 +1400,11 @@ Parse_InstructionSequence(struct parse_state *parseState,
                RETURN_ERROR;
             if (!Parse_String(parseState, ","))
                RETURN_ERROR1("Expected ,");
-            if (!Parse_VectorSrc(parseState, &inst->SrcReg[1]))
+            if (!Parse_VectorSrc(parseState, &inst->SrcReg[2]))
                RETURN_ERROR;
          }
          else if (instMatch.inputs == INPUT_1S) {
-            if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[1]))
+            if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0]))
                RETURN_ERROR;
          }
          else if (instMatch.inputs == INPUT_2S) {
@@ -1402,6 +1549,7 @@ _mesa_parse_nv_fragment_program(GLcontext *ctx, GLenum dstTarget,
          FREE(program->Base.String);
       }
       program->Base.String = programString;
+      program->Base.Format = GL_PROGRAM_FORMAT_ASCII_ARB;
       if (program->Instructions) {
          FREE(program->Instructions);
       }
@@ -1411,8 +1559,29 @@ _mesa_parse_nv_fragment_program(GLcontext *ctx, GLenum dstTarget,
       for (u = 0; u < ctx->Const.MaxTextureImageUnits; u++)
          program->TexturesUsed[u] = parseState.texturesUsed[u];
 
+      /* save program parameters */
+      if (program->Parameters) {
+         GLuint i;
+         for (i = 0; i < program->NumParameters; i++)
+            _mesa_free((void *) program->Parameters[i].Name);
+         _mesa_free(program->Parameters);
+      }
+      program->NumParameters = parseState.numParameters;
+      program->Parameters = parseState.parameters;
+
+      /* free program constants */
+      if (parseState.constants) {
+         GLuint i;
+         for (i = 0; i < parseState.numConstants; i++)
+            _mesa_free((void *) parseState.constants[i].Name);
+         _mesa_free(parseState.constants);
+      }
+         
+
       /* allocate registers for declared program parameters */
+#if 00
       _mesa_assign_program_registers(&(program->SymbolTable));
+#endif
 
 #ifdef DEBUG
       _mesa_printf("--- glLoadProgramNV(%d) result ---\n", program->Base.Id);
@@ -1429,7 +1598,8 @@ _mesa_parse_nv_fragment_program(GLcontext *ctx, GLenum dstTarget,
 
 
 static void
-PrintSrcReg(const struct fp_src_register *src)
+PrintSrcReg(const struct fragment_program *program,
+            const struct fp_src_register *src)
 {
    static const char comps[5] = "xyzw";
    GLint r;
@@ -1443,7 +1613,19 @@ PrintSrcReg(const struct fp_src_register *src)
    if (src->NegateBase) {
       _mesa_printf("-");
    }
-   if ((r = OutputRegisterNumber(src->Register)) >= 0) {
+   if (src->IsParameter) {
+      if (program->Parameters[src->Register].Constant) {
+         printf("{%g, %g, %g, %g}",
+                program->Parameters[src->Register].Values[0],
+                program->Parameters[src->Register].Values[1],
+                program->Parameters[src->Register].Values[2],
+                program->Parameters[src->Register].Values[3]);
+      }
+      else {
+         printf("%s", program->Parameters[src->Register].Name);
+      }
+   }
+   else if ((r = OutputRegisterNumber(src->Register)) >= 0) {
       _mesa_printf("o[%s]", OutputRegisters[r]);
    }
    else if ((r = InputRegisterNumber(src->Register)) >= 0) {
@@ -1548,7 +1730,7 @@ PrintDstReg(const struct fp_dst_register *dst)
       _mesa_printf("o[%s]", OutputRegisters[r]);
    }
    else if ((r = HalfTempRegisterNumber(dst->Register)) >= 0) {
-      _mesa_printf("H[%s]", InputRegisters[r]);
+      _mesa_printf("H%d", r);
    }
    else if ((r = TempRegisterNumber(dst->Register)) >= 0) {
       _mesa_printf("R%d", r);
@@ -1624,32 +1806,32 @@ _mesa_print_nv_fragment_program(const struct fragment_program *program)
             /* print source register(s) */
             if (Instructions[i].inputs == INPUT_1V ||
                 Instructions[i].inputs == INPUT_1S) {
-               PrintSrcReg(&inst->SrcReg[0]);
+               PrintSrcReg(program, &inst->SrcReg[0]);
             }
             else if (Instructions[i].inputs == INPUT_2V ||
                      Instructions[i].inputs == INPUT_2S) {
-               PrintSrcReg(&inst->SrcReg[0]);
+               PrintSrcReg(program, &inst->SrcReg[0]);
                _mesa_printf(", ");
-               PrintSrcReg(&inst->SrcReg[1]);
+               PrintSrcReg(program, &inst->SrcReg[1]);
             }
             else if (Instructions[i].inputs == INPUT_3V) {
-               PrintSrcReg(&inst->SrcReg[0]);
+               PrintSrcReg(program, &inst->SrcReg[0]);
                _mesa_printf(", ");
-               PrintSrcReg(&inst->SrcReg[1]);
+               PrintSrcReg(program, &inst->SrcReg[1]);
                _mesa_printf(", ");
-               PrintSrcReg(&inst->SrcReg[2]);
+               PrintSrcReg(program, &inst->SrcReg[2]);
             }
             else if (Instructions[i].inputs == INPUT_1V_T) {
-               PrintSrcReg(&inst->SrcReg[0]);
+               PrintSrcReg(program, &inst->SrcReg[0]);
                _mesa_printf(", ");
                PrintTextureSrc(inst);
             }
             else if (Instructions[i].inputs == INPUT_3V_T) {
-               PrintSrcReg(&inst->SrcReg[0]);
+               PrintSrcReg(program, &inst->SrcReg[0]);
                _mesa_printf(", ");
-               PrintSrcReg(&inst->SrcReg[1]);
+               PrintSrcReg(program, &inst->SrcReg[1]);
                _mesa_printf(", ");
-               PrintSrcReg(&inst->SrcReg[2]);
+               PrintSrcReg(program, &inst->SrcReg[2]);
                _mesa_printf(", ");
                PrintTextureSrc(inst);
             }