program.c revision 848b8605
1848b8605Smrg/* 2848b8605Smrg * Mesa 3-D graphics library 3848b8605Smrg * 4848b8605Smrg * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. 5848b8605Smrg * 6848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a 7848b8605Smrg * copy of this software and associated documentation files (the "Software"), 8848b8605Smrg * to deal in the Software without restriction, including without limitation 9848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the 11848b8605Smrg * Software is furnished to do so, subject to the following conditions: 12848b8605Smrg * 13848b8605Smrg * The above copyright notice and this permission notice shall be included 14848b8605Smrg * in all copies or substantial portions of the Software. 15848b8605Smrg * 16848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19848b8605Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20848b8605Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21848b8605Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22848b8605Smrg * OTHER DEALINGS IN THE SOFTWARE. 23848b8605Smrg */ 24848b8605Smrg 25848b8605Smrg/** 26848b8605Smrg * \file program.c 27848b8605Smrg * Vertex and fragment program support functions. 28848b8605Smrg * \author Brian Paul 29848b8605Smrg */ 30848b8605Smrg 31848b8605Smrg 32848b8605Smrg#include "main/glheader.h" 33848b8605Smrg#include "main/context.h" 34848b8605Smrg#include "main/hash.h" 35848b8605Smrg#include "main/macros.h" 36848b8605Smrg#include "program.h" 37848b8605Smrg#include "prog_cache.h" 38848b8605Smrg#include "prog_parameter.h" 39848b8605Smrg#include "prog_instruction.h" 40848b8605Smrg 41848b8605Smrg 42848b8605Smrg/** 43848b8605Smrg * A pointer to this dummy program is put into the hash table when 44848b8605Smrg * glGenPrograms is called. 45848b8605Smrg */ 46848b8605Smrgstruct gl_program _mesa_DummyProgram; 47848b8605Smrg 48848b8605Smrg 49848b8605Smrg/** 50848b8605Smrg * Init context's vertex/fragment program state 51848b8605Smrg */ 52848b8605Smrgvoid 53848b8605Smrg_mesa_init_program(struct gl_context *ctx) 54848b8605Smrg{ 55848b8605Smrg /* 56848b8605Smrg * If this assertion fails, we need to increase the field 57848b8605Smrg * size for register indexes (see INST_INDEX_BITS). 58848b8605Smrg */ 59848b8605Smrg ASSERT(ctx->Const.Program[MESA_SHADER_VERTEX].MaxUniformComponents / 4 60848b8605Smrg <= (1 << INST_INDEX_BITS)); 61848b8605Smrg ASSERT(ctx->Const.Program[MESA_SHADER_FRAGMENT].MaxUniformComponents / 4 62848b8605Smrg <= (1 << INST_INDEX_BITS)); 63848b8605Smrg 64848b8605Smrg ASSERT(ctx->Const.Program[MESA_SHADER_VERTEX].MaxTemps <= (1 << INST_INDEX_BITS)); 65848b8605Smrg ASSERT(ctx->Const.Program[MESA_SHADER_VERTEX].MaxLocalParams <= (1 << INST_INDEX_BITS)); 66848b8605Smrg ASSERT(ctx->Const.Program[MESA_SHADER_FRAGMENT].MaxTemps <= (1 << INST_INDEX_BITS)); 67848b8605Smrg ASSERT(ctx->Const.Program[MESA_SHADER_FRAGMENT].MaxLocalParams <= (1 << INST_INDEX_BITS)); 68848b8605Smrg 69848b8605Smrg ASSERT(ctx->Const.Program[MESA_SHADER_VERTEX].MaxUniformComponents <= 4 * MAX_UNIFORMS); 70848b8605Smrg ASSERT(ctx->Const.Program[MESA_SHADER_FRAGMENT].MaxUniformComponents <= 4 * MAX_UNIFORMS); 71848b8605Smrg 72848b8605Smrg ASSERT(ctx->Const.Program[MESA_SHADER_VERTEX].MaxAddressOffset <= (1 << INST_INDEX_BITS)); 73848b8605Smrg ASSERT(ctx->Const.Program[MESA_SHADER_FRAGMENT].MaxAddressOffset <= (1 << INST_INDEX_BITS)); 74848b8605Smrg 75848b8605Smrg /* If this fails, increase prog_instruction::TexSrcUnit size */ 76848b8605Smrg STATIC_ASSERT(MAX_TEXTURE_UNITS <= (1 << 5)); 77848b8605Smrg 78848b8605Smrg /* If this fails, increase prog_instruction::TexSrcTarget size */ 79848b8605Smrg STATIC_ASSERT(NUM_TEXTURE_TARGETS <= (1 << 4)); 80848b8605Smrg 81848b8605Smrg ctx->Program.ErrorPos = -1; 82848b8605Smrg ctx->Program.ErrorString = _mesa_strdup(""); 83848b8605Smrg 84848b8605Smrg ctx->VertexProgram.Enabled = GL_FALSE; 85848b8605Smrg ctx->VertexProgram.PointSizeEnabled = 86848b8605Smrg (ctx->API == API_OPENGLES2) ? GL_TRUE : GL_FALSE; 87848b8605Smrg ctx->VertexProgram.TwoSideEnabled = GL_FALSE; 88848b8605Smrg _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current, 89848b8605Smrg ctx->Shared->DefaultVertexProgram); 90848b8605Smrg assert(ctx->VertexProgram.Current); 91848b8605Smrg ctx->VertexProgram.Cache = _mesa_new_program_cache(); 92848b8605Smrg 93848b8605Smrg ctx->FragmentProgram.Enabled = GL_FALSE; 94848b8605Smrg _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current, 95848b8605Smrg ctx->Shared->DefaultFragmentProgram); 96848b8605Smrg assert(ctx->FragmentProgram.Current); 97848b8605Smrg ctx->FragmentProgram.Cache = _mesa_new_program_cache(); 98848b8605Smrg 99848b8605Smrg ctx->GeometryProgram.Enabled = GL_FALSE; 100848b8605Smrg /* right now by default we don't have a geometry program */ 101848b8605Smrg _mesa_reference_geomprog(ctx, &ctx->GeometryProgram.Current, 102848b8605Smrg NULL); 103848b8605Smrg ctx->GeometryProgram.Cache = _mesa_new_program_cache(); 104848b8605Smrg 105848b8605Smrg /* XXX probably move this stuff */ 106848b8605Smrg ctx->ATIFragmentShader.Enabled = GL_FALSE; 107848b8605Smrg ctx->ATIFragmentShader.Current = ctx->Shared->DefaultFragmentShader; 108848b8605Smrg assert(ctx->ATIFragmentShader.Current); 109848b8605Smrg ctx->ATIFragmentShader.Current->RefCount++; 110848b8605Smrg} 111848b8605Smrg 112848b8605Smrg 113848b8605Smrg/** 114848b8605Smrg * Free a context's vertex/fragment program state 115848b8605Smrg */ 116848b8605Smrgvoid 117848b8605Smrg_mesa_free_program_data(struct gl_context *ctx) 118848b8605Smrg{ 119848b8605Smrg _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current, NULL); 120848b8605Smrg _mesa_delete_program_cache(ctx, ctx->VertexProgram.Cache); 121848b8605Smrg _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current, NULL); 122848b8605Smrg _mesa_delete_shader_cache(ctx, ctx->FragmentProgram.Cache); 123848b8605Smrg _mesa_reference_geomprog(ctx, &ctx->GeometryProgram.Current, NULL); 124848b8605Smrg _mesa_delete_program_cache(ctx, ctx->GeometryProgram.Cache); 125848b8605Smrg 126848b8605Smrg /* XXX probably move this stuff */ 127848b8605Smrg if (ctx->ATIFragmentShader.Current) { 128848b8605Smrg ctx->ATIFragmentShader.Current->RefCount--; 129848b8605Smrg if (ctx->ATIFragmentShader.Current->RefCount <= 0) { 130848b8605Smrg free(ctx->ATIFragmentShader.Current); 131848b8605Smrg } 132848b8605Smrg } 133848b8605Smrg 134848b8605Smrg free((void *) ctx->Program.ErrorString); 135848b8605Smrg} 136848b8605Smrg 137848b8605Smrg 138848b8605Smrg/** 139848b8605Smrg * Update the default program objects in the given context to reference those 140848b8605Smrg * specified in the shared state and release those referencing the old 141848b8605Smrg * shared state. 142848b8605Smrg */ 143848b8605Smrgvoid 144848b8605Smrg_mesa_update_default_objects_program(struct gl_context *ctx) 145848b8605Smrg{ 146848b8605Smrg _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current, 147848b8605Smrg ctx->Shared->DefaultVertexProgram); 148848b8605Smrg assert(ctx->VertexProgram.Current); 149848b8605Smrg 150848b8605Smrg _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current, 151848b8605Smrg ctx->Shared->DefaultFragmentProgram); 152848b8605Smrg assert(ctx->FragmentProgram.Current); 153848b8605Smrg 154848b8605Smrg _mesa_reference_geomprog(ctx, &ctx->GeometryProgram.Current, 155848b8605Smrg ctx->Shared->DefaultGeometryProgram); 156848b8605Smrg 157848b8605Smrg /* XXX probably move this stuff */ 158848b8605Smrg if (ctx->ATIFragmentShader.Current) { 159848b8605Smrg ctx->ATIFragmentShader.Current->RefCount--; 160848b8605Smrg if (ctx->ATIFragmentShader.Current->RefCount <= 0) { 161848b8605Smrg free(ctx->ATIFragmentShader.Current); 162848b8605Smrg } 163848b8605Smrg } 164848b8605Smrg ctx->ATIFragmentShader.Current = (struct ati_fragment_shader *) ctx->Shared->DefaultFragmentShader; 165848b8605Smrg assert(ctx->ATIFragmentShader.Current); 166848b8605Smrg ctx->ATIFragmentShader.Current->RefCount++; 167848b8605Smrg} 168848b8605Smrg 169848b8605Smrg 170848b8605Smrg/** 171848b8605Smrg * Set the vertex/fragment program error state (position and error string). 172848b8605Smrg * This is generally called from within the parsers. 173848b8605Smrg */ 174848b8605Smrgvoid 175848b8605Smrg_mesa_set_program_error(struct gl_context *ctx, GLint pos, const char *string) 176848b8605Smrg{ 177848b8605Smrg ctx->Program.ErrorPos = pos; 178848b8605Smrg free((void *) ctx->Program.ErrorString); 179848b8605Smrg if (!string) 180848b8605Smrg string = ""; 181848b8605Smrg ctx->Program.ErrorString = _mesa_strdup(string); 182848b8605Smrg} 183848b8605Smrg 184848b8605Smrg 185848b8605Smrg/** 186848b8605Smrg * Find the line number and column for 'pos' within 'string'. 187848b8605Smrg * Return a copy of the line which contains 'pos'. Free the line with 188848b8605Smrg * free(). 189848b8605Smrg * \param string the program string 190848b8605Smrg * \param pos the position within the string 191848b8605Smrg * \param line returns the line number corresponding to 'pos'. 192848b8605Smrg * \param col returns the column number corresponding to 'pos'. 193848b8605Smrg * \return copy of the line containing 'pos'. 194848b8605Smrg */ 195848b8605Smrgconst GLubyte * 196848b8605Smrg_mesa_find_line_column(const GLubyte *string, const GLubyte *pos, 197848b8605Smrg GLint *line, GLint *col) 198848b8605Smrg{ 199848b8605Smrg const GLubyte *lineStart = string; 200848b8605Smrg const GLubyte *p = string; 201848b8605Smrg GLubyte *s; 202848b8605Smrg int len; 203848b8605Smrg 204848b8605Smrg *line = 1; 205848b8605Smrg 206848b8605Smrg while (p != pos) { 207848b8605Smrg if (*p == (GLubyte) '\n') { 208848b8605Smrg (*line)++; 209848b8605Smrg lineStart = p + 1; 210848b8605Smrg } 211848b8605Smrg p++; 212848b8605Smrg } 213848b8605Smrg 214848b8605Smrg *col = (pos - lineStart) + 1; 215848b8605Smrg 216848b8605Smrg /* return copy of this line */ 217848b8605Smrg while (*p != 0 && *p != '\n') 218848b8605Smrg p++; 219848b8605Smrg len = p - lineStart; 220848b8605Smrg s = malloc(len + 1); 221848b8605Smrg memcpy(s, lineStart, len); 222848b8605Smrg s[len] = 0; 223848b8605Smrg 224848b8605Smrg return s; 225848b8605Smrg} 226848b8605Smrg 227848b8605Smrg 228848b8605Smrg/** 229848b8605Smrg * Initialize a new gl_program object. 230848b8605Smrg */ 231848b8605Smrgstatic void 232848b8605Smrginit_program_struct(struct gl_program *prog, GLenum target, GLuint id) 233848b8605Smrg{ 234848b8605Smrg GLuint i; 235848b8605Smrg 236848b8605Smrg assert(prog); 237848b8605Smrg 238848b8605Smrg memset(prog, 0, sizeof(*prog)); 239848b8605Smrg prog->Id = id; 240848b8605Smrg prog->Target = target; 241848b8605Smrg prog->RefCount = 1; 242848b8605Smrg prog->Format = GL_PROGRAM_FORMAT_ASCII_ARB; 243848b8605Smrg 244848b8605Smrg /* default mapping from samplers to texture units */ 245848b8605Smrg for (i = 0; i < MAX_SAMPLERS; i++) 246848b8605Smrg prog->SamplerUnits[i] = i; 247848b8605Smrg} 248848b8605Smrg 249848b8605Smrg 250848b8605Smrg/** 251848b8605Smrg * Initialize a new fragment program object. 252848b8605Smrg */ 253848b8605Smrgstruct gl_program * 254848b8605Smrg_mesa_init_fragment_program(struct gl_context *ctx, 255848b8605Smrg struct gl_fragment_program *prog, 256848b8605Smrg GLenum target, GLuint id) 257848b8605Smrg{ 258848b8605Smrg if (prog) { 259848b8605Smrg init_program_struct(&prog->Base, target, id); 260848b8605Smrg return &prog->Base; 261848b8605Smrg } 262848b8605Smrg return NULL; 263848b8605Smrg} 264848b8605Smrg 265848b8605Smrg 266848b8605Smrg/** 267848b8605Smrg * Initialize a new vertex program object. 268848b8605Smrg */ 269848b8605Smrgstruct gl_program * 270848b8605Smrg_mesa_init_vertex_program(struct gl_context *ctx, 271848b8605Smrg struct gl_vertex_program *prog, 272848b8605Smrg GLenum target, GLuint id) 273848b8605Smrg{ 274848b8605Smrg if (prog) { 275848b8605Smrg init_program_struct(&prog->Base, target, id); 276848b8605Smrg return &prog->Base; 277848b8605Smrg } 278848b8605Smrg return NULL; 279848b8605Smrg} 280848b8605Smrg 281848b8605Smrg 282848b8605Smrg/** 283848b8605Smrg * Initialize a new compute program object. 284848b8605Smrg */ 285848b8605Smrgstruct gl_program * 286848b8605Smrg_mesa_init_compute_program(struct gl_context *ctx, 287848b8605Smrg struct gl_compute_program *prog, 288848b8605Smrg GLenum target, GLuint id) 289848b8605Smrg{ 290848b8605Smrg if (prog) { 291848b8605Smrg init_program_struct(&prog->Base, target, id); 292848b8605Smrg return &prog->Base; 293848b8605Smrg } 294848b8605Smrg return NULL; 295848b8605Smrg} 296848b8605Smrg 297848b8605Smrg 298848b8605Smrg/** 299848b8605Smrg * Initialize a new geometry program object. 300848b8605Smrg */ 301848b8605Smrgstruct gl_program * 302848b8605Smrg_mesa_init_geometry_program(struct gl_context *ctx, 303848b8605Smrg struct gl_geometry_program *prog, 304848b8605Smrg GLenum target, GLuint id) 305848b8605Smrg{ 306848b8605Smrg if (prog) { 307848b8605Smrg init_program_struct(&prog->Base, target, id); 308848b8605Smrg return &prog->Base; 309848b8605Smrg } 310848b8605Smrg return NULL; 311848b8605Smrg} 312848b8605Smrg 313848b8605Smrg 314848b8605Smrg/** 315848b8605Smrg * Allocate and initialize a new fragment/vertex program object but 316848b8605Smrg * don't put it into the program hash table. Called via 317848b8605Smrg * ctx->Driver.NewProgram. May be overridden (ie. replaced) by a 318848b8605Smrg * device driver function to implement OO deriviation with additional 319848b8605Smrg * types not understood by this function. 320848b8605Smrg * 321848b8605Smrg * \param ctx context 322848b8605Smrg * \param id program id/number 323848b8605Smrg * \param target program target/type 324848b8605Smrg * \return pointer to new program object 325848b8605Smrg */ 326848b8605Smrgstruct gl_program * 327848b8605Smrg_mesa_new_program(struct gl_context *ctx, GLenum target, GLuint id) 328848b8605Smrg{ 329848b8605Smrg struct gl_program *prog; 330848b8605Smrg switch (target) { 331848b8605Smrg case GL_VERTEX_PROGRAM_ARB: /* == GL_VERTEX_PROGRAM_NV */ 332848b8605Smrg prog = _mesa_init_vertex_program(ctx, CALLOC_STRUCT(gl_vertex_program), 333848b8605Smrg target, id ); 334848b8605Smrg break; 335848b8605Smrg case GL_FRAGMENT_PROGRAM_NV: 336848b8605Smrg case GL_FRAGMENT_PROGRAM_ARB: 337848b8605Smrg prog =_mesa_init_fragment_program(ctx, 338848b8605Smrg CALLOC_STRUCT(gl_fragment_program), 339848b8605Smrg target, id ); 340848b8605Smrg break; 341848b8605Smrg case MESA_GEOMETRY_PROGRAM: 342848b8605Smrg prog = _mesa_init_geometry_program(ctx, 343848b8605Smrg CALLOC_STRUCT(gl_geometry_program), 344848b8605Smrg target, id); 345848b8605Smrg break; 346848b8605Smrg case GL_COMPUTE_PROGRAM_NV: 347848b8605Smrg prog = _mesa_init_compute_program(ctx, 348848b8605Smrg CALLOC_STRUCT(gl_compute_program), 349848b8605Smrg target, id); 350848b8605Smrg break; 351848b8605Smrg default: 352848b8605Smrg _mesa_problem(ctx, "bad target in _mesa_new_program"); 353848b8605Smrg prog = NULL; 354848b8605Smrg } 355848b8605Smrg return prog; 356848b8605Smrg} 357848b8605Smrg 358848b8605Smrg 359848b8605Smrg/** 360848b8605Smrg * Delete a program and remove it from the hash table, ignoring the 361848b8605Smrg * reference count. 362848b8605Smrg * Called via ctx->Driver.DeleteProgram. May be wrapped (OO deriviation) 363848b8605Smrg * by a device driver function. 364848b8605Smrg */ 365848b8605Smrgvoid 366848b8605Smrg_mesa_delete_program(struct gl_context *ctx, struct gl_program *prog) 367848b8605Smrg{ 368848b8605Smrg (void) ctx; 369848b8605Smrg ASSERT(prog); 370848b8605Smrg ASSERT(prog->RefCount==0); 371848b8605Smrg 372848b8605Smrg if (prog == &_mesa_DummyProgram) 373848b8605Smrg return; 374848b8605Smrg 375848b8605Smrg free(prog->String); 376848b8605Smrg free(prog->LocalParams); 377848b8605Smrg 378848b8605Smrg if (prog->Instructions) { 379848b8605Smrg _mesa_free_instructions(prog->Instructions, prog->NumInstructions); 380848b8605Smrg } 381848b8605Smrg if (prog->Parameters) { 382848b8605Smrg _mesa_free_parameter_list(prog->Parameters); 383848b8605Smrg } 384848b8605Smrg 385848b8605Smrg free(prog); 386848b8605Smrg} 387848b8605Smrg 388848b8605Smrg 389848b8605Smrg/** 390848b8605Smrg * Return the gl_program object for a given ID. 391848b8605Smrg * Basically just a wrapper for _mesa_HashLookup() to avoid a lot of 392848b8605Smrg * casts elsewhere. 393848b8605Smrg */ 394848b8605Smrgstruct gl_program * 395848b8605Smrg_mesa_lookup_program(struct gl_context *ctx, GLuint id) 396848b8605Smrg{ 397848b8605Smrg if (id) 398848b8605Smrg return (struct gl_program *) _mesa_HashLookup(ctx->Shared->Programs, id); 399848b8605Smrg else 400848b8605Smrg return NULL; 401848b8605Smrg} 402848b8605Smrg 403848b8605Smrg 404848b8605Smrg/** 405848b8605Smrg * Reference counting for vertex/fragment programs 406848b8605Smrg * This is normally only called from the _mesa_reference_program() macro 407848b8605Smrg * when there's a real pointer change. 408848b8605Smrg */ 409848b8605Smrgvoid 410848b8605Smrg_mesa_reference_program_(struct gl_context *ctx, 411848b8605Smrg struct gl_program **ptr, 412848b8605Smrg struct gl_program *prog) 413848b8605Smrg{ 414848b8605Smrg#ifndef NDEBUG 415848b8605Smrg assert(ptr); 416848b8605Smrg if (*ptr && prog) { 417848b8605Smrg /* sanity check */ 418848b8605Smrg if ((*ptr)->Target == GL_VERTEX_PROGRAM_ARB) 419848b8605Smrg ASSERT(prog->Target == GL_VERTEX_PROGRAM_ARB); 420848b8605Smrg else if ((*ptr)->Target == GL_FRAGMENT_PROGRAM_ARB) 421848b8605Smrg ASSERT(prog->Target == GL_FRAGMENT_PROGRAM_ARB || 422848b8605Smrg prog->Target == GL_FRAGMENT_PROGRAM_NV); 423848b8605Smrg else if ((*ptr)->Target == MESA_GEOMETRY_PROGRAM) 424848b8605Smrg ASSERT(prog->Target == MESA_GEOMETRY_PROGRAM); 425848b8605Smrg } 426848b8605Smrg#endif 427848b8605Smrg 428848b8605Smrg if (*ptr) { 429848b8605Smrg GLboolean deleteFlag; 430848b8605Smrg 431848b8605Smrg /*mtx_lock(&(*ptr)->Mutex);*/ 432848b8605Smrg#if 0 433848b8605Smrg printf("Program %p ID=%u Target=%s Refcount-- to %d\n", 434848b8605Smrg *ptr, (*ptr)->Id, 435848b8605Smrg ((*ptr)->Target == GL_VERTEX_PROGRAM_ARB ? "VP" : 436848b8605Smrg ((*ptr)->Target == MESA_GEOMETRY_PROGRAM ? "GP" : "FP")), 437848b8605Smrg (*ptr)->RefCount - 1); 438848b8605Smrg#endif 439848b8605Smrg ASSERT((*ptr)->RefCount > 0); 440848b8605Smrg (*ptr)->RefCount--; 441848b8605Smrg 442848b8605Smrg deleteFlag = ((*ptr)->RefCount == 0); 443848b8605Smrg /*mtx_lock(&(*ptr)->Mutex);*/ 444848b8605Smrg 445848b8605Smrg if (deleteFlag) { 446848b8605Smrg ASSERT(ctx); 447848b8605Smrg ctx->Driver.DeleteProgram(ctx, *ptr); 448848b8605Smrg } 449848b8605Smrg 450848b8605Smrg *ptr = NULL; 451848b8605Smrg } 452848b8605Smrg 453848b8605Smrg assert(!*ptr); 454848b8605Smrg if (prog) { 455848b8605Smrg /*mtx_lock(&prog->Mutex);*/ 456848b8605Smrg prog->RefCount++; 457848b8605Smrg#if 0 458848b8605Smrg printf("Program %p ID=%u Target=%s Refcount++ to %d\n", 459848b8605Smrg prog, prog->Id, 460848b8605Smrg (prog->Target == GL_VERTEX_PROGRAM_ARB ? "VP" : 461848b8605Smrg (prog->Target == MESA_GEOMETRY_PROGRAM ? "GP" : "FP")), 462848b8605Smrg prog->RefCount); 463848b8605Smrg#endif 464848b8605Smrg /*mtx_unlock(&prog->Mutex);*/ 465848b8605Smrg } 466848b8605Smrg 467848b8605Smrg *ptr = prog; 468848b8605Smrg} 469848b8605Smrg 470848b8605Smrg 471848b8605Smrg/** 472848b8605Smrg * Return a copy of a program. 473848b8605Smrg * XXX Problem here if the program object is actually OO-derivation 474848b8605Smrg * made by a device driver. 475848b8605Smrg */ 476848b8605Smrgstruct gl_program * 477848b8605Smrg_mesa_clone_program(struct gl_context *ctx, const struct gl_program *prog) 478848b8605Smrg{ 479848b8605Smrg struct gl_program *clone; 480848b8605Smrg 481848b8605Smrg clone = ctx->Driver.NewProgram(ctx, prog->Target, prog->Id); 482848b8605Smrg if (!clone) 483848b8605Smrg return NULL; 484848b8605Smrg 485848b8605Smrg assert(clone->Target == prog->Target); 486848b8605Smrg assert(clone->RefCount == 1); 487848b8605Smrg 488848b8605Smrg clone->String = (GLubyte *) _mesa_strdup((char *) prog->String); 489848b8605Smrg clone->Format = prog->Format; 490848b8605Smrg clone->Instructions = _mesa_alloc_instructions(prog->NumInstructions); 491848b8605Smrg if (!clone->Instructions) { 492848b8605Smrg _mesa_reference_program(ctx, &clone, NULL); 493848b8605Smrg return NULL; 494848b8605Smrg } 495848b8605Smrg _mesa_copy_instructions(clone->Instructions, prog->Instructions, 496848b8605Smrg prog->NumInstructions); 497848b8605Smrg clone->InputsRead = prog->InputsRead; 498848b8605Smrg clone->OutputsWritten = prog->OutputsWritten; 499848b8605Smrg clone->SamplersUsed = prog->SamplersUsed; 500848b8605Smrg clone->ShadowSamplers = prog->ShadowSamplers; 501848b8605Smrg memcpy(clone->TexturesUsed, prog->TexturesUsed, sizeof(prog->TexturesUsed)); 502848b8605Smrg 503848b8605Smrg if (prog->Parameters) 504848b8605Smrg clone->Parameters = _mesa_clone_parameter_list(prog->Parameters); 505848b8605Smrg if (prog->LocalParams) { 506848b8605Smrg clone->LocalParams = malloc(MAX_PROGRAM_LOCAL_PARAMS * 507848b8605Smrg sizeof(float[4])); 508848b8605Smrg if (!clone->LocalParams) { 509848b8605Smrg _mesa_reference_program(ctx, &clone, NULL); 510848b8605Smrg return NULL; 511848b8605Smrg } 512848b8605Smrg memcpy(clone->LocalParams, prog->LocalParams, 513848b8605Smrg MAX_PROGRAM_LOCAL_PARAMS * sizeof(float[4])); 514848b8605Smrg } 515848b8605Smrg clone->IndirectRegisterFiles = prog->IndirectRegisterFiles; 516848b8605Smrg clone->NumInstructions = prog->NumInstructions; 517848b8605Smrg clone->NumTemporaries = prog->NumTemporaries; 518848b8605Smrg clone->NumParameters = prog->NumParameters; 519848b8605Smrg clone->NumAttributes = prog->NumAttributes; 520848b8605Smrg clone->NumAddressRegs = prog->NumAddressRegs; 521848b8605Smrg clone->NumNativeInstructions = prog->NumNativeInstructions; 522848b8605Smrg clone->NumNativeTemporaries = prog->NumNativeTemporaries; 523848b8605Smrg clone->NumNativeParameters = prog->NumNativeParameters; 524848b8605Smrg clone->NumNativeAttributes = prog->NumNativeAttributes; 525848b8605Smrg clone->NumNativeAddressRegs = prog->NumNativeAddressRegs; 526848b8605Smrg clone->NumAluInstructions = prog->NumAluInstructions; 527848b8605Smrg clone->NumTexInstructions = prog->NumTexInstructions; 528848b8605Smrg clone->NumTexIndirections = prog->NumTexIndirections; 529848b8605Smrg clone->NumNativeAluInstructions = prog->NumNativeAluInstructions; 530848b8605Smrg clone->NumNativeTexInstructions = prog->NumNativeTexInstructions; 531848b8605Smrg clone->NumNativeTexIndirections = prog->NumNativeTexIndirections; 532848b8605Smrg 533848b8605Smrg switch (prog->Target) { 534848b8605Smrg case GL_VERTEX_PROGRAM_ARB: 535848b8605Smrg { 536848b8605Smrg const struct gl_vertex_program *vp = gl_vertex_program_const(prog); 537848b8605Smrg struct gl_vertex_program *vpc = gl_vertex_program(clone); 538848b8605Smrg vpc->IsPositionInvariant = vp->IsPositionInvariant; 539848b8605Smrg } 540848b8605Smrg break; 541848b8605Smrg case GL_FRAGMENT_PROGRAM_ARB: 542848b8605Smrg { 543848b8605Smrg const struct gl_fragment_program *fp = gl_fragment_program_const(prog); 544848b8605Smrg struct gl_fragment_program *fpc = gl_fragment_program(clone); 545848b8605Smrg fpc->UsesKill = fp->UsesKill; 546848b8605Smrg fpc->UsesDFdy = fp->UsesDFdy; 547848b8605Smrg fpc->OriginUpperLeft = fp->OriginUpperLeft; 548848b8605Smrg fpc->PixelCenterInteger = fp->PixelCenterInteger; 549848b8605Smrg } 550848b8605Smrg break; 551848b8605Smrg case MESA_GEOMETRY_PROGRAM: 552848b8605Smrg { 553848b8605Smrg const struct gl_geometry_program *gp = gl_geometry_program_const(prog); 554848b8605Smrg struct gl_geometry_program *gpc = gl_geometry_program(clone); 555848b8605Smrg gpc->VerticesOut = gp->VerticesOut; 556848b8605Smrg gpc->InputType = gp->InputType; 557848b8605Smrg gpc->Invocations = gp->Invocations; 558848b8605Smrg gpc->OutputType = gp->OutputType; 559848b8605Smrg gpc->UsesEndPrimitive = gp->UsesEndPrimitive; 560848b8605Smrg gpc->UsesStreams = gp->UsesStreams; 561848b8605Smrg } 562848b8605Smrg break; 563848b8605Smrg default: 564848b8605Smrg _mesa_problem(NULL, "Unexpected target in _mesa_clone_program"); 565848b8605Smrg } 566848b8605Smrg 567848b8605Smrg return clone; 568848b8605Smrg} 569848b8605Smrg 570848b8605Smrg 571848b8605Smrg/** 572848b8605Smrg * Insert 'count' NOP instructions at 'start' in the given program. 573848b8605Smrg * Adjust branch targets accordingly. 574848b8605Smrg */ 575848b8605SmrgGLboolean 576848b8605Smrg_mesa_insert_instructions(struct gl_program *prog, GLuint start, GLuint count) 577848b8605Smrg{ 578848b8605Smrg const GLuint origLen = prog->NumInstructions; 579848b8605Smrg const GLuint newLen = origLen + count; 580848b8605Smrg struct prog_instruction *newInst; 581848b8605Smrg GLuint i; 582848b8605Smrg 583848b8605Smrg /* adjust branches */ 584848b8605Smrg for (i = 0; i < prog->NumInstructions; i++) { 585848b8605Smrg struct prog_instruction *inst = prog->Instructions + i; 586848b8605Smrg if (inst->BranchTarget > 0) { 587848b8605Smrg if ((GLuint)inst->BranchTarget >= start) { 588848b8605Smrg inst->BranchTarget += count; 589848b8605Smrg } 590848b8605Smrg } 591848b8605Smrg } 592848b8605Smrg 593848b8605Smrg /* Alloc storage for new instructions */ 594848b8605Smrg newInst = _mesa_alloc_instructions(newLen); 595848b8605Smrg if (!newInst) { 596848b8605Smrg return GL_FALSE; 597848b8605Smrg } 598848b8605Smrg 599848b8605Smrg /* Copy 'start' instructions into new instruction buffer */ 600848b8605Smrg _mesa_copy_instructions(newInst, prog->Instructions, start); 601848b8605Smrg 602848b8605Smrg /* init the new instructions */ 603848b8605Smrg _mesa_init_instructions(newInst + start, count); 604848b8605Smrg 605848b8605Smrg /* Copy the remaining/tail instructions to new inst buffer */ 606848b8605Smrg _mesa_copy_instructions(newInst + start + count, 607848b8605Smrg prog->Instructions + start, 608848b8605Smrg origLen - start); 609848b8605Smrg 610848b8605Smrg /* free old instructions */ 611848b8605Smrg _mesa_free_instructions(prog->Instructions, origLen); 612848b8605Smrg 613848b8605Smrg /* install new instructions */ 614848b8605Smrg prog->Instructions = newInst; 615848b8605Smrg prog->NumInstructions = newLen; 616848b8605Smrg 617848b8605Smrg return GL_TRUE; 618848b8605Smrg} 619848b8605Smrg 620848b8605Smrg/** 621848b8605Smrg * Delete 'count' instructions at 'start' in the given program. 622848b8605Smrg * Adjust branch targets accordingly. 623848b8605Smrg */ 624848b8605SmrgGLboolean 625848b8605Smrg_mesa_delete_instructions(struct gl_program *prog, GLuint start, GLuint count) 626848b8605Smrg{ 627848b8605Smrg const GLuint origLen = prog->NumInstructions; 628848b8605Smrg const GLuint newLen = origLen - count; 629848b8605Smrg struct prog_instruction *newInst; 630848b8605Smrg GLuint i; 631848b8605Smrg 632848b8605Smrg /* adjust branches */ 633848b8605Smrg for (i = 0; i < prog->NumInstructions; i++) { 634848b8605Smrg struct prog_instruction *inst = prog->Instructions + i; 635848b8605Smrg if (inst->BranchTarget > 0) { 636848b8605Smrg if (inst->BranchTarget > (GLint) start) { 637848b8605Smrg inst->BranchTarget -= count; 638848b8605Smrg } 639848b8605Smrg } 640848b8605Smrg } 641848b8605Smrg 642848b8605Smrg /* Alloc storage for new instructions */ 643848b8605Smrg newInst = _mesa_alloc_instructions(newLen); 644848b8605Smrg if (!newInst) { 645848b8605Smrg return GL_FALSE; 646848b8605Smrg } 647848b8605Smrg 648848b8605Smrg /* Copy 'start' instructions into new instruction buffer */ 649848b8605Smrg _mesa_copy_instructions(newInst, prog->Instructions, start); 650848b8605Smrg 651848b8605Smrg /* Copy the remaining/tail instructions to new inst buffer */ 652848b8605Smrg _mesa_copy_instructions(newInst + start, 653848b8605Smrg prog->Instructions + start + count, 654848b8605Smrg newLen - start); 655848b8605Smrg 656848b8605Smrg /* free old instructions */ 657848b8605Smrg _mesa_free_instructions(prog->Instructions, origLen); 658848b8605Smrg 659848b8605Smrg /* install new instructions */ 660848b8605Smrg prog->Instructions = newInst; 661848b8605Smrg prog->NumInstructions = newLen; 662848b8605Smrg 663848b8605Smrg return GL_TRUE; 664848b8605Smrg} 665848b8605Smrg 666848b8605Smrg 667848b8605Smrg/** 668848b8605Smrg * Search instructions for registers that match (oldFile, oldIndex), 669848b8605Smrg * replacing them with (newFile, newIndex). 670848b8605Smrg */ 671848b8605Smrgstatic void 672848b8605Smrgreplace_registers(struct prog_instruction *inst, GLuint numInst, 673848b8605Smrg GLuint oldFile, GLuint oldIndex, 674848b8605Smrg GLuint newFile, GLuint newIndex) 675848b8605Smrg{ 676848b8605Smrg GLuint i, j; 677848b8605Smrg for (i = 0; i < numInst; i++) { 678848b8605Smrg /* src regs */ 679848b8605Smrg for (j = 0; j < _mesa_num_inst_src_regs(inst[i].Opcode); j++) { 680848b8605Smrg if (inst[i].SrcReg[j].File == oldFile && 681848b8605Smrg inst[i].SrcReg[j].Index == oldIndex) { 682848b8605Smrg inst[i].SrcReg[j].File = newFile; 683848b8605Smrg inst[i].SrcReg[j].Index = newIndex; 684848b8605Smrg } 685848b8605Smrg } 686848b8605Smrg /* dst reg */ 687848b8605Smrg if (inst[i].DstReg.File == oldFile && inst[i].DstReg.Index == oldIndex) { 688848b8605Smrg inst[i].DstReg.File = newFile; 689848b8605Smrg inst[i].DstReg.Index = newIndex; 690848b8605Smrg } 691848b8605Smrg } 692848b8605Smrg} 693848b8605Smrg 694848b8605Smrg 695848b8605Smrg/** 696848b8605Smrg * Search instructions for references to program parameters. When found, 697848b8605Smrg * increment the parameter index by 'offset'. 698848b8605Smrg * Used when combining programs. 699848b8605Smrg */ 700848b8605Smrgstatic void 701848b8605Smrgadjust_param_indexes(struct prog_instruction *inst, GLuint numInst, 702848b8605Smrg GLuint offset) 703848b8605Smrg{ 704848b8605Smrg GLuint i, j; 705848b8605Smrg for (i = 0; i < numInst; i++) { 706848b8605Smrg for (j = 0; j < _mesa_num_inst_src_regs(inst[i].Opcode); j++) { 707848b8605Smrg GLuint f = inst[i].SrcReg[j].File; 708848b8605Smrg if (f == PROGRAM_CONSTANT || 709848b8605Smrg f == PROGRAM_UNIFORM || 710848b8605Smrg f == PROGRAM_STATE_VAR) { 711848b8605Smrg inst[i].SrcReg[j].Index += offset; 712848b8605Smrg } 713848b8605Smrg } 714848b8605Smrg } 715848b8605Smrg} 716848b8605Smrg 717848b8605Smrg 718848b8605Smrg/** 719848b8605Smrg * Combine two programs into one. Fix instructions so the outputs of 720848b8605Smrg * the first program go to the inputs of the second program. 721848b8605Smrg */ 722848b8605Smrgstruct gl_program * 723848b8605Smrg_mesa_combine_programs(struct gl_context *ctx, 724848b8605Smrg const struct gl_program *progA, 725848b8605Smrg const struct gl_program *progB) 726848b8605Smrg{ 727848b8605Smrg struct prog_instruction *newInst; 728848b8605Smrg struct gl_program *newProg; 729848b8605Smrg const GLuint lenA = progA->NumInstructions - 1; /* omit END instr */ 730848b8605Smrg const GLuint lenB = progB->NumInstructions; 731848b8605Smrg const GLuint numParamsA = _mesa_num_parameters(progA->Parameters); 732848b8605Smrg const GLuint newLength = lenA + lenB; 733848b8605Smrg GLboolean usedTemps[MAX_PROGRAM_TEMPS]; 734848b8605Smrg GLuint firstTemp = 0; 735848b8605Smrg GLbitfield64 inputsB; 736848b8605Smrg GLuint i; 737848b8605Smrg 738848b8605Smrg ASSERT(progA->Target == progB->Target); 739848b8605Smrg 740848b8605Smrg newInst = _mesa_alloc_instructions(newLength); 741848b8605Smrg if (!newInst) 742848b8605Smrg return GL_FALSE; 743848b8605Smrg 744848b8605Smrg _mesa_copy_instructions(newInst, progA->Instructions, lenA); 745848b8605Smrg _mesa_copy_instructions(newInst + lenA, progB->Instructions, lenB); 746848b8605Smrg 747848b8605Smrg /* adjust branch / instruction addresses for B's instructions */ 748848b8605Smrg for (i = 0; i < lenB; i++) { 749848b8605Smrg newInst[lenA + i].BranchTarget += lenA; 750848b8605Smrg } 751848b8605Smrg 752848b8605Smrg newProg = ctx->Driver.NewProgram(ctx, progA->Target, 0); 753848b8605Smrg newProg->Instructions = newInst; 754848b8605Smrg newProg->NumInstructions = newLength; 755848b8605Smrg 756848b8605Smrg /* find used temp regs (we may need new temps below) */ 757848b8605Smrg _mesa_find_used_registers(newProg, PROGRAM_TEMPORARY, 758848b8605Smrg usedTemps, MAX_PROGRAM_TEMPS); 759848b8605Smrg 760848b8605Smrg if (newProg->Target == GL_FRAGMENT_PROGRAM_ARB) { 761848b8605Smrg const struct gl_fragment_program *fprogA, *fprogB; 762848b8605Smrg struct gl_fragment_program *newFprog; 763848b8605Smrg GLbitfield64 progB_inputsRead = progB->InputsRead; 764848b8605Smrg GLint progB_colorFile, progB_colorIndex; 765848b8605Smrg 766848b8605Smrg fprogA = gl_fragment_program_const(progA); 767848b8605Smrg fprogB = gl_fragment_program_const(progB); 768848b8605Smrg newFprog = gl_fragment_program(newProg); 769848b8605Smrg 770848b8605Smrg newFprog->UsesKill = fprogA->UsesKill || fprogB->UsesKill; 771848b8605Smrg newFprog->UsesDFdy = fprogA->UsesDFdy || fprogB->UsesDFdy; 772848b8605Smrg 773848b8605Smrg /* We'll do a search and replace for instances 774848b8605Smrg * of progB_colorFile/progB_colorIndex below... 775848b8605Smrg */ 776848b8605Smrg progB_colorFile = PROGRAM_INPUT; 777848b8605Smrg progB_colorIndex = VARYING_SLOT_COL0; 778848b8605Smrg 779848b8605Smrg /* 780848b8605Smrg * The fragment program may get color from a state var rather than 781848b8605Smrg * a fragment input (vertex output) if it's constant. 782848b8605Smrg * See the texenvprogram.c code. 783848b8605Smrg * So, search the program's parameter list now to see if the program 784848b8605Smrg * gets color from a state var instead of a conventional fragment 785848b8605Smrg * input register. 786848b8605Smrg */ 787848b8605Smrg for (i = 0; i < progB->Parameters->NumParameters; i++) { 788848b8605Smrg struct gl_program_parameter *p = &progB->Parameters->Parameters[i]; 789848b8605Smrg if (p->Type == PROGRAM_STATE_VAR && 790848b8605Smrg p->StateIndexes[0] == STATE_INTERNAL && 791848b8605Smrg p->StateIndexes[1] == STATE_CURRENT_ATTRIB && 792848b8605Smrg (int) p->StateIndexes[2] == (int) VERT_ATTRIB_COLOR0) { 793848b8605Smrg progB_inputsRead |= VARYING_BIT_COL0; 794848b8605Smrg progB_colorFile = PROGRAM_STATE_VAR; 795848b8605Smrg progB_colorIndex = i; 796848b8605Smrg break; 797848b8605Smrg } 798848b8605Smrg } 799848b8605Smrg 800848b8605Smrg /* Connect color outputs of fprogA to color inputs of fprogB, via a 801848b8605Smrg * new temporary register. 802848b8605Smrg */ 803848b8605Smrg if ((progA->OutputsWritten & BITFIELD64_BIT(FRAG_RESULT_COLOR)) && 804848b8605Smrg (progB_inputsRead & VARYING_BIT_COL0)) { 805848b8605Smrg GLint tempReg = _mesa_find_free_register(usedTemps, MAX_PROGRAM_TEMPS, 806848b8605Smrg firstTemp); 807848b8605Smrg if (tempReg < 0) { 808848b8605Smrg _mesa_problem(ctx, "No free temp regs found in " 809848b8605Smrg "_mesa_combine_programs(), using 31"); 810848b8605Smrg tempReg = 31; 811848b8605Smrg } 812848b8605Smrg firstTemp = tempReg + 1; 813848b8605Smrg 814848b8605Smrg /* replace writes to result.color[0] with tempReg */ 815848b8605Smrg replace_registers(newInst, lenA, 816848b8605Smrg PROGRAM_OUTPUT, FRAG_RESULT_COLOR, 817848b8605Smrg PROGRAM_TEMPORARY, tempReg); 818848b8605Smrg /* replace reads from the input color with tempReg */ 819848b8605Smrg replace_registers(newInst + lenA, lenB, 820848b8605Smrg progB_colorFile, progB_colorIndex, /* search for */ 821848b8605Smrg PROGRAM_TEMPORARY, tempReg /* replace with */ ); 822848b8605Smrg } 823848b8605Smrg 824848b8605Smrg /* compute combined program's InputsRead */ 825848b8605Smrg inputsB = progB_inputsRead; 826848b8605Smrg if (progA->OutputsWritten & BITFIELD64_BIT(FRAG_RESULT_COLOR)) { 827848b8605Smrg inputsB &= ~(1 << VARYING_SLOT_COL0); 828848b8605Smrg } 829848b8605Smrg newProg->InputsRead = progA->InputsRead | inputsB; 830848b8605Smrg newProg->OutputsWritten = progB->OutputsWritten; 831848b8605Smrg newProg->SamplersUsed = progA->SamplersUsed | progB->SamplersUsed; 832848b8605Smrg } 833848b8605Smrg else { 834848b8605Smrg /* vertex program */ 835848b8605Smrg assert(0); /* XXX todo */ 836848b8605Smrg } 837848b8605Smrg 838848b8605Smrg /* 839848b8605Smrg * Merge parameters (uniforms, constants, etc) 840848b8605Smrg */ 841848b8605Smrg newProg->Parameters = _mesa_combine_parameter_lists(progA->Parameters, 842848b8605Smrg progB->Parameters); 843848b8605Smrg 844848b8605Smrg adjust_param_indexes(newInst + lenA, lenB, numParamsA); 845848b8605Smrg 846848b8605Smrg 847848b8605Smrg return newProg; 848848b8605Smrg} 849848b8605Smrg 850848b8605Smrg 851848b8605Smrg/** 852848b8605Smrg * Populate the 'used' array with flags indicating which registers (TEMPs, 853848b8605Smrg * INPUTs, OUTPUTs, etc, are used by the given program. 854848b8605Smrg * \param file type of register to scan for 855848b8605Smrg * \param used returns true/false flags for in use / free 856848b8605Smrg * \param usedSize size of the 'used' array 857848b8605Smrg */ 858848b8605Smrgvoid 859848b8605Smrg_mesa_find_used_registers(const struct gl_program *prog, 860848b8605Smrg gl_register_file file, 861848b8605Smrg GLboolean used[], GLuint usedSize) 862848b8605Smrg{ 863848b8605Smrg GLuint i, j; 864848b8605Smrg 865848b8605Smrg memset(used, 0, usedSize); 866848b8605Smrg 867848b8605Smrg for (i = 0; i < prog->NumInstructions; i++) { 868848b8605Smrg const struct prog_instruction *inst = prog->Instructions + i; 869848b8605Smrg const GLuint n = _mesa_num_inst_src_regs(inst->Opcode); 870848b8605Smrg 871848b8605Smrg if (inst->DstReg.File == file) { 872848b8605Smrg ASSERT(inst->DstReg.Index < usedSize); 873848b8605Smrg if(inst->DstReg.Index < usedSize) 874848b8605Smrg used[inst->DstReg.Index] = GL_TRUE; 875848b8605Smrg } 876848b8605Smrg 877848b8605Smrg for (j = 0; j < n; j++) { 878848b8605Smrg if (inst->SrcReg[j].File == file) { 879848b8605Smrg ASSERT(inst->SrcReg[j].Index < (GLint) usedSize); 880848b8605Smrg if (inst->SrcReg[j].Index < (GLint) usedSize) 881848b8605Smrg used[inst->SrcReg[j].Index] = GL_TRUE; 882848b8605Smrg } 883848b8605Smrg } 884848b8605Smrg } 885848b8605Smrg} 886848b8605Smrg 887848b8605Smrg 888848b8605Smrg/** 889848b8605Smrg * Scan the given 'used' register flag array for the first entry 890848b8605Smrg * that's >= firstReg. 891848b8605Smrg * \param used vector of flags indicating registers in use (as returned 892848b8605Smrg * by _mesa_find_used_registers()) 893848b8605Smrg * \param usedSize size of the 'used' array 894848b8605Smrg * \param firstReg first register to start searching at 895848b8605Smrg * \return index of unused register, or -1 if none. 896848b8605Smrg */ 897848b8605SmrgGLint 898848b8605Smrg_mesa_find_free_register(const GLboolean used[], 899848b8605Smrg GLuint usedSize, GLuint firstReg) 900848b8605Smrg{ 901848b8605Smrg GLuint i; 902848b8605Smrg 903848b8605Smrg assert(firstReg < usedSize); 904848b8605Smrg 905848b8605Smrg for (i = firstReg; i < usedSize; i++) 906848b8605Smrg if (!used[i]) 907848b8605Smrg return i; 908848b8605Smrg 909848b8605Smrg return -1; 910848b8605Smrg} 911848b8605Smrg 912848b8605Smrg 913848b8605Smrg 914848b8605Smrg/** 915848b8605Smrg * Check if the given register index is valid (doesn't exceed implementation- 916848b8605Smrg * dependent limits). 917848b8605Smrg * \return GL_TRUE if OK, GL_FALSE if bad index 918848b8605Smrg */ 919848b8605SmrgGLboolean 920848b8605Smrg_mesa_valid_register_index(const struct gl_context *ctx, 921848b8605Smrg gl_shader_stage shaderType, 922848b8605Smrg gl_register_file file, GLint index) 923848b8605Smrg{ 924848b8605Smrg const struct gl_program_constants *c; 925848b8605Smrg 926848b8605Smrg assert(0 <= shaderType && shaderType < MESA_SHADER_STAGES); 927848b8605Smrg c = &ctx->Const.Program[shaderType]; 928848b8605Smrg 929848b8605Smrg switch (file) { 930848b8605Smrg case PROGRAM_UNDEFINED: 931848b8605Smrg return GL_TRUE; /* XXX or maybe false? */ 932848b8605Smrg 933848b8605Smrg case PROGRAM_TEMPORARY: 934848b8605Smrg return index >= 0 && index < (GLint) c->MaxTemps; 935848b8605Smrg 936848b8605Smrg case PROGRAM_UNIFORM: 937848b8605Smrg case PROGRAM_STATE_VAR: 938848b8605Smrg /* aka constant buffer */ 939848b8605Smrg return index >= 0 && index < (GLint) c->MaxUniformComponents / 4; 940848b8605Smrg 941848b8605Smrg case PROGRAM_CONSTANT: 942848b8605Smrg /* constant buffer w/ possible relative negative addressing */ 943848b8605Smrg return (index > (int) c->MaxUniformComponents / -4 && 944848b8605Smrg index < (int) c->MaxUniformComponents / 4); 945848b8605Smrg 946848b8605Smrg case PROGRAM_INPUT: 947848b8605Smrg if (index < 0) 948848b8605Smrg return GL_FALSE; 949848b8605Smrg 950848b8605Smrg switch (shaderType) { 951848b8605Smrg case MESA_SHADER_VERTEX: 952848b8605Smrg return index < VERT_ATTRIB_GENERIC0 + (GLint) c->MaxAttribs; 953848b8605Smrg case MESA_SHADER_FRAGMENT: 954848b8605Smrg return index < VARYING_SLOT_VAR0 + (GLint) ctx->Const.MaxVarying; 955848b8605Smrg case MESA_SHADER_GEOMETRY: 956848b8605Smrg return index < VARYING_SLOT_VAR0 + (GLint) ctx->Const.MaxVarying; 957848b8605Smrg default: 958848b8605Smrg return GL_FALSE; 959848b8605Smrg } 960848b8605Smrg 961848b8605Smrg case PROGRAM_OUTPUT: 962848b8605Smrg if (index < 0) 963848b8605Smrg return GL_FALSE; 964848b8605Smrg 965848b8605Smrg switch (shaderType) { 966848b8605Smrg case MESA_SHADER_VERTEX: 967848b8605Smrg return index < VARYING_SLOT_VAR0 + (GLint) ctx->Const.MaxVarying; 968848b8605Smrg case MESA_SHADER_FRAGMENT: 969848b8605Smrg return index < FRAG_RESULT_DATA0 + (GLint) ctx->Const.MaxDrawBuffers; 970848b8605Smrg case MESA_SHADER_GEOMETRY: 971848b8605Smrg return index < VARYING_SLOT_VAR0 + (GLint) ctx->Const.MaxVarying; 972848b8605Smrg default: 973848b8605Smrg return GL_FALSE; 974848b8605Smrg } 975848b8605Smrg 976848b8605Smrg case PROGRAM_ADDRESS: 977848b8605Smrg return index >= 0 && index < (GLint) c->MaxAddressRegs; 978848b8605Smrg 979848b8605Smrg default: 980848b8605Smrg _mesa_problem(ctx, 981848b8605Smrg "unexpected register file in _mesa_valid_register_index()"); 982848b8605Smrg return GL_FALSE; 983848b8605Smrg } 984848b8605Smrg} 985848b8605Smrg 986848b8605Smrg 987848b8605Smrg 988848b8605Smrg/** 989848b8605Smrg * "Post-process" a GPU program. This is intended to be used for debugging. 990848b8605Smrg * Example actions include no-op'ing instructions or changing instruction 991848b8605Smrg * behaviour. 992848b8605Smrg */ 993848b8605Smrgvoid 994848b8605Smrg_mesa_postprocess_program(struct gl_context *ctx, struct gl_program *prog) 995848b8605Smrg{ 996848b8605Smrg static const GLfloat white[4] = { 0.5, 0.5, 0.5, 0.5 }; 997848b8605Smrg GLuint i; 998848b8605Smrg GLuint whiteSwizzle; 999848b8605Smrg GLint whiteIndex = _mesa_add_unnamed_constant(prog->Parameters, 1000848b8605Smrg (gl_constant_value *) white, 1001848b8605Smrg 4, &whiteSwizzle); 1002848b8605Smrg 1003848b8605Smrg (void) whiteIndex; 1004848b8605Smrg 1005848b8605Smrg for (i = 0; i < prog->NumInstructions; i++) { 1006848b8605Smrg struct prog_instruction *inst = prog->Instructions + i; 1007848b8605Smrg const GLuint n = _mesa_num_inst_src_regs(inst->Opcode); 1008848b8605Smrg 1009848b8605Smrg (void) n; 1010848b8605Smrg 1011848b8605Smrg if (_mesa_is_tex_instruction(inst->Opcode)) { 1012848b8605Smrg#if 0 1013848b8605Smrg /* replace TEX/TXP/TXB with MOV */ 1014848b8605Smrg inst->Opcode = OPCODE_MOV; 1015848b8605Smrg inst->DstReg.WriteMask = WRITEMASK_XYZW; 1016848b8605Smrg inst->SrcReg[0].Swizzle = SWIZZLE_XYZW; 1017848b8605Smrg inst->SrcReg[0].Negate = NEGATE_NONE; 1018848b8605Smrg#endif 1019848b8605Smrg 1020848b8605Smrg#if 0 1021848b8605Smrg /* disable shadow texture mode */ 1022848b8605Smrg inst->TexShadow = 0; 1023848b8605Smrg#endif 1024848b8605Smrg } 1025848b8605Smrg 1026848b8605Smrg if (inst->Opcode == OPCODE_TXP) { 1027848b8605Smrg#if 0 1028848b8605Smrg inst->Opcode = OPCODE_MOV; 1029848b8605Smrg inst->DstReg.WriteMask = WRITEMASK_XYZW; 1030848b8605Smrg inst->SrcReg[0].File = PROGRAM_CONSTANT; 1031848b8605Smrg inst->SrcReg[0].Index = whiteIndex; 1032848b8605Smrg inst->SrcReg[0].Swizzle = SWIZZLE_XYZW; 1033848b8605Smrg inst->SrcReg[0].Negate = NEGATE_NONE; 1034848b8605Smrg#endif 1035848b8605Smrg#if 0 1036848b8605Smrg inst->TexShadow = 0; 1037848b8605Smrg#endif 1038848b8605Smrg#if 0 1039848b8605Smrg inst->Opcode = OPCODE_TEX; 1040848b8605Smrg inst->TexShadow = 0; 1041848b8605Smrg#endif 1042848b8605Smrg } 1043848b8605Smrg 1044848b8605Smrg } 1045848b8605Smrg} 1046848b8605Smrg 1047848b8605Smrg/* Gets the minimum number of shader invocations per fragment. 1048848b8605Smrg * This function is useful to determine if we need to do per 1049848b8605Smrg * sample shading or per fragment shading. 1050848b8605Smrg */ 1051848b8605SmrgGLint 1052848b8605Smrg_mesa_get_min_invocations_per_fragment(struct gl_context *ctx, 1053848b8605Smrg const struct gl_fragment_program *prog, 1054848b8605Smrg bool ignore_sample_qualifier) 1055848b8605Smrg{ 1056848b8605Smrg /* From ARB_sample_shading specification: 1057848b8605Smrg * "Using gl_SampleID in a fragment shader causes the entire shader 1058848b8605Smrg * to be evaluated per-sample." 1059848b8605Smrg * 1060848b8605Smrg * "Using gl_SamplePosition in a fragment shader causes the entire 1061848b8605Smrg * shader to be evaluated per-sample." 1062848b8605Smrg * 1063848b8605Smrg * "If MULTISAMPLE or SAMPLE_SHADING_ARB is disabled, sample shading 1064848b8605Smrg * has no effect." 1065848b8605Smrg */ 1066848b8605Smrg if (ctx->Multisample.Enabled) { 1067848b8605Smrg /* The ARB_gpu_shader5 specification says: 1068848b8605Smrg * 1069848b8605Smrg * "Use of the "sample" qualifier on a fragment shader input 1070848b8605Smrg * forces per-sample shading" 1071848b8605Smrg */ 1072848b8605Smrg if (prog->IsSample && !ignore_sample_qualifier) 1073848b8605Smrg return MAX2(ctx->DrawBuffer->Visual.samples, 1); 1074848b8605Smrg 1075848b8605Smrg if (prog->Base.SystemValuesRead & (SYSTEM_BIT_SAMPLE_ID | 1076848b8605Smrg SYSTEM_BIT_SAMPLE_POS)) 1077848b8605Smrg return MAX2(ctx->DrawBuffer->Visual.samples, 1); 1078848b8605Smrg else if (ctx->Multisample.SampleShading) 1079848b8605Smrg return MAX2(ceil(ctx->Multisample.MinSampleShadingValue * 1080848b8605Smrg ctx->DrawBuffer->Visual.samples), 1); 1081848b8605Smrg else 1082848b8605Smrg return 1; 1083848b8605Smrg } 1084848b8605Smrg return 1; 1085848b8605Smrg} 1086