blob: d5b08def43ab00b9d89467305d20daefc1affc07 [file] [log] [blame]
Michal Krol2861e732004-03-29 11:09:34 +00001/*
2 * Mesa 3-D graphics library
Brian Paul7e807512005-11-05 17:10:45 +00003 * Version: 6.5
Michal Krol2861e732004-03-29 11:09:34 +00004 *
Brian Paul7e807512005-11-05 17:10:45 +00005 * Copyright (C) 1999-2005 Brian Paul All Rights Reserved.
Michal Krol2861e732004-03-29 11:09:34 +00006 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25/**
26 * \file nvvertparse.c
27 * NVIDIA vertex program parser.
28 * \author Brian Paul
29 */
30
31/*
32 * Regarding GL_NV_vertex_program, GL_NV_vertex_program1_1:
33 *
34 * Portions of this software may use or implement intellectual
35 * property owned and licensed by NVIDIA Corporation. NVIDIA disclaims
36 * any and all warranties with respect to such intellectual property,
37 * including any use thereof or modifications thereto.
38 */
39
40#include "glheader.h"
41#include "context.h"
42#include "hash.h"
43#include "imports.h"
44#include "macros.h"
45#include "mtypes.h"
46#include "nvprogram.h"
47#include "nvvertparse.h"
Brian Paul7e807512005-11-05 17:10:45 +000048#include "program_instruction.h"
Michal Krol2861e732004-03-29 11:09:34 +000049#include "program.h"
50
51
52/**
53 * Current parsing state. This structure is passed among the parsing
54 * functions and keeps track of the current parser position and various
55 * program attributes.
56 */
57struct parse_state {
58 GLcontext *ctx;
59 const GLubyte *start;
60 const GLubyte *pos;
61 const GLubyte *curLine;
62 GLboolean isStateProgram;
63 GLboolean isPositionInvariant;
64 GLboolean isVersion1_1;
65 GLuint inputsRead;
66 GLuint outputsWritten;
67 GLboolean anyProgRegsWritten;
68 GLuint numInst; /* number of instructions parsed */
69};
70
71
72/*
73 * Called whenever we find an error during parsing.
74 */
75static void
76record_error(struct parse_state *parseState, const char *msg, int lineNo)
77{
78#ifdef DEBUG
79 GLint line, column;
80 const GLubyte *lineStr;
81 lineStr = _mesa_find_line_column(parseState->start,
82 parseState->pos, &line, &column);
83 _mesa_debug(parseState->ctx,
84 "nvfragparse.c(%d): line %d, column %d:%s (%s)\n",
85 lineNo, line, column, (char *) lineStr, msg);
86 _mesa_free((void *) lineStr);
87#else
88 (void) lineNo;
89#endif
90
91 /* Check that no error was already recorded. Only record the first one. */
92 if (parseState->ctx->Program.ErrorString[0] == 0) {
93 _mesa_set_program_error(parseState->ctx,
94 parseState->pos - parseState->start,
95 msg);
96 }
97}
98
99
100#define RETURN_ERROR \
101do { \
102 record_error(parseState, "Unexpected end of input.", __LINE__); \
103 return GL_FALSE; \
104} while(0)
105
106#define RETURN_ERROR1(msg) \
107do { \
108 record_error(parseState, msg, __LINE__); \
109 return GL_FALSE; \
110} while(0)
111
112#define RETURN_ERROR2(msg1, msg2) \
113do { \
114 char err[1000]; \
115 _mesa_sprintf(err, "%s %s", msg1, msg2); \
116 record_error(parseState, err, __LINE__); \
117 return GL_FALSE; \
118} while(0)
119
120
121
122
123
124static GLboolean IsLetter(GLubyte b)
125{
126 return (b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z');
127}
128
129
130static GLboolean IsDigit(GLubyte b)
131{
132 return b >= '0' && b <= '9';
133}
134
135
136static GLboolean IsWhitespace(GLubyte b)
137{
138 return b == ' ' || b == '\t' || b == '\n' || b == '\r';
139}
140
141
142/**
143 * Starting at 'str' find the next token. A token can be an integer,
144 * an identifier or punctuation symbol.
145 * \return <= 0 we found an error, else, return number of characters parsed.
146 */
147static GLint
148GetToken(struct parse_state *parseState, GLubyte *token)
149{
150 const GLubyte *str = parseState->pos;
151 GLint i = 0, j = 0;
152
153 token[0] = 0;
154
155 /* skip whitespace and comments */
156 while (str[i] && (IsWhitespace(str[i]) || str[i] == '#')) {
157 if (str[i] == '#') {
158 /* skip comment */
159 while (str[i] && (str[i] != '\n' && str[i] != '\r')) {
160 i++;
161 }
162 if (str[i] == '\n' || str[i] == '\r')
163 parseState->curLine = str + i + 1;
164 }
165 else {
166 /* skip whitespace */
167 if (str[i] == '\n' || str[i] == '\r')
168 parseState->curLine = str + i + 1;
169 i++;
170 }
171 }
172
173 if (str[i] == 0)
174 return -i;
175
176 /* try matching an integer */
177 while (str[i] && IsDigit(str[i])) {
178 token[j++] = str[i++];
179 }
180 if (j > 0 || !str[i]) {
181 token[j] = 0;
182 return i;
183 }
184
185 /* try matching an identifier */
186 if (IsLetter(str[i])) {
187 while (str[i] && (IsLetter(str[i]) || IsDigit(str[i]))) {
188 token[j++] = str[i++];
189 }
190 token[j] = 0;
191 return i;
192 }
193
194 /* punctuation character */
195 if (str[i]) {
196 token[0] = str[i++];
197 token[1] = 0;
198 return i;
199 }
200
201 /* end of input */
202 token[0] = 0;
203 return i;
204}
205
206
207/**
208 * Get next token from input stream and increment stream pointer past token.
209 */
210static GLboolean
211Parse_Token(struct parse_state *parseState, GLubyte *token)
212{
213 GLint i;
214 i = GetToken(parseState, token);
215 if (i <= 0) {
216 parseState->pos += (-i);
217 return GL_FALSE;
218 }
219 parseState->pos += i;
220 return GL_TRUE;
221}
222
223
224/**
225 * Get next token from input stream but don't increment stream pointer.
226 */
227static GLboolean
228Peek_Token(struct parse_state *parseState, GLubyte *token)
229{
230 GLint i, len;
231 i = GetToken(parseState, token);
232 if (i <= 0) {
233 parseState->pos += (-i);
234 return GL_FALSE;
235 }
Karl Schultz6258b762005-05-05 21:08:07 +0000236 len = (GLint)_mesa_strlen((const char *) token);
Michal Krol2861e732004-03-29 11:09:34 +0000237 parseState->pos += (i - len);
238 return GL_TRUE;
239}
240
241
242/**
243 * Try to match 'pattern' as the next token after any whitespace/comments.
244 * Advance the current parsing position only if we match the pattern.
245 * \return GL_TRUE if pattern is matched, GL_FALSE otherwise.
246 */
247static GLboolean
248Parse_String(struct parse_state *parseState, const char *pattern)
249{
250 const GLubyte *m;
251 GLint i;
252
253 /* skip whitespace and comments */
254 while (IsWhitespace(*parseState->pos) || *parseState->pos == '#') {
255 if (*parseState->pos == '#') {
256 while (*parseState->pos && (*parseState->pos != '\n' && *parseState->pos != '\r')) {
257 parseState->pos += 1;
258 }
259 if (*parseState->pos == '\n' || *parseState->pos == '\r')
260 parseState->curLine = parseState->pos + 1;
261 }
262 else {
263 /* skip whitespace */
264 if (*parseState->pos == '\n' || *parseState->pos == '\r')
265 parseState->curLine = parseState->pos + 1;
266 parseState->pos += 1;
267 }
268 }
269
270 /* Try to match the pattern */
271 m = parseState->pos;
272 for (i = 0; pattern[i]; i++) {
273 if (*m != (GLubyte) pattern[i])
274 return GL_FALSE;
275 m += 1;
276 }
277 parseState->pos = m;
278
279 return GL_TRUE; /* success */
280}
281
282
283/**********************************************************************/
284
285static const char *InputRegisters[MAX_NV_VERTEX_PROGRAM_INPUTS + 1] = {
286 "OPOS", "WGHT", "NRML", "COL0", "COL1", "FOGC", "6", "7",
287 "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", NULL
288};
289
290static const char *OutputRegisters[MAX_NV_VERTEX_PROGRAM_OUTPUTS + 1] = {
Keith Whitwellc3626a92005-11-01 17:25:49 +0000291 "HPOS", "COL0", "COL1", "FOGC",
292 "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7",
293 "PSIZ", "BFC0", "BFC1", NULL
Michal Krol2861e732004-03-29 11:09:34 +0000294};
295
Brian Paul7e807512005-11-05 17:10:45 +0000296/* NOTE: the order here must match opcodes in program_instruction.h */
Michal Krol2861e732004-03-29 11:09:34 +0000297static const char *Opcodes[] = {
298 "MOV", "LIT", "RCP", "RSQ", "EXP", "LOG", "MUL", "ADD", "DP3", "DP4",
299 "DST", "MIN", "MAX", "SLT", "SGE", "MAD", "ARL", "DPH", "RCC", "SUB",
300 "ABS", "END",
301 /* GL_ARB_vertex_program */
302 "FLR", "FRC", "EX2", "LG2", "POW", "XPD", "SWZ",
Brian Paul575700f2004-12-16 03:07:18 +0000303 /* Mesa-specific */
304 "PRINT",
Michal Krol2861e732004-03-29 11:09:34 +0000305 NULL
306};
307
308
309
310/**
311 * Parse a temporary register: Rnn
312 */
313static GLboolean
314Parse_TempReg(struct parse_state *parseState, GLint *tempRegNum)
315{
316 GLubyte token[100];
317
318 /* Should be 'R##' */
319 if (!Parse_Token(parseState, token))
320 RETURN_ERROR;
321 if (token[0] != 'R')
322 RETURN_ERROR1("Expected R##");
323
324 if (IsDigit(token[1])) {
325 GLint reg = _mesa_atoi((char *) (token + 1));
326 if (reg >= MAX_NV_VERTEX_PROGRAM_TEMPS)
327 RETURN_ERROR1("Bad temporary register name");
328 *tempRegNum = reg;
329 }
330 else {
331 RETURN_ERROR1("Bad temporary register name");
332 }
333
334 return GL_TRUE;
335}
336
337
338/**
339 * Parse address register "A0.x"
340 */
341static GLboolean
342Parse_AddrReg(struct parse_state *parseState)
343{
344 /* match 'A0' */
345 if (!Parse_String(parseState, "A0"))
346 RETURN_ERROR;
347
348 /* match '.' */
349 if (!Parse_String(parseState, "."))
350 RETURN_ERROR;
351
352 /* match 'x' */
353 if (!Parse_String(parseState, "x"))
354 RETURN_ERROR;
355
356 return GL_TRUE;
357}
358
359
360/**
361 * Parse absolute program parameter register "c[##]"
362 */
363static GLboolean
364Parse_AbsParamReg(struct parse_state *parseState, GLint *regNum)
365{
366 GLubyte token[100];
367
368 if (!Parse_String(parseState, "c"))
369 RETURN_ERROR;
370
371 if (!Parse_String(parseState, "["))
372 RETURN_ERROR;
373
374 if (!Parse_Token(parseState, token))
375 RETURN_ERROR;
376
377 if (IsDigit(token[0])) {
378 /* a numbered program parameter register */
379 GLint reg = _mesa_atoi((char *) token);
380 if (reg >= MAX_NV_VERTEX_PROGRAM_PARAMS)
381 RETURN_ERROR1("Bad program parameter number");
382 *regNum = reg;
383 }
384 else {
385 RETURN_ERROR;
386 }
387
388 if (!Parse_String(parseState, "]"))
389 RETURN_ERROR;
390
391 return GL_TRUE;
392}
393
394
395static GLboolean
Brian Paul7e807512005-11-05 17:10:45 +0000396Parse_ParamReg(struct parse_state *parseState, struct prog_src_register *srcReg)
Michal Krol2861e732004-03-29 11:09:34 +0000397{
398 GLubyte token[100];
399
400 if (!Parse_String(parseState, "c"))
401 RETURN_ERROR;
402
403 if (!Parse_String(parseState, "["))
404 RETURN_ERROR;
405
406 if (!Peek_Token(parseState, token))
407 RETURN_ERROR;
408
409 if (IsDigit(token[0])) {
410 /* a numbered program parameter register */
411 GLint reg;
412 (void) Parse_Token(parseState, token);
413 reg = _mesa_atoi((char *) token);
414 if (reg >= MAX_NV_VERTEX_PROGRAM_PARAMS)
415 RETURN_ERROR1("Bad program parameter number");
416 srcReg->File = PROGRAM_ENV_PARAM;
417 srcReg->Index = reg;
418 }
419 else if (_mesa_strcmp((const char *) token, "A0") == 0) {
420 /* address register "A0.x" */
421 if (!Parse_AddrReg(parseState))
422 RETURN_ERROR;
423
424 srcReg->RelAddr = GL_TRUE;
425 srcReg->File = PROGRAM_ENV_PARAM;
426 /* Look for +/-N offset */
427 if (!Peek_Token(parseState, token))
428 RETURN_ERROR;
429
430 if (token[0] == '-' || token[0] == '+') {
431 const GLubyte sign = token[0];
432 (void) Parse_Token(parseState, token); /* consume +/- */
433
434 /* an integer should be next */
435 if (!Parse_Token(parseState, token))
436 RETURN_ERROR;
437
438 if (IsDigit(token[0])) {
439 const GLint k = _mesa_atoi((char *) token);
440 if (sign == '-') {
441 if (k > 64)
442 RETURN_ERROR1("Bad address offset");
443 srcReg->Index = -k;
444 }
445 else {
446 if (k > 63)
447 RETURN_ERROR1("Bad address offset");
448 srcReg->Index = k;
449 }
450 }
451 else {
452 RETURN_ERROR;
453 }
454 }
455 else {
456 /* probably got a ']', catch it below */
457 }
458 }
459 else {
460 RETURN_ERROR;
461 }
462
463 /* Match closing ']' */
464 if (!Parse_String(parseState, "]"))
465 RETURN_ERROR;
466
467 return GL_TRUE;
468}
469
470
471/**
472 * Parse v[#] or v[<name>]
473 */
474static GLboolean
475Parse_AttribReg(struct parse_state *parseState, GLint *tempRegNum)
476{
477 GLubyte token[100];
478 GLint j;
479
480 /* Match 'v' */
481 if (!Parse_String(parseState, "v"))
482 RETURN_ERROR;
483
484 /* Match '[' */
485 if (!Parse_String(parseState, "["))
486 RETURN_ERROR;
487
488 /* match number or named register */
489 if (!Parse_Token(parseState, token))
490 RETURN_ERROR;
491
492 if (parseState->isStateProgram && token[0] != '0')
493 RETURN_ERROR1("Only v[0] accessible in vertex state programs");
494
495 if (IsDigit(token[0])) {
496 GLint reg = _mesa_atoi((char *) token);
497 if (reg >= MAX_NV_VERTEX_PROGRAM_INPUTS)
498 RETURN_ERROR1("Bad vertex attribute register name");
499 *tempRegNum = reg;
500 }
501 else {
502 for (j = 0; InputRegisters[j]; j++) {
503 if (_mesa_strcmp((const char *) token, InputRegisters[j]) == 0) {
504 *tempRegNum = j;
505 break;
506 }
507 }
508 if (!InputRegisters[j]) {
509 /* unknown input register label */
510 RETURN_ERROR2("Bad register name", token);
511 }
512 }
513
514 /* Match '[' */
515 if (!Parse_String(parseState, "]"))
516 RETURN_ERROR;
517
518 return GL_TRUE;
519}
520
521
522static GLboolean
523Parse_OutputReg(struct parse_state *parseState, GLint *outputRegNum)
524{
525 GLubyte token[100];
526 GLint start, j;
527
528 /* Match 'o' */
529 if (!Parse_String(parseState, "o"))
530 RETURN_ERROR;
531
532 /* Match '[' */
533 if (!Parse_String(parseState, "["))
534 RETURN_ERROR;
535
536 /* Get output reg name */
537 if (!Parse_Token(parseState, token))
538 RETURN_ERROR;
539
540 if (parseState->isPositionInvariant)
541 start = 1; /* skip HPOS register name */
542 else
543 start = 0;
544
545 /* try to match an output register name */
546 for (j = start; OutputRegisters[j]; j++) {
547 if (_mesa_strcmp((const char *) token, OutputRegisters[j]) == 0) {
548 *outputRegNum = j;
549 break;
550 }
551 }
552 if (!OutputRegisters[j])
553 RETURN_ERROR1("Unrecognized output register name");
554
555 /* Match ']' */
556 if (!Parse_String(parseState, "]"))
557 RETURN_ERROR1("Expected ]");
558
559 return GL_TRUE;
560}
561
562
563static GLboolean
Brian Paul7e807512005-11-05 17:10:45 +0000564Parse_MaskedDstReg(struct parse_state *parseState, struct prog_dst_register *dstReg)
Michal Krol2861e732004-03-29 11:09:34 +0000565{
566 GLubyte token[100];
Keith Whitwell7c26b612005-04-21 14:46:57 +0000567 GLint idx;
Michal Krol2861e732004-03-29 11:09:34 +0000568
569 /* Dst reg can be R<n> or o[n] */
570 if (!Peek_Token(parseState, token))
571 RETURN_ERROR;
572
573 if (token[0] == 'R') {
574 /* a temporary register */
575 dstReg->File = PROGRAM_TEMPORARY;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000576 if (!Parse_TempReg(parseState, &idx))
Michal Krol2861e732004-03-29 11:09:34 +0000577 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000578 dstReg->Index = idx;
Michal Krol2861e732004-03-29 11:09:34 +0000579 }
580 else if (!parseState->isStateProgram && token[0] == 'o') {
581 /* an output register */
582 dstReg->File = PROGRAM_OUTPUT;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000583 if (!Parse_OutputReg(parseState, &idx))
Michal Krol2861e732004-03-29 11:09:34 +0000584 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000585 dstReg->Index = idx;
Michal Krol2861e732004-03-29 11:09:34 +0000586 }
587 else if (parseState->isStateProgram && token[0] == 'c' &&
588 parseState->isStateProgram) {
589 /* absolute program parameter register */
590 /* Only valid for vertex state programs */
591 dstReg->File = PROGRAM_ENV_PARAM;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000592 if (!Parse_AbsParamReg(parseState, &idx))
Michal Krol2861e732004-03-29 11:09:34 +0000593 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000594 dstReg->Index = idx;
Michal Krol2861e732004-03-29 11:09:34 +0000595 }
596 else {
597 RETURN_ERROR1("Bad destination register name");
598 }
599
600 /* Parse optional write mask */
601 if (!Peek_Token(parseState, token))
602 RETURN_ERROR;
603
604 if (token[0] == '.') {
605 /* got a mask */
606 GLint k = 0;
607
608 if (!Parse_String(parseState, "."))
609 RETURN_ERROR;
610
611 if (!Parse_Token(parseState, token))
612 RETURN_ERROR;
613
Keith Whitwell7c26b612005-04-21 14:46:57 +0000614 dstReg->WriteMask = 0;
Michal Krol2861e732004-03-29 11:09:34 +0000615
616 if (token[k] == 'x') {
Keith Whitwell7c26b612005-04-21 14:46:57 +0000617 dstReg->WriteMask |= WRITEMASK_X;
Michal Krol2861e732004-03-29 11:09:34 +0000618 k++;
619 }
620 if (token[k] == 'y') {
Keith Whitwell7c26b612005-04-21 14:46:57 +0000621 dstReg->WriteMask |= WRITEMASK_Y;
Michal Krol2861e732004-03-29 11:09:34 +0000622 k++;
623 }
624 if (token[k] == 'z') {
Keith Whitwell7c26b612005-04-21 14:46:57 +0000625 dstReg->WriteMask |= WRITEMASK_Z;
Michal Krol2861e732004-03-29 11:09:34 +0000626 k++;
627 }
628 if (token[k] == 'w') {
Keith Whitwell7c26b612005-04-21 14:46:57 +0000629 dstReg->WriteMask |= WRITEMASK_W;
Michal Krol2861e732004-03-29 11:09:34 +0000630 k++;
631 }
632 if (k == 0) {
633 RETURN_ERROR1("Bad writemask character");
634 }
635 return GL_TRUE;
636 }
637 else {
Keith Whitwell7c26b612005-04-21 14:46:57 +0000638 dstReg->WriteMask = WRITEMASK_XYZW;
Michal Krol2861e732004-03-29 11:09:34 +0000639 return GL_TRUE;
640 }
641}
642
643
644static GLboolean
Brian Paul7e807512005-11-05 17:10:45 +0000645Parse_SwizzleSrcReg(struct parse_state *parseState, struct prog_src_register *srcReg)
Michal Krol2861e732004-03-29 11:09:34 +0000646{
647 GLubyte token[100];
Keith Whitwell7c26b612005-04-21 14:46:57 +0000648 GLint idx;
Michal Krol2861e732004-03-29 11:09:34 +0000649
650 srcReg->RelAddr = GL_FALSE;
651
652 /* check for '-' */
653 if (!Peek_Token(parseState, token))
654 RETURN_ERROR;
655 if (token[0] == '-') {
656 (void) Parse_String(parseState, "-");
Brian Paul7e807512005-11-05 17:10:45 +0000657 srcReg->NegateBase = GL_TRUE;
Michal Krol2861e732004-03-29 11:09:34 +0000658 if (!Peek_Token(parseState, token))
659 RETURN_ERROR;
660 }
661 else {
Brian Paul7e807512005-11-05 17:10:45 +0000662 srcReg->NegateBase = GL_FALSE;
Michal Krol2861e732004-03-29 11:09:34 +0000663 }
664
665 /* Src reg can be R<n>, c[n], c[n +/- offset], or a named vertex attrib */
666 if (token[0] == 'R') {
667 srcReg->File = PROGRAM_TEMPORARY;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000668 if (!Parse_TempReg(parseState, &idx))
Michal Krol2861e732004-03-29 11:09:34 +0000669 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000670 srcReg->Index = idx;
Michal Krol2861e732004-03-29 11:09:34 +0000671 }
672 else if (token[0] == 'c') {
673 if (!Parse_ParamReg(parseState, srcReg))
674 RETURN_ERROR;
675 }
676 else if (token[0] == 'v') {
677 srcReg->File = PROGRAM_INPUT;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000678 if (!Parse_AttribReg(parseState, &idx))
Michal Krol2861e732004-03-29 11:09:34 +0000679 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000680 srcReg->Index = idx;
Michal Krol2861e732004-03-29 11:09:34 +0000681 }
682 else {
683 RETURN_ERROR2("Bad source register name", token);
684 }
685
686 /* init swizzle fields */
Keith Whitwell7c26b612005-04-21 14:46:57 +0000687 srcReg->Swizzle = SWIZZLE_NOOP;
Michal Krol2861e732004-03-29 11:09:34 +0000688
689 /* Look for optional swizzle suffix */
690 if (!Peek_Token(parseState, token))
691 RETURN_ERROR;
692 if (token[0] == '.') {
693 (void) Parse_String(parseState, "."); /* consume . */
694
695 if (!Parse_Token(parseState, token))
696 RETURN_ERROR;
697
698 if (token[1] == 0) {
699 /* single letter swizzle */
700 if (token[0] == 'x')
Keith Whitwell7c26b612005-04-21 14:46:57 +0000701 srcReg->Swizzle = MAKE_SWIZZLE4(0, 0, 0, 0);
Michal Krol2861e732004-03-29 11:09:34 +0000702 else if (token[0] == 'y')
Keith Whitwell7c26b612005-04-21 14:46:57 +0000703 srcReg->Swizzle = MAKE_SWIZZLE4(1, 1, 1, 1);
Michal Krol2861e732004-03-29 11:09:34 +0000704 else if (token[0] == 'z')
Keith Whitwell7c26b612005-04-21 14:46:57 +0000705 srcReg->Swizzle = MAKE_SWIZZLE4(2, 2, 2, 2);
Michal Krol2861e732004-03-29 11:09:34 +0000706 else if (token[0] == 'w')
Keith Whitwell7c26b612005-04-21 14:46:57 +0000707 srcReg->Swizzle = MAKE_SWIZZLE4(3, 3, 3, 3);
Michal Krol2861e732004-03-29 11:09:34 +0000708 else
709 RETURN_ERROR1("Expected x, y, z, or w");
710 }
711 else {
712 /* 2, 3 or 4-component swizzle */
713 GLint k;
714 for (k = 0; token[k] && k < 5; k++) {
715 if (token[k] == 'x')
Keith Whitwell7c26b612005-04-21 14:46:57 +0000716 srcReg->Swizzle |= 0 << (k*3);
Michal Krol2861e732004-03-29 11:09:34 +0000717 else if (token[k] == 'y')
Keith Whitwell7c26b612005-04-21 14:46:57 +0000718 srcReg->Swizzle |= 1 << (k*3);
Michal Krol2861e732004-03-29 11:09:34 +0000719 else if (token[k] == 'z')
Keith Whitwell7c26b612005-04-21 14:46:57 +0000720 srcReg->Swizzle |= 2 << (k*3);
Michal Krol2861e732004-03-29 11:09:34 +0000721 else if (token[k] == 'w')
Keith Whitwell7c26b612005-04-21 14:46:57 +0000722 srcReg->Swizzle |= 3 << (k*3);
Michal Krol2861e732004-03-29 11:09:34 +0000723 else
724 RETURN_ERROR;
725 }
726 if (k >= 5)
727 RETURN_ERROR;
728 }
729 }
730
731 return GL_TRUE;
732}
733
734
735static GLboolean
Brian Paul7e807512005-11-05 17:10:45 +0000736Parse_ScalarSrcReg(struct parse_state *parseState, struct prog_src_register *srcReg)
Michal Krol2861e732004-03-29 11:09:34 +0000737{
738 GLubyte token[100];
Keith Whitwell7c26b612005-04-21 14:46:57 +0000739 GLint idx;
Michal Krol2861e732004-03-29 11:09:34 +0000740
741 srcReg->RelAddr = GL_FALSE;
742
743 /* check for '-' */
744 if (!Peek_Token(parseState, token))
745 RETURN_ERROR;
746 if (token[0] == '-') {
Brian Paul7e807512005-11-05 17:10:45 +0000747 srcReg->NegateBase = GL_TRUE;
Michal Krol2861e732004-03-29 11:09:34 +0000748 (void) Parse_String(parseState, "-"); /* consume '-' */
749 if (!Peek_Token(parseState, token))
750 RETURN_ERROR;
751 }
752 else {
Brian Paul7e807512005-11-05 17:10:45 +0000753 srcReg->NegateBase = GL_FALSE;
Michal Krol2861e732004-03-29 11:09:34 +0000754 }
755
756 /* Src reg can be R<n>, c[n], c[n +/- offset], or a named vertex attrib */
757 if (token[0] == 'R') {
758 srcReg->File = PROGRAM_TEMPORARY;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000759 if (!Parse_TempReg(parseState, &idx))
Michal Krol2861e732004-03-29 11:09:34 +0000760 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000761 srcReg->Index = idx;
Michal Krol2861e732004-03-29 11:09:34 +0000762 }
763 else if (token[0] == 'c') {
764 if (!Parse_ParamReg(parseState, srcReg))
765 RETURN_ERROR;
766 }
767 else if (token[0] == 'v') {
768 srcReg->File = PROGRAM_INPUT;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000769 if (!Parse_AttribReg(parseState, &idx))
Michal Krol2861e732004-03-29 11:09:34 +0000770 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000771 srcReg->Index = idx;
Michal Krol2861e732004-03-29 11:09:34 +0000772 }
773 else {
774 RETURN_ERROR2("Bad source register name", token);
775 }
776
777 /* Look for .[xyzw] suffix */
778 if (!Parse_String(parseState, "."))
779 RETURN_ERROR;
780
781 if (!Parse_Token(parseState, token))
782 RETURN_ERROR;
783
784 if (token[0] == 'x' && token[1] == 0) {
Keith Whitwell7c26b612005-04-21 14:46:57 +0000785 srcReg->Swizzle = 0;
Michal Krol2861e732004-03-29 11:09:34 +0000786 }
787 else if (token[0] == 'y' && token[1] == 0) {
Keith Whitwell7c26b612005-04-21 14:46:57 +0000788 srcReg->Swizzle = 1;
Michal Krol2861e732004-03-29 11:09:34 +0000789 }
790 else if (token[0] == 'z' && token[1] == 0) {
Keith Whitwell7c26b612005-04-21 14:46:57 +0000791 srcReg->Swizzle = 2;
Michal Krol2861e732004-03-29 11:09:34 +0000792 }
793 else if (token[0] == 'w' && token[1] == 0) {
Keith Whitwell7c26b612005-04-21 14:46:57 +0000794 srcReg->Swizzle = 3;
Michal Krol2861e732004-03-29 11:09:34 +0000795 }
796 else {
797 RETURN_ERROR1("Bad scalar source suffix");
798 }
Michal Krol2861e732004-03-29 11:09:34 +0000799
800 return GL_TRUE;
801}
802
803
804static GLint
805Parse_UnaryOpInstruction(struct parse_state *parseState,
Brian Paul7e807512005-11-05 17:10:45 +0000806 struct prog_instruction *inst,
807 enum prog_opcode opcode)
Michal Krol2861e732004-03-29 11:09:34 +0000808{
Brian Paul7e807512005-11-05 17:10:45 +0000809 if (opcode == OPCODE_ABS && !parseState->isVersion1_1)
Michal Krol2861e732004-03-29 11:09:34 +0000810 RETURN_ERROR1("ABS illegal for vertex program 1.0");
811
812 inst->Opcode = opcode;
813 inst->StringPos = parseState->curLine - parseState->start;
814
815 /* dest reg */
816 if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
817 RETURN_ERROR;
818
819 /* comma */
820 if (!Parse_String(parseState, ","))
821 RETURN_ERROR;
822
823 /* src arg */
824 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[0]))
825 RETURN_ERROR;
826
827 /* semicolon */
828 if (!Parse_String(parseState, ";"))
829 RETURN_ERROR;
830
831 return GL_TRUE;
832}
833
834
835static GLboolean
836Parse_BiOpInstruction(struct parse_state *parseState,
Brian Paul7e807512005-11-05 17:10:45 +0000837 struct prog_instruction *inst,
838 enum prog_opcode opcode)
Michal Krol2861e732004-03-29 11:09:34 +0000839{
Brian Paul7e807512005-11-05 17:10:45 +0000840 if (opcode == OPCODE_DPH && !parseState->isVersion1_1)
Michal Krol2861e732004-03-29 11:09:34 +0000841 RETURN_ERROR1("DPH illegal for vertex program 1.0");
Brian Paul7e807512005-11-05 17:10:45 +0000842 if (opcode == OPCODE_SUB && !parseState->isVersion1_1)
Michal Krol2861e732004-03-29 11:09:34 +0000843 RETURN_ERROR1("SUB illegal for vertex program 1.0");
844
845 inst->Opcode = opcode;
846 inst->StringPos = parseState->curLine - parseState->start;
847
848 /* dest reg */
849 if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
850 RETURN_ERROR;
851
852 /* comma */
853 if (!Parse_String(parseState, ","))
854 RETURN_ERROR;
855
856 /* first src arg */
857 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[0]))
858 RETURN_ERROR;
859
860 /* comma */
861 if (!Parse_String(parseState, ","))
862 RETURN_ERROR;
863
864 /* second src arg */
865 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[1]))
866 RETURN_ERROR;
867
868 /* semicolon */
869 if (!Parse_String(parseState, ";"))
870 RETURN_ERROR;
871
872 /* make sure we don't reference more than one program parameter register */
873 if (inst->SrcReg[0].File == PROGRAM_ENV_PARAM &&
874 inst->SrcReg[1].File == PROGRAM_ENV_PARAM &&
875 inst->SrcReg[0].Index != inst->SrcReg[1].Index)
876 RETURN_ERROR1("Can't reference two program parameter registers");
877
878 /* make sure we don't reference more than one vertex attribute register */
879 if (inst->SrcReg[0].File == PROGRAM_INPUT &&
880 inst->SrcReg[1].File == PROGRAM_INPUT &&
881 inst->SrcReg[0].Index != inst->SrcReg[1].Index)
882 RETURN_ERROR1("Can't reference two vertex attribute registers");
883
884 return GL_TRUE;
885}
886
887
888static GLboolean
889Parse_TriOpInstruction(struct parse_state *parseState,
Brian Paul7e807512005-11-05 17:10:45 +0000890 struct prog_instruction *inst,
891 enum prog_opcode opcode)
Michal Krol2861e732004-03-29 11:09:34 +0000892{
893 inst->Opcode = opcode;
894 inst->StringPos = parseState->curLine - parseState->start;
895
896 /* dest reg */
897 if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
898 RETURN_ERROR;
899
900 /* comma */
901 if (!Parse_String(parseState, ","))
902 RETURN_ERROR;
903
904 /* first src arg */
905 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[0]))
906 RETURN_ERROR;
907
908 /* comma */
909 if (!Parse_String(parseState, ","))
910 RETURN_ERROR;
911
912 /* second src arg */
913 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[1]))
914 RETURN_ERROR;
915
916 /* comma */
917 if (!Parse_String(parseState, ","))
918 RETURN_ERROR;
919
920 /* third src arg */
921 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[2]))
922 RETURN_ERROR;
923
924 /* semicolon */
925 if (!Parse_String(parseState, ";"))
926 RETURN_ERROR;
927
928 /* make sure we don't reference more than one program parameter register */
929 if ((inst->SrcReg[0].File == PROGRAM_ENV_PARAM &&
930 inst->SrcReg[1].File == PROGRAM_ENV_PARAM &&
931 inst->SrcReg[0].Index != inst->SrcReg[1].Index) ||
932 (inst->SrcReg[0].File == PROGRAM_ENV_PARAM &&
933 inst->SrcReg[2].File == PROGRAM_ENV_PARAM &&
934 inst->SrcReg[0].Index != inst->SrcReg[2].Index) ||
935 (inst->SrcReg[1].File == PROGRAM_ENV_PARAM &&
936 inst->SrcReg[2].File == PROGRAM_ENV_PARAM &&
937 inst->SrcReg[1].Index != inst->SrcReg[2].Index))
938 RETURN_ERROR1("Can only reference one program register");
939
940 /* make sure we don't reference more than one vertex attribute register */
941 if ((inst->SrcReg[0].File == PROGRAM_INPUT &&
942 inst->SrcReg[1].File == PROGRAM_INPUT &&
943 inst->SrcReg[0].Index != inst->SrcReg[1].Index) ||
944 (inst->SrcReg[0].File == PROGRAM_INPUT &&
945 inst->SrcReg[2].File == PROGRAM_INPUT &&
946 inst->SrcReg[0].Index != inst->SrcReg[2].Index) ||
947 (inst->SrcReg[1].File == PROGRAM_INPUT &&
948 inst->SrcReg[2].File == PROGRAM_INPUT &&
949 inst->SrcReg[1].Index != inst->SrcReg[2].Index))
950 RETURN_ERROR1("Can only reference one input register");
951
952 return GL_TRUE;
953}
954
955
956static GLboolean
957Parse_ScalarInstruction(struct parse_state *parseState,
Brian Paul7e807512005-11-05 17:10:45 +0000958 struct prog_instruction *inst,
959 enum prog_opcode opcode)
Michal Krol2861e732004-03-29 11:09:34 +0000960{
Brian Paul7e807512005-11-05 17:10:45 +0000961 if (opcode == OPCODE_RCC && !parseState->isVersion1_1)
Michal Krol2861e732004-03-29 11:09:34 +0000962 RETURN_ERROR1("RCC illegal for vertex program 1.0");
963
964 inst->Opcode = opcode;
965 inst->StringPos = parseState->curLine - parseState->start;
966
967 /* dest reg */
968 if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
969 RETURN_ERROR;
970
971 /* comma */
972 if (!Parse_String(parseState, ","))
973 RETURN_ERROR;
974
975 /* first src arg */
976 if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0]))
977 RETURN_ERROR;
978
979 /* semicolon */
980 if (!Parse_String(parseState, ";"))
981 RETURN_ERROR;
982
983 return GL_TRUE;
984}
985
986
987static GLboolean
Brian Paul7e807512005-11-05 17:10:45 +0000988Parse_AddressInstruction(struct parse_state *parseState, struct prog_instruction *inst)
Michal Krol2861e732004-03-29 11:09:34 +0000989{
Brian Paul7e807512005-11-05 17:10:45 +0000990 inst->Opcode = OPCODE_ARL;
Michal Krol2861e732004-03-29 11:09:34 +0000991 inst->StringPos = parseState->curLine - parseState->start;
992
993 /* dest A0 reg */
994 if (!Parse_AddrReg(parseState))
995 RETURN_ERROR;
996
997 /* comma */
998 if (!Parse_String(parseState, ","))
999 RETURN_ERROR;
1000
1001 /* parse src reg */
1002 if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0]))
1003 RETURN_ERROR;
1004
1005 /* semicolon */
1006 if (!Parse_String(parseState, ";"))
1007 RETURN_ERROR;
1008
1009 return GL_TRUE;
1010}
1011
1012
1013static GLboolean
Brian Paul7e807512005-11-05 17:10:45 +00001014Parse_EndInstruction(struct parse_state *parseState, struct prog_instruction *inst)
Michal Krol2861e732004-03-29 11:09:34 +00001015{
1016 GLubyte token[100];
1017
Brian Paul7e807512005-11-05 17:10:45 +00001018 inst->Opcode = OPCODE_END;
Michal Krol2861e732004-03-29 11:09:34 +00001019 inst->StringPos = parseState->curLine - parseState->start;
1020
1021 /* this should fail! */
1022 if (Parse_Token(parseState, token))
1023 RETURN_ERROR2("Unexpected token after END:", token);
1024 else
1025 return GL_TRUE;
1026}
1027
1028
Brian Paul575700f2004-12-16 03:07:18 +00001029/**
1030 * The PRINT instruction is Mesa-specific and is meant as a debugging aid for
1031 * the vertex program developer.
1032 * The NV_vertex_program extension grammar is modified as follows:
1033 *
1034 * <instruction> ::= <ARL-instruction>
1035 * | ...
1036 * | <PRINT-instruction>
1037 *
1038 * <PRINT-instruction> ::= "PRINT" <string literal>
1039 * | "PRINT" <string literal> "," <srcReg>
1040 * | "PRINT" <string literal> "," <dstReg>
1041 */
1042static GLboolean
Brian Paul7e807512005-11-05 17:10:45 +00001043Parse_PrintInstruction(struct parse_state *parseState, struct prog_instruction *inst)
Brian Paul575700f2004-12-16 03:07:18 +00001044{
1045 const GLubyte *str;
1046 GLubyte *msg;
1047 GLuint len;
1048 GLubyte token[100];
Brian Paul7e807512005-11-05 17:10:45 +00001049 struct prog_src_register *srcReg = &inst->SrcReg[0];
Keith Whitwell7c26b612005-04-21 14:46:57 +00001050 GLint idx;
Brian Paul575700f2004-12-16 03:07:18 +00001051
Brian Paul7e807512005-11-05 17:10:45 +00001052 inst->Opcode = OPCODE_PRINT;
Brian Paul575700f2004-12-16 03:07:18 +00001053 inst->StringPos = parseState->curLine - parseState->start;
1054
1055 /* The first argument is a literal string 'just like this' */
1056 if (!Parse_String(parseState, "'"))
1057 RETURN_ERROR;
1058
1059 str = parseState->pos;
1060 for (len = 0; str[len] != '\''; len++) /* find closing quote */
1061 ;
1062 parseState->pos += len + 1;
1063 msg = _mesa_malloc(len + 1);
1064
1065 _mesa_memcpy(msg, str, len);
1066 msg[len] = 0;
1067 inst->Data = msg;
1068
1069 /* comma */
1070 if (Parse_String(parseState, ",")) {
1071
1072 /* The second argument is a register name */
1073 if (!Peek_Token(parseState, token))
1074 RETURN_ERROR;
1075
1076 srcReg->RelAddr = GL_FALSE;
Brian Paul7e807512005-11-05 17:10:45 +00001077 srcReg->NegateBase = GL_FALSE;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001078 srcReg->Swizzle = SWIZZLE_NOOP;
Brian Paul575700f2004-12-16 03:07:18 +00001079
1080 /* Register can be R<n>, c[n], c[n +/- offset], a named vertex attrib,
1081 * or an o[n] output register.
1082 */
1083 if (token[0] == 'R') {
1084 srcReg->File = PROGRAM_TEMPORARY;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001085 if (!Parse_TempReg(parseState, &idx))
Brian Paul575700f2004-12-16 03:07:18 +00001086 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001087 srcReg->Index = idx;
Brian Paul575700f2004-12-16 03:07:18 +00001088 }
1089 else if (token[0] == 'c') {
1090 srcReg->File = PROGRAM_ENV_PARAM;
1091 if (!Parse_ParamReg(parseState, srcReg))
1092 RETURN_ERROR;
1093 }
1094 else if (token[0] == 'v') {
1095 srcReg->File = PROGRAM_INPUT;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001096 if (!Parse_AttribReg(parseState, &idx))
Brian Paul575700f2004-12-16 03:07:18 +00001097 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001098 srcReg->Index = idx;
Brian Paul575700f2004-12-16 03:07:18 +00001099 }
1100 else if (token[0] == 'o') {
1101 srcReg->File = PROGRAM_OUTPUT;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001102 if (!Parse_OutputReg(parseState, &idx))
Brian Paul575700f2004-12-16 03:07:18 +00001103 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001104 srcReg->Index = idx;
Brian Paul575700f2004-12-16 03:07:18 +00001105 }
1106 else {
1107 RETURN_ERROR2("Bad source register name", token);
1108 }
1109 }
1110 else {
1111 srcReg->File = 0;
1112 }
1113
1114 /* semicolon */
1115 if (!Parse_String(parseState, ";"))
1116 RETURN_ERROR;
1117
1118 return GL_TRUE;
1119}
1120
1121
Michal Krol2861e732004-03-29 11:09:34 +00001122static GLboolean
1123Parse_OptionSequence(struct parse_state *parseState,
Brian Paul7e807512005-11-05 17:10:45 +00001124 struct prog_instruction program[])
Michal Krol2861e732004-03-29 11:09:34 +00001125{
Brian Paula6c423d2004-08-25 15:59:48 +00001126 (void) program;
Michal Krol2861e732004-03-29 11:09:34 +00001127 while (1) {
1128 if (!Parse_String(parseState, "OPTION"))
1129 return GL_TRUE; /* ok, not an OPTION statement */
1130 if (Parse_String(parseState, "NV_position_invariant")) {
1131 parseState->isPositionInvariant = GL_TRUE;
1132 }
1133 else {
1134 RETURN_ERROR1("unexpected OPTION statement");
1135 }
1136 if (!Parse_String(parseState, ";"))
1137 return GL_FALSE;
1138 }
1139}
1140
1141
1142static GLboolean
1143Parse_InstructionSequence(struct parse_state *parseState,
Brian Paul7e807512005-11-05 17:10:45 +00001144 struct prog_instruction program[])
Michal Krol2861e732004-03-29 11:09:34 +00001145{
1146 while (1) {
Brian Paul7e807512005-11-05 17:10:45 +00001147 struct prog_instruction *inst = program + parseState->numInst;
Michal Krol2861e732004-03-29 11:09:34 +00001148
1149 /* Initialize the instruction */
Brian Paul7e807512005-11-05 17:10:45 +00001150 _mesa_init_instruction(inst);
Michal Krol2861e732004-03-29 11:09:34 +00001151
1152 if (Parse_String(parseState, "MOV")) {
Brian Paul7e807512005-11-05 17:10:45 +00001153 if (!Parse_UnaryOpInstruction(parseState, inst, OPCODE_MOV))
Michal Krol2861e732004-03-29 11:09:34 +00001154 RETURN_ERROR;
1155 }
1156 else if (Parse_String(parseState, "LIT")) {
Brian Paul7e807512005-11-05 17:10:45 +00001157 if (!Parse_UnaryOpInstruction(parseState, inst, OPCODE_LIT))
Michal Krol2861e732004-03-29 11:09:34 +00001158 RETURN_ERROR;
1159 }
1160 else if (Parse_String(parseState, "ABS")) {
Brian Paul7e807512005-11-05 17:10:45 +00001161 if (!Parse_UnaryOpInstruction(parseState, inst, OPCODE_ABS))
Michal Krol2861e732004-03-29 11:09:34 +00001162 RETURN_ERROR;
1163 }
1164 else if (Parse_String(parseState, "MUL")) {
Brian Paul7e807512005-11-05 17:10:45 +00001165 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_MUL))
Michal Krol2861e732004-03-29 11:09:34 +00001166 RETURN_ERROR;
1167 }
1168 else if (Parse_String(parseState, "ADD")) {
Brian Paul7e807512005-11-05 17:10:45 +00001169 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_ADD))
Michal Krol2861e732004-03-29 11:09:34 +00001170 RETURN_ERROR;
1171 }
1172 else if (Parse_String(parseState, "DP3")) {
Brian Paul7e807512005-11-05 17:10:45 +00001173 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_DP3))
Michal Krol2861e732004-03-29 11:09:34 +00001174 RETURN_ERROR;
1175 }
1176 else if (Parse_String(parseState, "DP4")) {
Brian Paul7e807512005-11-05 17:10:45 +00001177 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_DP4))
Michal Krol2861e732004-03-29 11:09:34 +00001178 RETURN_ERROR;
1179 }
1180 else if (Parse_String(parseState, "DST")) {
Brian Paul7e807512005-11-05 17:10:45 +00001181 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_DST))
Michal Krol2861e732004-03-29 11:09:34 +00001182 RETURN_ERROR;
1183 }
1184 else if (Parse_String(parseState, "MIN")) {
Brian Paul7e807512005-11-05 17:10:45 +00001185 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_MIN))
Michal Krol2861e732004-03-29 11:09:34 +00001186 RETURN_ERROR;
1187 }
1188 else if (Parse_String(parseState, "MAX")) {
Brian Paul7e807512005-11-05 17:10:45 +00001189 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_MAX))
Michal Krol2861e732004-03-29 11:09:34 +00001190 RETURN_ERROR;
1191 }
1192 else if (Parse_String(parseState, "SLT")) {
Brian Paul7e807512005-11-05 17:10:45 +00001193 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_SLT))
Michal Krol2861e732004-03-29 11:09:34 +00001194 RETURN_ERROR;
1195 }
1196 else if (Parse_String(parseState, "SGE")) {
Brian Paul7e807512005-11-05 17:10:45 +00001197 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_SGE))
Michal Krol2861e732004-03-29 11:09:34 +00001198 RETURN_ERROR;
1199 }
1200 else if (Parse_String(parseState, "DPH")) {
Brian Paul7e807512005-11-05 17:10:45 +00001201 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_DPH))
Michal Krol2861e732004-03-29 11:09:34 +00001202 RETURN_ERROR;
1203 }
1204 else if (Parse_String(parseState, "SUB")) {
Brian Paul7e807512005-11-05 17:10:45 +00001205 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_SUB))
Michal Krol2861e732004-03-29 11:09:34 +00001206 RETURN_ERROR;
1207 }
1208 else if (Parse_String(parseState, "MAD")) {
Brian Paul7e807512005-11-05 17:10:45 +00001209 if (!Parse_TriOpInstruction(parseState, inst, OPCODE_MAD))
Michal Krol2861e732004-03-29 11:09:34 +00001210 RETURN_ERROR;
1211 }
1212 else if (Parse_String(parseState, "RCP")) {
Brian Paul7e807512005-11-05 17:10:45 +00001213 if (!Parse_ScalarInstruction(parseState, inst, OPCODE_RCP))
Michal Krol2861e732004-03-29 11:09:34 +00001214 RETURN_ERROR;
1215 }
1216 else if (Parse_String(parseState, "RSQ")) {
Brian Paul7e807512005-11-05 17:10:45 +00001217 if (!Parse_ScalarInstruction(parseState, inst, OPCODE_RSQ))
Michal Krol2861e732004-03-29 11:09:34 +00001218 RETURN_ERROR;
1219 }
1220 else if (Parse_String(parseState, "EXP")) {
Brian Paul7e807512005-11-05 17:10:45 +00001221 if (!Parse_ScalarInstruction(parseState, inst, OPCODE_EXP))
Michal Krol2861e732004-03-29 11:09:34 +00001222 RETURN_ERROR;
1223 }
1224 else if (Parse_String(parseState, "LOG")) {
Brian Paul7e807512005-11-05 17:10:45 +00001225 if (!Parse_ScalarInstruction(parseState, inst, OPCODE_LOG))
Michal Krol2861e732004-03-29 11:09:34 +00001226 RETURN_ERROR;
1227 }
1228 else if (Parse_String(parseState, "RCC")) {
Brian Paul7e807512005-11-05 17:10:45 +00001229 if (!Parse_ScalarInstruction(parseState, inst, OPCODE_RCC))
Michal Krol2861e732004-03-29 11:09:34 +00001230 RETURN_ERROR;
1231 }
1232 else if (Parse_String(parseState, "ARL")) {
1233 if (!Parse_AddressInstruction(parseState, inst))
1234 RETURN_ERROR;
1235 }
Brian Paul575700f2004-12-16 03:07:18 +00001236 else if (Parse_String(parseState, "PRINT")) {
1237 if (!Parse_PrintInstruction(parseState, inst))
1238 RETURN_ERROR;
1239 }
Michal Krol2861e732004-03-29 11:09:34 +00001240 else if (Parse_String(parseState, "END")) {
1241 if (!Parse_EndInstruction(parseState, inst))
1242 RETURN_ERROR;
1243 else {
1244 parseState->numInst++;
1245 return GL_TRUE; /* all done */
1246 }
1247 }
1248 else {
1249 /* bad instruction name */
1250 RETURN_ERROR1("Unexpected token");
1251 }
1252
1253 /* examine input/output registers */
1254 if (inst->DstReg.File == PROGRAM_OUTPUT)
1255 parseState->outputsWritten |= (1 << inst->DstReg.Index);
1256 else if (inst->DstReg.File == PROGRAM_ENV_PARAM)
1257 parseState->anyProgRegsWritten = GL_TRUE;
1258
1259 if (inst->SrcReg[0].File == PROGRAM_INPUT)
1260 parseState->inputsRead |= (1 << inst->SrcReg[0].Index);
1261 if (inst->SrcReg[1].File == PROGRAM_INPUT)
1262 parseState->inputsRead |= (1 << inst->SrcReg[1].Index);
1263 if (inst->SrcReg[2].File == PROGRAM_INPUT)
1264 parseState->inputsRead |= (1 << inst->SrcReg[2].Index);
1265
1266 parseState->numInst++;
1267
1268 if (parseState->numInst >= MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS)
1269 RETURN_ERROR1("Program too long");
1270 }
1271
1272 RETURN_ERROR;
1273}
1274
1275
1276static GLboolean
1277Parse_Program(struct parse_state *parseState,
Brian Paul7e807512005-11-05 17:10:45 +00001278 struct prog_instruction instBuffer[])
Michal Krol2861e732004-03-29 11:09:34 +00001279{
1280 if (parseState->isVersion1_1) {
1281 if (!Parse_OptionSequence(parseState, instBuffer)) {
1282 return GL_FALSE;
1283 }
1284 }
1285 return Parse_InstructionSequence(parseState, instBuffer);
1286}
1287
1288
1289/**
1290 * Parse/compile the 'str' returning the compiled 'program'.
1291 * ctx->Program.ErrorPos will be -1 if successful. Otherwise, ErrorPos
1292 * indicates the position of the error in 'str'.
1293 */
1294void
1295_mesa_parse_nv_vertex_program(GLcontext *ctx, GLenum dstTarget,
1296 const GLubyte *str, GLsizei len,
1297 struct vertex_program *program)
1298{
1299 struct parse_state parseState;
Brian Paul7e807512005-11-05 17:10:45 +00001300 struct prog_instruction instBuffer[MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS];
1301 struct prog_instruction *newInst;
Michal Krol2861e732004-03-29 11:09:34 +00001302 GLenum target;
1303 GLubyte *programString;
1304
1305 /* Make a null-terminated copy of the program string */
1306 programString = (GLubyte *) MALLOC(len + 1);
1307 if (!programString) {
1308 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
1309 return;
1310 }
1311 MEMCPY(programString, str, len);
1312 programString[len] = 0;
1313
1314 /* Get ready to parse */
1315 parseState.ctx = ctx;
1316 parseState.start = programString;
1317 parseState.isPositionInvariant = GL_FALSE;
1318 parseState.isVersion1_1 = GL_FALSE;
1319 parseState.numInst = 0;
1320 parseState.inputsRead = 0;
1321 parseState.outputsWritten = 0;
1322 parseState.anyProgRegsWritten = GL_FALSE;
1323
1324 /* Reset error state */
1325 _mesa_set_program_error(ctx, -1, NULL);
1326
1327 /* check the program header */
1328 if (_mesa_strncmp((const char *) programString, "!!VP1.0", 7) == 0) {
1329 target = GL_VERTEX_PROGRAM_NV;
1330 parseState.pos = programString + 7;
1331 parseState.isStateProgram = GL_FALSE;
1332 }
1333 else if (_mesa_strncmp((const char *) programString, "!!VP1.1", 7) == 0) {
1334 target = GL_VERTEX_PROGRAM_NV;
1335 parseState.pos = programString + 7;
1336 parseState.isStateProgram = GL_FALSE;
1337 parseState.isVersion1_1 = GL_TRUE;
1338 }
1339 else if (_mesa_strncmp((const char *) programString, "!!VSP1.0", 8) == 0) {
1340 target = GL_VERTEX_STATE_PROGRAM_NV;
1341 parseState.pos = programString + 8;
1342 parseState.isStateProgram = GL_TRUE;
1343 }
1344 else {
1345 /* invalid header */
1346 ctx->Program.ErrorPos = 0;
1347 _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(bad header)");
1348 return;
1349 }
1350
1351 /* make sure target and header match */
1352 if (target != dstTarget) {
1353 _mesa_error(ctx, GL_INVALID_OPERATION,
1354 "glLoadProgramNV(target mismatch)");
1355 return;
1356 }
1357
1358
1359 if (Parse_Program(&parseState, instBuffer)) {
1360 /* successful parse! */
1361
1362 if (parseState.isStateProgram) {
1363 if (!parseState.anyProgRegsWritten) {
1364 _mesa_error(ctx, GL_INVALID_OPERATION,
1365 "glLoadProgramNV(c[#] not written)");
1366 return;
1367 }
1368 }
1369 else {
1370 if (!parseState.isPositionInvariant &&
1371 !(parseState.outputsWritten & 1)) {
1372 /* bit 1 = HPOS register */
1373 _mesa_error(ctx, GL_INVALID_OPERATION,
1374 "glLoadProgramNV(HPOS not written)");
1375 return;
1376 }
1377 }
1378
1379 /* copy the compiled instructions */
1380 assert(parseState.numInst <= MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS);
Brian Paul7e807512005-11-05 17:10:45 +00001381 newInst = (struct prog_instruction *)
1382 MALLOC(parseState.numInst * sizeof(struct prog_instruction));
Michal Krol2861e732004-03-29 11:09:34 +00001383 if (!newInst) {
1384 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
1385 FREE(programString);
1386 return; /* out of memory */
1387 }
1388 MEMCPY(newInst, instBuffer,
Brian Paul7e807512005-11-05 17:10:45 +00001389 parseState.numInst * sizeof(struct prog_instruction));
Michal Krol2861e732004-03-29 11:09:34 +00001390
1391 /* install the program */
1392 program->Base.Target = target;
1393 if (program->Base.String) {
1394 FREE(program->Base.String);
1395 }
1396 program->Base.String = programString;
1397 program->Base.Format = GL_PROGRAM_FORMAT_ASCII_ARB;
1398 if (program->Instructions) {
1399 FREE(program->Instructions);
1400 }
1401 program->Instructions = newInst;
1402 program->InputsRead = parseState.inputsRead;
1403 program->OutputsWritten = parseState.outputsWritten;
1404 program->IsPositionInvariant = parseState.isPositionInvariant;
Brian Paul05a6f2f2004-04-21 18:09:14 +00001405 program->IsNVProgram = GL_TRUE;
Michal Krol2861e732004-03-29 11:09:34 +00001406
Brian Paul2a5afe32004-12-18 16:18:00 +00001407#ifdef DEBUG_foo
Michal Krol2861e732004-03-29 11:09:34 +00001408 _mesa_printf("--- glLoadProgramNV result ---\n");
1409 _mesa_print_nv_vertex_program(program);
1410 _mesa_printf("------------------------------\n");
1411#endif
1412 }
1413 else {
1414 /* Error! */
1415 _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV");
1416 /* NOTE: _mesa_set_program_error would have been called already */
1417 /* GL_NV_vertex_program isn't supposed to set the error string
1418 * so we reset it here.
1419 */
1420 _mesa_set_program_error(ctx, ctx->Program.ErrorPos, NULL);
1421 }
1422}
1423
1424
1425static void
Brian Paul7e807512005-11-05 17:10:45 +00001426PrintSrcReg(const struct prog_src_register *src)
Michal Krol2861e732004-03-29 11:09:34 +00001427{
1428 static const char comps[5] = "xyzw";
Brian Paul7e807512005-11-05 17:10:45 +00001429 if (src->NegateBase)
Michal Krol2861e732004-03-29 11:09:34 +00001430 _mesa_printf("-");
1431 if (src->RelAddr) {
1432 if (src->Index > 0)
1433 _mesa_printf("c[A0.x + %d]", src->Index);
1434 else if (src->Index < 0)
1435 _mesa_printf("c[A0.x - %d]", -src->Index);
1436 else
1437 _mesa_printf("c[A0.x]");
1438 }
1439 else if (src->File == PROGRAM_OUTPUT) {
1440 _mesa_printf("o[%s]", OutputRegisters[src->Index]);
1441 }
1442 else if (src->File == PROGRAM_INPUT) {
1443 _mesa_printf("v[%s]", InputRegisters[src->Index]);
1444 }
1445 else if (src->File == PROGRAM_ENV_PARAM) {
1446 _mesa_printf("c[%d]", src->Index);
1447 }
1448 else {
1449 ASSERT(src->File == PROGRAM_TEMPORARY);
1450 _mesa_printf("R%d", src->Index);
1451 }
1452
Keith Whitwell7c26b612005-04-21 14:46:57 +00001453 if (GET_SWZ(src->Swizzle, 0) == GET_SWZ(src->Swizzle, 1) &&
1454 GET_SWZ(src->Swizzle, 0) == GET_SWZ(src->Swizzle, 2) &&
1455 GET_SWZ(src->Swizzle, 0) == GET_SWZ(src->Swizzle, 3)) {
1456 _mesa_printf(".%c", comps[GET_SWZ(src->Swizzle, 0)]);
Michal Krol2861e732004-03-29 11:09:34 +00001457 }
Keith Whitwell7c26b612005-04-21 14:46:57 +00001458 else if (src->Swizzle != SWIZZLE_NOOP) {
Michal Krol2861e732004-03-29 11:09:34 +00001459 _mesa_printf(".%c%c%c%c",
Keith Whitwell7c26b612005-04-21 14:46:57 +00001460 comps[GET_SWZ(src->Swizzle, 0)],
1461 comps[GET_SWZ(src->Swizzle, 1)],
1462 comps[GET_SWZ(src->Swizzle, 2)],
1463 comps[GET_SWZ(src->Swizzle, 3)]);
Michal Krol2861e732004-03-29 11:09:34 +00001464 }
1465}
1466
1467
1468static void
Brian Paul7e807512005-11-05 17:10:45 +00001469PrintDstReg(const struct prog_dst_register *dst)
Michal Krol2861e732004-03-29 11:09:34 +00001470{
Michal Krol2861e732004-03-29 11:09:34 +00001471 if (dst->File == PROGRAM_OUTPUT) {
1472 _mesa_printf("o[%s]", OutputRegisters[dst->Index]);
1473 }
1474 else if (dst->File == PROGRAM_INPUT) {
1475 _mesa_printf("v[%s]", InputRegisters[dst->Index]);
1476 }
1477 else if (dst->File == PROGRAM_ENV_PARAM) {
1478 _mesa_printf("c[%d]", dst->Index);
1479 }
1480 else {
1481 ASSERT(dst->File == PROGRAM_TEMPORARY);
1482 _mesa_printf("R%d", dst->Index);
1483 }
1484
Brian Paulccfe3d42005-11-03 02:35:15 +00001485 if (dst->WriteMask != 0 && dst->WriteMask != WRITEMASK_XYZW) {
Michal Krol2861e732004-03-29 11:09:34 +00001486 _mesa_printf(".");
Brian Paulccfe3d42005-11-03 02:35:15 +00001487 if (dst->WriteMask & WRITEMASK_X)
Michal Krol2861e732004-03-29 11:09:34 +00001488 _mesa_printf("x");
Brian Paulccfe3d42005-11-03 02:35:15 +00001489 if (dst->WriteMask & WRITEMASK_Y)
Michal Krol2861e732004-03-29 11:09:34 +00001490 _mesa_printf("y");
Brian Paulccfe3d42005-11-03 02:35:15 +00001491 if (dst->WriteMask & WRITEMASK_Z)
Michal Krol2861e732004-03-29 11:09:34 +00001492 _mesa_printf("z");
Brian Paulccfe3d42005-11-03 02:35:15 +00001493 if (dst->WriteMask & WRITEMASK_W)
Michal Krol2861e732004-03-29 11:09:34 +00001494 _mesa_printf("w");
1495 }
1496}
1497
1498
1499/**
1500 * Print a single NVIDIA vertex program instruction.
1501 */
1502void
Brian Paul7e807512005-11-05 17:10:45 +00001503_mesa_print_nv_vertex_instruction(const struct prog_instruction *inst)
Michal Krol2861e732004-03-29 11:09:34 +00001504{
1505 switch (inst->Opcode) {
Brian Paul7e807512005-11-05 17:10:45 +00001506 case OPCODE_MOV:
1507 case OPCODE_LIT:
1508 case OPCODE_RCP:
1509 case OPCODE_RSQ:
1510 case OPCODE_EXP:
1511 case OPCODE_LOG:
1512 case OPCODE_RCC:
1513 case OPCODE_ABS:
Michal Krol2861e732004-03-29 11:09:34 +00001514 _mesa_printf("%s ", Opcodes[(int) inst->Opcode]);
1515 PrintDstReg(&inst->DstReg);
1516 _mesa_printf(", ");
1517 PrintSrcReg(&inst->SrcReg[0]);
1518 _mesa_printf(";\n");
1519 break;
Brian Paul7e807512005-11-05 17:10:45 +00001520 case OPCODE_MUL:
1521 case OPCODE_ADD:
1522 case OPCODE_DP3:
1523 case OPCODE_DP4:
1524 case OPCODE_DST:
1525 case OPCODE_MIN:
1526 case OPCODE_MAX:
1527 case OPCODE_SLT:
1528 case OPCODE_SGE:
1529 case OPCODE_DPH:
1530 case OPCODE_SUB:
Michal Krol2861e732004-03-29 11:09:34 +00001531 _mesa_printf("%s ", Opcodes[(int) inst->Opcode]);
1532 PrintDstReg(&inst->DstReg);
1533 _mesa_printf(", ");
1534 PrintSrcReg(&inst->SrcReg[0]);
1535 _mesa_printf(", ");
1536 PrintSrcReg(&inst->SrcReg[1]);
1537 _mesa_printf(";\n");
1538 break;
Brian Paul7e807512005-11-05 17:10:45 +00001539 case OPCODE_MAD:
Michal Krol2861e732004-03-29 11:09:34 +00001540 _mesa_printf("MAD ");
1541 PrintDstReg(&inst->DstReg);
1542 _mesa_printf(", ");
1543 PrintSrcReg(&inst->SrcReg[0]);
1544 _mesa_printf(", ");
1545 PrintSrcReg(&inst->SrcReg[1]);
1546 _mesa_printf(", ");
1547 PrintSrcReg(&inst->SrcReg[2]);
1548 _mesa_printf(";\n");
1549 break;
Brian Paul7e807512005-11-05 17:10:45 +00001550 case OPCODE_ARL:
Michal Krol2861e732004-03-29 11:09:34 +00001551 _mesa_printf("ARL A0.x, ");
1552 PrintSrcReg(&inst->SrcReg[0]);
1553 _mesa_printf(";\n");
1554 break;
Brian Paul7e807512005-11-05 17:10:45 +00001555 case OPCODE_PRINT:
Brian Paul575700f2004-12-16 03:07:18 +00001556 _mesa_printf("PRINT '%s'", inst->Data);
1557 if (inst->SrcReg[0].File) {
1558 _mesa_printf(", ");
1559 PrintSrcReg(&inst->SrcReg[0]);
1560 _mesa_printf(";\n");
1561 }
1562 else {
1563 _mesa_printf("\n");
1564 }
1565 break;
Brian Paul7e807512005-11-05 17:10:45 +00001566 case OPCODE_END:
Michal Krol2861e732004-03-29 11:09:34 +00001567 _mesa_printf("END\n");
1568 break;
1569 default:
1570 _mesa_printf("BAD INSTRUCTION\n");
1571 }
1572}
1573
1574
1575/**
1576 * Print (unparse) the given vertex program. Just for debugging.
1577 */
1578void
1579_mesa_print_nv_vertex_program(const struct vertex_program *program)
1580{
Brian Paul7e807512005-11-05 17:10:45 +00001581 const struct prog_instruction *inst;
Michal Krol2861e732004-03-29 11:09:34 +00001582
1583 for (inst = program->Instructions; ; inst++) {
1584 _mesa_print_nv_vertex_instruction(inst);
Brian Paul7e807512005-11-05 17:10:45 +00001585 if (inst->Opcode == OPCODE_END)
Michal Krol2861e732004-03-29 11:09:34 +00001586 return;
1587 }
1588}
1589
1590
1591const char *
1592_mesa_nv_vertex_input_register_name(GLuint i)
1593{
1594 ASSERT(i < MAX_NV_VERTEX_PROGRAM_INPUTS);
1595 return InputRegisters[i];
1596}
1597
1598
1599const char *
1600_mesa_nv_vertex_output_register_name(GLuint i)
1601{
1602 ASSERT(i < MAX_NV_VERTEX_PROGRAM_OUTPUTS);
1603 return OutputRegisters[i];
1604}
Brian Paul7aebaf32005-10-30 21:23:23 +00001605
1606
1607/**
Brian Paul7e807512005-11-05 17:10:45 +00001608 * Initialize program instruction fields to defaults.
Brian Paul7aebaf32005-10-30 21:23:23 +00001609 */
1610void
Brian Paul7e807512005-11-05 17:10:45 +00001611_mesa_init_instruction(struct prog_instruction *inst)
Brian Paul7aebaf32005-10-30 21:23:23 +00001612{
Brian Paul7e807512005-11-05 17:10:45 +00001613 _mesa_bzero(inst, sizeof(struct prog_instruction));
1614
Brian Paul7aebaf32005-10-30 21:23:23 +00001615 inst->SrcReg[0].File = PROGRAM_UNDEFINED;
1616 inst->SrcReg[0].Swizzle = SWIZZLE_NOOP;
1617 inst->SrcReg[1].File = PROGRAM_UNDEFINED;
1618 inst->SrcReg[1].Swizzle = SWIZZLE_NOOP;
1619 inst->SrcReg[2].File = PROGRAM_UNDEFINED;
1620 inst->SrcReg[2].Swizzle = SWIZZLE_NOOP;
Brian Paul7e807512005-11-05 17:10:45 +00001621
Brian Paul7aebaf32005-10-30 21:23:23 +00001622 inst->DstReg.File = PROGRAM_UNDEFINED;
Brian Paulccfe3d42005-11-03 02:35:15 +00001623 inst->DstReg.WriteMask = WRITEMASK_XYZW;
Brian Paul7e807512005-11-05 17:10:45 +00001624 inst->DstReg.CondMask = COND_TR;
1625 inst->DstReg.CondSwizzle = SWIZZLE_NOOP;
1626
1627 inst->Precision = FLOAT32;
Brian Paul7aebaf32005-10-30 21:23:23 +00001628}