program.c revision af69d88d
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" 343464ebd5Sriastradh#include "main/hash.h" 35af69d88dSmrg#include "main/macros.h" 363464ebd5Sriastradh#include "program.h" 373464ebd5Sriastradh#include "prog_cache.h" 383464ebd5Sriastradh#include "prog_parameter.h" 393464ebd5Sriastradh#include "prog_instruction.h" 403464ebd5Sriastradh 413464ebd5Sriastradh 423464ebd5Sriastradh/** 433464ebd5Sriastradh * A pointer to this dummy program is put into the hash table when 443464ebd5Sriastradh * glGenPrograms is called. 453464ebd5Sriastradh */ 463464ebd5Sriastradhstruct gl_program _mesa_DummyProgram; 473464ebd5Sriastradh 483464ebd5Sriastradh 493464ebd5Sriastradh/** 503464ebd5Sriastradh * Init context's vertex/fragment program state 513464ebd5Sriastradh */ 523464ebd5Sriastradhvoid 533464ebd5Sriastradh_mesa_init_program(struct gl_context *ctx) 543464ebd5Sriastradh{ 553464ebd5Sriastradh /* 563464ebd5Sriastradh * If this assertion fails, we need to increase the field 573464ebd5Sriastradh * size for register indexes (see INST_INDEX_BITS). 583464ebd5Sriastradh */ 59af69d88dSmrg ASSERT(ctx->Const.Program[MESA_SHADER_VERTEX].MaxUniformComponents / 4 603464ebd5Sriastradh <= (1 << INST_INDEX_BITS)); 61af69d88dSmrg ASSERT(ctx->Const.Program[MESA_SHADER_FRAGMENT].MaxUniformComponents / 4 623464ebd5Sriastradh <= (1 << INST_INDEX_BITS)); 633464ebd5Sriastradh 64af69d88dSmrg ASSERT(ctx->Const.Program[MESA_SHADER_VERTEX].MaxTemps <= (1 << INST_INDEX_BITS)); 65af69d88dSmrg ASSERT(ctx->Const.Program[MESA_SHADER_VERTEX].MaxLocalParams <= (1 << INST_INDEX_BITS)); 66af69d88dSmrg ASSERT(ctx->Const.Program[MESA_SHADER_FRAGMENT].MaxTemps <= (1 << INST_INDEX_BITS)); 67af69d88dSmrg ASSERT(ctx->Const.Program[MESA_SHADER_FRAGMENT].MaxLocalParams <= (1 << INST_INDEX_BITS)); 683464ebd5Sriastradh 69af69d88dSmrg ASSERT(ctx->Const.Program[MESA_SHADER_VERTEX].MaxUniformComponents <= 4 * MAX_UNIFORMS); 70af69d88dSmrg ASSERT(ctx->Const.Program[MESA_SHADER_FRAGMENT].MaxUniformComponents <= 4 * MAX_UNIFORMS); 713464ebd5Sriastradh 72af69d88dSmrg ASSERT(ctx->Const.Program[MESA_SHADER_VERTEX].MaxAddressOffset <= (1 << INST_INDEX_BITS)); 73af69d88dSmrg ASSERT(ctx->Const.Program[MESA_SHADER_FRAGMENT].MaxAddressOffset <= (1 << INST_INDEX_BITS)); 743464ebd5Sriastradh 753464ebd5Sriastradh /* If this fails, increase prog_instruction::TexSrcUnit size */ 76af69d88dSmrg STATIC_ASSERT(MAX_TEXTURE_UNITS <= (1 << 5)); 773464ebd5Sriastradh 783464ebd5Sriastradh /* If this fails, increase prog_instruction::TexSrcTarget size */ 79af69d88dSmrg STATIC_ASSERT(NUM_TEXTURE_TARGETS <= (1 << 4)); 803464ebd5Sriastradh 813464ebd5Sriastradh ctx->Program.ErrorPos = -1; 823464ebd5Sriastradh ctx->Program.ErrorString = _mesa_strdup(""); 833464ebd5Sriastradh 843464ebd5Sriastradh ctx->VertexProgram.Enabled = GL_FALSE; 853464ebd5Sriastradh ctx->VertexProgram.PointSizeEnabled = 863464ebd5Sriastradh (ctx->API == API_OPENGLES2) ? GL_TRUE : GL_FALSE; 873464ebd5Sriastradh ctx->VertexProgram.TwoSideEnabled = GL_FALSE; 883464ebd5Sriastradh _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current, 893464ebd5Sriastradh ctx->Shared->DefaultVertexProgram); 903464ebd5Sriastradh assert(ctx->VertexProgram.Current); 913464ebd5Sriastradh ctx->VertexProgram.Cache = _mesa_new_program_cache(); 923464ebd5Sriastradh 933464ebd5Sriastradh ctx->FragmentProgram.Enabled = GL_FALSE; 943464ebd5Sriastradh _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current, 953464ebd5Sriastradh ctx->Shared->DefaultFragmentProgram); 963464ebd5Sriastradh assert(ctx->FragmentProgram.Current); 973464ebd5Sriastradh ctx->FragmentProgram.Cache = _mesa_new_program_cache(); 983464ebd5Sriastradh 993464ebd5Sriastradh ctx->GeometryProgram.Enabled = GL_FALSE; 1003464ebd5Sriastradh /* right now by default we don't have a geometry program */ 1013464ebd5Sriastradh _mesa_reference_geomprog(ctx, &ctx->GeometryProgram.Current, 1023464ebd5Sriastradh NULL); 1033464ebd5Sriastradh ctx->GeometryProgram.Cache = _mesa_new_program_cache(); 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{ 1193464ebd5Sriastradh _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current, NULL); 1203464ebd5Sriastradh _mesa_delete_program_cache(ctx, ctx->VertexProgram.Cache); 1213464ebd5Sriastradh _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current, NULL); 122af69d88dSmrg _mesa_delete_shader_cache(ctx, ctx->FragmentProgram.Cache); 1233464ebd5Sriastradh _mesa_reference_geomprog(ctx, &ctx->GeometryProgram.Current, NULL); 1243464ebd5Sriastradh _mesa_delete_program_cache(ctx, ctx->GeometryProgram.Cache); 125af69d88dSmrg 1263464ebd5Sriastradh /* XXX probably move this stuff */ 1273464ebd5Sriastradh if (ctx->ATIFragmentShader.Current) { 1283464ebd5Sriastradh ctx->ATIFragmentShader.Current->RefCount--; 1293464ebd5Sriastradh if (ctx->ATIFragmentShader.Current->RefCount <= 0) { 1303464ebd5Sriastradh free(ctx->ATIFragmentShader.Current); 1313464ebd5Sriastradh } 1323464ebd5Sriastradh } 133af69d88dSmrg 1343464ebd5Sriastradh free((void *) ctx->Program.ErrorString); 1353464ebd5Sriastradh} 1363464ebd5Sriastradh 1373464ebd5Sriastradh 1383464ebd5Sriastradh/** 1393464ebd5Sriastradh * Update the default program objects in the given context to reference those 1403464ebd5Sriastradh * specified in the shared state and release those referencing the old 1413464ebd5Sriastradh * shared state. 1423464ebd5Sriastradh */ 1433464ebd5Sriastradhvoid 1443464ebd5Sriastradh_mesa_update_default_objects_program(struct gl_context *ctx) 1453464ebd5Sriastradh{ 1463464ebd5Sriastradh _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current, 1473464ebd5Sriastradh ctx->Shared->DefaultVertexProgram); 1483464ebd5Sriastradh assert(ctx->VertexProgram.Current); 1493464ebd5Sriastradh 1503464ebd5Sriastradh _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current, 1513464ebd5Sriastradh ctx->Shared->DefaultFragmentProgram); 1523464ebd5Sriastradh assert(ctx->FragmentProgram.Current); 1533464ebd5Sriastradh 1543464ebd5Sriastradh _mesa_reference_geomprog(ctx, &ctx->GeometryProgram.Current, 155af69d88dSmrg ctx->Shared->DefaultGeometryProgram); 1563464ebd5Sriastradh 1573464ebd5Sriastradh /* XXX probably move this stuff */ 1583464ebd5Sriastradh if (ctx->ATIFragmentShader.Current) { 1593464ebd5Sriastradh ctx->ATIFragmentShader.Current->RefCount--; 1603464ebd5Sriastradh if (ctx->ATIFragmentShader.Current->RefCount <= 0) { 1613464ebd5Sriastradh free(ctx->ATIFragmentShader.Current); 1623464ebd5Sriastradh } 1633464ebd5Sriastradh } 1643464ebd5Sriastradh ctx->ATIFragmentShader.Current = (struct ati_fragment_shader *) ctx->Shared->DefaultFragmentShader; 1653464ebd5Sriastradh assert(ctx->ATIFragmentShader.Current); 1663464ebd5Sriastradh ctx->ATIFragmentShader.Current->RefCount++; 1673464ebd5Sriastradh} 1683464ebd5Sriastradh 1693464ebd5Sriastradh 1703464ebd5Sriastradh/** 1713464ebd5Sriastradh * Set the vertex/fragment program error state (position and error string). 1723464ebd5Sriastradh * This is generally called from within the parsers. 1733464ebd5Sriastradh */ 1743464ebd5Sriastradhvoid 1753464ebd5Sriastradh_mesa_set_program_error(struct gl_context *ctx, GLint pos, const char *string) 1763464ebd5Sriastradh{ 1773464ebd5Sriastradh ctx->Program.ErrorPos = pos; 1783464ebd5Sriastradh free((void *) ctx->Program.ErrorString); 1793464ebd5Sriastradh if (!string) 1803464ebd5Sriastradh string = ""; 1813464ebd5Sriastradh ctx->Program.ErrorString = _mesa_strdup(string); 1823464ebd5Sriastradh} 1833464ebd5Sriastradh 1843464ebd5Sriastradh 1853464ebd5Sriastradh/** 1863464ebd5Sriastradh * Find the line number and column for 'pos' within 'string'. 1873464ebd5Sriastradh * Return a copy of the line which contains 'pos'. Free the line with 1883464ebd5Sriastradh * free(). 1893464ebd5Sriastradh * \param string the program string 1903464ebd5Sriastradh * \param pos the position within the string 1913464ebd5Sriastradh * \param line returns the line number corresponding to 'pos'. 1923464ebd5Sriastradh * \param col returns the column number corresponding to 'pos'. 1933464ebd5Sriastradh * \return copy of the line containing 'pos'. 1943464ebd5Sriastradh */ 1953464ebd5Sriastradhconst GLubyte * 1963464ebd5Sriastradh_mesa_find_line_column(const GLubyte *string, const GLubyte *pos, 1973464ebd5Sriastradh GLint *line, GLint *col) 1983464ebd5Sriastradh{ 1993464ebd5Sriastradh const GLubyte *lineStart = string; 2003464ebd5Sriastradh const GLubyte *p = string; 2013464ebd5Sriastradh GLubyte *s; 2023464ebd5Sriastradh int len; 2033464ebd5Sriastradh 2043464ebd5Sriastradh *line = 1; 2053464ebd5Sriastradh 2063464ebd5Sriastradh while (p != pos) { 2073464ebd5Sriastradh if (*p == (GLubyte) '\n') { 2083464ebd5Sriastradh (*line)++; 2093464ebd5Sriastradh lineStart = p + 1; 2103464ebd5Sriastradh } 2113464ebd5Sriastradh p++; 2123464ebd5Sriastradh } 2133464ebd5Sriastradh 2143464ebd5Sriastradh *col = (pos - lineStart) + 1; 2153464ebd5Sriastradh 2163464ebd5Sriastradh /* return copy of this line */ 2173464ebd5Sriastradh while (*p != 0 && *p != '\n') 2183464ebd5Sriastradh p++; 2193464ebd5Sriastradh len = p - lineStart; 220af69d88dSmrg s = malloc(len + 1); 2213464ebd5Sriastradh memcpy(s, lineStart, len); 2223464ebd5Sriastradh s[len] = 0; 2233464ebd5Sriastradh 2243464ebd5Sriastradh return s; 2253464ebd5Sriastradh} 2263464ebd5Sriastradh 2273464ebd5Sriastradh 2283464ebd5Sriastradh/** 229af69d88dSmrg * Initialize a new gl_program object. 2303464ebd5Sriastradh */ 231af69d88dSmrgstatic void 232af69d88dSmrginit_program_struct(struct gl_program *prog, GLenum target, GLuint id) 2333464ebd5Sriastradh{ 234af69d88dSmrg GLuint i; 2353464ebd5Sriastradh 236af69d88dSmrg assert(prog); 237af69d88dSmrg 238af69d88dSmrg memset(prog, 0, sizeof(*prog)); 239af69d88dSmrg prog->Id = id; 240af69d88dSmrg prog->Target = target; 241af69d88dSmrg prog->RefCount = 1; 242af69d88dSmrg prog->Format = GL_PROGRAM_FORMAT_ASCII_ARB; 243af69d88dSmrg 244af69d88dSmrg /* default mapping from samplers to texture units */ 245af69d88dSmrg for (i = 0; i < MAX_SAMPLERS; i++) 246af69d88dSmrg prog->SamplerUnits[i] = i; 2473464ebd5Sriastradh} 2483464ebd5Sriastradh 2493464ebd5Sriastradh 2503464ebd5Sriastradh/** 2513464ebd5Sriastradh * Initialize a new fragment program object. 2523464ebd5Sriastradh */ 2533464ebd5Sriastradhstruct gl_program * 254af69d88dSmrg_mesa_init_fragment_program(struct gl_context *ctx, 255af69d88dSmrg struct gl_fragment_program *prog, 256af69d88dSmrg GLenum target, GLuint id) 2573464ebd5Sriastradh{ 258af69d88dSmrg if (prog) { 259af69d88dSmrg init_program_struct(&prog->Base, target, id); 260af69d88dSmrg return &prog->Base; 261af69d88dSmrg } 262af69d88dSmrg return NULL; 2633464ebd5Sriastradh} 2643464ebd5Sriastradh 2653464ebd5Sriastradh 2663464ebd5Sriastradh/** 2673464ebd5Sriastradh * Initialize a new vertex program object. 2683464ebd5Sriastradh */ 2693464ebd5Sriastradhstruct gl_program * 270af69d88dSmrg_mesa_init_vertex_program(struct gl_context *ctx, 271af69d88dSmrg struct gl_vertex_program *prog, 272af69d88dSmrg GLenum target, GLuint id) 273af69d88dSmrg{ 274af69d88dSmrg if (prog) { 275af69d88dSmrg init_program_struct(&prog->Base, target, id); 276af69d88dSmrg return &prog->Base; 277af69d88dSmrg } 278af69d88dSmrg return NULL; 279af69d88dSmrg} 280af69d88dSmrg 281af69d88dSmrg 282af69d88dSmrg/** 283af69d88dSmrg * Initialize a new compute program object. 284af69d88dSmrg */ 285af69d88dSmrgstruct gl_program * 286af69d88dSmrg_mesa_init_compute_program(struct gl_context *ctx, 287af69d88dSmrg struct gl_compute_program *prog, 2883464ebd5Sriastradh GLenum target, GLuint id) 2893464ebd5Sriastradh{ 290af69d88dSmrg if (prog) { 291af69d88dSmrg init_program_struct(&prog->Base, target, id); 292af69d88dSmrg return &prog->Base; 293af69d88dSmrg } 294af69d88dSmrg return NULL; 2953464ebd5Sriastradh} 2963464ebd5Sriastradh 2973464ebd5Sriastradh 2983464ebd5Sriastradh/** 2993464ebd5Sriastradh * Initialize a new geometry program object. 3003464ebd5Sriastradh */ 3013464ebd5Sriastradhstruct gl_program * 302af69d88dSmrg_mesa_init_geometry_program(struct gl_context *ctx, 303af69d88dSmrg struct gl_geometry_program *prog, 304af69d88dSmrg GLenum target, GLuint id) 3053464ebd5Sriastradh{ 306af69d88dSmrg if (prog) { 307af69d88dSmrg init_program_struct(&prog->Base, target, id); 308af69d88dSmrg return &prog->Base; 309af69d88dSmrg } 310af69d88dSmrg return NULL; 3113464ebd5Sriastradh} 3123464ebd5Sriastradh 3133464ebd5Sriastradh 3143464ebd5Sriastradh/** 3153464ebd5Sriastradh * Allocate and initialize a new fragment/vertex program object but 3163464ebd5Sriastradh * don't put it into the program hash table. Called via 3173464ebd5Sriastradh * ctx->Driver.NewProgram. May be overridden (ie. replaced) by a 3183464ebd5Sriastradh * device driver function to implement OO deriviation with additional 3193464ebd5Sriastradh * types not understood by this function. 3203464ebd5Sriastradh * 3213464ebd5Sriastradh * \param ctx context 3223464ebd5Sriastradh * \param id program id/number 3233464ebd5Sriastradh * \param target program target/type 3243464ebd5Sriastradh * \return pointer to new program object 3253464ebd5Sriastradh */ 3263464ebd5Sriastradhstruct gl_program * 3273464ebd5Sriastradh_mesa_new_program(struct gl_context *ctx, GLenum target, GLuint id) 3283464ebd5Sriastradh{ 3293464ebd5Sriastradh struct gl_program *prog; 3303464ebd5Sriastradh switch (target) { 3313464ebd5Sriastradh case GL_VERTEX_PROGRAM_ARB: /* == GL_VERTEX_PROGRAM_NV */ 3323464ebd5Sriastradh prog = _mesa_init_vertex_program(ctx, CALLOC_STRUCT(gl_vertex_program), 3333464ebd5Sriastradh target, id ); 3343464ebd5Sriastradh break; 3353464ebd5Sriastradh case GL_FRAGMENT_PROGRAM_NV: 3363464ebd5Sriastradh case GL_FRAGMENT_PROGRAM_ARB: 3373464ebd5Sriastradh prog =_mesa_init_fragment_program(ctx, 3383464ebd5Sriastradh CALLOC_STRUCT(gl_fragment_program), 3393464ebd5Sriastradh target, id ); 3403464ebd5Sriastradh break; 3413464ebd5Sriastradh case MESA_GEOMETRY_PROGRAM: 3423464ebd5Sriastradh prog = _mesa_init_geometry_program(ctx, 3433464ebd5Sriastradh CALLOC_STRUCT(gl_geometry_program), 3443464ebd5Sriastradh target, id); 3453464ebd5Sriastradh break; 346af69d88dSmrg case GL_COMPUTE_PROGRAM_NV: 347af69d88dSmrg prog = _mesa_init_compute_program(ctx, 348af69d88dSmrg CALLOC_STRUCT(gl_compute_program), 349af69d88dSmrg target, id); 350af69d88dSmrg break; 3513464ebd5Sriastradh default: 3523464ebd5Sriastradh _mesa_problem(ctx, "bad target in _mesa_new_program"); 3533464ebd5Sriastradh prog = NULL; 3543464ebd5Sriastradh } 3553464ebd5Sriastradh return prog; 3563464ebd5Sriastradh} 3573464ebd5Sriastradh 3583464ebd5Sriastradh 3593464ebd5Sriastradh/** 3603464ebd5Sriastradh * Delete a program and remove it from the hash table, ignoring the 3613464ebd5Sriastradh * reference count. 3623464ebd5Sriastradh * Called via ctx->Driver.DeleteProgram. May be wrapped (OO deriviation) 3633464ebd5Sriastradh * by a device driver function. 3643464ebd5Sriastradh */ 3653464ebd5Sriastradhvoid 3663464ebd5Sriastradh_mesa_delete_program(struct gl_context *ctx, struct gl_program *prog) 3673464ebd5Sriastradh{ 3683464ebd5Sriastradh (void) ctx; 3693464ebd5Sriastradh ASSERT(prog); 3703464ebd5Sriastradh ASSERT(prog->RefCount==0); 3713464ebd5Sriastradh 3723464ebd5Sriastradh if (prog == &_mesa_DummyProgram) 3733464ebd5Sriastradh return; 3743464ebd5Sriastradh 375af69d88dSmrg free(prog->String); 376af69d88dSmrg free(prog->LocalParams); 3773464ebd5Sriastradh 378af69d88dSmrg if (prog->Instructions) { 379af69d88dSmrg _mesa_free_instructions(prog->Instructions, prog->NumInstructions); 380af69d88dSmrg } 3813464ebd5Sriastradh if (prog->Parameters) { 3823464ebd5Sriastradh _mesa_free_parameter_list(prog->Parameters); 3833464ebd5Sriastradh } 3843464ebd5Sriastradh 3853464ebd5Sriastradh free(prog); 3863464ebd5Sriastradh} 3873464ebd5Sriastradh 3883464ebd5Sriastradh 3893464ebd5Sriastradh/** 3903464ebd5Sriastradh * Return the gl_program object for a given ID. 3913464ebd5Sriastradh * Basically just a wrapper for _mesa_HashLookup() to avoid a lot of 3923464ebd5Sriastradh * casts elsewhere. 3933464ebd5Sriastradh */ 3943464ebd5Sriastradhstruct gl_program * 3953464ebd5Sriastradh_mesa_lookup_program(struct gl_context *ctx, GLuint id) 3963464ebd5Sriastradh{ 3973464ebd5Sriastradh if (id) 3983464ebd5Sriastradh return (struct gl_program *) _mesa_HashLookup(ctx->Shared->Programs, id); 3993464ebd5Sriastradh else 4003464ebd5Sriastradh return NULL; 4013464ebd5Sriastradh} 4023464ebd5Sriastradh 4033464ebd5Sriastradh 4043464ebd5Sriastradh/** 4053464ebd5Sriastradh * Reference counting for vertex/fragment programs 406af69d88dSmrg * This is normally only called from the _mesa_reference_program() macro 407af69d88dSmrg * when there's a real pointer change. 4083464ebd5Sriastradh */ 4093464ebd5Sriastradhvoid 410af69d88dSmrg_mesa_reference_program_(struct gl_context *ctx, 411af69d88dSmrg struct gl_program **ptr, 412af69d88dSmrg struct gl_program *prog) 4133464ebd5Sriastradh{ 414af69d88dSmrg#ifndef NDEBUG 4153464ebd5Sriastradh assert(ptr); 4163464ebd5Sriastradh if (*ptr && prog) { 4173464ebd5Sriastradh /* sanity check */ 4183464ebd5Sriastradh if ((*ptr)->Target == GL_VERTEX_PROGRAM_ARB) 4193464ebd5Sriastradh ASSERT(prog->Target == GL_VERTEX_PROGRAM_ARB); 4203464ebd5Sriastradh else if ((*ptr)->Target == GL_FRAGMENT_PROGRAM_ARB) 4213464ebd5Sriastradh ASSERT(prog->Target == GL_FRAGMENT_PROGRAM_ARB || 4223464ebd5Sriastradh prog->Target == GL_FRAGMENT_PROGRAM_NV); 4233464ebd5Sriastradh else if ((*ptr)->Target == MESA_GEOMETRY_PROGRAM) 4243464ebd5Sriastradh ASSERT(prog->Target == MESA_GEOMETRY_PROGRAM); 4253464ebd5Sriastradh } 426af69d88dSmrg#endif 427af69d88dSmrg 4283464ebd5Sriastradh if (*ptr) { 4293464ebd5Sriastradh GLboolean deleteFlag; 4303464ebd5Sriastradh 431af69d88dSmrg /*mtx_lock(&(*ptr)->Mutex);*/ 4323464ebd5Sriastradh#if 0 4333464ebd5Sriastradh printf("Program %p ID=%u Target=%s Refcount-- to %d\n", 4343464ebd5Sriastradh *ptr, (*ptr)->Id, 4353464ebd5Sriastradh ((*ptr)->Target == GL_VERTEX_PROGRAM_ARB ? "VP" : 4363464ebd5Sriastradh ((*ptr)->Target == MESA_GEOMETRY_PROGRAM ? "GP" : "FP")), 4373464ebd5Sriastradh (*ptr)->RefCount - 1); 4383464ebd5Sriastradh#endif 4393464ebd5Sriastradh ASSERT((*ptr)->RefCount > 0); 4403464ebd5Sriastradh (*ptr)->RefCount--; 4413464ebd5Sriastradh 4423464ebd5Sriastradh deleteFlag = ((*ptr)->RefCount == 0); 443af69d88dSmrg /*mtx_lock(&(*ptr)->Mutex);*/ 4443464ebd5Sriastradh 4453464ebd5Sriastradh if (deleteFlag) { 4463464ebd5Sriastradh ASSERT(ctx); 4473464ebd5Sriastradh ctx->Driver.DeleteProgram(ctx, *ptr); 4483464ebd5Sriastradh } 4493464ebd5Sriastradh 4503464ebd5Sriastradh *ptr = NULL; 4513464ebd5Sriastradh } 4523464ebd5Sriastradh 4533464ebd5Sriastradh assert(!*ptr); 4543464ebd5Sriastradh if (prog) { 455af69d88dSmrg /*mtx_lock(&prog->Mutex);*/ 4563464ebd5Sriastradh prog->RefCount++; 4573464ebd5Sriastradh#if 0 4583464ebd5Sriastradh printf("Program %p ID=%u Target=%s Refcount++ to %d\n", 4593464ebd5Sriastradh prog, prog->Id, 4603464ebd5Sriastradh (prog->Target == GL_VERTEX_PROGRAM_ARB ? "VP" : 4613464ebd5Sriastradh (prog->Target == MESA_GEOMETRY_PROGRAM ? "GP" : "FP")), 4623464ebd5Sriastradh prog->RefCount); 4633464ebd5Sriastradh#endif 464af69d88dSmrg /*mtx_unlock(&prog->Mutex);*/ 4653464ebd5Sriastradh } 4663464ebd5Sriastradh 4673464ebd5Sriastradh *ptr = prog; 4683464ebd5Sriastradh} 4693464ebd5Sriastradh 4703464ebd5Sriastradh 4713464ebd5Sriastradh/** 4723464ebd5Sriastradh * Return a copy of a program. 4733464ebd5Sriastradh * XXX Problem here if the program object is actually OO-derivation 4743464ebd5Sriastradh * made by a device driver. 4753464ebd5Sriastradh */ 4763464ebd5Sriastradhstruct gl_program * 4773464ebd5Sriastradh_mesa_clone_program(struct gl_context *ctx, const struct gl_program *prog) 4783464ebd5Sriastradh{ 4793464ebd5Sriastradh struct gl_program *clone; 4803464ebd5Sriastradh 4813464ebd5Sriastradh clone = ctx->Driver.NewProgram(ctx, prog->Target, prog->Id); 4823464ebd5Sriastradh if (!clone) 4833464ebd5Sriastradh return NULL; 4843464ebd5Sriastradh 4853464ebd5Sriastradh assert(clone->Target == prog->Target); 4863464ebd5Sriastradh assert(clone->RefCount == 1); 4873464ebd5Sriastradh 4883464ebd5Sriastradh clone->String = (GLubyte *) _mesa_strdup((char *) prog->String); 4893464ebd5Sriastradh clone->Format = prog->Format; 4903464ebd5Sriastradh clone->Instructions = _mesa_alloc_instructions(prog->NumInstructions); 4913464ebd5Sriastradh if (!clone->Instructions) { 4923464ebd5Sriastradh _mesa_reference_program(ctx, &clone, NULL); 4933464ebd5Sriastradh return NULL; 4943464ebd5Sriastradh } 4953464ebd5Sriastradh _mesa_copy_instructions(clone->Instructions, prog->Instructions, 4963464ebd5Sriastradh prog->NumInstructions); 4973464ebd5Sriastradh clone->InputsRead = prog->InputsRead; 4983464ebd5Sriastradh clone->OutputsWritten = prog->OutputsWritten; 4993464ebd5Sriastradh clone->SamplersUsed = prog->SamplersUsed; 5003464ebd5Sriastradh clone->ShadowSamplers = prog->ShadowSamplers; 5013464ebd5Sriastradh memcpy(clone->TexturesUsed, prog->TexturesUsed, sizeof(prog->TexturesUsed)); 5023464ebd5Sriastradh 5033464ebd5Sriastradh if (prog->Parameters) 5043464ebd5Sriastradh clone->Parameters = _mesa_clone_parameter_list(prog->Parameters); 505af69d88dSmrg if (prog->LocalParams) { 506af69d88dSmrg clone->LocalParams = malloc(MAX_PROGRAM_LOCAL_PARAMS * 507af69d88dSmrg sizeof(float[4])); 508af69d88dSmrg if (!clone->LocalParams) { 509af69d88dSmrg _mesa_reference_program(ctx, &clone, NULL); 510af69d88dSmrg return NULL; 511af69d88dSmrg } 512af69d88dSmrg memcpy(clone->LocalParams, prog->LocalParams, 513af69d88dSmrg MAX_PROGRAM_LOCAL_PARAMS * sizeof(float[4])); 514af69d88dSmrg } 5153464ebd5Sriastradh clone->IndirectRegisterFiles = prog->IndirectRegisterFiles; 5163464ebd5Sriastradh clone->NumInstructions = prog->NumInstructions; 5173464ebd5Sriastradh clone->NumTemporaries = prog->NumTemporaries; 5183464ebd5Sriastradh clone->NumParameters = prog->NumParameters; 5193464ebd5Sriastradh clone->NumAttributes = prog->NumAttributes; 5203464ebd5Sriastradh clone->NumAddressRegs = prog->NumAddressRegs; 5213464ebd5Sriastradh clone->NumNativeInstructions = prog->NumNativeInstructions; 5223464ebd5Sriastradh clone->NumNativeTemporaries = prog->NumNativeTemporaries; 5233464ebd5Sriastradh clone->NumNativeParameters = prog->NumNativeParameters; 5243464ebd5Sriastradh clone->NumNativeAttributes = prog->NumNativeAttributes; 5253464ebd5Sriastradh clone->NumNativeAddressRegs = prog->NumNativeAddressRegs; 5263464ebd5Sriastradh clone->NumAluInstructions = prog->NumAluInstructions; 5273464ebd5Sriastradh clone->NumTexInstructions = prog->NumTexInstructions; 5283464ebd5Sriastradh clone->NumTexIndirections = prog->NumTexIndirections; 5293464ebd5Sriastradh clone->NumNativeAluInstructions = prog->NumNativeAluInstructions; 5303464ebd5Sriastradh clone->NumNativeTexInstructions = prog->NumNativeTexInstructions; 5313464ebd5Sriastradh clone->NumNativeTexIndirections = prog->NumNativeTexIndirections; 5323464ebd5Sriastradh 5333464ebd5Sriastradh switch (prog->Target) { 5343464ebd5Sriastradh case GL_VERTEX_PROGRAM_ARB: 5353464ebd5Sriastradh { 536af69d88dSmrg const struct gl_vertex_program *vp = gl_vertex_program_const(prog); 537af69d88dSmrg struct gl_vertex_program *vpc = gl_vertex_program(clone); 5383464ebd5Sriastradh vpc->IsPositionInvariant = vp->IsPositionInvariant; 5393464ebd5Sriastradh } 5403464ebd5Sriastradh break; 5413464ebd5Sriastradh case GL_FRAGMENT_PROGRAM_ARB: 5423464ebd5Sriastradh { 543af69d88dSmrg const struct gl_fragment_program *fp = gl_fragment_program_const(prog); 544af69d88dSmrg struct gl_fragment_program *fpc = gl_fragment_program(clone); 5453464ebd5Sriastradh fpc->UsesKill = fp->UsesKill; 546af69d88dSmrg fpc->UsesDFdy = fp->UsesDFdy; 5473464ebd5Sriastradh fpc->OriginUpperLeft = fp->OriginUpperLeft; 5483464ebd5Sriastradh fpc->PixelCenterInteger = fp->PixelCenterInteger; 5493464ebd5Sriastradh } 5503464ebd5Sriastradh break; 5513464ebd5Sriastradh case MESA_GEOMETRY_PROGRAM: 5523464ebd5Sriastradh { 553af69d88dSmrg const struct gl_geometry_program *gp = gl_geometry_program_const(prog); 554af69d88dSmrg struct gl_geometry_program *gpc = gl_geometry_program(clone); 5553464ebd5Sriastradh gpc->VerticesOut = gp->VerticesOut; 5563464ebd5Sriastradh gpc->InputType = gp->InputType; 557af69d88dSmrg gpc->Invocations = gp->Invocations; 5583464ebd5Sriastradh gpc->OutputType = gp->OutputType; 559af69d88dSmrg gpc->UsesEndPrimitive = gp->UsesEndPrimitive; 560af69d88dSmrg gpc->UsesStreams = gp->UsesStreams; 5613464ebd5Sriastradh } 5623464ebd5Sriastradh break; 5633464ebd5Sriastradh default: 5643464ebd5Sriastradh _mesa_problem(NULL, "Unexpected target in _mesa_clone_program"); 5653464ebd5Sriastradh } 5663464ebd5Sriastradh 5673464ebd5Sriastradh return clone; 5683464ebd5Sriastradh} 5693464ebd5Sriastradh 5703464ebd5Sriastradh 5713464ebd5Sriastradh/** 5723464ebd5Sriastradh * Insert 'count' NOP instructions at 'start' in the given program. 5733464ebd5Sriastradh * Adjust branch targets accordingly. 5743464ebd5Sriastradh */ 5753464ebd5SriastradhGLboolean 5763464ebd5Sriastradh_mesa_insert_instructions(struct gl_program *prog, GLuint start, GLuint count) 5773464ebd5Sriastradh{ 5783464ebd5Sriastradh const GLuint origLen = prog->NumInstructions; 5793464ebd5Sriastradh const GLuint newLen = origLen + count; 5803464ebd5Sriastradh struct prog_instruction *newInst; 5813464ebd5Sriastradh GLuint i; 5823464ebd5Sriastradh 5833464ebd5Sriastradh /* adjust branches */ 5843464ebd5Sriastradh for (i = 0; i < prog->NumInstructions; i++) { 5853464ebd5Sriastradh struct prog_instruction *inst = prog->Instructions + i; 5863464ebd5Sriastradh if (inst->BranchTarget > 0) { 5873464ebd5Sriastradh if ((GLuint)inst->BranchTarget >= start) { 5883464ebd5Sriastradh inst->BranchTarget += count; 5893464ebd5Sriastradh } 5903464ebd5Sriastradh } 5913464ebd5Sriastradh } 5923464ebd5Sriastradh 5933464ebd5Sriastradh /* Alloc storage for new instructions */ 5943464ebd5Sriastradh newInst = _mesa_alloc_instructions(newLen); 5953464ebd5Sriastradh if (!newInst) { 5963464ebd5Sriastradh return GL_FALSE; 5973464ebd5Sriastradh } 5983464ebd5Sriastradh 5993464ebd5Sriastradh /* Copy 'start' instructions into new instruction buffer */ 6003464ebd5Sriastradh _mesa_copy_instructions(newInst, prog->Instructions, start); 6013464ebd5Sriastradh 6023464ebd5Sriastradh /* init the new instructions */ 6033464ebd5Sriastradh _mesa_init_instructions(newInst + start, count); 6043464ebd5Sriastradh 6053464ebd5Sriastradh /* Copy the remaining/tail instructions to new inst buffer */ 6063464ebd5Sriastradh _mesa_copy_instructions(newInst + start + count, 6073464ebd5Sriastradh prog->Instructions + start, 6083464ebd5Sriastradh origLen - start); 6093464ebd5Sriastradh 6103464ebd5Sriastradh /* free old instructions */ 6113464ebd5Sriastradh _mesa_free_instructions(prog->Instructions, origLen); 6123464ebd5Sriastradh 6133464ebd5Sriastradh /* install new instructions */ 6143464ebd5Sriastradh prog->Instructions = newInst; 6153464ebd5Sriastradh prog->NumInstructions = newLen; 6163464ebd5Sriastradh 6173464ebd5Sriastradh return GL_TRUE; 6183464ebd5Sriastradh} 6193464ebd5Sriastradh 6203464ebd5Sriastradh/** 6213464ebd5Sriastradh * Delete 'count' instructions at 'start' in the given program. 6223464ebd5Sriastradh * Adjust branch targets accordingly. 6233464ebd5Sriastradh */ 6243464ebd5SriastradhGLboolean 6253464ebd5Sriastradh_mesa_delete_instructions(struct gl_program *prog, GLuint start, GLuint count) 6263464ebd5Sriastradh{ 6273464ebd5Sriastradh const GLuint origLen = prog->NumInstructions; 6283464ebd5Sriastradh const GLuint newLen = origLen - count; 6293464ebd5Sriastradh struct prog_instruction *newInst; 6303464ebd5Sriastradh GLuint i; 6313464ebd5Sriastradh 6323464ebd5Sriastradh /* adjust branches */ 6333464ebd5Sriastradh for (i = 0; i < prog->NumInstructions; i++) { 6343464ebd5Sriastradh struct prog_instruction *inst = prog->Instructions + i; 6353464ebd5Sriastradh if (inst->BranchTarget > 0) { 6363464ebd5Sriastradh if (inst->BranchTarget > (GLint) start) { 6373464ebd5Sriastradh inst->BranchTarget -= count; 6383464ebd5Sriastradh } 6393464ebd5Sriastradh } 6403464ebd5Sriastradh } 6413464ebd5Sriastradh 6423464ebd5Sriastradh /* Alloc storage for new instructions */ 6433464ebd5Sriastradh newInst = _mesa_alloc_instructions(newLen); 6443464ebd5Sriastradh if (!newInst) { 6453464ebd5Sriastradh return GL_FALSE; 6463464ebd5Sriastradh } 6473464ebd5Sriastradh 6483464ebd5Sriastradh /* Copy 'start' instructions into new instruction buffer */ 6493464ebd5Sriastradh _mesa_copy_instructions(newInst, prog->Instructions, start); 6503464ebd5Sriastradh 6513464ebd5Sriastradh /* Copy the remaining/tail instructions to new inst buffer */ 6523464ebd5Sriastradh _mesa_copy_instructions(newInst + start, 6533464ebd5Sriastradh prog->Instructions + start + count, 6543464ebd5Sriastradh newLen - start); 6553464ebd5Sriastradh 6563464ebd5Sriastradh /* free old instructions */ 6573464ebd5Sriastradh _mesa_free_instructions(prog->Instructions, origLen); 6583464ebd5Sriastradh 6593464ebd5Sriastradh /* install new instructions */ 6603464ebd5Sriastradh prog->Instructions = newInst; 6613464ebd5Sriastradh prog->NumInstructions = newLen; 6623464ebd5Sriastradh 6633464ebd5Sriastradh return GL_TRUE; 6643464ebd5Sriastradh} 6653464ebd5Sriastradh 6663464ebd5Sriastradh 6673464ebd5Sriastradh/** 6683464ebd5Sriastradh * Search instructions for registers that match (oldFile, oldIndex), 6693464ebd5Sriastradh * replacing them with (newFile, newIndex). 6703464ebd5Sriastradh */ 6713464ebd5Sriastradhstatic void 6723464ebd5Sriastradhreplace_registers(struct prog_instruction *inst, GLuint numInst, 6733464ebd5Sriastradh GLuint oldFile, GLuint oldIndex, 6743464ebd5Sriastradh GLuint newFile, GLuint newIndex) 6753464ebd5Sriastradh{ 6763464ebd5Sriastradh GLuint i, j; 6773464ebd5Sriastradh for (i = 0; i < numInst; i++) { 6783464ebd5Sriastradh /* src regs */ 6793464ebd5Sriastradh for (j = 0; j < _mesa_num_inst_src_regs(inst[i].Opcode); j++) { 6803464ebd5Sriastradh if (inst[i].SrcReg[j].File == oldFile && 6813464ebd5Sriastradh inst[i].SrcReg[j].Index == oldIndex) { 6823464ebd5Sriastradh inst[i].SrcReg[j].File = newFile; 6833464ebd5Sriastradh inst[i].SrcReg[j].Index = newIndex; 6843464ebd5Sriastradh } 6853464ebd5Sriastradh } 6863464ebd5Sriastradh /* dst reg */ 6873464ebd5Sriastradh if (inst[i].DstReg.File == oldFile && inst[i].DstReg.Index == oldIndex) { 6883464ebd5Sriastradh inst[i].DstReg.File = newFile; 6893464ebd5Sriastradh inst[i].DstReg.Index = newIndex; 6903464ebd5Sriastradh } 6913464ebd5Sriastradh } 6923464ebd5Sriastradh} 6933464ebd5Sriastradh 6943464ebd5Sriastradh 6953464ebd5Sriastradh/** 6963464ebd5Sriastradh * Search instructions for references to program parameters. When found, 6973464ebd5Sriastradh * increment the parameter index by 'offset'. 6983464ebd5Sriastradh * Used when combining programs. 6993464ebd5Sriastradh */ 7003464ebd5Sriastradhstatic void 7013464ebd5Sriastradhadjust_param_indexes(struct prog_instruction *inst, GLuint numInst, 7023464ebd5Sriastradh GLuint offset) 7033464ebd5Sriastradh{ 7043464ebd5Sriastradh GLuint i, j; 7053464ebd5Sriastradh for (i = 0; i < numInst; i++) { 7063464ebd5Sriastradh for (j = 0; j < _mesa_num_inst_src_regs(inst[i].Opcode); j++) { 7073464ebd5Sriastradh GLuint f = inst[i].SrcReg[j].File; 7083464ebd5Sriastradh if (f == PROGRAM_CONSTANT || 7093464ebd5Sriastradh f == PROGRAM_UNIFORM || 7103464ebd5Sriastradh f == PROGRAM_STATE_VAR) { 7113464ebd5Sriastradh inst[i].SrcReg[j].Index += offset; 7123464ebd5Sriastradh } 7133464ebd5Sriastradh } 7143464ebd5Sriastradh } 7153464ebd5Sriastradh} 7163464ebd5Sriastradh 7173464ebd5Sriastradh 7183464ebd5Sriastradh/** 7193464ebd5Sriastradh * Combine two programs into one. Fix instructions so the outputs of 7203464ebd5Sriastradh * the first program go to the inputs of the second program. 7213464ebd5Sriastradh */ 7223464ebd5Sriastradhstruct gl_program * 7233464ebd5Sriastradh_mesa_combine_programs(struct gl_context *ctx, 7243464ebd5Sriastradh const struct gl_program *progA, 7253464ebd5Sriastradh const struct gl_program *progB) 7263464ebd5Sriastradh{ 7273464ebd5Sriastradh struct prog_instruction *newInst; 7283464ebd5Sriastradh struct gl_program *newProg; 7293464ebd5Sriastradh const GLuint lenA = progA->NumInstructions - 1; /* omit END instr */ 7303464ebd5Sriastradh const GLuint lenB = progB->NumInstructions; 7313464ebd5Sriastradh const GLuint numParamsA = _mesa_num_parameters(progA->Parameters); 7323464ebd5Sriastradh const GLuint newLength = lenA + lenB; 7333464ebd5Sriastradh GLboolean usedTemps[MAX_PROGRAM_TEMPS]; 7343464ebd5Sriastradh GLuint firstTemp = 0; 735af69d88dSmrg GLbitfield64 inputsB; 7363464ebd5Sriastradh GLuint i; 7373464ebd5Sriastradh 7383464ebd5Sriastradh ASSERT(progA->Target == progB->Target); 7393464ebd5Sriastradh 7403464ebd5Sriastradh newInst = _mesa_alloc_instructions(newLength); 7413464ebd5Sriastradh if (!newInst) 7423464ebd5Sriastradh return GL_FALSE; 7433464ebd5Sriastradh 7443464ebd5Sriastradh _mesa_copy_instructions(newInst, progA->Instructions, lenA); 7453464ebd5Sriastradh _mesa_copy_instructions(newInst + lenA, progB->Instructions, lenB); 7463464ebd5Sriastradh 7473464ebd5Sriastradh /* adjust branch / instruction addresses for B's instructions */ 7483464ebd5Sriastradh for (i = 0; i < lenB; i++) { 7493464ebd5Sriastradh newInst[lenA + i].BranchTarget += lenA; 7503464ebd5Sriastradh } 7513464ebd5Sriastradh 7523464ebd5Sriastradh newProg = ctx->Driver.NewProgram(ctx, progA->Target, 0); 7533464ebd5Sriastradh newProg->Instructions = newInst; 7543464ebd5Sriastradh newProg->NumInstructions = newLength; 7553464ebd5Sriastradh 7563464ebd5Sriastradh /* find used temp regs (we may need new temps below) */ 7573464ebd5Sriastradh _mesa_find_used_registers(newProg, PROGRAM_TEMPORARY, 7583464ebd5Sriastradh usedTemps, MAX_PROGRAM_TEMPS); 7593464ebd5Sriastradh 7603464ebd5Sriastradh if (newProg->Target == GL_FRAGMENT_PROGRAM_ARB) { 761af69d88dSmrg const struct gl_fragment_program *fprogA, *fprogB; 762af69d88dSmrg struct gl_fragment_program *newFprog; 763af69d88dSmrg GLbitfield64 progB_inputsRead = progB->InputsRead; 7643464ebd5Sriastradh GLint progB_colorFile, progB_colorIndex; 7653464ebd5Sriastradh 766af69d88dSmrg fprogA = gl_fragment_program_const(progA); 767af69d88dSmrg fprogB = gl_fragment_program_const(progB); 768af69d88dSmrg newFprog = gl_fragment_program(newProg); 7693464ebd5Sriastradh 7703464ebd5Sriastradh newFprog->UsesKill = fprogA->UsesKill || fprogB->UsesKill; 771af69d88dSmrg newFprog->UsesDFdy = fprogA->UsesDFdy || fprogB->UsesDFdy; 7723464ebd5Sriastradh 7733464ebd5Sriastradh /* We'll do a search and replace for instances 7743464ebd5Sriastradh * of progB_colorFile/progB_colorIndex below... 7753464ebd5Sriastradh */ 7763464ebd5Sriastradh progB_colorFile = PROGRAM_INPUT; 777af69d88dSmrg progB_colorIndex = VARYING_SLOT_COL0; 7783464ebd5Sriastradh 7793464ebd5Sriastradh /* 7803464ebd5Sriastradh * The fragment program may get color from a state var rather than 7813464ebd5Sriastradh * a fragment input (vertex output) if it's constant. 7823464ebd5Sriastradh * See the texenvprogram.c code. 7833464ebd5Sriastradh * So, search the program's parameter list now to see if the program 7843464ebd5Sriastradh * gets color from a state var instead of a conventional fragment 7853464ebd5Sriastradh * input register. 7863464ebd5Sriastradh */ 7873464ebd5Sriastradh for (i = 0; i < progB->Parameters->NumParameters; i++) { 7883464ebd5Sriastradh struct gl_program_parameter *p = &progB->Parameters->Parameters[i]; 7893464ebd5Sriastradh if (p->Type == PROGRAM_STATE_VAR && 7903464ebd5Sriastradh p->StateIndexes[0] == STATE_INTERNAL && 7913464ebd5Sriastradh p->StateIndexes[1] == STATE_CURRENT_ATTRIB && 7923464ebd5Sriastradh (int) p->StateIndexes[2] == (int) VERT_ATTRIB_COLOR0) { 793af69d88dSmrg progB_inputsRead |= VARYING_BIT_COL0; 7943464ebd5Sriastradh progB_colorFile = PROGRAM_STATE_VAR; 7953464ebd5Sriastradh progB_colorIndex = i; 7963464ebd5Sriastradh break; 7973464ebd5Sriastradh } 7983464ebd5Sriastradh } 7993464ebd5Sriastradh 8003464ebd5Sriastradh /* Connect color outputs of fprogA to color inputs of fprogB, via a 8013464ebd5Sriastradh * new temporary register. 8023464ebd5Sriastradh */ 8033464ebd5Sriastradh if ((progA->OutputsWritten & BITFIELD64_BIT(FRAG_RESULT_COLOR)) && 804af69d88dSmrg (progB_inputsRead & VARYING_BIT_COL0)) { 8053464ebd5Sriastradh GLint tempReg = _mesa_find_free_register(usedTemps, MAX_PROGRAM_TEMPS, 8063464ebd5Sriastradh firstTemp); 8073464ebd5Sriastradh if (tempReg < 0) { 8083464ebd5Sriastradh _mesa_problem(ctx, "No free temp regs found in " 8093464ebd5Sriastradh "_mesa_combine_programs(), using 31"); 8103464ebd5Sriastradh tempReg = 31; 8113464ebd5Sriastradh } 8123464ebd5Sriastradh firstTemp = tempReg + 1; 8133464ebd5Sriastradh 8143464ebd5Sriastradh /* replace writes to result.color[0] with tempReg */ 8153464ebd5Sriastradh replace_registers(newInst, lenA, 8163464ebd5Sriastradh PROGRAM_OUTPUT, FRAG_RESULT_COLOR, 8173464ebd5Sriastradh PROGRAM_TEMPORARY, tempReg); 8183464ebd5Sriastradh /* replace reads from the input color with tempReg */ 8193464ebd5Sriastradh replace_registers(newInst + lenA, lenB, 8203464ebd5Sriastradh progB_colorFile, progB_colorIndex, /* search for */ 8213464ebd5Sriastradh PROGRAM_TEMPORARY, tempReg /* replace with */ ); 8223464ebd5Sriastradh } 8233464ebd5Sriastradh 8243464ebd5Sriastradh /* compute combined program's InputsRead */ 8253464ebd5Sriastradh inputsB = progB_inputsRead; 8263464ebd5Sriastradh if (progA->OutputsWritten & BITFIELD64_BIT(FRAG_RESULT_COLOR)) { 827af69d88dSmrg inputsB &= ~(1 << VARYING_SLOT_COL0); 8283464ebd5Sriastradh } 8293464ebd5Sriastradh newProg->InputsRead = progA->InputsRead | inputsB; 8303464ebd5Sriastradh newProg->OutputsWritten = progB->OutputsWritten; 8313464ebd5Sriastradh newProg->SamplersUsed = progA->SamplersUsed | progB->SamplersUsed; 8323464ebd5Sriastradh } 8333464ebd5Sriastradh else { 8343464ebd5Sriastradh /* vertex program */ 8353464ebd5Sriastradh assert(0); /* XXX todo */ 8363464ebd5Sriastradh } 8373464ebd5Sriastradh 8383464ebd5Sriastradh /* 8393464ebd5Sriastradh * Merge parameters (uniforms, constants, etc) 8403464ebd5Sriastradh */ 8413464ebd5Sriastradh newProg->Parameters = _mesa_combine_parameter_lists(progA->Parameters, 8423464ebd5Sriastradh progB->Parameters); 8433464ebd5Sriastradh 8443464ebd5Sriastradh adjust_param_indexes(newInst + lenA, lenB, numParamsA); 8453464ebd5Sriastradh 8463464ebd5Sriastradh 8473464ebd5Sriastradh return newProg; 8483464ebd5Sriastradh} 8493464ebd5Sriastradh 8503464ebd5Sriastradh 8513464ebd5Sriastradh/** 8523464ebd5Sriastradh * Populate the 'used' array with flags indicating which registers (TEMPs, 8533464ebd5Sriastradh * INPUTs, OUTPUTs, etc, are used by the given program. 8543464ebd5Sriastradh * \param file type of register to scan for 8553464ebd5Sriastradh * \param used returns true/false flags for in use / free 8563464ebd5Sriastradh * \param usedSize size of the 'used' array 8573464ebd5Sriastradh */ 8583464ebd5Sriastradhvoid 8593464ebd5Sriastradh_mesa_find_used_registers(const struct gl_program *prog, 8603464ebd5Sriastradh gl_register_file file, 8613464ebd5Sriastradh GLboolean used[], GLuint usedSize) 8623464ebd5Sriastradh{ 8633464ebd5Sriastradh GLuint i, j; 8643464ebd5Sriastradh 8653464ebd5Sriastradh memset(used, 0, usedSize); 8663464ebd5Sriastradh 8673464ebd5Sriastradh for (i = 0; i < prog->NumInstructions; i++) { 8683464ebd5Sriastradh const struct prog_instruction *inst = prog->Instructions + i; 8693464ebd5Sriastradh const GLuint n = _mesa_num_inst_src_regs(inst->Opcode); 8703464ebd5Sriastradh 8713464ebd5Sriastradh if (inst->DstReg.File == file) { 8723464ebd5Sriastradh ASSERT(inst->DstReg.Index < usedSize); 8733464ebd5Sriastradh if(inst->DstReg.Index < usedSize) 8743464ebd5Sriastradh used[inst->DstReg.Index] = GL_TRUE; 8753464ebd5Sriastradh } 8763464ebd5Sriastradh 8773464ebd5Sriastradh for (j = 0; j < n; j++) { 8783464ebd5Sriastradh if (inst->SrcReg[j].File == file) { 879af69d88dSmrg ASSERT(inst->SrcReg[j].Index < (GLint) usedSize); 880af69d88dSmrg if (inst->SrcReg[j].Index < (GLint) usedSize) 8813464ebd5Sriastradh used[inst->SrcReg[j].Index] = GL_TRUE; 8823464ebd5Sriastradh } 8833464ebd5Sriastradh } 8843464ebd5Sriastradh } 8853464ebd5Sriastradh} 8863464ebd5Sriastradh 8873464ebd5Sriastradh 8883464ebd5Sriastradh/** 8893464ebd5Sriastradh * Scan the given 'used' register flag array for the first entry 8903464ebd5Sriastradh * that's >= firstReg. 8913464ebd5Sriastradh * \param used vector of flags indicating registers in use (as returned 8923464ebd5Sriastradh * by _mesa_find_used_registers()) 8933464ebd5Sriastradh * \param usedSize size of the 'used' array 8943464ebd5Sriastradh * \param firstReg first register to start searching at 8953464ebd5Sriastradh * \return index of unused register, or -1 if none. 8963464ebd5Sriastradh */ 8973464ebd5SriastradhGLint 8983464ebd5Sriastradh_mesa_find_free_register(const GLboolean used[], 8993464ebd5Sriastradh GLuint usedSize, GLuint firstReg) 9003464ebd5Sriastradh{ 9013464ebd5Sriastradh GLuint i; 9023464ebd5Sriastradh 9033464ebd5Sriastradh assert(firstReg < usedSize); 9043464ebd5Sriastradh 9053464ebd5Sriastradh for (i = firstReg; i < usedSize; i++) 9063464ebd5Sriastradh if (!used[i]) 9073464ebd5Sriastradh return i; 9083464ebd5Sriastradh 9093464ebd5Sriastradh return -1; 9103464ebd5Sriastradh} 9113464ebd5Sriastradh 9123464ebd5Sriastradh 9133464ebd5Sriastradh 9143464ebd5Sriastradh/** 9153464ebd5Sriastradh * Check if the given register index is valid (doesn't exceed implementation- 9163464ebd5Sriastradh * dependent limits). 9173464ebd5Sriastradh * \return GL_TRUE if OK, GL_FALSE if bad index 9183464ebd5Sriastradh */ 9193464ebd5SriastradhGLboolean 9203464ebd5Sriastradh_mesa_valid_register_index(const struct gl_context *ctx, 921af69d88dSmrg gl_shader_stage shaderType, 9223464ebd5Sriastradh gl_register_file file, GLint index) 9233464ebd5Sriastradh{ 9243464ebd5Sriastradh const struct gl_program_constants *c; 9253464ebd5Sriastradh 926af69d88dSmrg assert(0 <= shaderType && shaderType < MESA_SHADER_STAGES); 927af69d88dSmrg c = &ctx->Const.Program[shaderType]; 9283464ebd5Sriastradh 9293464ebd5Sriastradh switch (file) { 9303464ebd5Sriastradh case PROGRAM_UNDEFINED: 9313464ebd5Sriastradh return GL_TRUE; /* XXX or maybe false? */ 9323464ebd5Sriastradh 9333464ebd5Sriastradh case PROGRAM_TEMPORARY: 934af69d88dSmrg return index >= 0 && index < (GLint) c->MaxTemps; 9353464ebd5Sriastradh 9363464ebd5Sriastradh case PROGRAM_UNIFORM: 9373464ebd5Sriastradh case PROGRAM_STATE_VAR: 9383464ebd5Sriastradh /* aka constant buffer */ 939af69d88dSmrg return index >= 0 && index < (GLint) c->MaxUniformComponents / 4; 9403464ebd5Sriastradh 9413464ebd5Sriastradh case PROGRAM_CONSTANT: 9423464ebd5Sriastradh /* constant buffer w/ possible relative negative addressing */ 9433464ebd5Sriastradh return (index > (int) c->MaxUniformComponents / -4 && 944af69d88dSmrg index < (int) c->MaxUniformComponents / 4); 9453464ebd5Sriastradh 9463464ebd5Sriastradh case PROGRAM_INPUT: 9473464ebd5Sriastradh if (index < 0) 9483464ebd5Sriastradh return GL_FALSE; 9493464ebd5Sriastradh 9503464ebd5Sriastradh switch (shaderType) { 9513464ebd5Sriastradh case MESA_SHADER_VERTEX: 952af69d88dSmrg return index < VERT_ATTRIB_GENERIC0 + (GLint) c->MaxAttribs; 9533464ebd5Sriastradh case MESA_SHADER_FRAGMENT: 954af69d88dSmrg return index < VARYING_SLOT_VAR0 + (GLint) ctx->Const.MaxVarying; 9553464ebd5Sriastradh case MESA_SHADER_GEOMETRY: 956af69d88dSmrg return index < VARYING_SLOT_VAR0 + (GLint) ctx->Const.MaxVarying; 9573464ebd5Sriastradh default: 9583464ebd5Sriastradh return GL_FALSE; 9593464ebd5Sriastradh } 9603464ebd5Sriastradh 9613464ebd5Sriastradh case PROGRAM_OUTPUT: 9623464ebd5Sriastradh if (index < 0) 9633464ebd5Sriastradh return GL_FALSE; 9643464ebd5Sriastradh 9653464ebd5Sriastradh switch (shaderType) { 9663464ebd5Sriastradh case MESA_SHADER_VERTEX: 967af69d88dSmrg return index < VARYING_SLOT_VAR0 + (GLint) ctx->Const.MaxVarying; 9683464ebd5Sriastradh case MESA_SHADER_FRAGMENT: 969af69d88dSmrg return index < FRAG_RESULT_DATA0 + (GLint) ctx->Const.MaxDrawBuffers; 9703464ebd5Sriastradh case MESA_SHADER_GEOMETRY: 971af69d88dSmrg return index < VARYING_SLOT_VAR0 + (GLint) ctx->Const.MaxVarying; 9723464ebd5Sriastradh default: 9733464ebd5Sriastradh return GL_FALSE; 9743464ebd5Sriastradh } 9753464ebd5Sriastradh 9763464ebd5Sriastradh case PROGRAM_ADDRESS: 977af69d88dSmrg return index >= 0 && index < (GLint) c->MaxAddressRegs; 9783464ebd5Sriastradh 9793464ebd5Sriastradh default: 9803464ebd5Sriastradh _mesa_problem(ctx, 9813464ebd5Sriastradh "unexpected register file in _mesa_valid_register_index()"); 9823464ebd5Sriastradh return GL_FALSE; 9833464ebd5Sriastradh } 9843464ebd5Sriastradh} 9853464ebd5Sriastradh 9863464ebd5Sriastradh 9873464ebd5Sriastradh 9883464ebd5Sriastradh/** 9893464ebd5Sriastradh * "Post-process" a GPU program. This is intended to be used for debugging. 9903464ebd5Sriastradh * Example actions include no-op'ing instructions or changing instruction 9913464ebd5Sriastradh * behaviour. 9923464ebd5Sriastradh */ 9933464ebd5Sriastradhvoid 9943464ebd5Sriastradh_mesa_postprocess_program(struct gl_context *ctx, struct gl_program *prog) 9953464ebd5Sriastradh{ 9963464ebd5Sriastradh static const GLfloat white[4] = { 0.5, 0.5, 0.5, 0.5 }; 9973464ebd5Sriastradh GLuint i; 9983464ebd5Sriastradh GLuint whiteSwizzle; 9993464ebd5Sriastradh GLint whiteIndex = _mesa_add_unnamed_constant(prog->Parameters, 1000af69d88dSmrg (gl_constant_value *) white, 1001af69d88dSmrg 4, &whiteSwizzle); 10023464ebd5Sriastradh 10033464ebd5Sriastradh (void) whiteIndex; 10043464ebd5Sriastradh 10053464ebd5Sriastradh for (i = 0; i < prog->NumInstructions; i++) { 10063464ebd5Sriastradh struct prog_instruction *inst = prog->Instructions + i; 10073464ebd5Sriastradh const GLuint n = _mesa_num_inst_src_regs(inst->Opcode); 10083464ebd5Sriastradh 10093464ebd5Sriastradh (void) n; 10103464ebd5Sriastradh 10113464ebd5Sriastradh if (_mesa_is_tex_instruction(inst->Opcode)) { 10123464ebd5Sriastradh#if 0 10133464ebd5Sriastradh /* replace TEX/TXP/TXB with MOV */ 10143464ebd5Sriastradh inst->Opcode = OPCODE_MOV; 10153464ebd5Sriastradh inst->DstReg.WriteMask = WRITEMASK_XYZW; 10163464ebd5Sriastradh inst->SrcReg[0].Swizzle = SWIZZLE_XYZW; 10173464ebd5Sriastradh inst->SrcReg[0].Negate = NEGATE_NONE; 10183464ebd5Sriastradh#endif 10193464ebd5Sriastradh 10203464ebd5Sriastradh#if 0 10213464ebd5Sriastradh /* disable shadow texture mode */ 10223464ebd5Sriastradh inst->TexShadow = 0; 10233464ebd5Sriastradh#endif 10243464ebd5Sriastradh } 10253464ebd5Sriastradh 10263464ebd5Sriastradh if (inst->Opcode == OPCODE_TXP) { 10273464ebd5Sriastradh#if 0 10283464ebd5Sriastradh inst->Opcode = OPCODE_MOV; 10293464ebd5Sriastradh inst->DstReg.WriteMask = WRITEMASK_XYZW; 10303464ebd5Sriastradh inst->SrcReg[0].File = PROGRAM_CONSTANT; 10313464ebd5Sriastradh inst->SrcReg[0].Index = whiteIndex; 10323464ebd5Sriastradh inst->SrcReg[0].Swizzle = SWIZZLE_XYZW; 10333464ebd5Sriastradh inst->SrcReg[0].Negate = NEGATE_NONE; 10343464ebd5Sriastradh#endif 10353464ebd5Sriastradh#if 0 10363464ebd5Sriastradh inst->TexShadow = 0; 10373464ebd5Sriastradh#endif 10383464ebd5Sriastradh#if 0 10393464ebd5Sriastradh inst->Opcode = OPCODE_TEX; 10403464ebd5Sriastradh inst->TexShadow = 0; 10413464ebd5Sriastradh#endif 10423464ebd5Sriastradh } 10433464ebd5Sriastradh 10443464ebd5Sriastradh } 10453464ebd5Sriastradh} 1046af69d88dSmrg 1047af69d88dSmrg/* Gets the minimum number of shader invocations per fragment. 1048af69d88dSmrg * This function is useful to determine if we need to do per 1049af69d88dSmrg * sample shading or per fragment shading. 1050af69d88dSmrg */ 1051af69d88dSmrgGLint 1052af69d88dSmrg_mesa_get_min_invocations_per_fragment(struct gl_context *ctx, 1053af69d88dSmrg const struct gl_fragment_program *prog, 1054af69d88dSmrg bool ignore_sample_qualifier) 1055af69d88dSmrg{ 1056af69d88dSmrg /* From ARB_sample_shading specification: 1057af69d88dSmrg * "Using gl_SampleID in a fragment shader causes the entire shader 1058af69d88dSmrg * to be evaluated per-sample." 1059af69d88dSmrg * 1060af69d88dSmrg * "Using gl_SamplePosition in a fragment shader causes the entire 1061af69d88dSmrg * shader to be evaluated per-sample." 1062af69d88dSmrg * 1063af69d88dSmrg * "If MULTISAMPLE or SAMPLE_SHADING_ARB is disabled, sample shading 1064af69d88dSmrg * has no effect." 1065af69d88dSmrg */ 1066af69d88dSmrg if (ctx->Multisample.Enabled) { 1067af69d88dSmrg /* The ARB_gpu_shader5 specification says: 1068af69d88dSmrg * 1069af69d88dSmrg * "Use of the "sample" qualifier on a fragment shader input 1070af69d88dSmrg * forces per-sample shading" 1071af69d88dSmrg */ 1072af69d88dSmrg if (prog->IsSample && !ignore_sample_qualifier) 1073af69d88dSmrg return MAX2(ctx->DrawBuffer->Visual.samples, 1); 1074af69d88dSmrg 1075af69d88dSmrg if (prog->Base.SystemValuesRead & (SYSTEM_BIT_SAMPLE_ID | 1076af69d88dSmrg SYSTEM_BIT_SAMPLE_POS)) 1077af69d88dSmrg return MAX2(ctx->DrawBuffer->Visual.samples, 1); 1078af69d88dSmrg else if (ctx->Multisample.SampleShading) 1079af69d88dSmrg return MAX2(ceil(ctx->Multisample.MinSampleShadingValue * 1080af69d88dSmrg ctx->DrawBuffer->Visual.samples), 1); 1081af69d88dSmrg else 1082af69d88dSmrg return 1; 1083af69d88dSmrg } 1084af69d88dSmrg return 1; 1085af69d88dSmrg} 1086