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"
387ec681f3Smrg#include "main/state.h"
393464ebd5Sriastradh#include "program.h"
403464ebd5Sriastradh#include "prog_cache.h"
413464ebd5Sriastradh#include "prog_parameter.h"
423464ebd5Sriastradh#include "prog_instruction.h"
4301e04c3fSmrg#include "util/bitscan.h"
4401e04c3fSmrg#include "util/ralloc.h"
4501e04c3fSmrg#include "util/u_atomic.h"
463464ebd5Sriastradh
473464ebd5Sriastradh
483464ebd5Sriastradh/**
493464ebd5Sriastradh * A pointer to this dummy program is put into the hash table when
503464ebd5Sriastradh * glGenPrograms is called.
513464ebd5Sriastradh */
523464ebd5Sriastradhstruct gl_program _mesa_DummyProgram;
533464ebd5Sriastradh
543464ebd5Sriastradh
553464ebd5Sriastradh/**
563464ebd5Sriastradh * Init context's vertex/fragment program state
573464ebd5Sriastradh */
583464ebd5Sriastradhvoid
593464ebd5Sriastradh_mesa_init_program(struct gl_context *ctx)
603464ebd5Sriastradh{
613464ebd5Sriastradh   /*
623464ebd5Sriastradh    * If this assertion fails, we need to increase the field
633464ebd5Sriastradh    * size for register indexes (see INST_INDEX_BITS).
643464ebd5Sriastradh    */
6501e04c3fSmrg   assert(ctx->Const.Program[MESA_SHADER_VERTEX].MaxUniformComponents / 4
663464ebd5Sriastradh          <= (1 << INST_INDEX_BITS));
6701e04c3fSmrg   assert(ctx->Const.Program[MESA_SHADER_FRAGMENT].MaxUniformComponents / 4
683464ebd5Sriastradh          <= (1 << INST_INDEX_BITS));
693464ebd5Sriastradh
7001e04c3fSmrg   assert(ctx->Const.Program[MESA_SHADER_VERTEX].MaxTemps <= (1 << INST_INDEX_BITS));
7101e04c3fSmrg   assert(ctx->Const.Program[MESA_SHADER_VERTEX].MaxLocalParams <= (1 << INST_INDEX_BITS));
7201e04c3fSmrg   assert(ctx->Const.Program[MESA_SHADER_FRAGMENT].MaxTemps <= (1 << INST_INDEX_BITS));
7301e04c3fSmrg   assert(ctx->Const.Program[MESA_SHADER_FRAGMENT].MaxLocalParams <= (1 << INST_INDEX_BITS));
743464ebd5Sriastradh
7501e04c3fSmrg   assert(ctx->Const.Program[MESA_SHADER_VERTEX].MaxUniformComponents <= 4 * MAX_UNIFORMS);
7601e04c3fSmrg   assert(ctx->Const.Program[MESA_SHADER_FRAGMENT].MaxUniformComponents <= 4 * MAX_UNIFORMS);
773464ebd5Sriastradh
7801e04c3fSmrg   assert(ctx->Const.Program[MESA_SHADER_VERTEX].MaxAddressOffset <= (1 << INST_INDEX_BITS));
7901e04c3fSmrg   assert(ctx->Const.Program[MESA_SHADER_FRAGMENT].MaxAddressOffset <= (1 << INST_INDEX_BITS));
803464ebd5Sriastradh
813464ebd5Sriastradh   /* If this fails, increase prog_instruction::TexSrcUnit size */
82af69d88dSmrg   STATIC_ASSERT(MAX_TEXTURE_UNITS <= (1 << 5));
833464ebd5Sriastradh
843464ebd5Sriastradh   /* If this fails, increase prog_instruction::TexSrcTarget size */
85af69d88dSmrg   STATIC_ASSERT(NUM_TEXTURE_TARGETS <= (1 << 4));
863464ebd5Sriastradh
873464ebd5Sriastradh   ctx->Program.ErrorPos = -1;
8801e04c3fSmrg   ctx->Program.ErrorString = strdup("");
893464ebd5Sriastradh
903464ebd5Sriastradh   ctx->VertexProgram.Enabled = GL_FALSE;
913464ebd5Sriastradh   ctx->VertexProgram.PointSizeEnabled =
923464ebd5Sriastradh      (ctx->API == API_OPENGLES2) ? GL_TRUE : GL_FALSE;
933464ebd5Sriastradh   ctx->VertexProgram.TwoSideEnabled = GL_FALSE;
9401e04c3fSmrg   _mesa_reference_program(ctx, &ctx->VertexProgram.Current,
9501e04c3fSmrg                           ctx->Shared->DefaultVertexProgram);
963464ebd5Sriastradh   assert(ctx->VertexProgram.Current);
973464ebd5Sriastradh   ctx->VertexProgram.Cache = _mesa_new_program_cache();
983464ebd5Sriastradh
993464ebd5Sriastradh   ctx->FragmentProgram.Enabled = GL_FALSE;
10001e04c3fSmrg   _mesa_reference_program(ctx, &ctx->FragmentProgram.Current,
10101e04c3fSmrg                           ctx->Shared->DefaultFragmentProgram);
1023464ebd5Sriastradh   assert(ctx->FragmentProgram.Current);
1033464ebd5Sriastradh   ctx->FragmentProgram.Cache = _mesa_new_program_cache();
1047ec681f3Smrg   _mesa_reset_vertex_processing_mode(ctx);
1053464ebd5Sriastradh
1063464ebd5Sriastradh   /* XXX probably move this stuff */
1073464ebd5Sriastradh   ctx->ATIFragmentShader.Enabled = GL_FALSE;
1083464ebd5Sriastradh   ctx->ATIFragmentShader.Current = ctx->Shared->DefaultFragmentShader;
1093464ebd5Sriastradh   assert(ctx->ATIFragmentShader.Current);
1103464ebd5Sriastradh   ctx->ATIFragmentShader.Current->RefCount++;
1113464ebd5Sriastradh}
1123464ebd5Sriastradh
1133464ebd5Sriastradh
1143464ebd5Sriastradh/**
1153464ebd5Sriastradh * Free a context's vertex/fragment program state
1163464ebd5Sriastradh */
1173464ebd5Sriastradhvoid
1183464ebd5Sriastradh_mesa_free_program_data(struct gl_context *ctx)
1193464ebd5Sriastradh{
12001e04c3fSmrg   _mesa_reference_program(ctx, &ctx->VertexProgram.Current, NULL);
1213464ebd5Sriastradh   _mesa_delete_program_cache(ctx, ctx->VertexProgram.Cache);
12201e04c3fSmrg   _mesa_reference_program(ctx, &ctx->FragmentProgram.Current, NULL);
123af69d88dSmrg   _mesa_delete_shader_cache(ctx, ctx->FragmentProgram.Cache);
124af69d88dSmrg
1253464ebd5Sriastradh   /* XXX probably move this stuff */
1263464ebd5Sriastradh   if (ctx->ATIFragmentShader.Current) {
1273464ebd5Sriastradh      ctx->ATIFragmentShader.Current->RefCount--;
1283464ebd5Sriastradh      if (ctx->ATIFragmentShader.Current->RefCount <= 0) {
1293464ebd5Sriastradh         free(ctx->ATIFragmentShader.Current);
1303464ebd5Sriastradh      }
1313464ebd5Sriastradh   }
132af69d88dSmrg
1333464ebd5Sriastradh   free((void *) ctx->Program.ErrorString);
1343464ebd5Sriastradh}
1353464ebd5Sriastradh
1363464ebd5Sriastradh
1373464ebd5Sriastradh/**
1383464ebd5Sriastradh * Update the default program objects in the given context to reference those
1393464ebd5Sriastradh * specified in the shared state and release those referencing the old
1403464ebd5Sriastradh * shared state.
1413464ebd5Sriastradh */
1423464ebd5Sriastradhvoid
1433464ebd5Sriastradh_mesa_update_default_objects_program(struct gl_context *ctx)
1443464ebd5Sriastradh{
14501e04c3fSmrg   _mesa_reference_program(ctx, &ctx->VertexProgram.Current,
14601e04c3fSmrg                           ctx->Shared->DefaultVertexProgram);
1473464ebd5Sriastradh   assert(ctx->VertexProgram.Current);
1483464ebd5Sriastradh
14901e04c3fSmrg   _mesa_reference_program(ctx, &ctx->FragmentProgram.Current,
1503464ebd5Sriastradh                            ctx->Shared->DefaultFragmentProgram);
1513464ebd5Sriastradh   assert(ctx->FragmentProgram.Current);
1523464ebd5Sriastradh
1533464ebd5Sriastradh   /* XXX probably move this stuff */
1543464ebd5Sriastradh   if (ctx->ATIFragmentShader.Current) {
1553464ebd5Sriastradh      ctx->ATIFragmentShader.Current->RefCount--;
1563464ebd5Sriastradh      if (ctx->ATIFragmentShader.Current->RefCount <= 0) {
1573464ebd5Sriastradh         free(ctx->ATIFragmentShader.Current);
1583464ebd5Sriastradh      }
1593464ebd5Sriastradh   }
1603464ebd5Sriastradh   ctx->ATIFragmentShader.Current = (struct ati_fragment_shader *) ctx->Shared->DefaultFragmentShader;
1613464ebd5Sriastradh   assert(ctx->ATIFragmentShader.Current);
1623464ebd5Sriastradh   ctx->ATIFragmentShader.Current->RefCount++;
1633464ebd5Sriastradh}
1643464ebd5Sriastradh
1653464ebd5Sriastradh
1663464ebd5Sriastradh/**
1673464ebd5Sriastradh * Set the vertex/fragment program error state (position and error string).
1683464ebd5Sriastradh * This is generally called from within the parsers.
1693464ebd5Sriastradh */
1703464ebd5Sriastradhvoid
1713464ebd5Sriastradh_mesa_set_program_error(struct gl_context *ctx, GLint pos, const char *string)
1723464ebd5Sriastradh{
1733464ebd5Sriastradh   ctx->Program.ErrorPos = pos;
1743464ebd5Sriastradh   free((void *) ctx->Program.ErrorString);
1753464ebd5Sriastradh   if (!string)
1763464ebd5Sriastradh      string = "";
17701e04c3fSmrg   ctx->Program.ErrorString = strdup(string);
1783464ebd5Sriastradh}
1793464ebd5Sriastradh
1803464ebd5Sriastradh
1813464ebd5Sriastradh/**
182af69d88dSmrg * Initialize a new gl_program object.
1833464ebd5Sriastradh */
18401e04c3fSmrgstruct gl_program *
1857ec681f3Smrg_mesa_init_gl_program(struct gl_program *prog, gl_shader_stage stage,
1867ec681f3Smrg                      GLuint id, bool is_arb_asm)
1873464ebd5Sriastradh{
18801e04c3fSmrg   if (!prog)
18901e04c3fSmrg      return NULL;
190af69d88dSmrg
191af69d88dSmrg   memset(prog, 0, sizeof(*prog));
192af69d88dSmrg   prog->Id = id;
1937ec681f3Smrg   prog->Target = _mesa_shader_stage_to_program(stage);
194af69d88dSmrg   prog->RefCount = 1;
195af69d88dSmrg   prog->Format = GL_PROGRAM_FORMAT_ASCII_ARB;
1967ec681f3Smrg   prog->info.stage = stage;
1977ec681f3Smrg   prog->info.is_arb_asm = is_arb_asm;
198af69d88dSmrg
19901e04c3fSmrg   /* Uniforms that lack an initializer in the shader code have an initial
20001e04c3fSmrg    * value of zero.  This includes sampler uniforms.
20101e04c3fSmrg    *
20201e04c3fSmrg    * Page 24 (page 30 of the PDF) of the GLSL 1.20 spec says:
20301e04c3fSmrg    *
20401e04c3fSmrg    *     "The link time initial value is either the value of the variable's
20501e04c3fSmrg    *     initializer, if present, or 0 if no initializer is present. Sampler
20601e04c3fSmrg    *     types cannot have initializers."
20701e04c3fSmrg    *
20801e04c3fSmrg    * So we only initialise ARB assembly style programs.
20901e04c3fSmrg    */
21001e04c3fSmrg   if (is_arb_asm) {
21101e04c3fSmrg      /* default mapping from samplers to texture units */
21201e04c3fSmrg      for (unsigned i = 0; i < MAX_SAMPLERS; i++)
21301e04c3fSmrg         prog->SamplerUnits[i] = i;
214af69d88dSmrg   }
2153464ebd5Sriastradh
21601e04c3fSmrg   return prog;
2173464ebd5Sriastradh}
2183464ebd5Sriastradh
2193464ebd5Sriastradh
2203464ebd5Sriastradh/**
2213464ebd5Sriastradh * Allocate and initialize a new fragment/vertex program object but
2223464ebd5Sriastradh * don't put it into the program hash table.  Called via
2233464ebd5Sriastradh * ctx->Driver.NewProgram.  May be overridden (ie. replaced) by a
2243464ebd5Sriastradh * device driver function to implement OO deriviation with additional
2253464ebd5Sriastradh * types not understood by this function.
2263464ebd5Sriastradh *
2273464ebd5Sriastradh * \param ctx  context
2283464ebd5Sriastradh * \param id   program id/number
2297ec681f3Smrg * \param stage  shader stage
2303464ebd5Sriastradh * \return  pointer to new program object
2313464ebd5Sriastradh */
2323464ebd5Sriastradhstruct gl_program *
2337ec681f3Smrg_mesa_new_program(struct gl_context *ctx, gl_shader_stage stage, GLuint id,
23401e04c3fSmrg                  bool is_arb_asm)
2353464ebd5Sriastradh{
2367ec681f3Smrg   struct gl_program *prog = rzalloc(NULL, struct gl_program);
2377ec681f3Smrg
2387ec681f3Smrg   return _mesa_init_gl_program(prog, stage, id, is_arb_asm);
2393464ebd5Sriastradh}
2403464ebd5Sriastradh
2413464ebd5Sriastradh
2423464ebd5Sriastradh/**
2433464ebd5Sriastradh * Delete a program and remove it from the hash table, ignoring the
2443464ebd5Sriastradh * reference count.
2453464ebd5Sriastradh * Called via ctx->Driver.DeleteProgram.  May be wrapped (OO deriviation)
2463464ebd5Sriastradh * by a device driver function.
2473464ebd5Sriastradh */
2483464ebd5Sriastradhvoid
2493464ebd5Sriastradh_mesa_delete_program(struct gl_context *ctx, struct gl_program *prog)
2503464ebd5Sriastradh{
2513464ebd5Sriastradh   (void) ctx;
25201e04c3fSmrg   assert(prog);
25301e04c3fSmrg   assert(prog->RefCount==0);
2543464ebd5Sriastradh
2553464ebd5Sriastradh   if (prog == &_mesa_DummyProgram)
2563464ebd5Sriastradh      return;
2573464ebd5Sriastradh
2583464ebd5Sriastradh   if (prog->Parameters) {
2593464ebd5Sriastradh      _mesa_free_parameter_list(prog->Parameters);
2603464ebd5Sriastradh   }
2613464ebd5Sriastradh
26201e04c3fSmrg   if (prog->nir) {
26301e04c3fSmrg      ralloc_free(prog->nir);
26401e04c3fSmrg   }
26501e04c3fSmrg
26601e04c3fSmrg   if (prog->sh.BindlessSamplers) {
26701e04c3fSmrg      ralloc_free(prog->sh.BindlessSamplers);
26801e04c3fSmrg   }
26901e04c3fSmrg
27001e04c3fSmrg   if (prog->sh.BindlessImages) {
27101e04c3fSmrg      ralloc_free(prog->sh.BindlessImages);
27201e04c3fSmrg   }
27301e04c3fSmrg
27401e04c3fSmrg   if (prog->driver_cache_blob) {
27501e04c3fSmrg      ralloc_free(prog->driver_cache_blob);
27601e04c3fSmrg   }
27701e04c3fSmrg
27801e04c3fSmrg   ralloc_free(prog);
2793464ebd5Sriastradh}
2803464ebd5Sriastradh
2813464ebd5Sriastradh
2823464ebd5Sriastradh/**
2833464ebd5Sriastradh * Return the gl_program object for a given ID.
2843464ebd5Sriastradh * Basically just a wrapper for _mesa_HashLookup() to avoid a lot of
2853464ebd5Sriastradh * casts elsewhere.
2863464ebd5Sriastradh */
2873464ebd5Sriastradhstruct gl_program *
2883464ebd5Sriastradh_mesa_lookup_program(struct gl_context *ctx, GLuint id)
2893464ebd5Sriastradh{
2903464ebd5Sriastradh   if (id)
2913464ebd5Sriastradh      return (struct gl_program *) _mesa_HashLookup(ctx->Shared->Programs, id);
2923464ebd5Sriastradh   else
2933464ebd5Sriastradh      return NULL;
2943464ebd5Sriastradh}
2953464ebd5Sriastradh
2963464ebd5Sriastradh
2973464ebd5Sriastradh/**
2983464ebd5Sriastradh * Reference counting for vertex/fragment programs
299af69d88dSmrg * This is normally only called from the _mesa_reference_program() macro
300af69d88dSmrg * when there's a real pointer change.
3013464ebd5Sriastradh */
3023464ebd5Sriastradhvoid
303af69d88dSmrg_mesa_reference_program_(struct gl_context *ctx,
304af69d88dSmrg                         struct gl_program **ptr,
305af69d88dSmrg                         struct gl_program *prog)
3063464ebd5Sriastradh{
307af69d88dSmrg#ifndef NDEBUG
3083464ebd5Sriastradh   assert(ptr);
3093464ebd5Sriastradh   if (*ptr && prog) {
3103464ebd5Sriastradh      /* sanity check */
3113464ebd5Sriastradh      if ((*ptr)->Target == GL_VERTEX_PROGRAM_ARB)
31201e04c3fSmrg         assert(prog->Target == GL_VERTEX_PROGRAM_ARB);
3133464ebd5Sriastradh      else if ((*ptr)->Target == GL_FRAGMENT_PROGRAM_ARB)
31401e04c3fSmrg         assert(prog->Target == GL_FRAGMENT_PROGRAM_ARB ||
3153464ebd5Sriastradh                prog->Target == GL_FRAGMENT_PROGRAM_NV);
31601e04c3fSmrg      else if ((*ptr)->Target == GL_GEOMETRY_PROGRAM_NV)
31701e04c3fSmrg         assert(prog->Target == GL_GEOMETRY_PROGRAM_NV);
3183464ebd5Sriastradh   }
319af69d88dSmrg#endif
320af69d88dSmrg
3213464ebd5Sriastradh   if (*ptr) {
32201e04c3fSmrg      struct gl_program *oldProg = *ptr;
3233464ebd5Sriastradh
32401e04c3fSmrg      assert(oldProg->RefCount > 0);
3253464ebd5Sriastradh
32601e04c3fSmrg      if (p_atomic_dec_zero(&oldProg->RefCount)) {
32701e04c3fSmrg         assert(ctx);
32801e04c3fSmrg         _mesa_reference_shader_program_data(ctx, &oldProg->sh.data, NULL);
32901e04c3fSmrg         ctx->Driver.DeleteProgram(ctx, oldProg);
3303464ebd5Sriastradh      }
3313464ebd5Sriastradh
3323464ebd5Sriastradh      *ptr = NULL;
3333464ebd5Sriastradh   }
3343464ebd5Sriastradh
3353464ebd5Sriastradh   assert(!*ptr);
3363464ebd5Sriastradh   if (prog) {
33701e04c3fSmrg      p_atomic_inc(&prog->RefCount);
3383464ebd5Sriastradh   }
3393464ebd5Sriastradh
3403464ebd5Sriastradh   *ptr = prog;
3413464ebd5Sriastradh}
3423464ebd5Sriastradh
3433464ebd5Sriastradh
3443464ebd5Sriastradh/**
3453464ebd5Sriastradh * Insert 'count' NOP instructions at 'start' in the given program.
3463464ebd5Sriastradh * Adjust branch targets accordingly.
3473464ebd5Sriastradh */
3483464ebd5SriastradhGLboolean
3493464ebd5Sriastradh_mesa_insert_instructions(struct gl_program *prog, GLuint start, GLuint count)
3503464ebd5Sriastradh{
35101e04c3fSmrg   const GLuint origLen = prog->arb.NumInstructions;
3523464ebd5Sriastradh   const GLuint newLen = origLen + count;
3533464ebd5Sriastradh   struct prog_instruction *newInst;
3543464ebd5Sriastradh   GLuint i;
3553464ebd5Sriastradh
3563464ebd5Sriastradh   /* adjust branches */
35701e04c3fSmrg   for (i = 0; i < prog->arb.NumInstructions; i++) {
35801e04c3fSmrg      struct prog_instruction *inst = prog->arb.Instructions + i;
3593464ebd5Sriastradh      if (inst->BranchTarget > 0) {
3603464ebd5Sriastradh         if ((GLuint)inst->BranchTarget >= start) {
3613464ebd5Sriastradh            inst->BranchTarget += count;
3623464ebd5Sriastradh         }
3633464ebd5Sriastradh      }
3643464ebd5Sriastradh   }
3653464ebd5Sriastradh
3663464ebd5Sriastradh   /* Alloc storage for new instructions */
36701e04c3fSmrg   newInst = rzalloc_array(prog, struct prog_instruction, newLen);
3683464ebd5Sriastradh   if (!newInst) {
3693464ebd5Sriastradh      return GL_FALSE;
3703464ebd5Sriastradh   }
3713464ebd5Sriastradh
3723464ebd5Sriastradh   /* Copy 'start' instructions into new instruction buffer */
37301e04c3fSmrg   _mesa_copy_instructions(newInst, prog->arb.Instructions, start);
3743464ebd5Sriastradh
3753464ebd5Sriastradh   /* init the new instructions */
3763464ebd5Sriastradh   _mesa_init_instructions(newInst + start, count);
3773464ebd5Sriastradh
3783464ebd5Sriastradh   /* Copy the remaining/tail instructions to new inst buffer */
3793464ebd5Sriastradh   _mesa_copy_instructions(newInst + start + count,
38001e04c3fSmrg                           prog->arb.Instructions + start,
3813464ebd5Sriastradh                           origLen - start);
3823464ebd5Sriastradh
3833464ebd5Sriastradh   /* free old instructions */
38401e04c3fSmrg   ralloc_free(prog->arb.Instructions);
3853464ebd5Sriastradh
3863464ebd5Sriastradh   /* install new instructions */
38701e04c3fSmrg   prog->arb.Instructions = newInst;
38801e04c3fSmrg   prog->arb.NumInstructions = newLen;
3893464ebd5Sriastradh
3903464ebd5Sriastradh   return GL_TRUE;
3913464ebd5Sriastradh}
3923464ebd5Sriastradh
3933464ebd5Sriastradh/**
3943464ebd5Sriastradh * Delete 'count' instructions at 'start' in the given program.
3953464ebd5Sriastradh * Adjust branch targets accordingly.
3963464ebd5Sriastradh */
3973464ebd5SriastradhGLboolean
39801e04c3fSmrg_mesa_delete_instructions(struct gl_program *prog, GLuint start, GLuint count,
39901e04c3fSmrg                          void *mem_ctx)
4003464ebd5Sriastradh{
40101e04c3fSmrg   const GLuint origLen = prog->arb.NumInstructions;
4023464ebd5Sriastradh   const GLuint newLen = origLen - count;
4033464ebd5Sriastradh   struct prog_instruction *newInst;
4043464ebd5Sriastradh   GLuint i;
4053464ebd5Sriastradh
4063464ebd5Sriastradh   /* adjust branches */
40701e04c3fSmrg   for (i = 0; i < prog->arb.NumInstructions; i++) {
40801e04c3fSmrg      struct prog_instruction *inst = prog->arb.Instructions + i;
4093464ebd5Sriastradh      if (inst->BranchTarget > 0) {
4103464ebd5Sriastradh         if (inst->BranchTarget > (GLint) start) {
4113464ebd5Sriastradh            inst->BranchTarget -= count;
4123464ebd5Sriastradh         }
4133464ebd5Sriastradh      }
4143464ebd5Sriastradh   }
4153464ebd5Sriastradh
4163464ebd5Sriastradh   /* Alloc storage for new instructions */
41701e04c3fSmrg   newInst = rzalloc_array(mem_ctx, struct prog_instruction, newLen);
4183464ebd5Sriastradh   if (!newInst) {
4193464ebd5Sriastradh      return GL_FALSE;
4203464ebd5Sriastradh   }
4213464ebd5Sriastradh
4223464ebd5Sriastradh   /* Copy 'start' instructions into new instruction buffer */
42301e04c3fSmrg   _mesa_copy_instructions(newInst, prog->arb.Instructions, start);
4243464ebd5Sriastradh
4253464ebd5Sriastradh   /* Copy the remaining/tail instructions to new inst buffer */
4263464ebd5Sriastradh   _mesa_copy_instructions(newInst + start,
42701e04c3fSmrg                           prog->arb.Instructions + start + count,
4283464ebd5Sriastradh                           newLen - start);
4293464ebd5Sriastradh
4303464ebd5Sriastradh   /* free old instructions */
43101e04c3fSmrg   ralloc_free(prog->arb.Instructions);
4323464ebd5Sriastradh
4333464ebd5Sriastradh   /* install new instructions */
43401e04c3fSmrg   prog->arb.Instructions = newInst;
43501e04c3fSmrg   prog->arb.NumInstructions = newLen;
4363464ebd5Sriastradh
4373464ebd5Sriastradh   return GL_TRUE;
4383464ebd5Sriastradh}
4393464ebd5Sriastradh
4403464ebd5Sriastradh
4413464ebd5Sriastradh/**
4423464ebd5Sriastradh * Populate the 'used' array with flags indicating which registers (TEMPs,
4433464ebd5Sriastradh * INPUTs, OUTPUTs, etc, are used by the given program.
4443464ebd5Sriastradh * \param file  type of register to scan for
4453464ebd5Sriastradh * \param used  returns true/false flags for in use / free
4463464ebd5Sriastradh * \param usedSize  size of the 'used' array
4473464ebd5Sriastradh */
4483464ebd5Sriastradhvoid
4493464ebd5Sriastradh_mesa_find_used_registers(const struct gl_program *prog,
4503464ebd5Sriastradh                          gl_register_file file,
4513464ebd5Sriastradh                          GLboolean used[], GLuint usedSize)
4523464ebd5Sriastradh{
4533464ebd5Sriastradh   GLuint i, j;
4543464ebd5Sriastradh
4553464ebd5Sriastradh   memset(used, 0, usedSize);
4563464ebd5Sriastradh
45701e04c3fSmrg   for (i = 0; i < prog->arb.NumInstructions; i++) {
45801e04c3fSmrg      const struct prog_instruction *inst = prog->arb.Instructions + i;
4593464ebd5Sriastradh      const GLuint n = _mesa_num_inst_src_regs(inst->Opcode);
4603464ebd5Sriastradh
4613464ebd5Sriastradh      if (inst->DstReg.File == file) {
46201e04c3fSmrg         assert(inst->DstReg.Index < usedSize);
4633464ebd5Sriastradh         if(inst->DstReg.Index < usedSize)
4643464ebd5Sriastradh            used[inst->DstReg.Index] = GL_TRUE;
4653464ebd5Sriastradh      }
4663464ebd5Sriastradh
4673464ebd5Sriastradh      for (j = 0; j < n; j++) {
4683464ebd5Sriastradh         if (inst->SrcReg[j].File == file) {
46901e04c3fSmrg            assert(inst->SrcReg[j].Index < (GLint) usedSize);
470af69d88dSmrg            if (inst->SrcReg[j].Index < (GLint) usedSize)
4713464ebd5Sriastradh               used[inst->SrcReg[j].Index] = GL_TRUE;
4723464ebd5Sriastradh         }
4733464ebd5Sriastradh      }
4743464ebd5Sriastradh   }
4753464ebd5Sriastradh}
4763464ebd5Sriastradh
4773464ebd5Sriastradh
4783464ebd5Sriastradh/**
4793464ebd5Sriastradh * Scan the given 'used' register flag array for the first entry
4803464ebd5Sriastradh * that's >= firstReg.
4813464ebd5Sriastradh * \param used  vector of flags indicating registers in use (as returned
4823464ebd5Sriastradh *              by _mesa_find_used_registers())
4833464ebd5Sriastradh * \param usedSize  size of the 'used' array
4843464ebd5Sriastradh * \param firstReg  first register to start searching at
4853464ebd5Sriastradh * \return index of unused register, or -1 if none.
4863464ebd5Sriastradh */
4873464ebd5SriastradhGLint
4883464ebd5Sriastradh_mesa_find_free_register(const GLboolean used[],
4893464ebd5Sriastradh                         GLuint usedSize, GLuint firstReg)
4903464ebd5Sriastradh{
4913464ebd5Sriastradh   GLuint i;
4923464ebd5Sriastradh
4933464ebd5Sriastradh   assert(firstReg < usedSize);
4943464ebd5Sriastradh
4953464ebd5Sriastradh   for (i = firstReg; i < usedSize; i++)
4963464ebd5Sriastradh      if (!used[i])
4973464ebd5Sriastradh         return i;
4983464ebd5Sriastradh
4993464ebd5Sriastradh   return -1;
5003464ebd5Sriastradh}
5013464ebd5Sriastradh
5023464ebd5Sriastradh
503af69d88dSmrg/* Gets the minimum number of shader invocations per fragment.
504af69d88dSmrg * This function is useful to determine if we need to do per
505af69d88dSmrg * sample shading or per fragment shading.
506af69d88dSmrg */
507af69d88dSmrgGLint
508af69d88dSmrg_mesa_get_min_invocations_per_fragment(struct gl_context *ctx,
50901e04c3fSmrg                                       const struct gl_program *prog)
510af69d88dSmrg{
511af69d88dSmrg   /* From ARB_sample_shading specification:
512af69d88dSmrg    * "Using gl_SampleID in a fragment shader causes the entire shader
513af69d88dSmrg    *  to be evaluated per-sample."
514af69d88dSmrg    *
515af69d88dSmrg    * "Using gl_SamplePosition in a fragment shader causes the entire
516af69d88dSmrg    *  shader to be evaluated per-sample."
517af69d88dSmrg    *
518af69d88dSmrg    * "If MULTISAMPLE or SAMPLE_SHADING_ARB is disabled, sample shading
519af69d88dSmrg    *  has no effect."
520af69d88dSmrg    */
521af69d88dSmrg   if (ctx->Multisample.Enabled) {
522af69d88dSmrg      /* The ARB_gpu_shader5 specification says:
523af69d88dSmrg       *
524af69d88dSmrg       * "Use of the "sample" qualifier on a fragment shader input
525af69d88dSmrg       *  forces per-sample shading"
526af69d88dSmrg       */
52701e04c3fSmrg      if (prog->info.fs.uses_sample_qualifier ||
5287ec681f3Smrg          BITSET_TEST(prog->info.system_values_read, SYSTEM_VALUE_SAMPLE_ID) ||
5297ec681f3Smrg          BITSET_TEST(prog->info.system_values_read, SYSTEM_VALUE_SAMPLE_POS))
53001e04c3fSmrg         return MAX2(_mesa_geometric_samples(ctx->DrawBuffer), 1);
531af69d88dSmrg      else if (ctx->Multisample.SampleShading)
5327ec681f3Smrg         return MAX2(ceilf(ctx->Multisample.MinSampleShadingValue *
53301e04c3fSmrg                          _mesa_geometric_samples(ctx->DrawBuffer)), 1);
534af69d88dSmrg      else
535af69d88dSmrg         return 1;
536af69d88dSmrg   }
537af69d88dSmrg   return 1;
538af69d88dSmrg}
53901e04c3fSmrg
54001e04c3fSmrg
54101e04c3fSmrgGLbitfield
54201e04c3fSmrggl_external_samplers(const struct gl_program *prog)
54301e04c3fSmrg{
54401e04c3fSmrg   GLbitfield external_samplers = 0;
54501e04c3fSmrg   GLbitfield mask = prog->SamplersUsed;
54601e04c3fSmrg
54701e04c3fSmrg   while (mask) {
54801e04c3fSmrg      int idx = u_bit_scan(&mask);
54901e04c3fSmrg      if (prog->sh.SamplerTargets[idx] == TEXTURE_EXTERNAL_INDEX)
55001e04c3fSmrg         external_samplers |= (1 << idx);
55101e04c3fSmrg   }
55201e04c3fSmrg
55301e04c3fSmrg   return external_samplers;
55401e04c3fSmrg}
5557ec681f3Smrg
5567ec681f3Smrgstatic int compare_state_var(const void *a1, const void *a2)
5577ec681f3Smrg{
5587ec681f3Smrg   const struct gl_program_parameter *p1 =
5597ec681f3Smrg      (const struct gl_program_parameter *)a1;
5607ec681f3Smrg   const struct gl_program_parameter *p2 =
5617ec681f3Smrg      (const struct gl_program_parameter *)a2;
5627ec681f3Smrg
5637ec681f3Smrg   for (unsigned i = 0; i < STATE_LENGTH; i++) {
5647ec681f3Smrg      if (p1->StateIndexes[i] != p2->StateIndexes[i])
5657ec681f3Smrg         return p1->StateIndexes[i] - p2->StateIndexes[i];
5667ec681f3Smrg   }
5677ec681f3Smrg   return 0;
5687ec681f3Smrg}
5697ec681f3Smrg
5707ec681f3Smrgvoid
5717ec681f3Smrg_mesa_add_separate_state_parameters(struct gl_program *prog,
5727ec681f3Smrg                                    struct gl_program_parameter_list *state_params)
5737ec681f3Smrg{
5747ec681f3Smrg   unsigned num_state_params = state_params->NumParameters;
5757ec681f3Smrg
5767ec681f3Smrg   /* All state parameters should be vec4s. */
5777ec681f3Smrg   for (unsigned i = 0; i < num_state_params; i++) {
5787ec681f3Smrg      assert(state_params->Parameters[i].Type == PROGRAM_STATE_VAR);
5797ec681f3Smrg      assert(state_params->Parameters[i].Size == 4);
5807ec681f3Smrg      assert(state_params->Parameters[i].ValueOffset == i * 4);
5817ec681f3Smrg   }
5827ec681f3Smrg
5837ec681f3Smrg   /* Sort state parameters to facilitate better parameter merging. */
5847ec681f3Smrg   qsort(state_params->Parameters, num_state_params,
5857ec681f3Smrg         sizeof(state_params->Parameters[0]), compare_state_var);
5867ec681f3Smrg   unsigned *remap = malloc(num_state_params * sizeof(unsigned));
5877ec681f3Smrg
5887ec681f3Smrg   /* Add state parameters to the end of the parameter list. */
5897ec681f3Smrg   for (unsigned i = 0; i < num_state_params; i++) {
5907ec681f3Smrg      unsigned old_index = state_params->Parameters[i].ValueOffset / 4;
5917ec681f3Smrg
5927ec681f3Smrg      remap[old_index] =
5937ec681f3Smrg         _mesa_add_parameter(prog->Parameters, PROGRAM_STATE_VAR,
5947ec681f3Smrg                             state_params->Parameters[i].Name,
5957ec681f3Smrg                             state_params->Parameters[i].Size,
5967ec681f3Smrg                             GL_NONE, NULL,
5977ec681f3Smrg                             state_params->Parameters[i].StateIndexes,
5987ec681f3Smrg                             state_params->Parameters[i].Padded);
5997ec681f3Smrg
6007ec681f3Smrg      prog->Parameters->StateFlags |=
6017ec681f3Smrg         _mesa_program_state_flags(state_params->Parameters[i].StateIndexes);
6027ec681f3Smrg   }
6037ec681f3Smrg
6047ec681f3Smrg   /* Fix up state parameter offsets in instructions. */
6057ec681f3Smrg   int num_instr = prog->arb.NumInstructions;
6067ec681f3Smrg   struct prog_instruction *instrs = prog->arb.Instructions;
6077ec681f3Smrg
6087ec681f3Smrg   /* Fix src indices after sorting. */
6097ec681f3Smrg   for (unsigned i = 0; i < num_instr; i++) {
6107ec681f3Smrg      struct prog_instruction *inst = instrs + i;
6117ec681f3Smrg      unsigned num_src = _mesa_num_inst_src_regs(inst->Opcode);
6127ec681f3Smrg
6137ec681f3Smrg      for (unsigned j = 0; j < num_src; j++) {
6147ec681f3Smrg         if (inst->SrcReg[j].File == PROGRAM_STATE_VAR)
6157ec681f3Smrg            inst->SrcReg[j].Index = remap[inst->SrcReg[j].Index];
6167ec681f3Smrg      }
6177ec681f3Smrg   }
6187ec681f3Smrg   free(remap);
6197ec681f3Smrg}
620