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