Subversion Repositories shark

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
55 pj 1
/* $Id: vpparse.c,v 1.1 2003-02-28 11:42:06 pj Exp $ */
2
 
3
/*
4
 * Mesa 3-D graphics library
5
 * Version:  4.1
6
 *
7
 * Copyright (C) 1999-2001  Brian Paul   All Rights Reserved.
8
 *
9
 * Permission is hereby granted, free of charge, to any person obtaining a
10
 * copy of this software and associated documentation files (the "Software"),
11
 * to deal in the Software without restriction, including without limitation
12
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13
 * and/or sell copies of the Software, and to permit persons to whom the
14
 * Software is furnished to do so, subject to the following conditions:
15
 *
16
 * The above copyright notice and this permission notice shall be included
17
 * in all copies or substantial portions of the Software.
18
 *
19
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
22
 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23
 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
 */
26
 
27
/*
28
 * -------- Regarding NV_vertex_program --------
29
 * Redistribution and use in source and binary forms, with or without
30
 * modification, are permitted provided that the following conditions are met:
31
 *
32
 * o Redistribution of the source code must contain a copyright notice
33
 *   and this list of conditions;
34
 *
35
 * o Redistribution in binary and source code form must contain the
36
 *   following Notice in the software and any documentation and/or other
37
 *   materials provided with the distribution; and
38
 *
39
 * o The name of Nvidia may not be used to promote or endorse software
40
 *   derived from the software.
41
 *
42
 * NOTICE: Nvidia hereby grants to each recipient a non-exclusive worldwide
43
 * royalty free patent license under patent claims that are licensable by
44
 * Nvidia and which are necessarily required and for which no commercially
45
 * viable non infringing alternative exists to make, use, sell, offer to sell,
46
 * import and otherwise transfer the vertex extension for the Mesa 3D Graphics
47
 * Library as distributed in source code and object code form.  No hardware or
48
 * hardware implementation (including a semiconductor implementation and chips)
49
 * are licensed hereunder. If a recipient makes a patent claim or institutes
50
 * patent litigation against Nvidia or Nvidia's customers for use or sale of
51
 * Nvidia products, then this license grant as to such recipient shall
52
 * immediately terminate and recipient immediately agrees to cease use and
53
 * distribution of the Mesa Program and derivatives thereof.
54
 *
55
 * THE MESA 3D GRAPHICS LIBRARY IS PROVIDED ON AN "AS IS BASIS, WITHOUT
56
 * WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,
57
 * WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-NFRINGEMENT
58
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
59
 *
60
 * NVIDIA SHALL NOT HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL,
61
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION
62
 * LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
63
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
64
 * ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE MESA 3D GRAPHICS
65
 * LIBRARY OR EVIDENCE OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDR, EVEN
66
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
67
 *
68
 * If you do not comply with this agreement, then Nvidia may cancel the license
69
 * and rights granted herein.
70
 * ---------------------------------------------
71
 */
72
 
73
/**
74
 * \file vpparse.c
75
 * \brief Vertex program parser.
76
 * \author Brian Paul
77
 */
78
 
79
 
80
#include "glheader.h"
81
#include "context.h"
82
#include "hash.h"
83
#include "imports.h"
84
#include "macros.h"
85
#include "mtypes.h"
86
#include "vpparse.h"
87
 
88
 
89
 
90
/************************ Symbol Table ******************************/
91
 
92
/* A simple symbol table implementation for ARB_vertex_program
93
 * (not used yet)
94
 */
95
 
96
#if 000
97
struct symbol
98
{
99
   GLubyte *name;
100
   GLint value;
101
   struct symbol *next;
102
};
103
 
104
static struct symbol *SymbolTable = NULL;
105
 
106
static GLboolean
107
IsSymbol(const GLubyte *symbol)
108
{
109
   struct symbol *s;
110
   for (s = SymbolTable; s; s = s->next) {
111
      if (strcmp((char *) symbol, (char *)s->name) == 0)
112
         return GL_TRUE;
113
   }
114
   return GL_FALSE;
115
}
116
 
117
static GLint
118
GetSymbolValue(const GLubyte *symbol)
119
{
120
   struct symbol *s;
121
   for (s = SymbolTable; s; s = s->next) {
122
      if (strcmp((char *) symbol, (char *)s->name) == 0)
123
         return s->value;
124
   }
125
   return 0;
126
}
127
 
128
static void
129
AddSymbol(const GLubyte *symbol, GLint value)
130
{
131
   struct symbol *s = MALLOC_STRUCT(symbol);
132
   if (s) {
133
      s->name = (GLubyte *) strdup((char *) symbol);
134
      s->value = value;
135
      s->next = SymbolTable;
136
      SymbolTable = s;
137
   }
138
}
139
 
140
static void
141
ResetSymbolTable(void)
142
{
143
   struct symbol *s, *next;
144
   for (s = SymbolTable; s; s = next) {
145
      next = s->next;
146
      FREE(s->name);
147
      FREE(s);
148
      s = next;
149
   }  
150
   SymbolTable = NULL;
151
}
152
#endif
153
 
154
/***************************** Parsing ******************************/
155
 
156
 
157
static GLboolean IsLetter(GLubyte b)
158
{
159
   return (b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z');
160
}
161
 
162
 
163
static GLboolean IsDigit(GLubyte b)
164
{
165
   return b >= '0' && b <= '9';
166
}
167
 
168
 
169
static GLboolean IsWhitespace(GLubyte b)
170
{
171
   return b == ' ' || b == '\t' || b == '\n' || b == '\r';
172
}
173
 
174
 
175
/**
176
 * Starting at 'str' find the next token.  A token can be an integer,
177
 * an identifier or punctuation symbol.
178
 * \return <= 0 we found an error, else, return number of characters parsed.
179
 */
180
static GLint
181
GetToken(const GLubyte *str, GLubyte *token)
182
{
183
   GLint i = 0, j = 0;
184
 
185
   token[0] = 0;
186
 
187
   /* skip whitespace and comments */
188
   while (str[i] && (IsWhitespace(str[i]) || str[i] == '#')) {
189
      if (str[i] == '#') {
190
         /* skip comment */
191
         while (str[i] && (str[i] != '\n' && str[i] != '\r')) {
192
            i++;
193
         }
194
      }
195
      else {
196
         /* skip whitespace */
197
         i++;
198
      }
199
   }
200
 
201
   if (str[i] == 0)
202
      return -i;
203
 
204
   /* try matching an integer */
205
   while (str[i] && IsDigit(str[i])) {
206
      token[j++] = str[i++];
207
   }
208
   if (j > 0 || !str[i]) {
209
      token[j] = 0;
210
      return i;
211
   }
212
 
213
   /* try matching an identifier */
214
   if (IsLetter(str[i])) {
215
      while (str[i] && (IsLetter(str[i]) || IsDigit(str[i]))) {
216
         token[j++] = str[i++];
217
      }
218
      token[j] = 0;
219
      return i;
220
   }
221
 
222
   /* punctuation */
223
   if (str[i]) {
224
      token[0] = str[i++];
225
      token[1] = 0;
226
      return i;
227
   }
228
 
229
   /* end of input */
230
   token[0] = 0;
231
   return i;
232
}
233
 
234
 
235
/**
236
 * Get next token from input stream and increment stream pointer past token.
237
 */
238
static GLboolean
239
Parse_Token(const GLubyte **s, GLubyte *token)
240
{
241
   GLint i;
242
   i = GetToken(*s, token);
243
   if (i <= 0) {
244
      *s += (-i);
245
      return GL_FALSE;
246
   }
247
   *s += i;
248
   return GL_TRUE;
249
}
250
 
251
 
252
/**
253
 * Get next token from input stream but don't increment stream pointer.
254
 */
255
static GLboolean
256
Peek_Token(const GLubyte **s, GLubyte *token)
257
{
258
   GLint i, len;
259
   i = GetToken(*s, token);
260
   if (i <= 0) {
261
      *s += (-i);
262
      return GL_FALSE;
263
   }
264
   len = _mesa_strlen((char *) token);
265
   *s += (i - len);
266
   return GL_TRUE;
267
}
268
 
269
 
270
/**
271
 * String equality test
272
 */
273
static GLboolean
274
StrEq(const GLubyte *a, const GLubyte *b)
275
{
276
   GLint i;
277
   for (i = 0; a[i] && b[i] && a[i] == b[i]; i++)
278
      ;
279
   if (a[i] == 0 && b[i] == 0)
280
      return GL_TRUE;
281
   else
282
      return GL_FALSE;
283
}
284
 
285
 
286
/**********************************************************************/
287
 
288
static const char *InputRegisters[] = {
289
   "OPOS", "WGHT", "NRML", "COL0", "COL1", "FOGC", "6", "7",
290
   "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", NULL
291
};
292
 
293
static const char *OutputRegisters[] = {
294
   "HPOS", "COL0", "COL1", "BFC0", "BFC1", "FOGC", "PSIZ",
295
   "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", NULL
296
};
297
 
298
static const char *Opcodes[] = {
299
   "MOV", "LIT", "RCP", "RSQ", "EXP", "LOG", "MUL", "ADD", "DP3", "DP4",
300
   "DST", "MIN", "MAX", "SLT", "SGE", "MAD", "ARL", "DPH", "RCC", "SUB",
301
   "ABS", "END", NULL
302
};
303
 
304
 
305
#ifdef DEBUG
306
 
307
#define PARSE_ERROR                                             \
308
do {                                                            \
309
   _mesa_printf("vpparse.c error at %d: parse error\n", __LINE__);      \
310
   return GL_FALSE;                                             \
311
} while(0)
312
 
313
#define PARSE_ERROR1(msg)                                       \
314
do {                                                            \
315
   _mesa_printf("vpparse.c error at %d: %s\n", __LINE__, msg);  \
316
   return GL_FALSE;                                             \
317
} while(0)
318
 
319
#define PARSE_ERROR2(msg1, msg2)                                        \
320
do {                                                                    \
321
   _mesa_printf("vpparse.c error at %d: %s %s\n", __LINE__, msg1, msg2);        \
322
   return GL_FALSE;                                                     \
323
} while(0)
324
 
325
#else
326
 
327
#define PARSE_ERROR                return GL_FALSE
328
#define PARSE_ERROR1(msg1)         return GL_FALSE
329
#define PARSE_ERROR2(msg1, msg2)   return GL_FALSE
330
 
331
#endif
332
 
333
 
334
static GLuint
335
IsProgRegister(GLuint r)
336
{
337
   return (GLuint) (r >= VP_PROG_REG_START && r <= VP_PROG_REG_END);
338
}
339
 
340
static GLuint
341
IsInputRegister(GLuint r)
342
{
343
   return (GLuint) (r >= VP_INPUT_REG_START && r <= VP_INPUT_REG_END);
344
}
345
 
346
static GLuint
347
IsOutputRegister(GLuint r)
348
{
349
   return (GLuint) (r >= VP_OUTPUT_REG_START && r <= VP_OUTPUT_REG_END);
350
}
351
 
352
 
353
 
354
/**********************************************************************/
355
 
356
/* XXX
357
 * These shouldn't be globals as that makes the parser non-reentrant.
358
 * We should really define a "ParserContext" class which contains these
359
 * and the <s> pointer into the program text.
360
 */
361
static GLboolean IsStateProgram = GL_FALSE;
362
static GLboolean IsPositionInvariant = GL_FALSE;
363
static GLboolean IsVersion1_1 = GL_FALSE;
364
 
365
/**
366
 * Try to match 'pattern' as the next token after any whitespace/comments.
367
 */
368
static GLboolean
369
Parse_String(const GLubyte **s, const char *pattern)
370
{
371
   GLint i;
372
 
373
   /* skip whitespace and comments */
374
   while (IsWhitespace(**s) || **s == '#') {
375
      if (**s == '#') {
376
         while (**s && (**s != '\n' && **s != '\r')) {
377
            *s += 1;
378
         }
379
      }
380
      else {
381
         /* skip whitespace */
382
         *s += 1;
383
      }
384
   }
385
 
386
   /* Try to match the pattern */
387
   for (i = 0; pattern[i]; i++) {
388
      if (**s != pattern[i])
389
         PARSE_ERROR2("failed to match", pattern); /* failure */
390
      *s += 1;
391
   }
392
 
393
   return GL_TRUE; /* success */
394
}
395
 
396
 
397
/**
398
 * Parse a temporary register: Rnn
399
 */
400
static GLboolean
401
Parse_TempReg(const GLubyte **s, GLint *tempRegNum)
402
{
403
   GLubyte token[100];
404
 
405
   /* Should be 'R##' */
406
   if (!Parse_Token(s, token))
407
      PARSE_ERROR;
408
   if (token[0] != 'R')
409
      PARSE_ERROR1("Expected R##");
410
 
411
   if (IsDigit(token[1])) {
412
      GLint reg = _mesa_atoi((char *) (token + 1));
413
      if (reg >= VP_NUM_TEMP_REGS)
414
         PARSE_ERROR1("Bad temporary register name");
415
      *tempRegNum = VP_TEMP_REG_START + reg;
416
   }
417
   else {
418
      PARSE_ERROR1("Bad temporary register name");
419
   }
420
 
421
   return GL_TRUE;
422
}
423
 
424
 
425
/**
426
 * Parse address register "A0.x"
427
 */
428
static GLboolean
429
Parse_AddrReg(const GLubyte **s)
430
{
431
   /* match 'A0' */
432
   if (!Parse_String(s, "A0"))
433
      PARSE_ERROR;
434
 
435
   /* match '.' */
436
   if (!Parse_String(s, "."))
437
      PARSE_ERROR;
438
 
439
   /* match 'x' */
440
   if (!Parse_String(s, "x"))
441
      PARSE_ERROR;
442
 
443
   return GL_TRUE;
444
}
445
 
446
 
447
/**
448
 * Parse absolute program parameter register "c[##]"
449
 */
450
static GLboolean
451
Parse_AbsParamReg(const GLubyte **s, GLint *regNum)
452
{
453
   GLubyte token[100];
454
 
455
   if (!Parse_String(s, "c"))
456
      PARSE_ERROR;
457
 
458
   if (!Parse_String(s, "["))
459
      PARSE_ERROR;
460
 
461
   if (!Parse_Token(s, token))
462
      PARSE_ERROR;
463
 
464
   if (IsDigit(token[0])) {
465
      /* a numbered program parameter register */
466
      GLint reg = _mesa_atoi((char *) token);
467
      if (reg >= VP_NUM_PROG_REGS)
468
         PARSE_ERROR1("Bad constant program number");
469
      *regNum = VP_PROG_REG_START + reg;
470
   }
471
   else {
472
      PARSE_ERROR;
473
   }
474
 
475
   if (!Parse_String(s, "]"))
476
      PARSE_ERROR;
477
 
478
   return GL_TRUE;
479
}
480
 
481
 
482
static GLboolean
483
Parse_ParamReg(const GLubyte **s, struct vp_src_register *srcReg)
484
{
485
   GLubyte token[100];
486
 
487
   if (!Parse_String(s, "c"))
488
      PARSE_ERROR;
489
 
490
   if (!Parse_String(s, "["))
491
      PARSE_ERROR;
492
 
493
   if (!Peek_Token(s, token))
494
      PARSE_ERROR;
495
 
496
   if (IsDigit(token[0])) {
497
      /* a numbered program parameter register */
498
      GLint reg;
499
      (void) Parse_Token(s, token);
500
      reg = _mesa_atoi((char *) token);
501
      if (reg >= VP_NUM_PROG_REGS)
502
         PARSE_ERROR1("Bad constant program number");
503
      srcReg->Register = VP_PROG_REG_START + reg;
504
   }
505
   else if (StrEq(token, (GLubyte *) "A0")) {
506
      /* address register "A0.x" */
507
      if (!Parse_AddrReg(s))
508
         PARSE_ERROR;
509
 
510
      srcReg->RelAddr = GL_TRUE;
511
      srcReg->Register = 0;
512
 
513
      /* Look for +/-N offset */
514
      if (!Peek_Token(s, token))
515
         PARSE_ERROR;
516
 
517
      if (token[0] == '-' || token[0] == '+') {
518
         const GLubyte sign = token[0];
519
         (void) Parse_Token(s, token); /* consume +/- */
520
 
521
         /* an integer should be next */
522
         if (!Parse_Token(s, token))
523
            PARSE_ERROR;
524
 
525
         if (IsDigit(token[0])) {
526
            const GLint k = _mesa_atoi((char *) token);
527
            if (sign == '-') {
528
               if (k > 64)
529
                  PARSE_ERROR1("Bad address offset");
530
               srcReg->Register = -k;
531
            }
532
            else {
533
               if (k > 63)
534
                  PARSE_ERROR1("Bad address offset");
535
               srcReg->Register = k;
536
            }
537
         }
538
         else {
539
            PARSE_ERROR;
540
         }
541
      }
542
      else {
543
         /* probably got a ']', catch it below */
544
      }
545
   }
546
   else {
547
      PARSE_ERROR;
548
   }
549
 
550
   /* Match closing ']' */
551
   if (!Parse_String(s, "]"))
552
      PARSE_ERROR;
553
 
554
   return GL_TRUE;
555
}
556
 
557
 
558
/**
559
 * Parse v[#] or v[<name>]
560
 */
561
static GLboolean
562
Parse_AttribReg(const GLubyte **s, GLint *tempRegNum)
563
{
564
   GLubyte token[100];
565
   GLint j;
566
 
567
   /* Match 'v' */
568
   if (!Parse_String(s, "v"))
569
      PARSE_ERROR;
570
 
571
   /* Match '[' */
572
   if (!Parse_String(s, "["))
573
      PARSE_ERROR;
574
 
575
   /* match number or named register */
576
   if (!Parse_Token(s, token))
577
      PARSE_ERROR;
578
 
579
   if (IsStateProgram && token[0] != '0')
580
      PARSE_ERROR1("Only v[0] accessible in vertex state programs");
581
 
582
   if (IsDigit(token[0])) {
583
      GLint reg = _mesa_atoi((char *) token);
584
      if (reg >= VP_NUM_INPUT_REGS)
585
         PARSE_ERROR1("Bad vertex attribute register name");
586
      *tempRegNum = VP_INPUT_REG_START + reg;
587
   }
588
   else {
589
      for (j = 0; InputRegisters[j]; j++) {
590
         if (StrEq(token, (const GLubyte *) InputRegisters[j])) {
591
            *tempRegNum = VP_INPUT_REG_START + j;
592
            break;
593
         }
594
      }
595
      if (!InputRegisters[j]) {
596
         /* unknown input register label */
597
         PARSE_ERROR2("Bad register name", token);
598
      }
599
   }
600
 
601
   /* Match '[' */
602
   if (!Parse_String(s, "]"))
603
      PARSE_ERROR;
604
 
605
   return GL_TRUE;
606
}
607
 
608
 
609
static GLboolean
610
Parse_OutputReg(const GLubyte **s, GLint *outputRegNum)
611
{
612
   GLubyte token[100];
613
   GLint start, j;
614
 
615
   /* Match 'o' */
616
   if (!Parse_String(s, "o"))
617
      PARSE_ERROR;
618
 
619
   /* Match '[' */
620
   if (!Parse_String(s, "["))
621
      PARSE_ERROR;
622
 
623
   /* Get output reg name */
624
   if (!Parse_Token(s, token))
625
      PARSE_ERROR;
626
 
627
   if (IsPositionInvariant)
628
      start = 1; /* skip HPOS register name */
629
   else
630
      start = 0;
631
 
632
   /* try to match an output register name */
633
   for (j = start; OutputRegisters[j]; j++) {
634
      if (StrEq(token, (const GLubyte *) OutputRegisters[j])) {
635
         *outputRegNum = VP_OUTPUT_REG_START + j;
636
         break;
637
      }
638
   }
639
   if (!OutputRegisters[j])
640
      PARSE_ERROR1("Unrecognized output register name");
641
 
642
   /* Match ']' */
643
   if (!Parse_String(s, "]"))
644
      PARSE_ERROR1("Expected ]");
645
 
646
   return GL_TRUE;
647
}
648
 
649
 
650
static GLboolean
651
Parse_MaskedDstReg(const GLubyte **s, struct vp_dst_register *dstReg)
652
{
653
   GLubyte token[100];
654
 
655
   /* Dst reg can be R<n> or o[n] */
656
   if (!Peek_Token(s, token))
657
      PARSE_ERROR;
658
 
659
   if (token[0] == 'R') {
660
      /* a temporary register */
661
      if (!Parse_TempReg(s, &dstReg->Register))
662
         PARSE_ERROR;
663
   }
664
   else if (!IsStateProgram && token[0] == 'o') {
665
      /* an output register */
666
      if (!Parse_OutputReg(s, &dstReg->Register))
667
         PARSE_ERROR;
668
   }
669
   else if (IsStateProgram && token[0] == 'c') {
670
      /* absolute program parameter register */
671
      if (!Parse_AbsParamReg(s, &dstReg->Register))
672
         PARSE_ERROR;
673
   }
674
   else {
675
      PARSE_ERROR1("Bad destination register name");
676
   }
677
 
678
   /* Parse optional write mask */
679
   if (!Peek_Token(s, token))
680
      PARSE_ERROR;
681
 
682
   if (token[0] == '.') {
683
      /* got a mask */
684
      GLint k = 0;
685
 
686
      if (!Parse_String(s, "."))
687
         PARSE_ERROR;
688
 
689
      if (!Parse_Token(s, token))
690
         PARSE_ERROR;
691
 
692
      dstReg->WriteMask[0] = GL_FALSE;
693
      dstReg->WriteMask[1] = GL_FALSE;
694
      dstReg->WriteMask[2] = GL_FALSE;
695
      dstReg->WriteMask[3] = GL_FALSE;
696
 
697
      if (token[k] == 'x') {
698
         dstReg->WriteMask[0] = GL_TRUE;
699
         k++;
700
      }
701
      if (token[k] == 'y') {
702
         dstReg->WriteMask[1] = GL_TRUE;
703
         k++;
704
      }
705
      if (token[k] == 'z') {
706
         dstReg->WriteMask[2] = GL_TRUE;
707
         k++;
708
      }
709
      if (token[k] == 'w') {
710
         dstReg->WriteMask[3] = GL_TRUE;
711
         k++;
712
      }
713
      if (k == 0) {
714
         PARSE_ERROR1("Bad writemask character");
715
      }
716
      return GL_TRUE;
717
   }
718
   else {
719
      dstReg->WriteMask[0] = GL_TRUE;
720
      dstReg->WriteMask[1] = GL_TRUE;
721
      dstReg->WriteMask[2] = GL_TRUE;
722
      dstReg->WriteMask[3] = GL_TRUE;
723
      return GL_TRUE;
724
   }
725
}
726
 
727
 
728
static GLboolean
729
Parse_SwizzleSrcReg(const GLubyte **s, struct vp_src_register *srcReg)
730
{
731
   GLubyte token[100];
732
 
733
   srcReg->RelAddr = GL_FALSE;
734
 
735
   /* check for '-' */
736
   if (!Peek_Token(s, token))
737
      PARSE_ERROR;
738
   if (token[0] == '-') {
739
      (void) Parse_String(s, "-");
740
      srcReg->Negate = GL_TRUE;
741
      if (!Peek_Token(s, token))
742
         PARSE_ERROR;
743
   }
744
   else {
745
      srcReg->Negate = GL_FALSE;
746
   }
747
 
748
   /* Src reg can be R<n>, c[n], c[n +/- offset], or a named vertex attrib */
749
   if (token[0] == 'R') {
750
      if (!Parse_TempReg(s, &srcReg->Register))
751
         PARSE_ERROR;
752
   }
753
   else if (token[0] == 'c') {
754
      if (!Parse_ParamReg(s, srcReg))
755
         PARSE_ERROR;
756
   }
757
   else if (token[0] == 'v') {
758
      if (!Parse_AttribReg(s, &srcReg->Register))
759
         PARSE_ERROR;
760
   }
761
   else {
762
      PARSE_ERROR2("Bad source register name", token);
763
   }
764
 
765
   /* init swizzle fields */
766
   srcReg->Swizzle[0] = 0;
767
   srcReg->Swizzle[1] = 1;
768
   srcReg->Swizzle[2] = 2;
769
   srcReg->Swizzle[3] = 3;
770
 
771
   /* Look for optional swizzle suffix */
772
   if (!Peek_Token(s, token))
773
      PARSE_ERROR;
774
   if (token[0] == '.') {
775
      (void) Parse_String(s, ".");  /* consume . */
776
 
777
      if (!Parse_Token(s, token))
778
         PARSE_ERROR;
779
 
780
      if (token[1] == 0) {
781
         /* single letter swizzle */
782
         if (token[0] == 'x')
783
            ASSIGN_4V(srcReg->Swizzle, 0, 0, 0, 0);
784
         else if (token[0] == 'y')
785
            ASSIGN_4V(srcReg->Swizzle, 1, 1, 1, 1);
786
         else if (token[0] == 'z')
787
            ASSIGN_4V(srcReg->Swizzle, 2, 2, 2, 2);
788
         else if (token[0] == 'w')
789
            ASSIGN_4V(srcReg->Swizzle, 3, 3, 3, 3);
790
         else
791
            PARSE_ERROR1("Expected x, y, z, or w");
792
      }
793
      else {
794
         /* 2, 3 or 4-component swizzle */
795
         GLint k;
796
         for (k = 0; token[k] && k < 5; k++) {
797
            if (token[k] == 'x')
798
               srcReg->Swizzle[k] = 0;
799
            else if (token[k] == 'y')
800
               srcReg->Swizzle[k] = 1;
801
            else if (token[k] == 'z')
802
               srcReg->Swizzle[k] = 2;
803
            else if (token[k] == 'w')
804
               srcReg->Swizzle[k] = 3;
805
            else
806
               PARSE_ERROR;
807
         }
808
         if (k >= 5)
809
            PARSE_ERROR;
810
      }
811
   }
812
 
813
   return GL_TRUE;
814
}
815
 
816
 
817
static GLboolean
818
Parse_ScalarSrcReg(const GLubyte **s, struct vp_src_register *srcReg)
819
{
820
   GLubyte token[100];
821
 
822
   srcReg->RelAddr = GL_FALSE;
823
 
824
   /* check for '-' */
825
   if (!Peek_Token(s, token))
826
      PARSE_ERROR;
827
   if (token[0] == '-') {
828
      srcReg->Negate = GL_TRUE;
829
      (void) Parse_String(s, "-"); /* consume '-' */
830
      if (!Peek_Token(s, token))
831
         PARSE_ERROR;
832
   }
833
   else {
834
      srcReg->Negate = GL_FALSE;
835
   }
836
 
837
   /* Src reg can be R<n>, c[n], c[n +/- offset], or a named vertex attrib */
838
   if (token[0] == 'R') {
839
      if (!Parse_TempReg(s, &srcReg->Register))
840
         PARSE_ERROR;
841
   }
842
   else if (token[0] == 'c') {
843
      if (!Parse_ParamReg(s, srcReg))
844
         PARSE_ERROR;
845
   }
846
   else if (token[0] == 'v') {
847
      if (!Parse_AttribReg(s, &srcReg->Register))
848
         PARSE_ERROR;
849
   }
850
   else {
851
      PARSE_ERROR2("Bad source register name", token);
852
   }
853
 
854
   /* Look for .[xyzw] suffix */
855
   if (!Parse_String(s, "."))
856
      PARSE_ERROR;
857
 
858
   if (!Parse_Token(s, token))
859
      PARSE_ERROR;
860
 
861
   if (token[0] == 'x' && token[1] == 0) {
862
      srcReg->Swizzle[0] = 0;
863
   }
864
   else if (token[0] == 'y' && token[1] == 0) {
865
      srcReg->Swizzle[0] = 1;
866
   }
867
   else if (token[0] == 'z' && token[1] == 0) {
868
      srcReg->Swizzle[0] = 2;
869
   }
870
   else if (token[0] == 'w' && token[1] == 0) {
871
      srcReg->Swizzle[0] = 3;
872
   }
873
   else {
874
      PARSE_ERROR1("Bad scalar source suffix");
875
   }
876
   srcReg->Swizzle[1] = srcReg->Swizzle[2] = srcReg->Swizzle[3] = 0;
877
 
878
   return GL_TRUE;
879
}
880
 
881
 
882
static GLint
883
Parse_UnaryOpInstruction(const GLubyte **s, struct vp_instruction *inst)
884
{
885
   GLubyte token[100];
886
 
887
   /* opcode */
888
   if (!Parse_Token(s, token))
889
      PARSE_ERROR;
890
 
891
   if (StrEq(token, (GLubyte *) "MOV")) {
892
      inst->Opcode = MOV;
893
   }
894
   else if (StrEq(token, (GLubyte *) "LIT")) {
895
      inst->Opcode = LIT;
896
   }
897
   else if (StrEq(token, (GLubyte *) "ABS") && IsVersion1_1) {
898
      inst->Opcode = ABS;
899
   }
900
   else {
901
      PARSE_ERROR;
902
   }
903
 
904
   /* dest reg */
905
   if (!Parse_MaskedDstReg(s, &inst->DstReg))
906
      PARSE_ERROR;
907
 
908
   /* comma */
909
   if (!Parse_String(s, ","))
910
      PARSE_ERROR;
911
 
912
   /* src arg */
913
   if (!Parse_SwizzleSrcReg(s, &inst->SrcReg[0]))
914
      PARSE_ERROR;
915
 
916
   /* semicolon */
917
   if (!Parse_String(s, ";"))
918
      PARSE_ERROR;
919
 
920
   return GL_TRUE;
921
}
922
 
923
 
924
static GLboolean
925
Parse_BiOpInstruction(const GLubyte **s, struct vp_instruction *inst)
926
{
927
   GLubyte token[100];
928
 
929
   /* opcode */
930
   if (!Parse_Token(s, token))
931
      PARSE_ERROR;
932
 
933
   if (StrEq(token, (GLubyte *) "MUL")) {
934
      inst->Opcode = MUL;
935
   }
936
   else if (StrEq(token, (GLubyte *) "ADD")) {
937
      inst->Opcode = ADD;
938
   }
939
   else if (StrEq(token, (GLubyte *) "DP3")) {
940
      inst->Opcode = DP3;
941
   }
942
   else if (StrEq(token, (GLubyte *) "DP4")) {
943
      inst->Opcode = DP4;
944
   }
945
   else if (StrEq(token, (GLubyte *) "DST")) {
946
      inst->Opcode = DST;
947
   }
948
   else if (StrEq(token, (GLubyte *) "MIN")) {
949
      inst->Opcode = ADD;
950
   }
951
   else if (StrEq(token, (GLubyte *) "MAX")) {
952
      inst->Opcode = ADD;
953
   }
954
   else if (StrEq(token, (GLubyte *) "SLT")) {
955
      inst->Opcode = SLT;
956
   }
957
   else if (StrEq(token, (GLubyte *) "SGE")) {
958
      inst->Opcode = SGE;
959
   }
960
   else if (StrEq(token, (GLubyte *) "DPH") && IsVersion1_1) {
961
      inst->Opcode = DPH;
962
   }
963
   else if (StrEq(token, (GLubyte *) "SUB") && IsVersion1_1) {
964
      inst->Opcode = SUB;
965
   }
966
   else {
967
      PARSE_ERROR;
968
   }
969
 
970
   /* dest reg */
971
   if (!Parse_MaskedDstReg(s, &inst->DstReg))
972
      PARSE_ERROR;
973
 
974
   /* comma */
975
   if (!Parse_String(s, ","))
976
      PARSE_ERROR;
977
 
978
   /* first src arg */
979
   if (!Parse_SwizzleSrcReg(s, &inst->SrcReg[0]))
980
      PARSE_ERROR;
981
 
982
   /* comma */
983
   if (!Parse_String(s, ","))
984
      PARSE_ERROR;
985
 
986
   /* second src arg */
987
   if (!Parse_SwizzleSrcReg(s, &inst->SrcReg[1]))
988
      PARSE_ERROR;
989
 
990
   /* semicolon */
991
   if (!Parse_String(s, ";"))
992
      PARSE_ERROR;
993
 
994
   /* make sure we don't reference more than one program parameter register */
995
   if (IsProgRegister(inst->SrcReg[0].Register) &&
996
       IsProgRegister(inst->SrcReg[1].Register) &&
997
       inst->SrcReg[0].Register != inst->SrcReg[1].Register)
998
      PARSE_ERROR1("Can't reference two program parameter registers");
999
 
1000
   /* make sure we don't reference more than one vertex attribute register */
1001
   if (IsInputRegister(inst->SrcReg[0].Register) &&
1002
       IsInputRegister(inst->SrcReg[1].Register) &&
1003
       inst->SrcReg[0].Register != inst->SrcReg[1].Register)
1004
      PARSE_ERROR1("Can't reference two vertex attribute registers");
1005
 
1006
   return GL_TRUE;
1007
}
1008
 
1009
 
1010
static GLboolean
1011
Parse_TriOpInstruction(const GLubyte **s, struct vp_instruction *inst)
1012
{
1013
   GLubyte token[100];
1014
 
1015
   /* opcode */
1016
   if (!Parse_Token(s, token))
1017
      PARSE_ERROR;
1018
 
1019
   if (StrEq(token, (GLubyte *) "MAD")) {
1020
      inst->Opcode = MAD;
1021
   }
1022
   else {
1023
      PARSE_ERROR;
1024
   }
1025
 
1026
   /* dest reg */
1027
   if (!Parse_MaskedDstReg(s, &inst->DstReg))
1028
      PARSE_ERROR;
1029
 
1030
   /* comma */
1031
   if (!Parse_String(s, ","))
1032
      PARSE_ERROR;
1033
 
1034
   /* first src arg */
1035
   if (!Parse_SwizzleSrcReg(s, &inst->SrcReg[0]))
1036
      PARSE_ERROR;
1037
 
1038
   /* comma */
1039
   if (!Parse_String(s, ","))
1040
      PARSE_ERROR;
1041
 
1042
   /* second src arg */
1043
   if (!Parse_SwizzleSrcReg(s, &inst->SrcReg[1]))
1044
      PARSE_ERROR;
1045
 
1046
   /* comma */
1047
   if (!Parse_String(s, ","))
1048
      PARSE_ERROR;
1049
 
1050
   /* third src arg */
1051
   if (!Parse_SwizzleSrcReg(s, &inst->SrcReg[2]))
1052
      PARSE_ERROR;
1053
 
1054
   /* semicolon */
1055
   if (!Parse_String(s, ";"))
1056
      PARSE_ERROR;
1057
 
1058
   /* make sure we don't reference more than one program parameter register */
1059
   if ((IsProgRegister(inst->SrcReg[0].Register) &&
1060
        IsProgRegister(inst->SrcReg[1].Register) &&
1061
        inst->SrcReg[0].Register != inst->SrcReg[1].Register) ||
1062
       (IsProgRegister(inst->SrcReg[0].Register) &&
1063
        IsProgRegister(inst->SrcReg[2].Register) &&
1064
        inst->SrcReg[0].Register != inst->SrcReg[2].Register) ||
1065
       (IsProgRegister(inst->SrcReg[1].Register) &&
1066
        IsProgRegister(inst->SrcReg[2].Register) &&
1067
        inst->SrcReg[1].Register != inst->SrcReg[2].Register))
1068
      PARSE_ERROR1("Can only reference one program register");
1069
 
1070
   /* make sure we don't reference more than one vertex attribute register */
1071
   if ((IsInputRegister(inst->SrcReg[0].Register) &&
1072
        IsInputRegister(inst->SrcReg[1].Register) &&
1073
        inst->SrcReg[0].Register != inst->SrcReg[1].Register) ||
1074
       (IsInputRegister(inst->SrcReg[0].Register) &&
1075
        IsInputRegister(inst->SrcReg[2].Register) &&
1076
        inst->SrcReg[0].Register != inst->SrcReg[2].Register) ||
1077
       (IsInputRegister(inst->SrcReg[1].Register) &&
1078
        IsInputRegister(inst->SrcReg[2].Register) &&
1079
        inst->SrcReg[1].Register != inst->SrcReg[2].Register))
1080
      PARSE_ERROR1("Can only reference one input register");
1081
 
1082
   return GL_TRUE;
1083
}
1084
 
1085
 
1086
static GLboolean
1087
Parse_ScalarInstruction(const GLubyte **s, struct vp_instruction *inst)
1088
{
1089
   GLubyte token[100];
1090
 
1091
   /* opcode */
1092
   if (!Parse_Token(s, token))
1093
      PARSE_ERROR;
1094
 
1095
   if (StrEq(token, (GLubyte *) "RCP")) {
1096
      inst->Opcode = RCP;
1097
   }
1098
   else if (StrEq(token, (GLubyte *) "RSQ")) {
1099
      inst->Opcode = RSQ;
1100
   }
1101
   else if (StrEq(token, (GLubyte *) "EXP")) {
1102
      inst->Opcode = EXP;
1103
   }
1104
   else if (StrEq(token, (GLubyte *) "LOG")) {
1105
      inst->Opcode = LOG;
1106
   }
1107
   else if (StrEq(token, (GLubyte *) "RCC") && IsVersion1_1) {
1108
      inst->Opcode = RCC;
1109
   }
1110
   else {
1111
      PARSE_ERROR;
1112
   }
1113
 
1114
   /* dest reg */
1115
   if (!Parse_MaskedDstReg(s, &inst->DstReg))
1116
      PARSE_ERROR;
1117
 
1118
   /* comma */
1119
   if (!Parse_String(s, ","))
1120
      PARSE_ERROR;
1121
 
1122
   /* first src arg */
1123
   if (!Parse_ScalarSrcReg(s, &inst->SrcReg[0]))
1124
      PARSE_ERROR;
1125
 
1126
   /* semicolon */
1127
   if (!Parse_String(s, ";"))
1128
      PARSE_ERROR;
1129
 
1130
   return GL_TRUE;
1131
}
1132
 
1133
 
1134
static GLboolean
1135
Parse_AddressInstruction(const GLubyte **s, struct vp_instruction *inst)
1136
{
1137
   inst->Opcode = ARL;
1138
 
1139
   /* opcode */
1140
   if (!Parse_String(s, "ARL"))
1141
      PARSE_ERROR;
1142
 
1143
   /* dest A0 reg */
1144
   if (!Parse_AddrReg(s))
1145
      PARSE_ERROR;
1146
 
1147
   /* comma */
1148
   if (!Parse_String(s, ","))
1149
      PARSE_ERROR;
1150
 
1151
   /* parse src reg */
1152
   if (!Parse_ScalarSrcReg(s, &inst->SrcReg[0]))
1153
      PARSE_ERROR;
1154
 
1155
   /* semicolon */
1156
   if (!Parse_String(s, ";"))
1157
      PARSE_ERROR;
1158
 
1159
   return GL_TRUE;
1160
}
1161
 
1162
 
1163
static GLboolean
1164
Parse_EndInstruction(const GLubyte **s, struct vp_instruction *inst)
1165
{
1166
   GLubyte token[100];
1167
 
1168
   /* opcode */
1169
   if (!Parse_String(s, "END"))
1170
      PARSE_ERROR;
1171
 
1172
   inst->Opcode = END;
1173
 
1174
   /* this should fail! */
1175
   if (Parse_Token(s, token))
1176
      PARSE_ERROR2("Unexpected token after END:", token);
1177
   else
1178
      return GL_TRUE;
1179
}
1180
 
1181
 
1182
static GLboolean
1183
Parse_OptionSequence(const GLubyte **s, struct vp_instruction program[])
1184
{
1185
   while (1) {
1186
      GLubyte token[100];
1187
      if (!Peek_Token(s, token)) {
1188
         PARSE_ERROR1("Unexpected end of input");
1189
         return GL_FALSE; /* end of input */
1190
      }
1191
 
1192
      if (!StrEq(token, (GLubyte *) "OPTION"))
1193
         return GL_TRUE;  /* probably an instruction */
1194
 
1195
      Parse_Token(s, token);
1196
 
1197
      if (!Parse_String(s, "NV_position_invariant"))
1198
         return GL_FALSE;
1199
      if (!Parse_String(s, ";"))
1200
         return GL_FALSE;
1201
      IsPositionInvariant = GL_TRUE;
1202
   }
1203
}
1204
 
1205
 
1206
static GLboolean
1207
Parse_InstructionSequence(const GLubyte **s, struct vp_instruction program[])
1208
{
1209
   GLubyte token[100];
1210
   GLint count = 0;
1211
 
1212
   while (1) {
1213
      struct vp_instruction *inst = program + count;
1214
 
1215
      /* Initialize the instruction */
1216
      inst->SrcReg[0].Register = -1;
1217
      inst->SrcReg[1].Register = -1;
1218
      inst->SrcReg[2].Register = -1;
1219
      inst->DstReg.Register = -1;
1220
 
1221
      if (!Peek_Token(s, token))
1222
         PARSE_ERROR;
1223
 
1224
      if (StrEq(token, (GLubyte *) "MOV") ||
1225
          StrEq(token, (GLubyte *) "LIT") ||
1226
          StrEq(token, (GLubyte *) "ABS")) {
1227
         if (!Parse_UnaryOpInstruction(s, inst))
1228
            PARSE_ERROR;
1229
      }
1230
      else if (StrEq(token, (GLubyte *) "MUL") ||
1231
          StrEq(token, (GLubyte *) "ADD") ||
1232
          StrEq(token, (GLubyte *) "DP3") ||
1233
          StrEq(token, (GLubyte *) "DP4") ||
1234
          StrEq(token, (GLubyte *) "DST") ||
1235
          StrEq(token, (GLubyte *) "MIN") ||
1236
          StrEq(token, (GLubyte *) "MAX") ||
1237
          StrEq(token, (GLubyte *) "SLT") ||
1238
          StrEq(token, (GLubyte *) "SGE") ||
1239
          StrEq(token, (GLubyte *) "DPH") ||
1240
          StrEq(token, (GLubyte *) "SUB")) {
1241
         if (!Parse_BiOpInstruction(s, inst))
1242
            PARSE_ERROR;
1243
      }
1244
      else if (StrEq(token, (GLubyte *) "MAD")) {
1245
         if (!Parse_TriOpInstruction(s, inst))
1246
            PARSE_ERROR;
1247
      }
1248
      else if (StrEq(token, (GLubyte *) "RCP") ||
1249
               StrEq(token, (GLubyte *) "RSQ") ||
1250
               StrEq(token, (GLubyte *) "EXP") ||
1251
               StrEq(token, (GLubyte *) "LOG") ||
1252
               StrEq(token, (GLubyte *) "RCC")) {
1253
         if (!Parse_ScalarInstruction(s, inst))
1254
            PARSE_ERROR;
1255
      }
1256
      else if (StrEq(token, (GLubyte *) "ARL")) {
1257
         if (!Parse_AddressInstruction(s, inst))
1258
            PARSE_ERROR;
1259
      }
1260
      else if (StrEq(token, (GLubyte *) "END")) {
1261
         if (!Parse_EndInstruction(s, inst))
1262
            PARSE_ERROR;
1263
         else
1264
            return GL_TRUE;  /* all done */
1265
      }
1266
      else {
1267
         /* bad instruction name */
1268
         PARSE_ERROR2("Unexpected token: ", token);
1269
      }
1270
 
1271
      count++;
1272
      if (count >= VP_MAX_INSTRUCTIONS)
1273
         PARSE_ERROR1("Program too long");
1274
   }
1275
 
1276
   PARSE_ERROR;
1277
}
1278
 
1279
 
1280
static GLboolean
1281
Parse_Program(const GLubyte **s, struct vp_instruction instBuffer[])
1282
{
1283
   if (IsVersion1_1) {
1284
      if (!Parse_OptionSequence(s, instBuffer)) {
1285
         return GL_FALSE;
1286
      }
1287
   }
1288
   return Parse_InstructionSequence(s, instBuffer);
1289
}
1290
 
1291
 
1292
/**
1293
 * Parse/compile the 'str' returning the compiled 'program'.
1294
 * ctx->VertexProgram.ErrorPos will be -1 if successful.  Otherwise, ErrorPos
1295
 * indicates the position of the error in 'str'.
1296
 */
1297
void
1298
_mesa_parse_program(GLcontext *ctx, GLenum dstTarget,
1299
                    const GLubyte *str, struct vp_program *program)
1300
{
1301
   const GLubyte *s;
1302
   struct vp_instruction instBuffer[VP_MAX_INSTRUCTIONS];
1303
   GLubyte *newString;
1304
   struct vp_instruction *newInst;
1305
   GLenum target;
1306
 
1307
   ctx->VertexProgram.ErrorPos = -1;
1308
   IsPositionInvariant = GL_FALSE;
1309
   IsVersion1_1 = GL_FALSE;
1310
 
1311
   /* check the program header */
1312
   if (_mesa_strncmp((const char *) str, "!!VP1.0", 7) == 0) {
1313
      target = GL_VERTEX_PROGRAM_NV;
1314
      s = str + 7;
1315
      IsStateProgram = GL_FALSE;
1316
   }
1317
   else if (_mesa_strncmp((const char *) str, "!!VP1.1", 7) == 0) {
1318
      target = GL_VERTEX_PROGRAM_NV;
1319
      s = str + 7;
1320
      IsStateProgram = GL_FALSE;
1321
      IsVersion1_1 = GL_TRUE;
1322
   }
1323
   else if (_mesa_strncmp((const char *) str, "!!VSP1.0", 8) == 0) {
1324
      target = GL_VERTEX_STATE_PROGRAM_NV;
1325
      s = str + 8;
1326
      IsStateProgram = GL_TRUE;
1327
   }
1328
   else {
1329
      /* invalid header */
1330
      ctx->VertexProgram.ErrorPos = 0;
1331
      _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(bad header)");
1332
      return;
1333
   }
1334
 
1335
   /* make sure target and header match */
1336
   if (target != dstTarget) {
1337
      _mesa_error(ctx, GL_INVALID_OPERATION,
1338
                  "glLoadProgramNV(target mismatch)");
1339
      return;
1340
   }
1341
 
1342
   if (Parse_Program(&s, instBuffer)) {
1343
      GLuint numInst;
1344
      GLuint strLen;
1345
      GLuint inputsRead = 0;
1346
      GLuint outputsWritten = 0;
1347
      GLuint progRegsWritten = 0;
1348
 
1349
      /* Find length of the program and compute bitmasks to indicate which
1350
       * vertex input registers are read, which vertex result registers are
1351
       * written to, and which program registers are written to.
1352
       * We could actually do this while we parse the program.
1353
       */
1354
      for (numInst = 0; instBuffer[numInst].Opcode != END; numInst++) {
1355
         const GLint srcReg0 = instBuffer[numInst].SrcReg[0].Register;
1356
         const GLint srcReg1 = instBuffer[numInst].SrcReg[1].Register;
1357
         const GLint srcReg2 = instBuffer[numInst].SrcReg[2].Register;
1358
         const GLint dstReg = instBuffer[numInst].DstReg.Register;
1359
 
1360
         if (IsOutputRegister(dstReg))
1361
            outputsWritten |= (1 << (dstReg - VP_OUTPUT_REG_START));
1362
         else if (IsProgRegister(dstReg))
1363
            progRegsWritten |= (1 << (dstReg - VP_PROG_REG_START));
1364
         if (IsInputRegister(srcReg0)
1365
             && !instBuffer[numInst].SrcReg[0].RelAddr)
1366
            inputsRead |= (1 << (srcReg0 - VP_INPUT_REG_START));
1367
         if (IsInputRegister(srcReg1)
1368
             && !instBuffer[numInst].SrcReg[1].RelAddr)
1369
            inputsRead |= (1 << (srcReg1 - VP_INPUT_REG_START));
1370
         if (IsInputRegister(srcReg2)
1371
             && !instBuffer[numInst].SrcReg[2].RelAddr)
1372
            inputsRead |= (1 << (srcReg2 - VP_INPUT_REG_START));
1373
      }
1374
      numInst++;
1375
 
1376
      if (IsStateProgram) {
1377
         if (progRegsWritten == 0) {
1378
            _mesa_error(ctx, GL_INVALID_OPERATION,
1379
                        "glLoadProgramNV(c[#] not written)");
1380
            return;
1381
         }
1382
      }
1383
      else {
1384
         if (!IsPositionInvariant && !(outputsWritten & 1)) {
1385
            /* bit 1 = HPOS register */
1386
            _mesa_error(ctx, GL_INVALID_OPERATION,
1387
                        "glLoadProgramNV(HPOS not written)");
1388
            return;
1389
         }
1390
      }
1391
 
1392
      program->InputsRead = inputsRead;
1393
      program->OutputsWritten = outputsWritten;
1394
      program->IsPositionInvariant = IsPositionInvariant;
1395
 
1396
      /* make copy of the input program string */
1397
      strLen = _mesa_strlen((const char *) str);
1398
      newString = (GLubyte *) MALLOC(strLen + 1);
1399
      if (!newString) {
1400
         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
1401
         return;
1402
      }
1403
      MEMCPY(newString, str, strLen);
1404
      newString[strLen] = 0; /* terminate */
1405
 
1406
      /* copy the compiled instructions */
1407
      assert(numInst <= VP_MAX_INSTRUCTIONS);
1408
      newInst = (struct vp_instruction *) MALLOC(numInst * sizeof(struct vp_instruction));
1409
      if (!newInst) {
1410
         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
1411
         return;  /* out of memory */
1412
      }
1413
      MEMCPY(newInst, instBuffer, numInst * sizeof(struct vp_instruction));
1414
 
1415
      /* install the program */
1416
      program->Target = target;
1417
      if (program->String) {
1418
         FREE(program->String);
1419
      }
1420
      program->String = newString;
1421
      if (program->Instructions) {
1422
         FREE(program->Instructions);
1423
      }
1424
      program->Instructions = newInst;
1425
 
1426
#ifdef DEBUG_foo
1427
      _mesa_printf("--- glLoadProgramNV result ---\n");
1428
      _mesa_print_program(program);
1429
      _mesa_printf("------------------------------\n");
1430
#endif
1431
   }
1432
   else {
1433
      /* Error! */
1434
#ifdef DEBUG
1435
      /* print a message showing the program line containing the error */
1436
      ctx->VertexProgram.ErrorPos = s - str;
1437
      {
1438
         const GLubyte *p = str, *line = str;
1439
         int lineNum = 1, statementNum = 1, column = 0;
1440
         char errorLine[1000];
1441
         int i;
1442
         while (*p && p < s) {  /* s is the error position */
1443
            if (*p == '\n') {
1444
               line = p + 1;
1445
               lineNum++;
1446
               column = 0;
1447
            }
1448
            else if (*p == ';') {
1449
               statementNum++;
1450
            }
1451
            else
1452
               column++;
1453
            p++;
1454
         }
1455
         if (p) {
1456
            /* Copy the line with the error into errorLine so we can null-
1457
             * terminate it.
1458
             */
1459
            for (i = 0; line[i] != '\n' && line[i]; i++)
1460
               errorLine[i] = (char) line[i];
1461
            errorLine[i] = 0;
1462
         }
1463
         /*
1464
         _mesa_debug("Error pos = %d  (%c) col %d\n",
1465
                 ctx->VertexProgram.ErrorPos, *s, column);
1466
         */
1467
         _mesa_debug(ctx, "Vertex program error on line %2d: %s\n", lineNum, errorLine);
1468
         _mesa_debug(ctx, "  (statement %2d) near column %2d: ", statementNum, column+1);
1469
         for (i = 0; i < column; i++)
1470
            _mesa_debug(ctx, " ");
1471
         _mesa_debug(ctx, "^\n");
1472
      }
1473
#endif
1474
      _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV");
1475
   }
1476
}
1477
 
1478
 
1479
static void
1480
PrintSrcReg(const struct vp_src_register *src)
1481
{
1482
   static const char comps[5] = "xyzw";
1483
   if (src->Negate)
1484
      _mesa_printf("-");
1485
   if (src->RelAddr) {
1486
      if (src->Register > 0)
1487
         _mesa_printf("c[A0.x + %d]", src->Register);
1488
      else if (src->Register < 0)
1489
         _mesa_printf("c[A0.x - %d]", -src->Register);
1490
      else
1491
         _mesa_printf("c[A0.x]");
1492
   }
1493
   else if (src->Register >= VP_OUTPUT_REG_START
1494
       && src->Register <= VP_OUTPUT_REG_END) {
1495
      _mesa_printf("o[%s]", OutputRegisters[src->Register - VP_OUTPUT_REG_START]);
1496
   }
1497
   else if (src->Register >= VP_INPUT_REG_START
1498
            && src->Register <= VP_INPUT_REG_END) {
1499
      _mesa_printf("v[%s]", InputRegisters[src->Register - VP_INPUT_REG_START]);
1500
   }
1501
   else if (src->Register >= VP_PROG_REG_START
1502
            && src->Register <= VP_PROG_REG_END) {
1503
      _mesa_printf("c[%d]", src->Register - VP_PROG_REG_START);
1504
   }
1505
   else {
1506
      _mesa_printf("R%d", src->Register - VP_TEMP_REG_START);
1507
   }
1508
 
1509
   if (src->Swizzle[0] == src->Swizzle[1] &&
1510
       src->Swizzle[0] == src->Swizzle[2] &&
1511
       src->Swizzle[0] == src->Swizzle[3]) {
1512
      _mesa_printf(".%c", comps[src->Swizzle[0]]);
1513
   }
1514
   else if (src->Swizzle[0] != 0 ||
1515
            src->Swizzle[1] != 1 ||
1516
            src->Swizzle[2] != 2 ||
1517
            src->Swizzle[3] != 3) {
1518
      _mesa_printf(".%c%c%c%c",
1519
             comps[src->Swizzle[0]],
1520
             comps[src->Swizzle[1]],
1521
             comps[src->Swizzle[2]],
1522
             comps[src->Swizzle[3]]);
1523
   }
1524
}
1525
 
1526
 
1527
static void
1528
PrintDstReg(const struct vp_dst_register *dst)
1529
{
1530
   GLint w = dst->WriteMask[0] + dst->WriteMask[1]
1531
           + dst->WriteMask[2] + dst->WriteMask[3];
1532
 
1533
   if (dst->Register >= VP_OUTPUT_REG_START
1534
       && dst->Register <= VP_OUTPUT_REG_END) {
1535
      _mesa_printf("o[%s]", OutputRegisters[dst->Register - VP_OUTPUT_REG_START]);
1536
   }
1537
   else if (dst->Register >= VP_INPUT_REG_START
1538
            && dst->Register <= VP_INPUT_REG_END) {
1539
      _mesa_printf("v[%s]", InputRegisters[dst->Register - VP_INPUT_REG_START]);
1540
   }
1541
   else if (dst->Register >= VP_PROG_REG_START
1542
            && dst->Register <= VP_PROG_REG_END) {
1543
      _mesa_printf("c[%d]", dst->Register - VP_PROG_REG_START);
1544
   }
1545
   else {
1546
      _mesa_printf("R%d", dst->Register - VP_TEMP_REG_START);
1547
   }
1548
 
1549
   if (w != 0 && w != 4) {
1550
      _mesa_printf(".");
1551
      if (dst->WriteMask[0])
1552
         _mesa_printf("x");
1553
      if (dst->WriteMask[1])
1554
         _mesa_printf("y");
1555
      if (dst->WriteMask[2])
1556
         _mesa_printf("z");
1557
      if (dst->WriteMask[3])
1558
         _mesa_printf("w");
1559
   }
1560
}
1561
 
1562
 
1563
/**
1564
 * Print (unparse) the given vertex program.  Just for debugging.
1565
 */
1566
void
1567
_mesa_print_program(const struct vp_program *program)
1568
{
1569
   const struct vp_instruction *inst;
1570
 
1571
   for (inst = program->Instructions; ; inst++) {
1572
      switch (inst->Opcode) {
1573
      case MOV:
1574
      case LIT:
1575
      case RCP:
1576
      case RSQ:
1577
      case EXP:
1578
      case LOG:
1579
      case RCC:
1580
      case ABS:
1581
         _mesa_printf("%s ", Opcodes[(int) inst->Opcode]);
1582
         PrintDstReg(&inst->DstReg);
1583
         _mesa_printf(", ");
1584
         PrintSrcReg(&inst->SrcReg[0]);
1585
         _mesa_printf(";\n");
1586
         break;
1587
      case MUL:
1588
      case ADD:
1589
      case DP3:
1590
      case DP4:
1591
      case DST:
1592
      case MIN:
1593
      case MAX:
1594
      case SLT:
1595
      case SGE:
1596
      case DPH:
1597
      case SUB:
1598
         _mesa_printf("%s ", Opcodes[(int) inst->Opcode]);
1599
         PrintDstReg(&inst->DstReg);
1600
         _mesa_printf(", ");
1601
         PrintSrcReg(&inst->SrcReg[0]);
1602
         _mesa_printf(", ");
1603
         PrintSrcReg(&inst->SrcReg[1]);
1604
         _mesa_printf(";\n");
1605
         break;
1606
      case MAD:
1607
         _mesa_printf("MAD ");
1608
         PrintDstReg(&inst->DstReg);
1609
         _mesa_printf(", ");
1610
         PrintSrcReg(&inst->SrcReg[0]);
1611
         _mesa_printf(", ");
1612
         PrintSrcReg(&inst->SrcReg[1]);
1613
         _mesa_printf(", ");
1614
         PrintSrcReg(&inst->SrcReg[2]);
1615
         _mesa_printf(";\n");
1616
         break;
1617
      case ARL:
1618
         _mesa_printf("ARL A0.x, ");
1619
         PrintSrcReg(&inst->SrcReg[0]);
1620
         _mesa_printf(";\n");
1621
         break;
1622
      case END:
1623
         _mesa_printf("END\n");
1624
         return;
1625
         break;
1626
      default:
1627
         _mesa_printf("BAD INSTRUCTION\n");
1628
      }
1629
   }
1630
}
1631