arbprogram.c revision 412cddf954d35282f913d01d83d3cdb45cf0e2d0
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 "shader/arbprogparse.h" 40#include "shader/nvfragparse.h" 41#include "shader/nvvertparse.h" 42#include "shader/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 */ 54static GLboolean 55compatible_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 */ 72void 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 (struct 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 (struct 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 */ 163void 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 */ 218void 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 */ 255GLboolean 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 273void GLAPIENTRY 274_mesa_ProgramStringARB(GLenum target, GLenum format, GLsizei len, 275 const GLvoid *string) 276{ 277 struct gl_program *base; 278 GET_CURRENT_CONTEXT(ctx); 279 ASSERT_OUTSIDE_BEGIN_END(ctx); 280 281 FLUSH_VERTICES(ctx, _NEW_PROGRAM); 282 283 if (!ctx->Extensions.ARB_vertex_program 284 && !ctx->Extensions.ARB_fragment_program) { 285 _mesa_error(ctx, GL_INVALID_OPERATION, "glProgramStringARB()"); 286 return; 287 } 288 289 if (format != GL_PROGRAM_FORMAT_ASCII_ARB) { 290 _mesa_error(ctx, GL_INVALID_ENUM, "glProgramStringARB(format)"); 291 return; 292 } 293 294 /* The first couple cases are complicated. The same enum value is used for 295 * ARB and NV vertex programs. If the target is a vertex program, parse it 296 * using the ARB grammar if the string starts with "!!ARB" or if 297 * NV_vertex_program is not supported. 298 */ 299 if (target == GL_VERTEX_PROGRAM_ARB 300 && ctx->Extensions.ARB_vertex_program 301 && ((strncmp(string, "!!ARB", 5) == 0) 302 || !ctx->Extensions.NV_vertex_program)) { 303 struct gl_vertex_program *prog = ctx->VertexProgram.Current; 304 _mesa_parse_arb_vertex_program(ctx, target, string, len, prog); 305 306 base = & prog->Base; 307 } 308 else if ((target == GL_VERTEX_PROGRAM_ARB 309 || target == GL_VERTEX_STATE_PROGRAM_NV) 310 && ctx->Extensions.NV_vertex_program) { 311 struct gl_vertex_program *prog = ctx->VertexProgram.Current; 312 _mesa_parse_nv_vertex_program(ctx, target, string, len, prog); 313 314 base = & prog->Base; 315 } 316 else if (target == GL_FRAGMENT_PROGRAM_ARB 317 && ctx->Extensions.ARB_fragment_program) { 318 struct gl_fragment_program *prog = ctx->FragmentProgram.Current; 319 _mesa_parse_arb_fragment_program(ctx, target, string, len, prog); 320 321 base = & prog->Base; 322 } 323 else if (target == GL_FRAGMENT_PROGRAM_NV 324 && ctx->Extensions.NV_fragment_program) { 325 struct gl_fragment_program *prog = ctx->FragmentProgram.Current; 326 _mesa_parse_nv_fragment_program(ctx, target, string, len, prog); 327 328 base = & prog->Base; 329 } 330 else { 331 _mesa_error(ctx, GL_INVALID_ENUM, "glProgramStringARB(target)"); 332 return; 333 } 334 335 if (ctx->Program.ErrorPos == -1) { 336 /* finally, give the program to the driver for translation/checking */ 337 if (!ctx->Driver.ProgramStringNotify(ctx, target, base)) { 338 _mesa_error(ctx, GL_INVALID_OPERATION, 339 "glProgramStringARB(rejected by driver"); 340 } 341 } 342} 343 344 345/** 346 * Set a program env parameter register. 347 * \note Called from the GL API dispatcher. 348 * Note, this function is also used by the GL_NV_vertex_program extension 349 * (alias to ProgramParameterdNV) 350 */ 351void GLAPIENTRY 352_mesa_ProgramEnvParameter4dARB(GLenum target, GLuint index, 353 GLdouble x, GLdouble y, GLdouble z, GLdouble w) 354{ 355 _mesa_ProgramEnvParameter4fARB(target, index, (GLfloat) x, (GLfloat) y, 356 (GLfloat) z, (GLfloat) w); 357} 358 359 360/** 361 * Set a program env parameter register. 362 * \note Called from the GL API dispatcher. 363 * Note, this function is also used by the GL_NV_vertex_program extension 364 * (alias to ProgramParameterdvNV) 365 */ 366void GLAPIENTRY 367_mesa_ProgramEnvParameter4dvARB(GLenum target, GLuint index, 368 const GLdouble *params) 369{ 370 _mesa_ProgramEnvParameter4fARB(target, index, (GLfloat) params[0], 371 (GLfloat) params[1], (GLfloat) params[2], 372 (GLfloat) params[3]); 373} 374 375 376/** 377 * Set a program env parameter register. 378 * \note Called from the GL API dispatcher. 379 * Note, this function is also used by the GL_NV_vertex_program extension 380 * (alias to ProgramParameterfNV) 381 */ 382void GLAPIENTRY 383_mesa_ProgramEnvParameter4fARB(GLenum target, GLuint index, 384 GLfloat x, GLfloat y, GLfloat z, GLfloat w) 385{ 386 GET_CURRENT_CONTEXT(ctx); 387 ASSERT_OUTSIDE_BEGIN_END(ctx); 388 389 FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS); 390 391 if (target == GL_FRAGMENT_PROGRAM_ARB 392 && ctx->Extensions.ARB_fragment_program) { 393 if (index >= ctx->Const.FragmentProgram.MaxEnvParams) { 394 _mesa_error(ctx, GL_INVALID_VALUE, "glProgramEnvParameter(index)"); 395 return; 396 } 397 ASSIGN_4V(ctx->FragmentProgram.Parameters[index], x, y, z, w); 398 } 399 else if (target == GL_VERTEX_PROGRAM_ARB /* == GL_VERTEX_PROGRAM_NV */ 400 && (ctx->Extensions.ARB_vertex_program || ctx->Extensions.NV_vertex_program)) { 401 if (index >= ctx->Const.VertexProgram.MaxEnvParams) { 402 _mesa_error(ctx, GL_INVALID_VALUE, "glProgramEnvParameter(index)"); 403 return; 404 } 405 ASSIGN_4V(ctx->VertexProgram.Parameters[index], x, y, z, w); 406 } 407 else { 408 _mesa_error(ctx, GL_INVALID_ENUM, "glProgramEnvParameter(target)"); 409 return; 410 } 411} 412 413 414 415/** 416 * Set a program env parameter register. 417 * \note Called from the GL API dispatcher. 418 * Note, this function is also used by the GL_NV_vertex_program extension 419 * (alias to ProgramParameterfvNV) 420 */ 421void GLAPIENTRY 422_mesa_ProgramEnvParameter4fvARB(GLenum target, GLuint index, 423 const GLfloat *params) 424{ 425 GET_CURRENT_CONTEXT(ctx); 426 ASSERT_OUTSIDE_BEGIN_END(ctx); 427 428 FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS); 429 430 if (target == GL_FRAGMENT_PROGRAM_ARB 431 && ctx->Extensions.ARB_fragment_program) { 432 if (index >= ctx->Const.FragmentProgram.MaxEnvParams) { 433 _mesa_error(ctx, GL_INVALID_VALUE, "glProgramEnvParameter4fv(index)"); 434 return; 435 } 436 memcpy(ctx->FragmentProgram.Parameters[index], params, 437 4 * sizeof(GLfloat)); 438 } 439 else if (target == GL_VERTEX_PROGRAM_ARB /* == GL_VERTEX_PROGRAM_NV */ 440 && (ctx->Extensions.ARB_vertex_program || ctx->Extensions.NV_vertex_program)) { 441 if (index >= ctx->Const.VertexProgram.MaxEnvParams) { 442 _mesa_error(ctx, GL_INVALID_VALUE, "glProgramEnvParameter4fv(index)"); 443 return; 444 } 445 memcpy(ctx->VertexProgram.Parameters[index], params, 446 4 * sizeof(GLfloat)); 447 } 448 else { 449 _mesa_error(ctx, GL_INVALID_ENUM, "glProgramEnvParameter4fv(target)"); 450 return; 451 } 452} 453 454 455void GLAPIENTRY 456_mesa_ProgramEnvParameters4fvEXT(GLenum target, GLuint index, GLsizei count, 457 const GLfloat *params) 458{ 459 GET_CURRENT_CONTEXT(ctx); 460 GLfloat * dest; 461 ASSERT_OUTSIDE_BEGIN_END(ctx); 462 463 FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS); 464 465 if (count <= 0) { 466 _mesa_error(ctx, GL_INVALID_VALUE, "glProgramEnvParameters4fv(count)"); 467 } 468 469 if (target == GL_FRAGMENT_PROGRAM_ARB 470 && ctx->Extensions.ARB_fragment_program) { 471 if ((index + count) > ctx->Const.FragmentProgram.MaxEnvParams) { 472 _mesa_error(ctx, GL_INVALID_VALUE, "glProgramEnvParameters4fv(index + count)"); 473 return; 474 } 475 dest = ctx->FragmentProgram.Parameters[index]; 476 } 477 else if (target == GL_VERTEX_PROGRAM_ARB 478 && ctx->Extensions.ARB_vertex_program) { 479 if ((index + count) > ctx->Const.VertexProgram.MaxEnvParams) { 480 _mesa_error(ctx, GL_INVALID_VALUE, "glProgramEnvParameters4fv(index + count)"); 481 return; 482 } 483 dest = ctx->VertexProgram.Parameters[index]; 484 } 485 else { 486 _mesa_error(ctx, GL_INVALID_ENUM, "glProgramEnvParameters4fv(target)"); 487 return; 488 } 489 490 memcpy(dest, params, count * 4 * sizeof(GLfloat)); 491} 492 493 494void GLAPIENTRY 495_mesa_GetProgramEnvParameterdvARB(GLenum target, GLuint index, 496 GLdouble *params) 497{ 498 GET_CURRENT_CONTEXT(ctx); 499 GLfloat fparams[4]; 500 501 _mesa_GetProgramEnvParameterfvARB(target, index, fparams); 502 if (ctx->ErrorValue == GL_NO_ERROR) { 503 params[0] = fparams[0]; 504 params[1] = fparams[1]; 505 params[2] = fparams[2]; 506 params[3] = fparams[3]; 507 } 508} 509 510 511void GLAPIENTRY 512_mesa_GetProgramEnvParameterfvARB(GLenum target, GLuint index, 513 GLfloat *params) 514{ 515 GET_CURRENT_CONTEXT(ctx); 516 517 ASSERT_OUTSIDE_BEGIN_END(ctx); 518 519 if (target == GL_FRAGMENT_PROGRAM_ARB 520 && ctx->Extensions.ARB_fragment_program) { 521 if (index >= ctx->Const.FragmentProgram.MaxEnvParams) { 522 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramEnvParameter(index)"); 523 return; 524 } 525 COPY_4V(params, ctx->FragmentProgram.Parameters[index]); 526 } 527 else if (target == GL_VERTEX_PROGRAM_ARB 528 && ctx->Extensions.ARB_vertex_program) { 529 if (index >= ctx->Const.VertexProgram.MaxEnvParams) { 530 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramEnvParameter(index)"); 531 return; 532 } 533 COPY_4V(params, ctx->VertexProgram.Parameters[index]); 534 } 535 else { 536 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramEnvParameter(target)"); 537 return; 538 } 539} 540 541 542/** 543 * Note, this function is also used by the GL_NV_fragment_program extension. 544 */ 545void GLAPIENTRY 546_mesa_ProgramLocalParameter4fARB(GLenum target, GLuint index, 547 GLfloat x, GLfloat y, GLfloat z, GLfloat w) 548{ 549 GET_CURRENT_CONTEXT(ctx); 550 struct gl_program *prog; 551 ASSERT_OUTSIDE_BEGIN_END(ctx); 552 553 FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS); 554 555 if ((target == GL_FRAGMENT_PROGRAM_NV 556 && ctx->Extensions.NV_fragment_program) || 557 (target == GL_FRAGMENT_PROGRAM_ARB 558 && ctx->Extensions.ARB_fragment_program)) { 559 if (index >= ctx->Const.FragmentProgram.MaxLocalParams) { 560 _mesa_error(ctx, GL_INVALID_VALUE, "glProgramLocalParameterARB"); 561 return; 562 } 563 prog = &(ctx->FragmentProgram.Current->Base); 564 } 565 else if (target == GL_VERTEX_PROGRAM_ARB 566 && ctx->Extensions.ARB_vertex_program) { 567 if (index >= ctx->Const.VertexProgram.MaxLocalParams) { 568 _mesa_error(ctx, GL_INVALID_VALUE, "glProgramLocalParameterARB"); 569 return; 570 } 571 prog = &(ctx->VertexProgram.Current->Base); 572 } 573 else { 574 _mesa_error(ctx, GL_INVALID_ENUM, "glProgramLocalParameterARB"); 575 return; 576 } 577 578 ASSERT(index < MAX_PROGRAM_LOCAL_PARAMS); 579 prog->LocalParams[index][0] = x; 580 prog->LocalParams[index][1] = y; 581 prog->LocalParams[index][2] = z; 582 prog->LocalParams[index][3] = w; 583} 584 585 586/** 587 * Note, this function is also used by the GL_NV_fragment_program extension. 588 */ 589void GLAPIENTRY 590_mesa_ProgramLocalParameter4fvARB(GLenum target, GLuint index, 591 const GLfloat *params) 592{ 593 _mesa_ProgramLocalParameter4fARB(target, index, params[0], params[1], 594 params[2], params[3]); 595} 596 597 598void GLAPIENTRY 599_mesa_ProgramLocalParameters4fvEXT(GLenum target, GLuint index, GLsizei count, 600 const GLfloat *params) 601{ 602 GET_CURRENT_CONTEXT(ctx); 603 GLfloat *dest; 604 ASSERT_OUTSIDE_BEGIN_END(ctx); 605 606 FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS); 607 608 if (count <= 0) { 609 _mesa_error(ctx, GL_INVALID_VALUE, "glProgramLocalParameters4fv(count)"); 610 } 611 612 if (target == GL_FRAGMENT_PROGRAM_ARB 613 && ctx->Extensions.ARB_fragment_program) { 614 if ((index + count) > ctx->Const.FragmentProgram.MaxLocalParams) { 615 _mesa_error(ctx, GL_INVALID_VALUE, "glProgramLocalParameters4fvEXT(index + count)"); 616 return; 617 } 618 dest = ctx->FragmentProgram.Current->Base.LocalParams[index]; 619 } 620 else if (target == GL_VERTEX_PROGRAM_ARB 621 && ctx->Extensions.ARB_vertex_program) { 622 if ((index + count) > ctx->Const.VertexProgram.MaxLocalParams) { 623 _mesa_error(ctx, GL_INVALID_VALUE, "glProgramLocalParameters4fvEXT(index + count)"); 624 return; 625 } 626 dest = ctx->VertexProgram.Current->Base.LocalParams[index]; 627 } 628 else { 629 _mesa_error(ctx, GL_INVALID_ENUM, "glProgramLocalParameters4fvEXT(target)"); 630 return; 631 } 632 633 memcpy(dest, params, count * 4 * sizeof(GLfloat)); 634} 635 636 637/** 638 * Note, this function is also used by the GL_NV_fragment_program extension. 639 */ 640void GLAPIENTRY 641_mesa_ProgramLocalParameter4dARB(GLenum target, GLuint index, 642 GLdouble x, GLdouble y, 643 GLdouble z, GLdouble w) 644{ 645 _mesa_ProgramLocalParameter4fARB(target, index, (GLfloat) x, (GLfloat) y, 646 (GLfloat) z, (GLfloat) w); 647} 648 649 650/** 651 * Note, this function is also used by the GL_NV_fragment_program extension. 652 */ 653void GLAPIENTRY 654_mesa_ProgramLocalParameter4dvARB(GLenum target, GLuint index, 655 const GLdouble *params) 656{ 657 _mesa_ProgramLocalParameter4fARB(target, index, 658 (GLfloat) params[0], (GLfloat) params[1], 659 (GLfloat) params[2], (GLfloat) params[3]); 660} 661 662 663/** 664 * Note, this function is also used by the GL_NV_fragment_program extension. 665 */ 666void GLAPIENTRY 667_mesa_GetProgramLocalParameterfvARB(GLenum target, GLuint index, 668 GLfloat *params) 669{ 670 const struct gl_program *prog; 671 GLuint maxParams; 672 GET_CURRENT_CONTEXT(ctx); 673 ASSERT_OUTSIDE_BEGIN_END(ctx); 674 675 if (target == GL_VERTEX_PROGRAM_ARB 676 && ctx->Extensions.ARB_vertex_program) { 677 prog = &(ctx->VertexProgram.Current->Base); 678 maxParams = ctx->Const.VertexProgram.MaxLocalParams; 679 } 680 else if (target == GL_FRAGMENT_PROGRAM_ARB 681 && ctx->Extensions.ARB_fragment_program) { 682 prog = &(ctx->FragmentProgram.Current->Base); 683 maxParams = ctx->Const.FragmentProgram.MaxLocalParams; 684 } 685 else if (target == GL_FRAGMENT_PROGRAM_NV 686 && ctx->Extensions.NV_fragment_program) { 687 prog = &(ctx->FragmentProgram.Current->Base); 688 maxParams = MAX_NV_FRAGMENT_PROGRAM_PARAMS; 689 } 690 else { 691 _mesa_error(ctx, GL_INVALID_ENUM, 692 "glGetProgramLocalParameterARB(target)"); 693 return; 694 } 695 696 if (index >= maxParams) { 697 _mesa_error(ctx, GL_INVALID_VALUE, 698 "glGetProgramLocalParameterARB(index)"); 699 return; 700 } 701 702 ASSERT(prog); 703 ASSERT(index < MAX_PROGRAM_LOCAL_PARAMS); 704 COPY_4V(params, prog->LocalParams[index]); 705} 706 707 708/** 709 * Note, this function is also used by the GL_NV_fragment_program extension. 710 */ 711void GLAPIENTRY 712_mesa_GetProgramLocalParameterdvARB(GLenum target, GLuint index, 713 GLdouble *params) 714{ 715 GET_CURRENT_CONTEXT(ctx); 716 GLfloat floatParams[4]; 717 ASSIGN_4V(floatParams, 0.0F, 0.0F, 0.0F, 0.0F); 718 _mesa_GetProgramLocalParameterfvARB(target, index, floatParams); 719 if (ctx->ErrorValue == GL_NO_ERROR) { 720 COPY_4V(params, floatParams); 721 } 722} 723 724 725void GLAPIENTRY 726_mesa_GetProgramivARB(GLenum target, GLenum pname, GLint *params) 727{ 728 const struct gl_program_constants *limits; 729 struct gl_program *prog; 730 GET_CURRENT_CONTEXT(ctx); 731 732 ASSERT_OUTSIDE_BEGIN_END(ctx); 733 734 if (target == GL_VERTEX_PROGRAM_ARB 735 && ctx->Extensions.ARB_vertex_program) { 736 prog = &(ctx->VertexProgram.Current->Base); 737 limits = &ctx->Const.VertexProgram; 738 } 739 else if (target == GL_FRAGMENT_PROGRAM_ARB 740 && ctx->Extensions.ARB_fragment_program) { 741 prog = &(ctx->FragmentProgram.Current->Base); 742 limits = &ctx->Const.FragmentProgram; 743 } 744 else { 745 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramivARB(target)"); 746 return; 747 } 748 749 ASSERT(prog); 750 ASSERT(limits); 751 752 /* Queries supported for both vertex and fragment programs */ 753 switch (pname) { 754 case GL_PROGRAM_LENGTH_ARB: 755 *params 756 = prog->String ? (GLint) strlen((char *) prog->String) : 0; 757 return; 758 case GL_PROGRAM_FORMAT_ARB: 759 *params = prog->Format; 760 return; 761 case GL_PROGRAM_BINDING_ARB: 762 *params = prog->Id; 763 return; 764 case GL_PROGRAM_INSTRUCTIONS_ARB: 765 *params = prog->NumInstructions; 766 return; 767 case GL_MAX_PROGRAM_INSTRUCTIONS_ARB: 768 *params = limits->MaxInstructions; 769 return; 770 case GL_PROGRAM_NATIVE_INSTRUCTIONS_ARB: 771 *params = prog->NumNativeInstructions; 772 return; 773 case GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB: 774 *params = limits->MaxNativeInstructions; 775 return; 776 case GL_PROGRAM_TEMPORARIES_ARB: 777 *params = prog->NumTemporaries; 778 return; 779 case GL_MAX_PROGRAM_TEMPORARIES_ARB: 780 *params = limits->MaxTemps; 781 return; 782 case GL_PROGRAM_NATIVE_TEMPORARIES_ARB: 783 *params = prog->NumNativeTemporaries; 784 return; 785 case GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB: 786 *params = limits->MaxNativeTemps; 787 return; 788 case GL_PROGRAM_PARAMETERS_ARB: 789 *params = prog->NumParameters; 790 return; 791 case GL_MAX_PROGRAM_PARAMETERS_ARB: 792 *params = limits->MaxParameters; 793 return; 794 case GL_PROGRAM_NATIVE_PARAMETERS_ARB: 795 *params = prog->NumNativeParameters; 796 return; 797 case GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB: 798 *params = limits->MaxNativeParameters; 799 return; 800 case GL_PROGRAM_ATTRIBS_ARB: 801 *params = prog->NumAttributes; 802 return; 803 case GL_MAX_PROGRAM_ATTRIBS_ARB: 804 *params = limits->MaxAttribs; 805 return; 806 case GL_PROGRAM_NATIVE_ATTRIBS_ARB: 807 *params = prog->NumNativeAttributes; 808 return; 809 case GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB: 810 *params = limits->MaxNativeAttribs; 811 return; 812 case GL_PROGRAM_ADDRESS_REGISTERS_ARB: 813 *params = prog->NumAddressRegs; 814 return; 815 case GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB: 816 *params = limits->MaxAddressRegs; 817 return; 818 case GL_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB: 819 *params = prog->NumNativeAddressRegs; 820 return; 821 case GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB: 822 *params = limits->MaxNativeAddressRegs; 823 return; 824 case GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB: 825 *params = limits->MaxLocalParams; 826 return; 827 case GL_MAX_PROGRAM_ENV_PARAMETERS_ARB: 828 *params = limits->MaxEnvParams; 829 return; 830 case GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB: 831 /* 832 * XXX we may not really need a driver callback here. 833 * If the number of native instructions, registers, etc. used 834 * are all below the maximums, we could return true. 835 * The spec says that even if this query returns true, there's 836 * no guarantee that the program will run in hardware. 837 */ 838 if (prog->Id == 0) { 839 /* default/null program */ 840 *params = GL_FALSE; 841 } 842 else if (ctx->Driver.IsProgramNative) { 843 /* ask the driver */ 844 *params = ctx->Driver.IsProgramNative( ctx, target, prog ); 845 } 846 else { 847 /* probably running in software */ 848 *params = GL_TRUE; 849 } 850 return; 851 default: 852 /* continue with fragment-program only queries below */ 853 break; 854 } 855 856 /* 857 * The following apply to fragment programs only (at this time) 858 */ 859 if (target == GL_FRAGMENT_PROGRAM_ARB) { 860 const struct gl_fragment_program *fp = ctx->FragmentProgram.Current; 861 switch (pname) { 862 case GL_PROGRAM_ALU_INSTRUCTIONS_ARB: 863 *params = fp->Base.NumNativeAluInstructions; 864 return; 865 case GL_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB: 866 *params = fp->Base.NumAluInstructions; 867 return; 868 case GL_PROGRAM_TEX_INSTRUCTIONS_ARB: 869 *params = fp->Base.NumTexInstructions; 870 return; 871 case GL_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB: 872 *params = fp->Base.NumNativeTexInstructions; 873 return; 874 case GL_PROGRAM_TEX_INDIRECTIONS_ARB: 875 *params = fp->Base.NumTexIndirections; 876 return; 877 case GL_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB: 878 *params = fp->Base.NumNativeTexIndirections; 879 return; 880 case GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB: 881 *params = limits->MaxAluInstructions; 882 return; 883 case GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB: 884 *params = limits->MaxNativeAluInstructions; 885 return; 886 case GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB: 887 *params = limits->MaxTexInstructions; 888 return; 889 case GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB: 890 *params = limits->MaxNativeTexInstructions; 891 return; 892 case GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB: 893 *params = limits->MaxTexIndirections; 894 return; 895 case GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB: 896 *params = limits->MaxNativeTexIndirections; 897 return; 898 default: 899 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramivARB(pname)"); 900 return; 901 } 902 } else { 903 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramivARB(pname)"); 904 return; 905 } 906} 907 908 909void GLAPIENTRY 910_mesa_GetProgramStringARB(GLenum target, GLenum pname, GLvoid *string) 911{ 912 const struct gl_program *prog; 913 char *dst = (char *) string; 914 GET_CURRENT_CONTEXT(ctx); 915 916 ASSERT_OUTSIDE_BEGIN_END(ctx); 917 918 if (target == GL_VERTEX_PROGRAM_ARB) { 919 prog = &(ctx->VertexProgram.Current->Base); 920 } 921 else if (target == GL_FRAGMENT_PROGRAM_ARB) { 922 prog = &(ctx->FragmentProgram.Current->Base); 923 } 924 else { 925 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramStringARB(target)"); 926 return; 927 } 928 929 ASSERT(prog); 930 931 if (pname != GL_PROGRAM_STRING_ARB) { 932 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramStringARB(pname)"); 933 return; 934 } 935 936 if (prog->String) 937 memcpy(dst, prog->String, strlen((char *) prog->String)); 938 else 939 *dst = '\0'; 940} 941