Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

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