~ubuntu-branches/ubuntu/precise/mesa-lts-quantal/precise-updates

« back to all changes in this revision

Viewing changes to src/mesa/program/program.c

  • Committer: Package Import Robot
  • Author(s): Maarten Lankhorst
  • Date: 2012-11-30 20:58:34 UTC
  • Revision ID: package-import@ubuntu.com-20121130205834-gazuvne3fpwlf012
Tags: upstream-9.0
ImportĀ upstreamĀ versionĀ 9.0

Show diffs side-by-side

added added

removed removed

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