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.3
4
 *
5
 * Copyright (C) 1999-2007  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 program.c
27
 * Vertex and fragment program support functions.
28
 * \author Brian Paul
29
 */
30
 
31
 
32
#include "main/glheader.h"
33
#include "main/context.h"
34
#include "main/hash.h"
35
#include "program.h"
36
#include "prog_cache.h"
37
#include "prog_parameter.h"
38
#include "prog_instruction.h"
39
 
40
 
41
/**
42
 * A pointer to this dummy program is put into the hash table when
43
 * glGenPrograms is called.
44
 */
45
struct gl_program _mesa_DummyProgram;
46
 
47
 
48
/**
49
 * Init context's vertex/fragment program state
50
 */
51
void
52
_mesa_init_program(struct gl_context *ctx)
53
{
54
   GLuint i;
55
 
56
   /*
57
    * If this assertion fails, we need to increase the field
58
    * size for register indexes (see INST_INDEX_BITS).
59
    */
60
   ASSERT(ctx->Const.VertexProgram.MaxUniformComponents / 4
61
          <= (1 << INST_INDEX_BITS));
62
   ASSERT(ctx->Const.FragmentProgram.MaxUniformComponents / 4
63
          <= (1 << INST_INDEX_BITS));
64
 
65
   ASSERT(ctx->Const.VertexProgram.MaxTemps <= (1 << INST_INDEX_BITS));
66
   ASSERT(ctx->Const.VertexProgram.MaxLocalParams <= (1 << INST_INDEX_BITS));
67
   ASSERT(ctx->Const.FragmentProgram.MaxTemps <= (1 << INST_INDEX_BITS));
68
   ASSERT(ctx->Const.FragmentProgram.MaxLocalParams <= (1 << INST_INDEX_BITS));
69
 
70
   ASSERT(ctx->Const.VertexProgram.MaxUniformComponents <= 4 * MAX_UNIFORMS);
71
   ASSERT(ctx->Const.FragmentProgram.MaxUniformComponents <= 4 * MAX_UNIFORMS);
72
 
73
   /* If this fails, increase prog_instruction::TexSrcUnit size */
74
   ASSERT(MAX_TEXTURE_UNITS < (1 << 5));
75
 
76
   /* If this fails, increase prog_instruction::TexSrcTarget size */
77
   ASSERT(NUM_TEXTURE_TARGETS < (1 << 3));
78
 
79
   ctx->Program.ErrorPos = -1;
80
   ctx->Program.ErrorString = _mesa_strdup("");
81
 
82
#if FEATURE_NV_vertex_program || FEATURE_ARB_vertex_program
83
   ctx->VertexProgram.Enabled = GL_FALSE;
84
#if FEATURE_es2_glsl
85
   ctx->VertexProgram.PointSizeEnabled =
86
      (ctx->API == API_OPENGLES2) ? GL_TRUE : GL_FALSE;
87
#else
88
   ctx->VertexProgram.PointSizeEnabled = GL_FALSE;
89
#endif
90
   ctx->VertexProgram.TwoSideEnabled = GL_FALSE;
91
   _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current,
92
                            ctx->Shared->DefaultVertexProgram);
93
   assert(ctx->VertexProgram.Current);
94
   for (i = 0; i < MAX_NV_VERTEX_PROGRAM_PARAMS / 4; i++) {
95
      ctx->VertexProgram.TrackMatrix[i] = GL_NONE;
96
      ctx->VertexProgram.TrackMatrixTransform[i] = GL_IDENTITY_NV;
97
   }
98
   ctx->VertexProgram.Cache = _mesa_new_program_cache();
99
#endif
100
 
101
#if FEATURE_NV_fragment_program || FEATURE_ARB_fragment_program
102
   ctx->FragmentProgram.Enabled = GL_FALSE;
103
   _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current,
104
                            ctx->Shared->DefaultFragmentProgram);
105
   assert(ctx->FragmentProgram.Current);
106
   ctx->FragmentProgram.Cache = _mesa_new_program_cache();
107
#endif
108
 
109
#if FEATURE_ARB_geometry_shader4
110
   ctx->GeometryProgram.Enabled = GL_FALSE;
111
   /* right now by default we don't have a geometry program */
112
   _mesa_reference_geomprog(ctx, &ctx->GeometryProgram.Current,
113
                            NULL);
114
   ctx->GeometryProgram.Cache = _mesa_new_program_cache();
115
#endif
116
 
117
   /* XXX probably move this stuff */
118
#if FEATURE_ATI_fragment_shader
119
   ctx->ATIFragmentShader.Enabled = GL_FALSE;
120
   ctx->ATIFragmentShader.Current = ctx->Shared->DefaultFragmentShader;
121
   assert(ctx->ATIFragmentShader.Current);
122
   ctx->ATIFragmentShader.Current->RefCount++;
123
#endif
124
}
125
 
126
 
127
/**
128
 * Free a context's vertex/fragment program state
129
 */
130
void
131
_mesa_free_program_data(struct gl_context *ctx)
132
{
133
#if FEATURE_NV_vertex_program || FEATURE_ARB_vertex_program
134
   _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current, NULL);
135
   _mesa_delete_program_cache(ctx, ctx->VertexProgram.Cache);
136
#endif
137
#if FEATURE_NV_fragment_program || FEATURE_ARB_fragment_program
138
   _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current, NULL);
139
   _mesa_delete_program_cache(ctx, ctx->FragmentProgram.Cache);
140
#endif
141
#if FEATURE_ARB_geometry_shader4
142
   _mesa_reference_geomprog(ctx, &ctx->GeometryProgram.Current, NULL);
143
   _mesa_delete_program_cache(ctx, ctx->GeometryProgram.Cache);
144
#endif
145
   /* XXX probably move this stuff */
146
#if FEATURE_ATI_fragment_shader
147
   if (ctx->ATIFragmentShader.Current) {
148
      ctx->ATIFragmentShader.Current->RefCount--;
149
      if (ctx->ATIFragmentShader.Current->RefCount <= 0) {
150
         free(ctx->ATIFragmentShader.Current);
151
      }
152
   }
153
#endif
154
   free((void *) ctx->Program.ErrorString);
155
}
156
 
157
 
158
/**
159
 * Update the default program objects in the given context to reference those
160
 * specified in the shared state and release those referencing the old
161
 * shared state.
162
 */
163
void
164
_mesa_update_default_objects_program(struct gl_context *ctx)
165
{
166
#if FEATURE_NV_vertex_program || FEATURE_ARB_vertex_program
167
   _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current,
168
                            (struct gl_vertex_program *)
169
                            ctx->Shared->DefaultVertexProgram);
170
   assert(ctx->VertexProgram.Current);
171
#endif
172
 
173
#if FEATURE_NV_fragment_program || FEATURE_ARB_fragment_program
174
   _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current,
175
                            (struct gl_fragment_program *)
176
                            ctx->Shared->DefaultFragmentProgram);
177
   assert(ctx->FragmentProgram.Current);
178
#endif
179
 
180
#if FEATURE_ARB_geometry_shader4
181
   _mesa_reference_geomprog(ctx, &ctx->GeometryProgram.Current,
182
                            (struct gl_geometry_program *)
183
                            ctx->Shared->DefaultGeometryProgram);
184
#endif
185
 
186
   /* XXX probably move this stuff */
187
#if FEATURE_ATI_fragment_shader
188
   if (ctx->ATIFragmentShader.Current) {
189
      ctx->ATIFragmentShader.Current->RefCount--;
190
      if (ctx->ATIFragmentShader.Current->RefCount <= 0) {
191
         free(ctx->ATIFragmentShader.Current);
192
      }
193
   }
194
   ctx->ATIFragmentShader.Current = (struct ati_fragment_shader *) ctx->Shared->DefaultFragmentShader;
195
   assert(ctx->ATIFragmentShader.Current);
196
   ctx->ATIFragmentShader.Current->RefCount++;
197
#endif
198
}
199
 
200
 
201
/**
202
 * Set the vertex/fragment program error state (position and error string).
203
 * This is generally called from within the parsers.
204
 */
205
void
206
_mesa_set_program_error(struct gl_context *ctx, GLint pos, const char *string)
207
{
208
   ctx->Program.ErrorPos = pos;
209
   free((void *) ctx->Program.ErrorString);
210
   if (!string)
211
      string = "";
212
   ctx->Program.ErrorString = _mesa_strdup(string);
213
}
214
 
215
 
216
/**
217
 * Find the line number and column for 'pos' within 'string'.
218
 * Return a copy of the line which contains 'pos'.  Free the line with
219
 * free().
220
 * \param string  the program string
221
 * \param pos     the position within the string
222
 * \param line    returns the line number corresponding to 'pos'.
223
 * \param col     returns the column number corresponding to 'pos'.
224
 * \return copy of the line containing 'pos'.
225
 */
226
const GLubyte *
227
_mesa_find_line_column(const GLubyte *string, const GLubyte *pos,
228
                       GLint *line, GLint *col)
229
{
230
   const GLubyte *lineStart = string;
231
   const GLubyte *p = string;
232
   GLubyte *s;
233
   int len;
234
 
235
   *line = 1;
236
 
237
   while (p != pos) {
238
      if (*p == (GLubyte) '\n') {
239
         (*line)++;
240
         lineStart = p + 1;
241
      }
242
      p++;
243
   }
244
 
245
   *col = (pos - lineStart) + 1;
246
 
247
   /* return copy of this line */
248
   while (*p != 0 && *p != '\n')
249
      p++;
250
   len = p - lineStart;
251
   s = (GLubyte *) malloc(len + 1);
252
   memcpy(s, lineStart, len);
253
   s[len] = 0;
254
 
255
   return s;
256
}
257
 
258
 
259
/**
260
 * Initialize a new vertex/fragment program object.
261
 */
262
static struct gl_program *
263
_mesa_init_program_struct( struct gl_context *ctx, struct gl_program *prog,
264
                           GLenum target, GLuint id)
265
{
266
   (void) ctx;
267
   if (prog) {
268
      GLuint i;
269
      memset(prog, 0, sizeof(*prog));
270
      prog->Id = id;
271
      prog->Target = target;
272
      prog->Resident = GL_TRUE;
273
      prog->RefCount = 1;
274
      prog->Format = GL_PROGRAM_FORMAT_ASCII_ARB;
275
 
276
      /* default mapping from samplers to texture units */
277
      for (i = 0; i < MAX_SAMPLERS; i++)
278
         prog->SamplerUnits[i] = i;
279
   }
280
 
281
   return prog;
282
}
283
 
284
 
285
/**
286
 * Initialize a new fragment program object.
287
 */
288
struct gl_program *
289
_mesa_init_fragment_program( struct gl_context *ctx, struct gl_fragment_program *prog,
290
                             GLenum target, GLuint id)
291
{
292
   if (prog)
293
      return _mesa_init_program_struct( ctx, &prog->Base, target, id );
294
   else
295
      return NULL;
296
}
297
 
298
 
299
/**
300
 * Initialize a new vertex program object.
301
 */
302
struct gl_program *
303
_mesa_init_vertex_program( struct gl_context *ctx, struct gl_vertex_program *prog,
304
                           GLenum target, GLuint id)
305
{
306
   if (prog)
307
      return _mesa_init_program_struct( ctx, &prog->Base, target, id );
308
   else
309
      return NULL;
310
}
311
 
312
 
313
/**
314
 * Initialize a new geometry program object.
315
 */
316
struct gl_program *
317
_mesa_init_geometry_program( struct gl_context *ctx, struct gl_geometry_program *prog,
318
                             GLenum target, GLuint id)
319
{
320
   if (prog)
321
      return _mesa_init_program_struct( ctx, &prog->Base, target, id );
322
   else
323
      return NULL;
324
}
325
 
326
 
327
/**
328
 * Allocate and initialize a new fragment/vertex program object but
329
 * don't put it into the program hash table.  Called via
330
 * ctx->Driver.NewProgram.  May be overridden (ie. replaced) by a
331
 * device driver function to implement OO deriviation with additional
332
 * types not understood by this function.
333
 *
334
 * \param ctx  context
335
 * \param id   program id/number
336
 * \param target  program target/type
337
 * \return  pointer to new program object
338
 */
339
struct gl_program *
340
_mesa_new_program(struct gl_context *ctx, GLenum target, GLuint id)
341
{
342
   struct gl_program *prog;
343
   switch (target) {
344
   case GL_VERTEX_PROGRAM_ARB: /* == GL_VERTEX_PROGRAM_NV */
345
   case GL_VERTEX_STATE_PROGRAM_NV:
346
      prog = _mesa_init_vertex_program(ctx, CALLOC_STRUCT(gl_vertex_program),
347
                                       target, id );
348
      break;
349
   case GL_FRAGMENT_PROGRAM_NV:
350
   case GL_FRAGMENT_PROGRAM_ARB:
351
      prog =_mesa_init_fragment_program(ctx,
352
                                         CALLOC_STRUCT(gl_fragment_program),
353
                                         target, id );
354
      break;
355
   case MESA_GEOMETRY_PROGRAM:
356
      prog = _mesa_init_geometry_program(ctx,
357
                                         CALLOC_STRUCT(gl_geometry_program),
358
                                         target, id);
359
      break;
360
   default:
361
      _mesa_problem(ctx, "bad target in _mesa_new_program");
362
      prog = NULL;
363
   }
364
   return prog;
365
}
366
 
367
 
368
/**
369
 * Delete a program and remove it from the hash table, ignoring the
370
 * reference count.
371
 * Called via ctx->Driver.DeleteProgram.  May be wrapped (OO deriviation)
372
 * by a device driver function.
373
 */
374
void
375
_mesa_delete_program(struct gl_context *ctx, struct gl_program *prog)
376
{
377
   (void) ctx;
378
   ASSERT(prog);
379
   ASSERT(prog->RefCount==0);
380
 
381
   if (prog == &_mesa_DummyProgram)
382
      return;
383
 
384
   if (prog->String)
385
      free(prog->String);
386
 
387
   _mesa_free_instructions(prog->Instructions, prog->NumInstructions);
388
 
389
   if (prog->Parameters) {
390
      _mesa_free_parameter_list(prog->Parameters);
391
   }
392
   if (prog->Varying) {
393
      _mesa_free_parameter_list(prog->Varying);
394
   }
395
   if (prog->Attributes) {
396
      _mesa_free_parameter_list(prog->Attributes);
397
   }
398
 
399
   free(prog);
400
}
401
 
402
 
403
/**
404
 * Return the gl_program object for a given ID.
405
 * Basically just a wrapper for _mesa_HashLookup() to avoid a lot of
406
 * casts elsewhere.
407
 */
408
struct gl_program *
409
_mesa_lookup_program(struct gl_context *ctx, GLuint id)
410
{
411
   if (id)
412
      return (struct gl_program *) _mesa_HashLookup(ctx->Shared->Programs, id);
413
   else
414
      return NULL;
415
}
416
 
417
 
418
/**
419
 * Reference counting for vertex/fragment programs
420
 */
421
void
422
_mesa_reference_program(struct gl_context *ctx,
423
                        struct gl_program **ptr,
424
                        struct gl_program *prog)
425
{
426
   assert(ptr);
427
   if (*ptr && prog) {
428
      /* sanity check */
429
      if ((*ptr)->Target == GL_VERTEX_PROGRAM_ARB)
430
         ASSERT(prog->Target == GL_VERTEX_PROGRAM_ARB);
431
      else if ((*ptr)->Target == GL_FRAGMENT_PROGRAM_ARB)
432
         ASSERT(prog->Target == GL_FRAGMENT_PROGRAM_ARB ||
433
                prog->Target == GL_FRAGMENT_PROGRAM_NV);
434
      else if ((*ptr)->Target == MESA_GEOMETRY_PROGRAM)
435
         ASSERT(prog->Target == MESA_GEOMETRY_PROGRAM);
436
   }
437
   if (*ptr == prog) {
438
      return;  /* no change */
439
   }
440
   if (*ptr) {
441
      GLboolean deleteFlag;
442
 
443
      /*_glthread_LOCK_MUTEX((*ptr)->Mutex);*/
444
#if 0
445
      printf("Program %p ID=%u Target=%s  Refcount-- to %d\n",
446
             *ptr, (*ptr)->Id,
447
             ((*ptr)->Target == GL_VERTEX_PROGRAM_ARB ? "VP" :
448
              ((*ptr)->Target == MESA_GEOMETRY_PROGRAM ? "GP" : "FP")),
449
             (*ptr)->RefCount - 1);
450
#endif
451
      ASSERT((*ptr)->RefCount > 0);
452
      (*ptr)->RefCount--;
453
 
454
      deleteFlag = ((*ptr)->RefCount == 0);
455
      /*_glthread_UNLOCK_MUTEX((*ptr)->Mutex);*/
456
 
457
      if (deleteFlag) {
458
         ASSERT(ctx);
459
         ctx->Driver.DeleteProgram(ctx, *ptr);
460
      }
461
 
462
      *ptr = NULL;
463
   }
464
 
465
   assert(!*ptr);
466
   if (prog) {
467
      /*_glthread_LOCK_MUTEX(prog->Mutex);*/
468
      prog->RefCount++;
469
#if 0
470
      printf("Program %p ID=%u Target=%s  Refcount++ to %d\n",
471
             prog, prog->Id,
472
             (prog->Target == GL_VERTEX_PROGRAM_ARB ? "VP" :
473
              (prog->Target == MESA_GEOMETRY_PROGRAM ? "GP" : "FP")),
474
             prog->RefCount);
475
#endif
476
      /*_glthread_UNLOCK_MUTEX(prog->Mutex);*/
477
   }
478
 
479
   *ptr = prog;
480
}
481
 
482
 
483
/**
484
 * Return a copy of a program.
485
 * XXX Problem here if the program object is actually OO-derivation
486
 * made by a device driver.
487
 */
488
struct gl_program *
489
_mesa_clone_program(struct gl_context *ctx, const struct gl_program *prog)
490
{
491
   struct gl_program *clone;
492
 
493
   clone = ctx->Driver.NewProgram(ctx, prog->Target, prog->Id);
494
   if (!clone)
495
      return NULL;
496
 
497
   assert(clone->Target == prog->Target);
498
   assert(clone->RefCount == 1);
499
 
500
   clone->String = (GLubyte *) _mesa_strdup((char *) prog->String);
501
   clone->Format = prog->Format;
502
   clone->Instructions = _mesa_alloc_instructions(prog->NumInstructions);
503
   if (!clone->Instructions) {
504
      _mesa_reference_program(ctx, &clone, NULL);
505
      return NULL;
506
   }
507
   _mesa_copy_instructions(clone->Instructions, prog->Instructions,
508
                           prog->NumInstructions);
509
   clone->InputsRead = prog->InputsRead;
510
   clone->OutputsWritten = prog->OutputsWritten;
511
   clone->SamplersUsed = prog->SamplersUsed;
512
   clone->ShadowSamplers = prog->ShadowSamplers;
513
   memcpy(clone->TexturesUsed, prog->TexturesUsed, sizeof(prog->TexturesUsed));
514
 
515
   if (prog->Parameters)
516
      clone->Parameters = _mesa_clone_parameter_list(prog->Parameters);
517
   memcpy(clone->LocalParams, prog->LocalParams, sizeof(clone->LocalParams));
518
   if (prog->Varying)
519
      clone->Varying = _mesa_clone_parameter_list(prog->Varying);
520
   if (prog->Attributes)
521
      clone->Attributes = _mesa_clone_parameter_list(prog->Attributes);
522
   memcpy(clone->LocalParams, prog->LocalParams, sizeof(clone->LocalParams));
523
   clone->IndirectRegisterFiles = prog->IndirectRegisterFiles;
524
   clone->NumInstructions = prog->NumInstructions;
525
   clone->NumTemporaries = prog->NumTemporaries;
526
   clone->NumParameters = prog->NumParameters;
527
   clone->NumAttributes = prog->NumAttributes;
528
   clone->NumAddressRegs = prog->NumAddressRegs;
529
   clone->NumNativeInstructions = prog->NumNativeInstructions;
530
   clone->NumNativeTemporaries = prog->NumNativeTemporaries;
531
   clone->NumNativeParameters = prog->NumNativeParameters;
532
   clone->NumNativeAttributes = prog->NumNativeAttributes;
533
   clone->NumNativeAddressRegs = prog->NumNativeAddressRegs;
534
   clone->NumAluInstructions = prog->NumAluInstructions;
535
   clone->NumTexInstructions = prog->NumTexInstructions;
536
   clone->NumTexIndirections = prog->NumTexIndirections;
537
   clone->NumNativeAluInstructions = prog->NumNativeAluInstructions;
538
   clone->NumNativeTexInstructions = prog->NumNativeTexInstructions;
539
   clone->NumNativeTexIndirections = prog->NumNativeTexIndirections;
540
 
541
   switch (prog->Target) {
542
   case GL_VERTEX_PROGRAM_ARB:
543
      {
544
         const struct gl_vertex_program *vp
545
            = (const struct gl_vertex_program *) prog;
546
         struct gl_vertex_program *vpc = (struct gl_vertex_program *) clone;
547
         vpc->IsPositionInvariant = vp->IsPositionInvariant;
548
         vpc->IsNVProgram = vp->IsNVProgram;
549
      }
550
      break;
551
   case GL_FRAGMENT_PROGRAM_ARB:
552
      {
553
         const struct gl_fragment_program *fp
554
            = (const struct gl_fragment_program *) prog;
555
         struct gl_fragment_program *fpc = (struct gl_fragment_program *) clone;
556
         fpc->FogOption = fp->FogOption;
557
         fpc->UsesKill = fp->UsesKill;
558
         fpc->OriginUpperLeft = fp->OriginUpperLeft;
559
         fpc->PixelCenterInteger = fp->PixelCenterInteger;
560
      }
561
      break;
562
   case MESA_GEOMETRY_PROGRAM:
563
      {
564
         const struct gl_geometry_program *gp
565
            = (const struct gl_geometry_program *) prog;
566
         struct gl_geometry_program *gpc = (struct gl_geometry_program *) clone;
567
         gpc->VerticesOut = gp->VerticesOut;
568
         gpc->InputType = gp->InputType;
569
         gpc->OutputType = gp->OutputType;
570
      }
571
      break;
572
   default:
573
      _mesa_problem(NULL, "Unexpected target in _mesa_clone_program");
574
   }
575
 
576
   return clone;
577
}
578
 
579
 
580
/**
581
 * Insert 'count' NOP instructions at 'start' in the given program.
582
 * Adjust branch targets accordingly.
583
 */
584
GLboolean
585
_mesa_insert_instructions(struct gl_program *prog, GLuint start, GLuint count)
586
{
587
   const GLuint origLen = prog->NumInstructions;
588
   const GLuint newLen = origLen + count;
589
   struct prog_instruction *newInst;
590
   GLuint i;
591
 
592
   /* adjust branches */
593
   for (i = 0; i < prog->NumInstructions; i++) {
594
      struct prog_instruction *inst = prog->Instructions + i;
595
      if (inst->BranchTarget > 0) {
596
         if ((GLuint)inst->BranchTarget >= start) {
597
            inst->BranchTarget += count;
598
         }
599
      }
600
   }
601
 
602
   /* Alloc storage for new instructions */
603
   newInst = _mesa_alloc_instructions(newLen);
604
   if (!newInst) {
605
      return GL_FALSE;
606
   }
607
 
608
   /* Copy 'start' instructions into new instruction buffer */
609
   _mesa_copy_instructions(newInst, prog->Instructions, start);
610
 
611
   /* init the new instructions */
612
   _mesa_init_instructions(newInst + start, count);
613
 
614
   /* Copy the remaining/tail instructions to new inst buffer */
615
   _mesa_copy_instructions(newInst + start + count,
616
                           prog->Instructions + start,
617
                           origLen - start);
618
 
619
   /* free old instructions */
620
   _mesa_free_instructions(prog->Instructions, origLen);
621
 
622
   /* install new instructions */
623
   prog->Instructions = newInst;
624
   prog->NumInstructions = newLen;
625
 
626
   return GL_TRUE;
627
}
628
 
629
/**
630
 * Delete 'count' instructions at 'start' in the given program.
631
 * Adjust branch targets accordingly.
632
 */
633
GLboolean
634
_mesa_delete_instructions(struct gl_program *prog, GLuint start, GLuint count)
635
{
636
   const GLuint origLen = prog->NumInstructions;
637
   const GLuint newLen = origLen - count;
638
   struct prog_instruction *newInst;
639
   GLuint i;
640
 
641
   /* adjust branches */
642
   for (i = 0; i < prog->NumInstructions; i++) {
643
      struct prog_instruction *inst = prog->Instructions + i;
644
      if (inst->BranchTarget > 0) {
645
         if (inst->BranchTarget > (GLint) start) {
646
            inst->BranchTarget -= count;
647
         }
648
      }
649
   }
650
 
651
   /* Alloc storage for new instructions */
652
   newInst = _mesa_alloc_instructions(newLen);
653
   if (!newInst) {
654
      return GL_FALSE;
655
   }
656
 
657
   /* Copy 'start' instructions into new instruction buffer */
658
   _mesa_copy_instructions(newInst, prog->Instructions, start);
659
 
660
   /* Copy the remaining/tail instructions to new inst buffer */
661
   _mesa_copy_instructions(newInst + start,
662
                           prog->Instructions + start + count,
663
                           newLen - start);
664
 
665
   /* free old instructions */
666
   _mesa_free_instructions(prog->Instructions, origLen);
667
 
668
   /* install new instructions */
669
   prog->Instructions = newInst;
670
   prog->NumInstructions = newLen;
671
 
672
   return GL_TRUE;
673
}
674
 
675
 
676
/**
677
 * Search instructions for registers that match (oldFile, oldIndex),
678
 * replacing them with (newFile, newIndex).
679
 */
680
static void
681
replace_registers(struct prog_instruction *inst, GLuint numInst,
682
                  GLuint oldFile, GLuint oldIndex,
683
                  GLuint newFile, GLuint newIndex)
684
{
685
   GLuint i, j;
686
   for (i = 0; i < numInst; i++) {
687
      /* src regs */
688
      for (j = 0; j < _mesa_num_inst_src_regs(inst[i].Opcode); j++) {
689
         if (inst[i].SrcReg[j].File == oldFile &&
690
             inst[i].SrcReg[j].Index == oldIndex) {
691
            inst[i].SrcReg[j].File = newFile;
692
            inst[i].SrcReg[j].Index = newIndex;
693
         }
694
      }
695
      /* dst reg */
696
      if (inst[i].DstReg.File == oldFile && inst[i].DstReg.Index == oldIndex) {
697
         inst[i].DstReg.File = newFile;
698
         inst[i].DstReg.Index = newIndex;
699
      }
700
   }
701
}
702
 
703
 
704
/**
705
 * Search instructions for references to program parameters.  When found,
706
 * increment the parameter index by 'offset'.
707
 * Used when combining programs.
708
 */
709
static void
710
adjust_param_indexes(struct prog_instruction *inst, GLuint numInst,
711
                     GLuint offset)
712
{
713
   GLuint i, j;
714
   for (i = 0; i < numInst; i++) {
715
      for (j = 0; j < _mesa_num_inst_src_regs(inst[i].Opcode); j++) {
716
         GLuint f = inst[i].SrcReg[j].File;
717
         if (f == PROGRAM_CONSTANT ||
718
             f == PROGRAM_UNIFORM ||
719
             f == PROGRAM_STATE_VAR) {
720
            inst[i].SrcReg[j].Index += offset;
721
         }
722
      }
723
   }
724
}
725
 
726
 
727
/**
728
 * Combine two programs into one.  Fix instructions so the outputs of
729
 * the first program go to the inputs of the second program.
730
 */
731
struct gl_program *
732
_mesa_combine_programs(struct gl_context *ctx,
733
                       const struct gl_program *progA,
734
                       const struct gl_program *progB)
735
{
736
   struct prog_instruction *newInst;
737
   struct gl_program *newProg;
738
   const GLuint lenA = progA->NumInstructions - 1; /* omit END instr */
739
   const GLuint lenB = progB->NumInstructions;
740
   const GLuint numParamsA = _mesa_num_parameters(progA->Parameters);
741
   const GLuint newLength = lenA + lenB;
742
   GLboolean usedTemps[MAX_PROGRAM_TEMPS];
743
   GLuint firstTemp = 0;
744
   GLbitfield inputsB;
745
   GLuint i;
746
 
747
   ASSERT(progA->Target == progB->Target);
748
 
749
   newInst = _mesa_alloc_instructions(newLength);
750
   if (!newInst)
751
      return GL_FALSE;
752
 
753
   _mesa_copy_instructions(newInst, progA->Instructions, lenA);
754
   _mesa_copy_instructions(newInst + lenA, progB->Instructions, lenB);
755
 
756
   /* adjust branch / instruction addresses for B's instructions */
757
   for (i = 0; i < lenB; i++) {
758
      newInst[lenA + i].BranchTarget += lenA;
759
   }
760
 
761
   newProg = ctx->Driver.NewProgram(ctx, progA->Target, 0);
762
   newProg->Instructions = newInst;
763
   newProg->NumInstructions = newLength;
764
 
765
   /* find used temp regs (we may need new temps below) */
766
   _mesa_find_used_registers(newProg, PROGRAM_TEMPORARY,
767
                             usedTemps, MAX_PROGRAM_TEMPS);
768
 
769
   if (newProg->Target == GL_FRAGMENT_PROGRAM_ARB) {
770
      struct gl_fragment_program *fprogA, *fprogB, *newFprog;
771
      GLbitfield progB_inputsRead = progB->InputsRead;
772
      GLint progB_colorFile, progB_colorIndex;
773
 
774
      fprogA = (struct gl_fragment_program *) progA;
775
      fprogB = (struct gl_fragment_program *) progB;
776
      newFprog = (struct gl_fragment_program *) newProg;
777
 
778
      newFprog->UsesKill = fprogA->UsesKill || fprogB->UsesKill;
779
 
780
      /* We'll do a search and replace for instances
781
       * of progB_colorFile/progB_colorIndex below...
782
       */
783
      progB_colorFile = PROGRAM_INPUT;
784
      progB_colorIndex = FRAG_ATTRIB_COL0;
785
 
786
      /*
787
       * The fragment program may get color from a state var rather than
788
       * a fragment input (vertex output) if it's constant.
789
       * See the texenvprogram.c code.
790
       * So, search the program's parameter list now to see if the program
791
       * gets color from a state var instead of a conventional fragment
792
       * input register.
793
       */
794
      for (i = 0; i < progB->Parameters->NumParameters; i++) {
795
         struct gl_program_parameter *p = &progB->Parameters->Parameters[i];
796
         if (p->Type == PROGRAM_STATE_VAR &&
797
             p->StateIndexes[0] == STATE_INTERNAL &&
798
             p->StateIndexes[1] == STATE_CURRENT_ATTRIB &&
799
             (int) p->StateIndexes[2] == (int) VERT_ATTRIB_COLOR0) {
800
            progB_inputsRead |= FRAG_BIT_COL0;
801
            progB_colorFile = PROGRAM_STATE_VAR;
802
            progB_colorIndex = i;
803
            break;
804
         }
805
      }
806
 
807
      /* Connect color outputs of fprogA to color inputs of fprogB, via a
808
       * new temporary register.
809
       */
810
      if ((progA->OutputsWritten & (1 << FRAG_RESULT_COLOR)) &&
811
          (progB_inputsRead & FRAG_BIT_COL0)) {
812
         GLint tempReg = _mesa_find_free_register(usedTemps, MAX_PROGRAM_TEMPS,
813
                                                  firstTemp);
814
         if (tempReg < 0) {
815
            _mesa_problem(ctx, "No free temp regs found in "
816
                          "_mesa_combine_programs(), using 31");
817
            tempReg = 31;
818
         }
819
         firstTemp = tempReg + 1;
820
 
821
         /* replace writes to result.color[0] with tempReg */
822
         replace_registers(newInst, lenA,
823
                           PROGRAM_OUTPUT, FRAG_RESULT_COLOR,
824
                           PROGRAM_TEMPORARY, tempReg);
825
         /* replace reads from the input color with tempReg */
826
         replace_registers(newInst + lenA, lenB,
827
                           progB_colorFile, progB_colorIndex, /* search for */
828
                           PROGRAM_TEMPORARY, tempReg  /* replace with */ );
829
      }
830
 
831
      /* compute combined program's InputsRead */
832
      inputsB = progB_inputsRead;
833
      if (progA->OutputsWritten & (1 << FRAG_RESULT_COLOR)) {
834
         inputsB &= ~(1 << FRAG_ATTRIB_COL0);
835
      }
836
      newProg->InputsRead = progA->InputsRead | inputsB;
837
      newProg->OutputsWritten = progB->OutputsWritten;
838
      newProg->SamplersUsed = progA->SamplersUsed | progB->SamplersUsed;
839
   }
840
   else {
841
      /* vertex program */
842
      assert(0);      /* XXX todo */
843
   }
844
 
845
   /*
846
    * Merge parameters (uniforms, constants, etc)
847
    */
848
   newProg->Parameters = _mesa_combine_parameter_lists(progA->Parameters,
849
                                                       progB->Parameters);
850
 
851
   adjust_param_indexes(newInst + lenA, lenB, numParamsA);
852
 
853
 
854
   return newProg;
855
}
856
 
857
 
858
/**
859
 * Populate the 'used' array with flags indicating which registers (TEMPs,
860
 * INPUTs, OUTPUTs, etc, are used by the given program.
861
 * \param file  type of register to scan for
862
 * \param used  returns true/false flags for in use / free
863
 * \param usedSize  size of the 'used' array
864
 */
865
void
866
_mesa_find_used_registers(const struct gl_program *prog,
867
                          gl_register_file file,
868
                          GLboolean used[], GLuint usedSize)
869
{
870
   GLuint i, j;
871
 
872
   memset(used, 0, usedSize);
873
 
874
   for (i = 0; i < prog->NumInstructions; i++) {
875
      const struct prog_instruction *inst = prog->Instructions + i;
876
      const GLuint n = _mesa_num_inst_src_regs(inst->Opcode);
877
 
878
      if (inst->DstReg.File == file) {
879
         ASSERT(inst->DstReg.Index < usedSize);
880
         if(inst->DstReg.Index < usedSize)
881
            used[inst->DstReg.Index] = GL_TRUE;
882
      }
883
 
884
      for (j = 0; j < n; j++) {
885
         if (inst->SrcReg[j].File == file) {
886
            ASSERT(inst->SrcReg[j].Index < usedSize);
887
            if(inst->SrcReg[j].Index < usedSize)
888
               used[inst->SrcReg[j].Index] = GL_TRUE;
889
         }
890
      }
891
   }
892
}
893
 
894
 
895
/**
896
 * Scan the given 'used' register flag array for the first entry
897
 * that's >= firstReg.
898
 * \param used  vector of flags indicating registers in use (as returned
899
 *              by _mesa_find_used_registers())
900
 * \param usedSize  size of the 'used' array
901
 * \param firstReg  first register to start searching at
902
 * \return index of unused register, or -1 if none.
903
 */
904
GLint
905
_mesa_find_free_register(const GLboolean used[],
906
                         GLuint usedSize, GLuint firstReg)
907
{
908
   GLuint i;
909
 
910
   assert(firstReg < usedSize);
911
 
912
   for (i = firstReg; i < usedSize; i++)
913
      if (!used[i])
914
         return i;
915
 
916
   return -1;
917
}
918
 
919
 
920
 
921
/**
922
 * Check if the given register index is valid (doesn't exceed implementation-
923
 * dependent limits).
924
 * \return GL_TRUE if OK, GL_FALSE if bad index
925
 */
926
GLboolean
927
_mesa_valid_register_index(const struct gl_context *ctx,
928
                           gl_shader_type shaderType,
929
                           gl_register_file file, GLint index)
930
{
931
   const struct gl_program_constants *c;
932
 
933
   switch (shaderType) {
934
   case MESA_SHADER_VERTEX:
935
      c = &ctx->Const.VertexProgram;
936
      break;
937
   case MESA_SHADER_FRAGMENT:
938
      c = &ctx->Const.FragmentProgram;
939
      break;
940
   case MESA_SHADER_GEOMETRY:
941
      c = &ctx->Const.GeometryProgram;
942
      break;
943
   default:
944
      _mesa_problem(ctx,
945
                    "unexpected shader type in _mesa_valid_register_index()");
946
      return GL_FALSE;
947
   }
948
 
949
   switch (file) {
950
   case PROGRAM_UNDEFINED:
951
      return GL_TRUE;  /* XXX or maybe false? */
952
 
953
   case PROGRAM_TEMPORARY:
954
      return index >= 0 && index < c->MaxTemps;
955
 
956
   case PROGRAM_ENV_PARAM:
957
      return index >= 0 && index < c->MaxEnvParams;
958
 
959
   case PROGRAM_LOCAL_PARAM:
960
      return index >= 0 && index < c->MaxLocalParams;
961
 
962
   case PROGRAM_NAMED_PARAM:
963
      return index >= 0 && index < c->MaxParameters;
964
 
965
   case PROGRAM_UNIFORM:
966
   case PROGRAM_STATE_VAR:
967
      /* aka constant buffer */
968
      return index >= 0 && index < c->MaxUniformComponents / 4;
969
 
970
   case PROGRAM_CONSTANT:
971
      /* constant buffer w/ possible relative negative addressing */
972
      return (index > (int) c->MaxUniformComponents / -4 &&
973
              index < c->MaxUniformComponents / 4);
974
 
975
   case PROGRAM_INPUT:
976
      if (index < 0)
977
         return GL_FALSE;
978
 
979
      switch (shaderType) {
980
      case MESA_SHADER_VERTEX:
981
         return index < VERT_ATTRIB_GENERIC0 + c->MaxAttribs;
982
      case MESA_SHADER_FRAGMENT:
983
         return index < FRAG_ATTRIB_VAR0 + ctx->Const.MaxVarying;
984
      case MESA_SHADER_GEOMETRY:
985
         return index < GEOM_ATTRIB_VAR0 + ctx->Const.MaxVarying;
986
      default:
987
         return GL_FALSE;
988
      }
989
 
990
   case PROGRAM_OUTPUT:
991
      if (index < 0)
992
         return GL_FALSE;
993
 
994
      switch (shaderType) {
995
      case MESA_SHADER_VERTEX:
996
         return index < VERT_RESULT_VAR0 + ctx->Const.MaxVarying;
997
      case MESA_SHADER_FRAGMENT:
998
         return index < FRAG_RESULT_DATA0 + ctx->Const.MaxDrawBuffers;
999
      case MESA_SHADER_GEOMETRY:
1000
         return index < GEOM_RESULT_VAR0 + ctx->Const.MaxVarying;
1001
      default:
1002
         return GL_FALSE;
1003
      }
1004
 
1005
   case PROGRAM_ADDRESS:
1006
      return index >= 0 && index < c->MaxAddressRegs;
1007
 
1008
   default:
1009
      _mesa_problem(ctx,
1010
                    "unexpected register file in _mesa_valid_register_index()");
1011
      return GL_FALSE;
1012
   }
1013
}
1014
 
1015
 
1016
 
1017
/**
1018
 * "Post-process" a GPU program.  This is intended to be used for debugging.
1019
 * Example actions include no-op'ing instructions or changing instruction
1020
 * behaviour.
1021
 */
1022
void
1023
_mesa_postprocess_program(struct gl_context *ctx, struct gl_program *prog)
1024
{
1025
   static const GLfloat white[4] = { 0.5, 0.5, 0.5, 0.5 };
1026
   GLuint i;
1027
   GLuint whiteSwizzle;
1028
   GLint whiteIndex = _mesa_add_unnamed_constant(prog->Parameters,
1029
                                                 white, 4, &whiteSwizzle);
1030
 
1031
   (void) whiteIndex;
1032
 
1033
   for (i = 0; i < prog->NumInstructions; i++) {
1034
      struct prog_instruction *inst = prog->Instructions + i;
1035
      const GLuint n = _mesa_num_inst_src_regs(inst->Opcode);
1036
 
1037
      (void) n;
1038
 
1039
      if (_mesa_is_tex_instruction(inst->Opcode)) {
1040
#if 0
1041
         /* replace TEX/TXP/TXB with MOV */
1042
         inst->Opcode = OPCODE_MOV;
1043
         inst->DstReg.WriteMask = WRITEMASK_XYZW;
1044
         inst->SrcReg[0].Swizzle = SWIZZLE_XYZW;
1045
         inst->SrcReg[0].Negate = NEGATE_NONE;
1046
#endif
1047
 
1048
#if 0
1049
         /* disable shadow texture mode */
1050
         inst->TexShadow = 0;
1051
#endif
1052
      }
1053
 
1054
      if (inst->Opcode == OPCODE_TXP) {
1055
#if 0
1056
         inst->Opcode = OPCODE_MOV;
1057
         inst->DstReg.WriteMask = WRITEMASK_XYZW;
1058
         inst->SrcReg[0].File = PROGRAM_CONSTANT;
1059
         inst->SrcReg[0].Index = whiteIndex;
1060
         inst->SrcReg[0].Swizzle = SWIZZLE_XYZW;
1061
         inst->SrcReg[0].Negate = NEGATE_NONE;
1062
#endif
1063
#if 0
1064
         inst->TexShadow = 0;
1065
#endif
1066
#if 0
1067
         inst->Opcode = OPCODE_TEX;
1068
         inst->TexShadow = 0;
1069
#endif
1070
      }
1071
 
1072
   }
1073
}