Blame |
Last modification |
View Log
| RSS feed
/* $Id: vpparse.c,v 1.1 2003-02-28 11:42:06 pj Exp $ */
/*
* Mesa 3-D graphics library
* Version: 4.1
*
* Copyright (C) 1999-2001 Brian Paul 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, sublicense,
* 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 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 NONINFRINGEMENT. IN NO EVENT SHALL
* BRIAN PAUL 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.
*/
/*
* -------- Regarding NV_vertex_program --------
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* o Redistribution of the source code must contain a copyright notice
* and this list of conditions;
*
* o Redistribution in binary and source code form must contain the
* following Notice in the software and any documentation and/or other
* materials provided with the distribution; and
*
* o The name of Nvidia may not be used to promote or endorse software
* derived from the software.
*
* NOTICE: Nvidia hereby grants to each recipient a non-exclusive worldwide
* royalty free patent license under patent claims that are licensable by
* Nvidia and which are necessarily required and for which no commercially
* viable non infringing alternative exists to make, use, sell, offer to sell,
* import and otherwise transfer the vertex extension for the Mesa 3D Graphics
* Library as distributed in source code and object code form. No hardware or
* hardware implementation (including a semiconductor implementation and chips)
* are licensed hereunder. If a recipient makes a patent claim or institutes
* patent litigation against Nvidia or Nvidia's customers for use or sale of
* Nvidia products, then this license grant as to such recipient shall
* immediately terminate and recipient immediately agrees to cease use and
* distribution of the Mesa Program and derivatives thereof.
*
* THE MESA 3D GRAPHICS LIBRARY IS PROVIDED ON AN "AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,
* WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-NFRINGEMENT
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
*
* NVIDIA SHALL NOT HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION
* LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE MESA 3D GRAPHICS
* LIBRARY OR EVIDENCE OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDR, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* If you do not comply with this agreement, then Nvidia may cancel the license
* and rights granted herein.
* ---------------------------------------------
*/
/**
* \file vpparse.c
* \brief Vertex program parser.
* \author Brian Paul
*/
#include "glheader.h"
#include "context.h"
#include "hash.h"
#include "imports.h"
#include "macros.h"
#include "mtypes.h"
#include "vpparse.h"
/************************ Symbol Table ******************************/
/* A simple symbol table implementation for ARB_vertex_program
* (not used yet)
*/
#if 000
struct symbol
{
GLubyte
*name
;
GLint value
;
struct symbol
*next
;
};
static struct symbol
*SymbolTable
= NULL
;
static GLboolean
IsSymbol
(const GLubyte
*symbol
)
{
struct symbol
*s
;
for (s
= SymbolTable
; s
; s
= s
->next
) {
if (strcmp((char *) symbol
, (char *)s
->name
) == 0)
return GL_TRUE
;
}
return GL_FALSE
;
}
static GLint
GetSymbolValue
(const GLubyte
*symbol
)
{
struct symbol
*s
;
for (s
= SymbolTable
; s
; s
= s
->next
) {
if (strcmp((char *) symbol
, (char *)s
->name
) == 0)
return s
->value
;
}
return 0;
}
static void
AddSymbol
(const GLubyte
*symbol
, GLint value
)
{
struct symbol
*s
= MALLOC_STRUCT
(symbol
);
if (s
) {
s
->name
= (GLubyte
*) strdup
((char *) symbol
);
s
->value
= value
;
s
->next
= SymbolTable
;
SymbolTable
= s
;
}
}
static void
ResetSymbolTable
(void)
{
struct symbol
*s
, *next
;
for (s
= SymbolTable
; s
; s
= next
) {
next
= s
->next
;
FREE
(s
->name
);
FREE
(s
);
s
= next
;
}
SymbolTable
= NULL
;
}
#endif
/***************************** Parsing ******************************/
static GLboolean IsLetter
(GLubyte b
)
{
return (b
>= 'a' && b
<= 'z') || (b
>= 'A' && b
<= 'Z');
}
static GLboolean IsDigit
(GLubyte b
)
{
return b
>= '0' && b
<= '9';
}
static GLboolean IsWhitespace
(GLubyte b
)
{
return b
== ' ' || b
== '\t' || b
== '\n' || b
== '\r';
}
/**
* Starting at 'str' find the next token. A token can be an integer,
* an identifier or punctuation symbol.
* \return <= 0 we found an error, else, return number of characters parsed.
*/
static GLint
GetToken
(const GLubyte
*str
, GLubyte
*token
)
{
GLint i
= 0, j
= 0;
token
[0] = 0;
/* skip whitespace and comments */
while (str
[i
] && (IsWhitespace
(str
[i
]) || str
[i
] == '#')) {
if (str
[i
] == '#') {
/* skip comment */
while (str
[i
] && (str
[i
] != '\n' && str
[i
] != '\r')) {
i
++;
}
}
else {
/* skip whitespace */
i
++;
}
}
if (str
[i
] == 0)
return -i
;
/* try matching an integer */
while (str
[i
] && IsDigit
(str
[i
])) {
token
[j
++] = str
[i
++];
}
if (j
> 0 || !str
[i
]) {
token
[j
] = 0;
return i
;
}
/* try matching an identifier */
if (IsLetter
(str
[i
])) {
while (str
[i
] && (IsLetter
(str
[i
]) || IsDigit
(str
[i
]))) {
token
[j
++] = str
[i
++];
}
token
[j
] = 0;
return i
;
}
/* punctuation */
if (str
[i
]) {
token
[0] = str
[i
++];
token
[1] = 0;
return i
;
}
/* end of input */
token
[0] = 0;
return i
;
}
/**
* Get next token from input stream and increment stream pointer past token.
*/
static GLboolean
Parse_Token
(const GLubyte
**s
, GLubyte
*token
)
{
GLint i
;
i
= GetToken
(*s
, token
);
if (i
<= 0) {
*s
+= (-i
);
return GL_FALSE
;
}
*s
+= i
;
return GL_TRUE
;
}
/**
* Get next token from input stream but don't increment stream pointer.
*/
static GLboolean
Peek_Token
(const GLubyte
**s
, GLubyte
*token
)
{
GLint i
, len
;
i
= GetToken
(*s
, token
);
if (i
<= 0) {
*s
+= (-i
);
return GL_FALSE
;
}
len
= _mesa_strlen
((char *) token
);
*s
+= (i
- len
);
return GL_TRUE
;
}
/**
* String equality test
*/
static GLboolean
StrEq
(const GLubyte
*a
, const GLubyte
*b
)
{
GLint i
;
for (i
= 0; a
[i
] && b
[i
] && a
[i
] == b
[i
]; i
++)
;
if (a
[i
] == 0 && b
[i
] == 0)
return GL_TRUE
;
else
return GL_FALSE
;
}
/**********************************************************************/
static const char *InputRegisters
[] = {
"OPOS", "WGHT", "NRML", "COL0", "COL1", "FOGC", "6", "7",
"TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", NULL
};
static const char *OutputRegisters
[] = {
"HPOS", "COL0", "COL1", "BFC0", "BFC1", "FOGC", "PSIZ",
"TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", NULL
};
static const char *Opcodes
[] = {
"MOV", "LIT", "RCP", "RSQ", "EXP", "LOG", "MUL", "ADD", "DP3", "DP4",
"DST", "MIN", "MAX", "SLT", "SGE", "MAD", "ARL", "DPH", "RCC", "SUB",
"ABS", "END", NULL
};
#ifdef DEBUG
#define PARSE_ERROR \
do { \
_mesa_printf("vpparse.c error at %d: parse error\n", __LINE__); \
return GL_FALSE; \
} while(0)
#define PARSE_ERROR1(msg) \
do { \
_mesa_printf("vpparse.c error at %d: %s\n", __LINE__, msg); \
return GL_FALSE; \
} while(0)
#define PARSE_ERROR2(msg1, msg2) \
do { \
_mesa_printf("vpparse.c error at %d: %s %s\n", __LINE__, msg1, msg2); \
return GL_FALSE; \
} while(0)
#else
#define PARSE_ERROR return GL_FALSE
#define PARSE_ERROR1(msg1) return GL_FALSE
#define PARSE_ERROR2(msg1, msg2) return GL_FALSE
#endif
static GLuint
IsProgRegister
(GLuint r
)
{
return (GLuint
) (r
>= VP_PROG_REG_START
&& r
<= VP_PROG_REG_END
);
}
static GLuint
IsInputRegister
(GLuint r
)
{
return (GLuint
) (r
>= VP_INPUT_REG_START
&& r
<= VP_INPUT_REG_END
);
}
static GLuint
IsOutputRegister
(GLuint r
)
{
return (GLuint
) (r
>= VP_OUTPUT_REG_START
&& r
<= VP_OUTPUT_REG_END
);
}
/**********************************************************************/
/* XXX
* These shouldn't be globals as that makes the parser non-reentrant.
* We should really define a "ParserContext" class which contains these
* and the <s> pointer into the program text.
*/
static GLboolean IsStateProgram
= GL_FALSE
;
static GLboolean IsPositionInvariant
= GL_FALSE
;
static GLboolean IsVersion1_1
= GL_FALSE
;
/**
* Try to match 'pattern' as the next token after any whitespace/comments.
*/
static GLboolean
Parse_String
(const GLubyte
**s
, const char *pattern
)
{
GLint i
;
/* skip whitespace and comments */
while (IsWhitespace
(**s
) || **s
== '#') {
if (**s
== '#') {
while (**s
&& (**s
!= '\n' && **s
!= '\r')) {
*s
+= 1;
}
}
else {
/* skip whitespace */
*s
+= 1;
}
}
/* Try to match the pattern */
for (i
= 0; pattern
[i
]; i
++) {
if (**s
!= pattern
[i
])
PARSE_ERROR2
("failed to match", pattern
); /* failure */
*s
+= 1;
}
return GL_TRUE
; /* success */
}
/**
* Parse a temporary register: Rnn
*/
static GLboolean
Parse_TempReg
(const GLubyte
**s
, GLint
*tempRegNum
)
{
GLubyte token
[100];
/* Should be 'R##' */
if (!Parse_Token
(s
, token
))
PARSE_ERROR
;
if (token
[0] != 'R')
PARSE_ERROR1
("Expected R##");
if (IsDigit
(token
[1])) {
GLint reg
= _mesa_atoi
((char *) (token
+ 1));
if (reg
>= VP_NUM_TEMP_REGS
)
PARSE_ERROR1
("Bad temporary register name");
*tempRegNum
= VP_TEMP_REG_START
+ reg
;
}
else {
PARSE_ERROR1
("Bad temporary register name");
}
return GL_TRUE
;
}
/**
* Parse address register "A0.x"
*/
static GLboolean
Parse_AddrReg
(const GLubyte
**s
)
{
/* match 'A0' */
if (!Parse_String
(s
, "A0"))
PARSE_ERROR
;
/* match '.' */
if (!Parse_String
(s
, "."))
PARSE_ERROR
;
/* match 'x' */
if (!Parse_String
(s
, "x"))
PARSE_ERROR
;
return GL_TRUE
;
}
/**
* Parse absolute program parameter register "c[##]"
*/
static GLboolean
Parse_AbsParamReg
(const GLubyte
**s
, GLint
*regNum
)
{
GLubyte token
[100];
if (!Parse_String
(s
, "c"))
PARSE_ERROR
;
if (!Parse_String
(s
, "["))
PARSE_ERROR
;
if (!Parse_Token
(s
, token
))
PARSE_ERROR
;
if (IsDigit
(token
[0])) {
/* a numbered program parameter register */
GLint reg
= _mesa_atoi
((char *) token
);
if (reg
>= VP_NUM_PROG_REGS
)
PARSE_ERROR1
("Bad constant program number");
*regNum
= VP_PROG_REG_START
+ reg
;
}
else {
PARSE_ERROR
;
}
if (!Parse_String
(s
, "]"))
PARSE_ERROR
;
return GL_TRUE
;
}
static GLboolean
Parse_ParamReg
(const GLubyte
**s
, struct vp_src_register
*srcReg
)
{
GLubyte token
[100];
if (!Parse_String
(s
, "c"))
PARSE_ERROR
;
if (!Parse_String
(s
, "["))
PARSE_ERROR
;
if (!Peek_Token
(s
, token
))
PARSE_ERROR
;
if (IsDigit
(token
[0])) {
/* a numbered program parameter register */
GLint reg
;
(void) Parse_Token
(s
, token
);
reg
= _mesa_atoi
((char *) token
);
if (reg
>= VP_NUM_PROG_REGS
)
PARSE_ERROR1
("Bad constant program number");
srcReg
->Register
= VP_PROG_REG_START
+ reg
;
}
else if (StrEq
(token
, (GLubyte
*) "A0")) {
/* address register "A0.x" */
if (!Parse_AddrReg
(s
))
PARSE_ERROR
;
srcReg
->RelAddr
= GL_TRUE
;
srcReg
->Register
= 0;
/* Look for +/-N offset */
if (!Peek_Token
(s
, token
))
PARSE_ERROR
;
if (token
[0] == '-' || token
[0] == '+') {
const GLubyte sign
= token
[0];
(void) Parse_Token
(s
, token
); /* consume +/- */
/* an integer should be next */
if (!Parse_Token
(s
, token
))
PARSE_ERROR
;
if (IsDigit
(token
[0])) {
const GLint k
= _mesa_atoi
((char *) token
);
if (sign
== '-') {
if (k
> 64)
PARSE_ERROR1
("Bad address offset");
srcReg
->Register
= -k
;
}
else {
if (k
> 63)
PARSE_ERROR1
("Bad address offset");
srcReg
->Register
= k
;
}
}
else {
PARSE_ERROR
;
}
}
else {
/* probably got a ']', catch it below */
}
}
else {
PARSE_ERROR
;
}
/* Match closing ']' */
if (!Parse_String
(s
, "]"))
PARSE_ERROR
;
return GL_TRUE
;
}
/**
* Parse v[#] or v[<name>]
*/
static GLboolean
Parse_AttribReg
(const GLubyte
**s
, GLint
*tempRegNum
)
{
GLubyte token
[100];
GLint j
;
/* Match 'v' */
if (!Parse_String
(s
, "v"))
PARSE_ERROR
;
/* Match '[' */
if (!Parse_String
(s
, "["))
PARSE_ERROR
;
/* match number or named register */
if (!Parse_Token
(s
, token
))
PARSE_ERROR
;
if (IsStateProgram
&& token
[0] != '0')
PARSE_ERROR1
("Only v[0] accessible in vertex state programs");
if (IsDigit
(token
[0])) {
GLint reg
= _mesa_atoi
((char *) token
);
if (reg
>= VP_NUM_INPUT_REGS
)
PARSE_ERROR1
("Bad vertex attribute register name");
*tempRegNum
= VP_INPUT_REG_START
+ reg
;
}
else {
for (j
= 0; InputRegisters
[j
]; j
++) {
if (StrEq
(token
, (const GLubyte
*) InputRegisters
[j
])) {
*tempRegNum
= VP_INPUT_REG_START
+ j
;
break;
}
}
if (!InputRegisters
[j
]) {
/* unknown input register label */
PARSE_ERROR2
("Bad register name", token
);
}
}
/* Match '[' */
if (!Parse_String
(s
, "]"))
PARSE_ERROR
;
return GL_TRUE
;
}
static GLboolean
Parse_OutputReg
(const GLubyte
**s
, GLint
*outputRegNum
)
{
GLubyte token
[100];
GLint start
, j
;
/* Match 'o' */
if (!Parse_String
(s
, "o"))
PARSE_ERROR
;
/* Match '[' */
if (!Parse_String
(s
, "["))
PARSE_ERROR
;
/* Get output reg name */
if (!Parse_Token
(s
, token
))
PARSE_ERROR
;
if (IsPositionInvariant
)
start
= 1; /* skip HPOS register name */
else
start
= 0;
/* try to match an output register name */
for (j
= start
; OutputRegisters
[j
]; j
++) {
if (StrEq
(token
, (const GLubyte
*) OutputRegisters
[j
])) {
*outputRegNum
= VP_OUTPUT_REG_START
+ j
;
break;
}
}
if (!OutputRegisters
[j
])
PARSE_ERROR1
("Unrecognized output register name");
/* Match ']' */
if (!Parse_String
(s
, "]"))
PARSE_ERROR1
("Expected ]");
return GL_TRUE
;
}
static GLboolean
Parse_MaskedDstReg
(const GLubyte
**s
, struct vp_dst_register
*dstReg
)
{
GLubyte token
[100];
/* Dst reg can be R<n> or o[n] */
if (!Peek_Token
(s
, token
))
PARSE_ERROR
;
if (token
[0] == 'R') {
/* a temporary register */
if (!Parse_TempReg
(s
, &dstReg
->Register
))
PARSE_ERROR
;
}
else if (!IsStateProgram
&& token
[0] == 'o') {
/* an output register */
if (!Parse_OutputReg
(s
, &dstReg
->Register
))
PARSE_ERROR
;
}
else if (IsStateProgram
&& token
[0] == 'c') {
/* absolute program parameter register */
if (!Parse_AbsParamReg
(s
, &dstReg
->Register
))
PARSE_ERROR
;
}
else {
PARSE_ERROR1
("Bad destination register name");
}
/* Parse optional write mask */
if (!Peek_Token
(s
, token
))
PARSE_ERROR
;
if (token
[0] == '.') {
/* got a mask */
GLint k
= 0;
if (!Parse_String
(s
, "."))
PARSE_ERROR
;
if (!Parse_Token
(s
, token
))
PARSE_ERROR
;
dstReg
->WriteMask
[0] = GL_FALSE
;
dstReg
->WriteMask
[1] = GL_FALSE
;
dstReg
->WriteMask
[2] = GL_FALSE
;
dstReg
->WriteMask
[3] = GL_FALSE
;
if (token
[k
] == 'x') {
dstReg
->WriteMask
[0] = GL_TRUE
;
k
++;
}
if (token
[k
] == 'y') {
dstReg
->WriteMask
[1] = GL_TRUE
;
k
++;
}
if (token
[k
] == 'z') {
dstReg
->WriteMask
[2] = GL_TRUE
;
k
++;
}
if (token
[k
] == 'w') {
dstReg
->WriteMask
[3] = GL_TRUE
;
k
++;
}
if (k
== 0) {
PARSE_ERROR1
("Bad writemask character");
}
return GL_TRUE
;
}
else {
dstReg
->WriteMask
[0] = GL_TRUE
;
dstReg
->WriteMask
[1] = GL_TRUE
;
dstReg
->WriteMask
[2] = GL_TRUE
;
dstReg
->WriteMask
[3] = GL_TRUE
;
return GL_TRUE
;
}
}
static GLboolean
Parse_SwizzleSrcReg
(const GLubyte
**s
, struct vp_src_register
*srcReg
)
{
GLubyte token
[100];
srcReg
->RelAddr
= GL_FALSE
;
/* check for '-' */
if (!Peek_Token
(s
, token
))
PARSE_ERROR
;
if (token
[0] == '-') {
(void) Parse_String
(s
, "-");
srcReg
->Negate
= GL_TRUE
;
if (!Peek_Token
(s
, token
))
PARSE_ERROR
;
}
else {
srcReg
->Negate
= GL_FALSE
;
}
/* Src reg can be R<n>, c[n], c[n +/- offset], or a named vertex attrib */
if (token
[0] == 'R') {
if (!Parse_TempReg
(s
, &srcReg
->Register
))
PARSE_ERROR
;
}
else if (token
[0] == 'c') {
if (!Parse_ParamReg
(s
, srcReg
))
PARSE_ERROR
;
}
else if (token
[0] == 'v') {
if (!Parse_AttribReg
(s
, &srcReg
->Register
))
PARSE_ERROR
;
}
else {
PARSE_ERROR2
("Bad source register name", token
);
}
/* init swizzle fields */
srcReg
->Swizzle
[0] = 0;
srcReg
->Swizzle
[1] = 1;
srcReg
->Swizzle
[2] = 2;
srcReg
->Swizzle
[3] = 3;
/* Look for optional swizzle suffix */
if (!Peek_Token
(s
, token
))
PARSE_ERROR
;
if (token
[0] == '.') {
(void) Parse_String
(s
, "."); /* consume . */
if (!Parse_Token
(s
, token
))
PARSE_ERROR
;
if (token
[1] == 0) {
/* single letter swizzle */
if (token
[0] == 'x')
ASSIGN_4V
(srcReg
->Swizzle
, 0, 0, 0, 0);
else if (token
[0] == 'y')
ASSIGN_4V
(srcReg
->Swizzle
, 1, 1, 1, 1);
else if (token
[0] == 'z')
ASSIGN_4V
(srcReg
->Swizzle
, 2, 2, 2, 2);
else if (token
[0] == 'w')
ASSIGN_4V
(srcReg
->Swizzle
, 3, 3, 3, 3);
else
PARSE_ERROR1
("Expected x, y, z, or w");
}
else {
/* 2, 3 or 4-component swizzle */
GLint k
;
for (k
= 0; token
[k
] && k
< 5; k
++) {
if (token
[k
] == 'x')
srcReg
->Swizzle
[k
] = 0;
else if (token
[k
] == 'y')
srcReg
->Swizzle
[k
] = 1;
else if (token
[k
] == 'z')
srcReg
->Swizzle
[k
] = 2;
else if (token
[k
] == 'w')
srcReg
->Swizzle
[k
] = 3;
else
PARSE_ERROR
;
}
if (k
>= 5)
PARSE_ERROR
;
}
}
return GL_TRUE
;
}
static GLboolean
Parse_ScalarSrcReg
(const GLubyte
**s
, struct vp_src_register
*srcReg
)
{
GLubyte token
[100];
srcReg
->RelAddr
= GL_FALSE
;
/* check for '-' */
if (!Peek_Token
(s
, token
))
PARSE_ERROR
;
if (token
[0] == '-') {
srcReg
->Negate
= GL_TRUE
;
(void) Parse_String
(s
, "-"); /* consume '-' */
if (!Peek_Token
(s
, token
))
PARSE_ERROR
;
}
else {
srcReg
->Negate
= GL_FALSE
;
}
/* Src reg can be R<n>, c[n], c[n +/- offset], or a named vertex attrib */
if (token
[0] == 'R') {
if (!Parse_TempReg
(s
, &srcReg
->Register
))
PARSE_ERROR
;
}
else if (token
[0] == 'c') {
if (!Parse_ParamReg
(s
, srcReg
))
PARSE_ERROR
;
}
else if (token
[0] == 'v') {
if (!Parse_AttribReg
(s
, &srcReg
->Register
))
PARSE_ERROR
;
}
else {
PARSE_ERROR2
("Bad source register name", token
);
}
/* Look for .[xyzw] suffix */
if (!Parse_String
(s
, "."))
PARSE_ERROR
;
if (!Parse_Token
(s
, token
))
PARSE_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;
}
else {
PARSE_ERROR1
("Bad scalar source suffix");
}
srcReg
->Swizzle
[1] = srcReg
->Swizzle
[2] = srcReg
->Swizzle
[3] = 0;
return GL_TRUE
;
}
static GLint
Parse_UnaryOpInstruction
(const GLubyte
**s
, struct vp_instruction
*inst
)
{
GLubyte token
[100];
/* opcode */
if (!Parse_Token
(s
, token
))
PARSE_ERROR
;
if (StrEq
(token
, (GLubyte
*) "MOV")) {
inst
->Opcode
= MOV
;
}
else if (StrEq
(token
, (GLubyte
*) "LIT")) {
inst
->Opcode
= LIT
;
}
else if (StrEq
(token
, (GLubyte
*) "ABS") && IsVersion1_1
) {
inst
->Opcode
= ABS
;
}
else {
PARSE_ERROR
;
}
/* dest reg */
if (!Parse_MaskedDstReg
(s
, &inst
->DstReg
))
PARSE_ERROR
;
/* comma */
if (!Parse_String
(s
, ","))
PARSE_ERROR
;
/* src arg */
if (!Parse_SwizzleSrcReg
(s
, &inst
->SrcReg
[0]))
PARSE_ERROR
;
/* semicolon */
if (!Parse_String
(s
, ";"))
PARSE_ERROR
;
return GL_TRUE
;
}
static GLboolean
Parse_BiOpInstruction
(const GLubyte
**s
, struct vp_instruction
*inst
)
{
GLubyte token
[100];
/* opcode */
if (!Parse_Token
(s
, token
))
PARSE_ERROR
;
if (StrEq
(token
, (GLubyte
*) "MUL")) {
inst
->Opcode
= MUL
;
}
else if (StrEq
(token
, (GLubyte
*) "ADD")) {
inst
->Opcode
= ADD
;
}
else if (StrEq
(token
, (GLubyte
*) "DP3")) {
inst
->Opcode
= DP3
;
}
else if (StrEq
(token
, (GLubyte
*) "DP4")) {
inst
->Opcode
= DP4
;
}
else if (StrEq
(token
, (GLubyte
*) "DST")) {
inst
->Opcode
= DST
;
}
else if (StrEq
(token
, (GLubyte
*) "MIN")) {
inst
->Opcode
= ADD
;
}
else if (StrEq
(token
, (GLubyte
*) "MAX")) {
inst
->Opcode
= ADD
;
}
else if (StrEq
(token
, (GLubyte
*) "SLT")) {
inst
->Opcode
= SLT
;
}
else if (StrEq
(token
, (GLubyte
*) "SGE")) {
inst
->Opcode
= SGE
;
}
else if (StrEq
(token
, (GLubyte
*) "DPH") && IsVersion1_1
) {
inst
->Opcode
= DPH
;
}
else if (StrEq
(token
, (GLubyte
*) "SUB") && IsVersion1_1
) {
inst
->Opcode
= SUB
;
}
else {
PARSE_ERROR
;
}
/* dest reg */
if (!Parse_MaskedDstReg
(s
, &inst
->DstReg
))
PARSE_ERROR
;
/* comma */
if (!Parse_String
(s
, ","))
PARSE_ERROR
;
/* first src arg */
if (!Parse_SwizzleSrcReg
(s
, &inst
->SrcReg
[0]))
PARSE_ERROR
;
/* comma */
if (!Parse_String
(s
, ","))
PARSE_ERROR
;
/* second src arg */
if (!Parse_SwizzleSrcReg
(s
, &inst
->SrcReg
[1]))
PARSE_ERROR
;
/* semicolon */
if (!Parse_String
(s
, ";"))
PARSE_ERROR
;
/* make sure we don't reference more than one program parameter register */
if (IsProgRegister
(inst
->SrcReg
[0].
Register) &&
IsProgRegister
(inst
->SrcReg
[1].
Register) &&
inst
->SrcReg
[0].
Register != inst
->SrcReg
[1].
Register)
PARSE_ERROR1
("Can't reference two program parameter registers");
/* make sure we don't reference more than one vertex attribute register */
if (IsInputRegister
(inst
->SrcReg
[0].
Register) &&
IsInputRegister
(inst
->SrcReg
[1].
Register) &&
inst
->SrcReg
[0].
Register != inst
->SrcReg
[1].
Register)
PARSE_ERROR1
("Can't reference two vertex attribute registers");
return GL_TRUE
;
}
static GLboolean
Parse_TriOpInstruction
(const GLubyte
**s
, struct vp_instruction
*inst
)
{
GLubyte token
[100];
/* opcode */
if (!Parse_Token
(s
, token
))
PARSE_ERROR
;
if (StrEq
(token
, (GLubyte
*) "MAD")) {
inst
->Opcode
= MAD
;
}
else {
PARSE_ERROR
;
}
/* dest reg */
if (!Parse_MaskedDstReg
(s
, &inst
->DstReg
))
PARSE_ERROR
;
/* comma */
if (!Parse_String
(s
, ","))
PARSE_ERROR
;
/* first src arg */
if (!Parse_SwizzleSrcReg
(s
, &inst
->SrcReg
[0]))
PARSE_ERROR
;
/* comma */
if (!Parse_String
(s
, ","))
PARSE_ERROR
;
/* second src arg */
if (!Parse_SwizzleSrcReg
(s
, &inst
->SrcReg
[1]))
PARSE_ERROR
;
/* comma */
if (!Parse_String
(s
, ","))
PARSE_ERROR
;
/* third src arg */
if (!Parse_SwizzleSrcReg
(s
, &inst
->SrcReg
[2]))
PARSE_ERROR
;
/* semicolon */
if (!Parse_String
(s
, ";"))
PARSE_ERROR
;
/* make sure we don't reference more than one program parameter register */
if ((IsProgRegister
(inst
->SrcReg
[0].
Register) &&
IsProgRegister
(inst
->SrcReg
[1].
Register) &&
inst
->SrcReg
[0].
Register != inst
->SrcReg
[1].
Register) ||
(IsProgRegister
(inst
->SrcReg
[0].
Register) &&
IsProgRegister
(inst
->SrcReg
[2].
Register) &&
inst
->SrcReg
[0].
Register != inst
->SrcReg
[2].
Register) ||
(IsProgRegister
(inst
->SrcReg
[1].
Register) &&
IsProgRegister
(inst
->SrcReg
[2].
Register) &&
inst
->SrcReg
[1].
Register != inst
->SrcReg
[2].
Register))
PARSE_ERROR1
("Can only reference one program register");
/* make sure we don't reference more than one vertex attribute register */
if ((IsInputRegister
(inst
->SrcReg
[0].
Register) &&
IsInputRegister
(inst
->SrcReg
[1].
Register) &&
inst
->SrcReg
[0].
Register != inst
->SrcReg
[1].
Register) ||
(IsInputRegister
(inst
->SrcReg
[0].
Register) &&
IsInputRegister
(inst
->SrcReg
[2].
Register) &&
inst
->SrcReg
[0].
Register != inst
->SrcReg
[2].
Register) ||
(IsInputRegister
(inst
->SrcReg
[1].
Register) &&
IsInputRegister
(inst
->SrcReg
[2].
Register) &&
inst
->SrcReg
[1].
Register != inst
->SrcReg
[2].
Register))
PARSE_ERROR1
("Can only reference one input register");
return GL_TRUE
;
}
static GLboolean
Parse_ScalarInstruction
(const GLubyte
**s
, struct vp_instruction
*inst
)
{
GLubyte token
[100];
/* opcode */
if (!Parse_Token
(s
, token
))
PARSE_ERROR
;
if (StrEq
(token
, (GLubyte
*) "RCP")) {
inst
->Opcode
= RCP
;
}
else if (StrEq
(token
, (GLubyte
*) "RSQ")) {
inst
->Opcode
= RSQ
;
}
else if (StrEq
(token
, (GLubyte
*) "EXP")) {
inst
->Opcode
= EXP
;
}
else if (StrEq
(token
, (GLubyte
*) "LOG")) {
inst
->Opcode
= LOG
;
}
else if (StrEq
(token
, (GLubyte
*) "RCC") && IsVersion1_1
) {
inst
->Opcode
= RCC
;
}
else {
PARSE_ERROR
;
}
/* dest reg */
if (!Parse_MaskedDstReg
(s
, &inst
->DstReg
))
PARSE_ERROR
;
/* comma */
if (!Parse_String
(s
, ","))
PARSE_ERROR
;
/* first src arg */
if (!Parse_ScalarSrcReg
(s
, &inst
->SrcReg
[0]))
PARSE_ERROR
;
/* semicolon */
if (!Parse_String
(s
, ";"))
PARSE_ERROR
;
return GL_TRUE
;
}
static GLboolean
Parse_AddressInstruction
(const GLubyte
**s
, struct vp_instruction
*inst
)
{
inst
->Opcode
= ARL
;
/* opcode */
if (!Parse_String
(s
, "ARL"))
PARSE_ERROR
;
/* dest A0 reg */
if (!Parse_AddrReg
(s
))
PARSE_ERROR
;
/* comma */
if (!Parse_String
(s
, ","))
PARSE_ERROR
;
/* parse src reg */
if (!Parse_ScalarSrcReg
(s
, &inst
->SrcReg
[0]))
PARSE_ERROR
;
/* semicolon */
if (!Parse_String
(s
, ";"))
PARSE_ERROR
;
return GL_TRUE
;
}
static GLboolean
Parse_EndInstruction
(const GLubyte
**s
, struct vp_instruction
*inst
)
{
GLubyte token
[100];
/* opcode */
if (!Parse_String
(s
, "END"))
PARSE_ERROR
;
inst
->Opcode
= END
;
/* this should fail! */
if (Parse_Token
(s
, token
))
PARSE_ERROR2
("Unexpected token after END:", token
);
else
return GL_TRUE
;
}
static GLboolean
Parse_OptionSequence
(const GLubyte
**s
, struct vp_instruction program
[])
{
while (1) {
GLubyte token
[100];
if (!Peek_Token
(s
, token
)) {
PARSE_ERROR1
("Unexpected end of input");
return GL_FALSE
; /* end of input */
}
if (!StrEq
(token
, (GLubyte
*) "OPTION"))
return GL_TRUE
; /* probably an instruction */
Parse_Token
(s
, token
);
if (!Parse_String
(s
, "NV_position_invariant"))
return GL_FALSE
;
if (!Parse_String
(s
, ";"))
return GL_FALSE
;
IsPositionInvariant
= GL_TRUE
;
}
}
static GLboolean
Parse_InstructionSequence
(const GLubyte
**s
, struct vp_instruction program
[])
{
GLubyte token
[100];
GLint count
= 0;
while (1) {
struct vp_instruction
*inst
= program
+ count
;
/* Initialize the instruction */
inst
->SrcReg
[0].
Register = -1;
inst
->SrcReg
[1].
Register = -1;
inst
->SrcReg
[2].
Register = -1;
inst
->DstReg.
Register = -1;
if (!Peek_Token
(s
, token
))
PARSE_ERROR
;
if (StrEq
(token
, (GLubyte
*) "MOV") ||
StrEq
(token
, (GLubyte
*) "LIT") ||
StrEq
(token
, (GLubyte
*) "ABS")) {
if (!Parse_UnaryOpInstruction
(s
, inst
))
PARSE_ERROR
;
}
else if (StrEq
(token
, (GLubyte
*) "MUL") ||
StrEq
(token
, (GLubyte
*) "ADD") ||
StrEq
(token
, (GLubyte
*) "DP3") ||
StrEq
(token
, (GLubyte
*) "DP4") ||
StrEq
(token
, (GLubyte
*) "DST") ||
StrEq
(token
, (GLubyte
*) "MIN") ||
StrEq
(token
, (GLubyte
*) "MAX") ||
StrEq
(token
, (GLubyte
*) "SLT") ||
StrEq
(token
, (GLubyte
*) "SGE") ||
StrEq
(token
, (GLubyte
*) "DPH") ||
StrEq
(token
, (GLubyte
*) "SUB")) {
if (!Parse_BiOpInstruction
(s
, inst
))
PARSE_ERROR
;
}
else if (StrEq
(token
, (GLubyte
*) "MAD")) {
if (!Parse_TriOpInstruction
(s
, inst
))
PARSE_ERROR
;
}
else if (StrEq
(token
, (GLubyte
*) "RCP") ||
StrEq
(token
, (GLubyte
*) "RSQ") ||
StrEq
(token
, (GLubyte
*) "EXP") ||
StrEq
(token
, (GLubyte
*) "LOG") ||
StrEq
(token
, (GLubyte
*) "RCC")) {
if (!Parse_ScalarInstruction
(s
, inst
))
PARSE_ERROR
;
}
else if (StrEq
(token
, (GLubyte
*) "ARL")) {
if (!Parse_AddressInstruction
(s
, inst
))
PARSE_ERROR
;
}
else if (StrEq
(token
, (GLubyte
*) "END")) {
if (!Parse_EndInstruction
(s
, inst
))
PARSE_ERROR
;
else
return GL_TRUE
; /* all done */
}
else {
/* bad instruction name */
PARSE_ERROR2
("Unexpected token: ", token
);
}
count
++;
if (count
>= VP_MAX_INSTRUCTIONS
)
PARSE_ERROR1
("Program too long");
}
PARSE_ERROR
;
}
static GLboolean
Parse_Program
(const GLubyte
**s
, struct vp_instruction instBuffer
[])
{
if (IsVersion1_1
) {
if (!Parse_OptionSequence
(s
, instBuffer
)) {
return GL_FALSE
;
}
}
return Parse_InstructionSequence
(s
, instBuffer
);
}
/**
* Parse/compile the 'str' returning the compiled 'program'.
* ctx->VertexProgram.ErrorPos will be -1 if successful. Otherwise, ErrorPos
* indicates the position of the error in 'str'.
*/
void
_mesa_parse_program
(GLcontext
*ctx
, GLenum dstTarget
,
const GLubyte
*str
, struct vp_program
*program
)
{
const GLubyte
*s
;
struct vp_instruction instBuffer
[VP_MAX_INSTRUCTIONS
];
GLubyte
*newString
;
struct vp_instruction
*newInst
;
GLenum target
;
ctx
->VertexProgram.
ErrorPos = -1;
IsPositionInvariant
= GL_FALSE
;
IsVersion1_1
= GL_FALSE
;
/* check the program header */
if (_mesa_strncmp
((const char *) str
, "!!VP1.0", 7) == 0) {
target
= GL_VERTEX_PROGRAM_NV
;
s
= str
+ 7;
IsStateProgram
= GL_FALSE
;
}
else if (_mesa_strncmp
((const char *) str
, "!!VP1.1", 7) == 0) {
target
= GL_VERTEX_PROGRAM_NV
;
s
= str
+ 7;
IsStateProgram
= GL_FALSE
;
IsVersion1_1
= GL_TRUE
;
}
else if (_mesa_strncmp
((const char *) str
, "!!VSP1.0", 8) == 0) {
target
= GL_VERTEX_STATE_PROGRAM_NV
;
s
= str
+ 8;
IsStateProgram
= GL_TRUE
;
}
else {
/* invalid header */
ctx
->VertexProgram.
ErrorPos = 0;
_mesa_error
(ctx
, GL_INVALID_OPERATION
, "glLoadProgramNV(bad header)");
return;
}
/* make sure target and header match */
if (target
!= dstTarget
) {
_mesa_error
(ctx
, GL_INVALID_OPERATION
,
"glLoadProgramNV(target mismatch)");
return;
}
if (Parse_Program
(&s
, instBuffer
)) {
GLuint numInst
;
GLuint strLen
;
GLuint inputsRead
= 0;
GLuint outputsWritten
= 0;
GLuint progRegsWritten
= 0;
/* Find length of the program and compute bitmasks to indicate which
* vertex input registers are read, which vertex result registers are
* written to, and which program registers are written to.
* We could actually do this while we parse the program.
*/
for (numInst
= 0; instBuffer
[numInst
].
Opcode != END
; numInst
++) {
const GLint srcReg0
= instBuffer
[numInst
].
SrcReg[0].
Register;
const GLint srcReg1
= instBuffer
[numInst
].
SrcReg[1].
Register;
const GLint srcReg2
= instBuffer
[numInst
].
SrcReg[2].
Register;
const GLint dstReg
= instBuffer
[numInst
].
DstReg.
Register;
if (IsOutputRegister
(dstReg
))
outputsWritten
|= (1 << (dstReg
- VP_OUTPUT_REG_START
));
else if (IsProgRegister
(dstReg
))
progRegsWritten
|= (1 << (dstReg
- VP_PROG_REG_START
));
if (IsInputRegister
(srcReg0
)
&& !instBuffer
[numInst
].
SrcReg[0].
RelAddr)
inputsRead
|= (1 << (srcReg0
- VP_INPUT_REG_START
));
if (IsInputRegister
(srcReg1
)
&& !instBuffer
[numInst
].
SrcReg[1].
RelAddr)
inputsRead
|= (1 << (srcReg1
- VP_INPUT_REG_START
));
if (IsInputRegister
(srcReg2
)
&& !instBuffer
[numInst
].
SrcReg[2].
RelAddr)
inputsRead
|= (1 << (srcReg2
- VP_INPUT_REG_START
));
}
numInst
++;
if (IsStateProgram
) {
if (progRegsWritten
== 0) {
_mesa_error
(ctx
, GL_INVALID_OPERATION
,
"glLoadProgramNV(c[#] not written)");
return;
}
}
else {
if (!IsPositionInvariant
&& !(outputsWritten
& 1)) {
/* bit 1 = HPOS register */
_mesa_error
(ctx
, GL_INVALID_OPERATION
,
"glLoadProgramNV(HPOS not written)");
return;
}
}
program
->InputsRead
= inputsRead
;
program
->OutputsWritten
= outputsWritten
;
program
->IsPositionInvariant
= IsPositionInvariant
;
/* make copy of the input program string */
strLen
= _mesa_strlen
((const char *) str
);
newString
= (GLubyte
*) MALLOC
(strLen
+ 1);
if (!newString
) {
_mesa_error
(ctx
, GL_OUT_OF_MEMORY
, "glLoadProgramNV");
return;
}
MEMCPY
(newString
, str
, strLen
);
newString
[strLen
] = 0; /* terminate */
/* copy the compiled instructions */
assert(numInst
<= VP_MAX_INSTRUCTIONS
);
newInst
= (struct vp_instruction
*) MALLOC
(numInst
* sizeof(struct vp_instruction
));
if (!newInst
) {
_mesa_error
(ctx
, GL_OUT_OF_MEMORY
, "glLoadProgramNV");
return; /* out of memory */
}
MEMCPY
(newInst
, instBuffer
, numInst
* sizeof(struct vp_instruction
));
/* install the program */
program
->Target
= target
;
if (program
->String
) {
FREE
(program
->String
);
}
program
->String
= newString
;
if (program
->Instructions
) {
FREE
(program
->Instructions
);
}
program
->Instructions
= newInst
;
#ifdef DEBUG_foo
_mesa_printf
("--- glLoadProgramNV result ---\n");
_mesa_print_program
(program
);
_mesa_printf
("------------------------------\n");
#endif
}
else {
/* Error! */
#ifdef DEBUG
/* print a message showing the program line containing the error */
ctx
->VertexProgram.
ErrorPos = s
- str
;
{
const GLubyte
*p
= str
, *line
= str
;
int lineNum
= 1, statementNum
= 1, column
= 0;
char errorLine
[1000];
int i
;
while (*p
&& p
< s
) { /* s is the error position */
if (*p
== '\n') {
line
= p
+ 1;
lineNum
++;
column
= 0;
}
else if (*p
== ';') {
statementNum
++;
}
else
column
++;
p
++;
}
if (p
) {
/* Copy the line with the error into errorLine so we can null-
* terminate it.
*/
for (i
= 0; line
[i
] != '\n' && line
[i
]; i
++)
errorLine
[i
] = (char) line
[i
];
errorLine
[i
] = 0;
}
/*
_mesa_debug("Error pos = %d (%c) col %d\n",
ctx->VertexProgram.ErrorPos, *s, column);
*/
_mesa_debug
(ctx
, "Vertex program error on line %2d: %s\n", lineNum
, errorLine
);
_mesa_debug
(ctx
, " (statement %2d) near column %2d: ", statementNum
, column
+1);
for (i
= 0; i
< column
; i
++)
_mesa_debug
(ctx
, " ");
_mesa_debug
(ctx
, "^\n");
}
#endif
_mesa_error
(ctx
, GL_INVALID_OPERATION
, "glLoadProgramNV");
}
}
static void
PrintSrcReg
(const struct vp_src_register
*src
)
{
static const char comps
[5] = "xyzw";
if (src
->Negate
)
_mesa_printf
("-");
if (src
->RelAddr
) {
if (src
->Register
> 0)
_mesa_printf
("c[A0.x + %d]", src
->Register
);
else if (src
->Register
< 0)
_mesa_printf
("c[A0.x - %d]", -src
->Register
);
else
_mesa_printf
("c[A0.x]");
}
else if (src
->Register
>= VP_OUTPUT_REG_START
&& src
->Register
<= VP_OUTPUT_REG_END
) {
_mesa_printf
("o[%s]", OutputRegisters
[src
->Register
- VP_OUTPUT_REG_START
]);
}
else if (src
->Register
>= VP_INPUT_REG_START
&& src
->Register
<= VP_INPUT_REG_END
) {
_mesa_printf
("v[%s]", InputRegisters
[src
->Register
- VP_INPUT_REG_START
]);
}
else if (src
->Register
>= VP_PROG_REG_START
&& src
->Register
<= VP_PROG_REG_END
) {
_mesa_printf
("c[%d]", src
->Register
- VP_PROG_REG_START
);
}
else {
_mesa_printf
("R%d", src
->Register
- VP_TEMP_REG_START
);
}
if (src
->Swizzle
[0] == src
->Swizzle
[1] &&
src
->Swizzle
[0] == src
->Swizzle
[2] &&
src
->Swizzle
[0] == src
->Swizzle
[3]) {
_mesa_printf
(".%c", comps
[src
->Swizzle
[0]]);
}
else if (src
->Swizzle
[0] != 0 ||
src
->Swizzle
[1] != 1 ||
src
->Swizzle
[2] != 2 ||
src
->Swizzle
[3] != 3) {
_mesa_printf
(".%c%c%c%c",
comps
[src
->Swizzle
[0]],
comps
[src
->Swizzle
[1]],
comps
[src
->Swizzle
[2]],
comps
[src
->Swizzle
[3]]);
}
}
static void
PrintDstReg
(const struct vp_dst_register
*dst
)
{
GLint w
= dst
->WriteMask
[0] + dst
->WriteMask
[1]
+ dst
->WriteMask
[2] + dst
->WriteMask
[3];
if (dst
->Register
>= VP_OUTPUT_REG_START
&& dst
->Register
<= VP_OUTPUT_REG_END
) {
_mesa_printf
("o[%s]", OutputRegisters
[dst
->Register
- VP_OUTPUT_REG_START
]);
}
else if (dst
->Register
>= VP_INPUT_REG_START
&& dst
->Register
<= VP_INPUT_REG_END
) {
_mesa_printf
("v[%s]", InputRegisters
[dst
->Register
- VP_INPUT_REG_START
]);
}
else if (dst
->Register
>= VP_PROG_REG_START
&& dst
->Register
<= VP_PROG_REG_END
) {
_mesa_printf
("c[%d]", dst
->Register
- VP_PROG_REG_START
);
}
else {
_mesa_printf
("R%d", dst
->Register
- VP_TEMP_REG_START
);
}
if (w
!= 0 && w
!= 4) {
_mesa_printf
(".");
if (dst
->WriteMask
[0])
_mesa_printf
("x");
if (dst
->WriteMask
[1])
_mesa_printf
("y");
if (dst
->WriteMask
[2])
_mesa_printf
("z");
if (dst
->WriteMask
[3])
_mesa_printf
("w");
}
}
/**
* Print (unparse) the given vertex program. Just for debugging.
*/
void
_mesa_print_program
(const struct vp_program
*program
)
{
const struct vp_instruction
*inst
;
for (inst
= program
->Instructions
; ; inst
++) {
switch (inst
->Opcode
) {
case MOV
:
case LIT
:
case RCP
:
case RSQ
:
case EXP
:
case LOG
:
case RCC
:
case ABS
:
_mesa_printf
("%s ", Opcodes
[(int) inst
->Opcode
]);
PrintDstReg
(&inst
->DstReg
);
_mesa_printf
(", ");
PrintSrcReg
(&inst
->SrcReg
[0]);
_mesa_printf
(";\n");
break;
case MUL
:
case ADD
:
case DP3
:
case DP4
:
case DST
:
case MIN
:
case MAX
:
case SLT
:
case SGE
:
case DPH
:
case SUB
:
_mesa_printf
("%s ", Opcodes
[(int) inst
->Opcode
]);
PrintDstReg
(&inst
->DstReg
);
_mesa_printf
(", ");
PrintSrcReg
(&inst
->SrcReg
[0]);
_mesa_printf
(", ");
PrintSrcReg
(&inst
->SrcReg
[1]);
_mesa_printf
(";\n");
break;
case MAD
:
_mesa_printf
("MAD ");
PrintDstReg
(&inst
->DstReg
);
_mesa_printf
(", ");
PrintSrcReg
(&inst
->SrcReg
[0]);
_mesa_printf
(", ");
PrintSrcReg
(&inst
->SrcReg
[1]);
_mesa_printf
(", ");
PrintSrcReg
(&inst
->SrcReg
[2]);
_mesa_printf
(";\n");
break;
case ARL
:
_mesa_printf
("ARL A0.x, ");
PrintSrcReg
(&inst
->SrcReg
[0]);
_mesa_printf
(";\n");
break;
case END
:
_mesa_printf
("END\n");
return;
break;
default:
_mesa_printf
("BAD INSTRUCTION\n");
}
}
}