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