program.c revision 7ec2b0d0d6b6a0f760e55ffdee0bdb385a3e900a
1d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/* 2d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Mesa 3-D graphics library 3d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Version: 6.5.3 4d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 5d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. 6d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 7d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Permission is hereby granted, free of charge, to any person obtaining a 8d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * copy of this software and associated documentation files (the "Software"), 9d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * to deal in the Software without restriction, including without limitation 10d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * and/or sell copies of the Software, and to permit persons to whom the 12d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Software is furnished to do so, subject to the following conditions: 13d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 14d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * The above copyright notice and this permission notice shall be included 15d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * in all copies or substantial portions of the Software. 16d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 17d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 21d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 24d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 25d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/** 26d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * \file program.c 27d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Vertex and fragment program support functions. 28d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * \author Brian Paul 29d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 30d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 31d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 32d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen#include "main/glheader.h" 33d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen#include "main/context.h" 34d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen#include "main/hash.h" 35d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen#include "main/mfeatures.h" 36d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen#include "program.h" 37d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen#include "prog_cache.h" 38d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen#include "prog_parameter.h" 39d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen#include "prog_instruction.h" 40d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 41d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 42d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/** 43d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * A pointer to this dummy program is put into the hash table when 44d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * glGenPrograms is called. 45d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 46d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenstruct gl_program _mesa_DummyProgram; 47d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 48d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 49d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/** 50d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Init context's vertex/fragment program state 51d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 52d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenvoid 53d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen_mesa_init_program(struct gl_context *ctx) 54d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen{ 55d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen GLuint i; 56d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 57d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /* 58d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * If this assertion fails, we need to increase the field 59d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * size for register indexes (see INST_INDEX_BITS). 60d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 61d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen ASSERT(ctx->Const.VertexProgram.MaxUniformComponents / 4 62d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen <= (1 << INST_INDEX_BITS)); 63d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen ASSERT(ctx->Const.FragmentProgram.MaxUniformComponents / 4 64d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen <= (1 << INST_INDEX_BITS)); 65d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 66d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen ASSERT(ctx->Const.VertexProgram.MaxTemps <= (1 << INST_INDEX_BITS)); 67d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen ASSERT(ctx->Const.VertexProgram.MaxLocalParams <= (1 << INST_INDEX_BITS)); 68d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen ASSERT(ctx->Const.FragmentProgram.MaxTemps <= (1 << INST_INDEX_BITS)); 69d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen ASSERT(ctx->Const.FragmentProgram.MaxLocalParams <= (1 << INST_INDEX_BITS)); 70d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 71d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen ASSERT(ctx->Const.VertexProgram.MaxUniformComponents <= 4 * MAX_UNIFORMS); 72d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen ASSERT(ctx->Const.FragmentProgram.MaxUniformComponents <= 4 * MAX_UNIFORMS); 73d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 74d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen ASSERT(ctx->Const.VertexProgram.MaxAddressOffset <= (1 << INST_INDEX_BITS)); 75 ASSERT(ctx->Const.FragmentProgram.MaxAddressOffset <= (1 << INST_INDEX_BITS)); 76 77 /* If this fails, increase prog_instruction::TexSrcUnit size */ 78 ASSERT(MAX_TEXTURE_UNITS <= (1 << 5)); 79 80 /* If this fails, increase prog_instruction::TexSrcTarget size */ 81 ASSERT(NUM_TEXTURE_TARGETS <= (1 << 3)); 82 83 ctx->Program.ErrorPos = -1; 84 ctx->Program.ErrorString = _mesa_strdup(""); 85 86#if FEATURE_NV_vertex_program || FEATURE_ARB_vertex_program 87 ctx->VertexProgram.Enabled = GL_FALSE; 88#if FEATURE_es2_glsl 89 ctx->VertexProgram.PointSizeEnabled = 90 (ctx->API == API_OPENGLES2) ? GL_TRUE : GL_FALSE; 91#else 92 ctx->VertexProgram.PointSizeEnabled = GL_FALSE; 93#endif 94 ctx->VertexProgram.TwoSideEnabled = GL_FALSE; 95 _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current, 96 ctx->Shared->DefaultVertexProgram); 97 assert(ctx->VertexProgram.Current); 98 for (i = 0; i < MAX_NV_VERTEX_PROGRAM_PARAMS / 4; i++) { 99 ctx->VertexProgram.TrackMatrix[i] = GL_NONE; 100 ctx->VertexProgram.TrackMatrixTransform[i] = GL_IDENTITY_NV; 101 } 102 ctx->VertexProgram.Cache = _mesa_new_program_cache(); 103#endif 104 105#if FEATURE_NV_fragment_program || FEATURE_ARB_fragment_program 106 ctx->FragmentProgram.Enabled = GL_FALSE; 107 _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current, 108 ctx->Shared->DefaultFragmentProgram); 109 assert(ctx->FragmentProgram.Current); 110 ctx->FragmentProgram.Cache = _mesa_new_program_cache(); 111#endif 112 113#if FEATURE_ARB_geometry_shader4 114 ctx->GeometryProgram.Enabled = GL_FALSE; 115 /* right now by default we don't have a geometry program */ 116 _mesa_reference_geomprog(ctx, &ctx->GeometryProgram.Current, 117 NULL); 118 ctx->GeometryProgram.Cache = _mesa_new_program_cache(); 119#endif 120 121 /* XXX probably move this stuff */ 122#if FEATURE_ATI_fragment_shader 123 ctx->ATIFragmentShader.Enabled = GL_FALSE; 124 ctx->ATIFragmentShader.Current = ctx->Shared->DefaultFragmentShader; 125 assert(ctx->ATIFragmentShader.Current); 126 ctx->ATIFragmentShader.Current->RefCount++; 127#endif 128} 129 130 131/** 132 * Free a context's vertex/fragment program state 133 */ 134void 135_mesa_free_program_data(struct gl_context *ctx) 136{ 137#if FEATURE_NV_vertex_program || FEATURE_ARB_vertex_program 138 _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current, NULL); 139 _mesa_delete_program_cache(ctx, ctx->VertexProgram.Cache); 140#endif 141#if FEATURE_NV_fragment_program || FEATURE_ARB_fragment_program 142 _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current, NULL); 143 _mesa_delete_shader_cache(ctx, ctx->FragmentProgram.Cache); 144#endif 145#if FEATURE_ARB_geometry_shader4 146 _mesa_reference_geomprog(ctx, &ctx->GeometryProgram.Current, NULL); 147 _mesa_delete_program_cache(ctx, ctx->GeometryProgram.Cache); 148#endif 149 /* XXX probably move this stuff */ 150#if FEATURE_ATI_fragment_shader 151 if (ctx->ATIFragmentShader.Current) { 152 ctx->ATIFragmentShader.Current->RefCount--; 153 if (ctx->ATIFragmentShader.Current->RefCount <= 0) { 154 free(ctx->ATIFragmentShader.Current); 155 } 156 } 157#endif 158 free((void *) ctx->Program.ErrorString); 159} 160 161 162/** 163 * Update the default program objects in the given context to reference those 164 * specified in the shared state and release those referencing the old 165 * shared state. 166 */ 167void 168_mesa_update_default_objects_program(struct gl_context *ctx) 169{ 170#if FEATURE_NV_vertex_program || FEATURE_ARB_vertex_program 171 _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current, 172 (struct gl_vertex_program *) 173 ctx->Shared->DefaultVertexProgram); 174 assert(ctx->VertexProgram.Current); 175#endif 176 177#if FEATURE_NV_fragment_program || FEATURE_ARB_fragment_program 178 _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current, 179 (struct gl_fragment_program *) 180 ctx->Shared->DefaultFragmentProgram); 181 assert(ctx->FragmentProgram.Current); 182#endif 183 184#if FEATURE_ARB_geometry_shader4 185 _mesa_reference_geomprog(ctx, &ctx->GeometryProgram.Current, 186 (struct gl_geometry_program *) 187 ctx->Shared->DefaultGeometryProgram); 188#endif 189 190 /* XXX probably move this stuff */ 191#if FEATURE_ATI_fragment_shader 192 if (ctx->ATIFragmentShader.Current) { 193 ctx->ATIFragmentShader.Current->RefCount--; 194 if (ctx->ATIFragmentShader.Current->RefCount <= 0) { 195 free(ctx->ATIFragmentShader.Current); 196 } 197 } 198 ctx->ATIFragmentShader.Current = (struct ati_fragment_shader *) ctx->Shared->DefaultFragmentShader; 199 assert(ctx->ATIFragmentShader.Current); 200 ctx->ATIFragmentShader.Current->RefCount++; 201#endif 202} 203 204 205/** 206 * Set the vertex/fragment program error state (position and error string). 207 * This is generally called from within the parsers. 208 */ 209void 210_mesa_set_program_error(struct gl_context *ctx, GLint pos, const char *string) 211{ 212 ctx->Program.ErrorPos = pos; 213 free((void *) ctx->Program.ErrorString); 214 if (!string) 215 string = ""; 216 ctx->Program.ErrorString = _mesa_strdup(string); 217} 218 219 220/** 221 * Find the line number and column for 'pos' within 'string'. 222 * Return a copy of the line which contains 'pos'. Free the line with 223 * free(). 224 * \param string the program string 225 * \param pos the position within the string 226 * \param line returns the line number corresponding to 'pos'. 227 * \param col returns the column number corresponding to 'pos'. 228 * \return copy of the line containing 'pos'. 229 */ 230const GLubyte * 231_mesa_find_line_column(const GLubyte *string, const GLubyte *pos, 232 GLint *line, GLint *col) 233{ 234 const GLubyte *lineStart = string; 235 const GLubyte *p = string; 236 GLubyte *s; 237 int len; 238 239 *line = 1; 240 241 while (p != pos) { 242 if (*p == (GLubyte) '\n') { 243 (*line)++; 244 lineStart = p + 1; 245 } 246 p++; 247 } 248 249 *col = (pos - lineStart) + 1; 250 251 /* return copy of this line */ 252 while (*p != 0 && *p != '\n') 253 p++; 254 len = p - lineStart; 255 s = (GLubyte *) malloc(len + 1); 256 memcpy(s, lineStart, len); 257 s[len] = 0; 258 259 return s; 260} 261 262 263/** 264 * Initialize a new vertex/fragment program object. 265 */ 266static struct gl_program * 267_mesa_init_program_struct( struct gl_context *ctx, struct gl_program *prog, 268 GLenum target, GLuint id) 269{ 270 (void) ctx; 271 if (prog) { 272 GLuint i; 273 memset(prog, 0, sizeof(*prog)); 274 prog->Id = id; 275 prog->Target = target; 276 prog->Resident = GL_TRUE; 277 prog->RefCount = 1; 278 prog->Format = GL_PROGRAM_FORMAT_ASCII_ARB; 279 280 /* default mapping from samplers to texture units */ 281 for (i = 0; i < MAX_SAMPLERS; i++) 282 prog->SamplerUnits[i] = i; 283 } 284 285 return prog; 286} 287 288 289/** 290 * Initialize a new fragment program object. 291 */ 292struct gl_program * 293_mesa_init_fragment_program( struct gl_context *ctx, struct gl_fragment_program *prog, 294 GLenum target, GLuint id) 295{ 296 if (prog) 297 return _mesa_init_program_struct( ctx, &prog->Base, target, id ); 298 else 299 return NULL; 300} 301 302 303/** 304 * Initialize a new vertex program object. 305 */ 306struct gl_program * 307_mesa_init_vertex_program( struct gl_context *ctx, struct gl_vertex_program *prog, 308 GLenum target, GLuint id) 309{ 310 if (prog) 311 return _mesa_init_program_struct( ctx, &prog->Base, target, id ); 312 else 313 return NULL; 314} 315 316 317/** 318 * Initialize a new geometry program object. 319 */ 320struct gl_program * 321_mesa_init_geometry_program( struct gl_context *ctx, struct gl_geometry_program *prog, 322 GLenum target, GLuint id) 323{ 324 if (prog) 325 return _mesa_init_program_struct( ctx, &prog->Base, target, id ); 326 else 327 return NULL; 328} 329 330 331/** 332 * Allocate and initialize a new fragment/vertex program object but 333 * don't put it into the program hash table. Called via 334 * ctx->Driver.NewProgram. May be overridden (ie. replaced) by a 335 * device driver function to implement OO deriviation with additional 336 * types not understood by this function. 337 * 338 * \param ctx context 339 * \param id program id/number 340 * \param target program target/type 341 * \return pointer to new program object 342 */ 343struct gl_program * 344_mesa_new_program(struct gl_context *ctx, GLenum target, GLuint id) 345{ 346 struct gl_program *prog; 347 switch (target) { 348 case GL_VERTEX_PROGRAM_ARB: /* == GL_VERTEX_PROGRAM_NV */ 349 case GL_VERTEX_STATE_PROGRAM_NV: 350 prog = _mesa_init_vertex_program(ctx, CALLOC_STRUCT(gl_vertex_program), 351 target, id ); 352 break; 353 case GL_FRAGMENT_PROGRAM_NV: 354 case GL_FRAGMENT_PROGRAM_ARB: 355 prog =_mesa_init_fragment_program(ctx, 356 CALLOC_STRUCT(gl_fragment_program), 357 target, id ); 358 break; 359 case MESA_GEOMETRY_PROGRAM: 360 prog = _mesa_init_geometry_program(ctx, 361 CALLOC_STRUCT(gl_geometry_program), 362 target, id); 363 break; 364 default: 365 _mesa_problem(ctx, "bad target in _mesa_new_program"); 366 prog = NULL; 367 } 368 return prog; 369} 370 371 372/** 373 * Delete a program and remove it from the hash table, ignoring the 374 * reference count. 375 * Called via ctx->Driver.DeleteProgram. May be wrapped (OO deriviation) 376 * by a device driver function. 377 */ 378void 379_mesa_delete_program(struct gl_context *ctx, struct gl_program *prog) 380{ 381 (void) ctx; 382 ASSERT(prog); 383 ASSERT(prog->RefCount==0); 384 385 if (prog == &_mesa_DummyProgram) 386 return; 387 388 if (prog->String) 389 free(prog->String); 390 391 if (prog->Instructions) { 392 _mesa_free_instructions(prog->Instructions, prog->NumInstructions); 393 } 394 if (prog->Parameters) { 395 _mesa_free_parameter_list(prog->Parameters); 396 } 397 398 free(prog); 399} 400 401 402/** 403 * Return the gl_program object for a given ID. 404 * Basically just a wrapper for _mesa_HashLookup() to avoid a lot of 405 * casts elsewhere. 406 */ 407struct gl_program * 408_mesa_lookup_program(struct gl_context *ctx, GLuint id) 409{ 410 if (id) 411 return (struct gl_program *) _mesa_HashLookup(ctx->Shared->Programs, id); 412 else 413 return NULL; 414} 415 416 417/** 418 * Reference counting for vertex/fragment programs 419 * This is normally only called from the _mesa_reference_program() macro 420 * when there's a real pointer change. 421 */ 422void 423_mesa_reference_program_(struct gl_context *ctx, 424 struct gl_program **ptr, 425 struct gl_program *prog) 426{ 427#ifndef NDEBUG 428 assert(ptr); 429 if (*ptr && prog) { 430 /* sanity check */ 431 if ((*ptr)->Target == GL_VERTEX_PROGRAM_ARB) 432 ASSERT(prog->Target == GL_VERTEX_PROGRAM_ARB); 433 else if ((*ptr)->Target == GL_FRAGMENT_PROGRAM_ARB) 434 ASSERT(prog->Target == GL_FRAGMENT_PROGRAM_ARB || 435 prog->Target == GL_FRAGMENT_PROGRAM_NV); 436 else if ((*ptr)->Target == MESA_GEOMETRY_PROGRAM) 437 ASSERT(prog->Target == MESA_GEOMETRY_PROGRAM); 438 } 439#endif 440 441 if (*ptr) { 442 GLboolean deleteFlag; 443 444 /*_glthread_LOCK_MUTEX((*ptr)->Mutex);*/ 445#if 0 446 printf("Program %p ID=%u Target=%s Refcount-- to %d\n", 447 *ptr, (*ptr)->Id, 448 ((*ptr)->Target == GL_VERTEX_PROGRAM_ARB ? "VP" : 449 ((*ptr)->Target == MESA_GEOMETRY_PROGRAM ? "GP" : "FP")), 450 (*ptr)->RefCount - 1); 451#endif 452 ASSERT((*ptr)->RefCount > 0); 453 (*ptr)->RefCount--; 454 455 deleteFlag = ((*ptr)->RefCount == 0); 456 /*_glthread_UNLOCK_MUTEX((*ptr)->Mutex);*/ 457 458 if (deleteFlag) { 459 ASSERT(ctx); 460 ctx->Driver.DeleteProgram(ctx, *ptr); 461 } 462 463 *ptr = NULL; 464 } 465 466 assert(!*ptr); 467 if (prog) { 468 /*_glthread_LOCK_MUTEX(prog->Mutex);*/ 469 prog->RefCount++; 470#if 0 471 printf("Program %p ID=%u Target=%s Refcount++ to %d\n", 472 prog, prog->Id, 473 (prog->Target == GL_VERTEX_PROGRAM_ARB ? "VP" : 474 (prog->Target == MESA_GEOMETRY_PROGRAM ? "GP" : "FP")), 475 prog->RefCount); 476#endif 477 /*_glthread_UNLOCK_MUTEX(prog->Mutex);*/ 478 } 479 480 *ptr = prog; 481} 482 483 484/** 485 * Return a copy of a program. 486 * XXX Problem here if the program object is actually OO-derivation 487 * made by a device driver. 488 */ 489struct gl_program * 490_mesa_clone_program(struct gl_context *ctx, const struct gl_program *prog) 491{ 492 struct gl_program *clone; 493 494 clone = ctx->Driver.NewProgram(ctx, prog->Target, prog->Id); 495 if (!clone) 496 return NULL; 497 498 assert(clone->Target == prog->Target); 499 assert(clone->RefCount == 1); 500 501 clone->String = (GLubyte *) _mesa_strdup((char *) prog->String); 502 clone->Format = prog->Format; 503 clone->Instructions = _mesa_alloc_instructions(prog->NumInstructions); 504 if (!clone->Instructions) { 505 _mesa_reference_program(ctx, &clone, NULL); 506 return NULL; 507 } 508 _mesa_copy_instructions(clone->Instructions, prog->Instructions, 509 prog->NumInstructions); 510 clone->InputsRead = prog->InputsRead; 511 clone->OutputsWritten = prog->OutputsWritten; 512 clone->SamplersUsed = prog->SamplersUsed; 513 clone->ShadowSamplers = prog->ShadowSamplers; 514 memcpy(clone->TexturesUsed, prog->TexturesUsed, sizeof(prog->TexturesUsed)); 515 516 if (prog->Parameters) 517 clone->Parameters = _mesa_clone_parameter_list(prog->Parameters); 518 memcpy(clone->LocalParams, prog->LocalParams, sizeof(clone->LocalParams)); 519 memcpy(clone->LocalParams, prog->LocalParams, sizeof(clone->LocalParams)); 520 clone->IndirectRegisterFiles = prog->IndirectRegisterFiles; 521 clone->NumInstructions = prog->NumInstructions; 522 clone->NumTemporaries = prog->NumTemporaries; 523 clone->NumParameters = prog->NumParameters; 524 clone->NumAttributes = prog->NumAttributes; 525 clone->NumAddressRegs = prog->NumAddressRegs; 526 clone->NumNativeInstructions = prog->NumNativeInstructions; 527 clone->NumNativeTemporaries = prog->NumNativeTemporaries; 528 clone->NumNativeParameters = prog->NumNativeParameters; 529 clone->NumNativeAttributes = prog->NumNativeAttributes; 530 clone->NumNativeAddressRegs = prog->NumNativeAddressRegs; 531 clone->NumAluInstructions = prog->NumAluInstructions; 532 clone->NumTexInstructions = prog->NumTexInstructions; 533 clone->NumTexIndirections = prog->NumTexIndirections; 534 clone->NumNativeAluInstructions = prog->NumNativeAluInstructions; 535 clone->NumNativeTexInstructions = prog->NumNativeTexInstructions; 536 clone->NumNativeTexIndirections = prog->NumNativeTexIndirections; 537 538 switch (prog->Target) { 539 case GL_VERTEX_PROGRAM_ARB: 540 { 541 const struct gl_vertex_program *vp 542 = (const struct gl_vertex_program *) prog; 543 struct gl_vertex_program *vpc = (struct gl_vertex_program *) clone; 544 vpc->IsPositionInvariant = vp->IsPositionInvariant; 545 vpc->IsNVProgram = vp->IsNVProgram; 546 } 547 break; 548 case GL_FRAGMENT_PROGRAM_ARB: 549 { 550 const struct gl_fragment_program *fp 551 = (const struct gl_fragment_program *) prog; 552 struct gl_fragment_program *fpc = (struct gl_fragment_program *) clone; 553 fpc->UsesKill = fp->UsesKill; 554 fpc->OriginUpperLeft = fp->OriginUpperLeft; 555 fpc->PixelCenterInteger = fp->PixelCenterInteger; 556 } 557 break; 558 case MESA_GEOMETRY_PROGRAM: 559 { 560 const struct gl_geometry_program *gp 561 = (const struct gl_geometry_program *) prog; 562 struct gl_geometry_program *gpc = (struct gl_geometry_program *) clone; 563 gpc->VerticesOut = gp->VerticesOut; 564 gpc->InputType = gp->InputType; 565 gpc->OutputType = gp->OutputType; 566 } 567 break; 568 default: 569 _mesa_problem(NULL, "Unexpected target in _mesa_clone_program"); 570 } 571 572 return clone; 573} 574 575 576/** 577 * Insert 'count' NOP instructions at 'start' in the given program. 578 * Adjust branch targets accordingly. 579 */ 580GLboolean 581_mesa_insert_instructions(struct gl_program *prog, GLuint start, GLuint count) 582{ 583 const GLuint origLen = prog->NumInstructions; 584 const GLuint newLen = origLen + count; 585 struct prog_instruction *newInst; 586 GLuint i; 587 588 /* adjust branches */ 589 for (i = 0; i < prog->NumInstructions; i++) { 590 struct prog_instruction *inst = prog->Instructions + i; 591 if (inst->BranchTarget > 0) { 592 if ((GLuint)inst->BranchTarget >= start) { 593 inst->BranchTarget += count; 594 } 595 } 596 } 597 598 /* Alloc storage for new instructions */ 599 newInst = _mesa_alloc_instructions(newLen); 600 if (!newInst) { 601 return GL_FALSE; 602 } 603 604 /* Copy 'start' instructions into new instruction buffer */ 605 _mesa_copy_instructions(newInst, prog->Instructions, start); 606 607 /* init the new instructions */ 608 _mesa_init_instructions(newInst + start, count); 609 610 /* Copy the remaining/tail instructions to new inst buffer */ 611 _mesa_copy_instructions(newInst + start + count, 612 prog->Instructions + start, 613 origLen - start); 614 615 /* free old instructions */ 616 _mesa_free_instructions(prog->Instructions, origLen); 617 618 /* install new instructions */ 619 prog->Instructions = newInst; 620 prog->NumInstructions = newLen; 621 622 return GL_TRUE; 623} 624 625/** 626 * Delete 'count' instructions at 'start' in the given program. 627 * Adjust branch targets accordingly. 628 */ 629GLboolean 630_mesa_delete_instructions(struct gl_program *prog, GLuint start, GLuint count) 631{ 632 const GLuint origLen = prog->NumInstructions; 633 const GLuint newLen = origLen - count; 634 struct prog_instruction *newInst; 635 GLuint i; 636 637 /* adjust branches */ 638 for (i = 0; i < prog->NumInstructions; i++) { 639 struct prog_instruction *inst = prog->Instructions + i; 640 if (inst->BranchTarget > 0) { 641 if (inst->BranchTarget > (GLint) start) { 642 inst->BranchTarget -= count; 643 } 644 } 645 } 646 647 /* Alloc storage for new instructions */ 648 newInst = _mesa_alloc_instructions(newLen); 649 if (!newInst) { 650 return GL_FALSE; 651 } 652 653 /* Copy 'start' instructions into new instruction buffer */ 654 _mesa_copy_instructions(newInst, prog->Instructions, start); 655 656 /* Copy the remaining/tail instructions to new inst buffer */ 657 _mesa_copy_instructions(newInst + start, 658 prog->Instructions + start + count, 659 newLen - start); 660 661 /* free old instructions */ 662 _mesa_free_instructions(prog->Instructions, origLen); 663 664 /* install new instructions */ 665 prog->Instructions = newInst; 666 prog->NumInstructions = newLen; 667 668 return GL_TRUE; 669} 670 671 672/** 673 * Search instructions for registers that match (oldFile, oldIndex), 674 * replacing them with (newFile, newIndex). 675 */ 676static void 677replace_registers(struct prog_instruction *inst, GLuint numInst, 678 GLuint oldFile, GLuint oldIndex, 679 GLuint newFile, GLuint newIndex) 680{ 681 GLuint i, j; 682 for (i = 0; i < numInst; i++) { 683 /* src regs */ 684 for (j = 0; j < _mesa_num_inst_src_regs(inst[i].Opcode); j++) { 685 if (inst[i].SrcReg[j].File == oldFile && 686 inst[i].SrcReg[j].Index == oldIndex) { 687 inst[i].SrcReg[j].File = newFile; 688 inst[i].SrcReg[j].Index = newIndex; 689 } 690 } 691 /* dst reg */ 692 if (inst[i].DstReg.File == oldFile && inst[i].DstReg.Index == oldIndex) { 693 inst[i].DstReg.File = newFile; 694 inst[i].DstReg.Index = newIndex; 695 } 696 } 697} 698 699 700/** 701 * Search instructions for references to program parameters. When found, 702 * increment the parameter index by 'offset'. 703 * Used when combining programs. 704 */ 705static void 706adjust_param_indexes(struct prog_instruction *inst, GLuint numInst, 707 GLuint offset) 708{ 709 GLuint i, j; 710 for (i = 0; i < numInst; i++) { 711 for (j = 0; j < _mesa_num_inst_src_regs(inst[i].Opcode); j++) { 712 GLuint f = inst[i].SrcReg[j].File; 713 if (f == PROGRAM_CONSTANT || 714 f == PROGRAM_UNIFORM || 715 f == PROGRAM_STATE_VAR) { 716 inst[i].SrcReg[j].Index += offset; 717 } 718 } 719 } 720} 721 722 723/** 724 * Combine two programs into one. Fix instructions so the outputs of 725 * the first program go to the inputs of the second program. 726 */ 727struct gl_program * 728_mesa_combine_programs(struct gl_context *ctx, 729 const struct gl_program *progA, 730 const struct gl_program *progB) 731{ 732 struct prog_instruction *newInst; 733 struct gl_program *newProg; 734 const GLuint lenA = progA->NumInstructions - 1; /* omit END instr */ 735 const GLuint lenB = progB->NumInstructions; 736 const GLuint numParamsA = _mesa_num_parameters(progA->Parameters); 737 const GLuint newLength = lenA + lenB; 738 GLboolean usedTemps[MAX_PROGRAM_TEMPS]; 739 GLuint firstTemp = 0; 740 GLbitfield inputsB; 741 GLuint i; 742 743 ASSERT(progA->Target == progB->Target); 744 745 newInst = _mesa_alloc_instructions(newLength); 746 if (!newInst) 747 return GL_FALSE; 748 749 _mesa_copy_instructions(newInst, progA->Instructions, lenA); 750 _mesa_copy_instructions(newInst + lenA, progB->Instructions, lenB); 751 752 /* adjust branch / instruction addresses for B's instructions */ 753 for (i = 0; i < lenB; i++) { 754 newInst[lenA + i].BranchTarget += lenA; 755 } 756 757 newProg = ctx->Driver.NewProgram(ctx, progA->Target, 0); 758 newProg->Instructions = newInst; 759 newProg->NumInstructions = newLength; 760 761 /* find used temp regs (we may need new temps below) */ 762 _mesa_find_used_registers(newProg, PROGRAM_TEMPORARY, 763 usedTemps, MAX_PROGRAM_TEMPS); 764 765 if (newProg->Target == GL_FRAGMENT_PROGRAM_ARB) { 766 struct gl_fragment_program *fprogA, *fprogB, *newFprog; 767 GLbitfield progB_inputsRead = progB->InputsRead; 768 GLint progB_colorFile, progB_colorIndex; 769 770 fprogA = (struct gl_fragment_program *) progA; 771 fprogB = (struct gl_fragment_program *) progB; 772 newFprog = (struct gl_fragment_program *) newProg; 773 774 newFprog->UsesKill = fprogA->UsesKill || fprogB->UsesKill; 775 776 /* We'll do a search and replace for instances 777 * of progB_colorFile/progB_colorIndex below... 778 */ 779 progB_colorFile = PROGRAM_INPUT; 780 progB_colorIndex = FRAG_ATTRIB_COL0; 781 782 /* 783 * The fragment program may get color from a state var rather than 784 * a fragment input (vertex output) if it's constant. 785 * See the texenvprogram.c code. 786 * So, search the program's parameter list now to see if the program 787 * gets color from a state var instead of a conventional fragment 788 * input register. 789 */ 790 for (i = 0; i < progB->Parameters->NumParameters; i++) { 791 struct gl_program_parameter *p = &progB->Parameters->Parameters[i]; 792 if (p->Type == PROGRAM_STATE_VAR && 793 p->StateIndexes[0] == STATE_INTERNAL && 794 p->StateIndexes[1] == STATE_CURRENT_ATTRIB && 795 (int) p->StateIndexes[2] == (int) VERT_ATTRIB_COLOR0) { 796 progB_inputsRead |= FRAG_BIT_COL0; 797 progB_colorFile = PROGRAM_STATE_VAR; 798 progB_colorIndex = i; 799 break; 800 } 801 } 802 803 /* Connect color outputs of fprogA to color inputs of fprogB, via a 804 * new temporary register. 805 */ 806 if ((progA->OutputsWritten & BITFIELD64_BIT(FRAG_RESULT_COLOR)) && 807 (progB_inputsRead & FRAG_BIT_COL0)) { 808 GLint tempReg = _mesa_find_free_register(usedTemps, MAX_PROGRAM_TEMPS, 809 firstTemp); 810 if (tempReg < 0) { 811 _mesa_problem(ctx, "No free temp regs found in " 812 "_mesa_combine_programs(), using 31"); 813 tempReg = 31; 814 } 815 firstTemp = tempReg + 1; 816 817 /* replace writes to result.color[0] with tempReg */ 818 replace_registers(newInst, lenA, 819 PROGRAM_OUTPUT, FRAG_RESULT_COLOR, 820 PROGRAM_TEMPORARY, tempReg); 821 /* replace reads from the input color with tempReg */ 822 replace_registers(newInst + lenA, lenB, 823 progB_colorFile, progB_colorIndex, /* search for */ 824 PROGRAM_TEMPORARY, tempReg /* replace with */ ); 825 } 826 827 /* compute combined program's InputsRead */ 828 inputsB = progB_inputsRead; 829 if (progA->OutputsWritten & BITFIELD64_BIT(FRAG_RESULT_COLOR)) { 830 inputsB &= ~(1 << FRAG_ATTRIB_COL0); 831 } 832 newProg->InputsRead = progA->InputsRead | inputsB; 833 newProg->OutputsWritten = progB->OutputsWritten; 834 newProg->SamplersUsed = progA->SamplersUsed | progB->SamplersUsed; 835 } 836 else { 837 /* vertex program */ 838 assert(0); /* XXX todo */ 839 } 840 841 /* 842 * Merge parameters (uniforms, constants, etc) 843 */ 844 newProg->Parameters = _mesa_combine_parameter_lists(progA->Parameters, 845 progB->Parameters); 846 847 adjust_param_indexes(newInst + lenA, lenB, numParamsA); 848 849 850 return newProg; 851} 852 853 854/** 855 * Populate the 'used' array with flags indicating which registers (TEMPs, 856 * INPUTs, OUTPUTs, etc, are used by the given program. 857 * \param file type of register to scan for 858 * \param used returns true/false flags for in use / free 859 * \param usedSize size of the 'used' array 860 */ 861void 862_mesa_find_used_registers(const struct gl_program *prog, 863 gl_register_file file, 864 GLboolean used[], GLuint usedSize) 865{ 866 GLuint i, j; 867 868 memset(used, 0, usedSize); 869 870 for (i = 0; i < prog->NumInstructions; i++) { 871 const struct prog_instruction *inst = prog->Instructions + i; 872 const GLuint n = _mesa_num_inst_src_regs(inst->Opcode); 873 874 if (inst->DstReg.File == file) { 875 ASSERT(inst->DstReg.Index < usedSize); 876 if(inst->DstReg.Index < usedSize) 877 used[inst->DstReg.Index] = GL_TRUE; 878 } 879 880 for (j = 0; j < n; j++) { 881 if (inst->SrcReg[j].File == file) { 882 ASSERT(inst->SrcReg[j].Index < usedSize); 883 if(inst->SrcReg[j].Index < usedSize) 884 used[inst->SrcReg[j].Index] = GL_TRUE; 885 } 886 } 887 } 888} 889 890 891/** 892 * Scan the given 'used' register flag array for the first entry 893 * that's >= firstReg. 894 * \param used vector of flags indicating registers in use (as returned 895 * by _mesa_find_used_registers()) 896 * \param usedSize size of the 'used' array 897 * \param firstReg first register to start searching at 898 * \return index of unused register, or -1 if none. 899 */ 900GLint 901_mesa_find_free_register(const GLboolean used[], 902 GLuint usedSize, GLuint firstReg) 903{ 904 GLuint i; 905 906 assert(firstReg < usedSize); 907 908 for (i = firstReg; i < usedSize; i++) 909 if (!used[i]) 910 return i; 911 912 return -1; 913} 914 915 916 917/** 918 * Check if the given register index is valid (doesn't exceed implementation- 919 * dependent limits). 920 * \return GL_TRUE if OK, GL_FALSE if bad index 921 */ 922GLboolean 923_mesa_valid_register_index(const struct gl_context *ctx, 924 gl_shader_type shaderType, 925 gl_register_file file, GLint index) 926{ 927 const struct gl_program_constants *c; 928 929 switch (shaderType) { 930 case MESA_SHADER_VERTEX: 931 c = &ctx->Const.VertexProgram; 932 break; 933 case MESA_SHADER_FRAGMENT: 934 c = &ctx->Const.FragmentProgram; 935 break; 936 case MESA_SHADER_GEOMETRY: 937 c = &ctx->Const.GeometryProgram; 938 break; 939 default: 940 _mesa_problem(ctx, 941 "unexpected shader type in _mesa_valid_register_index()"); 942 return GL_FALSE; 943 } 944 945 switch (file) { 946 case PROGRAM_UNDEFINED: 947 return GL_TRUE; /* XXX or maybe false? */ 948 949 case PROGRAM_TEMPORARY: 950 return index >= 0 && index < c->MaxTemps; 951 952 case PROGRAM_ENV_PARAM: 953 return index >= 0 && index < c->MaxEnvParams; 954 955 case PROGRAM_LOCAL_PARAM: 956 return index >= 0 && index < c->MaxLocalParams; 957 958 case PROGRAM_NAMED_PARAM: 959 return index >= 0 && index < c->MaxParameters; 960 961 case PROGRAM_UNIFORM: 962 case PROGRAM_STATE_VAR: 963 /* aka constant buffer */ 964 return index >= 0 && index < c->MaxUniformComponents / 4; 965 966 case PROGRAM_CONSTANT: 967 /* constant buffer w/ possible relative negative addressing */ 968 return (index > (int) c->MaxUniformComponents / -4 && 969 index < c->MaxUniformComponents / 4); 970 971 case PROGRAM_INPUT: 972 if (index < 0) 973 return GL_FALSE; 974 975 switch (shaderType) { 976 case MESA_SHADER_VERTEX: 977 return index < VERT_ATTRIB_GENERIC0 + c->MaxAttribs; 978 case MESA_SHADER_FRAGMENT: 979 return index < FRAG_ATTRIB_VAR0 + ctx->Const.MaxVarying; 980 case MESA_SHADER_GEOMETRY: 981 return index < GEOM_ATTRIB_VAR0 + ctx->Const.MaxVarying; 982 default: 983 return GL_FALSE; 984 } 985 986 case PROGRAM_OUTPUT: 987 if (index < 0) 988 return GL_FALSE; 989 990 switch (shaderType) { 991 case MESA_SHADER_VERTEX: 992 return index < VERT_RESULT_VAR0 + ctx->Const.MaxVarying; 993 case MESA_SHADER_FRAGMENT: 994 return index < FRAG_RESULT_DATA0 + ctx->Const.MaxDrawBuffers; 995 case MESA_SHADER_GEOMETRY: 996 return index < GEOM_RESULT_VAR0 + ctx->Const.MaxVarying; 997 default: 998 return GL_FALSE; 999 } 1000 1001 case PROGRAM_ADDRESS: 1002 return index >= 0 && index < c->MaxAddressRegs; 1003 1004 default: 1005 _mesa_problem(ctx, 1006 "unexpected register file in _mesa_valid_register_index()"); 1007 return GL_FALSE; 1008 } 1009} 1010 1011 1012 1013/** 1014 * "Post-process" a GPU program. This is intended to be used for debugging. 1015 * Example actions include no-op'ing instructions or changing instruction 1016 * behaviour. 1017 */ 1018void 1019_mesa_postprocess_program(struct gl_context *ctx, struct gl_program *prog) 1020{ 1021 static const GLfloat white[4] = { 0.5, 0.5, 0.5, 0.5 }; 1022 GLuint i; 1023 GLuint whiteSwizzle; 1024 GLint whiteIndex = _mesa_add_unnamed_constant(prog->Parameters, 1025 (gl_constant_value *) white, 1026 4, &whiteSwizzle); 1027 1028 (void) whiteIndex; 1029 1030 for (i = 0; i < prog->NumInstructions; i++) { 1031 struct prog_instruction *inst = prog->Instructions + i; 1032 const GLuint n = _mesa_num_inst_src_regs(inst->Opcode); 1033 1034 (void) n; 1035 1036 if (_mesa_is_tex_instruction(inst->Opcode)) { 1037#if 0 1038 /* replace TEX/TXP/TXB with MOV */ 1039 inst->Opcode = OPCODE_MOV; 1040 inst->DstReg.WriteMask = WRITEMASK_XYZW; 1041 inst->SrcReg[0].Swizzle = SWIZZLE_XYZW; 1042 inst->SrcReg[0].Negate = NEGATE_NONE; 1043#endif 1044 1045#if 0 1046 /* disable shadow texture mode */ 1047 inst->TexShadow = 0; 1048#endif 1049 } 1050 1051 if (inst->Opcode == OPCODE_TXP) { 1052#if 0 1053 inst->Opcode = OPCODE_MOV; 1054 inst->DstReg.WriteMask = WRITEMASK_XYZW; 1055 inst->SrcReg[0].File = PROGRAM_CONSTANT; 1056 inst->SrcReg[0].Index = whiteIndex; 1057 inst->SrcReg[0].Swizzle = SWIZZLE_XYZW; 1058 inst->SrcReg[0].Negate = NEGATE_NONE; 1059#endif 1060#if 0 1061 inst->TexShadow = 0; 1062#endif 1063#if 0 1064 inst->Opcode = OPCODE_TEX; 1065 inst->TexShadow = 0; 1066#endif 1067 } 1068 1069 } 1070} 1071