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