arbprogram.c revision 01e04c3f
1/* 2 * Mesa 3-D graphics library 3 * 4 * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included 14 * in all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 * OTHER DEALINGS IN THE SOFTWARE. 23 */ 24 25/** 26 * \file arbprogram.c 27 * ARB_vertex/fragment_program state management functions. 28 * \author Brian Paul 29 */ 30 31 32#include "main/glheader.h" 33#include "main/context.h" 34#include "main/hash.h" 35#include "main/imports.h" 36#include "main/macros.h" 37#include "main/mtypes.h" 38#include "main/arbprogram.h" 39#include "main/shaderapi.h" 40#include "main/state.h" 41#include "program/arbprogparse.h" 42#include "program/program.h" 43#include "program/prog_print.h" 44 45static void 46flush_vertices_for_program_constants(struct gl_context *ctx, GLenum target) 47{ 48 uint64_t new_driver_state; 49 50 if (target == GL_FRAGMENT_PROGRAM_ARB) { 51 new_driver_state = 52 ctx->DriverFlags.NewShaderConstants[MESA_SHADER_FRAGMENT]; 53 } else { 54 new_driver_state = 55 ctx->DriverFlags.NewShaderConstants[MESA_SHADER_VERTEX]; 56 } 57 58 FLUSH_VERTICES(ctx, new_driver_state ? 0 : _NEW_PROGRAM_CONSTANTS); 59 ctx->NewDriverState |= new_driver_state; 60} 61 62/** 63 * Bind a program (make it current) 64 * \note Called from the GL API dispatcher by both glBindProgramNV 65 * and glBindProgramARB. 66 */ 67void GLAPIENTRY 68_mesa_BindProgramARB(GLenum target, GLuint id) 69{ 70 struct gl_program *curProg, *newProg; 71 GET_CURRENT_CONTEXT(ctx); 72 73 /* Error-check target and get curProg */ 74 if (target == GL_VERTEX_PROGRAM_ARB && ctx->Extensions.ARB_vertex_program) { 75 curProg = ctx->VertexProgram.Current; 76 } 77 else if (target == GL_FRAGMENT_PROGRAM_ARB 78 && ctx->Extensions.ARB_fragment_program) { 79 curProg = ctx->FragmentProgram.Current; 80 } 81 else { 82 _mesa_error(ctx, GL_INVALID_ENUM, "glBindProgramARB(target)"); 83 return; 84 } 85 86 /* 87 * Get pointer to new program to bind. 88 * NOTE: binding to a non-existant program is not an error. 89 * That's supposed to be caught in glBegin. 90 */ 91 if (id == 0) { 92 /* Bind a default program */ 93 newProg = NULL; 94 if (target == GL_VERTEX_PROGRAM_ARB) 95 newProg = ctx->Shared->DefaultVertexProgram; 96 else 97 newProg = ctx->Shared->DefaultFragmentProgram; 98 } 99 else { 100 /* Bind a user program */ 101 newProg = _mesa_lookup_program(ctx, id); 102 if (!newProg || newProg == &_mesa_DummyProgram) { 103 /* allocate a new program now */ 104 newProg = ctx->Driver.NewProgram(ctx, target, id, true); 105 if (!newProg) { 106 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindProgramARB"); 107 return; 108 } 109 _mesa_HashInsert(ctx->Shared->Programs, id, newProg); 110 } 111 else if (newProg->Target != target) { 112 _mesa_error(ctx, GL_INVALID_OPERATION, 113 "glBindProgramARB(target mismatch)"); 114 return; 115 } 116 } 117 118 /** All error checking is complete now **/ 119 120 if (curProg->Id == id) { 121 /* binding same program - no change */ 122 return; 123 } 124 125 /* signal new program (and its new constants) */ 126 FLUSH_VERTICES(ctx, _NEW_PROGRAM); 127 flush_vertices_for_program_constants(ctx, target); 128 129 /* bind newProg */ 130 if (target == GL_VERTEX_PROGRAM_ARB) { 131 _mesa_reference_program(ctx, &ctx->VertexProgram.Current, newProg); 132 } 133 else if (target == GL_FRAGMENT_PROGRAM_ARB) { 134 _mesa_reference_program(ctx, &ctx->FragmentProgram.Current, newProg); 135 } 136 137 _mesa_update_vertex_processing_mode(ctx); 138 139 /* Never null pointers */ 140 assert(ctx->VertexProgram.Current); 141 assert(ctx->FragmentProgram.Current); 142} 143 144 145/** 146 * Delete a list of programs. 147 * \note Not compiled into display lists. 148 * \note Called by both glDeleteProgramsNV and glDeleteProgramsARB. 149 */ 150void GLAPIENTRY 151_mesa_DeleteProgramsARB(GLsizei n, const GLuint *ids) 152{ 153 GLint i; 154 GET_CURRENT_CONTEXT(ctx); 155 156 FLUSH_VERTICES(ctx, 0); 157 158 if (n < 0) { 159 _mesa_error( ctx, GL_INVALID_VALUE, "glDeleteProgramsNV" ); 160 return; 161 } 162 163 for (i = 0; i < n; i++) { 164 if (ids[i] != 0) { 165 struct gl_program *prog = _mesa_lookup_program(ctx, ids[i]); 166 if (prog == &_mesa_DummyProgram) { 167 _mesa_HashRemove(ctx->Shared->Programs, ids[i]); 168 } 169 else if (prog) { 170 /* Unbind program if necessary */ 171 switch (prog->Target) { 172 case GL_VERTEX_PROGRAM_ARB: 173 if (ctx->VertexProgram.Current && 174 ctx->VertexProgram.Current->Id == ids[i]) { 175 /* unbind this currently bound program */ 176 _mesa_BindProgramARB(prog->Target, 0); 177 } 178 break; 179 case GL_FRAGMENT_PROGRAM_ARB: 180 if (ctx->FragmentProgram.Current && 181 ctx->FragmentProgram.Current->Id == ids[i]) { 182 /* unbind this currently bound program */ 183 _mesa_BindProgramARB(prog->Target, 0); 184 } 185 break; 186 default: 187 _mesa_problem(ctx, "bad target in glDeleteProgramsNV"); 188 return; 189 } 190 /* The ID is immediately available for re-use now */ 191 _mesa_HashRemove(ctx->Shared->Programs, ids[i]); 192 _mesa_reference_program(ctx, &prog, NULL); 193 } 194 } 195 } 196} 197 198 199/** 200 * Generate a list of new program identifiers. 201 * \note Not compiled into display lists. 202 * \note Called by both glGenProgramsNV and glGenProgramsARB. 203 */ 204void GLAPIENTRY 205_mesa_GenProgramsARB(GLsizei n, GLuint *ids) 206{ 207 GLuint first; 208 GLuint i; 209 GET_CURRENT_CONTEXT(ctx); 210 211 if (n < 0) { 212 _mesa_error(ctx, GL_INVALID_VALUE, "glGenPrograms"); 213 return; 214 } 215 216 if (!ids) 217 return; 218 219 _mesa_HashLockMutex(ctx->Shared->Programs); 220 221 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->Programs, n); 222 223 /* Insert pointer to dummy program as placeholder */ 224 for (i = 0; i < (GLuint) n; i++) { 225 _mesa_HashInsertLocked(ctx->Shared->Programs, first + i, 226 &_mesa_DummyProgram); 227 } 228 229 _mesa_HashUnlockMutex(ctx->Shared->Programs); 230 231 /* Return the program names */ 232 for (i = 0; i < (GLuint) n; i++) { 233 ids[i] = first + i; 234 } 235} 236 237 238/** 239 * Determine if id names a vertex or fragment program. 240 * \note Not compiled into display lists. 241 * \note Called from both glIsProgramNV and glIsProgramARB. 242 * \param id is the program identifier 243 * \return GL_TRUE if id is a program, else GL_FALSE. 244 */ 245GLboolean GLAPIENTRY 246_mesa_IsProgramARB(GLuint id) 247{ 248 struct gl_program *prog = NULL; 249 GET_CURRENT_CONTEXT(ctx); 250 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 251 252 if (id == 0) 253 return GL_FALSE; 254 255 prog = _mesa_lookup_program(ctx, id); 256 if (prog && (prog != &_mesa_DummyProgram)) 257 return GL_TRUE; 258 else 259 return GL_FALSE; 260} 261 262static GLboolean 263get_local_param_pointer(struct gl_context *ctx, const char *func, 264 GLenum target, GLuint index, GLfloat **param) 265{ 266 struct gl_program *prog; 267 GLuint maxParams; 268 269 if (target == GL_VERTEX_PROGRAM_ARB 270 && ctx->Extensions.ARB_vertex_program) { 271 prog = ctx->VertexProgram.Current; 272 maxParams = ctx->Const.Program[MESA_SHADER_VERTEX].MaxLocalParams; 273 } 274 else if (target == GL_FRAGMENT_PROGRAM_ARB 275 && ctx->Extensions.ARB_fragment_program) { 276 prog = ctx->FragmentProgram.Current; 277 maxParams = ctx->Const.Program[MESA_SHADER_FRAGMENT].MaxLocalParams; 278 } 279 else { 280 _mesa_error(ctx, GL_INVALID_ENUM, 281 "%s(target)", func); 282 return GL_FALSE; 283 } 284 285 if (index >= maxParams) { 286 _mesa_error(ctx, GL_INVALID_VALUE, "%s(index)", func); 287 return GL_FALSE; 288 } 289 290 if (!prog->arb.LocalParams) { 291 prog->arb.LocalParams = rzalloc_array_size(prog, sizeof(float[4]), 292 maxParams); 293 if (!prog->arb.LocalParams) 294 return GL_FALSE; 295 } 296 297 *param = prog->arb.LocalParams[index]; 298 return GL_TRUE; 299} 300 301 302static GLboolean 303get_env_param_pointer(struct gl_context *ctx, const char *func, 304 GLenum target, GLuint index, GLfloat **param) 305{ 306 if (target == GL_FRAGMENT_PROGRAM_ARB 307 && ctx->Extensions.ARB_fragment_program) { 308 if (index >= ctx->Const.Program[MESA_SHADER_FRAGMENT].MaxEnvParams) { 309 _mesa_error(ctx, GL_INVALID_VALUE, "%s(index)", func); 310 return GL_FALSE; 311 } 312 *param = ctx->FragmentProgram.Parameters[index]; 313 return GL_TRUE; 314 } 315 else if (target == GL_VERTEX_PROGRAM_ARB && 316 ctx->Extensions.ARB_vertex_program) { 317 if (index >= ctx->Const.Program[MESA_SHADER_VERTEX].MaxEnvParams) { 318 _mesa_error(ctx, GL_INVALID_VALUE, "%s(index)", func); 319 return GL_FALSE; 320 } 321 *param = ctx->VertexProgram.Parameters[index]; 322 return GL_TRUE; 323 } else { 324 _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", func); 325 return GL_FALSE; 326 } 327} 328 329void GLAPIENTRY 330_mesa_ProgramStringARB(GLenum target, GLenum format, GLsizei len, 331 const GLvoid *string) 332{ 333 struct gl_program *prog; 334 bool failed; 335 GET_CURRENT_CONTEXT(ctx); 336 337 FLUSH_VERTICES(ctx, _NEW_PROGRAM); 338 339 if (!ctx->Extensions.ARB_vertex_program 340 && !ctx->Extensions.ARB_fragment_program) { 341 _mesa_error(ctx, GL_INVALID_OPERATION, "glProgramStringARB()"); 342 return; 343 } 344 345 if (format != GL_PROGRAM_FORMAT_ASCII_ARB) { 346 _mesa_error(ctx, GL_INVALID_ENUM, "glProgramStringARB(format)"); 347 return; 348 } 349 350#ifdef ENABLE_SHADER_CACHE 351 GLcharARB *replacement; 352 353 gl_shader_stage stage = _mesa_program_enum_to_shader_stage(target); 354 355 /* Dump original shader source to MESA_SHADER_DUMP_PATH and replace 356 * if corresponding entry found from MESA_SHADER_READ_PATH. 357 */ 358 _mesa_dump_shader_source(stage, string); 359 360 replacement = _mesa_read_shader_source(stage, string); 361 if (replacement) 362 string = replacement; 363#endif /* ENABLE_SHADER_CACHE */ 364 365 if (target == GL_VERTEX_PROGRAM_ARB && ctx->Extensions.ARB_vertex_program) { 366 prog = ctx->VertexProgram.Current; 367 _mesa_parse_arb_vertex_program(ctx, target, string, len, prog); 368 } 369 else if (target == GL_FRAGMENT_PROGRAM_ARB 370 && ctx->Extensions.ARB_fragment_program) { 371 prog = ctx->FragmentProgram.Current; 372 _mesa_parse_arb_fragment_program(ctx, target, string, len, prog); 373 } 374 else { 375 _mesa_error(ctx, GL_INVALID_ENUM, "glProgramStringARB(target)"); 376 return; 377 } 378 379 failed = ctx->Program.ErrorPos != -1; 380 381 if (!failed) { 382 /* finally, give the program to the driver for translation/checking */ 383 if (!ctx->Driver.ProgramStringNotify(ctx, target, prog)) { 384 failed = true; 385 _mesa_error(ctx, GL_INVALID_OPERATION, 386 "glProgramStringARB(rejected by driver"); 387 } 388 } 389 390 _mesa_update_vertex_processing_mode(ctx); 391 392 if (ctx->_Shader->Flags & GLSL_DUMP) { 393 const char *shader_type = 394 target == GL_FRAGMENT_PROGRAM_ARB ? "fragment" : "vertex"; 395 396 fprintf(stderr, "ARB_%s_program source for program %d:\n", 397 shader_type, prog->Id); 398 fprintf(stderr, "%s\n", (const char *) string); 399 400 if (failed) { 401 fprintf(stderr, "ARB_%s_program %d failed to compile.\n", 402 shader_type, prog->Id); 403 } else { 404 fprintf(stderr, "Mesa IR for ARB_%s_program %d:\n", 405 shader_type, prog->Id); 406 _mesa_print_program(prog); 407 fprintf(stderr, "\n"); 408 } 409 fflush(stderr); 410 } 411 412 /* Capture vp-*.shader_test/fp-*.shader_test files. */ 413 const char *capture_path = _mesa_get_shader_capture_path(); 414 if (capture_path != NULL) { 415 FILE *file; 416 const char *shader_type = 417 target == GL_FRAGMENT_PROGRAM_ARB ? "fragment" : "vertex"; 418 char *filename = 419 ralloc_asprintf(NULL, "%s/%cp-%u.shader_test", 420 capture_path, shader_type[0], prog->Id); 421 422 file = fopen(filename, "w"); 423 if (file) { 424 fprintf(file, 425 "[require]\nGL_ARB_%s_program\n\n[%s program]\n%s\n", 426 shader_type, shader_type, (const char *) string); 427 fclose(file); 428 } else { 429 _mesa_warning(ctx, "Failed to open %s", filename); 430 } 431 ralloc_free(filename); 432 } 433} 434 435 436/** 437 * Set a program env parameter register. 438 * \note Called from the GL API dispatcher. 439 */ 440void GLAPIENTRY 441_mesa_ProgramEnvParameter4dARB(GLenum target, GLuint index, 442 GLdouble x, GLdouble y, GLdouble z, GLdouble w) 443{ 444 _mesa_ProgramEnvParameter4fARB(target, index, (GLfloat) x, (GLfloat) y, 445 (GLfloat) z, (GLfloat) w); 446} 447 448 449/** 450 * Set a program env parameter register. 451 * \note Called from the GL API dispatcher. 452 */ 453void GLAPIENTRY 454_mesa_ProgramEnvParameter4dvARB(GLenum target, GLuint index, 455 const GLdouble *params) 456{ 457 _mesa_ProgramEnvParameter4fARB(target, index, (GLfloat) params[0], 458 (GLfloat) params[1], (GLfloat) params[2], 459 (GLfloat) params[3]); 460} 461 462 463/** 464 * Set a program env parameter register. 465 * \note Called from the GL API dispatcher. 466 */ 467void GLAPIENTRY 468_mesa_ProgramEnvParameter4fARB(GLenum target, GLuint index, 469 GLfloat x, GLfloat y, GLfloat z, GLfloat w) 470{ 471 GLfloat *param; 472 473 GET_CURRENT_CONTEXT(ctx); 474 475 flush_vertices_for_program_constants(ctx, target); 476 477 if (get_env_param_pointer(ctx, "glProgramEnvParameter", 478 target, index, ¶m)) { 479 ASSIGN_4V(param, x, y, z, w); 480 } 481} 482 483 484 485/** 486 * Set a program env parameter register. 487 * \note Called from the GL API dispatcher. 488 */ 489void GLAPIENTRY 490_mesa_ProgramEnvParameter4fvARB(GLenum target, GLuint index, 491 const GLfloat *params) 492{ 493 GLfloat *param; 494 495 GET_CURRENT_CONTEXT(ctx); 496 497 flush_vertices_for_program_constants(ctx, target); 498 499 if (get_env_param_pointer(ctx, "glProgramEnvParameter4fv", 500 target, index, ¶m)) { 501 memcpy(param, params, 4 * sizeof(GLfloat)); 502 } 503} 504 505 506void GLAPIENTRY 507_mesa_ProgramEnvParameters4fvEXT(GLenum target, GLuint index, GLsizei count, 508 const GLfloat *params) 509{ 510 GET_CURRENT_CONTEXT(ctx); 511 GLfloat * dest; 512 513 flush_vertices_for_program_constants(ctx, target); 514 515 if (count <= 0) { 516 _mesa_error(ctx, GL_INVALID_VALUE, "glProgramEnvParameters4fv(count)"); 517 } 518 519 if (target == GL_FRAGMENT_PROGRAM_ARB 520 && ctx->Extensions.ARB_fragment_program) { 521 if ((index + count) > ctx->Const.Program[MESA_SHADER_FRAGMENT].MaxEnvParams) { 522 _mesa_error(ctx, GL_INVALID_VALUE, "glProgramEnvParameters4fv(index + count)"); 523 return; 524 } 525 dest = ctx->FragmentProgram.Parameters[index]; 526 } 527 else if (target == GL_VERTEX_PROGRAM_ARB 528 && ctx->Extensions.ARB_vertex_program) { 529 if ((index + count) > ctx->Const.Program[MESA_SHADER_VERTEX].MaxEnvParams) { 530 _mesa_error(ctx, GL_INVALID_VALUE, "glProgramEnvParameters4fv(index + count)"); 531 return; 532 } 533 dest = ctx->VertexProgram.Parameters[index]; 534 } 535 else { 536 _mesa_error(ctx, GL_INVALID_ENUM, "glProgramEnvParameters4fv(target)"); 537 return; 538 } 539 540 memcpy(dest, params, count * 4 * sizeof(GLfloat)); 541} 542 543 544void GLAPIENTRY 545_mesa_GetProgramEnvParameterdvARB(GLenum target, GLuint index, 546 GLdouble *params) 547{ 548 GET_CURRENT_CONTEXT(ctx); 549 GLfloat *fparam; 550 551 if (get_env_param_pointer(ctx, "glGetProgramEnvParameterdv", 552 target, index, &fparam)) { 553 COPY_4V(params, fparam); 554 } 555} 556 557 558void GLAPIENTRY 559_mesa_GetProgramEnvParameterfvARB(GLenum target, GLuint index, 560 GLfloat *params) 561{ 562 GLfloat *param; 563 564 GET_CURRENT_CONTEXT(ctx); 565 566 if (get_env_param_pointer(ctx, "glGetProgramEnvParameterfv", 567 target, index, ¶m)) { 568 COPY_4V(params, param); 569 } 570} 571 572 573void GLAPIENTRY 574_mesa_ProgramLocalParameter4fARB(GLenum target, GLuint index, 575 GLfloat x, GLfloat y, GLfloat z, GLfloat w) 576{ 577 GET_CURRENT_CONTEXT(ctx); 578 GLfloat *param; 579 580 flush_vertices_for_program_constants(ctx, target); 581 582 if (get_local_param_pointer(ctx, "glProgramLocalParameterARB", 583 target, index, ¶m)) { 584 assert(index < MAX_PROGRAM_LOCAL_PARAMS); 585 ASSIGN_4V(param, x, y, z, w); 586 } 587} 588 589 590void GLAPIENTRY 591_mesa_ProgramLocalParameter4fvARB(GLenum target, GLuint index, 592 const GLfloat *params) 593{ 594 _mesa_ProgramLocalParameter4fARB(target, index, params[0], params[1], 595 params[2], params[3]); 596} 597 598 599void GLAPIENTRY 600_mesa_ProgramLocalParameters4fvEXT(GLenum target, GLuint index, GLsizei count, 601 const GLfloat *params) 602{ 603 GET_CURRENT_CONTEXT(ctx); 604 GLfloat *dest; 605 606 flush_vertices_for_program_constants(ctx, target); 607 608 if (count <= 0) { 609 _mesa_error(ctx, GL_INVALID_VALUE, "glProgramLocalParameters4fv(count)"); 610 } 611 612 if (get_local_param_pointer(ctx, "glProgramLocalParameters4fvEXT", 613 target, index, &dest)) { 614 GLuint maxParams = target == GL_FRAGMENT_PROGRAM_ARB ? 615 ctx->Const.Program[MESA_SHADER_FRAGMENT].MaxLocalParams : 616 ctx->Const.Program[MESA_SHADER_VERTEX].MaxLocalParams; 617 618 if ((index + count) > maxParams) { 619 _mesa_error(ctx, GL_INVALID_VALUE, 620 "glProgramLocalParameters4fvEXT(index + count)"); 621 return; 622 } 623 624 memcpy(dest, params, count * 4 * sizeof(GLfloat)); 625 } 626} 627 628 629void GLAPIENTRY 630_mesa_ProgramLocalParameter4dARB(GLenum target, GLuint index, 631 GLdouble x, GLdouble y, 632 GLdouble z, GLdouble w) 633{ 634 _mesa_ProgramLocalParameter4fARB(target, index, (GLfloat) x, (GLfloat) y, 635 (GLfloat) z, (GLfloat) w); 636} 637 638 639void GLAPIENTRY 640_mesa_ProgramLocalParameter4dvARB(GLenum target, GLuint index, 641 const GLdouble *params) 642{ 643 _mesa_ProgramLocalParameter4fARB(target, index, 644 (GLfloat) params[0], (GLfloat) params[1], 645 (GLfloat) params[2], (GLfloat) params[3]); 646} 647 648 649void GLAPIENTRY 650_mesa_GetProgramLocalParameterfvARB(GLenum target, GLuint index, 651 GLfloat *params) 652{ 653 GLfloat *param; 654 GET_CURRENT_CONTEXT(ctx); 655 656 if (get_local_param_pointer(ctx, "glProgramLocalParameters4fvEXT", 657 target, index, ¶m)) { 658 COPY_4V(params, param); 659 } 660} 661 662 663void GLAPIENTRY 664_mesa_GetProgramLocalParameterdvARB(GLenum target, GLuint index, 665 GLdouble *params) 666{ 667 GLfloat *param; 668 GET_CURRENT_CONTEXT(ctx); 669 670 if (get_local_param_pointer(ctx, "glProgramLocalParameters4fvEXT", 671 target, index, ¶m)) { 672 COPY_4V(params, param); 673 } 674} 675 676 677void GLAPIENTRY 678_mesa_GetProgramivARB(GLenum target, GLenum pname, GLint *params) 679{ 680 const struct gl_program_constants *limits; 681 struct gl_program *prog; 682 GET_CURRENT_CONTEXT(ctx); 683 684 if (target == GL_VERTEX_PROGRAM_ARB 685 && ctx->Extensions.ARB_vertex_program) { 686 prog = ctx->VertexProgram.Current; 687 limits = &ctx->Const.Program[MESA_SHADER_VERTEX]; 688 } 689 else if (target == GL_FRAGMENT_PROGRAM_ARB 690 && ctx->Extensions.ARB_fragment_program) { 691 prog = ctx->FragmentProgram.Current; 692 limits = &ctx->Const.Program[MESA_SHADER_FRAGMENT]; 693 } 694 else { 695 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramivARB(target)"); 696 return; 697 } 698 699 assert(prog); 700 assert(limits); 701 702 /* Queries supported for both vertex and fragment programs */ 703 switch (pname) { 704 case GL_PROGRAM_LENGTH_ARB: 705 *params 706 = prog->String ? (GLint) strlen((char *) prog->String) : 0; 707 return; 708 case GL_PROGRAM_FORMAT_ARB: 709 *params = prog->Format; 710 return; 711 case GL_PROGRAM_BINDING_ARB: 712 *params = prog->Id; 713 return; 714 case GL_PROGRAM_INSTRUCTIONS_ARB: 715 *params = prog->arb.NumInstructions; 716 return; 717 case GL_MAX_PROGRAM_INSTRUCTIONS_ARB: 718 *params = limits->MaxInstructions; 719 return; 720 case GL_PROGRAM_NATIVE_INSTRUCTIONS_ARB: 721 *params = prog->arb.NumNativeInstructions; 722 return; 723 case GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB: 724 *params = limits->MaxNativeInstructions; 725 return; 726 case GL_PROGRAM_TEMPORARIES_ARB: 727 *params = prog->arb.NumTemporaries; 728 return; 729 case GL_MAX_PROGRAM_TEMPORARIES_ARB: 730 *params = limits->MaxTemps; 731 return; 732 case GL_PROGRAM_NATIVE_TEMPORARIES_ARB: 733 *params = prog->arb.NumNativeTemporaries; 734 return; 735 case GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB: 736 *params = limits->MaxNativeTemps; 737 return; 738 case GL_PROGRAM_PARAMETERS_ARB: 739 *params = prog->arb.NumParameters; 740 return; 741 case GL_MAX_PROGRAM_PARAMETERS_ARB: 742 *params = limits->MaxParameters; 743 return; 744 case GL_PROGRAM_NATIVE_PARAMETERS_ARB: 745 *params = prog->arb.NumNativeParameters; 746 return; 747 case GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB: 748 *params = limits->MaxNativeParameters; 749 return; 750 case GL_PROGRAM_ATTRIBS_ARB: 751 *params = prog->arb.NumAttributes; 752 return; 753 case GL_MAX_PROGRAM_ATTRIBS_ARB: 754 *params = limits->MaxAttribs; 755 return; 756 case GL_PROGRAM_NATIVE_ATTRIBS_ARB: 757 *params = prog->arb.NumNativeAttributes; 758 return; 759 case GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB: 760 *params = limits->MaxNativeAttribs; 761 return; 762 case GL_PROGRAM_ADDRESS_REGISTERS_ARB: 763 *params = prog->arb.NumAddressRegs; 764 return; 765 case GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB: 766 *params = limits->MaxAddressRegs; 767 return; 768 case GL_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB: 769 *params = prog->arb.NumNativeAddressRegs; 770 return; 771 case GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB: 772 *params = limits->MaxNativeAddressRegs; 773 return; 774 case GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB: 775 *params = limits->MaxLocalParams; 776 return; 777 case GL_MAX_PROGRAM_ENV_PARAMETERS_ARB: 778 *params = limits->MaxEnvParams; 779 return; 780 case GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB: 781 /* 782 * XXX we may not really need a driver callback here. 783 * If the number of native instructions, registers, etc. used 784 * are all below the maximums, we could return true. 785 * The spec says that even if this query returns true, there's 786 * no guarantee that the program will run in hardware. 787 */ 788 if (prog->Id == 0) { 789 /* default/null program */ 790 *params = GL_FALSE; 791 } 792 else if (ctx->Driver.IsProgramNative) { 793 /* ask the driver */ 794 *params = ctx->Driver.IsProgramNative( ctx, target, prog ); 795 } 796 else { 797 /* probably running in software */ 798 *params = GL_TRUE; 799 } 800 return; 801 default: 802 /* continue with fragment-program only queries below */ 803 break; 804 } 805 806 /* 807 * The following apply to fragment programs only (at this time) 808 */ 809 if (target == GL_FRAGMENT_PROGRAM_ARB) { 810 const struct gl_program *fp = ctx->FragmentProgram.Current; 811 switch (pname) { 812 case GL_PROGRAM_ALU_INSTRUCTIONS_ARB: 813 *params = fp->arb.NumNativeAluInstructions; 814 return; 815 case GL_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB: 816 *params = fp->arb.NumAluInstructions; 817 return; 818 case GL_PROGRAM_TEX_INSTRUCTIONS_ARB: 819 *params = fp->arb.NumTexInstructions; 820 return; 821 case GL_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB: 822 *params = fp->arb.NumNativeTexInstructions; 823 return; 824 case GL_PROGRAM_TEX_INDIRECTIONS_ARB: 825 *params = fp->arb.NumTexIndirections; 826 return; 827 case GL_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB: 828 *params = fp->arb.NumNativeTexIndirections; 829 return; 830 case GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB: 831 *params = limits->MaxAluInstructions; 832 return; 833 case GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB: 834 *params = limits->MaxNativeAluInstructions; 835 return; 836 case GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB: 837 *params = limits->MaxTexInstructions; 838 return; 839 case GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB: 840 *params = limits->MaxNativeTexInstructions; 841 return; 842 case GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB: 843 *params = limits->MaxTexIndirections; 844 return; 845 case GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB: 846 *params = limits->MaxNativeTexIndirections; 847 return; 848 default: 849 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramivARB(pname)"); 850 return; 851 } 852 } else { 853 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramivARB(pname)"); 854 return; 855 } 856} 857 858 859void GLAPIENTRY 860_mesa_GetProgramStringARB(GLenum target, GLenum pname, GLvoid *string) 861{ 862 const struct gl_program *prog; 863 char *dst = (char *) string; 864 GET_CURRENT_CONTEXT(ctx); 865 866 if (target == GL_VERTEX_PROGRAM_ARB) { 867 prog = ctx->VertexProgram.Current; 868 } 869 else if (target == GL_FRAGMENT_PROGRAM_ARB) { 870 prog = ctx->FragmentProgram.Current; 871 } 872 else { 873 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramStringARB(target)"); 874 return; 875 } 876 877 assert(prog); 878 879 if (pname != GL_PROGRAM_STRING_ARB) { 880 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramStringARB(pname)"); 881 return; 882 } 883 884 if (prog->String) 885 memcpy(dst, prog->String, strlen((char *) prog->String)); 886 else 887 *dst = '\0'; 888} 889