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