blob: 24882a289797c8606818ee8e815eb6ed88007450 [file] [log] [blame]
Michal Krol2861e732004-03-29 11:09:34 +00001/*
2 * Mesa 3-D graphics library
Brian Paul575700f2004-12-16 03:07:18 +00003 * Version: 6.3
Michal Krol2861e732004-03-29 11:09:34 +00004 *
5 * Copyright (C) 1999-2004 Brian Paul All Rights Reserved.
6 *
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"
48#include "nvvertprog.h"
49#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
296/* NOTE: the order here must match opcodes in nvvertprog.h */
297static 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
396Parse_ParamReg(struct parse_state *parseState, struct vp_src_register *srcReg)
397{
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
564Parse_MaskedDstReg(struct parse_state *parseState, struct vp_dst_register *dstReg)
565{
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
645Parse_SwizzleSrcReg(struct parse_state *parseState, struct vp_src_register *srcReg)
646{
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, "-");
657 srcReg->Negate = GL_TRUE;
658 if (!Peek_Token(parseState, token))
659 RETURN_ERROR;
660 }
661 else {
662 srcReg->Negate = GL_FALSE;
663 }
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
736Parse_ScalarSrcReg(struct parse_state *parseState, struct vp_src_register *srcReg)
737{
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] == '-') {
747 srcReg->Negate = GL_TRUE;
748 (void) Parse_String(parseState, "-"); /* consume '-' */
749 if (!Peek_Token(parseState, token))
750 RETURN_ERROR;
751 }
752 else {
753 srcReg->Negate = GL_FALSE;
754 }
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,
806 struct vp_instruction *inst, enum vp_opcode opcode)
807{
808 if (opcode == VP_OPCODE_ABS && !parseState->isVersion1_1)
809 RETURN_ERROR1("ABS illegal for vertex program 1.0");
810
811 inst->Opcode = opcode;
812 inst->StringPos = parseState->curLine - parseState->start;
813
814 /* dest reg */
815 if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
816 RETURN_ERROR;
817
818 /* comma */
819 if (!Parse_String(parseState, ","))
820 RETURN_ERROR;
821
822 /* src arg */
823 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[0]))
824 RETURN_ERROR;
825
826 /* semicolon */
827 if (!Parse_String(parseState, ";"))
828 RETURN_ERROR;
829
830 return GL_TRUE;
831}
832
833
834static GLboolean
835Parse_BiOpInstruction(struct parse_state *parseState,
836 struct vp_instruction *inst, enum vp_opcode opcode)
837{
838 if (opcode == VP_OPCODE_DPH && !parseState->isVersion1_1)
839 RETURN_ERROR1("DPH illegal for vertex program 1.0");
840 if (opcode == VP_OPCODE_SUB && !parseState->isVersion1_1)
841 RETURN_ERROR1("SUB illegal for vertex program 1.0");
842
843 inst->Opcode = opcode;
844 inst->StringPos = parseState->curLine - parseState->start;
845
846 /* dest reg */
847 if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
848 RETURN_ERROR;
849
850 /* comma */
851 if (!Parse_String(parseState, ","))
852 RETURN_ERROR;
853
854 /* first src arg */
855 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[0]))
856 RETURN_ERROR;
857
858 /* comma */
859 if (!Parse_String(parseState, ","))
860 RETURN_ERROR;
861
862 /* second src arg */
863 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[1]))
864 RETURN_ERROR;
865
866 /* semicolon */
867 if (!Parse_String(parseState, ";"))
868 RETURN_ERROR;
869
870 /* make sure we don't reference more than one program parameter register */
871 if (inst->SrcReg[0].File == PROGRAM_ENV_PARAM &&
872 inst->SrcReg[1].File == PROGRAM_ENV_PARAM &&
873 inst->SrcReg[0].Index != inst->SrcReg[1].Index)
874 RETURN_ERROR1("Can't reference two program parameter registers");
875
876 /* make sure we don't reference more than one vertex attribute register */
877 if (inst->SrcReg[0].File == PROGRAM_INPUT &&
878 inst->SrcReg[1].File == PROGRAM_INPUT &&
879 inst->SrcReg[0].Index != inst->SrcReg[1].Index)
880 RETURN_ERROR1("Can't reference two vertex attribute registers");
881
882 return GL_TRUE;
883}
884
885
886static GLboolean
887Parse_TriOpInstruction(struct parse_state *parseState,
888 struct vp_instruction *inst, enum vp_opcode opcode)
889{
890 inst->Opcode = opcode;
891 inst->StringPos = parseState->curLine - parseState->start;
892
893 /* dest reg */
894 if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
895 RETURN_ERROR;
896
897 /* comma */
898 if (!Parse_String(parseState, ","))
899 RETURN_ERROR;
900
901 /* first src arg */
902 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[0]))
903 RETURN_ERROR;
904
905 /* comma */
906 if (!Parse_String(parseState, ","))
907 RETURN_ERROR;
908
909 /* second src arg */
910 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[1]))
911 RETURN_ERROR;
912
913 /* comma */
914 if (!Parse_String(parseState, ","))
915 RETURN_ERROR;
916
917 /* third src arg */
918 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[2]))
919 RETURN_ERROR;
920
921 /* semicolon */
922 if (!Parse_String(parseState, ";"))
923 RETURN_ERROR;
924
925 /* make sure we don't reference more than one program parameter register */
926 if ((inst->SrcReg[0].File == PROGRAM_ENV_PARAM &&
927 inst->SrcReg[1].File == PROGRAM_ENV_PARAM &&
928 inst->SrcReg[0].Index != inst->SrcReg[1].Index) ||
929 (inst->SrcReg[0].File == PROGRAM_ENV_PARAM &&
930 inst->SrcReg[2].File == PROGRAM_ENV_PARAM &&
931 inst->SrcReg[0].Index != inst->SrcReg[2].Index) ||
932 (inst->SrcReg[1].File == PROGRAM_ENV_PARAM &&
933 inst->SrcReg[2].File == PROGRAM_ENV_PARAM &&
934 inst->SrcReg[1].Index != inst->SrcReg[2].Index))
935 RETURN_ERROR1("Can only reference one program register");
936
937 /* make sure we don't reference more than one vertex attribute register */
938 if ((inst->SrcReg[0].File == PROGRAM_INPUT &&
939 inst->SrcReg[1].File == PROGRAM_INPUT &&
940 inst->SrcReg[0].Index != inst->SrcReg[1].Index) ||
941 (inst->SrcReg[0].File == PROGRAM_INPUT &&
942 inst->SrcReg[2].File == PROGRAM_INPUT &&
943 inst->SrcReg[0].Index != inst->SrcReg[2].Index) ||
944 (inst->SrcReg[1].File == PROGRAM_INPUT &&
945 inst->SrcReg[2].File == PROGRAM_INPUT &&
946 inst->SrcReg[1].Index != inst->SrcReg[2].Index))
947 RETURN_ERROR1("Can only reference one input register");
948
949 return GL_TRUE;
950}
951
952
953static GLboolean
954Parse_ScalarInstruction(struct parse_state *parseState,
955 struct vp_instruction *inst, enum vp_opcode opcode)
956{
957 if (opcode == VP_OPCODE_RCC && !parseState->isVersion1_1)
958 RETURN_ERROR1("RCC illegal for vertex program 1.0");
959
960 inst->Opcode = opcode;
961 inst->StringPos = parseState->curLine - parseState->start;
962
963 /* dest reg */
964 if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
965 RETURN_ERROR;
966
967 /* comma */
968 if (!Parse_String(parseState, ","))
969 RETURN_ERROR;
970
971 /* first src arg */
972 if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0]))
973 RETURN_ERROR;
974
975 /* semicolon */
976 if (!Parse_String(parseState, ";"))
977 RETURN_ERROR;
978
979 return GL_TRUE;
980}
981
982
983static GLboolean
984Parse_AddressInstruction(struct parse_state *parseState, struct vp_instruction *inst)
985{
986 inst->Opcode = VP_OPCODE_ARL;
987 inst->StringPos = parseState->curLine - parseState->start;
988
989 /* dest A0 reg */
990 if (!Parse_AddrReg(parseState))
991 RETURN_ERROR;
992
993 /* comma */
994 if (!Parse_String(parseState, ","))
995 RETURN_ERROR;
996
997 /* parse src reg */
998 if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0]))
999 RETURN_ERROR;
1000
1001 /* semicolon */
1002 if (!Parse_String(parseState, ";"))
1003 RETURN_ERROR;
1004
1005 return GL_TRUE;
1006}
1007
1008
1009static GLboolean
1010Parse_EndInstruction(struct parse_state *parseState, struct vp_instruction *inst)
1011{
1012 GLubyte token[100];
1013
1014 inst->Opcode = VP_OPCODE_END;
1015 inst->StringPos = parseState->curLine - parseState->start;
1016
1017 /* this should fail! */
1018 if (Parse_Token(parseState, token))
1019 RETURN_ERROR2("Unexpected token after END:", token);
1020 else
1021 return GL_TRUE;
1022}
1023
1024
Brian Paul575700f2004-12-16 03:07:18 +00001025/**
1026 * The PRINT instruction is Mesa-specific and is meant as a debugging aid for
1027 * the vertex program developer.
1028 * The NV_vertex_program extension grammar is modified as follows:
1029 *
1030 * <instruction> ::= <ARL-instruction>
1031 * | ...
1032 * | <PRINT-instruction>
1033 *
1034 * <PRINT-instruction> ::= "PRINT" <string literal>
1035 * | "PRINT" <string literal> "," <srcReg>
1036 * | "PRINT" <string literal> "," <dstReg>
1037 */
1038static GLboolean
1039Parse_PrintInstruction(struct parse_state *parseState, struct vp_instruction *inst)
1040{
1041 const GLubyte *str;
1042 GLubyte *msg;
1043 GLuint len;
1044 GLubyte token[100];
1045 struct vp_src_register *srcReg = &inst->SrcReg[0];
Keith Whitwell7c26b612005-04-21 14:46:57 +00001046 GLint idx;
Brian Paul575700f2004-12-16 03:07:18 +00001047
1048 inst->Opcode = VP_OPCODE_PRINT;
1049 inst->StringPos = parseState->curLine - parseState->start;
1050
1051 /* The first argument is a literal string 'just like this' */
1052 if (!Parse_String(parseState, "'"))
1053 RETURN_ERROR;
1054
1055 str = parseState->pos;
1056 for (len = 0; str[len] != '\''; len++) /* find closing quote */
1057 ;
1058 parseState->pos += len + 1;
1059 msg = _mesa_malloc(len + 1);
1060
1061 _mesa_memcpy(msg, str, len);
1062 msg[len] = 0;
1063 inst->Data = msg;
1064
1065 /* comma */
1066 if (Parse_String(parseState, ",")) {
1067
1068 /* The second argument is a register name */
1069 if (!Peek_Token(parseState, token))
1070 RETURN_ERROR;
1071
1072 srcReg->RelAddr = GL_FALSE;
1073 srcReg->Negate = GL_FALSE;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001074 srcReg->Swizzle = SWIZZLE_NOOP;
Brian Paul575700f2004-12-16 03:07:18 +00001075
1076 /* Register can be R<n>, c[n], c[n +/- offset], a named vertex attrib,
1077 * or an o[n] output register.
1078 */
1079 if (token[0] == 'R') {
1080 srcReg->File = PROGRAM_TEMPORARY;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001081 if (!Parse_TempReg(parseState, &idx))
Brian Paul575700f2004-12-16 03:07:18 +00001082 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001083 srcReg->Index = idx;
Brian Paul575700f2004-12-16 03:07:18 +00001084 }
1085 else if (token[0] == 'c') {
1086 srcReg->File = PROGRAM_ENV_PARAM;
1087 if (!Parse_ParamReg(parseState, srcReg))
1088 RETURN_ERROR;
1089 }
1090 else if (token[0] == 'v') {
1091 srcReg->File = PROGRAM_INPUT;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001092 if (!Parse_AttribReg(parseState, &idx))
Brian Paul575700f2004-12-16 03:07:18 +00001093 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001094 srcReg->Index = idx;
Brian Paul575700f2004-12-16 03:07:18 +00001095 }
1096 else if (token[0] == 'o') {
1097 srcReg->File = PROGRAM_OUTPUT;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001098 if (!Parse_OutputReg(parseState, &idx))
Brian Paul575700f2004-12-16 03:07:18 +00001099 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001100 srcReg->Index = idx;
Brian Paul575700f2004-12-16 03:07:18 +00001101 }
1102 else {
1103 RETURN_ERROR2("Bad source register name", token);
1104 }
1105 }
1106 else {
1107 srcReg->File = 0;
1108 }
1109
1110 /* semicolon */
1111 if (!Parse_String(parseState, ";"))
1112 RETURN_ERROR;
1113
1114 return GL_TRUE;
1115}
1116
1117
Michal Krol2861e732004-03-29 11:09:34 +00001118static GLboolean
1119Parse_OptionSequence(struct parse_state *parseState,
1120 struct vp_instruction program[])
1121{
Brian Paula6c423d2004-08-25 15:59:48 +00001122 (void) program;
Michal Krol2861e732004-03-29 11:09:34 +00001123 while (1) {
1124 if (!Parse_String(parseState, "OPTION"))
1125 return GL_TRUE; /* ok, not an OPTION statement */
1126 if (Parse_String(parseState, "NV_position_invariant")) {
1127 parseState->isPositionInvariant = GL_TRUE;
1128 }
1129 else {
1130 RETURN_ERROR1("unexpected OPTION statement");
1131 }
1132 if (!Parse_String(parseState, ";"))
1133 return GL_FALSE;
1134 }
1135}
1136
1137
1138static GLboolean
1139Parse_InstructionSequence(struct parse_state *parseState,
1140 struct vp_instruction program[])
1141{
1142 while (1) {
1143 struct vp_instruction *inst = program + parseState->numInst;
1144
1145 /* Initialize the instruction */
Brian Paul7aebaf32005-10-30 21:23:23 +00001146 _mesa_init_vp_instruction(inst);
Michal Krol2861e732004-03-29 11:09:34 +00001147
1148 if (Parse_String(parseState, "MOV")) {
1149 if (!Parse_UnaryOpInstruction(parseState, inst, VP_OPCODE_MOV))
1150 RETURN_ERROR;
1151 }
1152 else if (Parse_String(parseState, "LIT")) {
1153 if (!Parse_UnaryOpInstruction(parseState, inst, VP_OPCODE_LIT))
1154 RETURN_ERROR;
1155 }
1156 else if (Parse_String(parseState, "ABS")) {
1157 if (!Parse_UnaryOpInstruction(parseState, inst, VP_OPCODE_ABS))
1158 RETURN_ERROR;
1159 }
1160 else if (Parse_String(parseState, "MUL")) {
1161 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_MUL))
1162 RETURN_ERROR;
1163 }
1164 else if (Parse_String(parseState, "ADD")) {
1165 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_ADD))
1166 RETURN_ERROR;
1167 }
1168 else if (Parse_String(parseState, "DP3")) {
1169 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_DP3))
1170 RETURN_ERROR;
1171 }
1172 else if (Parse_String(parseState, "DP4")) {
1173 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_DP4))
1174 RETURN_ERROR;
1175 }
1176 else if (Parse_String(parseState, "DST")) {
1177 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_DST))
1178 RETURN_ERROR;
1179 }
1180 else if (Parse_String(parseState, "MIN")) {
1181 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_MIN))
1182 RETURN_ERROR;
1183 }
1184 else if (Parse_String(parseState, "MAX")) {
1185 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_MAX))
1186 RETURN_ERROR;
1187 }
1188 else if (Parse_String(parseState, "SLT")) {
1189 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_SLT))
1190 RETURN_ERROR;
1191 }
1192 else if (Parse_String(parseState, "SGE")) {
1193 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_SGE))
1194 RETURN_ERROR;
1195 }
1196 else if (Parse_String(parseState, "DPH")) {
1197 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_DPH))
1198 RETURN_ERROR;
1199 }
1200 else if (Parse_String(parseState, "SUB")) {
1201 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_SUB))
1202 RETURN_ERROR;
1203 }
1204 else if (Parse_String(parseState, "MAD")) {
1205 if (!Parse_TriOpInstruction(parseState, inst, VP_OPCODE_MAD))
1206 RETURN_ERROR;
1207 }
1208 else if (Parse_String(parseState, "RCP")) {
1209 if (!Parse_ScalarInstruction(parseState, inst, VP_OPCODE_RCP))
1210 RETURN_ERROR;
1211 }
1212 else if (Parse_String(parseState, "RSQ")) {
1213 if (!Parse_ScalarInstruction(parseState, inst, VP_OPCODE_RSQ))
1214 RETURN_ERROR;
1215 }
1216 else if (Parse_String(parseState, "EXP")) {
1217 if (!Parse_ScalarInstruction(parseState, inst, VP_OPCODE_EXP))
1218 RETURN_ERROR;
1219 }
1220 else if (Parse_String(parseState, "LOG")) {
1221 if (!Parse_ScalarInstruction(parseState, inst, VP_OPCODE_LOG))
1222 RETURN_ERROR;
1223 }
1224 else if (Parse_String(parseState, "RCC")) {
1225 if (!Parse_ScalarInstruction(parseState, inst, VP_OPCODE_RCC))
1226 RETURN_ERROR;
1227 }
1228 else if (Parse_String(parseState, "ARL")) {
1229 if (!Parse_AddressInstruction(parseState, inst))
1230 RETURN_ERROR;
1231 }
Brian Paul575700f2004-12-16 03:07:18 +00001232 else if (Parse_String(parseState, "PRINT")) {
1233 if (!Parse_PrintInstruction(parseState, inst))
1234 RETURN_ERROR;
1235 }
Michal Krol2861e732004-03-29 11:09:34 +00001236 else if (Parse_String(parseState, "END")) {
1237 if (!Parse_EndInstruction(parseState, inst))
1238 RETURN_ERROR;
1239 else {
1240 parseState->numInst++;
1241 return GL_TRUE; /* all done */
1242 }
1243 }
1244 else {
1245 /* bad instruction name */
1246 RETURN_ERROR1("Unexpected token");
1247 }
1248
1249 /* examine input/output registers */
1250 if (inst->DstReg.File == PROGRAM_OUTPUT)
1251 parseState->outputsWritten |= (1 << inst->DstReg.Index);
1252 else if (inst->DstReg.File == PROGRAM_ENV_PARAM)
1253 parseState->anyProgRegsWritten = GL_TRUE;
1254
1255 if (inst->SrcReg[0].File == PROGRAM_INPUT)
1256 parseState->inputsRead |= (1 << inst->SrcReg[0].Index);
1257 if (inst->SrcReg[1].File == PROGRAM_INPUT)
1258 parseState->inputsRead |= (1 << inst->SrcReg[1].Index);
1259 if (inst->SrcReg[2].File == PROGRAM_INPUT)
1260 parseState->inputsRead |= (1 << inst->SrcReg[2].Index);
1261
1262 parseState->numInst++;
1263
1264 if (parseState->numInst >= MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS)
1265 RETURN_ERROR1("Program too long");
1266 }
1267
1268 RETURN_ERROR;
1269}
1270
1271
1272static GLboolean
1273Parse_Program(struct parse_state *parseState,
1274 struct vp_instruction instBuffer[])
1275{
1276 if (parseState->isVersion1_1) {
1277 if (!Parse_OptionSequence(parseState, instBuffer)) {
1278 return GL_FALSE;
1279 }
1280 }
1281 return Parse_InstructionSequence(parseState, instBuffer);
1282}
1283
1284
1285/**
1286 * Parse/compile the 'str' returning the compiled 'program'.
1287 * ctx->Program.ErrorPos will be -1 if successful. Otherwise, ErrorPos
1288 * indicates the position of the error in 'str'.
1289 */
1290void
1291_mesa_parse_nv_vertex_program(GLcontext *ctx, GLenum dstTarget,
1292 const GLubyte *str, GLsizei len,
1293 struct vertex_program *program)
1294{
1295 struct parse_state parseState;
1296 struct vp_instruction instBuffer[MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS];
1297 struct vp_instruction *newInst;
1298 GLenum target;
1299 GLubyte *programString;
1300
1301 /* Make a null-terminated copy of the program string */
1302 programString = (GLubyte *) MALLOC(len + 1);
1303 if (!programString) {
1304 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
1305 return;
1306 }
1307 MEMCPY(programString, str, len);
1308 programString[len] = 0;
1309
1310 /* Get ready to parse */
1311 parseState.ctx = ctx;
1312 parseState.start = programString;
1313 parseState.isPositionInvariant = GL_FALSE;
1314 parseState.isVersion1_1 = GL_FALSE;
1315 parseState.numInst = 0;
1316 parseState.inputsRead = 0;
1317 parseState.outputsWritten = 0;
1318 parseState.anyProgRegsWritten = GL_FALSE;
1319
1320 /* Reset error state */
1321 _mesa_set_program_error(ctx, -1, NULL);
1322
1323 /* check the program header */
1324 if (_mesa_strncmp((const char *) programString, "!!VP1.0", 7) == 0) {
1325 target = GL_VERTEX_PROGRAM_NV;
1326 parseState.pos = programString + 7;
1327 parseState.isStateProgram = GL_FALSE;
1328 }
1329 else if (_mesa_strncmp((const char *) programString, "!!VP1.1", 7) == 0) {
1330 target = GL_VERTEX_PROGRAM_NV;
1331 parseState.pos = programString + 7;
1332 parseState.isStateProgram = GL_FALSE;
1333 parseState.isVersion1_1 = GL_TRUE;
1334 }
1335 else if (_mesa_strncmp((const char *) programString, "!!VSP1.0", 8) == 0) {
1336 target = GL_VERTEX_STATE_PROGRAM_NV;
1337 parseState.pos = programString + 8;
1338 parseState.isStateProgram = GL_TRUE;
1339 }
1340 else {
1341 /* invalid header */
1342 ctx->Program.ErrorPos = 0;
1343 _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(bad header)");
1344 return;
1345 }
1346
1347 /* make sure target and header match */
1348 if (target != dstTarget) {
1349 _mesa_error(ctx, GL_INVALID_OPERATION,
1350 "glLoadProgramNV(target mismatch)");
1351 return;
1352 }
1353
1354
1355 if (Parse_Program(&parseState, instBuffer)) {
1356 /* successful parse! */
1357
1358 if (parseState.isStateProgram) {
1359 if (!parseState.anyProgRegsWritten) {
1360 _mesa_error(ctx, GL_INVALID_OPERATION,
1361 "glLoadProgramNV(c[#] not written)");
1362 return;
1363 }
1364 }
1365 else {
1366 if (!parseState.isPositionInvariant &&
1367 !(parseState.outputsWritten & 1)) {
1368 /* bit 1 = HPOS register */
1369 _mesa_error(ctx, GL_INVALID_OPERATION,
1370 "glLoadProgramNV(HPOS not written)");
1371 return;
1372 }
1373 }
1374
1375 /* copy the compiled instructions */
1376 assert(parseState.numInst <= MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS);
1377 newInst = (struct vp_instruction *)
1378 MALLOC(parseState.numInst * sizeof(struct vp_instruction));
1379 if (!newInst) {
1380 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
1381 FREE(programString);
1382 return; /* out of memory */
1383 }
1384 MEMCPY(newInst, instBuffer,
1385 parseState.numInst * sizeof(struct vp_instruction));
1386
1387 /* install the program */
1388 program->Base.Target = target;
1389 if (program->Base.String) {
1390 FREE(program->Base.String);
1391 }
1392 program->Base.String = programString;
1393 program->Base.Format = GL_PROGRAM_FORMAT_ASCII_ARB;
1394 if (program->Instructions) {
1395 FREE(program->Instructions);
1396 }
1397 program->Instructions = newInst;
1398 program->InputsRead = parseState.inputsRead;
1399 program->OutputsWritten = parseState.outputsWritten;
1400 program->IsPositionInvariant = parseState.isPositionInvariant;
Brian Paul05a6f2f2004-04-21 18:09:14 +00001401 program->IsNVProgram = GL_TRUE;
Michal Krol2861e732004-03-29 11:09:34 +00001402
Brian Paul2a5afe32004-12-18 16:18:00 +00001403#ifdef DEBUG_foo
Michal Krol2861e732004-03-29 11:09:34 +00001404 _mesa_printf("--- glLoadProgramNV result ---\n");
1405 _mesa_print_nv_vertex_program(program);
1406 _mesa_printf("------------------------------\n");
1407#endif
1408 }
1409 else {
1410 /* Error! */
1411 _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV");
1412 /* NOTE: _mesa_set_program_error would have been called already */
1413 /* GL_NV_vertex_program isn't supposed to set the error string
1414 * so we reset it here.
1415 */
1416 _mesa_set_program_error(ctx, ctx->Program.ErrorPos, NULL);
1417 }
1418}
1419
1420
1421static void
1422PrintSrcReg(const struct vp_src_register *src)
1423{
1424 static const char comps[5] = "xyzw";
1425 if (src->Negate)
1426 _mesa_printf("-");
1427 if (src->RelAddr) {
1428 if (src->Index > 0)
1429 _mesa_printf("c[A0.x + %d]", src->Index);
1430 else if (src->Index < 0)
1431 _mesa_printf("c[A0.x - %d]", -src->Index);
1432 else
1433 _mesa_printf("c[A0.x]");
1434 }
1435 else if (src->File == PROGRAM_OUTPUT) {
1436 _mesa_printf("o[%s]", OutputRegisters[src->Index]);
1437 }
1438 else if (src->File == PROGRAM_INPUT) {
1439 _mesa_printf("v[%s]", InputRegisters[src->Index]);
1440 }
1441 else if (src->File == PROGRAM_ENV_PARAM) {
1442 _mesa_printf("c[%d]", src->Index);
1443 }
1444 else {
1445 ASSERT(src->File == PROGRAM_TEMPORARY);
1446 _mesa_printf("R%d", src->Index);
1447 }
1448
Keith Whitwell7c26b612005-04-21 14:46:57 +00001449 if (GET_SWZ(src->Swizzle, 0) == GET_SWZ(src->Swizzle, 1) &&
1450 GET_SWZ(src->Swizzle, 0) == GET_SWZ(src->Swizzle, 2) &&
1451 GET_SWZ(src->Swizzle, 0) == GET_SWZ(src->Swizzle, 3)) {
1452 _mesa_printf(".%c", comps[GET_SWZ(src->Swizzle, 0)]);
Michal Krol2861e732004-03-29 11:09:34 +00001453 }
Keith Whitwell7c26b612005-04-21 14:46:57 +00001454 else if (src->Swizzle != SWIZZLE_NOOP) {
Michal Krol2861e732004-03-29 11:09:34 +00001455 _mesa_printf(".%c%c%c%c",
Keith Whitwell7c26b612005-04-21 14:46:57 +00001456 comps[GET_SWZ(src->Swizzle, 0)],
1457 comps[GET_SWZ(src->Swizzle, 1)],
1458 comps[GET_SWZ(src->Swizzle, 2)],
1459 comps[GET_SWZ(src->Swizzle, 3)]);
Michal Krol2861e732004-03-29 11:09:34 +00001460 }
1461}
1462
1463
1464static void
1465PrintDstReg(const struct vp_dst_register *dst)
1466{
Michal Krol2861e732004-03-29 11:09:34 +00001467 if (dst->File == PROGRAM_OUTPUT) {
1468 _mesa_printf("o[%s]", OutputRegisters[dst->Index]);
1469 }
1470 else if (dst->File == PROGRAM_INPUT) {
1471 _mesa_printf("v[%s]", InputRegisters[dst->Index]);
1472 }
1473 else if (dst->File == PROGRAM_ENV_PARAM) {
1474 _mesa_printf("c[%d]", dst->Index);
1475 }
1476 else {
1477 ASSERT(dst->File == PROGRAM_TEMPORARY);
1478 _mesa_printf("R%d", dst->Index);
1479 }
1480
Keith Whitwell7c26b612005-04-21 14:46:57 +00001481 if (dst->WriteMask != 0 && dst->WriteMask != 0xf) {
Michal Krol2861e732004-03-29 11:09:34 +00001482 _mesa_printf(".");
Keith Whitwell7c26b612005-04-21 14:46:57 +00001483 if (dst->WriteMask & 0x1)
Michal Krol2861e732004-03-29 11:09:34 +00001484 _mesa_printf("x");
Keith Whitwell7c26b612005-04-21 14:46:57 +00001485 if (dst->WriteMask & 0x2)
Michal Krol2861e732004-03-29 11:09:34 +00001486 _mesa_printf("y");
Keith Whitwell7c26b612005-04-21 14:46:57 +00001487 if (dst->WriteMask & 0x4)
Michal Krol2861e732004-03-29 11:09:34 +00001488 _mesa_printf("z");
Keith Whitwell7c26b612005-04-21 14:46:57 +00001489 if (dst->WriteMask & 0x8)
Michal Krol2861e732004-03-29 11:09:34 +00001490 _mesa_printf("w");
1491 }
1492}
1493
1494
1495/**
1496 * Print a single NVIDIA vertex program instruction.
1497 */
1498void
1499_mesa_print_nv_vertex_instruction(const struct vp_instruction *inst)
1500{
1501 switch (inst->Opcode) {
1502 case VP_OPCODE_MOV:
1503 case VP_OPCODE_LIT:
1504 case VP_OPCODE_RCP:
1505 case VP_OPCODE_RSQ:
1506 case VP_OPCODE_EXP:
1507 case VP_OPCODE_LOG:
1508 case VP_OPCODE_RCC:
1509 case VP_OPCODE_ABS:
1510 _mesa_printf("%s ", Opcodes[(int) inst->Opcode]);
1511 PrintDstReg(&inst->DstReg);
1512 _mesa_printf(", ");
1513 PrintSrcReg(&inst->SrcReg[0]);
1514 _mesa_printf(";\n");
1515 break;
1516 case VP_OPCODE_MUL:
1517 case VP_OPCODE_ADD:
1518 case VP_OPCODE_DP3:
1519 case VP_OPCODE_DP4:
1520 case VP_OPCODE_DST:
1521 case VP_OPCODE_MIN:
1522 case VP_OPCODE_MAX:
1523 case VP_OPCODE_SLT:
1524 case VP_OPCODE_SGE:
1525 case VP_OPCODE_DPH:
1526 case VP_OPCODE_SUB:
1527 _mesa_printf("%s ", Opcodes[(int) inst->Opcode]);
1528 PrintDstReg(&inst->DstReg);
1529 _mesa_printf(", ");
1530 PrintSrcReg(&inst->SrcReg[0]);
1531 _mesa_printf(", ");
1532 PrintSrcReg(&inst->SrcReg[1]);
1533 _mesa_printf(";\n");
1534 break;
1535 case VP_OPCODE_MAD:
1536 _mesa_printf("MAD ");
1537 PrintDstReg(&inst->DstReg);
1538 _mesa_printf(", ");
1539 PrintSrcReg(&inst->SrcReg[0]);
1540 _mesa_printf(", ");
1541 PrintSrcReg(&inst->SrcReg[1]);
1542 _mesa_printf(", ");
1543 PrintSrcReg(&inst->SrcReg[2]);
1544 _mesa_printf(";\n");
1545 break;
1546 case VP_OPCODE_ARL:
1547 _mesa_printf("ARL A0.x, ");
1548 PrintSrcReg(&inst->SrcReg[0]);
1549 _mesa_printf(";\n");
1550 break;
Brian Paul575700f2004-12-16 03:07:18 +00001551 case VP_OPCODE_PRINT:
1552 _mesa_printf("PRINT '%s'", inst->Data);
1553 if (inst->SrcReg[0].File) {
1554 _mesa_printf(", ");
1555 PrintSrcReg(&inst->SrcReg[0]);
1556 _mesa_printf(";\n");
1557 }
1558 else {
1559 _mesa_printf("\n");
1560 }
1561 break;
Michal Krol2861e732004-03-29 11:09:34 +00001562 case VP_OPCODE_END:
1563 _mesa_printf("END\n");
1564 break;
1565 default:
1566 _mesa_printf("BAD INSTRUCTION\n");
1567 }
1568}
1569
1570
1571/**
1572 * Print (unparse) the given vertex program. Just for debugging.
1573 */
1574void
1575_mesa_print_nv_vertex_program(const struct vertex_program *program)
1576{
1577 const struct vp_instruction *inst;
1578
1579 for (inst = program->Instructions; ; inst++) {
1580 _mesa_print_nv_vertex_instruction(inst);
1581 if (inst->Opcode == VP_OPCODE_END)
1582 return;
1583 }
1584}
1585
1586
1587const char *
1588_mesa_nv_vertex_input_register_name(GLuint i)
1589{
1590 ASSERT(i < MAX_NV_VERTEX_PROGRAM_INPUTS);
1591 return InputRegisters[i];
1592}
1593
1594
1595const char *
1596_mesa_nv_vertex_output_register_name(GLuint i)
1597{
1598 ASSERT(i < MAX_NV_VERTEX_PROGRAM_OUTPUTS);
1599 return OutputRegisters[i];
1600}
Brian Paul7aebaf32005-10-30 21:23:23 +00001601
1602
1603/**
1604 * Initialize vertex program instruction fields to defaults.
1605 */
1606void
1607_mesa_init_vp_instruction(struct vp_instruction *inst)
1608{
1609 _mesa_bzero(inst, sizeof(struct vp_instruction));
1610 inst->SrcReg[0].File = PROGRAM_UNDEFINED;
1611 inst->SrcReg[0].Swizzle = SWIZZLE_NOOP;
1612 inst->SrcReg[1].File = PROGRAM_UNDEFINED;
1613 inst->SrcReg[1].Swizzle = SWIZZLE_NOOP;
1614 inst->SrcReg[2].File = PROGRAM_UNDEFINED;
1615 inst->SrcReg[2].Swizzle = SWIZZLE_NOOP;
1616 inst->DstReg.File = PROGRAM_UNDEFINED;
1617 inst->DstReg.WriteMask = 0xf;
1618}
1619