blob: fd880dc007da95135eeae6728370a50f49504e95 [file] [log] [blame]
Michal Krol2861e732004-03-29 11:09:34 +00001/*
2 * Mesa 3-D graphics library
Brian Paul7e807512005-11-05 17:10:45 +00003 * Version: 6.5
Michal Krol2861e732004-03-29 11:09:34 +00004 *
Brian Paul7e807512005-11-05 17:10:45 +00005 * Copyright (C) 1999-2005 Brian Paul All Rights Reserved.
Michal Krol2861e732004-03-29 11:09:34 +00006 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25/**
26 * \file nvvertparse.c
27 * NVIDIA vertex program parser.
28 * \author Brian Paul
29 */
30
31/*
32 * Regarding GL_NV_vertex_program, GL_NV_vertex_program1_1:
33 *
34 * Portions of this software may use or implement intellectual
35 * property owned and licensed by NVIDIA Corporation. NVIDIA disclaims
36 * any and all warranties with respect to such intellectual property,
37 * including any use thereof or modifications thereto.
38 */
39
40#include "glheader.h"
41#include "context.h"
42#include "hash.h"
43#include "imports.h"
44#include "macros.h"
45#include "mtypes.h"
46#include "nvprogram.h"
47#include "nvvertparse.h"
Brian Paul7e807512005-11-05 17:10:45 +000048#include "program_instruction.h"
Michal Krol2861e732004-03-29 11:09:34 +000049#include "program.h"
50
51
52/**
53 * Current parsing state. This structure is passed among the parsing
54 * functions and keeps track of the current parser position and various
55 * program attributes.
56 */
57struct parse_state {
58 GLcontext *ctx;
59 const GLubyte *start;
60 const GLubyte *pos;
61 const GLubyte *curLine;
62 GLboolean isStateProgram;
63 GLboolean isPositionInvariant;
64 GLboolean isVersion1_1;
65 GLuint inputsRead;
66 GLuint outputsWritten;
67 GLboolean anyProgRegsWritten;
68 GLuint numInst; /* number of instructions parsed */
69};
70
71
72/*
73 * Called whenever we find an error during parsing.
74 */
75static void
76record_error(struct parse_state *parseState, const char *msg, int lineNo)
77{
78#ifdef DEBUG
79 GLint line, column;
80 const GLubyte *lineStr;
81 lineStr = _mesa_find_line_column(parseState->start,
82 parseState->pos, &line, &column);
83 _mesa_debug(parseState->ctx,
84 "nvfragparse.c(%d): line %d, column %d:%s (%s)\n",
85 lineNo, line, column, (char *) lineStr, msg);
86 _mesa_free((void *) lineStr);
87#else
88 (void) lineNo;
89#endif
90
91 /* Check that no error was already recorded. Only record the first one. */
92 if (parseState->ctx->Program.ErrorString[0] == 0) {
93 _mesa_set_program_error(parseState->ctx,
94 parseState->pos - parseState->start,
95 msg);
96 }
97}
98
99
100#define RETURN_ERROR \
101do { \
102 record_error(parseState, "Unexpected end of input.", __LINE__); \
103 return GL_FALSE; \
104} while(0)
105
106#define RETURN_ERROR1(msg) \
107do { \
108 record_error(parseState, msg, __LINE__); \
109 return GL_FALSE; \
110} while(0)
111
112#define RETURN_ERROR2(msg1, msg2) \
113do { \
114 char err[1000]; \
115 _mesa_sprintf(err, "%s %s", msg1, msg2); \
116 record_error(parseState, err, __LINE__); \
117 return GL_FALSE; \
118} while(0)
119
120
121
122
123
124static GLboolean IsLetter(GLubyte b)
125{
126 return (b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z');
127}
128
129
130static GLboolean IsDigit(GLubyte b)
131{
132 return b >= '0' && b <= '9';
133}
134
135
136static GLboolean IsWhitespace(GLubyte b)
137{
138 return b == ' ' || b == '\t' || b == '\n' || b == '\r';
139}
140
141
142/**
143 * Starting at 'str' find the next token. A token can be an integer,
144 * an identifier or punctuation symbol.
145 * \return <= 0 we found an error, else, return number of characters parsed.
146 */
147static GLint
148GetToken(struct parse_state *parseState, GLubyte *token)
149{
150 const GLubyte *str = parseState->pos;
151 GLint i = 0, j = 0;
152
153 token[0] = 0;
154
155 /* skip whitespace and comments */
156 while (str[i] && (IsWhitespace(str[i]) || str[i] == '#')) {
157 if (str[i] == '#') {
158 /* skip comment */
159 while (str[i] && (str[i] != '\n' && str[i] != '\r')) {
160 i++;
161 }
162 if (str[i] == '\n' || str[i] == '\r')
163 parseState->curLine = str + i + 1;
164 }
165 else {
166 /* skip whitespace */
167 if (str[i] == '\n' || str[i] == '\r')
168 parseState->curLine = str + i + 1;
169 i++;
170 }
171 }
172
173 if (str[i] == 0)
174 return -i;
175
176 /* try matching an integer */
177 while (str[i] && IsDigit(str[i])) {
178 token[j++] = str[i++];
179 }
180 if (j > 0 || !str[i]) {
181 token[j] = 0;
182 return i;
183 }
184
185 /* try matching an identifier */
186 if (IsLetter(str[i])) {
187 while (str[i] && (IsLetter(str[i]) || IsDigit(str[i]))) {
188 token[j++] = str[i++];
189 }
190 token[j] = 0;
191 return i;
192 }
193
194 /* punctuation character */
195 if (str[i]) {
196 token[0] = str[i++];
197 token[1] = 0;
198 return i;
199 }
200
201 /* end of input */
202 token[0] = 0;
203 return i;
204}
205
206
207/**
208 * Get next token from input stream and increment stream pointer past token.
209 */
210static GLboolean
211Parse_Token(struct parse_state *parseState, GLubyte *token)
212{
213 GLint i;
214 i = GetToken(parseState, token);
215 if (i <= 0) {
216 parseState->pos += (-i);
217 return GL_FALSE;
218 }
219 parseState->pos += i;
220 return GL_TRUE;
221}
222
223
224/**
225 * Get next token from input stream but don't increment stream pointer.
226 */
227static GLboolean
228Peek_Token(struct parse_state *parseState, GLubyte *token)
229{
230 GLint i, len;
231 i = GetToken(parseState, token);
232 if (i <= 0) {
233 parseState->pos += (-i);
234 return GL_FALSE;
235 }
Karl Schultz6258b762005-05-05 21:08:07 +0000236 len = (GLint)_mesa_strlen((const char *) token);
Michal Krol2861e732004-03-29 11:09:34 +0000237 parseState->pos += (i - len);
238 return GL_TRUE;
239}
240
241
242/**
243 * Try to match 'pattern' as the next token after any whitespace/comments.
244 * Advance the current parsing position only if we match the pattern.
245 * \return GL_TRUE if pattern is matched, GL_FALSE otherwise.
246 */
247static GLboolean
248Parse_String(struct parse_state *parseState, const char *pattern)
249{
250 const GLubyte *m;
251 GLint i;
252
253 /* skip whitespace and comments */
254 while (IsWhitespace(*parseState->pos) || *parseState->pos == '#') {
255 if (*parseState->pos == '#') {
256 while (*parseState->pos && (*parseState->pos != '\n' && *parseState->pos != '\r')) {
257 parseState->pos += 1;
258 }
259 if (*parseState->pos == '\n' || *parseState->pos == '\r')
260 parseState->curLine = parseState->pos + 1;
261 }
262 else {
263 /* skip whitespace */
264 if (*parseState->pos == '\n' || *parseState->pos == '\r')
265 parseState->curLine = parseState->pos + 1;
266 parseState->pos += 1;
267 }
268 }
269
270 /* Try to match the pattern */
271 m = parseState->pos;
272 for (i = 0; pattern[i]; i++) {
273 if (*m != (GLubyte) pattern[i])
274 return GL_FALSE;
275 m += 1;
276 }
277 parseState->pos = m;
278
279 return GL_TRUE; /* success */
280}
281
282
283/**********************************************************************/
284
285static const char *InputRegisters[MAX_NV_VERTEX_PROGRAM_INPUTS + 1] = {
286 "OPOS", "WGHT", "NRML", "COL0", "COL1", "FOGC", "6", "7",
287 "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", NULL
288};
289
290static const char *OutputRegisters[MAX_NV_VERTEX_PROGRAM_OUTPUTS + 1] = {
Keith Whitwellc3626a92005-11-01 17:25:49 +0000291 "HPOS", "COL0", "COL1", "FOGC",
292 "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7",
293 "PSIZ", "BFC0", "BFC1", NULL
Michal Krol2861e732004-03-29 11:09:34 +0000294};
295
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 Paul7e807512005-11-05 17:10:45 +0000645 srcReg->NegateBase = GL_TRUE;
Michal Krol2861e732004-03-29 11:09:34 +0000646 if (!Peek_Token(parseState, token))
647 RETURN_ERROR;
648 }
649 else {
Brian Paul7e807512005-11-05 17:10:45 +0000650 srcReg->NegateBase = GL_FALSE;
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;
702 for (k = 0; token[k] && k < 5; k++) {
703 if (token[k] == 'x')
Keith Whitwell7c26b612005-04-21 14:46:57 +0000704 srcReg->Swizzle |= 0 << (k*3);
Michal Krol2861e732004-03-29 11:09:34 +0000705 else if (token[k] == 'y')
Keith Whitwell7c26b612005-04-21 14:46:57 +0000706 srcReg->Swizzle |= 1 << (k*3);
Michal Krol2861e732004-03-29 11:09:34 +0000707 else if (token[k] == 'z')
Keith Whitwell7c26b612005-04-21 14:46:57 +0000708 srcReg->Swizzle |= 2 << (k*3);
Michal Krol2861e732004-03-29 11:09:34 +0000709 else if (token[k] == 'w')
Keith Whitwell7c26b612005-04-21 14:46:57 +0000710 srcReg->Swizzle |= 3 << (k*3);
Michal Krol2861e732004-03-29 11:09:34 +0000711 else
712 RETURN_ERROR;
713 }
714 if (k >= 5)
715 RETURN_ERROR;
716 }
717 }
718
719 return GL_TRUE;
720}
721
722
723static GLboolean
Brian Paul7e807512005-11-05 17:10:45 +0000724Parse_ScalarSrcReg(struct parse_state *parseState, struct prog_src_register *srcReg)
Michal Krol2861e732004-03-29 11:09:34 +0000725{
726 GLubyte token[100];
Keith Whitwell7c26b612005-04-21 14:46:57 +0000727 GLint idx;
Michal Krol2861e732004-03-29 11:09:34 +0000728
729 srcReg->RelAddr = GL_FALSE;
730
731 /* check for '-' */
732 if (!Peek_Token(parseState, token))
733 RETURN_ERROR;
734 if (token[0] == '-') {
Brian Paul7e807512005-11-05 17:10:45 +0000735 srcReg->NegateBase = GL_TRUE;
Michal Krol2861e732004-03-29 11:09:34 +0000736 (void) Parse_String(parseState, "-"); /* consume '-' */
737 if (!Peek_Token(parseState, token))
738 RETURN_ERROR;
739 }
740 else {
Brian Paul7e807512005-11-05 17:10:45 +0000741 srcReg->NegateBase = GL_FALSE;
Michal Krol2861e732004-03-29 11:09:34 +0000742 }
743
744 /* Src reg can be R<n>, c[n], c[n +/- offset], or a named vertex attrib */
745 if (token[0] == 'R') {
746 srcReg->File = PROGRAM_TEMPORARY;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000747 if (!Parse_TempReg(parseState, &idx))
Michal Krol2861e732004-03-29 11:09:34 +0000748 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000749 srcReg->Index = idx;
Michal Krol2861e732004-03-29 11:09:34 +0000750 }
751 else if (token[0] == 'c') {
752 if (!Parse_ParamReg(parseState, srcReg))
753 RETURN_ERROR;
754 }
755 else if (token[0] == 'v') {
756 srcReg->File = PROGRAM_INPUT;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000757 if (!Parse_AttribReg(parseState, &idx))
Michal Krol2861e732004-03-29 11:09:34 +0000758 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000759 srcReg->Index = idx;
Michal Krol2861e732004-03-29 11:09:34 +0000760 }
761 else {
762 RETURN_ERROR2("Bad source register name", token);
763 }
764
765 /* Look for .[xyzw] suffix */
766 if (!Parse_String(parseState, "."))
767 RETURN_ERROR;
768
769 if (!Parse_Token(parseState, token))
770 RETURN_ERROR;
771
772 if (token[0] == 'x' && token[1] == 0) {
Keith Whitwell7c26b612005-04-21 14:46:57 +0000773 srcReg->Swizzle = 0;
Michal Krol2861e732004-03-29 11:09:34 +0000774 }
775 else if (token[0] == 'y' && token[1] == 0) {
Keith Whitwell7c26b612005-04-21 14:46:57 +0000776 srcReg->Swizzle = 1;
Michal Krol2861e732004-03-29 11:09:34 +0000777 }
778 else if (token[0] == 'z' && token[1] == 0) {
Keith Whitwell7c26b612005-04-21 14:46:57 +0000779 srcReg->Swizzle = 2;
Michal Krol2861e732004-03-29 11:09:34 +0000780 }
781 else if (token[0] == 'w' && token[1] == 0) {
Keith Whitwell7c26b612005-04-21 14:46:57 +0000782 srcReg->Swizzle = 3;
Michal Krol2861e732004-03-29 11:09:34 +0000783 }
784 else {
785 RETURN_ERROR1("Bad scalar source suffix");
786 }
Michal Krol2861e732004-03-29 11:09:34 +0000787
788 return GL_TRUE;
789}
790
791
792static GLint
793Parse_UnaryOpInstruction(struct parse_state *parseState,
Brian Paul7e807512005-11-05 17:10:45 +0000794 struct prog_instruction *inst,
795 enum prog_opcode opcode)
Michal Krol2861e732004-03-29 11:09:34 +0000796{
Brian Paul7e807512005-11-05 17:10:45 +0000797 if (opcode == OPCODE_ABS && !parseState->isVersion1_1)
Michal Krol2861e732004-03-29 11:09:34 +0000798 RETURN_ERROR1("ABS illegal for vertex program 1.0");
799
800 inst->Opcode = opcode;
801 inst->StringPos = parseState->curLine - parseState->start;
802
803 /* dest reg */
804 if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
805 RETURN_ERROR;
806
807 /* comma */
808 if (!Parse_String(parseState, ","))
809 RETURN_ERROR;
810
811 /* src arg */
812 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[0]))
813 RETURN_ERROR;
814
815 /* semicolon */
816 if (!Parse_String(parseState, ";"))
817 RETURN_ERROR;
818
819 return GL_TRUE;
820}
821
822
823static GLboolean
824Parse_BiOpInstruction(struct parse_state *parseState,
Brian Paul7e807512005-11-05 17:10:45 +0000825 struct prog_instruction *inst,
826 enum prog_opcode opcode)
Michal Krol2861e732004-03-29 11:09:34 +0000827{
Brian Paul7e807512005-11-05 17:10:45 +0000828 if (opcode == OPCODE_DPH && !parseState->isVersion1_1)
Michal Krol2861e732004-03-29 11:09:34 +0000829 RETURN_ERROR1("DPH illegal for vertex program 1.0");
Brian Paul7e807512005-11-05 17:10:45 +0000830 if (opcode == OPCODE_SUB && !parseState->isVersion1_1)
Michal Krol2861e732004-03-29 11:09:34 +0000831 RETURN_ERROR1("SUB illegal for vertex program 1.0");
832
833 inst->Opcode = opcode;
834 inst->StringPos = parseState->curLine - parseState->start;
835
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;
882 inst->StringPos = parseState->curLine - parseState->start;
883
884 /* dest reg */
885 if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
886 RETURN_ERROR;
887
888 /* comma */
889 if (!Parse_String(parseState, ","))
890 RETURN_ERROR;
891
892 /* first src arg */
893 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[0]))
894 RETURN_ERROR;
895
896 /* comma */
897 if (!Parse_String(parseState, ","))
898 RETURN_ERROR;
899
900 /* second src arg */
901 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[1]))
902 RETURN_ERROR;
903
904 /* comma */
905 if (!Parse_String(parseState, ","))
906 RETURN_ERROR;
907
908 /* third src arg */
909 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[2]))
910 RETURN_ERROR;
911
912 /* semicolon */
913 if (!Parse_String(parseState, ";"))
914 RETURN_ERROR;
915
916 /* make sure we don't reference more than one program parameter register */
917 if ((inst->SrcReg[0].File == PROGRAM_ENV_PARAM &&
918 inst->SrcReg[1].File == PROGRAM_ENV_PARAM &&
919 inst->SrcReg[0].Index != inst->SrcReg[1].Index) ||
920 (inst->SrcReg[0].File == PROGRAM_ENV_PARAM &&
921 inst->SrcReg[2].File == PROGRAM_ENV_PARAM &&
922 inst->SrcReg[0].Index != inst->SrcReg[2].Index) ||
923 (inst->SrcReg[1].File == PROGRAM_ENV_PARAM &&
924 inst->SrcReg[2].File == PROGRAM_ENV_PARAM &&
925 inst->SrcReg[1].Index != inst->SrcReg[2].Index))
926 RETURN_ERROR1("Can only reference one program register");
927
928 /* make sure we don't reference more than one vertex attribute register */
929 if ((inst->SrcReg[0].File == PROGRAM_INPUT &&
930 inst->SrcReg[1].File == PROGRAM_INPUT &&
931 inst->SrcReg[0].Index != inst->SrcReg[1].Index) ||
932 (inst->SrcReg[0].File == PROGRAM_INPUT &&
933 inst->SrcReg[2].File == PROGRAM_INPUT &&
934 inst->SrcReg[0].Index != inst->SrcReg[2].Index) ||
935 (inst->SrcReg[1].File == PROGRAM_INPUT &&
936 inst->SrcReg[2].File == PROGRAM_INPUT &&
937 inst->SrcReg[1].Index != inst->SrcReg[2].Index))
938 RETURN_ERROR1("Can only reference one input register");
939
940 return GL_TRUE;
941}
942
943
944static GLboolean
945Parse_ScalarInstruction(struct parse_state *parseState,
Brian Paul7e807512005-11-05 17:10:45 +0000946 struct prog_instruction *inst,
947 enum prog_opcode opcode)
Michal Krol2861e732004-03-29 11:09:34 +0000948{
Brian Paul7e807512005-11-05 17:10:45 +0000949 if (opcode == OPCODE_RCC && !parseState->isVersion1_1)
Michal Krol2861e732004-03-29 11:09:34 +0000950 RETURN_ERROR1("RCC illegal for vertex program 1.0");
951
952 inst->Opcode = opcode;
953 inst->StringPos = parseState->curLine - parseState->start;
954
955 /* dest reg */
956 if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
957 RETURN_ERROR;
958
959 /* comma */
960 if (!Parse_String(parseState, ","))
961 RETURN_ERROR;
962
963 /* first src arg */
964 if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0]))
965 RETURN_ERROR;
966
967 /* semicolon */
968 if (!Parse_String(parseState, ";"))
969 RETURN_ERROR;
970
971 return GL_TRUE;
972}
973
974
975static GLboolean
Brian Paul7e807512005-11-05 17:10:45 +0000976Parse_AddressInstruction(struct parse_state *parseState, struct prog_instruction *inst)
Michal Krol2861e732004-03-29 11:09:34 +0000977{
Brian Paul7e807512005-11-05 17:10:45 +0000978 inst->Opcode = OPCODE_ARL;
Michal Krol2861e732004-03-29 11:09:34 +0000979 inst->StringPos = parseState->curLine - parseState->start;
980
981 /* dest A0 reg */
982 if (!Parse_AddrReg(parseState))
983 RETURN_ERROR;
984
985 /* comma */
986 if (!Parse_String(parseState, ","))
987 RETURN_ERROR;
988
989 /* parse src reg */
990 if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0]))
991 RETURN_ERROR;
992
993 /* semicolon */
994 if (!Parse_String(parseState, ";"))
995 RETURN_ERROR;
996
997 return GL_TRUE;
998}
999
1000
1001static GLboolean
Brian Paul7e807512005-11-05 17:10:45 +00001002Parse_EndInstruction(struct parse_state *parseState, struct prog_instruction *inst)
Michal Krol2861e732004-03-29 11:09:34 +00001003{
1004 GLubyte token[100];
1005
Brian Paul7e807512005-11-05 17:10:45 +00001006 inst->Opcode = OPCODE_END;
Michal Krol2861e732004-03-29 11:09:34 +00001007 inst->StringPos = parseState->curLine - parseState->start;
1008
1009 /* this should fail! */
1010 if (Parse_Token(parseState, token))
1011 RETURN_ERROR2("Unexpected token after END:", token);
1012 else
1013 return GL_TRUE;
1014}
1015
1016
Brian Paul575700f2004-12-16 03:07:18 +00001017/**
1018 * The PRINT instruction is Mesa-specific and is meant as a debugging aid for
1019 * the vertex program developer.
1020 * The NV_vertex_program extension grammar is modified as follows:
1021 *
1022 * <instruction> ::= <ARL-instruction>
1023 * | ...
1024 * | <PRINT-instruction>
1025 *
1026 * <PRINT-instruction> ::= "PRINT" <string literal>
1027 * | "PRINT" <string literal> "," <srcReg>
1028 * | "PRINT" <string literal> "," <dstReg>
1029 */
1030static GLboolean
Brian Paul7e807512005-11-05 17:10:45 +00001031Parse_PrintInstruction(struct parse_state *parseState, struct prog_instruction *inst)
Brian Paul575700f2004-12-16 03:07:18 +00001032{
1033 const GLubyte *str;
1034 GLubyte *msg;
1035 GLuint len;
1036 GLubyte token[100];
Brian Paul7e807512005-11-05 17:10:45 +00001037 struct prog_src_register *srcReg = &inst->SrcReg[0];
Keith Whitwell7c26b612005-04-21 14:46:57 +00001038 GLint idx;
Brian Paul575700f2004-12-16 03:07:18 +00001039
Brian Paul7e807512005-11-05 17:10:45 +00001040 inst->Opcode = OPCODE_PRINT;
Brian Paul575700f2004-12-16 03:07:18 +00001041 inst->StringPos = parseState->curLine - parseState->start;
1042
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;
1051 msg = _mesa_malloc(len + 1);
1052
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 Paul7e807512005-11-05 17:10:45 +00001065 srcReg->NegateBase = GL_FALSE;
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 Paul7e807512005-11-05 17:10:45 +00001138 _mesa_init_instruction(inst);
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,
1285 struct vertex_program *program)
1286{
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 &&
1359 !(parseState.outputsWritten & 1)) {
1360 /* 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 Paul7e807512005-11-05 17:10:45 +00001369 newInst = (struct prog_instruction *)
1370 MALLOC(parseState.numInst * sizeof(struct prog_instruction));
Michal Krol2861e732004-03-29 11:09:34 +00001371 if (!newInst) {
1372 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
1373 FREE(programString);
1374 return; /* out of memory */
1375 }
1376 MEMCPY(newInst, instBuffer,
Brian Paul7e807512005-11-05 17:10:45 +00001377 parseState.numInst * sizeof(struct prog_instruction));
Michal Krol2861e732004-03-29 11:09:34 +00001378
1379 /* install the program */
1380 program->Base.Target = target;
1381 if (program->Base.String) {
1382 FREE(program->Base.String);
1383 }
1384 program->Base.String = programString;
1385 program->Base.Format = GL_PROGRAM_FORMAT_ASCII_ARB;
1386 if (program->Instructions) {
1387 FREE(program->Instructions);
1388 }
1389 program->Instructions = newInst;
1390 program->InputsRead = parseState.inputsRead;
1391 program->OutputsWritten = parseState.outputsWritten;
1392 program->IsPositionInvariant = parseState.isPositionInvariant;
Brian Paul05a6f2f2004-04-21 18:09:14 +00001393 program->IsNVProgram = GL_TRUE;
Michal Krol2861e732004-03-29 11:09:34 +00001394
Brian Paul2a5afe32004-12-18 16:18:00 +00001395#ifdef DEBUG_foo
Michal Krol2861e732004-03-29 11:09:34 +00001396 _mesa_printf("--- glLoadProgramNV result ---\n");
1397 _mesa_print_nv_vertex_program(program);
1398 _mesa_printf("------------------------------\n");
1399#endif
1400 }
1401 else {
1402 /* Error! */
1403 _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV");
1404 /* NOTE: _mesa_set_program_error would have been called already */
1405 /* GL_NV_vertex_program isn't supposed to set the error string
1406 * so we reset it here.
1407 */
1408 _mesa_set_program_error(ctx, ctx->Program.ErrorPos, NULL);
1409 }
1410}
1411
1412
1413static void
Brian Paul7e807512005-11-05 17:10:45 +00001414PrintSrcReg(const struct prog_src_register *src)
Michal Krol2861e732004-03-29 11:09:34 +00001415{
1416 static const char comps[5] = "xyzw";
Brian Paul7e807512005-11-05 17:10:45 +00001417 if (src->NegateBase)
Michal Krol2861e732004-03-29 11:09:34 +00001418 _mesa_printf("-");
1419 if (src->RelAddr) {
1420 if (src->Index > 0)
1421 _mesa_printf("c[A0.x + %d]", src->Index);
1422 else if (src->Index < 0)
1423 _mesa_printf("c[A0.x - %d]", -src->Index);
1424 else
1425 _mesa_printf("c[A0.x]");
1426 }
1427 else if (src->File == PROGRAM_OUTPUT) {
1428 _mesa_printf("o[%s]", OutputRegisters[src->Index]);
1429 }
1430 else if (src->File == PROGRAM_INPUT) {
1431 _mesa_printf("v[%s]", InputRegisters[src->Index]);
1432 }
1433 else if (src->File == PROGRAM_ENV_PARAM) {
1434 _mesa_printf("c[%d]", src->Index);
1435 }
1436 else {
1437 ASSERT(src->File == PROGRAM_TEMPORARY);
1438 _mesa_printf("R%d", src->Index);
1439 }
1440
Keith Whitwell7c26b612005-04-21 14:46:57 +00001441 if (GET_SWZ(src->Swizzle, 0) == GET_SWZ(src->Swizzle, 1) &&
1442 GET_SWZ(src->Swizzle, 0) == GET_SWZ(src->Swizzle, 2) &&
1443 GET_SWZ(src->Swizzle, 0) == GET_SWZ(src->Swizzle, 3)) {
1444 _mesa_printf(".%c", comps[GET_SWZ(src->Swizzle, 0)]);
Michal Krol2861e732004-03-29 11:09:34 +00001445 }
Keith Whitwell7c26b612005-04-21 14:46:57 +00001446 else if (src->Swizzle != SWIZZLE_NOOP) {
Michal Krol2861e732004-03-29 11:09:34 +00001447 _mesa_printf(".%c%c%c%c",
Keith Whitwell7c26b612005-04-21 14:46:57 +00001448 comps[GET_SWZ(src->Swizzle, 0)],
1449 comps[GET_SWZ(src->Swizzle, 1)],
1450 comps[GET_SWZ(src->Swizzle, 2)],
1451 comps[GET_SWZ(src->Swizzle, 3)]);
Michal Krol2861e732004-03-29 11:09:34 +00001452 }
1453}
1454
1455
1456static void
Brian Paul7e807512005-11-05 17:10:45 +00001457PrintDstReg(const struct prog_dst_register *dst)
Michal Krol2861e732004-03-29 11:09:34 +00001458{
Michal Krol2861e732004-03-29 11:09:34 +00001459 if (dst->File == PROGRAM_OUTPUT) {
1460 _mesa_printf("o[%s]", OutputRegisters[dst->Index]);
1461 }
1462 else if (dst->File == PROGRAM_INPUT) {
1463 _mesa_printf("v[%s]", InputRegisters[dst->Index]);
1464 }
1465 else if (dst->File == PROGRAM_ENV_PARAM) {
1466 _mesa_printf("c[%d]", dst->Index);
1467 }
1468 else {
1469 ASSERT(dst->File == PROGRAM_TEMPORARY);
1470 _mesa_printf("R%d", dst->Index);
1471 }
1472
Brian Paulccfe3d42005-11-03 02:35:15 +00001473 if (dst->WriteMask != 0 && dst->WriteMask != WRITEMASK_XYZW) {
Michal Krol2861e732004-03-29 11:09:34 +00001474 _mesa_printf(".");
Brian Paulccfe3d42005-11-03 02:35:15 +00001475 if (dst->WriteMask & WRITEMASK_X)
Michal Krol2861e732004-03-29 11:09:34 +00001476 _mesa_printf("x");
Brian Paulccfe3d42005-11-03 02:35:15 +00001477 if (dst->WriteMask & WRITEMASK_Y)
Michal Krol2861e732004-03-29 11:09:34 +00001478 _mesa_printf("y");
Brian Paulccfe3d42005-11-03 02:35:15 +00001479 if (dst->WriteMask & WRITEMASK_Z)
Michal Krol2861e732004-03-29 11:09:34 +00001480 _mesa_printf("z");
Brian Paulccfe3d42005-11-03 02:35:15 +00001481 if (dst->WriteMask & WRITEMASK_W)
Michal Krol2861e732004-03-29 11:09:34 +00001482 _mesa_printf("w");
1483 }
1484}
1485
1486
1487/**
1488 * Print a single NVIDIA vertex program instruction.
1489 */
1490void
Brian Paul7e807512005-11-05 17:10:45 +00001491_mesa_print_nv_vertex_instruction(const struct prog_instruction *inst)
Michal Krol2861e732004-03-29 11:09:34 +00001492{
Brian Paulb7c87972005-11-05 19:24:08 +00001493 GLuint i, n;
1494
Michal Krol2861e732004-03-29 11:09:34 +00001495 switch (inst->Opcode) {
Brian Paul7e807512005-11-05 17:10:45 +00001496 case OPCODE_MOV:
1497 case OPCODE_LIT:
1498 case OPCODE_RCP:
1499 case OPCODE_RSQ:
1500 case OPCODE_EXP:
1501 case OPCODE_LOG:
1502 case OPCODE_RCC:
1503 case OPCODE_ABS:
Brian Paul7e807512005-11-05 17:10:45 +00001504 case OPCODE_MUL:
1505 case OPCODE_ADD:
1506 case OPCODE_DP3:
1507 case OPCODE_DP4:
1508 case OPCODE_DST:
1509 case OPCODE_MIN:
1510 case OPCODE_MAX:
1511 case OPCODE_SLT:
1512 case OPCODE_SGE:
1513 case OPCODE_DPH:
1514 case OPCODE_SUB:
Brian Paul7e807512005-11-05 17:10:45 +00001515 case OPCODE_MAD:
Brian Paulb7c87972005-11-05 19:24:08 +00001516 _mesa_printf("%s ", _mesa_opcode_string(inst->Opcode));
Michal Krol2861e732004-03-29 11:09:34 +00001517 PrintDstReg(&inst->DstReg);
1518 _mesa_printf(", ");
Brian Paulb7c87972005-11-05 19:24:08 +00001519 n = _mesa_num_inst_src_regs(inst->Opcode);
1520 for (i = 0; i < n; i++) {
1521 PrintSrcReg(&inst->SrcReg[i]);
1522 if (i + 1 < n)
1523 _mesa_printf(", ");
1524 }
Michal Krol2861e732004-03-29 11:09:34 +00001525 _mesa_printf(";\n");
1526 break;
Brian Paul7e807512005-11-05 17:10:45 +00001527 case OPCODE_ARL:
Michal Krol2861e732004-03-29 11:09:34 +00001528 _mesa_printf("ARL A0.x, ");
1529 PrintSrcReg(&inst->SrcReg[0]);
1530 _mesa_printf(";\n");
1531 break;
Brian Paul7e807512005-11-05 17:10:45 +00001532 case OPCODE_PRINT:
Brian Paul575700f2004-12-16 03:07:18 +00001533 _mesa_printf("PRINT '%s'", inst->Data);
1534 if (inst->SrcReg[0].File) {
1535 _mesa_printf(", ");
1536 PrintSrcReg(&inst->SrcReg[0]);
1537 _mesa_printf(";\n");
1538 }
1539 else {
1540 _mesa_printf("\n");
1541 }
1542 break;
Brian Paul7e807512005-11-05 17:10:45 +00001543 case OPCODE_END:
Michal Krol2861e732004-03-29 11:09:34 +00001544 _mesa_printf("END\n");
1545 break;
1546 default:
1547 _mesa_printf("BAD INSTRUCTION\n");
1548 }
1549}
1550
1551
1552/**
1553 * Print (unparse) the given vertex program. Just for debugging.
1554 */
1555void
1556_mesa_print_nv_vertex_program(const struct vertex_program *program)
1557{
Brian Paul7e807512005-11-05 17:10:45 +00001558 const struct prog_instruction *inst;
Michal Krol2861e732004-03-29 11:09:34 +00001559
1560 for (inst = program->Instructions; ; inst++) {
1561 _mesa_print_nv_vertex_instruction(inst);
Brian Paul7e807512005-11-05 17:10:45 +00001562 if (inst->Opcode == OPCODE_END)
Michal Krol2861e732004-03-29 11:09:34 +00001563 return;
1564 }
1565}
1566
1567
1568const char *
1569_mesa_nv_vertex_input_register_name(GLuint i)
1570{
1571 ASSERT(i < MAX_NV_VERTEX_PROGRAM_INPUTS);
1572 return InputRegisters[i];
1573}
1574
1575
1576const char *
1577_mesa_nv_vertex_output_register_name(GLuint i)
1578{
1579 ASSERT(i < MAX_NV_VERTEX_PROGRAM_OUTPUTS);
1580 return OutputRegisters[i];
1581}
Brian Paul7aebaf32005-10-30 21:23:23 +00001582
1583
1584/**
Brian Paul7e807512005-11-05 17:10:45 +00001585 * Initialize program instruction fields to defaults.
Brian Paul7aebaf32005-10-30 21:23:23 +00001586 */
1587void
Brian Paul7e807512005-11-05 17:10:45 +00001588_mesa_init_instruction(struct prog_instruction *inst)
Brian Paul7aebaf32005-10-30 21:23:23 +00001589{
Brian Paul7e807512005-11-05 17:10:45 +00001590 _mesa_bzero(inst, sizeof(struct prog_instruction));
1591
Brian Paul7aebaf32005-10-30 21:23:23 +00001592 inst->SrcReg[0].File = PROGRAM_UNDEFINED;
1593 inst->SrcReg[0].Swizzle = SWIZZLE_NOOP;
1594 inst->SrcReg[1].File = PROGRAM_UNDEFINED;
1595 inst->SrcReg[1].Swizzle = SWIZZLE_NOOP;
1596 inst->SrcReg[2].File = PROGRAM_UNDEFINED;
1597 inst->SrcReg[2].Swizzle = SWIZZLE_NOOP;
Brian Paul7e807512005-11-05 17:10:45 +00001598
Brian Paul7aebaf32005-10-30 21:23:23 +00001599 inst->DstReg.File = PROGRAM_UNDEFINED;
Brian Paulccfe3d42005-11-03 02:35:15 +00001600 inst->DstReg.WriteMask = WRITEMASK_XYZW;
Brian Paul7e807512005-11-05 17:10:45 +00001601 inst->DstReg.CondMask = COND_TR;
1602 inst->DstReg.CondSwizzle = SWIZZLE_NOOP;
1603
1604 inst->Precision = FLOAT32;
Brian Paul7aebaf32005-10-30 21:23:23 +00001605}