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