program.c revision 01e04c3f
13464ebd5Sriastradh/*
23464ebd5Sriastradh * Mesa 3-D graphics library
33464ebd5Sriastradh *
43464ebd5Sriastradh * Copyright (C) 1999-2007  Brian Paul   All Rights Reserved.
53464ebd5Sriastradh *
63464ebd5Sriastradh * Permission is hereby granted, free of charge, to any person obtaining a
73464ebd5Sriastradh * copy of this software and associated documentation files (the "Software"),
83464ebd5Sriastradh * to deal in the Software without restriction, including without limitation
93464ebd5Sriastradh * the rights to use, copy, modify, merge, publish, distribute, sublicense,
103464ebd5Sriastradh * and/or sell copies of the Software, and to permit persons to whom the
113464ebd5Sriastradh * Software is furnished to do so, subject to the following conditions:
123464ebd5Sriastradh *
133464ebd5Sriastradh * The above copyright notice and this permission notice shall be included
143464ebd5Sriastradh * in all copies or substantial portions of the Software.
153464ebd5Sriastradh *
163464ebd5Sriastradh * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
173464ebd5Sriastradh * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
183464ebd5Sriastradh * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19af69d88dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20af69d88dSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21af69d88dSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22af69d88dSmrg * OTHER DEALINGS IN THE SOFTWARE.
233464ebd5Sriastradh */
243464ebd5Sriastradh
253464ebd5Sriastradh/**
263464ebd5Sriastradh * \file program.c
273464ebd5Sriastradh * Vertex and fragment program support functions.
283464ebd5Sriastradh * \author Brian Paul
293464ebd5Sriastradh */
303464ebd5Sriastradh
313464ebd5Sriastradh
323464ebd5Sriastradh#include "main/glheader.h"
333464ebd5Sriastradh#include "main/context.h"
3401e04c3fSmrg#include "main/framebuffer.h"
353464ebd5Sriastradh#include "main/hash.h"
36af69d88dSmrg#include "main/macros.h"
3701e04c3fSmrg#include "main/shaderobj.h"
383464ebd5Sriastradh#include "program.h"
393464ebd5Sriastradh#include "prog_cache.h"
403464ebd5Sriastradh#include "prog_parameter.h"
413464ebd5Sriastradh#include "prog_instruction.h"
4201e04c3fSmrg#include "util/bitscan.h"
4301e04c3fSmrg#include "util/ralloc.h"
4401e04c3fSmrg#include "util/u_atomic.h"
453464ebd5Sriastradh
463464ebd5Sriastradh
473464ebd5Sriastradh/**
483464ebd5Sriastradh * A pointer to this dummy program is put into the hash table when
493464ebd5Sriastradh * glGenPrograms is called.
503464ebd5Sriastradh */
513464ebd5Sriastradhstruct gl_program _mesa_DummyProgram;
523464ebd5Sriastradh
533464ebd5Sriastradh
543464ebd5Sriastradh/**
553464ebd5Sriastradh * Init context's vertex/fragment program state
563464ebd5Sriastradh */
573464ebd5Sriastradhvoid
583464ebd5Sriastradh_mesa_init_program(struct gl_context *ctx)
593464ebd5Sriastradh{
603464ebd5Sriastradh   /*
613464ebd5Sriastradh    * If this assertion fails, we need to increase the field
623464ebd5Sriastradh    * size for register indexes (see INST_INDEX_BITS).
633464ebd5Sriastradh    */
6401e04c3fSmrg   assert(ctx->Const.Program[MESA_SHADER_VERTEX].MaxUniformComponents / 4
653464ebd5Sriastradh          <= (1 << INST_INDEX_BITS));
6601e04c3fSmrg   assert(ctx->Const.Program[MESA_SHADER_FRAGMENT].MaxUniformComponents / 4
673464ebd5Sriastradh          <= (1 << INST_INDEX_BITS));
683464ebd5Sriastradh
6901e04c3fSmrg   assert(ctx->Const.Program[MESA_SHADER_VERTEX].MaxTemps <= (1 << INST_INDEX_BITS));
7001e04c3fSmrg   assert(ctx->Const.Program[MESA_SHADER_VERTEX].MaxLocalParams <= (1 << INST_INDEX_BITS));
7101e04c3fSmrg   assert(ctx->Const.Program[MESA_SHADER_FRAGMENT].MaxTemps <= (1 << INST_INDEX_BITS));
7201e04c3fSmrg   assert(ctx->Const.Program[MESA_SHADER_FRAGMENT].MaxLocalParams <= (1 << INST_INDEX_BITS));
733464ebd5Sriastradh
7401e04c3fSmrg   assert(ctx->Const.Program[MESA_SHADER_VERTEX].MaxUniformComponents <= 4 * MAX_UNIFORMS);
7501e04c3fSmrg   assert(ctx->Const.Program[MESA_SHADER_FRAGMENT].MaxUniformComponents <= 4 * MAX_UNIFORMS);
763464ebd5Sriastradh
7701e04c3fSmrg   assert(ctx->Const.Program[MESA_SHADER_VERTEX].MaxAddressOffset <= (1 << INST_INDEX_BITS));
7801e04c3fSmrg   assert(ctx->Const.Program[MESA_SHADER_FRAGMENT].MaxAddressOffset <= (1 << INST_INDEX_BITS));
793464ebd5Sriastradh
803464ebd5Sriastradh   /* If this fails, increase prog_instruction::TexSrcUnit size */
81af69d88dSmrg   STATIC_ASSERT(MAX_TEXTURE_UNITS <= (1 << 5));
823464ebd5Sriastradh
833464ebd5Sriastradh   /* If this fails, increase prog_instruction::TexSrcTarget size */
84af69d88dSmrg   STATIC_ASSERT(NUM_TEXTURE_TARGETS <= (1 << 4));
853464ebd5Sriastradh
863464ebd5Sriastradh   ctx->Program.ErrorPos = -1;
8701e04c3fSmrg   ctx->Program.ErrorString = strdup("");
883464ebd5Sriastradh
893464ebd5Sriastradh   ctx->VertexProgram.Enabled = GL_FALSE;
903464ebd5Sriastradh   ctx->VertexProgram.PointSizeEnabled =
913464ebd5Sriastradh      (ctx->API == API_OPENGLES2) ? GL_TRUE : GL_FALSE;
923464ebd5Sriastradh   ctx->VertexProgram.TwoSideEnabled = GL_FALSE;
9301e04c3fSmrg   _mesa_reference_program(ctx, &ctx->VertexProgram.Current,
9401e04c3fSmrg                           ctx->Shared->DefaultVertexProgram);
953464ebd5Sriastradh   assert(ctx->VertexProgram.Current);
963464ebd5Sriastradh   ctx->VertexProgram.Cache = _mesa_new_program_cache();
973464ebd5Sriastradh
983464ebd5Sriastradh   ctx->FragmentProgram.Enabled = GL_FALSE;
9901e04c3fSmrg   _mesa_reference_program(ctx, &ctx->FragmentProgram.Current,
10001e04c3fSmrg                           ctx->Shared->DefaultFragmentProgram);
1013464ebd5Sriastradh   assert(ctx->FragmentProgram.Current);
1023464ebd5Sriastradh   ctx->FragmentProgram.Cache = _mesa_new_program_cache();
10301e04c3fSmrg   ctx->VertexProgram._VPMode = VP_MODE_FF;
1043464ebd5Sriastradh
1053464ebd5Sriastradh   /* XXX probably move this stuff */
1063464ebd5Sriastradh   ctx->ATIFragmentShader.Enabled = GL_FALSE;
1073464ebd5Sriastradh   ctx->ATIFragmentShader.Current = ctx->Shared->DefaultFragmentShader;
1083464ebd5Sriastradh   assert(ctx->ATIFragmentShader.Current);
1093464ebd5Sriastradh   ctx->ATIFragmentShader.Current->RefCount++;
1103464ebd5Sriastradh}
1113464ebd5Sriastradh
1123464ebd5Sriastradh
1133464ebd5Sriastradh/**
1143464ebd5Sriastradh * Free a context's vertex/fragment program state
1153464ebd5Sriastradh */
1163464ebd5Sriastradhvoid
1173464ebd5Sriastradh_mesa_free_program_data(struct gl_context *ctx)
1183464ebd5Sriastradh{
11901e04c3fSmrg   _mesa_reference_program(ctx, &ctx->VertexProgram.Current, NULL);
1203464ebd5Sriastradh   _mesa_delete_program_cache(ctx, ctx->VertexProgram.Cache);
12101e04c3fSmrg   _mesa_reference_program(ctx, &ctx->FragmentProgram.Current, NULL);
122af69d88dSmrg   _mesa_delete_shader_cache(ctx, ctx->FragmentProgram.Cache);
123af69d88dSmrg
1243464ebd5Sriastradh   /* XXX probably move this stuff */
1253464ebd5Sriastradh   if (ctx->ATIFragmentShader.Current) {
1263464ebd5Sriastradh      ctx->ATIFragmentShader.Current->RefCount--;
1273464ebd5Sriastradh      if (ctx->ATIFragmentShader.Current->RefCount <= 0) {
1283464ebd5Sriastradh         free(ctx->ATIFragmentShader.Current);
1293464ebd5Sriastradh      }
1303464ebd5Sriastradh   }
131af69d88dSmrg
1323464ebd5Sriastradh   free((void *) ctx->Program.ErrorString);
1333464ebd5Sriastradh}
1343464ebd5Sriastradh
1353464ebd5Sriastradh
1363464ebd5Sriastradh/**
1373464ebd5Sriastradh * Update the default program objects in the given context to reference those
1383464ebd5Sriastradh * specified in the shared state and release those referencing the old
1393464ebd5Sriastradh * shared state.
1403464ebd5Sriastradh */
1413464ebd5Sriastradhvoid
1423464ebd5Sriastradh_mesa_update_default_objects_program(struct gl_context *ctx)
1433464ebd5Sriastradh{
14401e04c3fSmrg   _mesa_reference_program(ctx, &ctx->VertexProgram.Current,
14501e04c3fSmrg                           ctx->Shared->DefaultVertexProgram);
1463464ebd5Sriastradh   assert(ctx->VertexProgram.Current);
1473464ebd5Sriastradh
14801e04c3fSmrg   _mesa_reference_program(ctx, &ctx->FragmentProgram.Current,
1493464ebd5Sriastradh                            ctx->Shared->DefaultFragmentProgram);
1503464ebd5Sriastradh   assert(ctx->FragmentProgram.Current);
1513464ebd5Sriastradh
1523464ebd5Sriastradh   /* XXX probably move this stuff */
1533464ebd5Sriastradh   if (ctx->ATIFragmentShader.Current) {
1543464ebd5Sriastradh      ctx->ATIFragmentShader.Current->RefCount--;
1553464ebd5Sriastradh      if (ctx->ATIFragmentShader.Current->RefCount <= 0) {
1563464ebd5Sriastradh         free(ctx->ATIFragmentShader.Current);
1573464ebd5Sriastradh      }
1583464ebd5Sriastradh   }
1593464ebd5Sriastradh   ctx->ATIFragmentShader.Current = (struct ati_fragment_shader *) ctx->Shared->DefaultFragmentShader;
1603464ebd5Sriastradh   assert(ctx->ATIFragmentShader.Current);
1613464ebd5Sriastradh   ctx->ATIFragmentShader.Current->RefCount++;
1623464ebd5Sriastradh}
1633464ebd5Sriastradh
1643464ebd5Sriastradh
1653464ebd5Sriastradh/**
1663464ebd5Sriastradh * Set the vertex/fragment program error state (position and error string).
1673464ebd5Sriastradh * This is generally called from within the parsers.
1683464ebd5Sriastradh */
1693464ebd5Sriastradhvoid
1703464ebd5Sriastradh_mesa_set_program_error(struct gl_context *ctx, GLint pos, const char *string)
1713464ebd5Sriastradh{
1723464ebd5Sriastradh   ctx->Program.ErrorPos = pos;
1733464ebd5Sriastradh   free((void *) ctx->Program.ErrorString);
1743464ebd5Sriastradh   if (!string)
1753464ebd5Sriastradh      string = "";
17601e04c3fSmrg   ctx->Program.ErrorString = strdup(string);
1773464ebd5Sriastradh}
1783464ebd5Sriastradh
1793464ebd5Sriastradh
1803464ebd5Sriastradh/**
181af69d88dSmrg * Initialize a new gl_program object.
1823464ebd5Sriastradh */
18301e04c3fSmrgstruct gl_program *
18401e04c3fSmrg_mesa_init_gl_program(struct gl_program *prog, GLenum target, GLuint id,
18501e04c3fSmrg                      bool is_arb_asm)
1863464ebd5Sriastradh{
18701e04c3fSmrg   if (!prog)
18801e04c3fSmrg      return NULL;
189af69d88dSmrg
190af69d88dSmrg   memset(prog, 0, sizeof(*prog));
191af69d88dSmrg   prog->Id = id;
192af69d88dSmrg   prog->Target = target;
193af69d88dSmrg   prog->RefCount = 1;
194af69d88dSmrg   prog->Format = GL_PROGRAM_FORMAT_ASCII_ARB;
19501e04c3fSmrg   prog->info.stage = _mesa_program_enum_to_shader_stage(target);
19601e04c3fSmrg   prog->is_arb_asm = is_arb_asm;
197af69d88dSmrg
19801e04c3fSmrg   /* Uniforms that lack an initializer in the shader code have an initial
19901e04c3fSmrg    * value of zero.  This includes sampler uniforms.
20001e04c3fSmrg    *
20101e04c3fSmrg    * Page 24 (page 30 of the PDF) of the GLSL 1.20 spec says:
20201e04c3fSmrg    *
20301e04c3fSmrg    *     "The link time initial value is either the value of the variable's
20401e04c3fSmrg    *     initializer, if present, or 0 if no initializer is present. Sampler
20501e04c3fSmrg    *     types cannot have initializers."
20601e04c3fSmrg    *
20701e04c3fSmrg    * So we only initialise ARB assembly style programs.
20801e04c3fSmrg    */
20901e04c3fSmrg   if (is_arb_asm) {
21001e04c3fSmrg      /* default mapping from samplers to texture units */
21101e04c3fSmrg      for (unsigned i = 0; i < MAX_SAMPLERS; i++)
21201e04c3fSmrg         prog->SamplerUnits[i] = i;
213af69d88dSmrg   }
2143464ebd5Sriastradh
21501e04c3fSmrg   return prog;
2163464ebd5Sriastradh}
2173464ebd5Sriastradh
2183464ebd5Sriastradh
2193464ebd5Sriastradh/**
2203464ebd5Sriastradh * Allocate and initialize a new fragment/vertex program object but
2213464ebd5Sriastradh * don't put it into the program hash table.  Called via
2223464ebd5Sriastradh * ctx->Driver.NewProgram.  May be overridden (ie. replaced) by a
2233464ebd5Sriastradh * device driver function to implement OO deriviation with additional
2243464ebd5Sriastradh * types not understood by this function.
2253464ebd5Sriastradh *
2263464ebd5Sriastradh * \param ctx  context
2273464ebd5Sriastradh * \param id   program id/number
2283464ebd5Sriastradh * \param target  program target/type
2293464ebd5Sriastradh * \return  pointer to new program object
2303464ebd5Sriastradh */
2313464ebd5Sriastradhstruct gl_program *
23201e04c3fSmrg_mesa_new_program(struct gl_context *ctx, GLenum target, GLuint id,
23301e04c3fSmrg                  bool is_arb_asm)
2343464ebd5Sriastradh{
2353464ebd5Sriastradh   switch (target) {
2363464ebd5Sriastradh   case GL_VERTEX_PROGRAM_ARB: /* == GL_VERTEX_PROGRAM_NV */
23701e04c3fSmrg   case GL_GEOMETRY_PROGRAM_NV:
23801e04c3fSmrg   case GL_TESS_CONTROL_PROGRAM_NV:
23901e04c3fSmrg   case GL_TESS_EVALUATION_PROGRAM_NV:
2403464ebd5Sriastradh   case GL_FRAGMENT_PROGRAM_ARB:
24101e04c3fSmrg   case GL_COMPUTE_PROGRAM_NV: {
24201e04c3fSmrg      struct gl_program *prog = rzalloc(NULL, struct gl_program);
24301e04c3fSmrg      return _mesa_init_gl_program(prog, target, id, is_arb_asm);
24401e04c3fSmrg   }
2453464ebd5Sriastradh   default:
2463464ebd5Sriastradh      _mesa_problem(ctx, "bad target in _mesa_new_program");
24701e04c3fSmrg      return NULL;
2483464ebd5Sriastradh   }
2493464ebd5Sriastradh}
2503464ebd5Sriastradh
2513464ebd5Sriastradh
2523464ebd5Sriastradh/**
2533464ebd5Sriastradh * Delete a program and remove it from the hash table, ignoring the
2543464ebd5Sriastradh * reference count.
2553464ebd5Sriastradh * Called via ctx->Driver.DeleteProgram.  May be wrapped (OO deriviation)
2563464ebd5Sriastradh * by a device driver function.
2573464ebd5Sriastradh */
2583464ebd5Sriastradhvoid
2593464ebd5Sriastradh_mesa_delete_program(struct gl_context *ctx, struct gl_program *prog)
2603464ebd5Sriastradh{
2613464ebd5Sriastradh   (void) ctx;
26201e04c3fSmrg   assert(prog);
26301e04c3fSmrg   assert(prog->RefCount==0);
2643464ebd5Sriastradh
2653464ebd5Sriastradh   if (prog == &_mesa_DummyProgram)
2663464ebd5Sriastradh      return;
2673464ebd5Sriastradh
2683464ebd5Sriastradh   if (prog->Parameters) {
2693464ebd5Sriastradh      _mesa_free_parameter_list(prog->Parameters);
2703464ebd5Sriastradh   }
2713464ebd5Sriastradh
27201e04c3fSmrg   if (prog->nir) {
27301e04c3fSmrg      ralloc_free(prog->nir);
27401e04c3fSmrg   }
27501e04c3fSmrg
27601e04c3fSmrg   if (prog->sh.BindlessSamplers) {
27701e04c3fSmrg      ralloc_free(prog->sh.BindlessSamplers);
27801e04c3fSmrg   }
27901e04c3fSmrg
28001e04c3fSmrg   if (prog->sh.BindlessImages) {
28101e04c3fSmrg      ralloc_free(prog->sh.BindlessImages);
28201e04c3fSmrg   }
28301e04c3fSmrg
28401e04c3fSmrg   if (prog->driver_cache_blob) {
28501e04c3fSmrg      ralloc_free(prog->driver_cache_blob);
28601e04c3fSmrg   }
28701e04c3fSmrg
28801e04c3fSmrg   ralloc_free(prog);
2893464ebd5Sriastradh}
2903464ebd5Sriastradh
2913464ebd5Sriastradh
2923464ebd5Sriastradh/**
2933464ebd5Sriastradh * Return the gl_program object for a given ID.
2943464ebd5Sriastradh * Basically just a wrapper for _mesa_HashLookup() to avoid a lot of
2953464ebd5Sriastradh * casts elsewhere.
2963464ebd5Sriastradh */
2973464ebd5Sriastradhstruct gl_program *
2983464ebd5Sriastradh_mesa_lookup_program(struct gl_context *ctx, GLuint id)
2993464ebd5Sriastradh{
3003464ebd5Sriastradh   if (id)
3013464ebd5Sriastradh      return (struct gl_program *) _mesa_HashLookup(ctx->Shared->Programs, id);
3023464ebd5Sriastradh   else
3033464ebd5Sriastradh      return NULL;
3043464ebd5Sriastradh}
3053464ebd5Sriastradh
3063464ebd5Sriastradh
3073464ebd5Sriastradh/**
3083464ebd5Sriastradh * Reference counting for vertex/fragment programs
309af69d88dSmrg * This is normally only called from the _mesa_reference_program() macro
310af69d88dSmrg * when there's a real pointer change.
3113464ebd5Sriastradh */
3123464ebd5Sriastradhvoid
313af69d88dSmrg_mesa_reference_program_(struct gl_context *ctx,
314af69d88dSmrg                         struct gl_program **ptr,
315af69d88dSmrg                         struct gl_program *prog)
3163464ebd5Sriastradh{
317af69d88dSmrg#ifndef NDEBUG
3183464ebd5Sriastradh   assert(ptr);
3193464ebd5Sriastradh   if (*ptr && prog) {
3203464ebd5Sriastradh      /* sanity check */
3213464ebd5Sriastradh      if ((*ptr)->Target == GL_VERTEX_PROGRAM_ARB)
32201e04c3fSmrg         assert(prog->Target == GL_VERTEX_PROGRAM_ARB);
3233464ebd5Sriastradh      else if ((*ptr)->Target == GL_FRAGMENT_PROGRAM_ARB)
32401e04c3fSmrg         assert(prog->Target == GL_FRAGMENT_PROGRAM_ARB ||
3253464ebd5Sriastradh                prog->Target == GL_FRAGMENT_PROGRAM_NV);
32601e04c3fSmrg      else if ((*ptr)->Target == GL_GEOMETRY_PROGRAM_NV)
32701e04c3fSmrg         assert(prog->Target == GL_GEOMETRY_PROGRAM_NV);
3283464ebd5Sriastradh   }
329af69d88dSmrg#endif
330af69d88dSmrg
3313464ebd5Sriastradh   if (*ptr) {
33201e04c3fSmrg      struct gl_program *oldProg = *ptr;
3333464ebd5Sriastradh
33401e04c3fSmrg      assert(oldProg->RefCount > 0);
3353464ebd5Sriastradh
33601e04c3fSmrg      if (p_atomic_dec_zero(&oldProg->RefCount)) {
33701e04c3fSmrg         assert(ctx);
33801e04c3fSmrg         _mesa_reference_shader_program_data(ctx, &oldProg->sh.data, NULL);
33901e04c3fSmrg         ctx->Driver.DeleteProgram(ctx, oldProg);
3403464ebd5Sriastradh      }
3413464ebd5Sriastradh
3423464ebd5Sriastradh      *ptr = NULL;
3433464ebd5Sriastradh   }
3443464ebd5Sriastradh
3453464ebd5Sriastradh   assert(!*ptr);
3463464ebd5Sriastradh   if (prog) {
34701e04c3fSmrg      p_atomic_inc(&prog->RefCount);
3483464ebd5Sriastradh   }
3493464ebd5Sriastradh
3503464ebd5Sriastradh   *ptr = prog;
3513464ebd5Sriastradh}
3523464ebd5Sriastradh
3533464ebd5Sriastradh
3543464ebd5Sriastradh/**
3553464ebd5Sriastradh * Insert 'count' NOP instructions at 'start' in the given program.
3563464ebd5Sriastradh * Adjust branch targets accordingly.
3573464ebd5Sriastradh */
3583464ebd5SriastradhGLboolean
3593464ebd5Sriastradh_mesa_insert_instructions(struct gl_program *prog, GLuint start, GLuint count)
3603464ebd5Sriastradh{
36101e04c3fSmrg   const GLuint origLen = prog->arb.NumInstructions;
3623464ebd5Sriastradh   const GLuint newLen = origLen + count;
3633464ebd5Sriastradh   struct prog_instruction *newInst;
3643464ebd5Sriastradh   GLuint i;
3653464ebd5Sriastradh
3663464ebd5Sriastradh   /* adjust branches */
36701e04c3fSmrg   for (i = 0; i < prog->arb.NumInstructions; i++) {
36801e04c3fSmrg      struct prog_instruction *inst = prog->arb.Instructions + i;
3693464ebd5Sriastradh      if (inst->BranchTarget > 0) {
3703464ebd5Sriastradh         if ((GLuint)inst->BranchTarget >= start) {
3713464ebd5Sriastradh            inst->BranchTarget += count;
3723464ebd5Sriastradh         }
3733464ebd5Sriastradh      }
3743464ebd5Sriastradh   }
3753464ebd5Sriastradh
3763464ebd5Sriastradh   /* Alloc storage for new instructions */
37701e04c3fSmrg   newInst = rzalloc_array(prog, struct prog_instruction, newLen);
3783464ebd5Sriastradh   if (!newInst) {
3793464ebd5Sriastradh      return GL_FALSE;
3803464ebd5Sriastradh   }
3813464ebd5Sriastradh
3823464ebd5Sriastradh   /* Copy 'start' instructions into new instruction buffer */
38301e04c3fSmrg   _mesa_copy_instructions(newInst, prog->arb.Instructions, start);
3843464ebd5Sriastradh
3853464ebd5Sriastradh   /* init the new instructions */
3863464ebd5Sriastradh   _mesa_init_instructions(newInst + start, count);
3873464ebd5Sriastradh
3883464ebd5Sriastradh   /* Copy the remaining/tail instructions to new inst buffer */
3893464ebd5Sriastradh   _mesa_copy_instructions(newInst + start + count,
39001e04c3fSmrg                           prog->arb.Instructions + start,
3913464ebd5Sriastradh                           origLen - start);
3923464ebd5Sriastradh
3933464ebd5Sriastradh   /* free old instructions */
39401e04c3fSmrg   ralloc_free(prog->arb.Instructions);
3953464ebd5Sriastradh
3963464ebd5Sriastradh   /* install new instructions */
39701e04c3fSmrg   prog->arb.Instructions = newInst;
39801e04c3fSmrg   prog->arb.NumInstructions = newLen;
3993464ebd5Sriastradh
4003464ebd5Sriastradh   return GL_TRUE;
4013464ebd5Sriastradh}
4023464ebd5Sriastradh
4033464ebd5Sriastradh/**
4043464ebd5Sriastradh * Delete 'count' instructions at 'start' in the given program.
4053464ebd5Sriastradh * Adjust branch targets accordingly.
4063464ebd5Sriastradh */
4073464ebd5SriastradhGLboolean
40801e04c3fSmrg_mesa_delete_instructions(struct gl_program *prog, GLuint start, GLuint count,
40901e04c3fSmrg                          void *mem_ctx)
4103464ebd5Sriastradh{
41101e04c3fSmrg   const GLuint origLen = prog->arb.NumInstructions;
4123464ebd5Sriastradh   const GLuint newLen = origLen - count;
4133464ebd5Sriastradh   struct prog_instruction *newInst;
4143464ebd5Sriastradh   GLuint i;
4153464ebd5Sriastradh
4163464ebd5Sriastradh   /* adjust branches */
41701e04c3fSmrg   for (i = 0; i < prog->arb.NumInstructions; i++) {
41801e04c3fSmrg      struct prog_instruction *inst = prog->arb.Instructions + i;
4193464ebd5Sriastradh      if (inst->BranchTarget > 0) {
4203464ebd5Sriastradh         if (inst->BranchTarget > (GLint) start) {
4213464ebd5Sriastradh            inst->BranchTarget -= count;
4223464ebd5Sriastradh         }
4233464ebd5Sriastradh      }
4243464ebd5Sriastradh   }
4253464ebd5Sriastradh
4263464ebd5Sriastradh   /* Alloc storage for new instructions */
42701e04c3fSmrg   newInst = rzalloc_array(mem_ctx, struct prog_instruction, newLen);
4283464ebd5Sriastradh   if (!newInst) {
4293464ebd5Sriastradh      return GL_FALSE;
4303464ebd5Sriastradh   }
4313464ebd5Sriastradh
4323464ebd5Sriastradh   /* Copy 'start' instructions into new instruction buffer */
43301e04c3fSmrg   _mesa_copy_instructions(newInst, prog->arb.Instructions, start);
4343464ebd5Sriastradh
4353464ebd5Sriastradh   /* Copy the remaining/tail instructions to new inst buffer */
4363464ebd5Sriastradh   _mesa_copy_instructions(newInst + start,
43701e04c3fSmrg                           prog->arb.Instructions + start + count,
4383464ebd5Sriastradh                           newLen - start);
4393464ebd5Sriastradh
4403464ebd5Sriastradh   /* free old instructions */
44101e04c3fSmrg   ralloc_free(prog->arb.Instructions);
4423464ebd5Sriastradh
4433464ebd5Sriastradh   /* install new instructions */
44401e04c3fSmrg   prog->arb.Instructions = newInst;
44501e04c3fSmrg   prog->arb.NumInstructions = newLen;
4463464ebd5Sriastradh
4473464ebd5Sriastradh   return GL_TRUE;
4483464ebd5Sriastradh}
4493464ebd5Sriastradh
4503464ebd5Sriastradh
4513464ebd5Sriastradh/**
4523464ebd5Sriastradh * Populate the 'used' array with flags indicating which registers (TEMPs,
4533464ebd5Sriastradh * INPUTs, OUTPUTs, etc, are used by the given program.
4543464ebd5Sriastradh * \param file  type of register to scan for
4553464ebd5Sriastradh * \param used  returns true/false flags for in use / free
4563464ebd5Sriastradh * \param usedSize  size of the 'used' array
4573464ebd5Sriastradh */
4583464ebd5Sriastradhvoid
4593464ebd5Sriastradh_mesa_find_used_registers(const struct gl_program *prog,
4603464ebd5Sriastradh                          gl_register_file file,
4613464ebd5Sriastradh                          GLboolean used[], GLuint usedSize)
4623464ebd5Sriastradh{
4633464ebd5Sriastradh   GLuint i, j;
4643464ebd5Sriastradh
4653464ebd5Sriastradh   memset(used, 0, usedSize);
4663464ebd5Sriastradh
46701e04c3fSmrg   for (i = 0; i < prog->arb.NumInstructions; i++) {
46801e04c3fSmrg      const struct prog_instruction *inst = prog->arb.Instructions + i;
4693464ebd5Sriastradh      const GLuint n = _mesa_num_inst_src_regs(inst->Opcode);
4703464ebd5Sriastradh
4713464ebd5Sriastradh      if (inst->DstReg.File == file) {
47201e04c3fSmrg         assert(inst->DstReg.Index < usedSize);
4733464ebd5Sriastradh         if(inst->DstReg.Index < usedSize)
4743464ebd5Sriastradh            used[inst->DstReg.Index] = GL_TRUE;
4753464ebd5Sriastradh      }
4763464ebd5Sriastradh
4773464ebd5Sriastradh      for (j = 0; j < n; j++) {
4783464ebd5Sriastradh         if (inst->SrcReg[j].File == file) {
47901e04c3fSmrg            assert(inst->SrcReg[j].Index < (GLint) usedSize);
480af69d88dSmrg            if (inst->SrcReg[j].Index < (GLint) usedSize)
4813464ebd5Sriastradh               used[inst->SrcReg[j].Index] = GL_TRUE;
4823464ebd5Sriastradh         }
4833464ebd5Sriastradh      }
4843464ebd5Sriastradh   }
4853464ebd5Sriastradh}
4863464ebd5Sriastradh
4873464ebd5Sriastradh
4883464ebd5Sriastradh/**
4893464ebd5Sriastradh * Scan the given 'used' register flag array for the first entry
4903464ebd5Sriastradh * that's >= firstReg.
4913464ebd5Sriastradh * \param used  vector of flags indicating registers in use (as returned
4923464ebd5Sriastradh *              by _mesa_find_used_registers())
4933464ebd5Sriastradh * \param usedSize  size of the 'used' array
4943464ebd5Sriastradh * \param firstReg  first register to start searching at
4953464ebd5Sriastradh * \return index of unused register, or -1 if none.
4963464ebd5Sriastradh */
4973464ebd5SriastradhGLint
4983464ebd5Sriastradh_mesa_find_free_register(const GLboolean used[],
4993464ebd5Sriastradh                         GLuint usedSize, GLuint firstReg)
5003464ebd5Sriastradh{
5013464ebd5Sriastradh   GLuint i;
5023464ebd5Sriastradh
5033464ebd5Sriastradh   assert(firstReg < usedSize);
5043464ebd5Sriastradh
5053464ebd5Sriastradh   for (i = firstReg; i < usedSize; i++)
5063464ebd5Sriastradh      if (!used[i])
5073464ebd5Sriastradh         return i;
5083464ebd5Sriastradh
5093464ebd5Sriastradh   return -1;
5103464ebd5Sriastradh}
5113464ebd5Sriastradh
5123464ebd5Sriastradh
513af69d88dSmrg/* Gets the minimum number of shader invocations per fragment.
514af69d88dSmrg * This function is useful to determine if we need to do per
515af69d88dSmrg * sample shading or per fragment shading.
516af69d88dSmrg */
517af69d88dSmrgGLint
518af69d88dSmrg_mesa_get_min_invocations_per_fragment(struct gl_context *ctx,
51901e04c3fSmrg                                       const struct gl_program *prog)
520af69d88dSmrg{
521af69d88dSmrg   /* From ARB_sample_shading specification:
522af69d88dSmrg    * "Using gl_SampleID in a fragment shader causes the entire shader
523af69d88dSmrg    *  to be evaluated per-sample."
524af69d88dSmrg    *
525af69d88dSmrg    * "Using gl_SamplePosition in a fragment shader causes the entire
526af69d88dSmrg    *  shader to be evaluated per-sample."
527af69d88dSmrg    *
528af69d88dSmrg    * "If MULTISAMPLE or SAMPLE_SHADING_ARB is disabled, sample shading
529af69d88dSmrg    *  has no effect."
530af69d88dSmrg    */
531af69d88dSmrg   if (ctx->Multisample.Enabled) {
532af69d88dSmrg      /* The ARB_gpu_shader5 specification says:
533af69d88dSmrg       *
534af69d88dSmrg       * "Use of the "sample" qualifier on a fragment shader input
535af69d88dSmrg       *  forces per-sample shading"
536af69d88dSmrg       */
53701e04c3fSmrg      if (prog->info.fs.uses_sample_qualifier ||
53801e04c3fSmrg          (prog->info.system_values_read & (SYSTEM_BIT_SAMPLE_ID |
53901e04c3fSmrg                                            SYSTEM_BIT_SAMPLE_POS)))
54001e04c3fSmrg         return MAX2(_mesa_geometric_samples(ctx->DrawBuffer), 1);
541af69d88dSmrg      else if (ctx->Multisample.SampleShading)
542af69d88dSmrg         return MAX2(ceil(ctx->Multisample.MinSampleShadingValue *
54301e04c3fSmrg                          _mesa_geometric_samples(ctx->DrawBuffer)), 1);
544af69d88dSmrg      else
545af69d88dSmrg         return 1;
546af69d88dSmrg   }
547af69d88dSmrg   return 1;
548af69d88dSmrg}
54901e04c3fSmrg
55001e04c3fSmrg
55101e04c3fSmrgGLbitfield
55201e04c3fSmrggl_external_samplers(const struct gl_program *prog)
55301e04c3fSmrg{
55401e04c3fSmrg   GLbitfield external_samplers = 0;
55501e04c3fSmrg   GLbitfield mask = prog->SamplersUsed;
55601e04c3fSmrg
55701e04c3fSmrg   while (mask) {
55801e04c3fSmrg      int idx = u_bit_scan(&mask);
55901e04c3fSmrg      if (prog->sh.SamplerTargets[idx] == TEXTURE_EXTERNAL_INDEX)
56001e04c3fSmrg         external_samplers |= (1 << idx);
56101e04c3fSmrg   }
56201e04c3fSmrg
56301e04c3fSmrg   return external_samplers;
56401e04c3fSmrg}
565