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