• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
_mesa_init_program(struct gl_context * ctx)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
_mesa_free_program_data(struct gl_context * ctx)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
_mesa_update_default_objects_program(struct gl_context * ctx)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
_mesa_set_program_error(struct gl_context * ctx,GLint pos,const char * string)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 *
_mesa_find_line_column(const GLubyte * string,const GLubyte * pos,GLint * line,GLint * col)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 *
_mesa_init_program_struct(struct gl_context * ctx,struct gl_program * prog,GLenum target,GLuint id)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 *
_mesa_init_fragment_program(struct gl_context * ctx,struct gl_fragment_program * prog,GLenum target,GLuint id)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 *
_mesa_init_vertex_program(struct gl_context * ctx,struct gl_vertex_program * prog,GLenum target,GLuint id)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 *
_mesa_init_geometry_program(struct gl_context * ctx,struct gl_geometry_program * prog,GLenum target,GLuint id)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 *
_mesa_new_program(struct gl_context * ctx,GLenum target,GLuint id)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
_mesa_delete_program(struct gl_context * ctx,struct gl_program * prog)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 *
_mesa_lookup_program(struct gl_context * ctx,GLuint id)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
_mesa_reference_program_(struct gl_context * ctx,struct gl_program ** ptr,struct gl_program * prog)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 *
_mesa_clone_program(struct gl_context * ctx,const struct gl_program * prog)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
_mesa_insert_instructions(struct gl_program * prog,GLuint start,GLuint count)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
_mesa_delete_instructions(struct gl_program * prog,GLuint start,GLuint count)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
replace_registers(struct prog_instruction * inst,GLuint numInst,GLuint oldFile,GLuint oldIndex,GLuint newFile,GLuint newIndex)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
adjust_param_indexes(struct prog_instruction * inst,GLuint numInst,GLuint offset)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 *
_mesa_combine_programs(struct gl_context * ctx,const struct gl_program * progA,const struct gl_program * progB)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    GLbitfield64 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       GLbitfield64 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
_mesa_find_used_registers(const struct gl_program * prog,gl_register_file file,GLboolean used[],GLuint usedSize)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
_mesa_find_free_register(const GLboolean used[],GLuint usedSize,GLuint firstReg)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
_mesa_valid_register_index(const struct gl_context * ctx,gl_shader_type shaderType,gl_register_file file,GLint index)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
_mesa_postprocess_program(struct gl_context * ctx,struct gl_program * prog)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 }
1068