blob: 268b577aec9c22b50e9ec34061148463324294ef [file] [log] [blame]
Michal Krol2861e732004-03-29 11:09:34 +00001/*
2 * Mesa 3-D graphics library
Brian Paulfe694702006-10-10 21:23:23 +00003 * Version: 6.5.2
Michal Krol2861e732004-03-29 11:09:34 +00004 *
Brian Paulfe694702006-10-10 21:23:23 +00005 * Copyright (C) 1999-2006 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
Brian Paulbbd28712008-09-18 12:26:54 -060040#include "main/glheader.h"
41#include "main/context.h"
42#include "main/imports.h"
43#include "main/macros.h"
Michal Krol2861e732004-03-29 11:09:34 +000044#include "nvprogram.h"
45#include "nvvertparse.h"
Brianc0551f02006-12-14 15:02:37 -070046#include "prog_instruction.h"
Michal Krol2861e732004-03-29 11:09:34 +000047#include "program.h"
48
49
50/**
51 * Current parsing state. This structure is passed among the parsing
52 * functions and keeps track of the current parser position and various
53 * program attributes.
54 */
55struct parse_state {
56 GLcontext *ctx;
57 const GLubyte *start;
58 const GLubyte *pos;
59 const GLubyte *curLine;
60 GLboolean isStateProgram;
61 GLboolean isPositionInvariant;
62 GLboolean isVersion1_1;
Brian Paul97a65932006-10-10 21:25:27 +000063 GLbitfield inputsRead;
64 GLbitfield outputsWritten;
Michal Krol2861e732004-03-29 11:09:34 +000065 GLboolean anyProgRegsWritten;
66 GLuint numInst; /* number of instructions parsed */
67};
68
69
70/*
71 * Called whenever we find an error during parsing.
72 */
73static void
74record_error(struct parse_state *parseState, const char *msg, int lineNo)
75{
76#ifdef DEBUG
77 GLint line, column;
78 const GLubyte *lineStr;
79 lineStr = _mesa_find_line_column(parseState->start,
80 parseState->pos, &line, &column);
81 _mesa_debug(parseState->ctx,
82 "nvfragparse.c(%d): line %d, column %d:%s (%s)\n",
83 lineNo, line, column, (char *) lineStr, msg);
84 _mesa_free((void *) lineStr);
85#else
86 (void) lineNo;
87#endif
88
89 /* Check that no error was already recorded. Only record the first one. */
90 if (parseState->ctx->Program.ErrorString[0] == 0) {
91 _mesa_set_program_error(parseState->ctx,
92 parseState->pos - parseState->start,
93 msg);
94 }
95}
96
97
98#define RETURN_ERROR \
99do { \
100 record_error(parseState, "Unexpected end of input.", __LINE__); \
101 return GL_FALSE; \
102} while(0)
103
104#define RETURN_ERROR1(msg) \
105do { \
106 record_error(parseState, msg, __LINE__); \
107 return GL_FALSE; \
108} while(0)
109
110#define RETURN_ERROR2(msg1, msg2) \
111do { \
112 char err[1000]; \
113 _mesa_sprintf(err, "%s %s", msg1, msg2); \
114 record_error(parseState, err, __LINE__); \
115 return GL_FALSE; \
116} while(0)
117
118
119
120
121
122static GLboolean IsLetter(GLubyte b)
123{
124 return (b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z');
125}
126
127
128static GLboolean IsDigit(GLubyte b)
129{
130 return b >= '0' && b <= '9';
131}
132
133
134static GLboolean IsWhitespace(GLubyte b)
135{
136 return b == ' ' || b == '\t' || b == '\n' || b == '\r';
137}
138
139
140/**
141 * Starting at 'str' find the next token. A token can be an integer,
142 * an identifier or punctuation symbol.
143 * \return <= 0 we found an error, else, return number of characters parsed.
144 */
145static GLint
146GetToken(struct parse_state *parseState, GLubyte *token)
147{
148 const GLubyte *str = parseState->pos;
149 GLint i = 0, j = 0;
150
151 token[0] = 0;
152
153 /* skip whitespace and comments */
154 while (str[i] && (IsWhitespace(str[i]) || str[i] == '#')) {
155 if (str[i] == '#') {
156 /* skip comment */
157 while (str[i] && (str[i] != '\n' && str[i] != '\r')) {
158 i++;
159 }
160 if (str[i] == '\n' || str[i] == '\r')
161 parseState->curLine = str + i + 1;
162 }
163 else {
164 /* skip whitespace */
165 if (str[i] == '\n' || str[i] == '\r')
166 parseState->curLine = str + i + 1;
167 i++;
168 }
169 }
170
171 if (str[i] == 0)
172 return -i;
173
174 /* try matching an integer */
175 while (str[i] && IsDigit(str[i])) {
176 token[j++] = str[i++];
177 }
178 if (j > 0 || !str[i]) {
179 token[j] = 0;
180 return i;
181 }
182
183 /* try matching an identifier */
184 if (IsLetter(str[i])) {
185 while (str[i] && (IsLetter(str[i]) || IsDigit(str[i]))) {
186 token[j++] = str[i++];
187 }
188 token[j] = 0;
189 return i;
190 }
191
192 /* punctuation character */
193 if (str[i]) {
194 token[0] = str[i++];
195 token[1] = 0;
196 return i;
197 }
198
199 /* end of input */
200 token[0] = 0;
201 return i;
202}
203
204
205/**
206 * Get next token from input stream and increment stream pointer past token.
207 */
208static GLboolean
209Parse_Token(struct parse_state *parseState, GLubyte *token)
210{
211 GLint i;
212 i = GetToken(parseState, token);
213 if (i <= 0) {
214 parseState->pos += (-i);
215 return GL_FALSE;
216 }
217 parseState->pos += i;
218 return GL_TRUE;
219}
220
221
222/**
223 * Get next token from input stream but don't increment stream pointer.
224 */
225static GLboolean
226Peek_Token(struct parse_state *parseState, GLubyte *token)
227{
228 GLint i, len;
229 i = GetToken(parseState, token);
230 if (i <= 0) {
231 parseState->pos += (-i);
232 return GL_FALSE;
233 }
Karl Schultz6258b762005-05-05 21:08:07 +0000234 len = (GLint)_mesa_strlen((const char *) token);
Michal Krol2861e732004-03-29 11:09:34 +0000235 parseState->pos += (i - len);
236 return GL_TRUE;
237}
238
239
240/**
241 * Try to match 'pattern' as the next token after any whitespace/comments.
242 * Advance the current parsing position only if we match the pattern.
243 * \return GL_TRUE if pattern is matched, GL_FALSE otherwise.
244 */
245static GLboolean
246Parse_String(struct parse_state *parseState, const char *pattern)
247{
248 const GLubyte *m;
249 GLint i;
250
251 /* skip whitespace and comments */
252 while (IsWhitespace(*parseState->pos) || *parseState->pos == '#') {
253 if (*parseState->pos == '#') {
254 while (*parseState->pos && (*parseState->pos != '\n' && *parseState->pos != '\r')) {
255 parseState->pos += 1;
256 }
257 if (*parseState->pos == '\n' || *parseState->pos == '\r')
258 parseState->curLine = parseState->pos + 1;
259 }
260 else {
261 /* skip whitespace */
262 if (*parseState->pos == '\n' || *parseState->pos == '\r')
263 parseState->curLine = parseState->pos + 1;
264 parseState->pos += 1;
265 }
266 }
267
268 /* Try to match the pattern */
269 m = parseState->pos;
270 for (i = 0; pattern[i]; i++) {
271 if (*m != (GLubyte) pattern[i])
272 return GL_FALSE;
273 m += 1;
274 }
275 parseState->pos = m;
276
277 return GL_TRUE; /* success */
278}
279
280
281/**********************************************************************/
282
283static const char *InputRegisters[MAX_NV_VERTEX_PROGRAM_INPUTS + 1] = {
284 "OPOS", "WGHT", "NRML", "COL0", "COL1", "FOGC", "6", "7",
285 "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", NULL
286};
287
288static const char *OutputRegisters[MAX_NV_VERTEX_PROGRAM_OUTPUTS + 1] = {
Keith Whitwellc3626a92005-11-01 17:25:49 +0000289 "HPOS", "COL0", "COL1", "FOGC",
290 "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7",
291 "PSIZ", "BFC0", "BFC1", NULL
Michal Krol2861e732004-03-29 11:09:34 +0000292};
293
Michal Krol2861e732004-03-29 11:09:34 +0000294
295
296/**
297 * Parse a temporary register: Rnn
298 */
299static GLboolean
300Parse_TempReg(struct parse_state *parseState, GLint *tempRegNum)
301{
302 GLubyte token[100];
303
304 /* Should be 'R##' */
305 if (!Parse_Token(parseState, token))
306 RETURN_ERROR;
307 if (token[0] != 'R')
308 RETURN_ERROR1("Expected R##");
309
310 if (IsDigit(token[1])) {
311 GLint reg = _mesa_atoi((char *) (token + 1));
312 if (reg >= MAX_NV_VERTEX_PROGRAM_TEMPS)
313 RETURN_ERROR1("Bad temporary register name");
314 *tempRegNum = reg;
315 }
316 else {
317 RETURN_ERROR1("Bad temporary register name");
318 }
319
320 return GL_TRUE;
321}
322
323
324/**
325 * Parse address register "A0.x"
326 */
327static GLboolean
328Parse_AddrReg(struct parse_state *parseState)
329{
330 /* match 'A0' */
331 if (!Parse_String(parseState, "A0"))
332 RETURN_ERROR;
333
334 /* match '.' */
335 if (!Parse_String(parseState, "."))
336 RETURN_ERROR;
337
338 /* match 'x' */
339 if (!Parse_String(parseState, "x"))
340 RETURN_ERROR;
341
342 return GL_TRUE;
343}
344
345
346/**
347 * Parse absolute program parameter register "c[##]"
348 */
349static GLboolean
350Parse_AbsParamReg(struct parse_state *parseState, GLint *regNum)
351{
352 GLubyte token[100];
353
354 if (!Parse_String(parseState, "c"))
355 RETURN_ERROR;
356
357 if (!Parse_String(parseState, "["))
358 RETURN_ERROR;
359
360 if (!Parse_Token(parseState, token))
361 RETURN_ERROR;
362
363 if (IsDigit(token[0])) {
364 /* a numbered program parameter register */
365 GLint reg = _mesa_atoi((char *) token);
366 if (reg >= MAX_NV_VERTEX_PROGRAM_PARAMS)
367 RETURN_ERROR1("Bad program parameter number");
368 *regNum = reg;
369 }
370 else {
371 RETURN_ERROR;
372 }
373
374 if (!Parse_String(parseState, "]"))
375 RETURN_ERROR;
376
377 return GL_TRUE;
378}
379
380
381static GLboolean
Brian Paul7e807512005-11-05 17:10:45 +0000382Parse_ParamReg(struct parse_state *parseState, struct prog_src_register *srcReg)
Michal Krol2861e732004-03-29 11:09:34 +0000383{
384 GLubyte token[100];
385
386 if (!Parse_String(parseState, "c"))
387 RETURN_ERROR;
388
389 if (!Parse_String(parseState, "["))
390 RETURN_ERROR;
391
392 if (!Peek_Token(parseState, token))
393 RETURN_ERROR;
394
395 if (IsDigit(token[0])) {
396 /* a numbered program parameter register */
397 GLint reg;
398 (void) Parse_Token(parseState, token);
399 reg = _mesa_atoi((char *) token);
400 if (reg >= MAX_NV_VERTEX_PROGRAM_PARAMS)
401 RETURN_ERROR1("Bad program parameter number");
402 srcReg->File = PROGRAM_ENV_PARAM;
403 srcReg->Index = reg;
404 }
405 else if (_mesa_strcmp((const char *) token, "A0") == 0) {
406 /* address register "A0.x" */
407 if (!Parse_AddrReg(parseState))
408 RETURN_ERROR;
409
410 srcReg->RelAddr = GL_TRUE;
411 srcReg->File = PROGRAM_ENV_PARAM;
412 /* Look for +/-N offset */
413 if (!Peek_Token(parseState, token))
414 RETURN_ERROR;
415
416 if (token[0] == '-' || token[0] == '+') {
417 const GLubyte sign = token[0];
418 (void) Parse_Token(parseState, token); /* consume +/- */
419
420 /* an integer should be next */
421 if (!Parse_Token(parseState, token))
422 RETURN_ERROR;
423
424 if (IsDigit(token[0])) {
425 const GLint k = _mesa_atoi((char *) token);
426 if (sign == '-') {
427 if (k > 64)
428 RETURN_ERROR1("Bad address offset");
429 srcReg->Index = -k;
430 }
431 else {
432 if (k > 63)
433 RETURN_ERROR1("Bad address offset");
434 srcReg->Index = k;
435 }
436 }
437 else {
438 RETURN_ERROR;
439 }
440 }
441 else {
442 /* probably got a ']', catch it below */
443 }
444 }
445 else {
446 RETURN_ERROR;
447 }
448
449 /* Match closing ']' */
450 if (!Parse_String(parseState, "]"))
451 RETURN_ERROR;
452
453 return GL_TRUE;
454}
455
456
457/**
458 * Parse v[#] or v[<name>]
459 */
460static GLboolean
461Parse_AttribReg(struct parse_state *parseState, GLint *tempRegNum)
462{
463 GLubyte token[100];
464 GLint j;
465
466 /* Match 'v' */
467 if (!Parse_String(parseState, "v"))
468 RETURN_ERROR;
469
470 /* Match '[' */
471 if (!Parse_String(parseState, "["))
472 RETURN_ERROR;
473
474 /* match number or named register */
475 if (!Parse_Token(parseState, token))
476 RETURN_ERROR;
477
478 if (parseState->isStateProgram && token[0] != '0')
479 RETURN_ERROR1("Only v[0] accessible in vertex state programs");
480
481 if (IsDigit(token[0])) {
482 GLint reg = _mesa_atoi((char *) token);
483 if (reg >= MAX_NV_VERTEX_PROGRAM_INPUTS)
484 RETURN_ERROR1("Bad vertex attribute register name");
485 *tempRegNum = reg;
486 }
487 else {
488 for (j = 0; InputRegisters[j]; j++) {
489 if (_mesa_strcmp((const char *) token, InputRegisters[j]) == 0) {
490 *tempRegNum = j;
491 break;
492 }
493 }
494 if (!InputRegisters[j]) {
495 /* unknown input register label */
496 RETURN_ERROR2("Bad register name", token);
497 }
498 }
499
500 /* Match '[' */
501 if (!Parse_String(parseState, "]"))
502 RETURN_ERROR;
503
504 return GL_TRUE;
505}
506
507
508static GLboolean
509Parse_OutputReg(struct parse_state *parseState, GLint *outputRegNum)
510{
511 GLubyte token[100];
512 GLint start, j;
513
514 /* Match 'o' */
515 if (!Parse_String(parseState, "o"))
516 RETURN_ERROR;
517
518 /* Match '[' */
519 if (!Parse_String(parseState, "["))
520 RETURN_ERROR;
521
522 /* Get output reg name */
523 if (!Parse_Token(parseState, token))
524 RETURN_ERROR;
525
526 if (parseState->isPositionInvariant)
527 start = 1; /* skip HPOS register name */
528 else
529 start = 0;
530
531 /* try to match an output register name */
532 for (j = start; OutputRegisters[j]; j++) {
533 if (_mesa_strcmp((const char *) token, OutputRegisters[j]) == 0) {
534 *outputRegNum = j;
535 break;
536 }
537 }
538 if (!OutputRegisters[j])
539 RETURN_ERROR1("Unrecognized output register name");
540
541 /* Match ']' */
542 if (!Parse_String(parseState, "]"))
543 RETURN_ERROR1("Expected ]");
544
545 return GL_TRUE;
546}
547
548
549static GLboolean
Brian Paul7e807512005-11-05 17:10:45 +0000550Parse_MaskedDstReg(struct parse_state *parseState, struct prog_dst_register *dstReg)
Michal Krol2861e732004-03-29 11:09:34 +0000551{
552 GLubyte token[100];
Keith Whitwell7c26b612005-04-21 14:46:57 +0000553 GLint idx;
Michal Krol2861e732004-03-29 11:09:34 +0000554
555 /* Dst reg can be R<n> or o[n] */
556 if (!Peek_Token(parseState, token))
557 RETURN_ERROR;
558
559 if (token[0] == 'R') {
560 /* a temporary register */
561 dstReg->File = PROGRAM_TEMPORARY;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000562 if (!Parse_TempReg(parseState, &idx))
Michal Krol2861e732004-03-29 11:09:34 +0000563 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000564 dstReg->Index = idx;
Michal Krol2861e732004-03-29 11:09:34 +0000565 }
566 else if (!parseState->isStateProgram && token[0] == 'o') {
567 /* an output register */
568 dstReg->File = PROGRAM_OUTPUT;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000569 if (!Parse_OutputReg(parseState, &idx))
Michal Krol2861e732004-03-29 11:09:34 +0000570 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000571 dstReg->Index = idx;
Michal Krol2861e732004-03-29 11:09:34 +0000572 }
573 else if (parseState->isStateProgram && token[0] == 'c' &&
574 parseState->isStateProgram) {
575 /* absolute program parameter register */
576 /* Only valid for vertex state programs */
577 dstReg->File = PROGRAM_ENV_PARAM;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000578 if (!Parse_AbsParamReg(parseState, &idx))
Michal Krol2861e732004-03-29 11:09:34 +0000579 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000580 dstReg->Index = idx;
Michal Krol2861e732004-03-29 11:09:34 +0000581 }
582 else {
583 RETURN_ERROR1("Bad destination register name");
584 }
585
586 /* Parse optional write mask */
587 if (!Peek_Token(parseState, token))
588 RETURN_ERROR;
589
590 if (token[0] == '.') {
591 /* got a mask */
592 GLint k = 0;
593
594 if (!Parse_String(parseState, "."))
595 RETURN_ERROR;
596
597 if (!Parse_Token(parseState, token))
598 RETURN_ERROR;
599
Keith Whitwell7c26b612005-04-21 14:46:57 +0000600 dstReg->WriteMask = 0;
Michal Krol2861e732004-03-29 11:09:34 +0000601
602 if (token[k] == 'x') {
Keith Whitwell7c26b612005-04-21 14:46:57 +0000603 dstReg->WriteMask |= WRITEMASK_X;
Michal Krol2861e732004-03-29 11:09:34 +0000604 k++;
605 }
606 if (token[k] == 'y') {
Keith Whitwell7c26b612005-04-21 14:46:57 +0000607 dstReg->WriteMask |= WRITEMASK_Y;
Michal Krol2861e732004-03-29 11:09:34 +0000608 k++;
609 }
610 if (token[k] == 'z') {
Keith Whitwell7c26b612005-04-21 14:46:57 +0000611 dstReg->WriteMask |= WRITEMASK_Z;
Michal Krol2861e732004-03-29 11:09:34 +0000612 k++;
613 }
614 if (token[k] == 'w') {
Keith Whitwell7c26b612005-04-21 14:46:57 +0000615 dstReg->WriteMask |= WRITEMASK_W;
Michal Krol2861e732004-03-29 11:09:34 +0000616 k++;
617 }
618 if (k == 0) {
619 RETURN_ERROR1("Bad writemask character");
620 }
621 return GL_TRUE;
622 }
623 else {
Keith Whitwell7c26b612005-04-21 14:46:57 +0000624 dstReg->WriteMask = WRITEMASK_XYZW;
Michal Krol2861e732004-03-29 11:09:34 +0000625 return GL_TRUE;
626 }
627}
628
629
630static GLboolean
Brian Paul7e807512005-11-05 17:10:45 +0000631Parse_SwizzleSrcReg(struct parse_state *parseState, struct prog_src_register *srcReg)
Michal Krol2861e732004-03-29 11:09:34 +0000632{
633 GLubyte token[100];
Keith Whitwell7c26b612005-04-21 14:46:57 +0000634 GLint idx;
Michal Krol2861e732004-03-29 11:09:34 +0000635
636 srcReg->RelAddr = GL_FALSE;
637
638 /* check for '-' */
639 if (!Peek_Token(parseState, token))
640 RETURN_ERROR;
641 if (token[0] == '-') {
642 (void) Parse_String(parseState, "-");
Brian Paula8c42422006-05-30 22:17:35 +0000643 srcReg->NegateBase = NEGATE_XYZW;
Michal Krol2861e732004-03-29 11:09:34 +0000644 if (!Peek_Token(parseState, token))
645 RETURN_ERROR;
646 }
647 else {
Brian Paula8c42422006-05-30 22:17:35 +0000648 srcReg->NegateBase = NEGATE_NONE;
Michal Krol2861e732004-03-29 11:09:34 +0000649 }
650
651 /* Src reg can be R<n>, c[n], c[n +/- offset], or a named vertex attrib */
652 if (token[0] == 'R') {
653 srcReg->File = PROGRAM_TEMPORARY;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000654 if (!Parse_TempReg(parseState, &idx))
Michal Krol2861e732004-03-29 11:09:34 +0000655 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000656 srcReg->Index = idx;
Michal Krol2861e732004-03-29 11:09:34 +0000657 }
658 else if (token[0] == 'c') {
659 if (!Parse_ParamReg(parseState, srcReg))
660 RETURN_ERROR;
661 }
662 else if (token[0] == 'v') {
663 srcReg->File = PROGRAM_INPUT;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000664 if (!Parse_AttribReg(parseState, &idx))
Michal Krol2861e732004-03-29 11:09:34 +0000665 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000666 srcReg->Index = idx;
Michal Krol2861e732004-03-29 11:09:34 +0000667 }
668 else {
669 RETURN_ERROR2("Bad source register name", token);
670 }
671
672 /* init swizzle fields */
Keith Whitwell7c26b612005-04-21 14:46:57 +0000673 srcReg->Swizzle = SWIZZLE_NOOP;
Michal Krol2861e732004-03-29 11:09:34 +0000674
675 /* Look for optional swizzle suffix */
676 if (!Peek_Token(parseState, token))
677 RETURN_ERROR;
678 if (token[0] == '.') {
679 (void) Parse_String(parseState, "."); /* consume . */
680
681 if (!Parse_Token(parseState, token))
682 RETURN_ERROR;
683
684 if (token[1] == 0) {
685 /* single letter swizzle */
686 if (token[0] == 'x')
Brianfc6b8f22007-03-15 11:51:54 -0600687 srcReg->Swizzle = SWIZZLE_XXXX;
Michal Krol2861e732004-03-29 11:09:34 +0000688 else if (token[0] == 'y')
Brianfc6b8f22007-03-15 11:51:54 -0600689 srcReg->Swizzle = SWIZZLE_YYYY;
Michal Krol2861e732004-03-29 11:09:34 +0000690 else if (token[0] == 'z')
Brianfc6b8f22007-03-15 11:51:54 -0600691 srcReg->Swizzle = SWIZZLE_ZZZZ;
Michal Krol2861e732004-03-29 11:09:34 +0000692 else if (token[0] == 'w')
Brianfc6b8f22007-03-15 11:51:54 -0600693 srcReg->Swizzle = SWIZZLE_WWWW;
Michal Krol2861e732004-03-29 11:09:34 +0000694 else
695 RETURN_ERROR1("Expected x, y, z, or w");
696 }
697 else {
698 /* 2, 3 or 4-component swizzle */
699 GLint k;
Dave Airlieb5d76b62006-04-19 23:15:51 +0000700
701 srcReg->Swizzle = 0;
702
Michal Krol2861e732004-03-29 11:09:34 +0000703 for (k = 0; token[k] && k < 5; k++) {
704 if (token[k] == 'x')
Keith Whitwell7c26b612005-04-21 14:46:57 +0000705 srcReg->Swizzle |= 0 << (k*3);
Michal Krol2861e732004-03-29 11:09:34 +0000706 else if (token[k] == 'y')
Keith Whitwell7c26b612005-04-21 14:46:57 +0000707 srcReg->Swizzle |= 1 << (k*3);
Michal Krol2861e732004-03-29 11:09:34 +0000708 else if (token[k] == 'z')
Keith Whitwell7c26b612005-04-21 14:46:57 +0000709 srcReg->Swizzle |= 2 << (k*3);
Michal Krol2861e732004-03-29 11:09:34 +0000710 else if (token[k] == 'w')
Keith Whitwell7c26b612005-04-21 14:46:57 +0000711 srcReg->Swizzle |= 3 << (k*3);
Michal Krol2861e732004-03-29 11:09:34 +0000712 else
713 RETURN_ERROR;
714 }
715 if (k >= 5)
716 RETURN_ERROR;
717 }
718 }
719
720 return GL_TRUE;
721}
722
723
724static GLboolean
Brian Paul7e807512005-11-05 17:10:45 +0000725Parse_ScalarSrcReg(struct parse_state *parseState, struct prog_src_register *srcReg)
Michal Krol2861e732004-03-29 11:09:34 +0000726{
727 GLubyte token[100];
Keith Whitwell7c26b612005-04-21 14:46:57 +0000728 GLint idx;
Michal Krol2861e732004-03-29 11:09:34 +0000729
730 srcReg->RelAddr = GL_FALSE;
731
732 /* check for '-' */
733 if (!Peek_Token(parseState, token))
734 RETURN_ERROR;
735 if (token[0] == '-') {
Brian Paula8c42422006-05-30 22:17:35 +0000736 srcReg->NegateBase = NEGATE_XYZW;
Michal Krol2861e732004-03-29 11:09:34 +0000737 (void) Parse_String(parseState, "-"); /* consume '-' */
738 if (!Peek_Token(parseState, token))
739 RETURN_ERROR;
740 }
741 else {
Brian Paula8c42422006-05-30 22:17:35 +0000742 srcReg->NegateBase = NEGATE_NONE;
Michal Krol2861e732004-03-29 11:09:34 +0000743 }
744
745 /* Src reg can be R<n>, c[n], c[n +/- offset], or a named vertex attrib */
746 if (token[0] == 'R') {
747 srcReg->File = PROGRAM_TEMPORARY;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000748 if (!Parse_TempReg(parseState, &idx))
Michal Krol2861e732004-03-29 11:09:34 +0000749 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000750 srcReg->Index = idx;
Michal Krol2861e732004-03-29 11:09:34 +0000751 }
752 else if (token[0] == 'c') {
753 if (!Parse_ParamReg(parseState, srcReg))
754 RETURN_ERROR;
755 }
756 else if (token[0] == 'v') {
757 srcReg->File = PROGRAM_INPUT;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000758 if (!Parse_AttribReg(parseState, &idx))
Michal Krol2861e732004-03-29 11:09:34 +0000759 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000760 srcReg->Index = idx;
Michal Krol2861e732004-03-29 11:09:34 +0000761 }
762 else {
763 RETURN_ERROR2("Bad source register name", token);
764 }
765
766 /* Look for .[xyzw] suffix */
767 if (!Parse_String(parseState, "."))
768 RETURN_ERROR;
769
770 if (!Parse_Token(parseState, token))
771 RETURN_ERROR;
772
773 if (token[0] == 'x' && token[1] == 0) {
Keith Whitwell7c26b612005-04-21 14:46:57 +0000774 srcReg->Swizzle = 0;
Michal Krol2861e732004-03-29 11:09:34 +0000775 }
776 else if (token[0] == 'y' && token[1] == 0) {
Keith Whitwell7c26b612005-04-21 14:46:57 +0000777 srcReg->Swizzle = 1;
Michal Krol2861e732004-03-29 11:09:34 +0000778 }
779 else if (token[0] == 'z' && token[1] == 0) {
Keith Whitwell7c26b612005-04-21 14:46:57 +0000780 srcReg->Swizzle = 2;
Michal Krol2861e732004-03-29 11:09:34 +0000781 }
782 else if (token[0] == 'w' && token[1] == 0) {
Keith Whitwell7c26b612005-04-21 14:46:57 +0000783 srcReg->Swizzle = 3;
Michal Krol2861e732004-03-29 11:09:34 +0000784 }
785 else {
786 RETURN_ERROR1("Bad scalar source suffix");
787 }
Michal Krol2861e732004-03-29 11:09:34 +0000788
789 return GL_TRUE;
790}
791
792
793static GLint
794Parse_UnaryOpInstruction(struct parse_state *parseState,
Brian Paul7e807512005-11-05 17:10:45 +0000795 struct prog_instruction *inst,
796 enum prog_opcode opcode)
Michal Krol2861e732004-03-29 11:09:34 +0000797{
Brian Paul7e807512005-11-05 17:10:45 +0000798 if (opcode == OPCODE_ABS && !parseState->isVersion1_1)
Michal Krol2861e732004-03-29 11:09:34 +0000799 RETURN_ERROR1("ABS illegal for vertex program 1.0");
800
801 inst->Opcode = opcode;
Michal Krol2861e732004-03-29 11:09:34 +0000802
803 /* dest reg */
804 if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
805 RETURN_ERROR;
806
807 /* comma */
808 if (!Parse_String(parseState, ","))
809 RETURN_ERROR;
810
811 /* src arg */
812 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[0]))
813 RETURN_ERROR;
814
815 /* semicolon */
816 if (!Parse_String(parseState, ";"))
817 RETURN_ERROR;
818
819 return GL_TRUE;
820}
821
822
823static GLboolean
824Parse_BiOpInstruction(struct parse_state *parseState,
Brian Paul7e807512005-11-05 17:10:45 +0000825 struct prog_instruction *inst,
826 enum prog_opcode opcode)
Michal Krol2861e732004-03-29 11:09:34 +0000827{
Brian Paul7e807512005-11-05 17:10:45 +0000828 if (opcode == OPCODE_DPH && !parseState->isVersion1_1)
Michal Krol2861e732004-03-29 11:09:34 +0000829 RETURN_ERROR1("DPH illegal for vertex program 1.0");
Brian Paul7e807512005-11-05 17:10:45 +0000830 if (opcode == OPCODE_SUB && !parseState->isVersion1_1)
Michal Krol2861e732004-03-29 11:09:34 +0000831 RETURN_ERROR1("SUB illegal for vertex program 1.0");
832
833 inst->Opcode = opcode;
Michal Krol2861e732004-03-29 11:09:34 +0000834
835 /* dest reg */
836 if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
837 RETURN_ERROR;
838
839 /* comma */
840 if (!Parse_String(parseState, ","))
841 RETURN_ERROR;
842
843 /* first src arg */
844 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[0]))
845 RETURN_ERROR;
846
847 /* comma */
848 if (!Parse_String(parseState, ","))
849 RETURN_ERROR;
850
851 /* second src arg */
852 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[1]))
853 RETURN_ERROR;
854
855 /* semicolon */
856 if (!Parse_String(parseState, ";"))
857 RETURN_ERROR;
858
859 /* make sure we don't reference more than one program parameter register */
860 if (inst->SrcReg[0].File == PROGRAM_ENV_PARAM &&
861 inst->SrcReg[1].File == PROGRAM_ENV_PARAM &&
862 inst->SrcReg[0].Index != inst->SrcReg[1].Index)
863 RETURN_ERROR1("Can't reference two program parameter registers");
864
865 /* make sure we don't reference more than one vertex attribute register */
866 if (inst->SrcReg[0].File == PROGRAM_INPUT &&
867 inst->SrcReg[1].File == PROGRAM_INPUT &&
868 inst->SrcReg[0].Index != inst->SrcReg[1].Index)
869 RETURN_ERROR1("Can't reference two vertex attribute registers");
870
871 return GL_TRUE;
872}
873
874
875static GLboolean
876Parse_TriOpInstruction(struct parse_state *parseState,
Brian Paul7e807512005-11-05 17:10:45 +0000877 struct prog_instruction *inst,
878 enum prog_opcode opcode)
Michal Krol2861e732004-03-29 11:09:34 +0000879{
880 inst->Opcode = opcode;
Michal Krol2861e732004-03-29 11:09:34 +0000881
882 /* dest reg */
883 if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
884 RETURN_ERROR;
885
886 /* comma */
887 if (!Parse_String(parseState, ","))
888 RETURN_ERROR;
889
890 /* first src arg */
891 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[0]))
892 RETURN_ERROR;
893
894 /* comma */
895 if (!Parse_String(parseState, ","))
896 RETURN_ERROR;
897
898 /* second src arg */
899 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[1]))
900 RETURN_ERROR;
901
902 /* comma */
903 if (!Parse_String(parseState, ","))
904 RETURN_ERROR;
905
906 /* third src arg */
907 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[2]))
908 RETURN_ERROR;
909
910 /* semicolon */
911 if (!Parse_String(parseState, ";"))
912 RETURN_ERROR;
913
914 /* make sure we don't reference more than one program parameter register */
915 if ((inst->SrcReg[0].File == PROGRAM_ENV_PARAM &&
916 inst->SrcReg[1].File == PROGRAM_ENV_PARAM &&
917 inst->SrcReg[0].Index != inst->SrcReg[1].Index) ||
918 (inst->SrcReg[0].File == PROGRAM_ENV_PARAM &&
919 inst->SrcReg[2].File == PROGRAM_ENV_PARAM &&
920 inst->SrcReg[0].Index != inst->SrcReg[2].Index) ||
921 (inst->SrcReg[1].File == PROGRAM_ENV_PARAM &&
922 inst->SrcReg[2].File == PROGRAM_ENV_PARAM &&
923 inst->SrcReg[1].Index != inst->SrcReg[2].Index))
924 RETURN_ERROR1("Can only reference one program register");
925
926 /* make sure we don't reference more than one vertex attribute register */
927 if ((inst->SrcReg[0].File == PROGRAM_INPUT &&
928 inst->SrcReg[1].File == PROGRAM_INPUT &&
929 inst->SrcReg[0].Index != inst->SrcReg[1].Index) ||
930 (inst->SrcReg[0].File == PROGRAM_INPUT &&
931 inst->SrcReg[2].File == PROGRAM_INPUT &&
932 inst->SrcReg[0].Index != inst->SrcReg[2].Index) ||
933 (inst->SrcReg[1].File == PROGRAM_INPUT &&
934 inst->SrcReg[2].File == PROGRAM_INPUT &&
935 inst->SrcReg[1].Index != inst->SrcReg[2].Index))
936 RETURN_ERROR1("Can only reference one input register");
937
938 return GL_TRUE;
939}
940
941
942static GLboolean
943Parse_ScalarInstruction(struct parse_state *parseState,
Brian Paul7e807512005-11-05 17:10:45 +0000944 struct prog_instruction *inst,
945 enum prog_opcode opcode)
Michal Krol2861e732004-03-29 11:09:34 +0000946{
Brian Paul7e807512005-11-05 17:10:45 +0000947 if (opcode == OPCODE_RCC && !parseState->isVersion1_1)
Michal Krol2861e732004-03-29 11:09:34 +0000948 RETURN_ERROR1("RCC illegal for vertex program 1.0");
949
950 inst->Opcode = opcode;
Michal Krol2861e732004-03-29 11:09:34 +0000951
952 /* dest reg */
953 if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
954 RETURN_ERROR;
955
956 /* comma */
957 if (!Parse_String(parseState, ","))
958 RETURN_ERROR;
959
960 /* first src arg */
961 if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0]))
962 RETURN_ERROR;
963
964 /* semicolon */
965 if (!Parse_String(parseState, ";"))
966 RETURN_ERROR;
967
968 return GL_TRUE;
969}
970
971
972static GLboolean
Brian Paul7e807512005-11-05 17:10:45 +0000973Parse_AddressInstruction(struct parse_state *parseState, struct prog_instruction *inst)
Michal Krol2861e732004-03-29 11:09:34 +0000974{
Brian Paul7e807512005-11-05 17:10:45 +0000975 inst->Opcode = OPCODE_ARL;
Michal Krol2861e732004-03-29 11:09:34 +0000976
Aapo Tahkolaed4ab132006-03-24 16:35:08 +0000977 /* Make ARB_vp backends happy */
978 inst->DstReg.File = PROGRAM_ADDRESS;
979 inst->DstReg.WriteMask = WRITEMASK_X;
980 inst->DstReg.Index = 0;
981
Michal Krol2861e732004-03-29 11:09:34 +0000982 /* dest A0 reg */
983 if (!Parse_AddrReg(parseState))
984 RETURN_ERROR;
985
986 /* comma */
987 if (!Parse_String(parseState, ","))
988 RETURN_ERROR;
989
990 /* parse src reg */
991 if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0]))
992 RETURN_ERROR;
993
994 /* semicolon */
995 if (!Parse_String(parseState, ";"))
996 RETURN_ERROR;
997
998 return GL_TRUE;
999}
1000
1001
1002static GLboolean
Brian Paul7e807512005-11-05 17:10:45 +00001003Parse_EndInstruction(struct parse_state *parseState, struct prog_instruction *inst)
Michal Krol2861e732004-03-29 11:09:34 +00001004{
1005 GLubyte token[100];
1006
Brian Paul7e807512005-11-05 17:10:45 +00001007 inst->Opcode = OPCODE_END;
Michal Krol2861e732004-03-29 11:09:34 +00001008
1009 /* this should fail! */
1010 if (Parse_Token(parseState, token))
1011 RETURN_ERROR2("Unexpected token after END:", token);
1012 else
1013 return GL_TRUE;
1014}
1015
1016
Brian Paul575700f2004-12-16 03:07:18 +00001017/**
1018 * The PRINT instruction is Mesa-specific and is meant as a debugging aid for
1019 * the vertex program developer.
1020 * The NV_vertex_program extension grammar is modified as follows:
1021 *
1022 * <instruction> ::= <ARL-instruction>
1023 * | ...
1024 * | <PRINT-instruction>
1025 *
1026 * <PRINT-instruction> ::= "PRINT" <string literal>
1027 * | "PRINT" <string literal> "," <srcReg>
1028 * | "PRINT" <string literal> "," <dstReg>
1029 */
1030static GLboolean
Brian Paul7e807512005-11-05 17:10:45 +00001031Parse_PrintInstruction(struct parse_state *parseState, struct prog_instruction *inst)
Brian Paul575700f2004-12-16 03:07:18 +00001032{
1033 const GLubyte *str;
1034 GLubyte *msg;
1035 GLuint len;
1036 GLubyte token[100];
Brian Paul7e807512005-11-05 17:10:45 +00001037 struct prog_src_register *srcReg = &inst->SrcReg[0];
Keith Whitwell7c26b612005-04-21 14:46:57 +00001038 GLint idx;
Brian Paul575700f2004-12-16 03:07:18 +00001039
Brian Paul7e807512005-11-05 17:10:45 +00001040 inst->Opcode = OPCODE_PRINT;
Brian Paul575700f2004-12-16 03:07:18 +00001041
1042 /* The first argument is a literal string 'just like this' */
1043 if (!Parse_String(parseState, "'"))
1044 RETURN_ERROR;
1045
1046 str = parseState->pos;
1047 for (len = 0; str[len] != '\''; len++) /* find closing quote */
1048 ;
1049 parseState->pos += len + 1;
Brian Paul95801792005-12-06 15:41:43 +00001050 msg = (GLubyte*) _mesa_malloc(len + 1);
Brian Paul575700f2004-12-16 03:07:18 +00001051
1052 _mesa_memcpy(msg, str, len);
1053 msg[len] = 0;
1054 inst->Data = msg;
1055
1056 /* comma */
1057 if (Parse_String(parseState, ",")) {
1058
1059 /* The second argument is a register name */
1060 if (!Peek_Token(parseState, token))
1061 RETURN_ERROR;
1062
1063 srcReg->RelAddr = GL_FALSE;
Brian Paula8c42422006-05-30 22:17:35 +00001064 srcReg->NegateBase = NEGATE_NONE;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001065 srcReg->Swizzle = SWIZZLE_NOOP;
Brian Paul575700f2004-12-16 03:07:18 +00001066
1067 /* Register can be R<n>, c[n], c[n +/- offset], a named vertex attrib,
1068 * or an o[n] output register.
1069 */
1070 if (token[0] == 'R') {
1071 srcReg->File = PROGRAM_TEMPORARY;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001072 if (!Parse_TempReg(parseState, &idx))
Brian Paul575700f2004-12-16 03:07:18 +00001073 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001074 srcReg->Index = idx;
Brian Paul575700f2004-12-16 03:07:18 +00001075 }
1076 else if (token[0] == 'c') {
1077 srcReg->File = PROGRAM_ENV_PARAM;
1078 if (!Parse_ParamReg(parseState, srcReg))
1079 RETURN_ERROR;
1080 }
1081 else if (token[0] == 'v') {
1082 srcReg->File = PROGRAM_INPUT;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001083 if (!Parse_AttribReg(parseState, &idx))
Brian Paul575700f2004-12-16 03:07:18 +00001084 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001085 srcReg->Index = idx;
Brian Paul575700f2004-12-16 03:07:18 +00001086 }
1087 else if (token[0] == 'o') {
1088 srcReg->File = PROGRAM_OUTPUT;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001089 if (!Parse_OutputReg(parseState, &idx))
Brian Paul575700f2004-12-16 03:07:18 +00001090 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001091 srcReg->Index = idx;
Brian Paul575700f2004-12-16 03:07:18 +00001092 }
1093 else {
1094 RETURN_ERROR2("Bad source register name", token);
1095 }
1096 }
1097 else {
1098 srcReg->File = 0;
1099 }
1100
1101 /* semicolon */
1102 if (!Parse_String(parseState, ";"))
1103 RETURN_ERROR;
1104
1105 return GL_TRUE;
1106}
1107
1108
Michal Krol2861e732004-03-29 11:09:34 +00001109static GLboolean
1110Parse_OptionSequence(struct parse_state *parseState,
Brian Paul7e807512005-11-05 17:10:45 +00001111 struct prog_instruction program[])
Michal Krol2861e732004-03-29 11:09:34 +00001112{
Brian Paula6c423d2004-08-25 15:59:48 +00001113 (void) program;
Michal Krol2861e732004-03-29 11:09:34 +00001114 while (1) {
1115 if (!Parse_String(parseState, "OPTION"))
1116 return GL_TRUE; /* ok, not an OPTION statement */
1117 if (Parse_String(parseState, "NV_position_invariant")) {
1118 parseState->isPositionInvariant = GL_TRUE;
1119 }
1120 else {
1121 RETURN_ERROR1("unexpected OPTION statement");
1122 }
1123 if (!Parse_String(parseState, ";"))
1124 return GL_FALSE;
1125 }
1126}
1127
1128
1129static GLboolean
1130Parse_InstructionSequence(struct parse_state *parseState,
Brian Paul7e807512005-11-05 17:10:45 +00001131 struct prog_instruction program[])
Michal Krol2861e732004-03-29 11:09:34 +00001132{
1133 while (1) {
Brian Paul7e807512005-11-05 17:10:45 +00001134 struct prog_instruction *inst = program + parseState->numInst;
Michal Krol2861e732004-03-29 11:09:34 +00001135
1136 /* Initialize the instruction */
Brian Pauld6272e02006-10-29 18:03:16 +00001137 _mesa_init_instructions(inst, 1);
Michal Krol2861e732004-03-29 11:09:34 +00001138
1139 if (Parse_String(parseState, "MOV")) {
Brian Paul7e807512005-11-05 17:10:45 +00001140 if (!Parse_UnaryOpInstruction(parseState, inst, OPCODE_MOV))
Michal Krol2861e732004-03-29 11:09:34 +00001141 RETURN_ERROR;
1142 }
1143 else if (Parse_String(parseState, "LIT")) {
Brian Paul7e807512005-11-05 17:10:45 +00001144 if (!Parse_UnaryOpInstruction(parseState, inst, OPCODE_LIT))
Michal Krol2861e732004-03-29 11:09:34 +00001145 RETURN_ERROR;
1146 }
1147 else if (Parse_String(parseState, "ABS")) {
Brian Paul7e807512005-11-05 17:10:45 +00001148 if (!Parse_UnaryOpInstruction(parseState, inst, OPCODE_ABS))
Michal Krol2861e732004-03-29 11:09:34 +00001149 RETURN_ERROR;
1150 }
1151 else if (Parse_String(parseState, "MUL")) {
Brian Paul7e807512005-11-05 17:10:45 +00001152 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_MUL))
Michal Krol2861e732004-03-29 11:09:34 +00001153 RETURN_ERROR;
1154 }
1155 else if (Parse_String(parseState, "ADD")) {
Brian Paul7e807512005-11-05 17:10:45 +00001156 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_ADD))
Michal Krol2861e732004-03-29 11:09:34 +00001157 RETURN_ERROR;
1158 }
1159 else if (Parse_String(parseState, "DP3")) {
Brian Paul7e807512005-11-05 17:10:45 +00001160 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_DP3))
Michal Krol2861e732004-03-29 11:09:34 +00001161 RETURN_ERROR;
1162 }
1163 else if (Parse_String(parseState, "DP4")) {
Brian Paul7e807512005-11-05 17:10:45 +00001164 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_DP4))
Michal Krol2861e732004-03-29 11:09:34 +00001165 RETURN_ERROR;
1166 }
1167 else if (Parse_String(parseState, "DST")) {
Brian Paul7e807512005-11-05 17:10:45 +00001168 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_DST))
Michal Krol2861e732004-03-29 11:09:34 +00001169 RETURN_ERROR;
1170 }
1171 else if (Parse_String(parseState, "MIN")) {
Brian Paul7e807512005-11-05 17:10:45 +00001172 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_MIN))
Michal Krol2861e732004-03-29 11:09:34 +00001173 RETURN_ERROR;
1174 }
1175 else if (Parse_String(parseState, "MAX")) {
Brian Paul7e807512005-11-05 17:10:45 +00001176 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_MAX))
Michal Krol2861e732004-03-29 11:09:34 +00001177 RETURN_ERROR;
1178 }
1179 else if (Parse_String(parseState, "SLT")) {
Brian Paul7e807512005-11-05 17:10:45 +00001180 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_SLT))
Michal Krol2861e732004-03-29 11:09:34 +00001181 RETURN_ERROR;
1182 }
1183 else if (Parse_String(parseState, "SGE")) {
Brian Paul7e807512005-11-05 17:10:45 +00001184 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_SGE))
Michal Krol2861e732004-03-29 11:09:34 +00001185 RETURN_ERROR;
1186 }
1187 else if (Parse_String(parseState, "DPH")) {
Brian Paul7e807512005-11-05 17:10:45 +00001188 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_DPH))
Michal Krol2861e732004-03-29 11:09:34 +00001189 RETURN_ERROR;
1190 }
1191 else if (Parse_String(parseState, "SUB")) {
Brian Paul7e807512005-11-05 17:10:45 +00001192 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_SUB))
Michal Krol2861e732004-03-29 11:09:34 +00001193 RETURN_ERROR;
1194 }
1195 else if (Parse_String(parseState, "MAD")) {
Brian Paul7e807512005-11-05 17:10:45 +00001196 if (!Parse_TriOpInstruction(parseState, inst, OPCODE_MAD))
Michal Krol2861e732004-03-29 11:09:34 +00001197 RETURN_ERROR;
1198 }
1199 else if (Parse_String(parseState, "RCP")) {
Brian Paul7e807512005-11-05 17:10:45 +00001200 if (!Parse_ScalarInstruction(parseState, inst, OPCODE_RCP))
Michal Krol2861e732004-03-29 11:09:34 +00001201 RETURN_ERROR;
1202 }
1203 else if (Parse_String(parseState, "RSQ")) {
Brian Paul7e807512005-11-05 17:10:45 +00001204 if (!Parse_ScalarInstruction(parseState, inst, OPCODE_RSQ))
Michal Krol2861e732004-03-29 11:09:34 +00001205 RETURN_ERROR;
1206 }
1207 else if (Parse_String(parseState, "EXP")) {
Brian Paul7e807512005-11-05 17:10:45 +00001208 if (!Parse_ScalarInstruction(parseState, inst, OPCODE_EXP))
Michal Krol2861e732004-03-29 11:09:34 +00001209 RETURN_ERROR;
1210 }
1211 else if (Parse_String(parseState, "LOG")) {
Brian Paul7e807512005-11-05 17:10:45 +00001212 if (!Parse_ScalarInstruction(parseState, inst, OPCODE_LOG))
Michal Krol2861e732004-03-29 11:09:34 +00001213 RETURN_ERROR;
1214 }
1215 else if (Parse_String(parseState, "RCC")) {
Brian Paul7e807512005-11-05 17:10:45 +00001216 if (!Parse_ScalarInstruction(parseState, inst, OPCODE_RCC))
Michal Krol2861e732004-03-29 11:09:34 +00001217 RETURN_ERROR;
1218 }
1219 else if (Parse_String(parseState, "ARL")) {
1220 if (!Parse_AddressInstruction(parseState, inst))
1221 RETURN_ERROR;
1222 }
Brian Paul575700f2004-12-16 03:07:18 +00001223 else if (Parse_String(parseState, "PRINT")) {
1224 if (!Parse_PrintInstruction(parseState, inst))
1225 RETURN_ERROR;
1226 }
Michal Krol2861e732004-03-29 11:09:34 +00001227 else if (Parse_String(parseState, "END")) {
1228 if (!Parse_EndInstruction(parseState, inst))
1229 RETURN_ERROR;
1230 else {
1231 parseState->numInst++;
1232 return GL_TRUE; /* all done */
1233 }
1234 }
1235 else {
1236 /* bad instruction name */
1237 RETURN_ERROR1("Unexpected token");
1238 }
1239
1240 /* examine input/output registers */
1241 if (inst->DstReg.File == PROGRAM_OUTPUT)
1242 parseState->outputsWritten |= (1 << inst->DstReg.Index);
1243 else if (inst->DstReg.File == PROGRAM_ENV_PARAM)
1244 parseState->anyProgRegsWritten = GL_TRUE;
1245
1246 if (inst->SrcReg[0].File == PROGRAM_INPUT)
1247 parseState->inputsRead |= (1 << inst->SrcReg[0].Index);
1248 if (inst->SrcReg[1].File == PROGRAM_INPUT)
1249 parseState->inputsRead |= (1 << inst->SrcReg[1].Index);
1250 if (inst->SrcReg[2].File == PROGRAM_INPUT)
1251 parseState->inputsRead |= (1 << inst->SrcReg[2].Index);
1252
1253 parseState->numInst++;
1254
1255 if (parseState->numInst >= MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS)
1256 RETURN_ERROR1("Program too long");
1257 }
1258
1259 RETURN_ERROR;
1260}
1261
1262
1263static GLboolean
1264Parse_Program(struct parse_state *parseState,
Brian Paul7e807512005-11-05 17:10:45 +00001265 struct prog_instruction instBuffer[])
Michal Krol2861e732004-03-29 11:09:34 +00001266{
1267 if (parseState->isVersion1_1) {
1268 if (!Parse_OptionSequence(parseState, instBuffer)) {
1269 return GL_FALSE;
1270 }
1271 }
1272 return Parse_InstructionSequence(parseState, instBuffer);
1273}
1274
1275
1276/**
1277 * Parse/compile the 'str' returning the compiled 'program'.
1278 * ctx->Program.ErrorPos will be -1 if successful. Otherwise, ErrorPos
1279 * indicates the position of the error in 'str'.
1280 */
1281void
1282_mesa_parse_nv_vertex_program(GLcontext *ctx, GLenum dstTarget,
1283 const GLubyte *str, GLsizei len,
Brian Paul122629f2006-07-20 16:49:57 +00001284 struct gl_vertex_program *program)
Michal Krol2861e732004-03-29 11:09:34 +00001285{
1286 struct parse_state parseState;
Brian Paul7e807512005-11-05 17:10:45 +00001287 struct prog_instruction instBuffer[MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS];
1288 struct prog_instruction *newInst;
Michal Krol2861e732004-03-29 11:09:34 +00001289 GLenum target;
1290 GLubyte *programString;
1291
1292 /* Make a null-terminated copy of the program string */
1293 programString = (GLubyte *) MALLOC(len + 1);
1294 if (!programString) {
1295 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
1296 return;
1297 }
1298 MEMCPY(programString, str, len);
1299 programString[len] = 0;
1300
1301 /* Get ready to parse */
1302 parseState.ctx = ctx;
1303 parseState.start = programString;
1304 parseState.isPositionInvariant = GL_FALSE;
1305 parseState.isVersion1_1 = GL_FALSE;
1306 parseState.numInst = 0;
1307 parseState.inputsRead = 0;
1308 parseState.outputsWritten = 0;
1309 parseState.anyProgRegsWritten = GL_FALSE;
1310
1311 /* Reset error state */
1312 _mesa_set_program_error(ctx, -1, NULL);
1313
1314 /* check the program header */
1315 if (_mesa_strncmp((const char *) programString, "!!VP1.0", 7) == 0) {
1316 target = GL_VERTEX_PROGRAM_NV;
1317 parseState.pos = programString + 7;
1318 parseState.isStateProgram = GL_FALSE;
1319 }
1320 else if (_mesa_strncmp((const char *) programString, "!!VP1.1", 7) == 0) {
1321 target = GL_VERTEX_PROGRAM_NV;
1322 parseState.pos = programString + 7;
1323 parseState.isStateProgram = GL_FALSE;
1324 parseState.isVersion1_1 = GL_TRUE;
1325 }
1326 else if (_mesa_strncmp((const char *) programString, "!!VSP1.0", 8) == 0) {
1327 target = GL_VERTEX_STATE_PROGRAM_NV;
1328 parseState.pos = programString + 8;
1329 parseState.isStateProgram = GL_TRUE;
1330 }
1331 else {
1332 /* invalid header */
1333 ctx->Program.ErrorPos = 0;
1334 _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(bad header)");
1335 return;
1336 }
1337
1338 /* make sure target and header match */
1339 if (target != dstTarget) {
1340 _mesa_error(ctx, GL_INVALID_OPERATION,
1341 "glLoadProgramNV(target mismatch)");
1342 return;
1343 }
1344
1345
1346 if (Parse_Program(&parseState, instBuffer)) {
1347 /* successful parse! */
1348
1349 if (parseState.isStateProgram) {
1350 if (!parseState.anyProgRegsWritten) {
1351 _mesa_error(ctx, GL_INVALID_OPERATION,
1352 "glLoadProgramNV(c[#] not written)");
1353 return;
1354 }
1355 }
1356 else {
1357 if (!parseState.isPositionInvariant &&
Brian Paulf6de8652006-08-30 23:36:52 +00001358 !(parseState.outputsWritten & (1 << VERT_RESULT_HPOS))) {
Michal Krol2861e732004-03-29 11:09:34 +00001359 /* bit 1 = HPOS register */
1360 _mesa_error(ctx, GL_INVALID_OPERATION,
1361 "glLoadProgramNV(HPOS not written)");
1362 return;
1363 }
1364 }
1365
1366 /* copy the compiled instructions */
1367 assert(parseState.numInst <= MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS);
Brian Paul383c39e2006-08-25 15:14:25 +00001368 newInst = _mesa_alloc_instructions(parseState.numInst);
Michal Krol2861e732004-03-29 11:09:34 +00001369 if (!newInst) {
1370 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
Brian Paulde997602005-11-12 17:53:14 +00001371 _mesa_free(programString);
Michal Krol2861e732004-03-29 11:09:34 +00001372 return; /* out of memory */
1373 }
Brian12229f12007-03-22 09:11:26 -06001374 _mesa_copy_instructions(newInst, instBuffer, parseState.numInst);
Michal Krol2861e732004-03-29 11:09:34 +00001375
1376 /* install the program */
1377 program->Base.Target = target;
1378 if (program->Base.String) {
Brian Paulde997602005-11-12 17:53:14 +00001379 _mesa_free(program->Base.String);
Michal Krol2861e732004-03-29 11:09:34 +00001380 }
1381 program->Base.String = programString;
1382 program->Base.Format = GL_PROGRAM_FORMAT_ASCII_ARB;
Brian Paulde997602005-11-12 17:53:14 +00001383 if (program->Base.Instructions) {
1384 _mesa_free(program->Base.Instructions);
Michal Krol2861e732004-03-29 11:09:34 +00001385 }
Brian Paulde997602005-11-12 17:53:14 +00001386 program->Base.Instructions = newInst;
1387 program->Base.InputsRead = parseState.inputsRead;
Brian Paulfe694702006-10-10 21:23:23 +00001388 if (parseState.isPositionInvariant)
1389 program->Base.InputsRead |= VERT_BIT_POS;
Brian Paulee40c4fb32006-02-15 15:59:37 +00001390 program->Base.NumInstructions = parseState.numInst;
Brian Paulde997602005-11-12 17:53:14 +00001391 program->Base.OutputsWritten = parseState.outputsWritten;
Michal Krol2861e732004-03-29 11:09:34 +00001392 program->IsPositionInvariant = parseState.isPositionInvariant;
Brian Paul05a6f2f2004-04-21 18:09:14 +00001393 program->IsNVProgram = GL_TRUE;
Michal Krol2861e732004-03-29 11:09:34 +00001394
Brian Paul2a5afe32004-12-18 16:18:00 +00001395#ifdef DEBUG_foo
Michal Krol2861e732004-03-29 11:09:34 +00001396 _mesa_printf("--- glLoadProgramNV result ---\n");
1397 _mesa_print_nv_vertex_program(program);
1398 _mesa_printf("------------------------------\n");
1399#endif
1400 }
1401 else {
1402 /* Error! */
1403 _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV");
1404 /* NOTE: _mesa_set_program_error would have been called already */
1405 /* GL_NV_vertex_program isn't supposed to set the error string
1406 * so we reset it here.
1407 */
1408 _mesa_set_program_error(ctx, ctx->Program.ErrorPos, NULL);
1409 }
1410}
1411
1412
1413static void
Brian Paul7e807512005-11-05 17:10:45 +00001414PrintSrcReg(const struct prog_src_register *src)
Michal Krol2861e732004-03-29 11:09:34 +00001415{
1416 static const char comps[5] = "xyzw";
Brian Paul7e807512005-11-05 17:10:45 +00001417 if (src->NegateBase)
Michal Krol2861e732004-03-29 11:09:34 +00001418 _mesa_printf("-");
1419 if (src->RelAddr) {
1420 if (src->Index > 0)
1421 _mesa_printf("c[A0.x + %d]", src->Index);
1422 else if (src->Index < 0)
1423 _mesa_printf("c[A0.x - %d]", -src->Index);
1424 else
1425 _mesa_printf("c[A0.x]");
1426 }
1427 else if (src->File == PROGRAM_OUTPUT) {
1428 _mesa_printf("o[%s]", OutputRegisters[src->Index]);
1429 }
1430 else if (src->File == PROGRAM_INPUT) {
1431 _mesa_printf("v[%s]", InputRegisters[src->Index]);
1432 }
1433 else if (src->File == PROGRAM_ENV_PARAM) {
1434 _mesa_printf("c[%d]", src->Index);
1435 }
1436 else {
1437 ASSERT(src->File == PROGRAM_TEMPORARY);
1438 _mesa_printf("R%d", src->Index);
1439 }
1440
Keith Whitwell7c26b612005-04-21 14:46:57 +00001441 if (GET_SWZ(src->Swizzle, 0) == GET_SWZ(src->Swizzle, 1) &&
1442 GET_SWZ(src->Swizzle, 0) == GET_SWZ(src->Swizzle, 2) &&
1443 GET_SWZ(src->Swizzle, 0) == GET_SWZ(src->Swizzle, 3)) {
1444 _mesa_printf(".%c", comps[GET_SWZ(src->Swizzle, 0)]);
Michal Krol2861e732004-03-29 11:09:34 +00001445 }
Keith Whitwell7c26b612005-04-21 14:46:57 +00001446 else if (src->Swizzle != SWIZZLE_NOOP) {
Michal Krol2861e732004-03-29 11:09:34 +00001447 _mesa_printf(".%c%c%c%c",
Keith Whitwell7c26b612005-04-21 14:46:57 +00001448 comps[GET_SWZ(src->Swizzle, 0)],
1449 comps[GET_SWZ(src->Swizzle, 1)],
1450 comps[GET_SWZ(src->Swizzle, 2)],
1451 comps[GET_SWZ(src->Swizzle, 3)]);
Michal Krol2861e732004-03-29 11:09:34 +00001452 }
1453}
1454
1455
1456static void
Brian Paul7e807512005-11-05 17:10:45 +00001457PrintDstReg(const struct prog_dst_register *dst)
Michal Krol2861e732004-03-29 11:09:34 +00001458{
Michal Krol2861e732004-03-29 11:09:34 +00001459 if (dst->File == PROGRAM_OUTPUT) {
1460 _mesa_printf("o[%s]", OutputRegisters[dst->Index]);
1461 }
1462 else if (dst->File == PROGRAM_INPUT) {
1463 _mesa_printf("v[%s]", InputRegisters[dst->Index]);
1464 }
1465 else if (dst->File == PROGRAM_ENV_PARAM) {
1466 _mesa_printf("c[%d]", dst->Index);
1467 }
1468 else {
1469 ASSERT(dst->File == PROGRAM_TEMPORARY);
1470 _mesa_printf("R%d", dst->Index);
1471 }
1472
Brian Paulccfe3d42005-11-03 02:35:15 +00001473 if (dst->WriteMask != 0 && dst->WriteMask != WRITEMASK_XYZW) {
Michal Krol2861e732004-03-29 11:09:34 +00001474 _mesa_printf(".");
Brian Paulccfe3d42005-11-03 02:35:15 +00001475 if (dst->WriteMask & WRITEMASK_X)
Michal Krol2861e732004-03-29 11:09:34 +00001476 _mesa_printf("x");
Brian Paulccfe3d42005-11-03 02:35:15 +00001477 if (dst->WriteMask & WRITEMASK_Y)
Michal Krol2861e732004-03-29 11:09:34 +00001478 _mesa_printf("y");
Brian Paulccfe3d42005-11-03 02:35:15 +00001479 if (dst->WriteMask & WRITEMASK_Z)
Michal Krol2861e732004-03-29 11:09:34 +00001480 _mesa_printf("z");
Brian Paulccfe3d42005-11-03 02:35:15 +00001481 if (dst->WriteMask & WRITEMASK_W)
Michal Krol2861e732004-03-29 11:09:34 +00001482 _mesa_printf("w");
1483 }
1484}
1485
1486
1487/**
1488 * Print a single NVIDIA vertex program instruction.
1489 */
1490void
Brian Paul7e807512005-11-05 17:10:45 +00001491_mesa_print_nv_vertex_instruction(const struct prog_instruction *inst)
Michal Krol2861e732004-03-29 11:09:34 +00001492{
Brian Paulb7c87972005-11-05 19:24:08 +00001493 GLuint i, n;
1494
Michal Krol2861e732004-03-29 11:09:34 +00001495 switch (inst->Opcode) {
Brian Paul7e807512005-11-05 17:10:45 +00001496 case OPCODE_MOV:
1497 case OPCODE_LIT:
1498 case OPCODE_RCP:
1499 case OPCODE_RSQ:
1500 case OPCODE_EXP:
1501 case OPCODE_LOG:
1502 case OPCODE_RCC:
1503 case OPCODE_ABS:
Brian Paul7e807512005-11-05 17:10:45 +00001504 case OPCODE_MUL:
1505 case OPCODE_ADD:
1506 case OPCODE_DP3:
1507 case OPCODE_DP4:
1508 case OPCODE_DST:
1509 case OPCODE_MIN:
1510 case OPCODE_MAX:
1511 case OPCODE_SLT:
1512 case OPCODE_SGE:
1513 case OPCODE_DPH:
1514 case OPCODE_SUB:
Brian Paul7e807512005-11-05 17:10:45 +00001515 case OPCODE_MAD:
Brian Paulb7c87972005-11-05 19:24:08 +00001516 _mesa_printf("%s ", _mesa_opcode_string(inst->Opcode));
Michal Krol2861e732004-03-29 11:09:34 +00001517 PrintDstReg(&inst->DstReg);
1518 _mesa_printf(", ");
Brian Paulb7c87972005-11-05 19:24:08 +00001519 n = _mesa_num_inst_src_regs(inst->Opcode);
1520 for (i = 0; i < n; i++) {
1521 PrintSrcReg(&inst->SrcReg[i]);
1522 if (i + 1 < n)
1523 _mesa_printf(", ");
1524 }
Michal Krol2861e732004-03-29 11:09:34 +00001525 _mesa_printf(";\n");
1526 break;
Brian Paul7e807512005-11-05 17:10:45 +00001527 case OPCODE_ARL:
Michal Krol2861e732004-03-29 11:09:34 +00001528 _mesa_printf("ARL A0.x, ");
1529 PrintSrcReg(&inst->SrcReg[0]);
1530 _mesa_printf(";\n");
1531 break;
Brian Paul7e807512005-11-05 17:10:45 +00001532 case OPCODE_PRINT:
Brian Paul575700f2004-12-16 03:07:18 +00001533 _mesa_printf("PRINT '%s'", inst->Data);
Brian Paulde997602005-11-12 17:53:14 +00001534 if (inst->SrcReg[0].File != PROGRAM_UNDEFINED) {
Brian Paul575700f2004-12-16 03:07:18 +00001535 _mesa_printf(", ");
1536 PrintSrcReg(&inst->SrcReg[0]);
1537 _mesa_printf(";\n");
1538 }
1539 else {
1540 _mesa_printf("\n");
1541 }
1542 break;
Brian Paul7e807512005-11-05 17:10:45 +00001543 case OPCODE_END:
Michal Krol2861e732004-03-29 11:09:34 +00001544 _mesa_printf("END\n");
1545 break;
1546 default:
1547 _mesa_printf("BAD INSTRUCTION\n");
1548 }
1549}
1550
1551
1552/**
1553 * Print (unparse) the given vertex program. Just for debugging.
1554 */
1555void
Brian Paul122629f2006-07-20 16:49:57 +00001556_mesa_print_nv_vertex_program(const struct gl_vertex_program *program)
Michal Krol2861e732004-03-29 11:09:34 +00001557{
Brian Paul7e807512005-11-05 17:10:45 +00001558 const struct prog_instruction *inst;
Michal Krol2861e732004-03-29 11:09:34 +00001559
Brian Paulde997602005-11-12 17:53:14 +00001560 for (inst = program->Base.Instructions; ; inst++) {
Michal Krol2861e732004-03-29 11:09:34 +00001561 _mesa_print_nv_vertex_instruction(inst);
Brian Paul7e807512005-11-05 17:10:45 +00001562 if (inst->Opcode == OPCODE_END)
Michal Krol2861e732004-03-29 11:09:34 +00001563 return;
1564 }
1565}
1566
1567
1568const char *
1569_mesa_nv_vertex_input_register_name(GLuint i)
1570{
1571 ASSERT(i < MAX_NV_VERTEX_PROGRAM_INPUTS);
1572 return InputRegisters[i];
1573}
1574
1575
1576const char *
1577_mesa_nv_vertex_output_register_name(GLuint i)
1578{
1579 ASSERT(i < MAX_NV_VERTEX_PROGRAM_OUTPUTS);
1580 return OutputRegisters[i];
1581}
Brian Paul7aebaf32005-10-30 21:23:23 +00001582