blob: f5e2df267081dbe2cc41cbe4e2c22c1142b9298b [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"
Brian Paulfe278f12009-04-14 19:53:37 -060047#include "prog_print.h"
Michal Krol2861e732004-03-29 11:09:34 +000048#include "program.h"
49
50
51/**
52 * Current parsing state. This structure is passed among the parsing
53 * functions and keeps track of the current parser position and various
54 * program attributes.
55 */
56struct parse_state {
57 GLcontext *ctx;
58 const GLubyte *start;
59 const GLubyte *pos;
60 const GLubyte *curLine;
61 GLboolean isStateProgram;
62 GLboolean isPositionInvariant;
63 GLboolean isVersion1_1;
Brian Paul97a65932006-10-10 21:25:27 +000064 GLbitfield inputsRead;
65 GLbitfield outputsWritten;
Michal Krol2861e732004-03-29 11:09:34 +000066 GLboolean anyProgRegsWritten;
67 GLuint numInst; /* number of instructions parsed */
68};
69
70
71/*
72 * Called whenever we find an error during parsing.
73 */
74static void
75record_error(struct parse_state *parseState, const char *msg, int lineNo)
76{
77#ifdef DEBUG
78 GLint line, column;
79 const GLubyte *lineStr;
80 lineStr = _mesa_find_line_column(parseState->start,
81 parseState->pos, &line, &column);
82 _mesa_debug(parseState->ctx,
83 "nvfragparse.c(%d): line %d, column %d:%s (%s)\n",
84 lineNo, line, column, (char *) lineStr, msg);
85 _mesa_free((void *) lineStr);
86#else
87 (void) lineNo;
88#endif
89
90 /* Check that no error was already recorded. Only record the first one. */
91 if (parseState->ctx->Program.ErrorString[0] == 0) {
92 _mesa_set_program_error(parseState->ctx,
93 parseState->pos - parseState->start,
94 msg);
95 }
96}
97
98
99#define RETURN_ERROR \
100do { \
101 record_error(parseState, "Unexpected end of input.", __LINE__); \
102 return GL_FALSE; \
103} while(0)
104
105#define RETURN_ERROR1(msg) \
106do { \
107 record_error(parseState, msg, __LINE__); \
108 return GL_FALSE; \
109} while(0)
110
111#define RETURN_ERROR2(msg1, msg2) \
112do { \
113 char err[1000]; \
114 _mesa_sprintf(err, "%s %s", msg1, msg2); \
115 record_error(parseState, err, __LINE__); \
116 return GL_FALSE; \
117} while(0)
118
119
120
121
122
123static GLboolean IsLetter(GLubyte b)
124{
125 return (b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z');
126}
127
128
129static GLboolean IsDigit(GLubyte b)
130{
131 return b >= '0' && b <= '9';
132}
133
134
135static GLboolean IsWhitespace(GLubyte b)
136{
137 return b == ' ' || b == '\t' || b == '\n' || b == '\r';
138}
139
140
141/**
142 * Starting at 'str' find the next token. A token can be an integer,
143 * an identifier or punctuation symbol.
144 * \return <= 0 we found an error, else, return number of characters parsed.
145 */
146static GLint
147GetToken(struct parse_state *parseState, GLubyte *token)
148{
149 const GLubyte *str = parseState->pos;
150 GLint i = 0, j = 0;
151
152 token[0] = 0;
153
154 /* skip whitespace and comments */
155 while (str[i] && (IsWhitespace(str[i]) || str[i] == '#')) {
156 if (str[i] == '#') {
157 /* skip comment */
158 while (str[i] && (str[i] != '\n' && str[i] != '\r')) {
159 i++;
160 }
161 if (str[i] == '\n' || str[i] == '\r')
162 parseState->curLine = str + i + 1;
163 }
164 else {
165 /* skip whitespace */
166 if (str[i] == '\n' || str[i] == '\r')
167 parseState->curLine = str + i + 1;
168 i++;
169 }
170 }
171
172 if (str[i] == 0)
173 return -i;
174
175 /* try matching an integer */
176 while (str[i] && IsDigit(str[i])) {
177 token[j++] = str[i++];
178 }
179 if (j > 0 || !str[i]) {
180 token[j] = 0;
181 return i;
182 }
183
184 /* try matching an identifier */
185 if (IsLetter(str[i])) {
186 while (str[i] && (IsLetter(str[i]) || IsDigit(str[i]))) {
187 token[j++] = str[i++];
188 }
189 token[j] = 0;
190 return i;
191 }
192
193 /* punctuation character */
194 if (str[i]) {
195 token[0] = str[i++];
196 token[1] = 0;
197 return i;
198 }
199
200 /* end of input */
201 token[0] = 0;
202 return i;
203}
204
205
206/**
207 * Get next token from input stream and increment stream pointer past token.
208 */
209static GLboolean
210Parse_Token(struct parse_state *parseState, GLubyte *token)
211{
212 GLint i;
213 i = GetToken(parseState, token);
214 if (i <= 0) {
215 parseState->pos += (-i);
216 return GL_FALSE;
217 }
218 parseState->pos += i;
219 return GL_TRUE;
220}
221
222
223/**
224 * Get next token from input stream but don't increment stream pointer.
225 */
226static GLboolean
227Peek_Token(struct parse_state *parseState, GLubyte *token)
228{
229 GLint i, len;
230 i = GetToken(parseState, token);
231 if (i <= 0) {
232 parseState->pos += (-i);
233 return GL_FALSE;
234 }
Karl Schultz6258b762005-05-05 21:08:07 +0000235 len = (GLint)_mesa_strlen((const char *) token);
Michal Krol2861e732004-03-29 11:09:34 +0000236 parseState->pos += (i - len);
237 return GL_TRUE;
238}
239
240
241/**
242 * Try to match 'pattern' as the next token after any whitespace/comments.
243 * Advance the current parsing position only if we match the pattern.
244 * \return GL_TRUE if pattern is matched, GL_FALSE otherwise.
245 */
246static GLboolean
247Parse_String(struct parse_state *parseState, const char *pattern)
248{
249 const GLubyte *m;
250 GLint i;
251
252 /* skip whitespace and comments */
253 while (IsWhitespace(*parseState->pos) || *parseState->pos == '#') {
254 if (*parseState->pos == '#') {
255 while (*parseState->pos && (*parseState->pos != '\n' && *parseState->pos != '\r')) {
256 parseState->pos += 1;
257 }
258 if (*parseState->pos == '\n' || *parseState->pos == '\r')
259 parseState->curLine = parseState->pos + 1;
260 }
261 else {
262 /* skip whitespace */
263 if (*parseState->pos == '\n' || *parseState->pos == '\r')
264 parseState->curLine = parseState->pos + 1;
265 parseState->pos += 1;
266 }
267 }
268
269 /* Try to match the pattern */
270 m = parseState->pos;
271 for (i = 0; pattern[i]; i++) {
272 if (*m != (GLubyte) pattern[i])
273 return GL_FALSE;
274 m += 1;
275 }
276 parseState->pos = m;
277
278 return GL_TRUE; /* success */
279}
280
281
282/**********************************************************************/
283
284static const char *InputRegisters[MAX_NV_VERTEX_PROGRAM_INPUTS + 1] = {
285 "OPOS", "WGHT", "NRML", "COL0", "COL1", "FOGC", "6", "7",
286 "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", NULL
287};
288
289static const char *OutputRegisters[MAX_NV_VERTEX_PROGRAM_OUTPUTS + 1] = {
Keith Whitwellc3626a92005-11-01 17:25:49 +0000290 "HPOS", "COL0", "COL1", "FOGC",
291 "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7",
292 "PSIZ", "BFC0", "BFC1", NULL
Michal Krol2861e732004-03-29 11:09:34 +0000293};
294
Michal Krol2861e732004-03-29 11:09:34 +0000295
296
297/**
298 * Parse a temporary register: Rnn
299 */
300static GLboolean
301Parse_TempReg(struct parse_state *parseState, GLint *tempRegNum)
302{
303 GLubyte token[100];
304
305 /* Should be 'R##' */
306 if (!Parse_Token(parseState, token))
307 RETURN_ERROR;
308 if (token[0] != 'R')
309 RETURN_ERROR1("Expected R##");
310
311 if (IsDigit(token[1])) {
312 GLint reg = _mesa_atoi((char *) (token + 1));
313 if (reg >= MAX_NV_VERTEX_PROGRAM_TEMPS)
314 RETURN_ERROR1("Bad temporary register name");
315 *tempRegNum = reg;
316 }
317 else {
318 RETURN_ERROR1("Bad temporary register name");
319 }
320
321 return GL_TRUE;
322}
323
324
325/**
326 * Parse address register "A0.x"
327 */
328static GLboolean
329Parse_AddrReg(struct parse_state *parseState)
330{
331 /* match 'A0' */
332 if (!Parse_String(parseState, "A0"))
333 RETURN_ERROR;
334
335 /* match '.' */
336 if (!Parse_String(parseState, "."))
337 RETURN_ERROR;
338
339 /* match 'x' */
340 if (!Parse_String(parseState, "x"))
341 RETURN_ERROR;
342
343 return GL_TRUE;
344}
345
346
347/**
348 * Parse absolute program parameter register "c[##]"
349 */
350static GLboolean
351Parse_AbsParamReg(struct parse_state *parseState, GLint *regNum)
352{
353 GLubyte token[100];
354
355 if (!Parse_String(parseState, "c"))
356 RETURN_ERROR;
357
358 if (!Parse_String(parseState, "["))
359 RETURN_ERROR;
360
361 if (!Parse_Token(parseState, token))
362 RETURN_ERROR;
363
364 if (IsDigit(token[0])) {
365 /* a numbered program parameter register */
366 GLint reg = _mesa_atoi((char *) token);
367 if (reg >= MAX_NV_VERTEX_PROGRAM_PARAMS)
368 RETURN_ERROR1("Bad program parameter number");
369 *regNum = reg;
370 }
371 else {
372 RETURN_ERROR;
373 }
374
375 if (!Parse_String(parseState, "]"))
376 RETURN_ERROR;
377
378 return GL_TRUE;
379}
380
381
382static GLboolean
Brian Paul7e807512005-11-05 17:10:45 +0000383Parse_ParamReg(struct parse_state *parseState, struct prog_src_register *srcReg)
Michal Krol2861e732004-03-29 11:09:34 +0000384{
385 GLubyte token[100];
386
387 if (!Parse_String(parseState, "c"))
388 RETURN_ERROR;
389
390 if (!Parse_String(parseState, "["))
391 RETURN_ERROR;
392
393 if (!Peek_Token(parseState, token))
394 RETURN_ERROR;
395
396 if (IsDigit(token[0])) {
397 /* a numbered program parameter register */
398 GLint reg;
399 (void) Parse_Token(parseState, token);
400 reg = _mesa_atoi((char *) token);
401 if (reg >= MAX_NV_VERTEX_PROGRAM_PARAMS)
402 RETURN_ERROR1("Bad program parameter number");
403 srcReg->File = PROGRAM_ENV_PARAM;
404 srcReg->Index = reg;
405 }
406 else if (_mesa_strcmp((const char *) token, "A0") == 0) {
407 /* address register "A0.x" */
408 if (!Parse_AddrReg(parseState))
409 RETURN_ERROR;
410
411 srcReg->RelAddr = GL_TRUE;
412 srcReg->File = PROGRAM_ENV_PARAM;
413 /* Look for +/-N offset */
414 if (!Peek_Token(parseState, token))
415 RETURN_ERROR;
416
417 if (token[0] == '-' || token[0] == '+') {
418 const GLubyte sign = token[0];
419 (void) Parse_Token(parseState, token); /* consume +/- */
420
421 /* an integer should be next */
422 if (!Parse_Token(parseState, token))
423 RETURN_ERROR;
424
425 if (IsDigit(token[0])) {
426 const GLint k = _mesa_atoi((char *) token);
427 if (sign == '-') {
428 if (k > 64)
429 RETURN_ERROR1("Bad address offset");
430 srcReg->Index = -k;
431 }
432 else {
433 if (k > 63)
434 RETURN_ERROR1("Bad address offset");
435 srcReg->Index = k;
436 }
437 }
438 else {
439 RETURN_ERROR;
440 }
441 }
442 else {
443 /* probably got a ']', catch it below */
444 }
445 }
446 else {
447 RETURN_ERROR;
448 }
449
450 /* Match closing ']' */
451 if (!Parse_String(parseState, "]"))
452 RETURN_ERROR;
453
454 return GL_TRUE;
455}
456
457
458/**
459 * Parse v[#] or v[<name>]
460 */
461static GLboolean
462Parse_AttribReg(struct parse_state *parseState, GLint *tempRegNum)
463{
464 GLubyte token[100];
465 GLint j;
466
467 /* Match 'v' */
468 if (!Parse_String(parseState, "v"))
469 RETURN_ERROR;
470
471 /* Match '[' */
472 if (!Parse_String(parseState, "["))
473 RETURN_ERROR;
474
475 /* match number or named register */
476 if (!Parse_Token(parseState, token))
477 RETURN_ERROR;
478
479 if (parseState->isStateProgram && token[0] != '0')
480 RETURN_ERROR1("Only v[0] accessible in vertex state programs");
481
482 if (IsDigit(token[0])) {
483 GLint reg = _mesa_atoi((char *) token);
484 if (reg >= MAX_NV_VERTEX_PROGRAM_INPUTS)
485 RETURN_ERROR1("Bad vertex attribute register name");
486 *tempRegNum = reg;
487 }
488 else {
489 for (j = 0; InputRegisters[j]; j++) {
490 if (_mesa_strcmp((const char *) token, InputRegisters[j]) == 0) {
491 *tempRegNum = j;
492 break;
493 }
494 }
495 if (!InputRegisters[j]) {
496 /* unknown input register label */
497 RETURN_ERROR2("Bad register name", token);
498 }
499 }
500
501 /* Match '[' */
502 if (!Parse_String(parseState, "]"))
503 RETURN_ERROR;
504
505 return GL_TRUE;
506}
507
508
509static GLboolean
510Parse_OutputReg(struct parse_state *parseState, GLint *outputRegNum)
511{
512 GLubyte token[100];
513 GLint start, j;
514
515 /* Match 'o' */
516 if (!Parse_String(parseState, "o"))
517 RETURN_ERROR;
518
519 /* Match '[' */
520 if (!Parse_String(parseState, "["))
521 RETURN_ERROR;
522
523 /* Get output reg name */
524 if (!Parse_Token(parseState, token))
525 RETURN_ERROR;
526
527 if (parseState->isPositionInvariant)
528 start = 1; /* skip HPOS register name */
529 else
530 start = 0;
531
532 /* try to match an output register name */
533 for (j = start; OutputRegisters[j]; j++) {
534 if (_mesa_strcmp((const char *) token, OutputRegisters[j]) == 0) {
535 *outputRegNum = j;
536 break;
537 }
538 }
539 if (!OutputRegisters[j])
540 RETURN_ERROR1("Unrecognized output register name");
541
542 /* Match ']' */
543 if (!Parse_String(parseState, "]"))
544 RETURN_ERROR1("Expected ]");
545
546 return GL_TRUE;
547}
548
549
550static GLboolean
Brian Paul7e807512005-11-05 17:10:45 +0000551Parse_MaskedDstReg(struct parse_state *parseState, struct prog_dst_register *dstReg)
Michal Krol2861e732004-03-29 11:09:34 +0000552{
553 GLubyte token[100];
Keith Whitwell7c26b612005-04-21 14:46:57 +0000554 GLint idx;
Michal Krol2861e732004-03-29 11:09:34 +0000555
556 /* Dst reg can be R<n> or o[n] */
557 if (!Peek_Token(parseState, token))
558 RETURN_ERROR;
559
560 if (token[0] == 'R') {
561 /* a temporary register */
562 dstReg->File = PROGRAM_TEMPORARY;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000563 if (!Parse_TempReg(parseState, &idx))
Michal Krol2861e732004-03-29 11:09:34 +0000564 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000565 dstReg->Index = idx;
Michal Krol2861e732004-03-29 11:09:34 +0000566 }
567 else if (!parseState->isStateProgram && token[0] == 'o') {
568 /* an output register */
569 dstReg->File = PROGRAM_OUTPUT;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000570 if (!Parse_OutputReg(parseState, &idx))
Michal Krol2861e732004-03-29 11:09:34 +0000571 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000572 dstReg->Index = idx;
Michal Krol2861e732004-03-29 11:09:34 +0000573 }
574 else if (parseState->isStateProgram && token[0] == 'c' &&
575 parseState->isStateProgram) {
576 /* absolute program parameter register */
577 /* Only valid for vertex state programs */
578 dstReg->File = PROGRAM_ENV_PARAM;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000579 if (!Parse_AbsParamReg(parseState, &idx))
Michal Krol2861e732004-03-29 11:09:34 +0000580 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000581 dstReg->Index = idx;
Michal Krol2861e732004-03-29 11:09:34 +0000582 }
583 else {
584 RETURN_ERROR1("Bad destination register name");
585 }
586
587 /* Parse optional write mask */
588 if (!Peek_Token(parseState, token))
589 RETURN_ERROR;
590
591 if (token[0] == '.') {
592 /* got a mask */
593 GLint k = 0;
594
595 if (!Parse_String(parseState, "."))
596 RETURN_ERROR;
597
598 if (!Parse_Token(parseState, token))
599 RETURN_ERROR;
600
Keith Whitwell7c26b612005-04-21 14:46:57 +0000601 dstReg->WriteMask = 0;
Michal Krol2861e732004-03-29 11:09:34 +0000602
603 if (token[k] == 'x') {
Keith Whitwell7c26b612005-04-21 14:46:57 +0000604 dstReg->WriteMask |= WRITEMASK_X;
Michal Krol2861e732004-03-29 11:09:34 +0000605 k++;
606 }
607 if (token[k] == 'y') {
Keith Whitwell7c26b612005-04-21 14:46:57 +0000608 dstReg->WriteMask |= WRITEMASK_Y;
Michal Krol2861e732004-03-29 11:09:34 +0000609 k++;
610 }
611 if (token[k] == 'z') {
Keith Whitwell7c26b612005-04-21 14:46:57 +0000612 dstReg->WriteMask |= WRITEMASK_Z;
Michal Krol2861e732004-03-29 11:09:34 +0000613 k++;
614 }
615 if (token[k] == 'w') {
Keith Whitwell7c26b612005-04-21 14:46:57 +0000616 dstReg->WriteMask |= WRITEMASK_W;
Michal Krol2861e732004-03-29 11:09:34 +0000617 k++;
618 }
619 if (k == 0) {
620 RETURN_ERROR1("Bad writemask character");
621 }
622 return GL_TRUE;
623 }
624 else {
Keith Whitwell7c26b612005-04-21 14:46:57 +0000625 dstReg->WriteMask = WRITEMASK_XYZW;
Michal Krol2861e732004-03-29 11:09:34 +0000626 return GL_TRUE;
627 }
628}
629
630
631static GLboolean
Brian Paul7e807512005-11-05 17:10:45 +0000632Parse_SwizzleSrcReg(struct parse_state *parseState, struct prog_src_register *srcReg)
Michal Krol2861e732004-03-29 11:09:34 +0000633{
634 GLubyte token[100];
Keith Whitwell7c26b612005-04-21 14:46:57 +0000635 GLint idx;
Michal Krol2861e732004-03-29 11:09:34 +0000636
637 srcReg->RelAddr = GL_FALSE;
638
639 /* check for '-' */
640 if (!Peek_Token(parseState, token))
641 RETURN_ERROR;
642 if (token[0] == '-') {
643 (void) Parse_String(parseState, "-");
Brian Paul7db7ff82009-04-14 22:14:30 -0600644 srcReg->Negate = NEGATE_XYZW;
Michal Krol2861e732004-03-29 11:09:34 +0000645 if (!Peek_Token(parseState, token))
646 RETURN_ERROR;
647 }
648 else {
Brian Paul7db7ff82009-04-14 22:14:30 -0600649 srcReg->Negate = NEGATE_NONE;
Michal Krol2861e732004-03-29 11:09:34 +0000650 }
651
652 /* Src reg can be R<n>, c[n], c[n +/- offset], or a named vertex attrib */
653 if (token[0] == 'R') {
654 srcReg->File = PROGRAM_TEMPORARY;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000655 if (!Parse_TempReg(parseState, &idx))
Michal Krol2861e732004-03-29 11:09:34 +0000656 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000657 srcReg->Index = idx;
Michal Krol2861e732004-03-29 11:09:34 +0000658 }
659 else if (token[0] == 'c') {
660 if (!Parse_ParamReg(parseState, srcReg))
661 RETURN_ERROR;
662 }
663 else if (token[0] == 'v') {
664 srcReg->File = PROGRAM_INPUT;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000665 if (!Parse_AttribReg(parseState, &idx))
Michal Krol2861e732004-03-29 11:09:34 +0000666 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000667 srcReg->Index = idx;
Michal Krol2861e732004-03-29 11:09:34 +0000668 }
669 else {
670 RETURN_ERROR2("Bad source register name", token);
671 }
672
673 /* init swizzle fields */
Keith Whitwell7c26b612005-04-21 14:46:57 +0000674 srcReg->Swizzle = SWIZZLE_NOOP;
Michal Krol2861e732004-03-29 11:09:34 +0000675
676 /* Look for optional swizzle suffix */
677 if (!Peek_Token(parseState, token))
678 RETURN_ERROR;
679 if (token[0] == '.') {
680 (void) Parse_String(parseState, "."); /* consume . */
681
682 if (!Parse_Token(parseState, token))
683 RETURN_ERROR;
684
685 if (token[1] == 0) {
686 /* single letter swizzle */
687 if (token[0] == 'x')
Brianfc6b8f22007-03-15 11:51:54 -0600688 srcReg->Swizzle = SWIZZLE_XXXX;
Michal Krol2861e732004-03-29 11:09:34 +0000689 else if (token[0] == 'y')
Brianfc6b8f22007-03-15 11:51:54 -0600690 srcReg->Swizzle = SWIZZLE_YYYY;
Michal Krol2861e732004-03-29 11:09:34 +0000691 else if (token[0] == 'z')
Brianfc6b8f22007-03-15 11:51:54 -0600692 srcReg->Swizzle = SWIZZLE_ZZZZ;
Michal Krol2861e732004-03-29 11:09:34 +0000693 else if (token[0] == 'w')
Brianfc6b8f22007-03-15 11:51:54 -0600694 srcReg->Swizzle = SWIZZLE_WWWW;
Michal Krol2861e732004-03-29 11:09:34 +0000695 else
696 RETURN_ERROR1("Expected x, y, z, or w");
697 }
698 else {
699 /* 2, 3 or 4-component swizzle */
700 GLint k;
Dave Airlieb5d76b62006-04-19 23:15:51 +0000701
702 srcReg->Swizzle = 0;
703
Michal Krol2861e732004-03-29 11:09:34 +0000704 for (k = 0; token[k] && k < 5; k++) {
705 if (token[k] == 'x')
Keith Whitwell7c26b612005-04-21 14:46:57 +0000706 srcReg->Swizzle |= 0 << (k*3);
Michal Krol2861e732004-03-29 11:09:34 +0000707 else if (token[k] == 'y')
Keith Whitwell7c26b612005-04-21 14:46:57 +0000708 srcReg->Swizzle |= 1 << (k*3);
Michal Krol2861e732004-03-29 11:09:34 +0000709 else if (token[k] == 'z')
Keith Whitwell7c26b612005-04-21 14:46:57 +0000710 srcReg->Swizzle |= 2 << (k*3);
Michal Krol2861e732004-03-29 11:09:34 +0000711 else if (token[k] == 'w')
Keith Whitwell7c26b612005-04-21 14:46:57 +0000712 srcReg->Swizzle |= 3 << (k*3);
Michal Krol2861e732004-03-29 11:09:34 +0000713 else
714 RETURN_ERROR;
715 }
716 if (k >= 5)
717 RETURN_ERROR;
718 }
719 }
720
721 return GL_TRUE;
722}
723
724
725static GLboolean
Brian Paul7e807512005-11-05 17:10:45 +0000726Parse_ScalarSrcReg(struct parse_state *parseState, struct prog_src_register *srcReg)
Michal Krol2861e732004-03-29 11:09:34 +0000727{
728 GLubyte token[100];
Keith Whitwell7c26b612005-04-21 14:46:57 +0000729 GLint idx;
Michal Krol2861e732004-03-29 11:09:34 +0000730
731 srcReg->RelAddr = GL_FALSE;
732
733 /* check for '-' */
734 if (!Peek_Token(parseState, token))
735 RETURN_ERROR;
736 if (token[0] == '-') {
Brian Paul7db7ff82009-04-14 22:14:30 -0600737 srcReg->Negate = NEGATE_XYZW;
Michal Krol2861e732004-03-29 11:09:34 +0000738 (void) Parse_String(parseState, "-"); /* consume '-' */
739 if (!Peek_Token(parseState, token))
740 RETURN_ERROR;
741 }
742 else {
Brian Paul7db7ff82009-04-14 22:14:30 -0600743 srcReg->Negate = NEGATE_NONE;
Michal Krol2861e732004-03-29 11:09:34 +0000744 }
745
746 /* Src reg can be R<n>, c[n], c[n +/- offset], or a named vertex attrib */
747 if (token[0] == 'R') {
748 srcReg->File = PROGRAM_TEMPORARY;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000749 if (!Parse_TempReg(parseState, &idx))
Michal Krol2861e732004-03-29 11:09:34 +0000750 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000751 srcReg->Index = idx;
Michal Krol2861e732004-03-29 11:09:34 +0000752 }
753 else if (token[0] == 'c') {
754 if (!Parse_ParamReg(parseState, srcReg))
755 RETURN_ERROR;
756 }
757 else if (token[0] == 'v') {
758 srcReg->File = PROGRAM_INPUT;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000759 if (!Parse_AttribReg(parseState, &idx))
Michal Krol2861e732004-03-29 11:09:34 +0000760 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000761 srcReg->Index = idx;
Michal Krol2861e732004-03-29 11:09:34 +0000762 }
763 else {
764 RETURN_ERROR2("Bad source register name", token);
765 }
766
767 /* Look for .[xyzw] suffix */
768 if (!Parse_String(parseState, "."))
769 RETURN_ERROR;
770
771 if (!Parse_Token(parseState, token))
772 RETURN_ERROR;
773
774 if (token[0] == 'x' && token[1] == 0) {
Keith Whitwell7c26b612005-04-21 14:46:57 +0000775 srcReg->Swizzle = 0;
Michal Krol2861e732004-03-29 11:09:34 +0000776 }
777 else if (token[0] == 'y' && token[1] == 0) {
Keith Whitwell7c26b612005-04-21 14:46:57 +0000778 srcReg->Swizzle = 1;
Michal Krol2861e732004-03-29 11:09:34 +0000779 }
780 else if (token[0] == 'z' && token[1] == 0) {
Keith Whitwell7c26b612005-04-21 14:46:57 +0000781 srcReg->Swizzle = 2;
Michal Krol2861e732004-03-29 11:09:34 +0000782 }
783 else if (token[0] == 'w' && token[1] == 0) {
Keith Whitwell7c26b612005-04-21 14:46:57 +0000784 srcReg->Swizzle = 3;
Michal Krol2861e732004-03-29 11:09:34 +0000785 }
786 else {
787 RETURN_ERROR1("Bad scalar source suffix");
788 }
Michal Krol2861e732004-03-29 11:09:34 +0000789
790 return GL_TRUE;
791}
792
793
794static GLint
795Parse_UnaryOpInstruction(struct parse_state *parseState,
Brian Paul7e807512005-11-05 17:10:45 +0000796 struct prog_instruction *inst,
797 enum prog_opcode opcode)
Michal Krol2861e732004-03-29 11:09:34 +0000798{
Brian Paul7e807512005-11-05 17:10:45 +0000799 if (opcode == OPCODE_ABS && !parseState->isVersion1_1)
Michal Krol2861e732004-03-29 11:09:34 +0000800 RETURN_ERROR1("ABS illegal for vertex program 1.0");
801
802 inst->Opcode = opcode;
Michal Krol2861e732004-03-29 11:09:34 +0000803
804 /* dest reg */
805 if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
806 RETURN_ERROR;
807
808 /* comma */
809 if (!Parse_String(parseState, ","))
810 RETURN_ERROR;
811
812 /* src arg */
813 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[0]))
814 RETURN_ERROR;
815
816 /* semicolon */
817 if (!Parse_String(parseState, ";"))
818 RETURN_ERROR;
819
820 return GL_TRUE;
821}
822
823
824static GLboolean
825Parse_BiOpInstruction(struct parse_state *parseState,
Brian Paul7e807512005-11-05 17:10:45 +0000826 struct prog_instruction *inst,
827 enum prog_opcode opcode)
Michal Krol2861e732004-03-29 11:09:34 +0000828{
Brian Paul7e807512005-11-05 17:10:45 +0000829 if (opcode == OPCODE_DPH && !parseState->isVersion1_1)
Michal Krol2861e732004-03-29 11:09:34 +0000830 RETURN_ERROR1("DPH illegal for vertex program 1.0");
Brian Paul7e807512005-11-05 17:10:45 +0000831 if (opcode == OPCODE_SUB && !parseState->isVersion1_1)
Michal Krol2861e732004-03-29 11:09:34 +0000832 RETURN_ERROR1("SUB illegal for vertex program 1.0");
833
834 inst->Opcode = opcode;
Michal Krol2861e732004-03-29 11:09:34 +0000835
836 /* dest reg */
837 if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
838 RETURN_ERROR;
839
840 /* comma */
841 if (!Parse_String(parseState, ","))
842 RETURN_ERROR;
843
844 /* first src arg */
845 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[0]))
846 RETURN_ERROR;
847
848 /* comma */
849 if (!Parse_String(parseState, ","))
850 RETURN_ERROR;
851
852 /* second src arg */
853 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[1]))
854 RETURN_ERROR;
855
856 /* semicolon */
857 if (!Parse_String(parseState, ";"))
858 RETURN_ERROR;
859
860 /* make sure we don't reference more than one program parameter register */
861 if (inst->SrcReg[0].File == PROGRAM_ENV_PARAM &&
862 inst->SrcReg[1].File == PROGRAM_ENV_PARAM &&
863 inst->SrcReg[0].Index != inst->SrcReg[1].Index)
864 RETURN_ERROR1("Can't reference two program parameter registers");
865
866 /* make sure we don't reference more than one vertex attribute register */
867 if (inst->SrcReg[0].File == PROGRAM_INPUT &&
868 inst->SrcReg[1].File == PROGRAM_INPUT &&
869 inst->SrcReg[0].Index != inst->SrcReg[1].Index)
870 RETURN_ERROR1("Can't reference two vertex attribute registers");
871
872 return GL_TRUE;
873}
874
875
876static GLboolean
877Parse_TriOpInstruction(struct parse_state *parseState,
Brian Paul7e807512005-11-05 17:10:45 +0000878 struct prog_instruction *inst,
879 enum prog_opcode opcode)
Michal Krol2861e732004-03-29 11:09:34 +0000880{
881 inst->Opcode = opcode;
Michal Krol2861e732004-03-29 11:09:34 +0000882
883 /* dest reg */
884 if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
885 RETURN_ERROR;
886
887 /* comma */
888 if (!Parse_String(parseState, ","))
889 RETURN_ERROR;
890
891 /* first src arg */
892 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[0]))
893 RETURN_ERROR;
894
895 /* comma */
896 if (!Parse_String(parseState, ","))
897 RETURN_ERROR;
898
899 /* second src arg */
900 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[1]))
901 RETURN_ERROR;
902
903 /* comma */
904 if (!Parse_String(parseState, ","))
905 RETURN_ERROR;
906
907 /* third src arg */
908 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[2]))
909 RETURN_ERROR;
910
911 /* semicolon */
912 if (!Parse_String(parseState, ";"))
913 RETURN_ERROR;
914
915 /* make sure we don't reference more than one program parameter register */
916 if ((inst->SrcReg[0].File == PROGRAM_ENV_PARAM &&
917 inst->SrcReg[1].File == PROGRAM_ENV_PARAM &&
918 inst->SrcReg[0].Index != inst->SrcReg[1].Index) ||
919 (inst->SrcReg[0].File == PROGRAM_ENV_PARAM &&
920 inst->SrcReg[2].File == PROGRAM_ENV_PARAM &&
921 inst->SrcReg[0].Index != inst->SrcReg[2].Index) ||
922 (inst->SrcReg[1].File == PROGRAM_ENV_PARAM &&
923 inst->SrcReg[2].File == PROGRAM_ENV_PARAM &&
924 inst->SrcReg[1].Index != inst->SrcReg[2].Index))
925 RETURN_ERROR1("Can only reference one program register");
926
927 /* make sure we don't reference more than one vertex attribute register */
928 if ((inst->SrcReg[0].File == PROGRAM_INPUT &&
929 inst->SrcReg[1].File == PROGRAM_INPUT &&
930 inst->SrcReg[0].Index != inst->SrcReg[1].Index) ||
931 (inst->SrcReg[0].File == PROGRAM_INPUT &&
932 inst->SrcReg[2].File == PROGRAM_INPUT &&
933 inst->SrcReg[0].Index != inst->SrcReg[2].Index) ||
934 (inst->SrcReg[1].File == PROGRAM_INPUT &&
935 inst->SrcReg[2].File == PROGRAM_INPUT &&
936 inst->SrcReg[1].Index != inst->SrcReg[2].Index))
937 RETURN_ERROR1("Can only reference one input register");
938
939 return GL_TRUE;
940}
941
942
943static GLboolean
944Parse_ScalarInstruction(struct parse_state *parseState,
Brian Paul7e807512005-11-05 17:10:45 +0000945 struct prog_instruction *inst,
946 enum prog_opcode opcode)
Michal Krol2861e732004-03-29 11:09:34 +0000947{
Brian Paul7e807512005-11-05 17:10:45 +0000948 if (opcode == OPCODE_RCC && !parseState->isVersion1_1)
Michal Krol2861e732004-03-29 11:09:34 +0000949 RETURN_ERROR1("RCC illegal for vertex program 1.0");
950
951 inst->Opcode = opcode;
Michal Krol2861e732004-03-29 11:09:34 +0000952
953 /* dest reg */
954 if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
955 RETURN_ERROR;
956
957 /* comma */
958 if (!Parse_String(parseState, ","))
959 RETURN_ERROR;
960
961 /* first src arg */
962 if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0]))
963 RETURN_ERROR;
964
965 /* semicolon */
966 if (!Parse_String(parseState, ";"))
967 RETURN_ERROR;
968
969 return GL_TRUE;
970}
971
972
973static GLboolean
Brian Paul7e807512005-11-05 17:10:45 +0000974Parse_AddressInstruction(struct parse_state *parseState, struct prog_instruction *inst)
Michal Krol2861e732004-03-29 11:09:34 +0000975{
Brian Paul7e807512005-11-05 17:10:45 +0000976 inst->Opcode = OPCODE_ARL;
Michal Krol2861e732004-03-29 11:09:34 +0000977
Aapo Tahkolaed4ab132006-03-24 16:35:08 +0000978 /* Make ARB_vp backends happy */
979 inst->DstReg.File = PROGRAM_ADDRESS;
980 inst->DstReg.WriteMask = WRITEMASK_X;
981 inst->DstReg.Index = 0;
982
Michal Krol2861e732004-03-29 11:09:34 +0000983 /* dest A0 reg */
984 if (!Parse_AddrReg(parseState))
985 RETURN_ERROR;
986
987 /* comma */
988 if (!Parse_String(parseState, ","))
989 RETURN_ERROR;
990
991 /* parse src reg */
992 if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0]))
993 RETURN_ERROR;
994
995 /* semicolon */
996 if (!Parse_String(parseState, ";"))
997 RETURN_ERROR;
998
999 return GL_TRUE;
1000}
1001
1002
1003static GLboolean
Brian Paul7e807512005-11-05 17:10:45 +00001004Parse_EndInstruction(struct parse_state *parseState, struct prog_instruction *inst)
Michal Krol2861e732004-03-29 11:09:34 +00001005{
1006 GLubyte token[100];
1007
Brian Paul7e807512005-11-05 17:10:45 +00001008 inst->Opcode = OPCODE_END;
Michal Krol2861e732004-03-29 11:09:34 +00001009
1010 /* this should fail! */
1011 if (Parse_Token(parseState, token))
1012 RETURN_ERROR2("Unexpected token after END:", token);
1013 else
1014 return GL_TRUE;
1015}
1016
1017
Brian Paul575700f2004-12-16 03:07:18 +00001018/**
1019 * The PRINT instruction is Mesa-specific and is meant as a debugging aid for
1020 * the vertex program developer.
1021 * The NV_vertex_program extension grammar is modified as follows:
1022 *
1023 * <instruction> ::= <ARL-instruction>
1024 * | ...
1025 * | <PRINT-instruction>
1026 *
1027 * <PRINT-instruction> ::= "PRINT" <string literal>
1028 * | "PRINT" <string literal> "," <srcReg>
1029 * | "PRINT" <string literal> "," <dstReg>
1030 */
1031static GLboolean
Brian Paul7e807512005-11-05 17:10:45 +00001032Parse_PrintInstruction(struct parse_state *parseState, struct prog_instruction *inst)
Brian Paul575700f2004-12-16 03:07:18 +00001033{
1034 const GLubyte *str;
1035 GLubyte *msg;
1036 GLuint len;
1037 GLubyte token[100];
Brian Paul7e807512005-11-05 17:10:45 +00001038 struct prog_src_register *srcReg = &inst->SrcReg[0];
Keith Whitwell7c26b612005-04-21 14:46:57 +00001039 GLint idx;
Brian Paul575700f2004-12-16 03:07:18 +00001040
Brian Paul7e807512005-11-05 17:10:45 +00001041 inst->Opcode = OPCODE_PRINT;
Brian Paul575700f2004-12-16 03:07:18 +00001042
1043 /* The first argument is a literal string 'just like this' */
1044 if (!Parse_String(parseState, "'"))
1045 RETURN_ERROR;
1046
1047 str = parseState->pos;
1048 for (len = 0; str[len] != '\''; len++) /* find closing quote */
1049 ;
1050 parseState->pos += len + 1;
Brian Paul95801792005-12-06 15:41:43 +00001051 msg = (GLubyte*) _mesa_malloc(len + 1);
Brian Paul575700f2004-12-16 03:07:18 +00001052
1053 _mesa_memcpy(msg, str, len);
1054 msg[len] = 0;
1055 inst->Data = msg;
1056
1057 /* comma */
1058 if (Parse_String(parseState, ",")) {
1059
1060 /* The second argument is a register name */
1061 if (!Peek_Token(parseState, token))
1062 RETURN_ERROR;
1063
1064 srcReg->RelAddr = GL_FALSE;
Brian Paul7db7ff82009-04-14 22:14:30 -06001065 srcReg->Negate = NEGATE_NONE;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001066 srcReg->Swizzle = SWIZZLE_NOOP;
Brian Paul575700f2004-12-16 03:07:18 +00001067
1068 /* Register can be R<n>, c[n], c[n +/- offset], a named vertex attrib,
1069 * or an o[n] output register.
1070 */
1071 if (token[0] == 'R') {
1072 srcReg->File = PROGRAM_TEMPORARY;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001073 if (!Parse_TempReg(parseState, &idx))
Brian Paul575700f2004-12-16 03:07:18 +00001074 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001075 srcReg->Index = idx;
Brian Paul575700f2004-12-16 03:07:18 +00001076 }
1077 else if (token[0] == 'c') {
1078 srcReg->File = PROGRAM_ENV_PARAM;
1079 if (!Parse_ParamReg(parseState, srcReg))
1080 RETURN_ERROR;
1081 }
1082 else if (token[0] == 'v') {
1083 srcReg->File = PROGRAM_INPUT;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001084 if (!Parse_AttribReg(parseState, &idx))
Brian Paul575700f2004-12-16 03:07:18 +00001085 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001086 srcReg->Index = idx;
Brian Paul575700f2004-12-16 03:07:18 +00001087 }
1088 else if (token[0] == 'o') {
1089 srcReg->File = PROGRAM_OUTPUT;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001090 if (!Parse_OutputReg(parseState, &idx))
Brian Paul575700f2004-12-16 03:07:18 +00001091 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001092 srcReg->Index = idx;
Brian Paul575700f2004-12-16 03:07:18 +00001093 }
1094 else {
1095 RETURN_ERROR2("Bad source register name", token);
1096 }
1097 }
1098 else {
1099 srcReg->File = 0;
1100 }
1101
1102 /* semicolon */
1103 if (!Parse_String(parseState, ";"))
1104 RETURN_ERROR;
1105
1106 return GL_TRUE;
1107}
1108
1109
Michal Krol2861e732004-03-29 11:09:34 +00001110static GLboolean
1111Parse_OptionSequence(struct parse_state *parseState,
Brian Paul7e807512005-11-05 17:10:45 +00001112 struct prog_instruction program[])
Michal Krol2861e732004-03-29 11:09:34 +00001113{
Brian Paula6c423d2004-08-25 15:59:48 +00001114 (void) program;
Michal Krol2861e732004-03-29 11:09:34 +00001115 while (1) {
1116 if (!Parse_String(parseState, "OPTION"))
1117 return GL_TRUE; /* ok, not an OPTION statement */
1118 if (Parse_String(parseState, "NV_position_invariant")) {
1119 parseState->isPositionInvariant = GL_TRUE;
1120 }
1121 else {
1122 RETURN_ERROR1("unexpected OPTION statement");
1123 }
1124 if (!Parse_String(parseState, ";"))
1125 return GL_FALSE;
1126 }
1127}
1128
1129
1130static GLboolean
1131Parse_InstructionSequence(struct parse_state *parseState,
Brian Paul7e807512005-11-05 17:10:45 +00001132 struct prog_instruction program[])
Michal Krol2861e732004-03-29 11:09:34 +00001133{
1134 while (1) {
Brian Paul7e807512005-11-05 17:10:45 +00001135 struct prog_instruction *inst = program + parseState->numInst;
Michal Krol2861e732004-03-29 11:09:34 +00001136
1137 /* Initialize the instruction */
Brian Pauld6272e02006-10-29 18:03:16 +00001138 _mesa_init_instructions(inst, 1);
Michal Krol2861e732004-03-29 11:09:34 +00001139
1140 if (Parse_String(parseState, "MOV")) {
Brian Paul7e807512005-11-05 17:10:45 +00001141 if (!Parse_UnaryOpInstruction(parseState, inst, OPCODE_MOV))
Michal Krol2861e732004-03-29 11:09:34 +00001142 RETURN_ERROR;
1143 }
1144 else if (Parse_String(parseState, "LIT")) {
Brian Paul7e807512005-11-05 17:10:45 +00001145 if (!Parse_UnaryOpInstruction(parseState, inst, OPCODE_LIT))
Michal Krol2861e732004-03-29 11:09:34 +00001146 RETURN_ERROR;
1147 }
1148 else if (Parse_String(parseState, "ABS")) {
Brian Paul7e807512005-11-05 17:10:45 +00001149 if (!Parse_UnaryOpInstruction(parseState, inst, OPCODE_ABS))
Michal Krol2861e732004-03-29 11:09:34 +00001150 RETURN_ERROR;
1151 }
1152 else if (Parse_String(parseState, "MUL")) {
Brian Paul7e807512005-11-05 17:10:45 +00001153 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_MUL))
Michal Krol2861e732004-03-29 11:09:34 +00001154 RETURN_ERROR;
1155 }
1156 else if (Parse_String(parseState, "ADD")) {
Brian Paul7e807512005-11-05 17:10:45 +00001157 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_ADD))
Michal Krol2861e732004-03-29 11:09:34 +00001158 RETURN_ERROR;
1159 }
1160 else if (Parse_String(parseState, "DP3")) {
Brian Paul7e807512005-11-05 17:10:45 +00001161 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_DP3))
Michal Krol2861e732004-03-29 11:09:34 +00001162 RETURN_ERROR;
1163 }
1164 else if (Parse_String(parseState, "DP4")) {
Brian Paul7e807512005-11-05 17:10:45 +00001165 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_DP4))
Michal Krol2861e732004-03-29 11:09:34 +00001166 RETURN_ERROR;
1167 }
1168 else if (Parse_String(parseState, "DST")) {
Brian Paul7e807512005-11-05 17:10:45 +00001169 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_DST))
Michal Krol2861e732004-03-29 11:09:34 +00001170 RETURN_ERROR;
1171 }
1172 else if (Parse_String(parseState, "MIN")) {
Brian Paul7e807512005-11-05 17:10:45 +00001173 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_MIN))
Michal Krol2861e732004-03-29 11:09:34 +00001174 RETURN_ERROR;
1175 }
1176 else if (Parse_String(parseState, "MAX")) {
Brian Paul7e807512005-11-05 17:10:45 +00001177 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_MAX))
Michal Krol2861e732004-03-29 11:09:34 +00001178 RETURN_ERROR;
1179 }
1180 else if (Parse_String(parseState, "SLT")) {
Brian Paul7e807512005-11-05 17:10:45 +00001181 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_SLT))
Michal Krol2861e732004-03-29 11:09:34 +00001182 RETURN_ERROR;
1183 }
1184 else if (Parse_String(parseState, "SGE")) {
Brian Paul7e807512005-11-05 17:10:45 +00001185 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_SGE))
Michal Krol2861e732004-03-29 11:09:34 +00001186 RETURN_ERROR;
1187 }
1188 else if (Parse_String(parseState, "DPH")) {
Brian Paul7e807512005-11-05 17:10:45 +00001189 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_DPH))
Michal Krol2861e732004-03-29 11:09:34 +00001190 RETURN_ERROR;
1191 }
1192 else if (Parse_String(parseState, "SUB")) {
Brian Paul7e807512005-11-05 17:10:45 +00001193 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_SUB))
Michal Krol2861e732004-03-29 11:09:34 +00001194 RETURN_ERROR;
1195 }
1196 else if (Parse_String(parseState, "MAD")) {
Brian Paul7e807512005-11-05 17:10:45 +00001197 if (!Parse_TriOpInstruction(parseState, inst, OPCODE_MAD))
Michal Krol2861e732004-03-29 11:09:34 +00001198 RETURN_ERROR;
1199 }
1200 else if (Parse_String(parseState, "RCP")) {
Brian Paul7e807512005-11-05 17:10:45 +00001201 if (!Parse_ScalarInstruction(parseState, inst, OPCODE_RCP))
Michal Krol2861e732004-03-29 11:09:34 +00001202 RETURN_ERROR;
1203 }
1204 else if (Parse_String(parseState, "RSQ")) {
Brian Paul7e807512005-11-05 17:10:45 +00001205 if (!Parse_ScalarInstruction(parseState, inst, OPCODE_RSQ))
Michal Krol2861e732004-03-29 11:09:34 +00001206 RETURN_ERROR;
1207 }
1208 else if (Parse_String(parseState, "EXP")) {
Brian Paul7e807512005-11-05 17:10:45 +00001209 if (!Parse_ScalarInstruction(parseState, inst, OPCODE_EXP))
Michal Krol2861e732004-03-29 11:09:34 +00001210 RETURN_ERROR;
1211 }
1212 else if (Parse_String(parseState, "LOG")) {
Brian Paul7e807512005-11-05 17:10:45 +00001213 if (!Parse_ScalarInstruction(parseState, inst, OPCODE_LOG))
Michal Krol2861e732004-03-29 11:09:34 +00001214 RETURN_ERROR;
1215 }
1216 else if (Parse_String(parseState, "RCC")) {
Brian Paul7e807512005-11-05 17:10:45 +00001217 if (!Parse_ScalarInstruction(parseState, inst, OPCODE_RCC))
Michal Krol2861e732004-03-29 11:09:34 +00001218 RETURN_ERROR;
1219 }
1220 else if (Parse_String(parseState, "ARL")) {
1221 if (!Parse_AddressInstruction(parseState, inst))
1222 RETURN_ERROR;
1223 }
Brian Paul575700f2004-12-16 03:07:18 +00001224 else if (Parse_String(parseState, "PRINT")) {
1225 if (!Parse_PrintInstruction(parseState, inst))
1226 RETURN_ERROR;
1227 }
Michal Krol2861e732004-03-29 11:09:34 +00001228 else if (Parse_String(parseState, "END")) {
1229 if (!Parse_EndInstruction(parseState, inst))
1230 RETURN_ERROR;
1231 else {
1232 parseState->numInst++;
1233 return GL_TRUE; /* all done */
1234 }
1235 }
1236 else {
1237 /* bad instruction name */
1238 RETURN_ERROR1("Unexpected token");
1239 }
1240
1241 /* examine input/output registers */
1242 if (inst->DstReg.File == PROGRAM_OUTPUT)
1243 parseState->outputsWritten |= (1 << inst->DstReg.Index);
1244 else if (inst->DstReg.File == PROGRAM_ENV_PARAM)
1245 parseState->anyProgRegsWritten = GL_TRUE;
1246
1247 if (inst->SrcReg[0].File == PROGRAM_INPUT)
1248 parseState->inputsRead |= (1 << inst->SrcReg[0].Index);
1249 if (inst->SrcReg[1].File == PROGRAM_INPUT)
1250 parseState->inputsRead |= (1 << inst->SrcReg[1].Index);
1251 if (inst->SrcReg[2].File == PROGRAM_INPUT)
1252 parseState->inputsRead |= (1 << inst->SrcReg[2].Index);
1253
1254 parseState->numInst++;
1255
1256 if (parseState->numInst >= MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS)
1257 RETURN_ERROR1("Program too long");
1258 }
1259
1260 RETURN_ERROR;
1261}
1262
1263
1264static GLboolean
1265Parse_Program(struct parse_state *parseState,
Brian Paul7e807512005-11-05 17:10:45 +00001266 struct prog_instruction instBuffer[])
Michal Krol2861e732004-03-29 11:09:34 +00001267{
1268 if (parseState->isVersion1_1) {
1269 if (!Parse_OptionSequence(parseState, instBuffer)) {
1270 return GL_FALSE;
1271 }
1272 }
1273 return Parse_InstructionSequence(parseState, instBuffer);
1274}
1275
1276
1277/**
1278 * Parse/compile the 'str' returning the compiled 'program'.
1279 * ctx->Program.ErrorPos will be -1 if successful. Otherwise, ErrorPos
1280 * indicates the position of the error in 'str'.
1281 */
1282void
1283_mesa_parse_nv_vertex_program(GLcontext *ctx, GLenum dstTarget,
1284 const GLubyte *str, GLsizei len,
Brian Paul122629f2006-07-20 16:49:57 +00001285 struct gl_vertex_program *program)
Michal Krol2861e732004-03-29 11:09:34 +00001286{
1287 struct parse_state parseState;
Brian Paul7e807512005-11-05 17:10:45 +00001288 struct prog_instruction instBuffer[MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS];
1289 struct prog_instruction *newInst;
Michal Krol2861e732004-03-29 11:09:34 +00001290 GLenum target;
1291 GLubyte *programString;
1292
1293 /* Make a null-terminated copy of the program string */
1294 programString = (GLubyte *) MALLOC(len + 1);
1295 if (!programString) {
1296 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
1297 return;
1298 }
1299 MEMCPY(programString, str, len);
1300 programString[len] = 0;
1301
1302 /* Get ready to parse */
1303 parseState.ctx = ctx;
1304 parseState.start = programString;
1305 parseState.isPositionInvariant = GL_FALSE;
1306 parseState.isVersion1_1 = GL_FALSE;
1307 parseState.numInst = 0;
1308 parseState.inputsRead = 0;
1309 parseState.outputsWritten = 0;
1310 parseState.anyProgRegsWritten = GL_FALSE;
1311
1312 /* Reset error state */
1313 _mesa_set_program_error(ctx, -1, NULL);
1314
1315 /* check the program header */
1316 if (_mesa_strncmp((const char *) programString, "!!VP1.0", 7) == 0) {
1317 target = GL_VERTEX_PROGRAM_NV;
1318 parseState.pos = programString + 7;
1319 parseState.isStateProgram = GL_FALSE;
1320 }
1321 else if (_mesa_strncmp((const char *) programString, "!!VP1.1", 7) == 0) {
1322 target = GL_VERTEX_PROGRAM_NV;
1323 parseState.pos = programString + 7;
1324 parseState.isStateProgram = GL_FALSE;
1325 parseState.isVersion1_1 = GL_TRUE;
1326 }
1327 else if (_mesa_strncmp((const char *) programString, "!!VSP1.0", 8) == 0) {
1328 target = GL_VERTEX_STATE_PROGRAM_NV;
1329 parseState.pos = programString + 8;
1330 parseState.isStateProgram = GL_TRUE;
1331 }
1332 else {
1333 /* invalid header */
1334 ctx->Program.ErrorPos = 0;
1335 _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(bad header)");
1336 return;
1337 }
1338
1339 /* make sure target and header match */
1340 if (target != dstTarget) {
1341 _mesa_error(ctx, GL_INVALID_OPERATION,
1342 "glLoadProgramNV(target mismatch)");
1343 return;
1344 }
1345
1346
1347 if (Parse_Program(&parseState, instBuffer)) {
1348 /* successful parse! */
1349
1350 if (parseState.isStateProgram) {
1351 if (!parseState.anyProgRegsWritten) {
1352 _mesa_error(ctx, GL_INVALID_OPERATION,
1353 "glLoadProgramNV(c[#] not written)");
1354 return;
1355 }
1356 }
1357 else {
1358 if (!parseState.isPositionInvariant &&
Brian Paulf6de8652006-08-30 23:36:52 +00001359 !(parseState.outputsWritten & (1 << VERT_RESULT_HPOS))) {
Michal Krol2861e732004-03-29 11:09:34 +00001360 /* bit 1 = HPOS register */
1361 _mesa_error(ctx, GL_INVALID_OPERATION,
1362 "glLoadProgramNV(HPOS not written)");
1363 return;
1364 }
1365 }
1366
1367 /* copy the compiled instructions */
1368 assert(parseState.numInst <= MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS);
Brian Paul383c39e2006-08-25 15:14:25 +00001369 newInst = _mesa_alloc_instructions(parseState.numInst);
Michal Krol2861e732004-03-29 11:09:34 +00001370 if (!newInst) {
1371 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
Brian Paulde997602005-11-12 17:53:14 +00001372 _mesa_free(programString);
Michal Krol2861e732004-03-29 11:09:34 +00001373 return; /* out of memory */
1374 }
Brian12229f12007-03-22 09:11:26 -06001375 _mesa_copy_instructions(newInst, instBuffer, parseState.numInst);
Michal Krol2861e732004-03-29 11:09:34 +00001376
1377 /* install the program */
1378 program->Base.Target = target;
1379 if (program->Base.String) {
Brian Paulde997602005-11-12 17:53:14 +00001380 _mesa_free(program->Base.String);
Michal Krol2861e732004-03-29 11:09:34 +00001381 }
1382 program->Base.String = programString;
1383 program->Base.Format = GL_PROGRAM_FORMAT_ASCII_ARB;
Brian Paulde997602005-11-12 17:53:14 +00001384 if (program->Base.Instructions) {
1385 _mesa_free(program->Base.Instructions);
Michal Krol2861e732004-03-29 11:09:34 +00001386 }
Brian Paulde997602005-11-12 17:53:14 +00001387 program->Base.Instructions = newInst;
1388 program->Base.InputsRead = parseState.inputsRead;
Brian Paulfe694702006-10-10 21:23:23 +00001389 if (parseState.isPositionInvariant)
1390 program->Base.InputsRead |= VERT_BIT_POS;
Brian Paulee40c4fb32006-02-15 15:59:37 +00001391 program->Base.NumInstructions = parseState.numInst;
Brian Paulde997602005-11-12 17:53:14 +00001392 program->Base.OutputsWritten = parseState.outputsWritten;
Michal Krol2861e732004-03-29 11:09:34 +00001393 program->IsPositionInvariant = parseState.isPositionInvariant;
Brian Paul05a6f2f2004-04-21 18:09:14 +00001394 program->IsNVProgram = GL_TRUE;
Michal Krol2861e732004-03-29 11:09:34 +00001395
Brian Paul2a5afe32004-12-18 16:18:00 +00001396#ifdef DEBUG_foo
Michal Krol2861e732004-03-29 11:09:34 +00001397 _mesa_printf("--- glLoadProgramNV result ---\n");
Brian Paulfe278f12009-04-14 19:53:37 -06001398 _mesa_fprint_program_opt(stdout, &program->Base, PROG_PRINT_NV, 0);
Michal Krol2861e732004-03-29 11:09:34 +00001399 _mesa_printf("------------------------------\n");
1400#endif
1401 }
1402 else {
1403 /* Error! */
1404 _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV");
1405 /* NOTE: _mesa_set_program_error would have been called already */
1406 /* GL_NV_vertex_program isn't supposed to set the error string
1407 * so we reset it here.
1408 */
1409 _mesa_set_program_error(ctx, ctx->Program.ErrorPos, NULL);
1410 }
1411}
1412
1413
Michal Krol2861e732004-03-29 11:09:34 +00001414const char *
1415_mesa_nv_vertex_input_register_name(GLuint i)
1416{
1417 ASSERT(i < MAX_NV_VERTEX_PROGRAM_INPUTS);
1418 return InputRegisters[i];
1419}
1420
1421
1422const char *
1423_mesa_nv_vertex_output_register_name(GLuint i)
1424{
1425 ASSERT(i < MAX_NV_VERTEX_PROGRAM_OUTPUTS);
1426 return OutputRegisters[i];
1427}
Brian Paul7aebaf32005-10-30 21:23:23 +00001428