Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1901 serge 1
/*
2
 * Mesa 3-D graphics library
3
 * Version:  6.5.2
4
 *
5
 * Copyright (C) 1999-2006  Brian Paul   All Rights Reserved.
6
 *
7
 * Permission is hereby granted, free of charge, to any person obtaining a
8
 * copy of this software and associated documentation files (the "Software"),
9
 * to deal in the Software without restriction, including without limitation
10
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11
 * and/or sell copies of the Software, and to permit persons to whom the
12
 * Software is furnished to do so, subject to the following conditions:
13
 *
14
 * The above copyright notice and this permission notice shall be included
15
 * in all copies or substantial portions of the Software.
16
 *
17
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21
 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
 */
24
 
25
/**
26
 * \file nvvertparse.c
27
 * NVIDIA vertex program parser.
28
 * \author Brian Paul
29
 */
30
 
31
/*
32
 * Regarding GL_NV_vertex_program, GL_NV_vertex_program1_1:
33
 *
34
 * Portions of this software may use or implement intellectual
35
 * property owned and licensed by NVIDIA Corporation. NVIDIA disclaims
36
 * any and all warranties with respect to such intellectual property,
37
 * including any use thereof or modifications thereto.
38
 */
39
 
40
#include "main/glheader.h"
41
#include "main/context.h"
42
#include "main/imports.h"
43
#include "main/nvprogram.h"
44
#include "nvvertparse.h"
45
#include "prog_instruction.h"
46
#include "prog_parameter.h"
47
#include "prog_print.h"
48
#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
 */
56
struct parse_state {
57
   struct gl_context *ctx;
58
   const GLubyte *start;
59
   const GLubyte *pos;
60
   const GLubyte *curLine;
61
   GLboolean isStateProgram;
62
   GLboolean isPositionInvariant;
63
   GLboolean isVersion1_1;
64
   GLbitfield inputsRead;
65
   GLbitfield outputsWritten;
66
   GLboolean anyProgRegsWritten;
67
   GLboolean indirectRegisterFiles;
68
   GLuint numInst;                 /* number of instructions parsed */
69
};
70
 
71
 
72
/*
73
 * Called whenever we find an error during parsing.
74
 */
75
static void
76
record_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
   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							\
101
do {									\
102
   record_error(parseState, "Unexpected end of input.", __LINE__);	\
103
   return GL_FALSE;							\
104
} while(0)
105
 
106
#define RETURN_ERROR1(msg)						\
107
do {									\
108
   record_error(parseState, msg, __LINE__);				\
109
   return GL_FALSE;							\
110
} while(0)
111
 
112
#define RETURN_ERROR2(msg1, msg2)					\
113
do {									\
114
   char err[1000];							\
115
   sprintf(err, "%s %s", msg1, msg2);				\
116
   record_error(parseState, err, __LINE__);				\
117
   return GL_FALSE;							\
118
} while(0)
119
 
120
 
121
 
122
 
123
 
124
static GLboolean IsLetter(GLubyte b)
125
{
126
   return (b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z');
127
}
128
 
129
 
130
static GLboolean IsDigit(GLubyte b)
131
{
132
   return b >= '0' && b <= '9';
133
}
134
 
135
 
136
static 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
 */
147
static GLint
148
GetToken(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
 */
210
static GLboolean
211
Parse_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
 */
227
static GLboolean
228
Peek_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
   }
236
   len = (GLint) strlen((const char *) token);
237
   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
 */
247
static GLboolean
248
Parse_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
 
285
static 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
 
290
static const char *OutputRegisters[MAX_NV_VERTEX_PROGRAM_OUTPUTS + 1] = {
291
   "HPOS", "COL0", "COL1", "FOGC",
292
   "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7",
293
   "PSIZ", "BFC0", "BFC1", NULL
294
};
295
 
296
 
297
 
298
/**
299
 * Parse a temporary register: Rnn
300
 */
301
static GLboolean
302
Parse_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 = 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
 */
329
static GLboolean
330
Parse_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
 */
351
static GLboolean
352
Parse_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 = 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
 
383
static GLboolean
384
Parse_ParamReg(struct parse_state *parseState, struct prog_src_register *srcReg)
385
{
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 = 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 (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
      parseState->indirectRegisterFiles |= (1 << srcReg->File);
415
      /* Look for +/-N offset */
416
      if (!Peek_Token(parseState, token))
417
         RETURN_ERROR;
418
 
419
      if (token[0] == '-' || token[0] == '+') {
420
         const GLubyte sign = token[0];
421
         (void) Parse_Token(parseState, token); /* consume +/- */
422
 
423
         /* an integer should be next */
424
         if (!Parse_Token(parseState, token))
425
            RETURN_ERROR;
426
 
427
         if (IsDigit(token[0])) {
428
            const GLint k = atoi((char *) token);
429
            if (sign == '-') {
430
               if (k > 64)
431
                  RETURN_ERROR1("Bad address offset");
432
               srcReg->Index = -k;
433
            }
434
            else {
435
               if (k > 63)
436
                  RETURN_ERROR1("Bad address offset");
437
               srcReg->Index = k;
438
            }
439
         }
440
         else {
441
            RETURN_ERROR;
442
         }
443
      }
444
      else {
445
         /* probably got a ']', catch it below */
446
      }
447
   }
448
   else {
449
      RETURN_ERROR;
450
   }
451
 
452
   /* Match closing ']' */
453
   if (!Parse_String(parseState, "]"))
454
      RETURN_ERROR;
455
 
456
   return GL_TRUE;
457
}
458
 
459
 
460
/**
461
 * Parse v[#] or v[]
462
 */
463
static GLboolean
464
Parse_AttribReg(struct parse_state *parseState, GLint *tempRegNum)
465
{
466
   GLubyte token[100];
467
   GLint j;
468
 
469
   /* Match 'v' */
470
   if (!Parse_String(parseState, "v"))
471
      RETURN_ERROR;
472
 
473
   /* Match '[' */
474
   if (!Parse_String(parseState, "["))
475
      RETURN_ERROR;
476
 
477
   /* match number or named register */
478
   if (!Parse_Token(parseState, token))
479
      RETURN_ERROR;
480
 
481
   if (parseState->isStateProgram && token[0] != '0')
482
      RETURN_ERROR1("Only v[0] accessible in vertex state programs");
483
 
484
   if (IsDigit(token[0])) {
485
      GLint reg = atoi((char *) token);
486
      if (reg >= MAX_NV_VERTEX_PROGRAM_INPUTS)
487
         RETURN_ERROR1("Bad vertex attribute register name");
488
      *tempRegNum = reg;
489
   }
490
   else {
491
      for (j = 0; InputRegisters[j]; j++) {
492
         if (strcmp((const char *) token, InputRegisters[j]) == 0) {
493
            *tempRegNum = j;
494
            break;
495
         }
496
      }
497
      if (!InputRegisters[j]) {
498
         /* unknown input register label */
499
         RETURN_ERROR2("Bad register name", token);
500
      }
501
   }
502
 
503
   /* Match '[' */
504
   if (!Parse_String(parseState, "]"))
505
      RETURN_ERROR;
506
 
507
   return GL_TRUE;
508
}
509
 
510
 
511
static GLboolean
512
Parse_OutputReg(struct parse_state *parseState, GLint *outputRegNum)
513
{
514
   GLubyte token[100];
515
   GLint start, j;
516
 
517
   /* Match 'o' */
518
   if (!Parse_String(parseState, "o"))
519
      RETURN_ERROR;
520
 
521
   /* Match '[' */
522
   if (!Parse_String(parseState, "["))
523
      RETURN_ERROR;
524
 
525
   /* Get output reg name */
526
   if (!Parse_Token(parseState, token))
527
      RETURN_ERROR;
528
 
529
   if (parseState->isPositionInvariant)
530
      start = 1; /* skip HPOS register name */
531
   else
532
      start = 0;
533
 
534
   /* try to match an output register name */
535
   for (j = start; OutputRegisters[j]; j++) {
536
      if (strcmp((const char *) token, OutputRegisters[j]) == 0) {
537
         *outputRegNum = j;
538
         break;
539
      }
540
   }
541
   if (!OutputRegisters[j])
542
      RETURN_ERROR1("Unrecognized output register name");
543
 
544
   /* Match ']' */
545
   if (!Parse_String(parseState, "]"))
546
      RETURN_ERROR1("Expected ]");
547
 
548
   return GL_TRUE;
549
}
550
 
551
 
552
static GLboolean
553
Parse_MaskedDstReg(struct parse_state *parseState, struct prog_dst_register *dstReg)
554
{
555
   GLubyte token[100];
556
   GLint idx;
557
 
558
   /* Dst reg can be R or o[n] */
559
   if (!Peek_Token(parseState, token))
560
      RETURN_ERROR;
561
 
562
   if (token[0] == 'R') {
563
      /* a temporary register */
564
      dstReg->File = PROGRAM_TEMPORARY;
565
      if (!Parse_TempReg(parseState, &idx))
566
         RETURN_ERROR;
567
      dstReg->Index = idx;
568
   }
569
   else if (!parseState->isStateProgram && token[0] == 'o') {
570
      /* an output register */
571
      dstReg->File = PROGRAM_OUTPUT;
572
      if (!Parse_OutputReg(parseState, &idx))
573
         RETURN_ERROR;
574
      dstReg->Index = idx;
575
   }
576
   else if (parseState->isStateProgram && token[0] == 'c' &&
577
            parseState->isStateProgram) {
578
      /* absolute program parameter register */
579
      /* Only valid for vertex state programs */
580
      dstReg->File = PROGRAM_ENV_PARAM;
581
      if (!Parse_AbsParamReg(parseState, &idx))
582
         RETURN_ERROR;
583
      dstReg->Index = idx;
584
   }
585
   else {
586
      RETURN_ERROR1("Bad destination register name");
587
   }
588
 
589
   /* Parse optional write mask */
590
   if (!Peek_Token(parseState, token))
591
      RETURN_ERROR;
592
 
593
   if (token[0] == '.') {
594
      /* got a mask */
595
      GLint k = 0;
596
 
597
      if (!Parse_String(parseState, "."))
598
         RETURN_ERROR;
599
 
600
      if (!Parse_Token(parseState, token))
601
         RETURN_ERROR;
602
 
603
      dstReg->WriteMask = 0;
604
 
605
      if (token[k] == 'x') {
606
         dstReg->WriteMask |= WRITEMASK_X;
607
         k++;
608
      }
609
      if (token[k] == 'y') {
610
         dstReg->WriteMask |= WRITEMASK_Y;
611
         k++;
612
      }
613
      if (token[k] == 'z') {
614
         dstReg->WriteMask |= WRITEMASK_Z;
615
         k++;
616
      }
617
      if (token[k] == 'w') {
618
         dstReg->WriteMask |= WRITEMASK_W;
619
         k++;
620
      }
621
      if (k == 0) {
622
         RETURN_ERROR1("Bad writemask character");
623
      }
624
      return GL_TRUE;
625
   }
626
   else {
627
      dstReg->WriteMask = WRITEMASK_XYZW;
628
      return GL_TRUE;
629
   }
630
}
631
 
632
 
633
static GLboolean
634
Parse_SwizzleSrcReg(struct parse_state *parseState, struct prog_src_register *srcReg)
635
{
636
   GLubyte token[100];
637
   GLint idx;
638
 
639
   srcReg->RelAddr = GL_FALSE;
640
 
641
   /* check for '-' */
642
   if (!Peek_Token(parseState, token))
643
      RETURN_ERROR;
644
   if (token[0] == '-') {
645
      (void) Parse_String(parseState, "-");
646
      srcReg->Negate = NEGATE_XYZW;
647
      if (!Peek_Token(parseState, token))
648
         RETURN_ERROR;
649
   }
650
   else {
651
      srcReg->Negate = NEGATE_NONE;
652
   }
653
 
654
   /* Src reg can be R, c[n], c[n +/- offset], or a named vertex attrib */
655
   if (token[0] == 'R') {
656
      srcReg->File = PROGRAM_TEMPORARY;
657
      if (!Parse_TempReg(parseState, &idx))
658
         RETURN_ERROR;
659
      srcReg->Index = idx;
660
   }
661
   else if (token[0] == 'c') {
662
      if (!Parse_ParamReg(parseState, srcReg))
663
         RETURN_ERROR;
664
   }
665
   else if (token[0] == 'v') {
666
      srcReg->File = PROGRAM_INPUT;
667
      if (!Parse_AttribReg(parseState, &idx))
668
         RETURN_ERROR;
669
      srcReg->Index = idx;
670
   }
671
   else {
672
      RETURN_ERROR2("Bad source register name", token);
673
   }
674
 
675
   /* init swizzle fields */
676
   srcReg->Swizzle = SWIZZLE_NOOP;
677
 
678
   /* Look for optional swizzle suffix */
679
   if (!Peek_Token(parseState, token))
680
      RETURN_ERROR;
681
   if (token[0] == '.') {
682
      (void) Parse_String(parseState, ".");  /* consume . */
683
 
684
      if (!Parse_Token(parseState, token))
685
         RETURN_ERROR;
686
 
687
      if (token[1] == 0) {
688
         /* single letter swizzle */
689
         if (token[0] == 'x')
690
            srcReg->Swizzle = SWIZZLE_XXXX;
691
         else if (token[0] == 'y')
692
            srcReg->Swizzle = SWIZZLE_YYYY;
693
         else if (token[0] == 'z')
694
            srcReg->Swizzle = SWIZZLE_ZZZZ;
695
         else if (token[0] == 'w')
696
            srcReg->Swizzle = SWIZZLE_WWWW;
697
         else
698
            RETURN_ERROR1("Expected x, y, z, or w");
699
      }
700
      else {
701
         /* 2, 3 or 4-component swizzle */
702
         GLint k;
703
 
704
         srcReg->Swizzle = 0;
705
 
706
         for (k = 0; token[k] && k < 5; k++) {
707
            if (token[k] == 'x')
708
               srcReg->Swizzle |= 0 << (k*3);
709
            else if (token[k] == 'y')
710
               srcReg->Swizzle |= 1 << (k*3);
711
            else if (token[k] == 'z')
712
               srcReg->Swizzle |= 2 << (k*3);
713
            else if (token[k] == 'w')
714
               srcReg->Swizzle |= 3 << (k*3);
715
            else
716
               RETURN_ERROR;
717
         }
718
         if (k >= 5)
719
            RETURN_ERROR;
720
      }
721
   }
722
 
723
   return GL_TRUE;
724
}
725
 
726
 
727
static GLboolean
728
Parse_ScalarSrcReg(struct parse_state *parseState, struct prog_src_register *srcReg)
729
{
730
   GLubyte token[100];
731
   GLint idx;
732
 
733
   srcReg->RelAddr = GL_FALSE;
734
 
735
   /* check for '-' */
736
   if (!Peek_Token(parseState, token))
737
      RETURN_ERROR;
738
   if (token[0] == '-') {
739
      srcReg->Negate = NEGATE_XYZW;
740
      (void) Parse_String(parseState, "-"); /* consume '-' */
741
      if (!Peek_Token(parseState, token))
742
         RETURN_ERROR;
743
   }
744
   else {
745
      srcReg->Negate = NEGATE_NONE;
746
   }
747
 
748
   /* Src reg can be R, c[n], c[n +/- offset], or a named vertex attrib */
749
   if (token[0] == 'R') {
750
      srcReg->File = PROGRAM_TEMPORARY;
751
      if (!Parse_TempReg(parseState, &idx))
752
         RETURN_ERROR;
753
      srcReg->Index = idx;
754
   }
755
   else if (token[0] == 'c') {
756
      if (!Parse_ParamReg(parseState, srcReg))
757
         RETURN_ERROR;
758
   }
759
   else if (token[0] == 'v') {
760
      srcReg->File = PROGRAM_INPUT;
761
      if (!Parse_AttribReg(parseState, &idx))
762
         RETURN_ERROR;
763
      srcReg->Index = idx;
764
   }
765
   else {
766
      RETURN_ERROR2("Bad source register name", token);
767
   }
768
 
769
   /* Look for .[xyzw] suffix */
770
   if (!Parse_String(parseState, "."))
771
      RETURN_ERROR;
772
 
773
   if (!Parse_Token(parseState, token))
774
      RETURN_ERROR;
775
 
776
   if (token[0] == 'x' && token[1] == 0) {
777
      srcReg->Swizzle = 0;
778
   }
779
   else if (token[0] == 'y' && token[1] == 0) {
780
      srcReg->Swizzle = 1;
781
   }
782
   else if (token[0] == 'z' && token[1] == 0) {
783
      srcReg->Swizzle = 2;
784
   }
785
   else if (token[0] == 'w' && token[1] == 0) {
786
      srcReg->Swizzle = 3;
787
   }
788
   else {
789
      RETURN_ERROR1("Bad scalar source suffix");
790
   }
791
 
792
   return GL_TRUE;
793
}
794
 
795
 
796
static GLint
797
Parse_UnaryOpInstruction(struct parse_state *parseState,
798
                         struct prog_instruction *inst,
799
                         enum prog_opcode opcode)
800
{
801
   if (opcode == OPCODE_ABS && !parseState->isVersion1_1)
802
      RETURN_ERROR1("ABS illegal for vertex program 1.0");
803
 
804
   inst->Opcode = opcode;
805
 
806
   /* dest reg */
807
   if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
808
      RETURN_ERROR;
809
 
810
   /* comma */
811
   if (!Parse_String(parseState, ","))
812
      RETURN_ERROR;
813
 
814
   /* src arg */
815
   if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[0]))
816
      RETURN_ERROR;
817
 
818
   /* semicolon */
819
   if (!Parse_String(parseState, ";"))
820
      RETURN_ERROR;
821
 
822
   return GL_TRUE;
823
}
824
 
825
 
826
static GLboolean
827
Parse_BiOpInstruction(struct parse_state *parseState,
828
                      struct prog_instruction *inst,
829
                      enum prog_opcode opcode)
830
{
831
   if (opcode == OPCODE_DPH && !parseState->isVersion1_1)
832
      RETURN_ERROR1("DPH illegal for vertex program 1.0");
833
   if (opcode == OPCODE_SUB && !parseState->isVersion1_1)
834
      RETURN_ERROR1("SUB illegal for vertex program 1.0");
835
 
836
   inst->Opcode = opcode;
837
 
838
   /* dest reg */
839
   if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
840
      RETURN_ERROR;
841
 
842
   /* comma */
843
   if (!Parse_String(parseState, ","))
844
      RETURN_ERROR;
845
 
846
   /* first src arg */
847
   if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[0]))
848
      RETURN_ERROR;
849
 
850
   /* comma */
851
   if (!Parse_String(parseState, ","))
852
      RETURN_ERROR;
853
 
854
   /* second src arg */
855
   if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[1]))
856
      RETURN_ERROR;
857
 
858
   /* semicolon */
859
   if (!Parse_String(parseState, ";"))
860
      RETURN_ERROR;
861
 
862
   /* make sure we don't reference more than one program parameter register */
863
   if (inst->SrcReg[0].File == PROGRAM_ENV_PARAM &&
864
       inst->SrcReg[1].File == PROGRAM_ENV_PARAM &&
865
       inst->SrcReg[0].Index != inst->SrcReg[1].Index)
866
      RETURN_ERROR1("Can't reference two program parameter registers");
867
 
868
   /* make sure we don't reference more than one vertex attribute register */
869
   if (inst->SrcReg[0].File == PROGRAM_INPUT &&
870
       inst->SrcReg[1].File == PROGRAM_INPUT &&
871
       inst->SrcReg[0].Index != inst->SrcReg[1].Index)
872
      RETURN_ERROR1("Can't reference two vertex attribute registers");
873
 
874
   return GL_TRUE;
875
}
876
 
877
 
878
static GLboolean
879
Parse_TriOpInstruction(struct parse_state *parseState,
880
                       struct prog_instruction *inst,
881
                       enum prog_opcode opcode)
882
{
883
   inst->Opcode = opcode;
884
 
885
   /* dest reg */
886
   if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
887
      RETURN_ERROR;
888
 
889
   /* comma */
890
   if (!Parse_String(parseState, ","))
891
      RETURN_ERROR;
892
 
893
   /* first src arg */
894
   if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[0]))
895
      RETURN_ERROR;
896
 
897
   /* comma */
898
   if (!Parse_String(parseState, ","))
899
      RETURN_ERROR;
900
 
901
   /* second src arg */
902
   if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[1]))
903
      RETURN_ERROR;
904
 
905
   /* comma */
906
   if (!Parse_String(parseState, ","))
907
      RETURN_ERROR;
908
 
909
   /* third src arg */
910
   if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[2]))
911
      RETURN_ERROR;
912
 
913
   /* semicolon */
914
   if (!Parse_String(parseState, ";"))
915
      RETURN_ERROR;
916
 
917
   /* make sure we don't reference more than one program parameter register */
918
   if ((inst->SrcReg[0].File == PROGRAM_ENV_PARAM &&
919
        inst->SrcReg[1].File == PROGRAM_ENV_PARAM &&
920
        inst->SrcReg[0].Index != inst->SrcReg[1].Index) ||
921
       (inst->SrcReg[0].File == PROGRAM_ENV_PARAM &&
922
        inst->SrcReg[2].File == PROGRAM_ENV_PARAM &&
923
        inst->SrcReg[0].Index != inst->SrcReg[2].Index) ||
924
       (inst->SrcReg[1].File == PROGRAM_ENV_PARAM &&
925
        inst->SrcReg[2].File == PROGRAM_ENV_PARAM &&
926
        inst->SrcReg[1].Index != inst->SrcReg[2].Index))
927
      RETURN_ERROR1("Can only reference one program register");
928
 
929
   /* make sure we don't reference more than one vertex attribute register */
930
   if ((inst->SrcReg[0].File == PROGRAM_INPUT &&
931
        inst->SrcReg[1].File == PROGRAM_INPUT &&
932
        inst->SrcReg[0].Index != inst->SrcReg[1].Index) ||
933
       (inst->SrcReg[0].File == PROGRAM_INPUT &&
934
        inst->SrcReg[2].File == PROGRAM_INPUT &&
935
        inst->SrcReg[0].Index != inst->SrcReg[2].Index) ||
936
       (inst->SrcReg[1].File == PROGRAM_INPUT &&
937
        inst->SrcReg[2].File == PROGRAM_INPUT &&
938
        inst->SrcReg[1].Index != inst->SrcReg[2].Index))
939
      RETURN_ERROR1("Can only reference one input register");
940
 
941
   return GL_TRUE;
942
}
943
 
944
 
945
static GLboolean
946
Parse_ScalarInstruction(struct parse_state *parseState,
947
                        struct prog_instruction *inst,
948
                        enum prog_opcode opcode)
949
{
950
   if (opcode == OPCODE_RCC && !parseState->isVersion1_1)
951
      RETURN_ERROR1("RCC illegal for vertex program 1.0");
952
 
953
   inst->Opcode = opcode;
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
 
975
static GLboolean
976
Parse_AddressInstruction(struct parse_state *parseState, struct prog_instruction *inst)
977
{
978
   inst->Opcode = OPCODE_ARL;
979
 
980
   /* Make ARB_vp backends happy */
981
   inst->DstReg.File = PROGRAM_ADDRESS;
982
   inst->DstReg.WriteMask = WRITEMASK_X;
983
   inst->DstReg.Index = 0;
984
 
985
   /* dest A0 reg */
986
   if (!Parse_AddrReg(parseState))
987
      RETURN_ERROR;
988
 
989
   /* comma */
990
   if (!Parse_String(parseState, ","))
991
      RETURN_ERROR;
992
 
993
   /* parse src reg */
994
   if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0]))
995
      RETURN_ERROR;
996
 
997
   /* semicolon */
998
   if (!Parse_String(parseState, ";"))
999
      RETURN_ERROR;
1000
 
1001
   return GL_TRUE;
1002
}
1003
 
1004
 
1005
static GLboolean
1006
Parse_EndInstruction(struct parse_state *parseState, struct prog_instruction *inst)
1007
{
1008
   GLubyte token[100];
1009
 
1010
   inst->Opcode = OPCODE_END;
1011
 
1012
   /* this should fail! */
1013
   if (Parse_Token(parseState, token))
1014
      RETURN_ERROR2("Unexpected token after END:", token);
1015
   else
1016
      return GL_TRUE;
1017
}
1018
 
1019
 
1020
/**
1021
 * The PRINT instruction is Mesa-specific and is meant as a debugging aid for
1022
 * the vertex program developer.
1023
 * The NV_vertex_program extension grammar is modified as follows:
1024
 *
1025
 *          ::= 
1026
 *                         | ...
1027
 *                         | 
1028
 *
1029
 *    ::= "PRINT" 
1030
 *                         | "PRINT"  "," 
1031
 *                         | "PRINT"  "," 
1032
 */
1033
static GLboolean
1034
Parse_PrintInstruction(struct parse_state *parseState, struct prog_instruction *inst)
1035
{
1036
   const GLubyte *str;
1037
   GLubyte *msg;
1038
   GLuint len;
1039
   GLubyte token[100];
1040
   struct prog_src_register *srcReg = &inst->SrcReg[0];
1041
   GLint idx;
1042
 
1043
   inst->Opcode = OPCODE_PRINT;
1044
 
1045
   /* The first argument is a literal string 'just like this' */
1046
   if (!Parse_String(parseState, "'"))
1047
      RETURN_ERROR;
1048
 
1049
   str = parseState->pos;
1050
   for (len = 0; str[len] != '\''; len++) /* find closing quote */
1051
      ;
1052
   parseState->pos += len + 1;
1053
   msg = (GLubyte*) malloc(len + 1);
1054
 
1055
   memcpy(msg, str, len);
1056
   msg[len] = 0;
1057
   inst->Data = msg;
1058
 
1059
   /* comma */
1060
   if (Parse_String(parseState, ",")) {
1061
 
1062
      /* The second argument is a register name */
1063
      if (!Peek_Token(parseState, token))
1064
         RETURN_ERROR;
1065
 
1066
      srcReg->RelAddr = GL_FALSE;
1067
      srcReg->Negate = NEGATE_NONE;
1068
      srcReg->Swizzle = SWIZZLE_NOOP;
1069
 
1070
      /* Register can be R, c[n], c[n +/- offset], a named vertex attrib,
1071
       * or an o[n] output register.
1072
       */
1073
      if (token[0] == 'R') {
1074
         srcReg->File = PROGRAM_TEMPORARY;
1075
         if (!Parse_TempReg(parseState, &idx))
1076
            RETURN_ERROR;
1077
	 srcReg->Index = idx;
1078
      }
1079
      else if (token[0] == 'c') {
1080
         srcReg->File = PROGRAM_ENV_PARAM;
1081
         if (!Parse_ParamReg(parseState, srcReg))
1082
            RETURN_ERROR;
1083
      }
1084
      else if (token[0] == 'v') {
1085
         srcReg->File = PROGRAM_INPUT;
1086
         if (!Parse_AttribReg(parseState, &idx))
1087
            RETURN_ERROR;
1088
	 srcReg->Index = idx;
1089
      }
1090
      else if (token[0] == 'o') {
1091
         srcReg->File = PROGRAM_OUTPUT;
1092
         if (!Parse_OutputReg(parseState, &idx))
1093
            RETURN_ERROR;
1094
	 srcReg->Index = idx;
1095
      }
1096
      else {
1097
         RETURN_ERROR2("Bad source register name", token);
1098
      }
1099
   }
1100
   else {
1101
      srcReg->File = PROGRAM_UNDEFINED;
1102
   }
1103
 
1104
   /* semicolon */
1105
   if (!Parse_String(parseState, ";"))
1106
      RETURN_ERROR;
1107
 
1108
   return GL_TRUE;
1109
}
1110
 
1111
 
1112
static GLboolean
1113
Parse_OptionSequence(struct parse_state *parseState,
1114
                     struct prog_instruction program[])
1115
{
1116
   (void) program;
1117
   while (1) {
1118
      if (!Parse_String(parseState, "OPTION"))
1119
         return GL_TRUE;  /* ok, not an OPTION statement */
1120
      if (Parse_String(parseState, "NV_position_invariant")) {
1121
         parseState->isPositionInvariant = GL_TRUE;
1122
      }
1123
      else {
1124
         RETURN_ERROR1("unexpected OPTION statement");
1125
      }
1126
      if (!Parse_String(parseState, ";"))
1127
         return GL_FALSE;
1128
   }
1129
}
1130
 
1131
 
1132
static GLboolean
1133
Parse_InstructionSequence(struct parse_state *parseState,
1134
                          struct prog_instruction program[])
1135
{
1136
   while (1) {
1137
      struct prog_instruction *inst = program + parseState->numInst;
1138
 
1139
      /* Initialize the instruction */
1140
      _mesa_init_instructions(inst, 1);
1141
 
1142
      if (Parse_String(parseState, "MOV")) {
1143
         if (!Parse_UnaryOpInstruction(parseState, inst, OPCODE_MOV))
1144
            RETURN_ERROR;
1145
      }
1146
      else if (Parse_String(parseState, "LIT")) {
1147
         if (!Parse_UnaryOpInstruction(parseState, inst, OPCODE_LIT))
1148
            RETURN_ERROR;
1149
      }
1150
      else if (Parse_String(parseState, "ABS")) {
1151
         if (!Parse_UnaryOpInstruction(parseState, inst, OPCODE_ABS))
1152
            RETURN_ERROR;
1153
      }
1154
      else if (Parse_String(parseState, "MUL")) {
1155
         if (!Parse_BiOpInstruction(parseState, inst, OPCODE_MUL))
1156
            RETURN_ERROR;
1157
      }
1158
      else if (Parse_String(parseState, "ADD")) {
1159
         if (!Parse_BiOpInstruction(parseState, inst, OPCODE_ADD))
1160
            RETURN_ERROR;
1161
      }
1162
      else if (Parse_String(parseState, "DP3")) {
1163
         if (!Parse_BiOpInstruction(parseState, inst, OPCODE_DP3))
1164
            RETURN_ERROR;
1165
      }
1166
      else if (Parse_String(parseState, "DP4")) {
1167
         if (!Parse_BiOpInstruction(parseState, inst, OPCODE_DP4))
1168
            RETURN_ERROR;
1169
      }
1170
      else if (Parse_String(parseState, "DST")) {
1171
         if (!Parse_BiOpInstruction(parseState, inst, OPCODE_DST))
1172
            RETURN_ERROR;
1173
      }
1174
      else if (Parse_String(parseState, "MIN")) {
1175
         if (!Parse_BiOpInstruction(parseState, inst, OPCODE_MIN))
1176
            RETURN_ERROR;
1177
      }
1178
      else if (Parse_String(parseState, "MAX")) {
1179
         if (!Parse_BiOpInstruction(parseState, inst, OPCODE_MAX))
1180
            RETURN_ERROR;
1181
      }
1182
      else if (Parse_String(parseState, "SLT")) {
1183
         if (!Parse_BiOpInstruction(parseState, inst, OPCODE_SLT))
1184
            RETURN_ERROR;
1185
      }
1186
      else if (Parse_String(parseState, "SGE")) {
1187
         if (!Parse_BiOpInstruction(parseState, inst, OPCODE_SGE))
1188
            RETURN_ERROR;
1189
      }
1190
      else if (Parse_String(parseState, "DPH")) {
1191
         if (!Parse_BiOpInstruction(parseState, inst, OPCODE_DPH))
1192
            RETURN_ERROR;
1193
      }
1194
      else if (Parse_String(parseState, "SUB")) {
1195
         if (!Parse_BiOpInstruction(parseState, inst, OPCODE_SUB))
1196
            RETURN_ERROR;
1197
      }
1198
      else if (Parse_String(parseState, "MAD")) {
1199
         if (!Parse_TriOpInstruction(parseState, inst, OPCODE_MAD))
1200
            RETURN_ERROR;
1201
      }
1202
      else if (Parse_String(parseState, "RCP")) {
1203
         if (!Parse_ScalarInstruction(parseState, inst, OPCODE_RCP))
1204
            RETURN_ERROR;
1205
      }
1206
      else if (Parse_String(parseState, "RSQ")) {
1207
         if (!Parse_ScalarInstruction(parseState, inst, OPCODE_RSQ))
1208
            RETURN_ERROR;
1209
      }
1210
      else if (Parse_String(parseState, "EXP")) {
1211
         if (!Parse_ScalarInstruction(parseState, inst, OPCODE_EXP))
1212
            RETURN_ERROR;
1213
      }
1214
      else if (Parse_String(parseState, "LOG")) {
1215
         if (!Parse_ScalarInstruction(parseState, inst, OPCODE_LOG))
1216
            RETURN_ERROR;
1217
      }
1218
      else if (Parse_String(parseState, "RCC")) {
1219
         if (!Parse_ScalarInstruction(parseState, inst, OPCODE_RCC))
1220
            RETURN_ERROR;
1221
      }
1222
      else if (Parse_String(parseState, "ARL")) {
1223
         if (!Parse_AddressInstruction(parseState, inst))
1224
            RETURN_ERROR;
1225
      }
1226
      else if (Parse_String(parseState, "PRINT")) {
1227
         if (!Parse_PrintInstruction(parseState, inst))
1228
            RETURN_ERROR;
1229
      }
1230
      else if (Parse_String(parseState, "END")) {
1231
         if (!Parse_EndInstruction(parseState, inst))
1232
            RETURN_ERROR;
1233
         else {
1234
            parseState->numInst++;
1235
            return GL_TRUE;  /* all done */
1236
         }
1237
      }
1238
      else {
1239
         /* bad instruction name */
1240
         RETURN_ERROR1("Unexpected token");
1241
      }
1242
 
1243
      /* examine input/output registers */
1244
      if (inst->DstReg.File == PROGRAM_OUTPUT)
1245
         parseState->outputsWritten |= (1 << inst->DstReg.Index);
1246
      else if (inst->DstReg.File == PROGRAM_ENV_PARAM)
1247
         parseState->anyProgRegsWritten = GL_TRUE;
1248
 
1249
      if (inst->SrcReg[0].File == PROGRAM_INPUT)
1250
         parseState->inputsRead |= (1 << inst->SrcReg[0].Index);
1251
      if (inst->SrcReg[1].File == PROGRAM_INPUT)
1252
         parseState->inputsRead |= (1 << inst->SrcReg[1].Index);
1253
      if (inst->SrcReg[2].File == PROGRAM_INPUT)
1254
         parseState->inputsRead |= (1 << inst->SrcReg[2].Index);
1255
 
1256
      parseState->numInst++;
1257
 
1258
      if (parseState->numInst >= MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS)
1259
         RETURN_ERROR1("Program too long");
1260
   }
1261
 
1262
   RETURN_ERROR;
1263
}
1264
 
1265
 
1266
static GLboolean
1267
Parse_Program(struct parse_state *parseState,
1268
              struct prog_instruction instBuffer[])
1269
{
1270
   if (parseState->isVersion1_1) {
1271
      if (!Parse_OptionSequence(parseState, instBuffer)) {
1272
         return GL_FALSE;
1273
      }
1274
   }
1275
   return Parse_InstructionSequence(parseState, instBuffer);
1276
}
1277
 
1278
 
1279
/**
1280
 * Parse/compile the 'str' returning the compiled 'program'.
1281
 * ctx->Program.ErrorPos will be -1 if successful.  Otherwise, ErrorPos
1282
 * indicates the position of the error in 'str'.
1283
 */
1284
void
1285
_mesa_parse_nv_vertex_program(struct gl_context *ctx, GLenum dstTarget,
1286
                              const GLubyte *str, GLsizei len,
1287
                              struct gl_vertex_program *program)
1288
{
1289
   struct parse_state parseState;
1290
   struct prog_instruction instBuffer[MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS];
1291
   struct prog_instruction *newInst;
1292
   GLenum target;
1293
   GLubyte *programString;
1294
 
1295
   /* Make a null-terminated copy of the program string */
1296
   programString = (GLubyte *) MALLOC(len + 1);
1297
   if (!programString) {
1298
      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
1299
      return;
1300
   }
1301
   memcpy(programString, str, len);
1302
   programString[len] = 0;
1303
 
1304
   /* Get ready to parse */
1305
   parseState.ctx = ctx;
1306
   parseState.start = programString;
1307
   parseState.isPositionInvariant = GL_FALSE;
1308
   parseState.isVersion1_1 = GL_FALSE;
1309
   parseState.numInst = 0;
1310
   parseState.inputsRead = 0;
1311
   parseState.outputsWritten = 0;
1312
   parseState.anyProgRegsWritten = GL_FALSE;
1313
   parseState.indirectRegisterFiles = 0x0;
1314
 
1315
   /* Reset error state */
1316
   _mesa_set_program_error(ctx, -1, NULL);
1317
 
1318
   /* check the program header */
1319
   if (strncmp((const char *) programString, "!!VP1.0", 7) == 0) {
1320
      target = GL_VERTEX_PROGRAM_NV;
1321
      parseState.pos = programString + 7;
1322
      parseState.isStateProgram = GL_FALSE;
1323
   }
1324
   else if (strncmp((const char *) programString, "!!VP1.1", 7) == 0) {
1325
      target = GL_VERTEX_PROGRAM_NV;
1326
      parseState.pos = programString + 7;
1327
      parseState.isStateProgram = GL_FALSE;
1328
      parseState.isVersion1_1 = GL_TRUE;
1329
   }
1330
   else if (strncmp((const char *) programString, "!!VSP1.0", 8) == 0) {
1331
      target = GL_VERTEX_STATE_PROGRAM_NV;
1332
      parseState.pos = programString + 8;
1333
      parseState.isStateProgram = GL_TRUE;
1334
   }
1335
   else {
1336
      /* invalid header */
1337
      ctx->Program.ErrorPos = 0;
1338
      _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(bad header)");
1339
      return;
1340
   }
1341
 
1342
   /* make sure target and header match */
1343
   if (target != dstTarget) {
1344
      _mesa_error(ctx, GL_INVALID_OPERATION,
1345
                  "glLoadProgramNV(target mismatch)");
1346
      return;
1347
   }
1348
 
1349
 
1350
   if (Parse_Program(&parseState, instBuffer)) {
1351
      gl_state_index state_tokens[STATE_LENGTH] = {0, 0, 0, 0, 0};
1352
      int i;
1353
 
1354
      /* successful parse! */
1355
 
1356
      if (parseState.isStateProgram) {
1357
         if (!parseState.anyProgRegsWritten) {
1358
            _mesa_error(ctx, GL_INVALID_OPERATION,
1359
                        "glLoadProgramNV(c[#] not written)");
1360
            return;
1361
         }
1362
      }
1363
      else {
1364
         if (!parseState.isPositionInvariant &&
1365
             !(parseState.outputsWritten & (1 << VERT_RESULT_HPOS))) {
1366
            /* bit 1 = HPOS register */
1367
            _mesa_error(ctx, GL_INVALID_OPERATION,
1368
                        "glLoadProgramNV(HPOS not written)");
1369
            return;
1370
         }
1371
      }
1372
 
1373
      /* copy the compiled instructions */
1374
      assert(parseState.numInst <= MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS);
1375
      newInst = _mesa_alloc_instructions(parseState.numInst);
1376
      if (!newInst) {
1377
         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
1378
         free(programString);
1379
         return;  /* out of memory */
1380
      }
1381
      _mesa_copy_instructions(newInst, instBuffer, parseState.numInst);
1382
 
1383
      /* install the program */
1384
      program->Base.Target = target;
1385
      if (program->Base.String) {
1386
         free(program->Base.String);
1387
      }
1388
      program->Base.String = programString;
1389
      program->Base.Format = GL_PROGRAM_FORMAT_ASCII_ARB;
1390
      if (program->Base.Instructions) {
1391
         free(program->Base.Instructions);
1392
      }
1393
      program->Base.Instructions = newInst;
1394
      program->Base.InputsRead = parseState.inputsRead;
1395
      if (parseState.isPositionInvariant)
1396
         program->Base.InputsRead |= VERT_BIT_POS;
1397
      program->Base.NumInstructions = parseState.numInst;
1398
      program->Base.OutputsWritten = parseState.outputsWritten;
1399
      program->IsPositionInvariant = parseState.isPositionInvariant;
1400
      program->IsNVProgram = GL_TRUE;
1401
 
1402
#ifdef DEBUG_foo
1403
      printf("--- glLoadProgramNV result ---\n");
1404
      _mesa_fprint_program_opt(stdout, &program->Base, PROG_PRINT_NV, 0);
1405
      printf("------------------------------\n");
1406
#endif
1407
 
1408
      if (program->Base.Parameters)
1409
	 _mesa_free_parameter_list(program->Base.Parameters);
1410
 
1411
      program->Base.Parameters = _mesa_new_parameter_list ();
1412
      program->Base.NumParameters = 0;
1413
 
1414
      program->Base.IndirectRegisterFiles = parseState.indirectRegisterFiles;
1415
 
1416
      state_tokens[0] = STATE_VERTEX_PROGRAM;
1417
      state_tokens[1] = STATE_ENV;
1418
      /* Add refs to all of the potential params, in order.  If we want to not
1419
       * upload everything, _mesa_layout_parameters is the answer.
1420
       */
1421
      for (i = 0; i < MAX_NV_VERTEX_PROGRAM_PARAMS; i++) {
1422
	 GLint index;
1423
	 state_tokens[2] = i;
1424
	 index = _mesa_add_state_reference(program->Base.Parameters,
1425
					   state_tokens);
1426
	 assert(index == i);
1427
      }
1428
      program->Base.NumParameters = program->Base.Parameters->NumParameters;
1429
 
1430
      _mesa_setup_nv_temporary_count(ctx, &program->Base);
1431
      _mesa_emit_nv_temp_initialization(ctx, &program->Base);
1432
   }
1433
   else {
1434
      /* Error! */
1435
      _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV");
1436
      /* NOTE: _mesa_set_program_error would have been called already */
1437
      /* GL_NV_vertex_program isn't supposed to set the error string
1438
       * so we reset it here.
1439
       */
1440
      _mesa_set_program_error(ctx, ctx->Program.ErrorPos, NULL);
1441
   }
1442
}
1443
 
1444
 
1445
const char *
1446
_mesa_nv_vertex_input_register_name(GLuint i)
1447
{
1448
   ASSERT(i < MAX_NV_VERTEX_PROGRAM_INPUTS);
1449
   return InputRegisters[i];
1450
}
1451
 
1452
 
1453
const char *
1454
_mesa_nv_vertex_output_register_name(GLuint i)
1455
{
1456
   ASSERT(i < MAX_NV_VERTEX_PROGRAM_OUTPUTS);
1457
   return OutputRegisters[i];
1458
}
1459