blob: ecfe8ec334fbaaa25487cc5df3f2b1840966ff51 [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
40#include "glheader.h"
41#include "context.h"
42#include "hash.h"
43#include "imports.h"
44#include "macros.h"
45#include "mtypes.h"
46#include "nvprogram.h"
47#include "nvvertparse.h"
Brian Paul7e807512005-11-05 17:10:45 +000048#include "program_instruction.h"
Michal Krol2861e732004-03-29 11:09:34 +000049#include "program.h"
50
51
52/**
53 * Current parsing state. This structure is passed among the parsing
54 * functions and keeps track of the current parser position and various
55 * program attributes.
56 */
57struct parse_state {
58 GLcontext *ctx;
59 const GLubyte *start;
60 const GLubyte *pos;
61 const GLubyte *curLine;
62 GLboolean isStateProgram;
63 GLboolean isPositionInvariant;
64 GLboolean isVersion1_1;
Brian Paul97a65932006-10-10 21:25:27 +000065 GLbitfield inputsRead;
66 GLbitfield outputsWritten;
Michal Krol2861e732004-03-29 11:09:34 +000067 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
Michal Krol2861e732004-03-29 11:09:34 +0000296
297
298/**
299 * Parse a temporary register: Rnn
300 */
301static GLboolean
302Parse_TempReg(struct parse_state *parseState, GLint *tempRegNum)
303{
304 GLubyte token[100];
305
306 /* Should be 'R##' */
307 if (!Parse_Token(parseState, token))
308 RETURN_ERROR;
309 if (token[0] != 'R')
310 RETURN_ERROR1("Expected R##");
311
312 if (IsDigit(token[1])) {
313 GLint reg = _mesa_atoi((char *) (token + 1));
314 if (reg >= MAX_NV_VERTEX_PROGRAM_TEMPS)
315 RETURN_ERROR1("Bad temporary register name");
316 *tempRegNum = reg;
317 }
318 else {
319 RETURN_ERROR1("Bad temporary register name");
320 }
321
322 return GL_TRUE;
323}
324
325
326/**
327 * Parse address register "A0.x"
328 */
329static GLboolean
330Parse_AddrReg(struct parse_state *parseState)
331{
332 /* match 'A0' */
333 if (!Parse_String(parseState, "A0"))
334 RETURN_ERROR;
335
336 /* match '.' */
337 if (!Parse_String(parseState, "."))
338 RETURN_ERROR;
339
340 /* match 'x' */
341 if (!Parse_String(parseState, "x"))
342 RETURN_ERROR;
343
344 return GL_TRUE;
345}
346
347
348/**
349 * Parse absolute program parameter register "c[##]"
350 */
351static GLboolean
352Parse_AbsParamReg(struct parse_state *parseState, GLint *regNum)
353{
354 GLubyte token[100];
355
356 if (!Parse_String(parseState, "c"))
357 RETURN_ERROR;
358
359 if (!Parse_String(parseState, "["))
360 RETURN_ERROR;
361
362 if (!Parse_Token(parseState, token))
363 RETURN_ERROR;
364
365 if (IsDigit(token[0])) {
366 /* a numbered program parameter register */
367 GLint reg = _mesa_atoi((char *) token);
368 if (reg >= MAX_NV_VERTEX_PROGRAM_PARAMS)
369 RETURN_ERROR1("Bad program parameter number");
370 *regNum = reg;
371 }
372 else {
373 RETURN_ERROR;
374 }
375
376 if (!Parse_String(parseState, "]"))
377 RETURN_ERROR;
378
379 return GL_TRUE;
380}
381
382
383static GLboolean
Brian Paul7e807512005-11-05 17:10:45 +0000384Parse_ParamReg(struct parse_state *parseState, struct prog_src_register *srcReg)
Michal Krol2861e732004-03-29 11:09:34 +0000385{
386 GLubyte token[100];
387
388 if (!Parse_String(parseState, "c"))
389 RETURN_ERROR;
390
391 if (!Parse_String(parseState, "["))
392 RETURN_ERROR;
393
394 if (!Peek_Token(parseState, token))
395 RETURN_ERROR;
396
397 if (IsDigit(token[0])) {
398 /* a numbered program parameter register */
399 GLint reg;
400 (void) Parse_Token(parseState, token);
401 reg = _mesa_atoi((char *) token);
402 if (reg >= MAX_NV_VERTEX_PROGRAM_PARAMS)
403 RETURN_ERROR1("Bad program parameter number");
404 srcReg->File = PROGRAM_ENV_PARAM;
405 srcReg->Index = reg;
406 }
407 else if (_mesa_strcmp((const char *) token, "A0") == 0) {
408 /* address register "A0.x" */
409 if (!Parse_AddrReg(parseState))
410 RETURN_ERROR;
411
412 srcReg->RelAddr = GL_TRUE;
413 srcReg->File = PROGRAM_ENV_PARAM;
414 /* Look for +/-N offset */
415 if (!Peek_Token(parseState, token))
416 RETURN_ERROR;
417
418 if (token[0] == '-' || token[0] == '+') {
419 const GLubyte sign = token[0];
420 (void) Parse_Token(parseState, token); /* consume +/- */
421
422 /* an integer should be next */
423 if (!Parse_Token(parseState, token))
424 RETURN_ERROR;
425
426 if (IsDigit(token[0])) {
427 const GLint k = _mesa_atoi((char *) token);
428 if (sign == '-') {
429 if (k > 64)
430 RETURN_ERROR1("Bad address offset");
431 srcReg->Index = -k;
432 }
433 else {
434 if (k > 63)
435 RETURN_ERROR1("Bad address offset");
436 srcReg->Index = k;
437 }
438 }
439 else {
440 RETURN_ERROR;
441 }
442 }
443 else {
444 /* probably got a ']', catch it below */
445 }
446 }
447 else {
448 RETURN_ERROR;
449 }
450
451 /* Match closing ']' */
452 if (!Parse_String(parseState, "]"))
453 RETURN_ERROR;
454
455 return GL_TRUE;
456}
457
458
459/**
460 * Parse v[#] or v[<name>]
461 */
462static GLboolean
463Parse_AttribReg(struct parse_state *parseState, GLint *tempRegNum)
464{
465 GLubyte token[100];
466 GLint j;
467
468 /* Match 'v' */
469 if (!Parse_String(parseState, "v"))
470 RETURN_ERROR;
471
472 /* Match '[' */
473 if (!Parse_String(parseState, "["))
474 RETURN_ERROR;
475
476 /* match number or named register */
477 if (!Parse_Token(parseState, token))
478 RETURN_ERROR;
479
480 if (parseState->isStateProgram && token[0] != '0')
481 RETURN_ERROR1("Only v[0] accessible in vertex state programs");
482
483 if (IsDigit(token[0])) {
484 GLint reg = _mesa_atoi((char *) token);
485 if (reg >= MAX_NV_VERTEX_PROGRAM_INPUTS)
486 RETURN_ERROR1("Bad vertex attribute register name");
487 *tempRegNum = reg;
488 }
489 else {
490 for (j = 0; InputRegisters[j]; j++) {
491 if (_mesa_strcmp((const char *) token, InputRegisters[j]) == 0) {
492 *tempRegNum = j;
493 break;
494 }
495 }
496 if (!InputRegisters[j]) {
497 /* unknown input register label */
498 RETURN_ERROR2("Bad register name", token);
499 }
500 }
501
502 /* Match '[' */
503 if (!Parse_String(parseState, "]"))
504 RETURN_ERROR;
505
506 return GL_TRUE;
507}
508
509
510static GLboolean
511Parse_OutputReg(struct parse_state *parseState, GLint *outputRegNum)
512{
513 GLubyte token[100];
514 GLint start, j;
515
516 /* Match 'o' */
517 if (!Parse_String(parseState, "o"))
518 RETURN_ERROR;
519
520 /* Match '[' */
521 if (!Parse_String(parseState, "["))
522 RETURN_ERROR;
523
524 /* Get output reg name */
525 if (!Parse_Token(parseState, token))
526 RETURN_ERROR;
527
528 if (parseState->isPositionInvariant)
529 start = 1; /* skip HPOS register name */
530 else
531 start = 0;
532
533 /* try to match an output register name */
534 for (j = start; OutputRegisters[j]; j++) {
535 if (_mesa_strcmp((const char *) token, OutputRegisters[j]) == 0) {
536 *outputRegNum = j;
537 break;
538 }
539 }
540 if (!OutputRegisters[j])
541 RETURN_ERROR1("Unrecognized output register name");
542
543 /* Match ']' */
544 if (!Parse_String(parseState, "]"))
545 RETURN_ERROR1("Expected ]");
546
547 return GL_TRUE;
548}
549
550
551static GLboolean
Brian Paul7e807512005-11-05 17:10:45 +0000552Parse_MaskedDstReg(struct parse_state *parseState, struct prog_dst_register *dstReg)
Michal Krol2861e732004-03-29 11:09:34 +0000553{
554 GLubyte token[100];
Keith Whitwell7c26b612005-04-21 14:46:57 +0000555 GLint idx;
Michal Krol2861e732004-03-29 11:09:34 +0000556
557 /* Dst reg can be R<n> or o[n] */
558 if (!Peek_Token(parseState, token))
559 RETURN_ERROR;
560
561 if (token[0] == 'R') {
562 /* a temporary register */
563 dstReg->File = PROGRAM_TEMPORARY;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000564 if (!Parse_TempReg(parseState, &idx))
Michal Krol2861e732004-03-29 11:09:34 +0000565 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000566 dstReg->Index = idx;
Michal Krol2861e732004-03-29 11:09:34 +0000567 }
568 else if (!parseState->isStateProgram && token[0] == 'o') {
569 /* an output register */
570 dstReg->File = PROGRAM_OUTPUT;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000571 if (!Parse_OutputReg(parseState, &idx))
Michal Krol2861e732004-03-29 11:09:34 +0000572 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000573 dstReg->Index = idx;
Michal Krol2861e732004-03-29 11:09:34 +0000574 }
575 else if (parseState->isStateProgram && token[0] == 'c' &&
576 parseState->isStateProgram) {
577 /* absolute program parameter register */
578 /* Only valid for vertex state programs */
579 dstReg->File = PROGRAM_ENV_PARAM;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000580 if (!Parse_AbsParamReg(parseState, &idx))
Michal Krol2861e732004-03-29 11:09:34 +0000581 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000582 dstReg->Index = idx;
Michal Krol2861e732004-03-29 11:09:34 +0000583 }
584 else {
585 RETURN_ERROR1("Bad destination register name");
586 }
587
588 /* Parse optional write mask */
589 if (!Peek_Token(parseState, token))
590 RETURN_ERROR;
591
592 if (token[0] == '.') {
593 /* got a mask */
594 GLint k = 0;
595
596 if (!Parse_String(parseState, "."))
597 RETURN_ERROR;
598
599 if (!Parse_Token(parseState, token))
600 RETURN_ERROR;
601
Keith Whitwell7c26b612005-04-21 14:46:57 +0000602 dstReg->WriteMask = 0;
Michal Krol2861e732004-03-29 11:09:34 +0000603
604 if (token[k] == 'x') {
Keith Whitwell7c26b612005-04-21 14:46:57 +0000605 dstReg->WriteMask |= WRITEMASK_X;
Michal Krol2861e732004-03-29 11:09:34 +0000606 k++;
607 }
608 if (token[k] == 'y') {
Keith Whitwell7c26b612005-04-21 14:46:57 +0000609 dstReg->WriteMask |= WRITEMASK_Y;
Michal Krol2861e732004-03-29 11:09:34 +0000610 k++;
611 }
612 if (token[k] == 'z') {
Keith Whitwell7c26b612005-04-21 14:46:57 +0000613 dstReg->WriteMask |= WRITEMASK_Z;
Michal Krol2861e732004-03-29 11:09:34 +0000614 k++;
615 }
616 if (token[k] == 'w') {
Keith Whitwell7c26b612005-04-21 14:46:57 +0000617 dstReg->WriteMask |= WRITEMASK_W;
Michal Krol2861e732004-03-29 11:09:34 +0000618 k++;
619 }
620 if (k == 0) {
621 RETURN_ERROR1("Bad writemask character");
622 }
623 return GL_TRUE;
624 }
625 else {
Keith Whitwell7c26b612005-04-21 14:46:57 +0000626 dstReg->WriteMask = WRITEMASK_XYZW;
Michal Krol2861e732004-03-29 11:09:34 +0000627 return GL_TRUE;
628 }
629}
630
631
632static GLboolean
Brian Paul7e807512005-11-05 17:10:45 +0000633Parse_SwizzleSrcReg(struct parse_state *parseState, struct prog_src_register *srcReg)
Michal Krol2861e732004-03-29 11:09:34 +0000634{
635 GLubyte token[100];
Keith Whitwell7c26b612005-04-21 14:46:57 +0000636 GLint idx;
Michal Krol2861e732004-03-29 11:09:34 +0000637
638 srcReg->RelAddr = GL_FALSE;
639
640 /* check for '-' */
641 if (!Peek_Token(parseState, token))
642 RETURN_ERROR;
643 if (token[0] == '-') {
644 (void) Parse_String(parseState, "-");
Brian Paula8c42422006-05-30 22:17:35 +0000645 srcReg->NegateBase = NEGATE_XYZW;
Michal Krol2861e732004-03-29 11:09:34 +0000646 if (!Peek_Token(parseState, token))
647 RETURN_ERROR;
648 }
649 else {
Brian Paula8c42422006-05-30 22:17:35 +0000650 srcReg->NegateBase = NEGATE_NONE;
Michal Krol2861e732004-03-29 11:09:34 +0000651 }
652
653 /* Src reg can be R<n>, c[n], c[n +/- offset], or a named vertex attrib */
654 if (token[0] == 'R') {
655 srcReg->File = PROGRAM_TEMPORARY;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000656 if (!Parse_TempReg(parseState, &idx))
Michal Krol2861e732004-03-29 11:09:34 +0000657 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000658 srcReg->Index = idx;
Michal Krol2861e732004-03-29 11:09:34 +0000659 }
660 else if (token[0] == 'c') {
661 if (!Parse_ParamReg(parseState, srcReg))
662 RETURN_ERROR;
663 }
664 else if (token[0] == 'v') {
665 srcReg->File = PROGRAM_INPUT;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000666 if (!Parse_AttribReg(parseState, &idx))
Michal Krol2861e732004-03-29 11:09:34 +0000667 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000668 srcReg->Index = idx;
Michal Krol2861e732004-03-29 11:09:34 +0000669 }
670 else {
671 RETURN_ERROR2("Bad source register name", token);
672 }
673
674 /* init swizzle fields */
Keith Whitwell7c26b612005-04-21 14:46:57 +0000675 srcReg->Swizzle = SWIZZLE_NOOP;
Michal Krol2861e732004-03-29 11:09:34 +0000676
677 /* Look for optional swizzle suffix */
678 if (!Peek_Token(parseState, token))
679 RETURN_ERROR;
680 if (token[0] == '.') {
681 (void) Parse_String(parseState, "."); /* consume . */
682
683 if (!Parse_Token(parseState, token))
684 RETURN_ERROR;
685
686 if (token[1] == 0) {
687 /* single letter swizzle */
688 if (token[0] == 'x')
Keith Whitwell7c26b612005-04-21 14:46:57 +0000689 srcReg->Swizzle = MAKE_SWIZZLE4(0, 0, 0, 0);
Michal Krol2861e732004-03-29 11:09:34 +0000690 else if (token[0] == 'y')
Keith Whitwell7c26b612005-04-21 14:46:57 +0000691 srcReg->Swizzle = MAKE_SWIZZLE4(1, 1, 1, 1);
Michal Krol2861e732004-03-29 11:09:34 +0000692 else if (token[0] == 'z')
Keith Whitwell7c26b612005-04-21 14:46:57 +0000693 srcReg->Swizzle = MAKE_SWIZZLE4(2, 2, 2, 2);
Michal Krol2861e732004-03-29 11:09:34 +0000694 else if (token[0] == 'w')
Keith Whitwell7c26b612005-04-21 14:46:57 +0000695 srcReg->Swizzle = MAKE_SWIZZLE4(3, 3, 3, 3);
Michal Krol2861e732004-03-29 11:09:34 +0000696 else
697 RETURN_ERROR1("Expected x, y, z, or w");
698 }
699 else {
700 /* 2, 3 or 4-component swizzle */
701 GLint k;
Dave Airlieb5d76b62006-04-19 23:15:51 +0000702
703 srcReg->Swizzle = 0;
704
Michal Krol2861e732004-03-29 11:09:34 +0000705 for (k = 0; token[k] && k < 5; k++) {
706 if (token[k] == 'x')
Keith Whitwell7c26b612005-04-21 14:46:57 +0000707 srcReg->Swizzle |= 0 << (k*3);
Michal Krol2861e732004-03-29 11:09:34 +0000708 else if (token[k] == 'y')
Keith Whitwell7c26b612005-04-21 14:46:57 +0000709 srcReg->Swizzle |= 1 << (k*3);
Michal Krol2861e732004-03-29 11:09:34 +0000710 else if (token[k] == 'z')
Keith Whitwell7c26b612005-04-21 14:46:57 +0000711 srcReg->Swizzle |= 2 << (k*3);
Michal Krol2861e732004-03-29 11:09:34 +0000712 else if (token[k] == 'w')
Keith Whitwell7c26b612005-04-21 14:46:57 +0000713 srcReg->Swizzle |= 3 << (k*3);
Michal Krol2861e732004-03-29 11:09:34 +0000714 else
715 RETURN_ERROR;
716 }
717 if (k >= 5)
718 RETURN_ERROR;
719 }
720 }
721
722 return GL_TRUE;
723}
724
725
726static GLboolean
Brian Paul7e807512005-11-05 17:10:45 +0000727Parse_ScalarSrcReg(struct parse_state *parseState, struct prog_src_register *srcReg)
Michal Krol2861e732004-03-29 11:09:34 +0000728{
729 GLubyte token[100];
Keith Whitwell7c26b612005-04-21 14:46:57 +0000730 GLint idx;
Michal Krol2861e732004-03-29 11:09:34 +0000731
732 srcReg->RelAddr = GL_FALSE;
733
734 /* check for '-' */
735 if (!Peek_Token(parseState, token))
736 RETURN_ERROR;
737 if (token[0] == '-') {
Brian Paula8c42422006-05-30 22:17:35 +0000738 srcReg->NegateBase = NEGATE_XYZW;
Michal Krol2861e732004-03-29 11:09:34 +0000739 (void) Parse_String(parseState, "-"); /* consume '-' */
740 if (!Peek_Token(parseState, token))
741 RETURN_ERROR;
742 }
743 else {
Brian Paula8c42422006-05-30 22:17:35 +0000744 srcReg->NegateBase = NEGATE_NONE;
Michal Krol2861e732004-03-29 11:09:34 +0000745 }
746
747 /* Src reg can be R<n>, c[n], c[n +/- offset], or a named vertex attrib */
748 if (token[0] == 'R') {
749 srcReg->File = PROGRAM_TEMPORARY;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000750 if (!Parse_TempReg(parseState, &idx))
Michal Krol2861e732004-03-29 11:09:34 +0000751 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000752 srcReg->Index = idx;
Michal Krol2861e732004-03-29 11:09:34 +0000753 }
754 else if (token[0] == 'c') {
755 if (!Parse_ParamReg(parseState, srcReg))
756 RETURN_ERROR;
757 }
758 else if (token[0] == 'v') {
759 srcReg->File = PROGRAM_INPUT;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000760 if (!Parse_AttribReg(parseState, &idx))
Michal Krol2861e732004-03-29 11:09:34 +0000761 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000762 srcReg->Index = idx;
Michal Krol2861e732004-03-29 11:09:34 +0000763 }
764 else {
765 RETURN_ERROR2("Bad source register name", token);
766 }
767
768 /* Look for .[xyzw] suffix */
769 if (!Parse_String(parseState, "."))
770 RETURN_ERROR;
771
772 if (!Parse_Token(parseState, token))
773 RETURN_ERROR;
774
775 if (token[0] == 'x' && token[1] == 0) {
Keith Whitwell7c26b612005-04-21 14:46:57 +0000776 srcReg->Swizzle = 0;
Michal Krol2861e732004-03-29 11:09:34 +0000777 }
778 else if (token[0] == 'y' && token[1] == 0) {
Keith Whitwell7c26b612005-04-21 14:46:57 +0000779 srcReg->Swizzle = 1;
Michal Krol2861e732004-03-29 11:09:34 +0000780 }
781 else if (token[0] == 'z' && token[1] == 0) {
Keith Whitwell7c26b612005-04-21 14:46:57 +0000782 srcReg->Swizzle = 2;
Michal Krol2861e732004-03-29 11:09:34 +0000783 }
784 else if (token[0] == 'w' && token[1] == 0) {
Keith Whitwell7c26b612005-04-21 14:46:57 +0000785 srcReg->Swizzle = 3;
Michal Krol2861e732004-03-29 11:09:34 +0000786 }
787 else {
788 RETURN_ERROR1("Bad scalar source suffix");
789 }
Michal Krol2861e732004-03-29 11:09:34 +0000790
791 return GL_TRUE;
792}
793
794
795static GLint
796Parse_UnaryOpInstruction(struct parse_state *parseState,
Brian Paul7e807512005-11-05 17:10:45 +0000797 struct prog_instruction *inst,
798 enum prog_opcode opcode)
Michal Krol2861e732004-03-29 11:09:34 +0000799{
Brian Paul7e807512005-11-05 17:10:45 +0000800 if (opcode == OPCODE_ABS && !parseState->isVersion1_1)
Michal Krol2861e732004-03-29 11:09:34 +0000801 RETURN_ERROR1("ABS illegal for vertex program 1.0");
802
803 inst->Opcode = opcode;
804 inst->StringPos = parseState->curLine - parseState->start;
805
806 /* dest reg */
807 if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
808 RETURN_ERROR;
809
810 /* comma */
811 if (!Parse_String(parseState, ","))
812 RETURN_ERROR;
813
814 /* src arg */
815 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[0]))
816 RETURN_ERROR;
817
818 /* semicolon */
819 if (!Parse_String(parseState, ";"))
820 RETURN_ERROR;
821
822 return GL_TRUE;
823}
824
825
826static GLboolean
827Parse_BiOpInstruction(struct parse_state *parseState,
Brian Paul7e807512005-11-05 17:10:45 +0000828 struct prog_instruction *inst,
829 enum prog_opcode opcode)
Michal Krol2861e732004-03-29 11:09:34 +0000830{
Brian Paul7e807512005-11-05 17:10:45 +0000831 if (opcode == OPCODE_DPH && !parseState->isVersion1_1)
Michal Krol2861e732004-03-29 11:09:34 +0000832 RETURN_ERROR1("DPH illegal for vertex program 1.0");
Brian Paul7e807512005-11-05 17:10:45 +0000833 if (opcode == OPCODE_SUB && !parseState->isVersion1_1)
Michal Krol2861e732004-03-29 11:09:34 +0000834 RETURN_ERROR1("SUB illegal for vertex program 1.0");
835
836 inst->Opcode = opcode;
837 inst->StringPos = parseState->curLine - parseState->start;
838
839 /* dest reg */
840 if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
841 RETURN_ERROR;
842
843 /* comma */
844 if (!Parse_String(parseState, ","))
845 RETURN_ERROR;
846
847 /* first src arg */
848 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[0]))
849 RETURN_ERROR;
850
851 /* comma */
852 if (!Parse_String(parseState, ","))
853 RETURN_ERROR;
854
855 /* second src arg */
856 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[1]))
857 RETURN_ERROR;
858
859 /* semicolon */
860 if (!Parse_String(parseState, ";"))
861 RETURN_ERROR;
862
863 /* make sure we don't reference more than one program parameter register */
864 if (inst->SrcReg[0].File == PROGRAM_ENV_PARAM &&
865 inst->SrcReg[1].File == PROGRAM_ENV_PARAM &&
866 inst->SrcReg[0].Index != inst->SrcReg[1].Index)
867 RETURN_ERROR1("Can't reference two program parameter registers");
868
869 /* make sure we don't reference more than one vertex attribute register */
870 if (inst->SrcReg[0].File == PROGRAM_INPUT &&
871 inst->SrcReg[1].File == PROGRAM_INPUT &&
872 inst->SrcReg[0].Index != inst->SrcReg[1].Index)
873 RETURN_ERROR1("Can't reference two vertex attribute registers");
874
875 return GL_TRUE;
876}
877
878
879static GLboolean
880Parse_TriOpInstruction(struct parse_state *parseState,
Brian Paul7e807512005-11-05 17:10:45 +0000881 struct prog_instruction *inst,
882 enum prog_opcode opcode)
Michal Krol2861e732004-03-29 11:09:34 +0000883{
884 inst->Opcode = opcode;
885 inst->StringPos = parseState->curLine - parseState->start;
886
887 /* dest reg */
888 if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
889 RETURN_ERROR;
890
891 /* comma */
892 if (!Parse_String(parseState, ","))
893 RETURN_ERROR;
894
895 /* first src arg */
896 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[0]))
897 RETURN_ERROR;
898
899 /* comma */
900 if (!Parse_String(parseState, ","))
901 RETURN_ERROR;
902
903 /* second src arg */
904 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[1]))
905 RETURN_ERROR;
906
907 /* comma */
908 if (!Parse_String(parseState, ","))
909 RETURN_ERROR;
910
911 /* third src arg */
912 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[2]))
913 RETURN_ERROR;
914
915 /* semicolon */
916 if (!Parse_String(parseState, ";"))
917 RETURN_ERROR;
918
919 /* make sure we don't reference more than one program parameter register */
920 if ((inst->SrcReg[0].File == PROGRAM_ENV_PARAM &&
921 inst->SrcReg[1].File == PROGRAM_ENV_PARAM &&
922 inst->SrcReg[0].Index != inst->SrcReg[1].Index) ||
923 (inst->SrcReg[0].File == PROGRAM_ENV_PARAM &&
924 inst->SrcReg[2].File == PROGRAM_ENV_PARAM &&
925 inst->SrcReg[0].Index != inst->SrcReg[2].Index) ||
926 (inst->SrcReg[1].File == PROGRAM_ENV_PARAM &&
927 inst->SrcReg[2].File == PROGRAM_ENV_PARAM &&
928 inst->SrcReg[1].Index != inst->SrcReg[2].Index))
929 RETURN_ERROR1("Can only reference one program register");
930
931 /* make sure we don't reference more than one vertex attribute register */
932 if ((inst->SrcReg[0].File == PROGRAM_INPUT &&
933 inst->SrcReg[1].File == PROGRAM_INPUT &&
934 inst->SrcReg[0].Index != inst->SrcReg[1].Index) ||
935 (inst->SrcReg[0].File == PROGRAM_INPUT &&
936 inst->SrcReg[2].File == PROGRAM_INPUT &&
937 inst->SrcReg[0].Index != inst->SrcReg[2].Index) ||
938 (inst->SrcReg[1].File == PROGRAM_INPUT &&
939 inst->SrcReg[2].File == PROGRAM_INPUT &&
940 inst->SrcReg[1].Index != inst->SrcReg[2].Index))
941 RETURN_ERROR1("Can only reference one input register");
942
943 return GL_TRUE;
944}
945
946
947static GLboolean
948Parse_ScalarInstruction(struct parse_state *parseState,
Brian Paul7e807512005-11-05 17:10:45 +0000949 struct prog_instruction *inst,
950 enum prog_opcode opcode)
Michal Krol2861e732004-03-29 11:09:34 +0000951{
Brian Paul7e807512005-11-05 17:10:45 +0000952 if (opcode == OPCODE_RCC && !parseState->isVersion1_1)
Michal Krol2861e732004-03-29 11:09:34 +0000953 RETURN_ERROR1("RCC illegal for vertex program 1.0");
954
955 inst->Opcode = opcode;
956 inst->StringPos = parseState->curLine - parseState->start;
957
958 /* dest reg */
959 if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
960 RETURN_ERROR;
961
962 /* comma */
963 if (!Parse_String(parseState, ","))
964 RETURN_ERROR;
965
966 /* first src arg */
967 if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0]))
968 RETURN_ERROR;
969
970 /* semicolon */
971 if (!Parse_String(parseState, ";"))
972 RETURN_ERROR;
973
974 return GL_TRUE;
975}
976
977
978static GLboolean
Brian Paul7e807512005-11-05 17:10:45 +0000979Parse_AddressInstruction(struct parse_state *parseState, struct prog_instruction *inst)
Michal Krol2861e732004-03-29 11:09:34 +0000980{
Brian Paul7e807512005-11-05 17:10:45 +0000981 inst->Opcode = OPCODE_ARL;
Michal Krol2861e732004-03-29 11:09:34 +0000982 inst->StringPos = parseState->curLine - parseState->start;
983
Aapo Tahkolaed4ab132006-03-24 16:35:08 +0000984 /* Make ARB_vp backends happy */
985 inst->DstReg.File = PROGRAM_ADDRESS;
986 inst->DstReg.WriteMask = WRITEMASK_X;
987 inst->DstReg.Index = 0;
988
Michal Krol2861e732004-03-29 11:09:34 +0000989 /* 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
Brian Paul7e807512005-11-05 17:10:45 +00001010Parse_EndInstruction(struct parse_state *parseState, struct prog_instruction *inst)
Michal Krol2861e732004-03-29 11:09:34 +00001011{
1012 GLubyte token[100];
1013
Brian Paul7e807512005-11-05 17:10:45 +00001014 inst->Opcode = OPCODE_END;
Michal Krol2861e732004-03-29 11:09:34 +00001015 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
Brian Paul7e807512005-11-05 17:10:45 +00001039Parse_PrintInstruction(struct parse_state *parseState, struct prog_instruction *inst)
Brian Paul575700f2004-12-16 03:07:18 +00001040{
1041 const GLubyte *str;
1042 GLubyte *msg;
1043 GLuint len;
1044 GLubyte token[100];
Brian Paul7e807512005-11-05 17:10:45 +00001045 struct prog_src_register *srcReg = &inst->SrcReg[0];
Keith Whitwell7c26b612005-04-21 14:46:57 +00001046 GLint idx;
Brian Paul575700f2004-12-16 03:07:18 +00001047
Brian Paul7e807512005-11-05 17:10:45 +00001048 inst->Opcode = OPCODE_PRINT;
Brian Paul575700f2004-12-16 03:07:18 +00001049 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;
Brian Paul95801792005-12-06 15:41:43 +00001059 msg = (GLubyte*) _mesa_malloc(len + 1);
Brian Paul575700f2004-12-16 03:07:18 +00001060
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;
Brian Paula8c42422006-05-30 22:17:35 +00001073 srcReg->NegateBase = NEGATE_NONE;
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,
Brian Paul7e807512005-11-05 17:10:45 +00001120 struct prog_instruction program[])
Michal Krol2861e732004-03-29 11:09:34 +00001121{
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,
Brian Paul7e807512005-11-05 17:10:45 +00001140 struct prog_instruction program[])
Michal Krol2861e732004-03-29 11:09:34 +00001141{
1142 while (1) {
Brian Paul7e807512005-11-05 17:10:45 +00001143 struct prog_instruction *inst = program + parseState->numInst;
Michal Krol2861e732004-03-29 11:09:34 +00001144
1145 /* Initialize the instruction */
Brian Pauld6272e02006-10-29 18:03:16 +00001146 _mesa_init_instructions(inst, 1);
Michal Krol2861e732004-03-29 11:09:34 +00001147
1148 if (Parse_String(parseState, "MOV")) {
Brian Paul7e807512005-11-05 17:10:45 +00001149 if (!Parse_UnaryOpInstruction(parseState, inst, OPCODE_MOV))
Michal Krol2861e732004-03-29 11:09:34 +00001150 RETURN_ERROR;
1151 }
1152 else if (Parse_String(parseState, "LIT")) {
Brian Paul7e807512005-11-05 17:10:45 +00001153 if (!Parse_UnaryOpInstruction(parseState, inst, OPCODE_LIT))
Michal Krol2861e732004-03-29 11:09:34 +00001154 RETURN_ERROR;
1155 }
1156 else if (Parse_String(parseState, "ABS")) {
Brian Paul7e807512005-11-05 17:10:45 +00001157 if (!Parse_UnaryOpInstruction(parseState, inst, OPCODE_ABS))
Michal Krol2861e732004-03-29 11:09:34 +00001158 RETURN_ERROR;
1159 }
1160 else if (Parse_String(parseState, "MUL")) {
Brian Paul7e807512005-11-05 17:10:45 +00001161 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_MUL))
Michal Krol2861e732004-03-29 11:09:34 +00001162 RETURN_ERROR;
1163 }
1164 else if (Parse_String(parseState, "ADD")) {
Brian Paul7e807512005-11-05 17:10:45 +00001165 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_ADD))
Michal Krol2861e732004-03-29 11:09:34 +00001166 RETURN_ERROR;
1167 }
1168 else if (Parse_String(parseState, "DP3")) {
Brian Paul7e807512005-11-05 17:10:45 +00001169 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_DP3))
Michal Krol2861e732004-03-29 11:09:34 +00001170 RETURN_ERROR;
1171 }
1172 else if (Parse_String(parseState, "DP4")) {
Brian Paul7e807512005-11-05 17:10:45 +00001173 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_DP4))
Michal Krol2861e732004-03-29 11:09:34 +00001174 RETURN_ERROR;
1175 }
1176 else if (Parse_String(parseState, "DST")) {
Brian Paul7e807512005-11-05 17:10:45 +00001177 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_DST))
Michal Krol2861e732004-03-29 11:09:34 +00001178 RETURN_ERROR;
1179 }
1180 else if (Parse_String(parseState, "MIN")) {
Brian Paul7e807512005-11-05 17:10:45 +00001181 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_MIN))
Michal Krol2861e732004-03-29 11:09:34 +00001182 RETURN_ERROR;
1183 }
1184 else if (Parse_String(parseState, "MAX")) {
Brian Paul7e807512005-11-05 17:10:45 +00001185 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_MAX))
Michal Krol2861e732004-03-29 11:09:34 +00001186 RETURN_ERROR;
1187 }
1188 else if (Parse_String(parseState, "SLT")) {
Brian Paul7e807512005-11-05 17:10:45 +00001189 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_SLT))
Michal Krol2861e732004-03-29 11:09:34 +00001190 RETURN_ERROR;
1191 }
1192 else if (Parse_String(parseState, "SGE")) {
Brian Paul7e807512005-11-05 17:10:45 +00001193 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_SGE))
Michal Krol2861e732004-03-29 11:09:34 +00001194 RETURN_ERROR;
1195 }
1196 else if (Parse_String(parseState, "DPH")) {
Brian Paul7e807512005-11-05 17:10:45 +00001197 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_DPH))
Michal Krol2861e732004-03-29 11:09:34 +00001198 RETURN_ERROR;
1199 }
1200 else if (Parse_String(parseState, "SUB")) {
Brian Paul7e807512005-11-05 17:10:45 +00001201 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_SUB))
Michal Krol2861e732004-03-29 11:09:34 +00001202 RETURN_ERROR;
1203 }
1204 else if (Parse_String(parseState, "MAD")) {
Brian Paul7e807512005-11-05 17:10:45 +00001205 if (!Parse_TriOpInstruction(parseState, inst, OPCODE_MAD))
Michal Krol2861e732004-03-29 11:09:34 +00001206 RETURN_ERROR;
1207 }
1208 else if (Parse_String(parseState, "RCP")) {
Brian Paul7e807512005-11-05 17:10:45 +00001209 if (!Parse_ScalarInstruction(parseState, inst, OPCODE_RCP))
Michal Krol2861e732004-03-29 11:09:34 +00001210 RETURN_ERROR;
1211 }
1212 else if (Parse_String(parseState, "RSQ")) {
Brian Paul7e807512005-11-05 17:10:45 +00001213 if (!Parse_ScalarInstruction(parseState, inst, OPCODE_RSQ))
Michal Krol2861e732004-03-29 11:09:34 +00001214 RETURN_ERROR;
1215 }
1216 else if (Parse_String(parseState, "EXP")) {
Brian Paul7e807512005-11-05 17:10:45 +00001217 if (!Parse_ScalarInstruction(parseState, inst, OPCODE_EXP))
Michal Krol2861e732004-03-29 11:09:34 +00001218 RETURN_ERROR;
1219 }
1220 else if (Parse_String(parseState, "LOG")) {
Brian Paul7e807512005-11-05 17:10:45 +00001221 if (!Parse_ScalarInstruction(parseState, inst, OPCODE_LOG))
Michal Krol2861e732004-03-29 11:09:34 +00001222 RETURN_ERROR;
1223 }
1224 else if (Parse_String(parseState, "RCC")) {
Brian Paul7e807512005-11-05 17:10:45 +00001225 if (!Parse_ScalarInstruction(parseState, inst, OPCODE_RCC))
Michal Krol2861e732004-03-29 11:09:34 +00001226 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,
Brian Paul7e807512005-11-05 17:10:45 +00001274 struct prog_instruction instBuffer[])
Michal Krol2861e732004-03-29 11:09:34 +00001275{
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,
Brian Paul122629f2006-07-20 16:49:57 +00001293 struct gl_vertex_program *program)
Michal Krol2861e732004-03-29 11:09:34 +00001294{
1295 struct parse_state parseState;
Brian Paul7e807512005-11-05 17:10:45 +00001296 struct prog_instruction instBuffer[MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS];
1297 struct prog_instruction *newInst;
Michal Krol2861e732004-03-29 11:09:34 +00001298 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 &&
Brian Paulf6de8652006-08-30 23:36:52 +00001367 !(parseState.outputsWritten & (1 << VERT_RESULT_HPOS))) {
Michal Krol2861e732004-03-29 11:09:34 +00001368 /* 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);
Brian Paul383c39e2006-08-25 15:14:25 +00001377 newInst = _mesa_alloc_instructions(parseState.numInst);
Michal Krol2861e732004-03-29 11:09:34 +00001378 if (!newInst) {
1379 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
Brian Paulde997602005-11-12 17:53:14 +00001380 _mesa_free(programString);
Michal Krol2861e732004-03-29 11:09:34 +00001381 return; /* out of memory */
1382 }
Brian Paulde997602005-11-12 17:53:14 +00001383 _mesa_memcpy(newInst, instBuffer,
1384 parseState.numInst * sizeof(struct prog_instruction));
Michal Krol2861e732004-03-29 11:09:34 +00001385
1386 /* install the program */
1387 program->Base.Target = target;
1388 if (program->Base.String) {
Brian Paulde997602005-11-12 17:53:14 +00001389 _mesa_free(program->Base.String);
Michal Krol2861e732004-03-29 11:09:34 +00001390 }
1391 program->Base.String = programString;
1392 program->Base.Format = GL_PROGRAM_FORMAT_ASCII_ARB;
Brian Paulde997602005-11-12 17:53:14 +00001393 if (program->Base.Instructions) {
1394 _mesa_free(program->Base.Instructions);
Michal Krol2861e732004-03-29 11:09:34 +00001395 }
Brian Paulde997602005-11-12 17:53:14 +00001396 program->Base.Instructions = newInst;
1397 program->Base.InputsRead = parseState.inputsRead;
Brian Paulfe694702006-10-10 21:23:23 +00001398 if (parseState.isPositionInvariant)
1399 program->Base.InputsRead |= VERT_BIT_POS;
Brian Paulee40c4fb32006-02-15 15:59:37 +00001400 program->Base.NumInstructions = parseState.numInst;
Brian Paulde997602005-11-12 17:53:14 +00001401 program->Base.OutputsWritten = parseState.outputsWritten;
Michal Krol2861e732004-03-29 11:09:34 +00001402 program->IsPositionInvariant = parseState.isPositionInvariant;
Brian Paul05a6f2f2004-04-21 18:09:14 +00001403 program->IsNVProgram = GL_TRUE;
Michal Krol2861e732004-03-29 11:09:34 +00001404
Brian Paul2a5afe32004-12-18 16:18:00 +00001405#ifdef DEBUG_foo
Michal Krol2861e732004-03-29 11:09:34 +00001406 _mesa_printf("--- glLoadProgramNV result ---\n");
1407 _mesa_print_nv_vertex_program(program);
1408 _mesa_printf("------------------------------\n");
1409#endif
1410 }
1411 else {
1412 /* Error! */
1413 _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV");
1414 /* NOTE: _mesa_set_program_error would have been called already */
1415 /* GL_NV_vertex_program isn't supposed to set the error string
1416 * so we reset it here.
1417 */
1418 _mesa_set_program_error(ctx, ctx->Program.ErrorPos, NULL);
1419 }
1420}
1421
1422
1423static void
Brian Paul7e807512005-11-05 17:10:45 +00001424PrintSrcReg(const struct prog_src_register *src)
Michal Krol2861e732004-03-29 11:09:34 +00001425{
1426 static const char comps[5] = "xyzw";
Brian Paul7e807512005-11-05 17:10:45 +00001427 if (src->NegateBase)
Michal Krol2861e732004-03-29 11:09:34 +00001428 _mesa_printf("-");
1429 if (src->RelAddr) {
1430 if (src->Index > 0)
1431 _mesa_printf("c[A0.x + %d]", src->Index);
1432 else if (src->Index < 0)
1433 _mesa_printf("c[A0.x - %d]", -src->Index);
1434 else
1435 _mesa_printf("c[A0.x]");
1436 }
1437 else if (src->File == PROGRAM_OUTPUT) {
1438 _mesa_printf("o[%s]", OutputRegisters[src->Index]);
1439 }
1440 else if (src->File == PROGRAM_INPUT) {
1441 _mesa_printf("v[%s]", InputRegisters[src->Index]);
1442 }
1443 else if (src->File == PROGRAM_ENV_PARAM) {
1444 _mesa_printf("c[%d]", src->Index);
1445 }
1446 else {
1447 ASSERT(src->File == PROGRAM_TEMPORARY);
1448 _mesa_printf("R%d", src->Index);
1449 }
1450
Keith Whitwell7c26b612005-04-21 14:46:57 +00001451 if (GET_SWZ(src->Swizzle, 0) == GET_SWZ(src->Swizzle, 1) &&
1452 GET_SWZ(src->Swizzle, 0) == GET_SWZ(src->Swizzle, 2) &&
1453 GET_SWZ(src->Swizzle, 0) == GET_SWZ(src->Swizzle, 3)) {
1454 _mesa_printf(".%c", comps[GET_SWZ(src->Swizzle, 0)]);
Michal Krol2861e732004-03-29 11:09:34 +00001455 }
Keith Whitwell7c26b612005-04-21 14:46:57 +00001456 else if (src->Swizzle != SWIZZLE_NOOP) {
Michal Krol2861e732004-03-29 11:09:34 +00001457 _mesa_printf(".%c%c%c%c",
Keith Whitwell7c26b612005-04-21 14:46:57 +00001458 comps[GET_SWZ(src->Swizzle, 0)],
1459 comps[GET_SWZ(src->Swizzle, 1)],
1460 comps[GET_SWZ(src->Swizzle, 2)],
1461 comps[GET_SWZ(src->Swizzle, 3)]);
Michal Krol2861e732004-03-29 11:09:34 +00001462 }
1463}
1464
1465
1466static void
Brian Paul7e807512005-11-05 17:10:45 +00001467PrintDstReg(const struct prog_dst_register *dst)
Michal Krol2861e732004-03-29 11:09:34 +00001468{
Michal Krol2861e732004-03-29 11:09:34 +00001469 if (dst->File == PROGRAM_OUTPUT) {
1470 _mesa_printf("o[%s]", OutputRegisters[dst->Index]);
1471 }
1472 else if (dst->File == PROGRAM_INPUT) {
1473 _mesa_printf("v[%s]", InputRegisters[dst->Index]);
1474 }
1475 else if (dst->File == PROGRAM_ENV_PARAM) {
1476 _mesa_printf("c[%d]", dst->Index);
1477 }
1478 else {
1479 ASSERT(dst->File == PROGRAM_TEMPORARY);
1480 _mesa_printf("R%d", dst->Index);
1481 }
1482
Brian Paulccfe3d42005-11-03 02:35:15 +00001483 if (dst->WriteMask != 0 && dst->WriteMask != WRITEMASK_XYZW) {
Michal Krol2861e732004-03-29 11:09:34 +00001484 _mesa_printf(".");
Brian Paulccfe3d42005-11-03 02:35:15 +00001485 if (dst->WriteMask & WRITEMASK_X)
Michal Krol2861e732004-03-29 11:09:34 +00001486 _mesa_printf("x");
Brian Paulccfe3d42005-11-03 02:35:15 +00001487 if (dst->WriteMask & WRITEMASK_Y)
Michal Krol2861e732004-03-29 11:09:34 +00001488 _mesa_printf("y");
Brian Paulccfe3d42005-11-03 02:35:15 +00001489 if (dst->WriteMask & WRITEMASK_Z)
Michal Krol2861e732004-03-29 11:09:34 +00001490 _mesa_printf("z");
Brian Paulccfe3d42005-11-03 02:35:15 +00001491 if (dst->WriteMask & WRITEMASK_W)
Michal Krol2861e732004-03-29 11:09:34 +00001492 _mesa_printf("w");
1493 }
1494}
1495
1496
1497/**
1498 * Print a single NVIDIA vertex program instruction.
1499 */
1500void
Brian Paul7e807512005-11-05 17:10:45 +00001501_mesa_print_nv_vertex_instruction(const struct prog_instruction *inst)
Michal Krol2861e732004-03-29 11:09:34 +00001502{
Brian Paulb7c87972005-11-05 19:24:08 +00001503 GLuint i, n;
1504
Michal Krol2861e732004-03-29 11:09:34 +00001505 switch (inst->Opcode) {
Brian Paul7e807512005-11-05 17:10:45 +00001506 case OPCODE_MOV:
1507 case OPCODE_LIT:
1508 case OPCODE_RCP:
1509 case OPCODE_RSQ:
1510 case OPCODE_EXP:
1511 case OPCODE_LOG:
1512 case OPCODE_RCC:
1513 case OPCODE_ABS:
Brian Paul7e807512005-11-05 17:10:45 +00001514 case OPCODE_MUL:
1515 case OPCODE_ADD:
1516 case OPCODE_DP3:
1517 case OPCODE_DP4:
1518 case OPCODE_DST:
1519 case OPCODE_MIN:
1520 case OPCODE_MAX:
1521 case OPCODE_SLT:
1522 case OPCODE_SGE:
1523 case OPCODE_DPH:
1524 case OPCODE_SUB:
Brian Paul7e807512005-11-05 17:10:45 +00001525 case OPCODE_MAD:
Brian Paulb7c87972005-11-05 19:24:08 +00001526 _mesa_printf("%s ", _mesa_opcode_string(inst->Opcode));
Michal Krol2861e732004-03-29 11:09:34 +00001527 PrintDstReg(&inst->DstReg);
1528 _mesa_printf(", ");
Brian Paulb7c87972005-11-05 19:24:08 +00001529 n = _mesa_num_inst_src_regs(inst->Opcode);
1530 for (i = 0; i < n; i++) {
1531 PrintSrcReg(&inst->SrcReg[i]);
1532 if (i + 1 < n)
1533 _mesa_printf(", ");
1534 }
Michal Krol2861e732004-03-29 11:09:34 +00001535 _mesa_printf(";\n");
1536 break;
Brian Paul7e807512005-11-05 17:10:45 +00001537 case OPCODE_ARL:
Michal Krol2861e732004-03-29 11:09:34 +00001538 _mesa_printf("ARL A0.x, ");
1539 PrintSrcReg(&inst->SrcReg[0]);
1540 _mesa_printf(";\n");
1541 break;
Brian Paul7e807512005-11-05 17:10:45 +00001542 case OPCODE_PRINT:
Brian Paul575700f2004-12-16 03:07:18 +00001543 _mesa_printf("PRINT '%s'", inst->Data);
Brian Paulde997602005-11-12 17:53:14 +00001544 if (inst->SrcReg[0].File != PROGRAM_UNDEFINED) {
Brian Paul575700f2004-12-16 03:07:18 +00001545 _mesa_printf(", ");
1546 PrintSrcReg(&inst->SrcReg[0]);
1547 _mesa_printf(";\n");
1548 }
1549 else {
1550 _mesa_printf("\n");
1551 }
1552 break;
Brian Paul7e807512005-11-05 17:10:45 +00001553 case OPCODE_END:
Michal Krol2861e732004-03-29 11:09:34 +00001554 _mesa_printf("END\n");
1555 break;
1556 default:
1557 _mesa_printf("BAD INSTRUCTION\n");
1558 }
1559}
1560
1561
1562/**
1563 * Print (unparse) the given vertex program. Just for debugging.
1564 */
1565void
Brian Paul122629f2006-07-20 16:49:57 +00001566_mesa_print_nv_vertex_program(const struct gl_vertex_program *program)
Michal Krol2861e732004-03-29 11:09:34 +00001567{
Brian Paul7e807512005-11-05 17:10:45 +00001568 const struct prog_instruction *inst;
Michal Krol2861e732004-03-29 11:09:34 +00001569
Brian Paulde997602005-11-12 17:53:14 +00001570 for (inst = program->Base.Instructions; ; inst++) {
Michal Krol2861e732004-03-29 11:09:34 +00001571 _mesa_print_nv_vertex_instruction(inst);
Brian Paul7e807512005-11-05 17:10:45 +00001572 if (inst->Opcode == OPCODE_END)
Michal Krol2861e732004-03-29 11:09:34 +00001573 return;
1574 }
1575}
1576
1577
1578const char *
1579_mesa_nv_vertex_input_register_name(GLuint i)
1580{
1581 ASSERT(i < MAX_NV_VERTEX_PROGRAM_INPUTS);
1582 return InputRegisters[i];
1583}
1584
1585
1586const char *
1587_mesa_nv_vertex_output_register_name(GLuint i)
1588{
1589 ASSERT(i < MAX_NV_VERTEX_PROGRAM_OUTPUTS);
1590 return OutputRegisters[i];
1591}
Brian Paul7aebaf32005-10-30 21:23:23 +00001592