Home | History | Annotate | Download | only in main
      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, &param)) {
    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, &param)) {
    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, &param)) {
    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, &param)) {
    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, &param)) {
    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, &param)) {
    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