Esempio n. 1
0
/**
 * Add parameter representing a vertex program attribute.
 * \param size  size of attribute (in floats), may be -1 if unknown
 * \param attrib  the attribute index, or -1 if unknown
 */
GLint
_mesa_add_attribute(struct gl_program_parameter_list *paramList,
                    const char *name, GLint size, GLint attrib)
{
   GLint i = _mesa_lookup_parameter_index(paramList, -1, name);
   if (i >= 0) {
      /* replace */
      if (attrib < 0)
         attrib = i;
      paramList->Parameters[i].StateIndexes[0] = attrib;
   }
   else {
      /* add */
      gl_state_index state[STATE_LENGTH];
      state[0] = (gl_state_index) attrib;
      if (size < 0)
         size = 4;
      i = _mesa_add_parameter(paramList, PROGRAM_INPUT, name,
                              size, GL_NONE, NULL, state);
   }
   return i;
}
Esempio n. 2
0
    int
    _mesa_get_sampler_uniform_value(class ir_dereference *sampler,
                                    struct gl_shader_program *shader_program,
                                    const struct gl_program *prog)
    {
        get_sampler_name getname(sampler, shader_program);

        sampler->accept(&getname);

        GLint index = _mesa_lookup_parameter_index(prog->Parameters, -1,
                      getname.name);

        if (index < 0) {
            fail_link(shader_program,
                      "failed to find sampler named %s.\n", getname.name);
            return 0;
        }

        index += getname.offset;

        return prog->Parameters->ParameterValues[index][0].f;
    }
Esempio n. 3
0
/**
 * Linking varying vars involves rearranging varying vars so that the
 * vertex program's output varyings matches the order of the fragment
 * program's input varyings.
 * We'll then rewrite instructions to replace PROGRAM_VARYING with either
 * PROGRAM_INPUT or PROGRAM_OUTPUT depending on whether it's a vertex or
 * fragment shader.
 * This is also where we set program Input/OutputFlags to indicate
 * which inputs are centroid-sampled, invariant, etc.
 */
static GLboolean
link_varying_vars(GLcontext *ctx,
                  struct gl_shader_program *shProg, struct gl_program *prog)
{
   GLuint *map, i, firstVarying, newFile;
   GLbitfield *inOutFlags;

   map = (GLuint *) malloc(prog->Varying->NumParameters * sizeof(GLuint));
   if (!map)
      return GL_FALSE;

   /* Varying variables are treated like other vertex program outputs
    * (and like other fragment program inputs).  The position of the
    * first varying differs for vertex/fragment programs...
    * Also, replace File=PROGRAM_VARYING with File=PROGRAM_INPUT/OUTPUT.
    */
   if (prog->Target == GL_VERTEX_PROGRAM_ARB) {
      firstVarying = VERT_RESULT_VAR0;
      newFile = PROGRAM_OUTPUT;
      inOutFlags = prog->OutputFlags;
   }
   else {
      assert(prog->Target == GL_FRAGMENT_PROGRAM_ARB);
      firstVarying = FRAG_ATTRIB_VAR0;
      newFile = PROGRAM_INPUT;
      inOutFlags = prog->InputFlags;
   }

   for (i = 0; i < prog->Varying->NumParameters; i++) {
      /* see if this varying is in the linked varying list */
      const struct gl_program_parameter *var = prog->Varying->Parameters + i;
      GLint j = _mesa_lookup_parameter_index(shProg->Varying, -1, var->Name);
      if (j >= 0) {
         /* varying is already in list, do some error checking */
         const struct gl_program_parameter *v =
            &shProg->Varying->Parameters[j];
         if (var->Size != v->Size) {
            link_error(shProg, "mismatched varying variable types");
            free(map);
            return GL_FALSE;
         }
         if (!bits_agree(var->Flags, v->Flags, PROG_PARAM_BIT_CENTROID)) {
            char msg[100];
            _mesa_snprintf(msg, sizeof(msg),
		     "centroid modifier mismatch for '%s'", var->Name);
            link_error(shProg, msg);
            free(map);
            return GL_FALSE;
         }
         if (!bits_agree(var->Flags, v->Flags, PROG_PARAM_BIT_INVARIANT)) {
            char msg[100];
            _mesa_snprintf(msg, sizeof(msg),
		     "invariant modifier mismatch for '%s'", var->Name);
            link_error(shProg, msg);
            free(map);
            return GL_FALSE;
         }
      }
      else {
         /* not already in linked list */
         j = _mesa_add_varying(shProg->Varying, var->Name, var->Size,
                               var->Flags);
      }

      if (shProg->Varying->NumParameters > ctx->Const.MaxVarying) {
         link_error(shProg, "Too many varying variables");
         free(map);
         return GL_FALSE;
      }

      /* Map varying[i] to varying[j].
       * Note: the loop here takes care of arrays or large (sz>4) vars.
       */
      {
         GLint sz = var->Size;
         while (sz > 0) {
            inOutFlags[firstVarying + j] = var->Flags;
            /*printf("Link varying from %d to %d\n", i, j);*/
            map[i++] = j++;
            sz -= 4;
         }
         i--; /* go back one */
      }
   }


   /* OK, now scan the program/shader instructions looking for varying vars,
    * replacing the old index with the new index.
    */
   for (i = 0; i < prog->NumInstructions; i++) {
      struct prog_instruction *inst = prog->Instructions + i;
      GLuint j;

      if (inst->DstReg.File == PROGRAM_VARYING) {
         inst->DstReg.File = newFile;
         inst->DstReg.Index = map[ inst->DstReg.Index ] + firstVarying;
      }

      for (j = 0; j < 3; j++) {
         if (inst->SrcReg[j].File == PROGRAM_VARYING) {
            inst->SrcReg[j].File = newFile;
            inst->SrcReg[j].Index = map[ inst->SrcReg[j].Index ] + firstVarying;
         }
      }
   }

   free(map);

   /* these will get recomputed before linking is completed */
   prog->InputsRead = 0x0;
   prog->OutputsWritten = 0x0;

   return GL_TRUE;
}
Esempio n. 4
0
/**
 * Resolve binding of generic vertex attributes.
 * For example, if the vertex shader declared "attribute vec4 foobar" we'll
 * allocate a generic vertex attribute for "foobar" and plug that value into
 * the vertex program instructions.
 * But if the user called glBindAttributeLocation(), those bindings will
 * have priority.
 */
static GLboolean
_slang_resolve_attributes(struct gl_shader_program *shProg,
                          const struct gl_program *origProg,
                          struct gl_program *linkedProg)
{
   GLint attribMap[MAX_VERTEX_GENERIC_ATTRIBS];
   GLuint i, j;
   GLbitfield usedAttributes; /* generics only, not legacy attributes */
   GLbitfield inputsRead = 0x0;

   assert(origProg != linkedProg);
   assert(origProg->Target == GL_VERTEX_PROGRAM_ARB);
   assert(linkedProg->Target == GL_VERTEX_PROGRAM_ARB);

   if (!shProg->Attributes)
      shProg->Attributes = _mesa_new_parameter_list();

   if (linkedProg->Attributes) {
      _mesa_free_parameter_list(linkedProg->Attributes);
   }
   linkedProg->Attributes = _mesa_new_parameter_list();


   /* Build a bitmask indicating which attribute indexes have been
    * explicitly bound by the user with glBindAttributeLocation().
    */
   usedAttributes = 0x0;
   for (i = 0; i < shProg->Attributes->NumParameters; i++) {
      GLint attr = shProg->Attributes->Parameters[i].StateIndexes[0];
      usedAttributes |= (1 << attr);
   }

   /* If gl_Vertex is used, that actually counts against the limit
    * on generic vertex attributes.  This avoids the ambiguity of
    * whether glVertexAttrib4fv(0, v) sets legacy attribute 0 (vert pos)
    * or generic attribute[0].  If gl_Vertex is used, we want the former.
    */
   if (origProg->InputsRead & VERT_BIT_POS) {
      usedAttributes |= 0x1;
   }

   /* initialize the generic attribute map entries to -1 */
   for (i = 0; i < MAX_VERTEX_GENERIC_ATTRIBS; i++) {
      attribMap[i] = -1;
   }

   /*
    * Scan program for generic attribute references
    */
   for (i = 0; i < linkedProg->NumInstructions; i++) {
      struct prog_instruction *inst = linkedProg->Instructions + i;
      for (j = 0; j < 3; j++) {
         if (inst->SrcReg[j].File == PROGRAM_INPUT) {
            inputsRead |= (1 << inst->SrcReg[j].Index);
         }

         if (inst->SrcReg[j].File == PROGRAM_INPUT &&
             inst->SrcReg[j].Index >= VERT_ATTRIB_GENERIC0) {
            /*
             * OK, we've found a generic vertex attribute reference.
             */
            const GLint k = inst->SrcReg[j].Index - VERT_ATTRIB_GENERIC0;

            GLint attr = attribMap[k];

            if (attr < 0) {
               /* Need to figure out attribute mapping now.
                */
               const char *name = origProg->Attributes->Parameters[k].Name;
               const GLint size = origProg->Attributes->Parameters[k].Size;
               const GLenum type =origProg->Attributes->Parameters[k].DataType;
               GLint index;

               /* See if there's a user-defined attribute binding for
                * this name.
                */
               index = _mesa_lookup_parameter_index(shProg->Attributes,
                                                    -1, name);
               if (index >= 0) {
                  /* Found a user-defined binding */
                  attr = shProg->Attributes->Parameters[index].StateIndexes[0];
               }
               else {
                  /* No user-defined binding, choose our own attribute number.
                   * Start at 1 since generic attribute 0 always aliases
                   * glVertex/position.
                   */
                  for (attr = 0; attr < MAX_VERTEX_GENERIC_ATTRIBS; attr++) {
                     if (((1 << attr) & usedAttributes) == 0)
                        break;
                  }
                  if (attr == MAX_VERTEX_GENERIC_ATTRIBS) {
                     link_error(shProg, "Too many vertex attributes");
                     return GL_FALSE;
                  }

                  /* mark this attribute as used */
                  usedAttributes |= (1 << attr);
               }

               attribMap[k] = attr;

               /* Save the final name->attrib binding so it can be queried
                * with glGetAttributeLocation().
                */
               _mesa_add_attribute(linkedProg->Attributes, name,
                                   size, type, attr);
            }

            assert(attr >= 0);

            /* update the instruction's src reg */
            inst->SrcReg[j].Index = VERT_ATTRIB_GENERIC0 + attr;
         }
      }
   }

   /* Handle pre-defined attributes here (gl_Vertex, gl_Normal, etc).
    * When the user queries the active attributes we need to include both
    * the user-defined attributes and the built-in ones.
    */
   for (i = VERT_ATTRIB_POS; i < VERT_ATTRIB_GENERIC0; i++) {
      if (inputsRead & (1 << i)) {
         _mesa_add_attribute(linkedProg->Attributes,
                             _slang_vert_attrib_name(i),
                             4, /* size in floats */
                             _slang_vert_attrib_type(i),
                             -1 /* attrib/input */);
      }
   }

   return GL_TRUE;
}
Esempio n. 5
0
/**
 * Parse a vector source (register, constant, etc):
 *   <vectorSrc>    ::= <absVectorSrc>
 *                    | <baseVectorSrc>
 *   <absVectorSrc> ::= <negate> "|" <baseVectorSrc> "|"
 */
static GLboolean
Parse_VectorSrc(struct parse_state *parseState,
                struct prog_src_register *srcReg)
{
   GLfloat sign = 1.0F;
   GLubyte token[100];
   GLint idx;
   GLuint negateBase, negateAbs;

   /*
    * 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;
      negateAbs = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE;

      if (Parse_String(parseState, "-"))
         negateBase = NEGATE_XYZW;
      else if (Parse_String(parseState, "+"))
         negateBase = NEGATE_NONE;
      else
         negateBase = NEGATE_NONE;
   }
   else {
      srcReg->Abs = GL_FALSE;
      negateAbs = NEGATE_NONE;
      negateBase = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE;
   }

   srcReg->Negate = srcReg->Abs ? negateAbs : negateBase;

   /* This should be the real src vector/register name */
   if (!Peek_Token(parseState, token))
      RETURN_ERROR;

   /* Src reg can be Rn, Hn, f[n], p[n], a named parameter, a scalar
    * literal or vector literal.
    */
   if (token[0] == 'R' || token[0] == 'H') {
      srcReg->File = PROGRAM_TEMPORARY;
      if (!Parse_TempReg(parseState, &idx))
         RETURN_ERROR;
      srcReg->Index = idx;
   }
   else if (token[0] == 'f') {
      /* XXX this might be an identifier! */
      srcReg->File = PROGRAM_INPUT;
      if (!Parse_FragReg(parseState, &idx))
         RETURN_ERROR;
      srcReg->Index = idx;
   }
   else if (token[0] == 'p') {
      /* XXX this might be an identifier! */
      srcReg->File = PROGRAM_LOCAL_PARAM;
      if (!Parse_ProgramParamReg(parseState, &idx))
         RETURN_ERROR;
      srcReg->Index = idx;
   }
   else if (IsLetter(token[0])){
      GLubyte ident[100];
      GLint paramIndex;
      if (!Parse_Identifier(parseState, ident))
         RETURN_ERROR;
      paramIndex = _mesa_lookup_parameter_index(parseState->parameters,
                                                -1, (const char *) ident);
      if (paramIndex < 0) {
         RETURN_ERROR2("Undefined constant or parameter: ", ident);
      }
      srcReg->File = PROGRAM_NAMED_PARAM;
      srcReg->Index = paramIndex;      
   }
   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;
      paramIndex = _mesa_add_unnamed_constant(parseState->parameters,
                                              values, 4, NULL);
      srcReg->File = PROGRAM_NAMED_PARAM;
      srcReg->Index = paramIndex;
   }
   else if (token[0] == '{'){
      /* literal vector constant */
      GLfloat values[4];
      GLuint paramIndex;
      (void) Parse_String(parseState, "{");
      if (!Parse_VectorConstant(parseState, values))
         RETURN_ERROR;
      paramIndex = _mesa_add_unnamed_constant(parseState->parameters,
                                              values, 4, NULL);
      srcReg->File = PROGRAM_NAMED_PARAM;
      srcReg->Index = paramIndex;      
   }
   else {
      RETURN_ERROR2("Invalid source register name", token);
   }

   /* init swizzle fields */
   srcReg->Swizzle = SWIZZLE_NOOP;

   /* Look for optional swizzle suffix */
   if (Parse_String(parseState, ".")) {
      GLuint swz[4];

      if (!Parse_Token(parseState, token))
         RETURN_ERROR;

      if (!Parse_SwizzleSuffix(token, swz))
         RETURN_ERROR1("Invalid swizzle suffix");

      srcReg->Swizzle = MAKE_SWIZZLE4(swz[0], swz[1], swz[2], swz[3]);
   }

   /* Finish absolute value */
   if (srcReg->Abs && !Parse_String(parseState, "|")) {
      RETURN_ERROR1("Expected |");
   }

   return GL_TRUE;
}
Esempio n. 6
0
static GLboolean
Parse_InstructionSequence(struct parse_state *parseState,
                          struct prog_instruction program[])
{
   while (1) {
      struct prog_instruction *inst = program + parseState->numInst;
      struct instruction_pattern instMatch;
      GLubyte token[100];

      /* Initialize the instruction */
      _mesa_init_instructions(inst, 1);

      /* special instructions */
      if (Parse_String(parseState, "DEFINE")) {
         GLubyte id[100];
         GLfloat value[7];  /* yes, 7 to be safe */
         if (!Parse_Identifier(parseState, id))
            RETURN_ERROR;
         /* XXX make sure id is not a reserved identifer, like R9 */
         if (!Parse_String(parseState, "="))
            RETURN_ERROR1("Expected =");
         if (!Parse_VectorOrScalarConstant(parseState, value))
            RETURN_ERROR;
         if (!Parse_String(parseState, ";"))
            RETURN_ERROR1("Expected ;");
         if (_mesa_lookup_parameter_index(parseState->parameters,
                                          -1, (const char *) id) >= 0) {
            RETURN_ERROR2(id, "already defined");
         }
         _mesa_add_named_parameter(parseState->parameters,
                                   (const char *) id, value);
      }
      else if (Parse_String(parseState, "DECLARE")) {
         GLubyte id[100];
         GLfloat value[7] = {0, 0, 0, 0, 0, 0, 0};  /* yes, to be safe */
         if (!Parse_Identifier(parseState, id))
            RETURN_ERROR;
         /* XXX make sure id is not a reserved identifer, like R9 */
         if (Parse_String(parseState, "=")) {
            if (!Parse_VectorOrScalarConstant(parseState, value))
               RETURN_ERROR;
         }
         if (!Parse_String(parseState, ";"))
            RETURN_ERROR1("Expected ;");
         if (_mesa_lookup_parameter_index(parseState->parameters,
                                          -1, (const char *) id) >= 0) {
            RETURN_ERROR2(id, "already declared");
         }
         _mesa_add_named_parameter(parseState->parameters,
                                   (const char *) id, value);
      }
      else if (Parse_String(parseState, "END")) {
         inst->Opcode = OPCODE_END;
         parseState->numInst++;
         if (Parse_Token(parseState, token)) {
            RETURN_ERROR1("Code after END opcode.");
         }
         break;
      }
      else {
         /* general/arithmetic instruction */

         /* get token */
         if (!Parse_Token(parseState, token)) {
            RETURN_ERROR1("Missing END instruction.");
         }

         /* try to find matching instuction */
         instMatch = MatchInstruction(token);
         if (instMatch.opcode >= MAX_OPCODE) {
            /* bad instruction name */
            RETURN_ERROR2("Unexpected token: ", token);
         }

         inst->Opcode = instMatch.opcode;
         inst->Precision = instMatch.suffixes & (_R | _H | _X);
         inst->SaturateMode = (instMatch.suffixes & (_S))
            ? SATURATE_ZERO_ONE : SATURATE_OFF;
         inst->CondUpdate = (instMatch.suffixes & (_C)) ? GL_TRUE : GL_FALSE;

         /*
          * parse the input and output operands
          */
         if (instMatch.outputs == OUTPUT_S || instMatch.outputs == OUTPUT_V) {
            if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
               RETURN_ERROR;
            if (!Parse_String(parseState, ","))
               RETURN_ERROR1("Expected ,");
         }
         else if (instMatch.outputs == OUTPUT_NONE) {
            if (instMatch.opcode == OPCODE_KIL_NV) {
               /* This is a little weird, the cond code info is in
                * the dest register.
                */
               if (!Parse_CondCodeMask(parseState, &inst->DstReg))
                  RETURN_ERROR;
            }
            else {
               ASSERT(instMatch.opcode == OPCODE_PRINT);
            }
         }

         if (instMatch.inputs == INPUT_1V) {
            if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
               RETURN_ERROR;
         }
         else if (instMatch.inputs == INPUT_2V) {
            if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
               RETURN_ERROR;
            if (!Parse_String(parseState, ","))
               RETURN_ERROR1("Expected ,");
            if (!Parse_VectorSrc(parseState, &inst->SrcReg[1]))
               RETURN_ERROR;
         }
         else if (instMatch.inputs == INPUT_3V) {
            if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
               RETURN_ERROR;
            if (!Parse_String(parseState, ","))
               RETURN_ERROR1("Expected ,");
            if (!Parse_VectorSrc(parseState, &inst->SrcReg[1]))
               RETURN_ERROR;
            if (!Parse_String(parseState, ","))
               RETURN_ERROR1("Expected ,");
            if (!Parse_VectorSrc(parseState, &inst->SrcReg[2]))
               RETURN_ERROR;
         }
         else if (instMatch.inputs == INPUT_1S) {
            if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0]))
               RETURN_ERROR;
         }
         else if (instMatch.inputs == INPUT_2S) {
            if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0]))
               RETURN_ERROR;
            if (!Parse_String(parseState, ","))
               RETURN_ERROR1("Expected ,");
            if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[1]))
               RETURN_ERROR;
         }
         else if (instMatch.inputs == INPUT_CC) {
            /* XXX to-do */
         }
         else if (instMatch.inputs == INPUT_1V_T) {
	    GLubyte unit, idx;
            if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
               RETURN_ERROR;
            if (!Parse_String(parseState, ","))
               RETURN_ERROR1("Expected ,");
            if (!Parse_TextureImageId(parseState, &unit, &idx))
               RETURN_ERROR;
	    inst->TexSrcUnit = unit;
	    inst->TexSrcTarget = idx;
         }
         else if (instMatch.inputs == INPUT_3V_T) {
	    GLubyte unit, idx;
            if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
               RETURN_ERROR;
            if (!Parse_String(parseState, ","))
               RETURN_ERROR1("Expected ,");
            if (!Parse_VectorSrc(parseState, &inst->SrcReg[1]))
               RETURN_ERROR;
            if (!Parse_String(parseState, ","))
               RETURN_ERROR1("Expected ,");
            if (!Parse_VectorSrc(parseState, &inst->SrcReg[2]))
               RETURN_ERROR;
            if (!Parse_String(parseState, ","))
               RETURN_ERROR1("Expected ,");
            if (!Parse_TextureImageId(parseState, &unit, &idx))
               RETURN_ERROR;
	    inst->TexSrcUnit = unit;
	    inst->TexSrcTarget = idx;
         }
         else if (instMatch.inputs == INPUT_1V_S) {
            if (!Parse_PrintInstruction(parseState, inst))
               RETURN_ERROR;
         }

         /* end of statement semicolon */
         if (!Parse_String(parseState, ";"))
            RETURN_ERROR1("Expected ;");

         parseState->numInst++;

         if (parseState->numInst >= MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS)
            RETURN_ERROR1("Program too long");
      }
   }
   return GL_TRUE;
}
Esempio n. 7
0
static GLboolean
Parse_ScalarSrcReg(struct parse_state *parseState,
                   struct prog_src_register *srcReg)
{
   GLubyte token[100];
   GLfloat sign = 1.0F;
   GLboolean needSuffix = GL_TRUE;
   GLint idx;
   GLuint negateBase, negateAbs;

   /*
    * 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;
      negateAbs = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE;

      if (Parse_String(parseState, "-"))
         negateBase = NEGATE_XYZW;
      else if (Parse_String(parseState, "+"))
         negateBase = NEGATE_NONE;
      else
         negateBase = NEGATE_NONE;
   }
   else {
      srcReg->Abs = GL_FALSE;
      negateAbs = NEGATE_NONE;
      negateBase = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE;
   }

   srcReg->Negate = srcReg->Abs ? negateAbs : negateBase;

   if (!Peek_Token(parseState, token))
      RETURN_ERROR;

   /* Src reg can be R<n>, H<n> or a named fragment attrib */
   if (token[0] == 'R' || token[0] == 'H') {
      srcReg->File = PROGRAM_TEMPORARY;
      if (!Parse_TempReg(parseState, &idx))
         RETURN_ERROR;
      srcReg->Index = idx;
   }
   else if (token[0] == 'f') {
      srcReg->File = PROGRAM_INPUT;
      if (!Parse_FragReg(parseState, &idx))
         RETURN_ERROR;
      srcReg->Index = idx;
   }
   else if (token[0] == '{') {
      /* vector literal */
      GLfloat values[4];
      GLuint paramIndex;
      (void) Parse_String(parseState, "{");
      if (!Parse_VectorConstant(parseState, values))
         RETURN_ERROR;
      paramIndex = _mesa_add_unnamed_constant(parseState->parameters,
                                              values, 4, NULL);
      srcReg->File = PROGRAM_NAMED_PARAM;
      srcReg->Index = paramIndex;      
   }
   else if (IsLetter(token[0])){
      /* named param/constant */
      GLubyte ident[100];
      GLint paramIndex;
      if (!Parse_Identifier(parseState, ident))
         RETURN_ERROR;
      paramIndex = _mesa_lookup_parameter_index(parseState->parameters,
                                                -1, (const char *) ident);
      if (paramIndex < 0) {
         RETURN_ERROR2("Undefined constant or parameter: ", ident);
      }
      srcReg->File = PROGRAM_NAMED_PARAM;
      srcReg->Index = paramIndex;      
   }
   else if (IsDigit(token[0])) {
      /* scalar literal */
      GLfloat values[4];
      GLuint paramIndex;
      if (!Parse_ScalarConstant(parseState, values))
         RETURN_ERROR;
      paramIndex = _mesa_add_unnamed_constant(parseState->parameters,
                                              values, 4, NULL);
      srcReg->Index = paramIndex;      
      srcReg->File = PROGRAM_NAMED_PARAM;
      needSuffix = GL_FALSE;
   }
   else {
      RETURN_ERROR2("Invalid scalar source argument", token);
   }

   srcReg->Swizzle = 0;
   if (needSuffix) {
      /* parse .[xyzw] suffix */
      if (!Parse_String(parseState, "."))
         RETURN_ERROR1("Expected .");

      if (!Parse_Token(parseState, token))
         RETURN_ERROR;

      if (token[0] == 'x' && token[1] == 0) {
         srcReg->Swizzle = 0;
      }
      else if (token[0] == 'y' && token[1] == 0) {
         srcReg->Swizzle = 1;
      }
      else if (token[0] == 'z' && token[1] == 0) {
         srcReg->Swizzle = 2;
      }
      else if (token[0] == 'w' && token[1] == 0) {
         srcReg->Swizzle = 3;
      }
      else {
         RETURN_ERROR1("Invalid scalar source suffix");
      }
   }

   /* Finish absolute value */
   if (srcReg->Abs && !Parse_String(parseState, "|")) {
      RETURN_ERROR1("Expected |");
   }

   return GL_TRUE;
}