back  Return to list

GL_NV_vertex_program
homeprevnext Name
      
    NV_vertex_program  
  
homeprevnext Name Strings
  
    GL_NV_vertex_program  
  
homeprevnext Contact
  
    Mark J. Kilgard, NVIDIA Corporation (mjk 'at' nvidia.com)  
  
homeprevnext Notice
  
    Copyright NVIDIA Corporation, 2000, 2001, 2002, 2003, 2004.  
  
homeprevnext IP Status
  
    NVIDIA Proprietary.  
  
homeprevnext Status
  
    Version 1.9  
  
homeprevnext Version
  
    NVIDIA Date: February 24, 2004  
    $Date$ $Revision$  
    $Id: //sw/main/docs/OpenGL/specs/GL_NV_vertex_program.txt#20 $  
  
homeprevnext Number
  
    233  
  
homeprevnext Dependencies
  
    Written based on the wording of the OpenGL 1.2.1 specification and  
    requires OpenGL 1.2.1.  
  
    Requires support for the ARB_multitexture extension with at least  
    two texture units.  
  
    EXT_point_parameters affects the definition of this extension.  
  
    EXT_secondary_color affects the definition of this extension.  
  
    EXT_fog_coord affects the definition of this extension.  
  
    EXT_vertex_weighting affects the definition of this extension.  
  
    ARB_imaging affects the definition of this extension.  
  
homeprevnext Overview
  
    Unextended OpenGL mandates a certain set of configurable per-vertex  
    computations defining vertex transformation, texture coordinate  
    generation and transformation, and lighting.  Several extensions  
    have added further per-vertex computations to OpenGL.  For example,  
    extensions have defined new texture coordinate generation modes  
    (ARB_texture_cube_map, NV_texgen_reflection, NV_texgen_emboss), new  
    vertex transformation modes (EXT_vertex_weighting), new lighting modes  
    (OpenGL 1.2's separate specular and rescale normal functionality),  
    several modes for fog distance generation (NV_fog_distance), and  
    eye-distance point size attenuation (EXT_point_parameters).  
  
    Each such extension adds a small set of relatively inflexible  
    per-vertex computations.  
  
    This inflexibility is in contrast to the typical flexibility provided  
    by the underlying programmable floating point engines (whether  
    micro-coded vertex engines, DSPs, or CPUs) that are traditionally used  
    to implement OpenGL's per-vertex computations.  The purpose of this  
    extension is to expose to the OpenGL application writer a significant  
    degree of per-vertex programmability for computing vertex parameters.  
  
    For the purposes of discussing this extension, a vertex program is  
    a sequence of floating-point 4-component vector operations that  
    determines how a set of program parameters (defined outside of  
    OpenGL's begin/end pair) and an input set of per-vertex parameters  
    are transformed to a set of per-vertex output parameters.  
  
    The per-vertex computations for standard OpenGL given a particular  
    set of lighting and texture coordinate generation modes (along with  
    any state for extensions defining per-vertex computations) is, in  
    essence, a vertex program.  However, the sequence of operations is  
    defined implicitly by the current OpenGL state settings rather than  
    defined explicitly as a sequence of instructions.  
  
    This extension provides an explicit mechanism for defining vertex  
    program instruction sequences for application-defined vertex programs.  
    In order to define such vertex programs, this extension defines  
    a vertex programming model including a floating-point 4-component  
    vector instruction set and a relatively large set of floating-point  
    4-component registers.  
  
    The extension's vertex programming model is designed for efficient  
    hardware implementation and to support a wide variety of vertex  
    programs.  By design, the entire set of existing vertex programs  
    defined by existing OpenGL per-vertex computation extensions can be  
    implemented using the extension's vertex programming model.  
  
homeprevnext Issues
  
    What should this extension be called?  
  
      RESOLUTION:  NV_vertex_program.  DirectX 8 refers to its similar  
      functionality as "vertex shaders".  This is a confusing term  
      because shaders are usually assumed to operate at the fragment or  
      pixel level, not the vertex level.  
  
      Conceptually, what the extension defines is an application-defined  
      program (admittedly limited by its sequential execution model) for  
      processing vertices so the "vertex program" term is more accurate.  
  
      Additionally, some of the API machinery in this extension for  
      describing programs could be useful for extending other OpenGL  
      operations with programs (though other types of programs would  
      likely look very different from vertex programs).  
  
    What terms are important to this specification?  
  
      vertex program mode - when vertex program mode is enabled, vertices  
      are transformed by an application-defined vertex program.  
  
      conventional GL vertex transform mode - when vertex program mode  
      is disabled (or the extension is not supported), vertices are  
      transformed by GL's conventional texgen, lighting, and transform  
      state.  
  
      provoke - the verb that denotes the beginning of vertex  
      transformation by either vertex program mode or conventional GL  
      vertex transform mode.  Vertices are provoked when either glVertex  
      or glVertexAttribNV(0, ...) is called.  
  
      program target - a type or class of program.  This extension  
      supports two program targets:  the vertex program and the vertex  
      state program.  Future extensions could add other program targets.  
  
      vertex program -  an application-defined vertex program used to  
      transform vertices when vertex program mode is enabled.  
  
      vertex state program - a program similar to a vertex program.  
      Unlike a vertex program, a vertex state program runs outside of  
      a glBegin/glEnd pair.  Vertex state programs do not transform  
      a vertex.  They just update program parameters.  
  
      vertex attribute - one of 16 4-component per-vertex parameters  
      defined by this extension.  These attributes alias with the  
      conventional per-vertex parameters.  
  
      per-vertex parameter - a vertex attribute or a conventional  
      per-vertex parameter such as set by glNormal3f or glColor3f.  
  
      program parameter - one of 96 4-component registers available  
      to vertex programs.  The state of these registers is shared  
      among all vertex programs.  
  
    What part of OpenGL do vertex programs specifically bypass?  
  
      Vertex programs bypass the following OpenGL functionality:  
  
        o  Normal transformation and normalization  
  
        o  Color material  
  
        o  Per-vertex lighting  
  
        o  Texture coordinate generation  
  
        o  The texture matrix  
  
        o  The normalization of AUTO_NORMAL evaluated normals  
  
        o  The modelview and projection matrix transforms  
  
        o  The per-vertex processing in EXT_point_parameters  
  
        o  The per-vertex processing in NV_fog_distance  
  
        o  Raster position transformation  
  
        o  Client-defined clip planes  
  
      Operations not subsumed by vertex programs  
  
        o  The view frustum clip  
  
        o  Perspective divide (division by w)  
  
        o  The viewport transformation  
  
        o  The depth range transformation  
  
        o  Clamping the primary and secondary color to [0,1]  
  
        o  Primitive assembly and subsequent operations  
  
        o  Evaluator (except the AUTO_NORMAL normalization)  
  
    How specific should this specification be about precision?  
  
      RESOLUTION:  Reasonable precision requirements are incorporated  
      into the specification beyond the often vague requirements of the  
      core OpenGL specification.  
  
      This extension essentially defines an instruction set and its  
      corresponding execution environment.  The instruction set specified  
      may find applications beyond the traditional purposes of 3D vertex  
      transformation, lighting, and texture coordinate generation that  
      have fairly lax precision requirements.  To facilitate such  
      possibly unexpected applications of this functionality, minimum  
      precision requirements are specified.  
  
      The minimum precision requirements in the specification are meant  
      to serve as a baseline so that application developers can write  
      vertex programs with minimal worries about precision issues.  
  
    What about when the "execution environment" involves support for  
    other extensions?  
  
      This extension assumes support for functionality that includes  
      a fog distance, secondary color, point parameters, and multiple  
      texture coordinates.  
  
      There is a trade-off between requiring support for these extensions  
      to guarantee a particular extended execution environment and  
      requiring lots of functionality that everyone might not support.  
  
      Application developers will desire a high baseline of functionality  
      so that OpenGL applications using vertex programs can work in  
      the full context of OpenGL.  But if too much is required, the  
      implementation burden mandated by the extension may limit the  
      number of available implementations.  
  
      Clearly we do not want to require support for 8 texture units  
      even if the machinery is there for it.  Still multitexture is a  
      common and important feature for using vertex programs effectively.  
      Requiring at least two texture units seems reasonable.  
  
    What do we say about the alpha component of the secondary color?  
  
      RESOLUTION:  When vertex program mode is enabled, the alpha  
      component of csec used for the color sum state is assumed always  
      zero.  Another downstream extension may actually make the alpha  
      component written into the COL1 (or BFC1) vertex result register  
      available.  
  
    Should client-defined clip planes operate when vertex program mode is  
    enabled?  
  
      RESOLUTION.  No.  
  
      OpenGL's client-defined clip planes are specified in eye-space.  
      Vertex programs generate homogeneous clip space positions.  
      Unlike the conventional OpenGL vertex transformation mode, vertex  
      program mode requires no semantic equivalent to eye-space.  
  
      Applications that require client-defined clip planes can simulate  
      OpenGL-style client-defined clip planes by generating texture  
      coordinates and using alpha testing or other per-fragment tests  
      such as NV_texture_shader's CULL_FRAGMENT_NV program to discard  
      fragments.  In many ways, these schemes provide a more flexible  
      mechanism for clipping than client-defined clip planes.  
  
      Unfortunately, vertex programs used in conjunction with selection  
      or feedback will not have a means to support client-defined clip  
      planes because the per-fragment culling mechanisms described in the  
      previous paragraph are not available in the selection or feedback  
      render modes.  Oh well.  
  
      Finally, as a practical concern, client-defined clip planes  
      greatly complicate clipping for various hardware rasterization  
      architectures.  
  
    How are edge flags handled?  
  
      RESOLUTION:  Passed through without the ability to be modified by  
      a vertex program.  Applications are free to send edge flags when  
      vertex program mode is enabled.  
  
    Should vertex attributes alias with conventional per-vertex  
    parameters?  
  
      RESOLUTION.  YES.  
  
      This aliasing should make it easy to use vertex programs with  
      existing OpenGL code that transfers per-vertex parameters using  
      conventional OpenGL per-vertex calls.  
  
      It also minimizes the number of per-vertex parameters that the  
      hardware must maintain.  
  
      See Table X.2 for the aliasing of vertex attributes and conventional  
      per-vertex parameters.  
  
    How should vertex attribute arrays interact with conventional vertex  
    arrays?  
  
      RESOLUTION:  When vertex program mode is enabled, a particular  
      vertex attribute array will be used if enabled, but if disabled,  
      and the corresponding aliased conventional vertex array is enabled  
      (assuming that there is a corresponding aliased conventional vertex  
      array for the particular vertex array), the conventional vertex  
      array will be used.  
  
      This matches the way immediate mode per-vertex parameter aliasing  
      works.  
  
      This does slightly complicate vertex array validation in program  
      mode, but programmers using vertex arrays can simply enable vertex  
      program mode without reconfiguring their conventional vertex arrays  
      and get what they expect.  
  
      Note that this does create an asymmetry between immediate mode  
      and vertex arrays depending on whether vertex program mode is  
      enabled or not.  The immediate mode vertex attribute commands  
      operate unchanged whether vertex program mode is enabled or not.  
      However the vertex attribute vertex arrays are used only when  
      vertex program mode is enabled.  
  
      Supporting vertex attribute vertex arrays when vertex program mode  
      is disabled would create a large implementation burden for existing  
      OpenGL implementations that have heavily optimized conventional  
      vertex arrays.  For example, the normal array can be assumed to  
      always contain 3 and only 3 components in conventional OpenGL  
      vertex transform mode, but may contain 1, 2, 3, or 4 components  
      in vertex program mode.  
  
      There is not any additional functionality gained by supporting  
      vertex attribute arrays when vertex program mode is disabled, but  
      there is lots of implementation overhead.  In any case, it does not  
      seem something worth encouraging so it is simply not supported.  
      So vertex attribute arrays are IGNORED when vertex program mode  
      is not enabled.  
  
      Ignoring VertexAttribute commands or treating VertexAttribute  
      commands as an error when vertex program mode is enabled  
      would likely add overhead for such a conditional check.  The  
      implementation overhead for supporting VertexAttribute commands  
      when vertex program mode is disabled is not that significant.  
      Additionally, it is likely that setting persistent vertex attribute  
      state while vertex program mode is disabled may be useful to  
      applications.  So vertex attribute immediate mode commands are  
      PERMITTED when vertex program mode is not enabled.  
  
    Colors and normals specified as ints, uints, shorts, ushorts, bytes,  
    and ubytes are converted to floating-point ranges when supplied to  
    core OpenGL as described in Table 2.6.  Other per-vertex attributes  
    such as texture coordinates and positions are not converted.  
    How does this mix with vertex programs where all vertex attributes  
    are supposedly treated identically?  
  
      RESOLUTION:  Vertex attributes specified as bytes and ubytes are  
      always converted as described in Table 2.6.  All other formats are  
      not converted according to Table 2.6 but simply converted directly  
      to floating-point.  
  
      The ubyte type is converted because those types seem more useful  
      for passing colors in the [0,1] range.  
  
      If an application desires a conversion, the conversion can be  
      incorporated into the vertex program itself.  
  
      This also applies to vertex attribute arrays.  However, by enabling  
      a color or normal vertex array and not enabling the corresponding  
      aliased vertex attribute array, programmers can get the conventional  
      conversions for color and normal arrays (but only for the vertex  
      attribute arrays that alias to the conventional color and normal  
      arrays and only with the sizes/types supported by these color and  
      normal arrays).  
  
    Should programs be C-style null-terminated strings?  
        
      RESOLUTION:  No.  Programs should be specified as an array of  
      GLubyte with an explicit length parameter.  OpenGL has no precedent  
      for passing null-terminated strings into the API (though glGetString  
      returns null-terminated strings).  Null-terminated strings are  
      problematic for some languages.  
  
    Should all existing OpenGL transform functionality and extensions  
    be implementable as vertex programs?  
  
      RESOLUTION:  Yes.  Vertex programs should be a complete superset  
      of what you can do with OpenGL 1.2 and existing vertex transform  
      extensions.  
  
      To implement EXT_point_parameters, the  
      GL_VERTEX_PROGRAM_POINT_SIZE_NV enable is introduced.  
  
      To implement two-sided lighting, the GL_VERTEX_PROGRAM_TWO_SIDE_NV  
      enable is introduced.  
  
    How does glPointSize work with vertex programs?  
  
      RESOLUTION:  If GL_VERTEX_PROGRAM_POINT_SIZE_NV is disabled, the size  
      of points is determine by the glPointSize state.  If enabled,  
      the point size is determined per-vertex by the clamped value of  
      the vertex result PSIZ register.  
  
    Can the currently bound vertex program object name be deleted or  
    reloaded?  
  
      RESOLUTION.  Yes.  When a vertex program object name is deleted  
      or reloaded when it is the currently bound vertex program object,  
      it is as if a rebind occurs after the deletion or reload.  
  
      In the case of a reload, the new vertex program object will be  
      used from then on.  In the case of a deletion, the current vertex  
      program object will be treated as if it is nonexistent.  
  
    Should program objects have a mechanism for managing program  
    residency?  
  
      RESOLUTION:  Yes.  Vertex program instruction memory is a limited  
      hardware resource.  glBindProgramNV will be faster if binding to  
      a resident program.  Applications are likely to want to quickly  
      switch between a small collection of programs.  
  
      glAreProgramsResidentNV allows the residency status of a  
      group of programs to be queried.  This mimics  
      glAreTexturesResident.  
  
      Instead of adopting the glPrioritizeTextures mechanism, a new  
      glRequestResidentProgramsNV command is specified instead.  
      Assigning priorities to textures has always been a problematic  
      endeavor and few OpenGL implementations implemented it effectively.  
      For the priority mechanism to work well, it requires the client  
      to routinely update the priorities of textures.  
  
      The glRequestResidentProgramsNV indicates to the GL that a  
      set of programs are intended for use together.  Because all  
      the programs are requesting residency as a group, drivers  
      should be able to attempt to load all the requested programs  
      at once (and remove from residency programs not in the group if  
      necessary).  Clients can use glAreProgramsResidentNV to query the  
      relative success of the request.  
  
      glRequestResidentProgramsNV should be superior to loading programs  
      on-demand because fragmentation can be avoided.  
  
    What happens when you execute a nonexistent or invalid program?  
  
      RESOLUTION:  glBegin will fail with a GL_INVALID_OPERATION if the  
      currently bound vertex program is nonexistent or invalid.  The same  
      applies to glRasterPos and any command that implies a glBegin.  
  
      Because the glVertex and glVertexAttribNV(0, ...) are ignored  
      outside of a glBegin/glEnd pair (without generating an error) it  
      is impossible to provoke a vertex program if the current vertex  
      program is nonexistent or invalid.  Other per-vertex parameters  
      (for examples those set by glColor, glNormal, and glVertexAttribNV  
      when the attribute number is not zero) are recorded since they  
      are legal outside of a glBegin/glEnd.  
  
      For vertex state programs, the problem is simpler because  
      glExecuteProgramNV can immediately fail with a GL_INVALID_OPERATION  
      when the named vertex state program is nonexistent or invalid.  
  
    What happens when a matrix has been tracked into a set of program  
    parameters, but then glTrackMatrixNV(GL_VERTEX_PROGRAM_NV, addr,  
    GL_NONE, GL_IDENTITY_NV) is performed?  
  
      RESOLUTION:  The specified program parameters stop tracking a  
      matrix, but they retain the values of the matrix they were last  
      tracking.  
  
    Can rows of tracked matrices be queried by querying the program  
    parameters that track them?  
  
      RESOLUTION:  Yes.  
  
    Discussing matrices is confusing because of row-major versus  
    column-major issues.  Can you give an example of how a matrix is  
    tracked?  
  
      // When loaded, the first row is "1, 2, 3, 4", because of column-major  
      // (OpenGL spec) vs. row-major (C) differences.  
      GLfloat matrix[16] = { 1, 5, 9,  13,  
                             2, 6, 10, 14,  
                             3, 7, 11, 15,  
                             4, 8, 12, 16 };  
      GLfloat row1[4], row2[4];  
  
      glMatrixMode(GL_MATRIX0_NV);  
      glLoadMatrixf(matrix);  
      glTrackMatrixNV(GL_VERTEX_PROGRAM_NV, 4, GL_MATRIX0_NV, GL_IDENTITY_NV);  
      glTrackMatrixNV(GL_VERTEX_PROGRAM_NV, 8, GL_MATRIX0_NV, GL_TRANSPOSE_NV);  
      glGetProgramParameterfvNV(GL_VERTEX_PROGRAM_NV, 5,  
        GL_PROGRAM_PARAMETER_NV, row1);  
      /* row1 is now [ 5 6 7 8 ] */  
      glGetProgramParameterfvNV(GL_VERTEX_PROGRAM_NV, 9,  
        GL_PROGRAM_PARAMETER_NV, row2);  
      /* row2 is now [ 2 6 10 14 ] because the tracked matrix is transposed */  
  
    Should evaluators be extended to evaluate arbitrary vertex  
    attributes?  
  
      RESOLUTION:  Yes.  We'll support 32 new maps (16 for MAP1 and 16  
      for MAP2) that take priority over the conventional maps that they  
      might alias to (only when vertex program mode is enabled).  
  
      These new maps always evaluate all four components.  The rationale  
      for this is that if we supported 1, 2, 3, or 4 components, that  
      would add 128 (16*4*2) enumerants which is too many.  In addition,  
      if you wanted to evaluate two 2-component vertex attributes, you  
      could instead generate one 4-component vertex attribute and use  
      the vertex program with swizzling to treat this as two-components.  
  
      Moreover, we are assuming 4-component vector instructions so less  
      than 4-component evaluations might not be any more efficient  
      than 4-component evaluations.  Implementations that use vector  
      instructions such as Intel's SSE instructions will be easier to  
      implement since they can focus on optimizing just the 4-component  
      case.  
  
    How should GL_AUTO_NORMAL work with vertex programs?  
  
      RESOLUTION:  GL_AUTO_NORMAL should NOT guarantee that the generated  
      analytical normal be normalized.  In vertex program mode, the  
      current vertex program can easily normalize the normal if required.  
  
      This can lead to greater efficiency if the vertex program transforms  
      the normal to another coordinate system such as eye-space with a  
      transform that preserves vector length.  Then a single normalize  
      after transform is more efficient than normalizing after evaluation  
      and also normalizing after transform.  
  
      Conceptually, the normalize mandated for AUTO_NORMAL in section  
      5.1 is just one of the many transformation operations subsumed by  
      vertex programs.  
  
    Should the new vertex program related enables push/pop with  
    GL_ENABLE_BIT?  
  
      RESOLUTION:  Yes.  Pushing and popping enable bits is easy.  
      This includes the 32 new evaluator map enable bits.  These evaluator  
      enable bits are also pushed and popped using GL_EVAL_BIT.  
  
    Should all the vertex attribute state push/pop with GL_CURRENT_BIT?  
  
      RESOLUTION: Yes.  The state is aliased with the conventional  
      per-vertex parameter state so it really should push/pop.  
  
    Should all the vertex attrib vertex array state push/pop with  
    GL_CLIENT_VERTEX_ARRAY_BIT?  
  
      RESOLUTION: Yes.  
  
    Should all the other vertex program-related state push/pop somehow?  
  
      RESOLUTION:  No.  
  
      The other vertex program doesn't fit well with the existing bits.  
      To be clear, GL_ALL_ATTRIB_BITS does not push/pop vertex program  
      state other than enables.  
  
    Should we generate a GL_INVALID_OPERATION operation if updating  
    a vertex attribute greater than 15?  
  
      RESOLUTION:  Yes.  
  
      The other option would be to mask or modulo the vertex attribute  
      index with 16.  This is cheap, but it would make it difficult to  
      increase the number of vertex attributes in the future.  
  
      If we check for the error, it should be a well predicted branch  
      for immediate mode calls.  For vertex arrays, the check is only  
      required at vertex array specification time.  
  
      Hopefully this will encourage people to use vertex arrays over  
      immediate mode.  
  
    Should writes to program parameter registers during a vertex program  
    be supported?  
  
      RESOLUTION.  No.  
  
      Writes to program parameter registers from within a vertex program  
      would require the execution of vertex programs to be serialized  
      with respect to each other.  This would create an unwarranted  
      implementation penalty for parallel vertex program execution  
      implementations.  
  
      However vertex state programs may write to program parameter  
      registers (that is the whole point of vertex state programs).  
  
    Should we support variously sized immediate mode byte and ubyte  
    commands?  How about for vertex arrays?  
  
      RESOLUTION.  Only support the 4ub mode.  
  
      There are simply too many glVertexAttribNV routines.  Passing less  
      than 4 bytes at a time is inefficient.  We expect the main use  
      for bytes to be for colors where these will be unsigned bytes.  
      So let's just support 4ub mode for bytes.  This applies to  
      vertex arrays too.  
  
    Should we support integer, unsigned integer, and unsigned short  
    formats for vertex attributes?  
  
      RESOLUTION:  No.  It's just too many immediate mode entry points,  
      most of which are not that useful.  Signed shorts are supported  
      however.  We expect signed shorts to be useful for passing compact  
      texture coordinates.  
  
    Should we support doubles for vertex attributes?  
  
      RESOLUTION:  Yes.  Some implementation of the extension might  
      support double precision.  Lots of math routines output double  
      precision.  
  
    Should there be a way to determine where in a loaded program  
    string the first parse error occurs?  
  
      RESOLUTION:  Yes.  You can query PROGRAM_ERROR_POSITION_NV.  
  
    Should program objects be shared among rendering contexts in the  
    same manner as display lists and texture objects?  
  
      RESOLUTION:  Yes.  
  
    How should this extension interact with color material?  
  
      RESOLUTION:  It should not.  Color material is a conventional  
      OpenGL vertex transform mode.  It does not have a place for vertex  
      programs.  If you want to emulate color material with vertex  
      programs, you would simply write a program where the material  
      parameters feed from the color vertex attribute.  
  
    Should there be a glMatrixMode or glActiveTextureARB style selector  
    for vertex attributes?  
  
      RESOLUTION:  No.  While this would let us reduce a lot of  
      enumerants down, it would make programming a hassle in lots  
      of cases.  Consider having to change the vertex attribute  
      mode to enable a set of vertex arrays.  
  
    How should gets for vertex attribute array pointers?  
  
      RESOLUTION:  Add new get commands.  Using the existing calls  
      would require adding 4 sets of 16 enumerants stride, type, size,  
      and pointer.  That's too many gets.  
  
      Instead add glGetVertexAttribNV and glGetVertexAttribPointervNV.  
      glGetVertexAttribNV is also useful for querying the current vertex  
      attribute.  
  
      glGet and glGetPointerv will not return vertex attribute array  
      pointers.  
  
    Why is the address register numbered and why is it a vector  
    register?  
  
      In the future, A0.y and A0.z and A0.w may exist.  For this  
      extension, only A0.x is useful.  Also in the future, there may be  
      more than one address register.  
  
      There's a nice consistency in thinking about all the registers  
      as 4-component vectors even if the address register has only one  
      usable component.  
  
    Should vertex programs and vertex state programs be required to  
    have a header token and an end token?  
  
      RESOLUTION:  Yes.  
  
      The "!!VP1.0" and "!!VSP1.0" tokens start vertex programs and  
      vertex state programs respectively.  Both types of programs must  
      end with the "END" token.  
  
      The initial header token reminds the programmer what type of program  
      they are writing.  If vertex programs and vertex state programs are  
      ever read from disk files, the header token can serve as a magic  
      number for identifying vertex programs and vertex state programs.  
  
      The target type for vertex programs and vertex state programs can be  
      distinguished based on their respective grammars independent of the  
      initial header tokens, but the initial header tokens will make it  
      easier for programmers to distinguish the two program target types.  
  
      We expect programs to often be generated by concatenation of  
      program fragments.  The "END" token will hopefully reduce bugs  
      due to specifying an incorrectly concatenated program.  
  
      It's tempting to make these additional header and end tokens  
      optional, but if there is a sanity check value in header and end  
      tokens, that value is undermined if the tokens are optional.  
  
    What should be said about rendering invariances?  
  
      RESOLUTION:  See the Appendix A additions below.  
  
      The justification for the two rules cited is to support multi-pass  
      rendering when using vertex programs.  Different rendering passes  
      will likely use different programs so there must be some means of  
      guaranteeing that two different programs can generate particular  
      identical vertex results between different passes.  
  
      In practice, this does limit the type of vertex program  
      implementations that are possible.  
  
      For example, consider a limited hardware implementation of vertex  
      programs that uses a different floating-point implementation  
      than the CPU's floating-point implementation.  If the limited  
      hardware implementation can only run small vertex programs (say  
      the hardware provides on 4 temporary registers instead of the  
      required 12), the implementation is incorrect and non-conformant  
      if programs that only require 4 temporary registers use the vertex  
      program hardware, but programs that require more than 4 temporary  
      registers are implemented by the CPU.  
  
      This is a very important practical requirement.  Consider a  
      multi-pass rendering algorithm where one pass uses a vertex program  
      that uses only 4 temporary registers, but a different pass uses a  
      vertex program that uses 5 temporary registers.  If two programs  
      have instruction sequences that given the same input state compute  
      identical resulting vertex positions, the multi-pass algorithm  
      should generate identically positioned primitives for each pass.  
      But given the non-conformant vertex program implementation described  
      above, this could not be guaranteed.  
  
      This does not mean that schemes for splitting vertex program  
      implementations between dedicated hardware and CPUs are impossible.  
      If the CPU and dedicated vertex program hardware used IDENTICAL  
      floating-point implementations and therefore generated exactly  
      identical results, the above described could work.  
  
      While these invariance rules are vital for vertex programs operating  
      correctly for multi-pass algorithms, there is no requirement that  
      conventional OpenGL vertex transform mode will be invariant with  
      vertex program mode.  A multi-pass algorithm should not assume  
      that one pass using vertex program mode and another pass using  
      conventional GL vertex transform mode will generate identically  
      positioned primitives.  
  
      Consider that while the conventional OpenGL vertex program mode  
      is repeatable with itself, the exact procedure used to transform  
      vertices is not specified nor is the procedure's precision  
      specified.  The GL specification indicates that vertex coordinates  
      are transformed by the modelview matrix and then transformed by the  
      projection matrix.  Some implementations may perform this sequence  
      of transformations exactly, but other implementations may transform  
      vertex coordinates by the composite of the modelview and projection  
      matrices (one matrix transform instead of two matrix transforms  
      in sequence).  Given this implementation flexibility, there is no  
      way for a vertex program author to exactly duplicate the precise  
      computations used by the conventional OpenGL vertex transform mode.  
  
      The guidance to OpenGL application programs is clear.  If you are  
      going to implement multi-pass rendering algorithms that require  
      certain invariances between the multiple passes, choose either  
      vertex program mode or the conventional OpenGL vertex transform  
      mode for your rendering passes, but do not mix the two modes.  
  
    What range of relative addressing offsets should be allowed?  
  
      RESOLUTION:  -64 to 63.  
  
      Negative offsets are useful for accessing a table centered at zero  
      without extra bias instructions.  Having the offsets support much  
      larger magnitudes just seems to increase the required instruction  
      widths.  The -64 to 63 range seems like a reasonable compromise.  
  
    When EXT_secondary_color is supported, how does the GL_COLOR_SUM_EXT  
    enable affect vertex program mode?  
  
      RESOLUTION:  The GL_COLOR_SUM_EXT enable has no affect when vertex  
      program mode is enabled.  
  
      When vertex program mode is enabled, the color sum operation is  
      always in operation.  A program can "avoid" the color sum operation  
      by not writing the COL1 (or BFC1 when GL_VERTEX_PROGRAM_TWO_SIDE_NV)  
      vertex result registers because the default values of all vertex  
      result registers is (0,0,0,1).  For the color sum operation,  
      the alpha value is always assumed zero.  So by not writing the  
      secondary color vertex result registers, the program assures that  
      zero is added as part of the color sum operation.  
  
      If there is a cost to the color sum operation, OpenGL  
      implementations may be smart enough to determine at program bind  
      time whether a secondary color vertex result is generated and  
      implicitly disable the color sum operation.  
  
    Why must RCP of 1.0 always be 1.0?  
  
      This is important for 3D graphics so that non-projective textures  
      and orthogonal projections work as expected.  Basically when q or  
      w is 1.0, things should work as expected.  
  
      Stronger requirements such as "RCP of -1.0 must always be -1.0"  
      are encouraged, but there is no compelling reason to state such  
      requirements explicitly as is the case for "RCP of 1.0 must always  
      be 1.0".  
  
    What happens when the source scalar value for the ARL instruction  
    is an extremely positive or extremely negative floating-point value?  
    Is there a problem mapping the value to a constrained integer range?  
  
      RESOLUTION:  It is not a problem.  Relative addressing can by offset  
      by a limited range of offsets (-64 to 63).  Relative addressing  
      that falls outside of the 0 to 95 range of program parameter  
      registers is automatically mapped to (0,0,0,0).  
  
      Clamping the source scalar value for ARL to the range -64 to 160  
      inclusive is sufficient to ensure that relative addressing is out  
      of range.  
  
    How do you perform a 3-component normalize in three instructions?  
  
      #  
      # R1 = (nx,ny,nz)  
      #  
      # R0.xyz = normalize(R1)  
      # R0.w   = 1/sqrt(nx*nx + ny*ny + nz*nz)  
      #  
      DP3 R0.w, R1, R1;  
      RSQ R0.w, R0.w;  
      MUL R0.xyz, R1, R0.w;  
  
    How do you perform a 3-component cross product in two instructions?  
  
      #  
      # Cross product |  i     j     k   | into R2.  
      #               | R0.x  R0.y  R0.z |  
      #               | R1.x  R1.y  R1.z |  
      #  
      MUL R2, R0.zxyw, R1.yzxw;  
      MAD R2, R0.yzxw, R1.zxyw, -R2;  
  
    How do you perform a 4-component vector absolute value in one  
    instruction?  
  
      #  
      # Absolute value is the maximum of the negative and positive  
      # components of a vector.  
      #  
      # R1 = abs(R0)  
      #  
      MAX R1, R0, -R0;  
  
    How do you compute the determinant of a 3x3 matrix in three  
    instructions?  
  
      #  
      # Determinant of | R0.x  R0.y  R0.z | into R3  
      #                | R1.x  R1.y  R1.z |  
      #                | R2.x  R2.y  R2.z |  
      #  
      MUL R3, R1.zxyw, R2.yzxw;  
      MAD R3, R1.yzxw, R2.zxyw, -R3;  
      DP3 R3, R0, R3;  
  
    How do you transform a vertex position by a 4x4 matrix and then  
    perform a homogeneous divide?  
  
      #  
      # c[20] = modelview row 0  
      # c[21] = modelview row 1  
      # c[22] = modelview row 2  
      # c[23] = modelview row 3  
      #  
      # result = R5  
      #  
      DP4 R5.w, v[OPOS], c[23];  
      DP4 R5.x, v[OPOS], c[20];  
      DP4 R5.y, v[OPOS], c[21];  
      DP4 R5.z, v[OPOS], c[22];  
      RCP R11, R5.w;  
      MUL R5,R5,R11;  
  
    How do you perform a vector weighting of two vectors using a single  
    weight?  
  
      #  
      # R2        = vector 0  
      # R3        = vector 1  
      # v[WGHT].x = scalar weight to blend vectors 0 and 1  
      # result    = R2 * v[WGHT].x + R3 * (1-v[WGHT])  
      #  
      # this is because A*B + (1-A)*C = A*(B-C) + C  
      #  
      ADD R4, R2, -R3;  
      MAD R4, v[WGHT].x, R4, R3;  
  
    How do you reduce a value to some fundamental period such as 2*PI?  
  
      #  
      # c[36] = (1.0/(2*PI), 2*PI, 0.0, 0.0)  
      #  
      # R1.x = input value  
      # R2   = result  
      #  
      MUL R0, R1, c[36].x;  
      EXP R4, R0.x;  
      MUL R2, R4.y, c[36].y;  
  
    How do you implement a simple specular and diffuse lighting  
    computation with an eye-space normal?  
  
      !!VP1.0  
      #  
      # c[0-3]  = modelview projection (composite) matrix  
      # c[4-7]  = modelview inverse transpose  
      # c[32]   = normalized eye-space light direction (infinite light)  
      # c[33]   = normalized constant eye-space half-angle vector (infinite viewer)  
      # c[35].x = pre-multiplied monochromatic diffuse light color & diffuse material  
      # c[35].y = pre-multiplied monochromatic ambient light color & diffuse material  
      # c[36]   = specular color  
      # c[38].x = specular power  
      #  
      # outputs homogenous position and color  
      #  
      DP4   o[HPOS].x, c[0], v[OPOS];  
      DP4   o[HPOS].y, c[1], v[OPOS];  
      DP4   o[HPOS].z, c[2], v[OPOS];  
      DP4   o[HPOS].w, c[3], v[OPOS];  
      DP3   R0.x, c[4], v[NRML];  
      DP3   R0.y, c[5], v[NRML];   
      DP3   R0.z, c[6], v[NRML];           # R0 = n' = transformed normal  
      DP3   R1.x, c[32], R0;               # R1.x = Lpos DOT n'  
      DP3   R1.y, c[33], R0;               # R1.y = hHat DOT n'  
      MOV   R1.w, c[38].x;                 # R1.w = specular power  
      LIT   R2, R1;                        # Compute lighting values  
      MAD   R3, c[35].x, R2.y, c[35].y;    # diffuse + emissive  
      MAD   o[COL0].xyz, c[36], R2.z, R3;  # + specular  
      END  
  
    Can you perturb transformed vertex positions with a vertex program?  
  
      Yes.  Here is an example that performs an object-space diffuse  
      lighting computations and perturbs the vertex position based on  
      this lighting result.  Do not take this example too seriously.  
  
        !!VP1.0  
        #  
        # c[0-3]  = modelview projection (composite) matrix  
        # c[32]   = normalized light direction in object-space  
        # c[35]   = yellow diffuse material, (1.0, 1.0, 0.0, 1.0)  
        # c[64].x = 0.0  
        # c[64].z = 0.125, a scaling factor  
        #  
        # outputs diffuse illumination for color and perturbed position  
        #  
        DP3   R0, c[32], v[NRML];     # light direction DOT normal  
        MUL   o[COL0].xyz, R0, c[35];   
        MAX   R0, c[64].x, R0;   
        MUL   R0, R0, v[NRML];   
        MUL   R0, R0, c[64].z;    
        ADD   R1, v[OPOS], -R0;       # perturb object space position  
        DP4   o[HPOS].x, c[0], R1;   
        DP4   o[HPOS].y, c[1], R1;   
        DP4   o[HPOS].z, c[2], R1;   
        DP4   o[HPOS].w, c[3], R1;   
        END  
  
    What if more exponential precision is needed than provided by the  
    builtin EXP instruction?  
  
        A sequence of vertex program instructions can be used refine  
        the initial EXP approximation.  The pseudo-macro below shows an  
        example of how to refine the EXP approximation.  
  
        The psuedo-macro requires 10 instructions, 1 temp register,  
        and 2 constant locations.  
  
        CE0 = { 9.61597636e-03, -1.32823968e-03, 1.47491097e-04, -1.08635004e-05 };  
        CE1 = { 1.00000000e+00, -6.93147182e-01, 2.40226462e-01, -5.55036440e-02 };  
  
        /* Rt != Ro && Rt != Ri */  
        EXP_MACRO(Ro:vector, Ri:scalar, Rt:vector) {  
           EXP Rt, Ri.x;                   /* Use appropriate component of Ri */  
           MAD Rt.w, c[CE0].w, Rt.y, c[CE0].z;  
           MAD Rt.w, Rt.w,Rt.y, c[CE0].y;  
           MAD Rt.w, Rt.w,Rt.y, c[CE0].x;  
           MAD Rt.w, Rt.w,Rt.y, c[CE1].w;  
           MAD Rt.w, Rt.w,Rt.y, c[CE1].z;  
           MAD Rt.w, Rt.w,Rt.y, c[CE1].y;  
           MAD Rt.w, Rt.w,Rt.y, c[CE1].x;  
           RCP Rt.w, Rt.w;  
           MUL Ro, Rt.w, Rt.x;             /* Apply user write mask to Ro */  
        }  
  
        Simulation gives |max abs error| < 3.77e-07 over the range (0.0  
        <= x < 1.0).  Actual vertex program precision may be slightly  
        less accurate than this.  
  
    What if more exponential precision is needed than provided by the  
    builtin LOG instruction?  
  
        The pseudo-macro requires 10 instructions, 1 temp register,  
        and 3 constant locations.  
     
        CL0 = { 2.41873696e-01, -1.37531206e-01, 5.20646796e-02, -9.31049418e-03 };  
        CL1 = { 1.44268966e+00, -7.21165776e-01, 4.78684813e-01, -3.47305417e-01 };  
        CL2 = { 1.0, NA, NA, NA };  
  
        /* Rt != Ro && Rt != Ri */  
        LOG_MACRO(Ro:vector, Ri:scalar, Rt:vector) {  
           LOG Rt, Ri.x;                   /* Use appropriate component of Ri */  
           ADD Rt.y, Rt.y, -c[CL2].x;  
           MAD Rt.w, c[CL0].w, Rt.y, c[CL0].z;  
           MAD Rt.w, Rt.w, Rt.y,c[CL0].y;  
           MAD Rt.w, Rt.w, Rt.y,c[CL0].x;  
           MAD Rt.w, Rt.w, Rt.y,c[CL1].w;  
           MAD Rt.w, Rt.w, Rt.y,c[CL1].z;  
           MAD Rt.w, Rt.w, Rt.y,c[CL1].y;  
           MAD Rt.w, Rt.w, Rt.y,c[CL1].x;  
           MAD Ro, Rt.w, Rt.y, Rt.x;       /* Apply user write mask to Ro */  
        }  
    
        Simulation gives |max abs error| < 1.79e-07 over the range (1.0  
        <= x < 2.0).  Actual vertex program precision may be slightly  
        less accurate than this.  
  
homeprevnext New Procedures and Functions
  
    void BindProgramNV(enum target, uint id);  
  
    void DeleteProgramsNV(sizei n, const uint *ids);  
  
    void ExecuteProgramNV(enum target, uint id, const float *params);  
  
    void GenProgramsNV(sizei n, uint *ids);  
  
    boolean AreProgramsResidentNV(sizei n, const uint *ids,  
                                  boolean *residences);  
  
    void RequestResidentProgramsNV(sizei n, uint *ids);  
  
    void GetProgramParameterfvNV(enum target, uint index,  
                                 enum pname, float *params);  
    void GetProgramParameterdvNV(enum target, uint index,  
                                 enum pname, double *params);  
  
    void GetProgramivNV(uint id, enum pname, int *params);  
  
    void GetProgramStringNV(uint id, enum pname, ubyte *program);  
  
    void GetTrackMatrixivNV(enum target, uint address,  
                            enum pname, int *params);  
  
    void GetVertexAttribdvNV(uint index, enum pname, double *params);  
    void GetVertexAttribfvNV(uint index, enum pname, float *params);  
    void GetVertexAttribivNV(uint index, enum pname, int *params);  
  
    void GetVertexAttribPointervNV(uint index, enum pname, void **pointer);  
  
    boolean IsProgramNV(uint id);  
  
    void LoadProgramNV(enum target, uint id, sizei len,  
                       const ubyte *program);  
  
    void ProgramParameter4fNV(enum target, uint index,  
                              float x, float y, float z, float w)  
    void ProgramParameter4dNV(enum target, uint index,  
                              double x, double y, double z, double w)  
  
    void ProgramParameter4dvNV(enum target, uint index,  
                               const double *params);  
    void ProgramParameter4fvNV(enum target, uint index,  
                               const float *params);  
  
    void ProgramParameters4dvNV(enum target, uint index,  
                                uint num, const double *params);  
    void ProgramParameters4fvNV(enum target, uint index,  
                                uint num, const float *params);  
  
    void TrackMatrixNV(enum target, uint address,  
                       enum matrix, enum transform);  
  
    void VertexAttribPointerNV(uint index, int size, enum type, sizei stride,  
                               const void *pointer);  
  
    void VertexAttrib1sNV(uint index, short x);  
    void VertexAttrib1fNV(uint index, float x);  
    void VertexAttrib1dNV(uint index, double x);  
    void VertexAttrib2sNV(uint index, short x, short y);  
    void VertexAttrib2fNV(uint index, float x, float y);  
    void VertexAttrib2dNV(uint index, double x, double y);  
    void VertexAttrib3sNV(uint index, short x, short y, short z);  
    void VertexAttrib3fNV(uint index, float x, float y, float z);  
    void VertexAttrib3dNV(uint index, double x, double y, double z);  
    void VertexAttrib4sNV(uint index, short x, short y, short z, short w);  
    void VertexAttrib4fNV(uint index, float x, float y, float z, float w);  
    void VertexAttrib4dNV(uint index, double x, double y, double z, double w);  
    void VertexAttrib4ubNV(uint index, ubyte x, ubyte y, ubyte z, ubyte w);  
  
    void VertexAttrib1svNV(uint index, const short *v);  
    void VertexAttrib1fvNV(uint index, const float *v);  
    void VertexAttrib1dvNV(uint index, const double *v);  
    void VertexAttrib2svNV(uint index, const short *v);  
    void VertexAttrib2fvNV(uint index, const float *v);  
    void VertexAttrib2dvNV(uint index, const double *v);  
    void VertexAttrib3svNV(uint index, const short *v);  
    void VertexAttrib3fvNV(uint index, const float *v);  
    void VertexAttrib3dvNV(uint index, const double *v);  
    void VertexAttrib4svNV(uint index, const short *v);  
    void VertexAttrib4fvNV(uint index, const float *v);  
    void VertexAttrib4dvNV(uint index, const double *v);  
    void VertexAttrib4ubvNV(uint index, const ubyte *v);  
  
    void VertexAttribs1svNV(uint index, sizei n, const short *v);  
    void VertexAttribs1fvNV(uint index, sizei n, const float *v);  
    void VertexAttribs1dvNV(uint index, sizei n, const double *v);  
    void VertexAttribs2svNV(uint index, sizei n, const short *v);  
    void VertexAttribs2fvNV(uint index, sizei n, const float *v);  
    void VertexAttribs2dvNV(uint index, sizei n, const double *v);  
    void VertexAttribs3svNV(uint index, sizei n, const short *v);  
    void VertexAttribs3fvNV(uint index, sizei n, const float *v);  
    void VertexAttribs3dvNV(uint index, sizei n, const double *v);  
    void VertexAttribs4svNV(uint index, sizei n, const short *v);  
    void VertexAttribs4fvNV(uint index, sizei n, const float *v);  
    void VertexAttribs4dvNV(uint index, sizei n, const double *v);  
    void VertexAttribs4ubvNV(uint index, sizei n, const ubyte *v);  
  
homeprevnext New Tokens
  
    Accepted by the <cap> parameter of Disable, Enable, and IsEnabled,  
    and by the <pname> parameter of GetBooleanv, GetIntegerv, GetFloatv,  
    and GetDoublev, and by the <target> parameter of BindProgramNV,  
    ExecuteProgramNV, GetProgramParameter[df]vNV, GetTrackMatrixivNV,  
    LoadProgramNV, ProgramParameter[s]4[df][v]NV, and TrackMatrixNV:  
  
        VERTEX_PROGRAM_NV                              0x8620   
  
    Accepted by the <cap> parameter of Disable, Enable, and IsEnabled,  
    and by the <pname> parameter of GetBooleanv, GetIntegerv, GetFloatv,  
    and GetDoublev:  
  
        VERTEX_PROGRAM_POINT_SIZE_NV                   0x8642  
        VERTEX_PROGRAM_TWO_SIDE_NV                     0x8643  
  
    Accepted by the <target> parameter of ExecuteProgramNV and  
    LoadProgramNV:  
      
        VERTEX_STATE_PROGRAM_NV                        0x8621   
  
    Accepted by the <pname> parameter of GetVertexAttrib[dfi]vNV:  
  
        ATTRIB_ARRAY_SIZE_NV                           0x8623  
        ATTRIB_ARRAY_STRIDE_NV                         0x8624  
        ATTRIB_ARRAY_TYPE_NV                           0x8625  
        CURRENT_ATTRIB_NV                              0x8626  
  
    Accepted by the <pname> parameter of GetProgramParameterfvNV  
    and GetProgramParameterdvNV:  
  
        PROGRAM_PARAMETER_NV                           0x8644  
  
    Accepted by the <pname> parameter of GetVertexAttribPointervNV:  
  
        ATTRIB_ARRAY_POINTER_NV                        0x8645  
  
    Accepted by the <pname> parameter of GetProgramivNV:  
  
        PROGRAM_TARGET_NV                              0x8646  
        PROGRAM_LENGTH_NV                              0x8627  
        PROGRAM_RESIDENT_NV                            0x8647  
  
    Accepted by the <pname> parameter of GetProgramStringNV:  
  
        PROGRAM_STRING_NV                              0x8628  
  
    Accepted by the <pname> parameter of GetTrackMatrixivNV:  
  
        TRACK_MATRIX_NV                                0x8648  
        TRACK_MATRIX_TRANSFORM_NV                      0x8649  
  
    Accepted by the <pname> parameter of GetBooleanv, GetIntegerv,  
    GetFloatv, and GetDoublev:  
  
        MAX_TRACK_MATRIX_STACK_DEPTH_NV                0x862E  
        MAX_TRACK_MATRICES_NV                          0x862F  
        CURRENT_MATRIX_STACK_DEPTH_NV                  0x8640  
        CURRENT_MATRIX_NV                              0x8641  
        VERTEX_PROGRAM_BINDING_NV                      0x864A  
        PROGRAM_ERROR_POSITION_NV                      0x864B  
  
    Accepted by the <matrix> parameter of TrackMatrixNV:  
      
        NONE  
        MODELVIEW  
        PROJECTION  
        TEXTURE  
        COLOR (if ARB_imaging is supported)  
        MODELVIEW_PROJECTION_NV                        0x8629  
        TEXTUREi_ARB  
  
    where i is between 0 and n-1 where n is the number of texture units  
    supported.  
  
    Accepted by the <matrix> parameter of TrackMatrixNV and by the  
    <mode> parameter of MatrixMode:  
      
        MATRIX0_NV                                     0x8630  
        MATRIX1_NV                                     0x8631  
        MATRIX2_NV                                     0x8632  
        MATRIX3_NV                                     0x8633  
        MATRIX4_NV                                     0x8634  
        MATRIX5_NV                                     0x8635  
        MATRIX6_NV                                     0x8636  
        MATRIX7_NV                                     0x8637  
  
        (Enumerants 0x8638 through 0x863F are reserved for further matrix  
        enumerants 8 through 15.)  
  
    Accepted by the <transform> parameter of TrackMatrixNV:  
  
        IDENTITY_NV                                    0x862A  
        INVERSE_NV                                     0x862B  
        TRANSPOSE_NV                                   0x862C  
        INVERSE_TRANSPOSE_NV                           0x862D   
  
    Accepted by the <array> parameter of EnableClientState and  
    DisableClientState, by the <cap> parameter of IsEnabled, and by  
    the <pname> parameter of GetBooleanv, GetIntegerv, GetFloatv, and  
    GetDoublev:  
  
        VERTEX_ATTRIB_ARRAY0_NV                        0x8650  
        VERTEX_ATTRIB_ARRAY1_NV                        0x8651  
        VERTEX_ATTRIB_ARRAY2_NV                        0x8652  
        VERTEX_ATTRIB_ARRAY3_NV                        0x8653  
        VERTEX_ATTRIB_ARRAY4_NV                        0x8654  
        VERTEX_ATTRIB_ARRAY5_NV                        0x8655  
        VERTEX_ATTRIB_ARRAY6_NV                        0x8656  
        VERTEX_ATTRIB_ARRAY7_NV                        0x8657  
        VERTEX_ATTRIB_ARRAY8_NV                        0x8658  
        VERTEX_ATTRIB_ARRAY9_NV                        0x8659  
        VERTEX_ATTRIB_ARRAY10_NV                       0x865A  
        VERTEX_ATTRIB_ARRAY11_NV                       0x865B  
        VERTEX_ATTRIB_ARRAY12_NV                       0x865C  
        VERTEX_ATTRIB_ARRAY13_NV                       0x865D  
        VERTEX_ATTRIB_ARRAY14_NV                       0x865E  
        VERTEX_ATTRIB_ARRAY15_NV                       0x865F  
  
    Accepted by the <target> parameter of GetMapdv, GetMapfv, GetMapiv,  
    Map1d and Map1f and by the <cap> parameter of Enable, Disable, and  
    IsEnabled, and by the <pname> parameter of GetBooleanv, GetIntegerv,  
    GetFloatv, and GetDoublev:  
  
        MAP1_VERTEX_ATTRIB0_4_NV                       0x8660  
        MAP1_VERTEX_ATTRIB1_4_NV                       0x8661  
        MAP1_VERTEX_ATTRIB2_4_NV                       0x8662  
        MAP1_VERTEX_ATTRIB3_4_NV                       0x8663  
        MAP1_VERTEX_ATTRIB4_4_NV                       0x8664  
        MAP1_VERTEX_ATTRIB5_4_NV                       0x8665  
        MAP1_VERTEX_ATTRIB6_4_NV                       0x8666  
        MAP1_VERTEX_ATTRIB7_4_NV                       0x8667  
        MAP1_VERTEX_ATTRIB8_4_NV                       0x8668  
        MAP1_VERTEX_ATTRIB9_4_NV                       0x8669  
        MAP1_VERTEX_ATTRIB10_4_NV                      0x866A  
        MAP1_VERTEX_ATTRIB11_4_NV                      0x866B  
        MAP1_VERTEX_ATTRIB12_4_NV                      0x866C  
        MAP1_VERTEX_ATTRIB13_4_NV                      0x866D  
        MAP1_VERTEX_ATTRIB14_4_NV                      0x866E  
        MAP1_VERTEX_ATTRIB15_4_NV                      0x866F  
  
    Accepted by the <target> parameter of GetMapdv, GetMapfv, GetMapiv,  
    Map2d and Map2f and by the <cap> parameter of Enable, Disable, and  
    IsEnabled, and by the <pname> parameter of GetBooleanv, GetIntegerv,  
    GetFloatv, and GetDoublev:  
  
        MAP2_VERTEX_ATTRIB0_4_NV                       0x8670  
        MAP2_VERTEX_ATTRIB1_4_NV                       0x8671  
        MAP2_VERTEX_ATTRIB2_4_NV                       0x8672  
        MAP2_VERTEX_ATTRIB3_4_NV                       0x8673  
        MAP2_VERTEX_ATTRIB4_4_NV                       0x8674  
        MAP2_VERTEX_ATTRIB5_4_NV                       0x8675  
        MAP2_VERTEX_ATTRIB6_4_NV                       0x8676  
        MAP2_VERTEX_ATTRIB7_4_NV                       0x8677  
        MAP2_VERTEX_ATTRIB8_4_NV                       0x8678  
        MAP2_VERTEX_ATTRIB9_4_NV                       0x8679  
        MAP2_VERTEX_ATTRIB10_4_NV                      0x867A  
        MAP2_VERTEX_ATTRIB11_4_NV                      0x867B  
        MAP2_VERTEX_ATTRIB12_4_NV                      0x867C  
        MAP2_VERTEX_ATTRIB13_4_NV                      0x867D  
        MAP2_VERTEX_ATTRIB14_4_NV                      0x867E  
        MAP2_VERTEX_ATTRIB15_4_NV                      0x867F  
  
homeprevnext Additions to Chapter 2 of the OpenGL 1.2.1 Specification (OpenGL Operation)
  
 --  Section 2.10 "Coordinate Transformations"  
  
    Add this initial discussion:  
  
    "Per-vertex parameters are transformed before the transformation  
    results are used to generate primitives for rasterization, establish  
    a raster position, or generate vertices for selection or feedback.  
  
    Each vertex's per-vertex parameters are transformed by one of  
    two vertex transformation modes.  The first vertex transformation mode  
    is GL's conventional vertex transformation model.  The second mode,  
    known as 'vertex program' mode, transforms the vertex's per-vertex  
    parameters by an application-supplied vertex program.  
  
    Vertex program mode is enabled and disabled, respectively, by  
  
      void Enable(enum target);  
  
    and  
  
      void Disable(enum target);  
  
    with target equal to VERTEX_PROGRAM_NV.  When vertex program mode  
    is enabled, vertices are transformed by the currently bound vertex  
    program as discussed in section 2.14."  
  
    Update the original initial paragraph in the section to read:  
  
    "When vertex program mode is disabled, vertices, normals, and texture  
    coordinates are transformed before their coordinates are used to  
    produce an image in the framebuffer.  We begin with a description  
    of how vertex coordinates are transformed and how the transformation  
    is controlled in the case when vertex program mode is disabled.  The  
    discussion that continues through section 2.13 applies when vertex  
    program mode is disabled."  
  
 --  Section 2.10.2 "Matrices"  
  
    Change the first paragraph to read:  
  
    "The projection matrix and model-view matrix are set and modified  
    with a variety of commands.  The affected matrix is determined by  
    the current matrix mode.  The current matrix mode is set with  
  
      void MatrixMode(enum mode);  
  
    which takes one of the pre-defined constants TEXTURE, MODELVIEW,  
    COLOR, PROJECTION, or MATRIXi_NV as the argument.  In the case  
    of MATRIXi_NV, i is an integer between 0 and n-1 indicating one  
    of n tracking matrices where n is the value of the implementation  
    defined constant MAX_TRACK_MATRICES_NV.  TEXTURE is described  
    later in section 2.10.2, and COLOR is described in section 3.6.3.  
    The tracking matrices of the form MATRIXi_NV are described in  
    section 2.14.5.  If the current matrix mode is MODELVIEW, then  
    matrix operations apply to the model-view matrix; if PROJECTION,  
    then they apply to the projection matrix."  
  
    Change the last paragraph to read:  
  
    "The state required to implement transformations consists of a n-value  
    integer indicating the current matrix mode (where n is 4 + the number  
    of tracking matrices supported), a stack of at least two 4x4 matrices  
    for each of COLOR, PROJECTION, and TEXTURE with associated stack  
    pointers, n stacks (where n is at least 8) of at least one 4x4 matrix  
    for each MATRIXi_NV with associated stack pointers, and a stack of at  
    least 32 4x4 matrices with an associated stack pointer for MODELVIEW.  
    Initially, there is only one matrix on each stack, and all matrices  
    are set to the identity.  The initial matrix mode is MODELVIEW."  
  
 --  NEW Section 2.14 "Vertex Programs"  
  
    "The conventional GL vertex transformation model described  
    in sections 2.10 through 2.13 is a configurable but essentially  
    hard-wired sequence of per-vertex computations based on a canonical  
    set of per-vertex parameters and vertex transformation related  
    state such as transformation matrices, lighting parameters, and  
    texture coordinate generation parameters.  
  
    The general success and utility of the conventional GL vertex  
    transformation model reflects its basic correspondence to the  
    typical vertex transformation requirements of 3D applications.  
  
    However when the conventional GL vertex transformation model  
    is not sufficient, the vertex program mode provides a substantially  
    more flexible model for vertex transformation.  The vertex program  
    mode permits applications to define their own vertex programs.  
  
    2.14.1  The Vertex Program Execution Model  
  
    A vertex program is a sequence of floating-point 4-component vector  
    operations that operate on per-vertex attributes and program  
    parameters.  Vertex programs execute on a per-vertex basis and  
    operate on each vertex completely independently from the processing  
    of other vertices.  Vertex programs execute a finite fixed sequence  
    of instructions with no branching or looping.  Vertex programs  
    execute without data hazards so results computed in one operation can  
    be used immediately afterwards.  The result of a vertex program is  
    a set of vertex result vectors that becomes the transformed vertex  
    parameters used by primitive assembly.  
  
    Vertex programs use a specific well-defined instruction set, register  
    set, and operational model defined in the following sections.  
  
    The vertex program register set consists of five types of registers  
    described in the following five sections.  
  
    2.14.1.1  The Vertex Attribute Registers  
  
    The Vertex Attribute Registers are sixteen 4-component  
    vector floating-point registers containing the current vertex's  
    per-vertex attributes.  These registers are numbered 0 through 15.  
    These registers are private to each vertex program invocation and are  
    initialized at each vertex program invocation by the current vertex  
    attribute state specified with VertexAttribNV commands.  These registers  
    are read-only during vertex program execution.  The VertexAttribNV  
    commands used to update the vertex attribute registers can be issued  
    both outside and inside of Begin/End pairs.  Vertex program execution  
    is provoked by updating vertex attribute zero.  Updating vertex  
    attribute zero outside of a Begin/End pair is ignored without  
    generating any error (identical to the Vertex command operation).  
  
    The commands  
  
      void VertexAttrib{1234}{sfd}NV(uint index, T coords);  
      void VertexAttrib{1234}{sfd}vNV(uint index, T coords);  
      void VertexAttrib4ubNV(uint index, T coords);  
      void VertexAttrib4ubvNV(uint index, T coords);  
  
    specify the particular current vertex attribute indicated by index.  
    The coordinates for each vertex attribute are named x, y, z, and w.  
    The VertexAttrib1NV family of commands sets the x coordinate to the  
    provided single argument while setting y and z to 0 and w to 1.  
    Similarly, VertexAttrib2NV sets x and y to the specified values,  
    z to 0 and w to 1; VertexAttrib3NV sets x, y, and z, with w set  
    to 1, and VertexAttrib4NV sets all four coordinates.  The error  
    INVALID_VALUE is generated if index is greater than 15.  
  
    No conversions are applied to the vertex attributes specified as  
    type short, float, or double.  However, vertex attributes specified  
    as type ubyte are converted as described by Table 2.6.  
  
    The commands  
  
      void VertexAttribs{1234}{sfd}vNV(uint index, sizei n, T coords[]);  
      void VertexAttribs4ubvNV(uint index, sizei n, GLubyte coords[]);  
  
    specify a contiguous set of n vertex attributes.  The effect of  
  
      VertexAttribs{1234}{sfd}vNV(index, n, coords)  
  
    is the same (assuming no errors) as the command sequence  
  
      #define NUM k  /* where k is 1, 2, 3, or 4 components */  
      int i;  
      for (i=n-1; i>=0; i--) {  
        VertexAttrib{NUM}{sfd}vNV(i+index, &coords[i*NUM]);  
      }  
  
    VertexAttribs4ubvNV behaves similarly.  
  
    The VertexAttribNV calls equivalent to VertexAttribsNV are issued in  
    reverse order so that vertex program execution is provoked when index  
    is zero only after all the other vertex attributes have first been  
    specified.  
  
    2.14.1.2  The Program Parameter Registers  
  
    The Program Parameter Registers are ninety-six 4-component  
    floating-point vector registers containing the vertex program  
    parameters.  These registers are numbered 0 through 95.  This  
    relatively large set of registers is intended to hold parameters  
    such as matrices, lighting parameters, and constants required by  
    vertex programs.  Vertex program parameter registers can be updated  
    in one of two ways:  by the ProgramParameterNV commands outside  
    of a Begin/End pair or by a vertex state program executed outside  
    of a Begin/End pair (vertex state programs are discussed in section  
    2.14.3).  
  
    The commands  
       
      void ProgramParameter4fNV(enum target, uint index,  
                                float x, float y, float z, float w)  
      void ProgramParameter4dNV(enum target, uint index,  
                                double x, double y, double z, double w)  
  
    specify the particular program parameter indicated by index.  
    The coordinates values x, y, z, and w are assigned to the respective  
    components of the particular program parameter.  target must be  
    VERTEX_PROGRAM_NV.  
  
    The commands  
  
      void ProgramParameter4dvNV(enum target, uint index, double *params);  
      void ProgramParameter4fvNV(enum target, uint index, float *params);  
  
    operate identically to ProgramParameter4fNV and ProgramParameter4dNV  
    respectively except that the program parameters are passed as an  
    array of four components.  
  
    The commands  
  
      void ProgramParameters4dvNV(enum target, uint index,  
                                  uint num, double *params);  
      void ProgramParameters4fvNV(enum target, uint index,  
                                  uint num, float *params);  
  
    specify a contiguous set of num program parameters.  target must  
    be VERTEX_PROGRAM_NV.  The effect is the same (assuming no errors) as  
  
      for (i=index; i<index+num; i++) {  
        ProgramParameter4{fd}vNV(target, i, ¶ms[i*4]);  
      }  
  
    The program parameter registers are shared to all vertex program  
    invocations within a rendering context.  ProgramParameterNV command  
    updates and vertex state program executions are serialized with  
    respect to vertex program invocations and other vertex state program  
    executions.  
  
    Writes to the program parameter registers during vertex state program  
    execution can be maskable on a per-component basis.  
  
    The error INVALID_VALUE is generated if any ProgramParameterNV has  
    an index is greater than 95.  
  
    The initial value of all ninety-six program parameter registers is  
    (0,0,0,0).  
  
    2.14.1.3  The Address Register  
  
    The Address Register is a single 4-component vector signed 32-bit  
    integer register though only the x component of the vector is  
    accessible.  The register is private to each vertex program invocation  
    and is initialized to (0,0,0,0) at every vertex program invocation.  
    This register can be written during vertex program execution (but  
    not read) and its value can be used for as a relative offset for  
    reading vertex program parameter registers.  Only the vertex program  
    parameter registers can be read using relative addressing (writes  
    using relative addressing are not supported).  
  
    See the discussion of relative addressing of program parameters  
    in section 2.14.1.9 and the discussion of the ARL instruction in  
    section 2.14.1.10.1.  
  
    2.14.1.4  The Temporary Registers  
  
    The Temporary Registers are twelve 4-component floating-point vector  
    registers used to hold temporary results during vertex program  
    execution.  These registers are numbered 0 through 11.  These  
    registers are private to each vertex program invocation and  
    initialized to (0,0,0,0) at every vertex program invocation.  These  
    registers can be read and written during vertex program execution.  
    Writes to these registers can be maskable on a per-component basis.  
  
    2.14.1.5  The Vertex Result Register Set  
  
    The Vertex Result Registers are fifteen 4-component floating-point  
    vector registers used to write the results of a vertex program.  
    Each register value is initialized to (0,0,0,1) at the invocation  
    of each vertex program.  Writes to the vertex result registers can  
    be maskable on a per-component basis.  These registers are named in  
    Table X.1 and further discussed below.  
  
  
Vertex Result                                      Component  
Register Name   Description                        Interpretation  
--------------  ---------------------------------  --------------  
 HPOS            Homogeneous clip space position    (x,y,z,w)  
 COL0            Primary color (front-facing)       (r,g,b,a)  
 COL1            Secondary color (front-facing)     (r,g,b,a)  
 BFC0            Back-facing primary color          (r,g,b,a)  
 BFC1            Back-facing secondary color        (r,g,b,a)  
 FOGC            Fog coordinate                     (f,*,*,*)  
 PSIZ            Point size                         (p,*,*,*)  
 TEX0            Texture coordinate set 0           (s,t,r,q)  
 TEX1            Texture coordinate set 1           (s,t,r,q)  
 TEX2            Texture coordinate set 2           (s,t,r,q)  
 TEX3            Texture coordinate set 3           (s,t,r,q)  
 TEX4            Texture coordinate set 4           (s,t,r,q)  
 TEX5            Texture coordinate set 5           (s,t,r,q)  
 TEX6            Texture coordinate set 6           (s,t,r,q)  
 TEX7            Texture coordinate set 7           (s,t,r,q)  
  
    Table X.1:  Vertex Result Registers.  
  
    HPOS is the transformed vertex's homogeneous clip space position.  
    The vertex's homogeneous clip space position is converted to  
    normalized device coordinates and transformed to window coordinates  
    as described at the end of section 2.10 and in section 2.11.  
    Further processing (subsequent to vertex program termination)  
    is responsible for clipping primitives assembled from vertex  
    program-generated vertices as described in section 2.10 but all  
    client-defined clip planes are treated as if they are disabled when  
    vertex program mode is enabled.  
  
    Four distinct color results can be generated for each vertex.  
    COL0 is the transformed vertex's front-facing primary color.  
    COL1 is the transformed vertex's front-facing secondary color.  
    BFC0 is the transformed vertex's back-facing primary color.  BFC1 is  
    the transformed vertex's back-facing secondary color.  
  
    Primitive coloring may operate in two-sided color mode.  This behavior  
    is enabled and disabled by calling Enable or Disable with the  
    symbolic value VERTEX_PROGRAM_TWO_SIDE_NV.  The selection between  
    the back-facing colors and the front-facing colors depends on the  
    primitive of which the vertex is a part.  If the primitive is a  
    point or a line segment, the front-facing colors are always selected.  
    If the primitive is a polygon and two-sided color mode is disabled,  
    the front-facing colors are selected.  If it is a polygon and  
    two-sided color mode is enabled, then the selection is based on the  
    sign of the (clipped or unclipped) polygon's signed area computed in  
    window coordinates.  This facingness determination is identical to  
    the two-sided lighting facingness determination described in section  
    2.13.1.  
  
    The selected primary and secondary colors for each primitive are  
    clamped to the range [0,1] and then interpolated across the assembled  
    primitive during rasterization with at least 8-bit accuracy for each  
    color component.  
  
    FOGC is the transformed vertex's fog coordinate.  The register's  
    first floating-point component is interpolated across the assembled  
    primitive during rasterization and used as the fog distance to  
    compute per-fragment the fog factor when fog is enabled.  However,  
    if both fog and vertex program mode are enabled, but the FOGC vertex  
    result register is not written, the fog factor is overridden to 1.0.  
    The register's other three components are ignored.  
  
    Point size determination may operate in program-specified point  
    size mode.  This behavior is enabled and disabled by calling Enable  
    or Disable with the symbolic value VERTEX_PROGRAM_POINT_SIZE_NV.  
    If the vertex is for a point primitive and the mode is enabled  
    and the PSIZ vertex result is written, the point primitive's size  
    is determined by the clamped x component of the PSIZ register.  
    Otherwise (because vertex program mode is disabled, program-specified  
    point size mode is disabled, or because the vertex program did not  
    write PSIZ), the point primitive's size is determined by the point  
    size state (the state specified using the PointSize command).  
  
    The PSIZ register's x component is clamped to the range zero through  
    either the hi value of ALIASED_POINT_SIZE_RANGE if point smoothing  
    is disabled or the hi value of the SMOOTH_POINT_SIZE_RANGE if  
    point smoothing is enabled.  The register's other three components  
    are ignored.  
  
    If the vertex is not for a point primitive, the value of the  
    PSIZ vertex result register is ignored.  
  
    TEX0 through TEX7 are the transformed vertex's texture coordinate  
    sets for texture units 0 through 7.  These floating-point coordinates  
    are interpolated across the assembled primitive during rasterization  
    and used for accessing textures.  If the number of texture units  
    supported is less than eight, the values of vertex result registers  
    that do not correspond to existent texture units are ignored.  
  
    2.14.1.6  Semantic Meaning for Vertex Attributes and Program Parameters  
  
    One important distinction between the conventional GL vertex  
    transformation mode and the vertex program mode is that per-vertex  
    parameters and other state parameters in vertex program mode do  
    not have dedicated semantic interpretations the way that they do  
    with the conventional GL vertex transformation mode.  
  
    For example, in the conventional GL vertex transformation mode,  
    the Normal command specifies a per-vertex normal.  The semantic that  
    the Normal command supplies a normal for lighting is established because  
    that is how the per-vertex attribute supplied by the Normal command  
    is used by the conventional GL vertex transformation mode.  
    Similarly, other state parameters such as a light source position have  
    semantic interpretations based on how the conventional GL vertex  
    transformation model uses each particular parameter.  
  
    In contrast, vertex attributes and program parameters for vertex  
    programs have no pre-defined semantic meanings.  The meaning of  
    a vertex attribute or program parameter in vertex program mode is  
    defined by how the vertex attribute or program parameter is used by  
    the current vertex program to compute and write values to the Vertex  
    Result Registers.  This is the reason that per-vertex attributes and  
    program parameters for vertex programs are numbered instead of named.  
  
    For convenience however, the existing per-vertex parameters for the  
    conventional GL vertex transformation mode (vertices, normals,  
    colors, fog coordinates, vertex weights, and texture coordinates) are  
    aliased to numbered vertex attributes.  This aliasing is specified in  
    Table X.2.  The table includes how the various conventional components  
    map to the 4-component vertex attribute components.  
  
Vertex  
Attribute  Conventional                                           Conventional  
Register   Per-vertex        Conventional                         Component  
Number     Parameter         Per-vertex Parameter Command         Mapping  
---------  ---------------   -----------------------------------  ------------  
 0         vertex position   Vertex                               x,y,z,w  
 1         vertex weights    VertexWeightEXT                      w,0,0,1  
 2         normal            Normal                               x,y,z,1  
 3         primary color     Color                                r,g,b,a  
 4         secondary color   SecondaryColorEXT                    r,g,b,1  
 5         fog coordinate    FogCoordEXT                          fc,0,0,1  
 6         -                 -                                    -  
 7         -                 -                                    -  
 8         texture coord 0   MultiTexCoord(GL_TEXTURE0_ARB, ...)  s,t,r,q  
 9         texture coord 1   MultiTexCoord(GL_TEXTURE1_ARB, ...)  s,t,r,q  
 10        texture coord 2   MultiTexCoord(GL_TEXTURE2_ARB, ...)  s,t,r,q  
 11        texture coord 3   MultiTexCoord(GL_TEXTURE3_ARB, ...)  s,t,r,q  
 12        texture coord 4   MultiTexCoord(GL_TEXTURE4_ARB, ...)  s,t,r,q  
 13        texture coord 5   MultiTexCoord(GL_TEXTURE5_ARB, ...)  s,t,r,q  
 14        texture coord 6   MultiTexCoord(GL_TEXTURE6_ARB, ...)  s,t,r,q  
 15        texture coord 7   MultiTexCoord(GL_TEXTURE7_ARB, ...)  s,t,r,q  
  
Table X.2:  Aliasing of vertex attributes with conventional per-vertex  
parameters.  
  
    Only vertex attribute zero is treated specially because it is  
    the attribute that provokes the execution of the vertex program;  
    this is the attribute that aliases to the Vertex command's vertex  
    coordinates.  
  
    The result of a vertex program is the set of post-transformation  
    vertex parameters written to the Vertex Result Registers.  
    All vertex programs must write a homogeneous clip space position, but  
    the other Vertex Result Registers can be optionally written.  
  
    Clipping and culling are not the responsibility of vertex programs  
    because these operations assume the assembly of multiple vertices  
    into a primitive.  View frustum clipping is performed subsequent to  
    vertex program execution.  Clip planes are not supported in vertex  
    program mode.  
  
    2.14.1.7  Vertex Program Specification  
  
    Vertex programs are specified as an array of ubytes.  The array is  
    a string of ASCII characters encoding the program.  
  
    The command  
  
      LoadProgramNV(enum target, uint id, sizei len,  
                    const ubyte *program);  
  
    loads a vertex program when the target parameter is VERTEX_PROGRAM_NV.  
    Multiple programs can be loaded with different names.  id names the  
    program to load.  The name space for programs is the positive integers  
    (zero is reserved).  The error INVALID_VALUE occurs if a program is  
    loaded with an id of zero.  The error INVALID_OPERATION is generated  
    if a program is loaded for an id that is currently loaded with a  
    program of a different program target.  Managing the program name  
    space and binding to vertex programs is discussed later in section  
    2.14.1.8.  
  
    program is a pointer to an array of ubytes that represents the  
    program being loaded.  The length of the array is indicated by len.  
  
    A second program target type known as vertex state programs is  
    discussed in 2.14.4.  
  
    At program load time, the program is parsed into a set of tokens  
    possibly separated by white space.  Spaces, tabs, newlines, carriage  
    returns, and comments are considered whitespace.  Comments begin with  
    the character "#" and are terminated by a newline, a carriage return,  
    or the end of the program array.  
  
    The Backus-Naur Form (BNF) grammar below specifies the syntactically  
    valid sequences for vertex programs.  The set of valid tokens can be  
    inferred from the grammar.  The token "" represents an empty string  
    and is used to indicate optional rules.  A program is invalid if it  
    contains any undefined tokens or characters.  
  
    <program>              ::= "!!VP1.0" <instructionSequence> "END"  
  
    <instructionSequence>  ::= <instructionSequence> <instructionLine>  
                             | <instructionLine>  
  
    <instructionLine>      ::= <instruction> ";"  
  
    <instruction>          ::= <ARL-instruction>  
                             | <VECTORop-instruction>  
                             | <SCALARop-instruction>  
                             | <BINop-instruction>  
                             | <TRIop-instruction>  
  
    <ARL-instruction>      ::= "ARL" <addrReg> "," <scalarSrcReg>  
  
    <VECTORop-instruction> ::= <VECTORop> <maskedDstReg> "," <swizzleSrcReg>  
  
    <SCALARop-instruction> ::= <SCALARop> <maskedDstReg> "," <scalarSrcReg>  
  
    <BINop-instruction>    ::= <BINop> <maskedDstReg> ","  
                               <swizzleSrcReg> "," <swizzleSrcReg>  
  
    <TRIop-instruction>    ::= <TRIop> <maskedDstReg> ","  
                               <swizzleSrcReg> "," <swizzleSrcReg> ","  
                               <swizzleSrcReg>  
  
    <VECTORop>             ::= "MOV"  
                             | "LIT"  
  
    <SCALARop>             ::= "RCP"  
                             | "RSQ"  
                             | "EXP"  
                             | "LOG"  
  
    <BINop>                ::= "MUL"  
                             | "ADD"  
                             | "DP3"  
                             | "DP4"  
                             | "DST"  
                             | "MIN"  
                             | "MAX"  
                             | "SLT"  
                             | "SGE"  
  
    <TRIop>                ::= "MAD"  
  
    <scalarSrcReg>         ::= <optionalSign> <srcReg> <scalarSuffix>  
  
    <swizzleSrcReg>        ::= <optionalSign> <srcReg> <swizzleSuffix>  
  
    <maskedDstReg>         ::= <dstReg> <optionalMask>  
  
    <optionalMask>         ::= ""  
                             | "." "x"  
                             | "."     "y"  
                             | "." "x" "y"  
                             | "."         "z"  
                             | "." "x"     "z"  
                             | "."     "y" "z"  
                             | "." "x" "y" "z"  
                             | "."             "w"  
                             | "." "x"         "w"  
                             | "."     "y"     "w"  
                             | "." "x" "y"     "w"  
                             | "."         "z" "w"  
                             | "." "x"     "z" "w"  
                             | "."     "y" "z" "w"  
                             | "." "x" "y" "z" "w"  
  
    <optionalSign>         ::= "-"  
                             | ""  
  
    <srcReg>               ::= <vertexAttribReg>  
                             | <progParamReg>  
                             | <temporaryReg>  
  
    <dstReg>               ::= <temporaryReg>  
                             | <vertexResultReg>  
  
    <vertexAttribReg>      ::= "v" "[" vertexAttribRegNum "]"  
  
    <vertexAttribRegNum>   ::= decimal integer from 0 to 15 inclusive  
                             | "OPOS"  
                             | "WGHT"  
                             | "NRML"  
                             | "COL0"  
                             | "COL1"  
                             | "FOGC"  
                             | "TEX0"  
                             | "TEX1"  
                             | "TEX2"  
                             | "TEX3"  
                             | "TEX4"  
                             | "TEX5"  
                             | "TEX6"  
                             | "TEX7"  
  
    <progParamReg>         ::= <absProgParamReg>  
                             | <relProgParamReg>  
  
    <absProgParamReg>      ::= "c" "[" <progParamRegNum> "]"  
  
    <progParamRegNum>      ::= decimal integer from 0 to 95 inclusive  
  
    <relProgParamReg>      ::= "c" "[" <addrReg> "]"  
                             | "c" "[" <addrReg> "+" <progParamPosOffset> "]"  
                             | "c" "[" <addrReg> "-" <progParamNegOffset> "]"  
  
    <progParamPosOffset>   ::= decimal integer from 0 to 63 inclusive  
  
    <progParamNegOffset>   ::= decimal integer from 0 to 64 inclusive  
  
    <addrReg>              ::= "A0" "." "x"  
  
    <temporaryReg>         ::= "R0"  
                             | "R1"  
                             | "R2"  
                             | "R3"  
                             | "R4"  
                             | "R5"  
                             | "R6"  
                             | "R7"  
                             | "R8"  
                             | "R9"  
                             | "R10"  
                             | "R11"  
  
    <vertexResultReg>      ::= "o" "[" vertexResultRegName "]"  
  
    <vertexResultRegName>  ::= "HPOS"  
                             | "COL0"  
                             | "COL1"  
                             | "BFC0"  
                             | "BFC1"  
                             | "FOGC"  
                             | "PSIZ"  
                             | "TEX0"  
                             | "TEX1"  
                             | "TEX2"  
                             | "TEX3"  
                             | "TEX4"  
                             | "TEX5"  
                             | "TEX6"  
                             | "TEX7"  
  
    <scalarSuffix>         ::= "." <component>  
  
    <swizzleSuffix>        ::= ""  
                             | "." <component>  
                             | "." <component> <component>  
                                   <component> <component>  
  
    <component>            ::= "x"  
                             | "y"  
                             | "z"  
                             | "w"  
  
    The <vertexAttribRegNum> rule matches both register numbers 0 through  
    15 and a set of mnemonics that abbreviate the aliasing of conventional  
    the per-vertex parameters to vertex attribute register numbers.  
    Table X.3 shows the mapping from mnemonic to vertex attribute register  
    number and what the mnemonic abbreviates.  
  
           Vertex Attribute  
Mnemonic   Register Number     Meaning  
--------   ----------------    --------------------  
 "OPOS"     0                  object position  
 "WGHT"     1                  vertex weight  
 "NRML"     2                  normal  
 "COL0"     3                  primary color  
 "COL1"     4                  secondary color  
 "FOGC"     5                  fog coordinate  
 "TEX0"     8                  texture coordinate 0  
 "TEX1"     9                  texture coordinate 1  
 "TEX2"     10                 texture coordinate 2  
 "TEX3"     11                 texture coordinate 3  
 "TEX4"     12                 texture coordinate 4  
 "TEX5"     13                 texture coordinate 5  
 "TEX6"     14                 texture coordinate 6  
 "TEX7"     15                 texture coordinate 7  
  
Table X.3:  The mapping between vertex attribute register numbers,  
mnemonics, and meanings.  
  
    A vertex programs fails to load if it does not write at least one  
    component of the HPOS register.  
  
    A vertex program fails to load if it contains more than 128  
    instructions.  
  
    A vertex program fails to load if any instruction sources more than  
    one unique program parameter register.  
  
    A vertex program fails to load if any instruction sources more than  
    one unique vertex attribute register.  
  
    The error INVALID_OPERATION is generated if a vertex program fails  
    to load because it is not syntactically correct or for one of the  
    semantic restrictions listed above.  
  
    The error INVALID_OPERATION is generated if a program is loaded for  
    id when id is currently loaded with a program of a different target.  
  
    A successfully loaded vertex program is parsed into a sequence of  
    instructions.  Each instruction is identified by its tokenized name.  
    The operation of these instructions when executed is defined in  
    section 2.14.1.10.    
  
    A successfully loaded program replaces the program previously assigned  
    to the name specified by id.  If the OUT_OF_MEMORY error is generated  
    by LoadProgramNV, no change is made to the previous contents of the  
    named program.  
  
    Querying the value of PROGRAM_ERROR_POSITION_NV returns a ubyte  
    offset into the last loaded program string indicating where the first  
    error in the program.  If the program fails to load because of a  
    semantic restriction that cannot be determined until the program  
    is fully scanned, the error position will be len, the length of  
    the program.  If the program loads successfully, the value of  
    PROGRAM_ERROR_POSITION_NV is assigned the value negative one.  
  
    2.14.1.8  Vertex Program Binding and Program Management  
  
    The current vertex program is invoked whenever vertex attribute  
    zero is updated (whether by a VertexAttributeNV or Vertex command).  
    The current vertex program is updated by  
  
      BindProgramNV(enum target, uint id);  
  
    where target must be VERTEX_PROGRAM_NV.  This binds the vertex program  
    named by id as the current vertex program. The error INVALID_OPERATION  
    is generated if id names a program that is not a vertex program  
    (for example, if id names a vertex state program as described in  
    section 2.14.4).    
  
    Binding to a nonexistent program id does not generate an error.  
    In particular, binding to program id zero does not generate an error.  
    However, because program zero cannot be loaded, program zero is  
    always nonexistent.  If a program id is successfully loaded with a  
    new vertex program and id is also the currently bound vertex program,  
    the new program is considered the currently bound vertex program.  
  
    The INVALID_OPERATION error is generated when both vertex program  
    mode is enabled and Begin is called (or when a command that performs  
    an implicit Begin is called) if the current vertex program is  
    nonexistent or not valid.  A vertex program may not be valid for  
    reasons explained in section 2.14.5.  
  
    Programs are deleted by calling  
  
      void DeleteProgramsNV(sizei n, const uint *ids);  
  
    ids contains n names of programs to be deleted.  After a program  
    is deleted, it becomes nonexistent, and its name is again unused.  
    If a program that is currently bound is deleted, it is as though  
    BindProgramNV has been executed with the same target as the deleted  
    program and program zero.  Unused names in ids are silently ignored,  
    as is the value zero.  
  
    The command  
  
      void GenProgramsNV(sizei n, uint *ids);  
  
    returns n previously unused program names in ids.  These names  
    are marked as used, for the purposes of GenProgramsNV only,  
    but they become existent programs only when the are first loaded  
    using LoadProgramNV.  The error INVALID_VALUE is generated if n  
    is negative.  
  
    An implementation may choose to establish a working set of programs on  
    which binding and ExecuteProgramNV operations (execute programs are  
    explained in section 2.14.4) are performed with higher performance.  
    A program that is currently part of this working set is said to  
    be resident.  
  
    The command  
        
      boolean AreProgramsResidentNV(sizei n, const uint *ids,  
                                    boolean *residences);  
  
    returns TRUE if all of the n programs named in ids are resident,  
    or if the implementation does not distinguish a working set.  If at  
    least one of the programs named in ids is not resident, then FALSE is  
    returned, and the residence of each program is returned in residences.  
    Otherwise the contents of residences are not changed.  If any of  
    the names in ids are nonexistent or zero, FALSE is returned, the  
    error INVALID_VALUE is generated, and the contents of residences  
    are indeterminate.  The residence status of a single named program  
    can also be queried by calling GetProgramivNV with id set to the  
    name of the program and pname set to PROGRAM_RESIDENT_NV.  
  
    AreProgramsResidentNV indicates only whether a program is  
    currently resident, not whether it could not be made resident.  
    An implementation may choose to make a program resident only on  
    first use, for example.  The client may guide the GL implementation  
    in determining which programs should be resident by requesting a  
    set of programs to make resident.  
  
    The command  
  
      void RequestResidentProgramsNV(sizei n, const uint *ids);  
  
    requests that the n programs named in ids should be made resident.  
    While all the programs are not guaranteed to become resident,  
    the implementation should make a best effort to make as many of  
    the programs resident as possible.  As a result of making the  
    requested programs resident, program names not among the requested  
    programs may become non-resident.  Higher priority for residency  
    should be given to programs listed earlier in the ids array.  
    RequestResidentProgramsNV silently ignores attempts to make resident  
    nonexistent program names or zero.  AreProgramsResidentNV can be  
    called after RequestResidentProgramsNV to determine which programs  
    actually became resident.  
  
    2.14.1.9  Vertex Program Register Accesses  
  
    There are 17 vertex program instructions.  The instructions and their  
    respective input and output parameters are summarized in Table X.4.  
  
                             Output  
         Inputs              (vector or  
Opcode   (scalar or vector)  replicated scalar)   Operation  
------   ------------------  ------------------   --------------------------  
 ARL     s                   address register     address register load  
 MOV     v                   v                    move  
 MUL     v,v                 v                    multiply  
 ADD     v,v                 v                    add  
 MAD     v,v,v               v                    multiply and add  
 RCP     s                   ssss                 reciprocal  
 RSQ     s                   ssss                 reciprocal square root  
 DP3     v,v                 ssss                 3-component dot product  
 DP4     v,v                 ssss                 4-component dot product  
 DST     v,v                 v                    distance vector  
 MIN     v,v                 v                    minimum  
 MAX     v,v                 v                    maximum  
 SLT     v,v                 v                    set on less than  
 SGE     v,v                 v                    set on greater equal than  
 EXP     s                   v                    exponential base 2  
 LOG     s                   v                    logarithm base 2  
 LIT     v                   v                    light coefficients  
  
Table X.4:  Summary of vertex program instructions.  "v" indicates a  
vector input or output, "s" indicates a scalar input, and "ssss" indicates  
a scalar output replicated across a 4-component vector.  
  
    Instructions use either scalar source values or swizzled source  
    values, indicated in the grammar (see section 2.14.1.7) by the rules  
    <scalarSrcReg> and <swizzleSrcReg> respectively.  Either type of  
    source value is negated when the <optionalSign> rule matches "-".  
  
    Scalar source register values select one of the source register's  
    four components based on the <component> of the <scalarSuffix> rule.  
    The characters "x", "y", "z", and "w" match the x, y, z, and  
    w components respectively.  The indicated component is used as a  
    scalar for the particular source value.  
  
    Swizzled source register values may arbitrarily swizzle the source  
    register's components based on the <swizzleSuffix> rule.  In the case  
    where the <swizzleSuffix> matches (ignoring whitespace) the pattern  
    ".????" where each question mark is one of "x", "y", "z", or "w",  
    this indicates the ith component of the source register value should  
    come from the component named by the ith component in the sequence.  
    For example, if the swizzle suffix is ".yzzx" and the source register  
    contains [ 2.0, 8.0, 9.0, 0.0 ] the swizzled source register value  
    used by the instruction is [ 8.0, 9.0, 9.0, 2.0 ].  
  
    If the <swizzleSuffix> rule matches "", this is treated the same as  
    ".xyzw".  If the <swizzleSuffix> rule matches (ignoring whitespace)  
    ".x", ".y", ".z", or ".w", these are treated the same as ".xxxx",  
    ".yyyy", ".zzzz", and ".wwww" respectively.  
  
    The register sourced for either a scalar source register value or a  
    swizzled source register value is indicated in the grammar by the rule  
    <srcReg>.  The <vertexAttribReg>, <progParamReg>, and <temporaryReg>  
    sub-rules correspond to one of the vertex attribute registers,  
    program parameter registers, or temporary register respectively.  
  
    The vertex attribute and temporary registers are accessed absolutely  
    based on the numbered register.  In the case of vertex attribute  
    registers, if the <vertexAttribRegNum> corresponds to a mnemonic,  
    the corresponding register number from Table X.3 is used.  
  
    Either absolute or relative addressing can be used to access the  
    program parameter registers.  Absolute addressing is indicated by  
    the grammar by the <absProgParamReg> rule.  Absolute addressing  
    accesses the numbered program parameter register indicated by the  
    <progParamRegNum> rule.  Relative addressing accesses the numbered  
    program parameter register plus an offset.  The offset is the positive  
    value of <progParamPosOffset> if the <progParamPosOffset> rule is  
    matched, or the offset is the negative value of <progParamNegOffset>  
    if the <progParamNegOffset> rule is matched, or otherwise the offset  
    is zero.  Relative addressing is available only for program parameter  
    registers and only for reads (not writes).  Relative addressing  
    reads outside of the 0 to 95 inclusive range always read the value  
    (0,0,0,0).  
  
    The result of all instructions except ARL is written back to a  
    masked destination register, indicated in the grammar by the rule  
    <maskedDstReg>.  
  
    Writes to each component of the destination register can be masked,  
    indicated in the grammar by the <optionalMask> rule.  If the optional  
    mask is "", all components are written.  Otherwise, the optional  
    mask names particular components to write.  The characters "x",  
    "y", "z", and "w" match the x, y, z, and w components respectively.  
    For example, an optional mask of ".xzw" indicates that the x, z,  
    and w components should be written but not the y component.  
    The grammar requires that the destination register mask components  
    must be listed in "xyzw" order.  
  
    The actual destination register is indicated in the grammar by  
    the rule <dstReg>.  The <temporaryReg> and <vertexResultReg>  
    sub-rules correspond to either the temporary registers or vertex  
    result registers.  The temporary registers are determined and accessed  
    as described earlier.  
  
    The vertex result registers are accessed absolutely based on the  
    named register.  The <vertexResultRegName> rule corresponds to  
    registers named in Table X.1.  
  
    2.14.1.10  Vertex Program Instruction Set Operations  
  
    The operation of the 17 vertex program instructions are described in  
    this section.  After the textual description of each instruction's  
    operation, a register transfer level description is also presented.  
  
    The following conventions are used in each instruction's register  
    transfer level description.  The 4-component vector variables "t",  
    "u", and "v" are assigned intermediate results.  The destination  
    register is called "destination".  The three possible source registers  
    are called "source0", "source1", and "source2" respectively.  
  
    The x, y, z, and w vector components are referred to with the suffixes  
    ".x", ".y", ".z", and ".w" respectively.  The suffix ".c" is used for  
    scalar source register values and c represents the particular source  
    register's selected scalar component.  Swizzling of components is  
    indicated with the suffixes ".c***", ".*c**", ".**c*", and ".***c"  
    where c is meant to indicate the x, y, z, or w component selected for  
    the particular source operand swizzle configuration.  For example:  
  
      t.x = source0.c***;  
      t.y = source0.*c**;  
      t.z = source0.**c*;  
      t.w = source0.***c;  
  
    This example indicates that t should be assigned the swizzled  
    version of the source0 operand based on the source0 operand's swizzle  
    configuration.  
  
    The variables "negate0", "negate1", and "negate2" are booleans  
    that are true when the respective source value should be negated.  
    The variables "xmask", "ymask", "zmask", and "wmask" are booleans  
    that are true when the destination write mask for the respective  
    component is enabled for writing.  
  
    Otherwise, the register transfer level descriptions mimic ANSI C  
    syntax.  
  
    The idiom "IEEE(expression)" represents the s23e8 single-precision  
    result of the expression if evaluated using IEEE single-precision  
    floating point operations.  The IEEE idiom is used to specify the  
    maximum allowed deviation from IEEE single-precision floating-point  
    arithmetic results.  
  
    The following abbreviations are also used:  
  
      +Inf    floating-point representation of positive infinity  
      -Inf    floating-point representation of negative infinity  
      +NaN    floating-point representation of positive not a number  
      -NaN    floating-point representation of negative not a number  
      NA      not applicable or not used  
  
    2.14.1.10.1  ARL: Address Register Load  
  
    The ARL instruction moves value of the source scalar into the address  
    register.  Conceptually, the address register load instruction is  
    a 4-component vector signed integer register, but the only valid  
    address register component for writing and indexing is the x  
    component.  The only use for A0.x is as a base address for program  
    parameter reads.  The source value is a float that is truncated  
    towards negative infinity into a signed integer.  
  
        t.x = source0.c;  
        if (negate0) t.x = -t.x;  
        A0.x = floor(t.x);  
  
    2.14.1.10.2  MOV: Move  
  
    The MOV instruction moves the value of the source vector into the  
    destination register.  
  
        t.x = source0.c***;  
        t.y = source0.*c**;  
        t.z = source0.**c*;  
        t.w = source0.***c;  
        if (negate0) {  
          t.x = -t.x;  
          t.y = -t.y;  
          t.z = -t.z;  
          t.w = -t.w;  
        }  
        if (xmask) destination.x = t.x;  
        if (ymask) destination.y = t.y;  
        if (zmask) destination.z = t.z;  
        if (wmask) destination.w = t.w;  
  
    2.14.1.10.3  MUL: Multiply  
  
    The MUL instruction multiplies the values of the two source vectors  
    into the destination register.  
  
        t.x = source0.c***;  
        t.y = source0.*c**;  
        t.z = source0.**c*;  
        t.w = source0.***c;  
        if (negate0) {  
          t.x = -t.x;  
          t.y = -t.y;  
          t.z = -t.z;  
          t.w = -t.w;  
        }  
        u.x = source1.c***;  
        u.y = source1.*c**;  
        u.z = source1.**c*;  
        u.w = source1.***c;  
        if (negate1) {  
          u.x = -u.x;  
          u.y = -u.y;  
          u.z = -u.z;  
          u.w = -u.w;  
        }  
        if (xmask) destination.x = t.x * u.x;  
        if (ymask) destination.y = t.y * u.y;  
        if (zmask) destination.z = t.z * u.z;  
        if (wmask) destination.w = t.w * u.w;  
  
    2.14.1.10.4  ADD: Add  
  
    The ADD instruction adds the values of the two source vectors into  
    the destination register.  
  
        t.x = source0.c***;  
        t.y = source0.*c**;  
        t.z = source0.**c*;  
        t.w = source0.***c;  
        if (negate0) {  
          t.x = -t.x;  
          t.y = -t.y;  
          t.z = -t.z;  
          t.w = -t.w;  
        }  
        u.x = source1.c***;  
        u.y = source1.*c**;  
        u.z = source1.**c*;  
        u.w = source1.***c;  
        if (negate1) {  
          u.x = -u.x;  
          u.y = -u.y;  
          u.z = -u.z;  
          u.w = -u.w;  
        }  
        if (xmask) destination.x = t.x + u.x;  
        if (ymask) destination.y = t.y + u.y;  
        if (zmask) destination.z = t.z + u.z;  
        if (wmask) destination.w = t.w + u.w;  
  
    2.14.1.10.5  MAD: Multiply and Add  
  
    The MAD instruction adds the value of the third source vector to the  
    product of the values of the first and second two source vectors,  
    writing the result to the destination register.  
  
        t.x = source0.c***;  
        t.y = source0.*c**;  
        t.z = source0.**c*;  
        t.w = source0.***c;  
        if (negate0) {  
          t.x = -t.x;  
          t.y = -t.y;  
          t.z = -t.z;  
          t.w = -t.w;  
        }  
        u.x = source1.c***;  
        u.y = source1.*c**;  
        u.z = source1.**c*;  
        u.w = source1.***c;  
        if (negate1) {  
          u.x = -u.x;  
          u.y = -u.y;  
          u.z = -u.z;  
          u.w = -u.w;  
        }  
        v.x = source2.c***;  
        v.y = source2.*c**;  
        v.z = source2.**c*;  
        v.w = source2.***c;  
        if (negate2) {  
          v.x = -v.x;  
          v.y = -v.y;  
          v.z = -v.z;  
          v.w = -v.w;  
        }  
        if (xmask) destination.x = t.x * u.x + v.x;  
        if (ymask) destination.y = t.y * u.y + v.y;  
        if (zmask) destination.z = t.z * u.z + v.z;  
        if (wmask) destination.w = t.w * u.w + v.w;  
  
    2.14.1.10.6  RCP: Reciprocal  
  
    The RCP instruction inverts the value of the source scalar into  
    the destination register.  The reciprocal of exactly 1.0 must be  
    exactly 1.0.  
  
    Additionally the reciprocal of negative infinity gives [-0.0, -0.0,  
    -0.0, -0.0]; the reciprocal of negative zero gives [-Inf, -Inf, -Inf,  
    -Inf]; the reciprocal of positive zero gives [+Inf, +Inf, +Inf, +Inf];  
    and the reciprocal of positive infinity gives [0.0, 0.0, 0.0, 0.0].  
  
        t.x = source0.c;  
        if (negate0) {  
          t.x = -t.x;  
        }  
        if (t.x == 1.0f) {  
          u.x = 1.0f;  
        } else {  
          u.x = 1.0f / t.x;  
        }  
        if (xmask) destination.x = u.x;  
        if (ymask) destination.y = u.x;  
        if (zmask) destination.z = u.x;  
        if (wmask) destination.w = u.x;  
  
    where  
  
        | u.x - IEEE(1.0f/t.x) | < 1.0f/(2^22)  
  
    for 1.0f <= t.x <= 2.0f.  The intent of this precision requirement is  
    that this amount of relative precision apply over all values of t.x.  
  
    2.14.1.10.7  RSQ: Reciprocal Square Root  
  
    The RSQ instruction assigns the inverse square root of the  
    absolute value of the source scalar into the destination register.  
  
    Additionally, RSQ(0.0) gives [+Inf, +Inf, +Inf, +Inf]; and both  
    RSQ(+Inf) and RSQ(-Inf) give [0.0, 0.0, 0.0, 0.0];  
  
        t.x = source0.c;  
        if (negate0) {  
          t.x = -t.x;  
        }  
        u.x = 1.0f / sqrt(fabs(t.x));  
        if (xmask) destination.x = u.x;  
        if (ymask) destination.y = u.x;  
        if (zmask) destination.z = u.x;  
        if (wmask) destination.w = u.x;  
  
    where  
  
        | u.x - IEEE(1.0f/sqrt(fabs(t.x))) | < 1.0f/(2^22)  
  
    for 1.0f <= t.x <= 4.0f.  The intent of this precision requirement is  
    that this amount of relative precision apply over all values of t.x.  
  
    2.14.1.10.8  DP3: Three-Component Dot Product  
  
    The DP3 instruction assigns the three-component dot product of the  
    two source vectors into the destination register.  
  
        t.x = source0.c***;  
        t.y = source0.*c**;  
        t.z = source0.**c*;  
        if (negate0) {  
          t.x = -t.x;  
          t.y = -t.y;  
          t.z = -t.z;  
        }  
        u.x = source1.c***;  
        u.y = source1.*c**;  
        u.z = source1.**c*;  
        if (negate1) {  
          u.x = -u.x;  
          u.y = -u.y;  
          u.z = -u.z;  
        }  
        v.x = t.x * u.x + t.y * u.y + t.z * u.z;  
        if (xmask) destination.x = v.x;  
        if (ymask) destination.y = v.x;  
        if (zmask) destination.z = v.x;  
        if (wmask) destination.w = v.x;  
  
    2.14.1.10.9  DP4: Four-Component Dot Product  
  
    The DP4 instruction assigns the four-component dot product of the  
    two source vectors into the destination register.  
  
        t.x = source0.c***;  
        t.y = source0.*c**;  
        t.z = source0.**c*;  
        t.w = source0.***c;  
        if (negate0) {  
          t.x = -t.x;  
          t.y = -t.y;  
          t.z = -t.z;  
          t.w = -t.w;  
        }  
        u.x = source1.c***;  
        u.y = source1.*c**;  
        u.z = source1.**c*;  
        u.w = source1.***c;  
        if (negate1) {  
          u.x = -u.x;  
          u.y = -u.y;  
          u.z = -u.z;  
          u.w = -u.w;  
        }  
        v.x = t.x * u.x + t.y * u.y + t.z * u.z + t.w * u.w;  
        if (xmask) destination.x = v.x;  
        if (ymask) destination.y = v.x;  
        if (zmask) destination.z = v.x;  
        if (wmask) destination.w = v.x;  
  
    2.14.1.10.10  DST: Distance Vector  
  
    The DST instructions calculates a distance vector for the values  
    of two source vectors.  The first vector is assumed to be [NA, d*d,  
    d*d, NA] and the second source vector is assumed to be [NA, 1.0/d,  
    NA, 1.0/d], where the value of a component labeled NA is undefined.  
    The destination vector is then assigned [1,d,d*d,1.0/d].  
  
        t.y = source0.*c**;  
        t.z = source0.**c*;  
        if (negate0) {  
          t.y = -t.y;  
          t.z = -t.z;  
        }  
        u.y = source1.*c**;  
        u.w = source1.***c;  
        if (negate1) {  
          u.y = -u.y;  
          u.w = -u.w;  
        }  
        if (xmask) destination.x = 1.0;  
        if (ymask) destination.y = t.y*u.y;  
        if (zmask) destination.z = t.z;  
        if (wmask) destination.w = u.w;  
  
    2.14.1.10.11  MIN: Minimum  
  
    The MIN instruction assigns the component-wise minimum of the two  
    source vectors into the destination register.  
  
        t.x = source0.c***;  
        t.y = source0.*c**;  
        t.z = source0.**c*;  
        t.w = source0.***c;  
        if (negate0) {  
          t.x = -t.x;  
          t.y = -t.y;  
          t.z = -t.z;  
          t.w = -t.w;  
        }  
        u.x = source1.c***;  
        u.y = source1.*c**;  
        u.z = source1.**c*;  
        u.w = source1.***c;  
        if (negate1) {  
          u.x = -u.x;  
          u.y = -u.y;  
          u.z = -u.z;  
          u.w = -u.w;  
        }  
        if (xmask) destination.x = (t.x < u.x) ? t.x : u.x;  
        if (ymask) destination.y = (t.y < u.y) ? t.y : u.y;  
        if (zmask) destination.z = (t.z < u.z) ? t.z : u.z;  
        if (wmask) destination.w = (t.w < u.w) ? t.w : u.w;  
  
    2.14.1.10.12  MAX: Maximum  
  
    The MAX instruction assigns the component-wise maximum of the two  
    source vectors into the destination register.  
  
        t.x = source0.c***;  
        t.y = source0.*c**;  
        t.z = source0.**c*;  
        t.w = source0.***c;  
        if (negate0) {  
          t.x = -t.x;  
          t.y = -t.y;  
          t.z = -t.z;  
          t.w = -t.w;  
        }  
        u.x = source1.c***;  
        u.y = source1.*c**;  
        u.z = source1.**c*;  
        u.w = source1.***c;  
        if (negate1) {  
          u.x = -u.x;  
          u.y = -u.y;  
          u.z = -u.z;  
          u.w = -u.w;  
        }  
        if (xmask) destination.x = (t.x >= u.x) ? t.x : u.x;  
        if (ymask) destination.y = (t.y >= u.y) ? t.y : u.y;  
        if (zmask) destination.z = (t.z >= u.z) ? t.z : u.z;  
        if (wmask) destination.w = (t.w >= u.w) ? t.w : u.w;  
  
    2.14.1.10.13  SLT: Set On Less Than  
  
    The SLT instruction performs a component-wise assignment of either  
    1.0 or 0.0 into the destination register.  1.0 is assigned if the  
    value of the first source vector is less than the value of the second  
    source vector; otherwise, 0.0 is assigned.  
  
        t.x = source0.c***;  
        t.y = source0.*c**;  
        t.z = source0.**c*;  
        t.w = source0.***c;  
        if (negate0) {  
          t.x = -t.x;  
          t.y = -t.y;  
          t.z = -t.z;  
          t.w = -t.w;  
        }  
        u.x = source1.c***;  
        u.y = source1.*c**;  
        u.z = source1.**c*;  
        u.w = source1.***c;  
        if (negate1) {  
          u.x = -u.x;  
          u.y = -u.y;  
          u.z = -u.z;  
          u.w = -u.w;  
        }  
        if (xmask) destination.x = (t.x < u.x) ? 1.0 : 0.0;  
        if (ymask) destination.y = (t.y < u.y) ? 1.0 : 0.0;  
        if (zmask) destination.z = (t.z < u.z) ? 1.0 : 0.0;  
        if (wmask) destination.w = (t.w < u.w) ? 1.0 : 0.0;  
  
    2.14.1.10.14  SGE: Set On Greater or Equal Than  
  
    The SGE instruction performs a component-wise assignment of either  
    1.0 or 0.0 into the destination register.  1.0 is assigned if the  
    value of the first source vector is greater than or equal the value  
    of the second source vector; otherwise, 0.0 is assigned.  
  
        t.x = source0.c***;  
        t.y = source0.*c**;  
        t.z = source0.**c*;  
        t.w = source0.***c;  
        if (negate0) {  
          t.x = -t.x;  
          t.y = -t.y;  
          t.z = -t.z;  
          t.w = -t.w;  
        }  
        u.x = source1.c***;  
        u.y = source1.*c**;  
        u.z = source1.**c*;  
        u.w = source1.***c;  
        if (negate1) {  
          u.x = -u.x;  
          u.y = -u.y;  
          u.z = -u.z;  
          u.w = -u.w;  
        }  
        if (xmask) destination.x = (t.x >= u.x) ? 1.0 : 0.0;  
        if (ymask) destination.y = (t.y >= u.y) ? 1.0 : 0.0;  
        if (zmask) destination.z = (t.z >= u.z) ? 1.0 : 0.0;  
        if (wmask) destination.w = (t.w >= u.w) ? 1.0 : 0.0;  
  
    2.14.1.10.15  EXP: Exponential Base 2  
  
    The EXP instruction generates an approximation of the exponential base  
    2 for the value of a source scalar.  This approximation is assigned  
    to the z component of the destination register.  Additionally,  
    the x and y components of the destination register are assigned  
    values useful for determining a more accurate approximation.  The  
    exponential base 2 of the source scalar can be better approximated  
    by destination.x*FUNC(destination.y) where FUNC is some user  
    approximation (presumably implemented by subsequent instructions in  
    the vertex program) to 2^destination.y where 0.0 <= destination.y <  
    1.0.  
  
    Additionally, EXP(-Inf) or if the exponential result underflows  
    gives [0.0, 0.0, 0.0, 1.0]; and EXP(+Inf) or if the exponential result  
    overflows gives [+Inf, 0.0, +Inf, 1.0].  
  
        t.x = source0.c;  
        if (negate0) {  
          t.x = -t.x;  
        }  
        q.x = 2^floor(t.x);  
        q.y = t.x - floor(t.x);  
        q.z = q.x * APPX(q.y);  
        if (xmask) destination.x = q.x;  
        if (ymask) destination.y = q.y;  
        if (zmask) destination.z = q.z;  
        if (wmask) destination.w = 1.0;  
  
    where APPX is an implementation dependent approximation of exponential  
    base 2 such that  
  
        | exp(q.y*log(2.0))-APPX(q.y) | < 1/(2^11)  
  
    for all 0 <= q.y < 1.0.  
  
    The expression "2^floor(t.x)" should overflow to +Inf and underflow  
    to zero.  
  
    2.14.1.10.16  LOG: Logarithm Base 2  
  
    The LOG instruction generates an approximation of the logarithm base  
    2 for the absolute value of a source scalar.  This approximation  
    is assigned to the z component of the destination register.  
    Additionally, the x and y components of the destination register are  
    assigned values useful for determining a more accurate approximation.  
    The logarithm base 2 of the absolute value of the source scalar  
    can be better approximated by destination.x+FUNC(destination.y)  
    where FUNC is some user approximation (presumably implemented by  
    subsequent instructions in the vertex program) of log2(destination.y)  
    where 1.0 <= destination.y < 2.0.  
  
    Additionally, LOG(0.0) gives [-Inf, 1.0, -Inf, 1.0]; and both  
    LOG(+Inf) and LOG(-Inf) give [+Inf, 1.0, +Inf, 1.0].  
  
        t.x = source0.c;  
        if (negate0) {  
          t.x = -t.x;  
        }  
        if (fabs(t.x) != 0.0f) {  
          if (fabs(t.x) == +Inf) {  
            q.x = +Inf;  
            q.y = 1.0;  
            q.z = +Inf;  
          } else {  
            q.x = Exponent(t.x);  
            q.y = Mantissa(t.x);  
            q.z = q.x + APPX(q.y);  
          }  
        } else {  
          q.x = -Inf;  
          q.y = 1.0;  
          q.z = -Inf;  
        }  
        if (xmask) destination.x = q.x;  
        if (ymask) destination.y = q.y;  
        if (zmask) destination.z = q.z;  
        if (wmask) destination.w = 1.0;  
  
    where APPX is an implementation dependent approximation of logarithm  
    base 2 such that  
      
        | log(q.y)/log(2.0) - APPX(q.y) | < 1/(2^11)  
  
    for all 1.0 <= q.y < 2.0.  
  
    The "Exponent(t.x)" function returns the unbiased exponent between  
    -126 and 127.  For example, "Exponent(1.0)" equals 0.0.  (Note that  
    the IEEE floating-point representation maintains the exponent as a  
    biased value.) Larger or smaller exponents should generate +Inf or  
    -Inf respectively.  The "Mantissa(t.x)" function returns a value  
    in the range [1.0f, 2.0).  The intent of these functions is that  
    fabs(t.x) is approximately "Mantissa(t.x)*2^Exponent(t.x)".  
  
    2.14.1.10.17  LIT: Light Coefficients  
  
    The LIT instruction is intended to compute ambient, diffuse,  
    and specular lighting coefficients from a diffuse dot product,  
    a specular dot product, and a specular power that is clamped to  
    (-128,128) exclusive.  The x component of the source vector is  
    assumed to contain a diffuse dot product (unit normal vector dotted  
    with a unit light vector).  The y component of the source vector is  
    assumed to contain a Blinn specular dot product (unit normal vector  
    dotted with a unit half-angle vector).  The w component is assumed  
    to contain a specular power.  
  
    An implementation must support at least 8 fraction bits in the  
    specular power.  Note that because 0.0 times anything must be 0.0,  
    taking any base to the power of 0.0 will yield 1.0.  
  
        t.x = source0.c***;  
        t.y = source0.*c**;  
        t.w = source0.***c;  
        if (negate0) {  
          t.x = -t.x;  
          t.y = -t.y;  
          t.w = -t.w;  
        }  
        if (t.w < -(128.0-epsilon)) t.w = -(128.0-epsilon);  
        else if (t.w > 128-epsilon) t.w = 128-epsilon;  
        if (t.x < 0.0) t.x = 0.0;  
        if (t.y < 0.0) t.y = 0.0;  
        if (xmask) destination.x = 1.0;  
        if (ymask) destination.y = t.x;  
        if (zmask) destination.z = (t.x > 0.0) ? EXP(t.w*LOG(t.y)) : 0.0;  
        if (wmask) destination.w = 1.0;  
  
    where EXP and LOG are functions that approximate the exponential base  
    2 and logarithm base 2 with the identical accuracy and special case  
    requirements of the EXP and LOG instructions.  epsilon is 1.0/256.0  
    or approximately 0.0039 which would correspond to representing the  
    specular power with a s8.8 representation.  
  
    2.14.1.11  Vertex Program Floating Point Requirements  
  
    All vertex program calculations are assumed to use IEEE single  
    precision floating-point math with a format of s1e8m23 (one signed  
    bit, 8 bits of exponent, 23 bits of magnitude) or better and the  
    round-to-zero rounding mode.  The only exceptions to this are the RCP,  
    RSQ, LOG, EXP, and LIT instructions.  
  
    Note that (positive or negative) 0.0 times anything is (positive)  
    0.0.  
  
    The RCP and RSQ instructions deliver results accurate to 1.0/(2^22)  
    and the approximate output (the z component) of the EXP and LOG  
    instructions only has to be accurate to 1.0/(2^11).  The LIT  
    instruction specular output (the z component) is allowed an error  
    equivalent to the combination of the EXP and LOG combination to  
    implement a power function.  
  
    The floor operations used by the ARL and EXP instructions must  
    operate identically.  Specifically, the EXP instruction's floor(t.x)  
    intermediate result must exactly match the integer stored in the  
    address register by the ARL instruction.  
  
    Since distance is calculated as (d^2)*(1/sqrt(d^2)), 0.0 multiplied  
    by anything must be 0.0.  This affects the MUL, MAD, DP3, DP4, DST,  
    and LIT instructions.  
  
    Because if/then/else conditional evaluation is done by multiplying  
    by 1.0 or 0.0 and adding, the floating point computations require:  
  
      0.0 * x = 0.0    for all x (including +Inf, -Inf, +NaN, and -NaN)  
      1.0 * x = x      for all x (including +Inf and -Inf)  
      0.0 + x = x      for all x (including +Inf and -Inf)  
  
    Including +Inf, -Inf, +NaN, and -NaN when applying the above three  
    rules is recommended but not required.  (The recommended inclusion  
    of +Inf, -Inf, +NaN, and -NaN when applying the first rule is  
    inconsistent with IEEE floating-point requirements.)  
  
    For the purpose of comparisons performed by the SGE and SLT  
    instructions, -0.0 is less than +0.0, -NaN is less than -Inf,  
    and +NaN is greater than +Inf.  (This is inconsistent with IEEE  
    floating-point requirements).  
  
    No floating-point exceptions or interrupts are generated.  Denorms  
    are not supported; if a denorm is input, it is treated as 0.0 (ie,  
    denorms are flushed to zero).  
  
    Computations involving +NaN or -NaN generate +NaN, except for the  
    requirement that zero times +NaN or -NaN must always be zero.  (This  
    exception is inconsistent with IEEE floating-point requirements).  
  
    2.14.2  Vertex Program Update for the Current Raster Position  
  
    When vertex programs are enabled, the raster position is determined  
    by the current vertex program.  The raster position specified by  
    RasterPos is treated as if they were specified in a Vertex command.  
    The contents of vertex result register set is used to update respective  
    raster position state.  
  
    Assuming an existent program, the homogeneous clip-space coordinates  
    are passed to clipping as if they represented a point and assuming no  
    client-defined clip planes are enabled.  If the point is not culled,  
    then the projection to window coordinates is computed (section 2.10)  
    and saved as the current raster position and the valid bit is set.  
    If the current vertex program is nonexistent or the "point" is  
    culled, the current raster position and its associated data become  
    indeterminate and the raster position valid bit is cleared.  
  
    2.14.3  Vertex Arrays for Vertex Attributes  
  
    Data for vertex attributes in vertex program mode may be specified  
    using vertex array commands.  The client may specify and enable any  
    of sixteen vertex attribute arrays.  
  
    The vertex attribute arrays are ignored when vertex program mode  
    is disabled.  When vertex program mode is enabled, vertex attribute  
    arrays are used.  
  
    The command  
  
      void VertexAttribPointerNV(uint index, int size, enum type,  
                                 sizei stride, const void *pointer);  
  
    describes the locations and organizations of the sixteen vertex  
    attribute arrays.  index specifies the particular vertex attribute  
    to be described.  size indicates the number of values per vertex  
    that are stored in the array; size must be one of 1, 2, 3, or 4.  
    type specifies the data type of the values stored in the array.  
    type must be one of SHORT, FLOAT, DOUBLE, or UNSIGNED_BYTE and these  
    values correspond to the array types short, int, float, double, and  
    ubyte respectively.  The INVALID_OPERATION error is generated if  
    type is UNSIGNED_BYTE and size is not 4.  The INVALID_VALUE error  
    is generated if index is greater than 15.  The INVALID_VALUE error  
    is generated if stride is negative.  
  
    The one, two, three, or four values in an array that correspond to a  
    single vertex attribute comprise an array element.  The values within  
    each array element at stored sequentially in memory.  If the stride  
    is specified as zero, then array elements are stored sequentially  
    as well.  Otherwise points to the ith and (i+1)st elements of an array  
    differ by stride basic machine units (typically unsigned bytes),  
    the pointer to the (i+1)st element being greater.  pointer specifies  
    the location in memory of the first value of the first element of  
    the array being specified.  
  
    Vertex attribute arrays are enabled with the EnableClientState command  
    and disabled with the DisableClientState command.  The value of the  
    argument to either command is VERTEX_ATTRIB_ARRAYi_NV where i is an  
    integer between 0 and 15; specifying a value of i enables or  
    disables the vertex attribute array with index i.  The constants  
    obey VERTEX_ATTRIB_ARRAYi_NV = VERTEX_ATTRIB_ARRAY0_NV + i.  
  
    When vertex program mode is enabled, the ArrayElement command operates  
    as described in this section in contrast to the behavior described  
    in section 2.8.  Likewise, any vertex array transfer commands that  
    are defined in terms of ArrayElement (DrawArrays, DrawElements, and  
    DrawRangeElements) assume the operation of ArrayElement described  
    in this section when vertex program mode is enabled.  
  
    When vertex program mode is enabled, the ArrayElement command  
    transfers the ith element of particular enabled vertex arrays as  
    described below.  For each enabled vertex attribute array, it is  
    as though the corresponding command from section 2.14.1.1 were  
    called with a pointer to element i.  For each vertex attribute,  
    the corresponding command is VertexAttrib[size][type]v, where size  
    is one of [1,2,3,4], and type is one of [s,f,d,ub], corresponding  
    to the array types short, int, float, double, and ubyte respectively.  
  
    However, if a given vertex attribute array is disabled, but its  
    corresponding aliased conventional per-vertex parameter's vertex  
    array (as described in section 2.14.1.6) is enabled, then it is  
    as though the corresponding command from section 2.7 or section  
    2.6.2 were called with a pointer to element i.  In this case, the  
    corresponding command is determined as described in section 2.8's  
    description of ArrayElement.  
  
    If the vertex attribute array 0 is enabled, it is as though  
    VertexAttrib[size][type]v(0, ...) is executed last, after the  
    executions of other corresponding commands.  If the vertex attribute  
    array 0 is disabled but the vertex array is enabled, it is as though  
    Vertex[size][type]v is executed last, after the executions of other  
    corresponding commands.  
  
    2.14.4  Vertex State Programs  
  
    Vertex state programs share the same instruction set as and a similar  
    execution model to vertex programs.  While vertex program are executed  
    implicitly when a vertex transformation is provoked, vertex state  
    programs are executed explicitly, independently of any vertices.  
    Vertex state programs can write program parameter registers, but  
    may not write vertex result registers.  
  
    The purpose of a vertex state program is to update program parameter  
    registers by means of an application-defined program.  Typically,  
    an application will load a set of program parameters and then execute  
    a vertex state program that reads and updates the program parameter  
    registers.  For example, a vertex state program might normalize a  
    set of unnormalized vectors previously loaded as program parameters.  
    The expectation is that subsequently executed vertex programs would  
    use the normalized program parameters.  
  
    Vertex state programs are loaded with the same LoadProgramNV command  
    (see section 2.14.1.7) used to load vertex programs except that the  
    target must be VERTEX_STATE_PROGRAM_NV when loading a vertex state  
    program.  
  
    Vertex state programs must conform to a more limited grammar than  
    the grammar for vertex programs.  The vertex state program grammar  
    for syntactically valid sequences is the same as the grammar defined  
    in section 2.14.1.7 with the following modified rules:  
  
    <program>              ::= "!!VSP1.0" <instructionSequence> "END"  
  
    <dstReg>               ::= <absProgParamReg>  
                             | <temporaryReg>  
  
    <vertexAttribReg>      ::= "v" "[" "0" "]"  
  
    A vertex state program fails to load if it does not write at least  
    one program parameter register.  
  
    A vertex state program fails to load if it contains more than 128  
    instructions.  
  
    A vertex state program fails to load if any instruction sources more  
    than one unique program parameter register.  
  
    A vertex state program fails to load if any instruction sources  
    more than one unique vertex attribute register (this is necessarily  
    true because only vertex attribute 0 is available in vertex state  
    programs).  
  
    The error INVALID_OPERATION is generated if a vertex state program  
    fails to load because it is not syntactically correct or for one  
    of the other reasons listed above.  
  
    A successfully loaded vertex state program is parsed into a sequence  
    of instructions.  Each instruction is identified by its tokenized  
    name.  The operation of these instructions when executed is defined  
    in section 2.14.1.10.  
  
    Executing vertex state programs is legal only outside a Begin/End  
    pair.  A vertex state program may not read any vertex attribute  
    register other than register zero.  A vertex state program may not  
    write any vertex result register.  
  
    The command  
  
      ExecuteProgramNV(enum target, uint id, const float *params);  
  
    executes the vertex state program named by id.  The target must be  
    VERTEX_STATE_PROGRAM_NV and the id must be the name of program loaded  
    with a target type of VERTEX_STATE_PROGRAM_NV.  params points to  
    an array of four floating-point values that are loaded into vertex  
    attribute register zero (the only vertex attribute readable from a  
    vertex state program).  
  
    The INVALID_OPERATION error is generated if the named program is  
    nonexistent, is invalid, or the program is not a vertex state  
    program.  A vertex state program may not be valid for reasons  
    explained in section 2.14.5.  
  
    2.14.5  Tracking Matrices   
  
    As a convenience to applications, standard GL matrix state can be  
    tracked into program parameter vectors.  This permits vertex programs  
    to access matrices specified through GL matrix commands.  
  
    In addition to GL's conventional matrices, several additional matrices  
    are available for tracking.  These matrices have names of the form  
    MATRIXi_NV where i is between zero and n-1 where n is the value  
    of the MAX_TRACK_MATRICES_NV implementation dependent constant.  
    The MATRIXi_NV constants obey MATRIXi_NV = MATRIX0_NV + i.  The value  
    of MAX_TRACK_MATRICES_NV must be at least eight.  The maximum  
    stack depth for tracking matrices is defined by the  
    MAX_TRACK_MATRIX_STACK_DEPTH_NV and must be at least 1.  
  
    The command  
  
      TrackMatrixNV(enum target, uint address, enum matrix, enum transform);  
  
    tracks a given transformed version of a particular matrix into  
    a contiguous sequence of four vertex program parameter registers  
    beginning at address.  target must be VERTEX_PROGRAM_NV (though  
    tracked matrices apply to vertex state programs as well because both  
    vertex state programs and vertex programs shared the same program  
    parameter registers).  matrix must be one of NONE, MODELVIEW,  
    PROJECTION, TEXTURE, TEXTUREi_ARB (where i is between 0 and n-1  
    where n is the number of texture units supported), COLOR (if  
    the ARB_imaging subset is supported), MODELVIEW_PROJECTION_NV,  
    or MATRIXi_NV.  transform must be one of IDENTITY_NV, INVERSE_NV,  
    TRANSPOSE_NV, or INVERSE_TRANSPOSE_NV.  The INVALID_VALUE error is  
    generated if address is not a multiple of four.  
  
    The MODELVIEW_PROJECTION_NV matrix represents the concatenation of  
    the current modelview and projection matrices.  If M is the current  
    modelview matrix and P is the current projection matrix, then the  
    MODELVIEW_PROJECTION_NV matrix is C and computed as  
  
        C = P M  
  
    Matrix tracking for the specified program parameter register and the  
    next consecutive three registers is disabled when NONE is supplied  
    for matrix.  When tracking is disabled the previously tracked program  
    parameter registers retain the state of their last tracked values.  
    Otherwise, the specified transformed version of matrix is tracked into  
    the specified program parameter register and the next three registers.  
    Whenever the matrix changes, the transformed version of the matrix  
    is updated in the specified range of program parameter registers.  
    If TEXTURE is specified for matrix, the texture matrix for the current  
    active texture unit is tracked.  If TEXTUREi_ARB is specified for  
    matrix, the <i>th texture matrix is tracked.  
  
    Matrices are tracked row-wise meaning that the top row of the  
    transformed matrix is loaded into the program parameter address,  
    the second from the top row of the transformed matrix is loaded into  
    the program parameter address+1, the third from the top row of the  
    transformed matrix is loaded into the program parameter address+2,  
    and the bottom row of the transformed matrix is loaded into the  
    program parameter address+3.  The transformed matrix may be identical  
    to the specified matrix, the inverse of the specified matrix, the  
    transpose of the specified matrix, or the inverse transpose of the  
    specified matrix, depending on the value of transform.  
  
    When matrix tracking is enabled for a particular program parameter  
    register sequence, updates to the program parameter using  
    ProgramParameterNV commands, a vertex program, or a vertex state  
    program are not possible.  The INVALID_OPERATION error is generated  
    if a ProgramParameterNV command is used to update a program parameter  
    register currently tracking a matrix.  
  
    The INVALID_OPERATION error is generated by ExecuteProgramNV when  
    the vertex state program requested for execution writes to a program  
    parameter register that is currently tracking a matrix because the  
    program is considered invalid.  
  
    2.14.6  Required Vertex Program State   
  
    The state required for vertex programs consists of:  
  
      a bit indicating whether or not program mode is enabled;  
  
      a bit indicating whether or not two-sided color mode is enabled;  
  
      a bit indicating whether or not program-specified point size mode  
      is enabled;  
  
      96 4-component floating-point program parameter registers;  
  
      16 4-component vertex attribute registers (though this state is  
      aliased with the current normal, primary color, secondary color,  
      fog coordinate, weights, and texture coordinate sets);  
  
      24 sets of matrix tracking state for each set of four sequential  
      program parameter registers, consisting of a n-valued integer  
      indicated the tracked matrix or GL_NONE (where n is 5 + the number  
      of texture units supported + the number of tracking matrices  
      supported) and a four-valued integer indicating the transformation  
      of the tracked matrix;  
  
      an unsigned integer naming the currently bound vertex program  
  
      and the state must be maintained to indicate which integers  
      are currently in use as program names.  
  
   Each existent program object consists of a target, a boolean indicating  
   whether the program is resident, an array of type ubyte containing the  
   program string, and the length of the program string array.  Initially,  
   no program objects exist.  
  
   Program mode, two-sided color mode, and program-specified point size  
   mode are all initially disabled.  
  
   The initial state of all 96 program parameter registers is (0,0,0,0).  
  
   The initial state of the 16 vertex attribute registers is (0,0,0,1)  
   except in cases where a vertex attribute register aliases to a  
   conventional GL transform mode vertex parameter in which case  
   the initial state is the initial state of the respective aliased  
   conventional vertex parameter.  
  
   The initial state of the 24 sets of matrix tracking state is NONE  
   for the tracked matrix and IDENTITY_NV for the transformation of the  
   tracked matrix.  
  
   The initial currently bound program is zero.  
  
   The client state required to implement the 16 vertex attribute  
   arrays consists of 16 boolean values, 16 memory pointers, 16 integer  
   stride values, 16 symbolic constants representing array types,  
   and 16 integers representing values per element.  Initially, the  
   boolean values are each disabled, the memory pointers are each null,  
   the strides are each zero, the array types are each FLOAT, and the  
   integers representing values per element are each four."  
  
homeprevnext Additions to Chapter 3 of the OpenGL 1.2.1 Specification (Rasterization)
  
 --  Section 3.3 "Points"  
  
   Change the first paragraph to read:  
  
   "When program vertex mode is disabled, the point size for rasterizing  
   points is controlled with  
  
     void PointSize(float size);  
  
   size specifies the width or diameter of a point.  The initial point size  
   value is 1.0.  A value less than or equal to zero results in the error  
   INVALID_VALUE.  When vertex program mode is enabled, the point size for  
   rasterizing points is determined as described in section 2.14.1.5."  
  
 --  Section 3.9 "Color Sum"  
  
   Change the first paragraph to read:  
  
   "At the beginning of color sum, a fragment has two RGBA colors:  a  
   primary color cpri (which texturing, if enabled, may have modified)  
   and a secondary color csec.  If vertex program mode is disabled, csec  
   is defined by the lighting equations in section 2.13.1.  If vertex  
   program mode is enabled, csec is the fragment's secondary color,  
   obtained by interpolating the COL1 (or BFC1 if the primitive is a  
   polygon, the vertex program two-sided color mode is enabled, and the  
   polygon is back-facing) vertex result register RGB components for the  
   vertices making up the primitive; the alpha component of csec when  
   program mode is enabled is always zero.  The components of these two  
   colors are summed to produce a single post-texturing RGBA color c.  
   The components of c are then clamped to the range [0,1]."  
  
 --  Section 3.10 "Fog"  
  
   Change the initial sentences in the second paragraph to read:  
  
   "This factor f may be computed according to one of three equations:  
  
            f = exp(-d*c)                                (3.24)  
            f = exp(-(d*c)^2)                            (3.25)  
            f = (e-c)/(e-s)                              (3.26)  
  
   If vertex program mode is enabled, then c is the fragment's fog  
   coordinate, obtained by interpolating the FOGC vertex result register  
   values for the vertices making up the primitive.  When vertex program  
   mode is disabled, the c is the eye-coordinate distance from the eye,  
   (0,0,0,1) in eye-coordinates, to the fragment center." ...  
  
homeprevnext Additions to Chapter 4 of the OpenGL 1.2.1 Specification (Per-Fragment Operations and the Framebuffer)
  
    None  
  
homeprevnext Additions to Chapter 5 of the OpenGL 1.2.1 Specification (Special Functions)
  
 --  Section 5.1 "Evaluators"  
  
    Add the following lines to the end of table 5.1 (page 165):  
  
    target                      k   values  
    -------------------------  ---  ------------------------------  
    MAP1_VERTEX_ATTRIB0_4_NV    4   x, y, z, w vertex attribute 0  
    MAP1_VERTEX_ATTRIB1_4_NV    4   x, y, z, w vertex attribute 1  
    MAP1_VERTEX_ATTRIB2_4_NV    4   x, y, z, w vertex attribute 2  
    MAP1_VERTEX_ATTRIB3_4_NV    4   x, y, z, w vertex attribute 3  
    MAP1_VERTEX_ATTRIB4_4_NV    4   x, y, z, w vertex attribute 4  
    MAP1_VERTEX_ATTRIB5_4_NV    4   x, y, z, w vertex attribute 5  
    MAP1_VERTEX_ATTRIB6_4_NV    4   x, y, z, w vertex attribute 6  
    MAP1_VERTEX_ATTRIB7_4_NV    4   x, y, z, w vertex attribute 7  
    MAP1_VERTEX_ATTRIB8_4_NV    4   x, y, z, w vertex attribute 8  
    MAP1_VERTEX_ATTRIB9_4_NV    4   x, y, z, w vertex attribute 9  
    MAP1_VERTEX_ATTRIB10_4_NV   4   x, y, z, w vertex attribute 10  
    MAP1_VERTEX_ATTRIB11_4_NV   4   x, y, z, w vertex attribute 11  
    MAP1_VERTEX_ATTRIB12_4_NV   4   x, y, z, w vertex attribute 12  
    MAP1_VERTEX_ATTRIB13_4_NV   4   x, y, z, w vertex attribute 13  
    MAP1_VERTEX_ATTRIB14_4_NV   4   x, y, z, w vertex attribute 14  
    MAP1_VERTEX_ATTRIB15_4_NV   4   x, y, z, w vertex attribute 15  
  
    Replace the four paragraphs on pages 167-168 that explain the  
    operation of EvalCoord:  
  
    "EvalCoord operates differently depending on whether vertex program  
    mode is enabled or not.  We first discuss how EvalCoord operates when  
    vertex program mode is disabled.  
  
    When one of the EvalCoord commands is issued and vertex program  
    mode is disabled, all currently enabled maps (excluding the  
    maps that correspond to vertex attributes, i.e. maps of the form  
    MAPx_VERTEX_ATTRIBn_4_NV).  ..."  
  
    Add a paragraph before the initial paragraph discussing AUTO_NORMAL:  
  
    "When one of the EvalCoord commands is issued and vertex program mode  
    is enabled, the evaluation and the issuing of per-vertex parameter commands  
    matches the discussion above, except that if any vertex attribute  
    maps are enabled, the corresponding VertexAttribNV call for each enabled  
    vertex attribute map is issued with the map's evaluated coordinates  
    and the corresponding aliased per-vertex parameter map is ignored  
    if it is also enabled, with one important difference.  As is the case when  
    vertex program mode is disabled, the GL uses evaluated values  
    instead of current values for those evaluations that are enabled  
    (otherwise the current values are used).  The order of the effective  
    commands is immaterial, except that Vertex or VertexAttribNV(0,  
    ...) (the commands that issue provoke vertex program execution)  
    must be issued last.  Use of evaluators has no effect on the current  
    vertex attributes or conventional per-vertex parameters.  If a  
    vertex attribute map is disabled, but its corresponding conventional  
    per-vertex parameter map is enabled, the conventional per-vertex  
    parameter map is evaluated and issued as when vertex program mode  
    is not enabled."  
  
    Replace the two paragraphs discussing AUTO_NORMAL with:  
  
    "Finally, if either MAP2_VERTEX_3 or MAP2_VERTEX_4 is enabled or if  
    both MAP2_VERTEX_ATTRIB0_4_NV and vertex program mode are enabled,  
    then the normal to the surface is computed.  Analytic computation,  
    which sometimes yields normals of length zero, is one method which  
    may be used.  If automatic normal generation is enabled, then this  
    computed normal is used as the normal associated with a generated  
    vertex (when program mode is disabled) or as vertex attribute 2  
    (when vertex program mode is enabled).  Automatic normal generation  
    is controlled with Enable and Disable with the symbolic constant  
    AUTO_NORMAL.  If automatic normal generation is disabled and vertex  
    program mode is enabled, then vertex attribute 2 is evaluated  
    as usual.  If automatic normal generation and vertex program mode  
    are disabled, then a corresponding normal map, if enabled, is used  
    to produce a normal.  If neither automatic normal generation nor  
    a map corresponding to the normal per-vertex parameter (or vertex  
    attribute 2 in program mode) are enabled, then no normal is sent with  
    a vertex resulting from an evaluation (the effect is that the current  
    normal is used).  For MAP_VERTEX3, let q=p.  For MAP_VERTEX_4 or  
    MAP2_VERTEX_ATTRBI0_4_NV, let q = (x/w, y/w, z/w) where (x,y,z,w)=p.  
    Then let  
  
       m = (partial q / partial u) cross (partial q / partial v)  
  
    Then when vertex program mode is disabled, the generated analytic  
    normal, n, is given by n=m/||m||.  However, when vertex program mode  
    is enabled, the generated analytic normal used for vertex attribute  
    2 is simply (mx,my,mz,1).  In vertex program mode, the normalization  
    of the generated analytic normal can be performed by the current  
    vertex program."  
  
    Change the respective sentences of the last paragraph discussing  
    required evaluator state to read:  
  
    "The state required for evaluators potentially consists of 9  
    conventional one-dimensional map specifications, 16 vertex attribute  
    one-dimensional map specifications, 9 conventional two-dimensional  
    map specifications, and 16 vertex attribute two-dimensional map  
    specifications indicating which are enabled.  ...  All vertex  
    coordinate maps produce the coordinates (0,0,0,1) (or the appropriate  
    subset); all normal coordinate maps produce (0,0,1); RGBA maps produce  
    (1,1,1,1); color index maps produce 1.0; texture coordinate maps  
    produce (0,0,0,1); and vertex attribute maps produce (0,0,0,1).  ...  
    If any evaluation command is issued when none of MAPn_VERTEX_3,  
    MAPn_VERTEX_4, or MAPn_VERTEX_ATTRIB0_NV (where n is the map dimension  
    being evaluated) are enabled, nothing happens."  
  
 --  Section 5.4 "Display Lists"  
  
    Add to the list of commands not compiled into display lists in the  
    third to the last paragraph:  
  
    "AreProgramsResidentNV, IsProgramNV, GenProgramsNV, DeleteProgramsNV,  
    VertexAttribPointerNV"  
  
homeprevnext Additions to Chapter 6 of the OpenGL 1.2.1 Specification (State and State Requests)
  
 --  Section 6.1.12 "Saving and Restoring State"  
  
    Only the enables and vertex array state introduced by this extension  
    can be pushed and popped.  
  
    See the attribute column in table X.5 for determining what vertex  
    program state can be pushed and popped with PushAttrib, PopAttrib,  
    PushClientAttrib, and PopClientAttrib.  
  
    The new evaluator enables in table 6.22 can also be pushed and  
    popped.  
  
 --  NEW Section 6.1.13 "Vertex Program Queries"  
  
    "The commands  
  
      void GetProgramParameterfvNV(enum target, uint index,  
                                   enum pname, float *params);  
      void GetProgramParameterdvNV(enum target, uint index,  
                                   enum pname, double *params);  
  
    obtain the current program parameters for the given program  
    target and parameter index into the array params.  target must  
    be VERTEX_PROGRAM_NV.  pname must be PROGRAM_PARAMETER_NV.  
    The INVALID_VALUE error is generated if index is greater than 95.  
    Each program parameter is an array of four values.  
  
    The command  
  
      void GetProgramivNV(uint id, enum pname, int *params);  
  
    obtains program state named by pname for the program named id  
    in the array params.  pname must be one of PROGRAM_TARGET_NV,  
    PROGRAM_LENGTH_NV, or PROGRAM_RESIDENT_NV.  The INVALID_OPERATION  
    error is generated if the program named id does not exist.  
  
    The command  
  
      void GetProgramStringNV(uint id, enum pname,  
                              ubyte *program);  
  
    obtains the program string for program id.  pname must be  
    PROGRAM_STRING_NV.  n ubytes are returned into the array program  
    where n is the length of the program in ubytes.  GetProgramivNV with  
    PROGRAM_LENGTH_NV can be used to query the length of a program's  
    string.  The INVALID_OPERATION error is generated if the program  
    named id does not exist.  
  
    The command  
  
      void GetTrackMatrixivNV(enum target, uint address,  
                              enum pname, int *params);  
  
    obtains the matrix tracking state named by pname for the specified  
    address in the array params.  target must be VERTEX_PROGRAM_NV. pname  
    must be either TRACK_MATRIX_NV or TRACK_MATRIX_TRANSFORM_NV.  If the  
    matrix tracked is a texture matrix, TEXTUREi_ARB is returned (never  
    TEXTURE) where i indicates the texture unit of the particular tracked  
    texture matrix.  The INVALID_VALUE error is generated if address is  
    not divisible by four and is not less than 96.  
  
    The commands  
  
      void GetVertexAttribdvNV(uint index, enum pname, double *params);  
      void GetVertexAttribfvNV(uint index, enum pname, float *params);  
      void GetVertexAttribivNV(uint index, enum pname, int *params);  
  
    obtain the vertex attribute state named by pname for the vertex  
    attribute numbered index.  pname must be one of ATTRIB_ARRAY_SIZE_NV,  
    ATTRIB_ARRAY_STRIDE_NV, ATTRIB_ARRAY_TYPE_NV, or CURRENT_ATTRIB_NV.  
    Note that all the queries except CURRENT_ATTRIB_NV return client  
    state.  The INVALID_VALUE error is generated if index is greater than  
    15, or if index is zero and pname is CURRENT_ATTRIB_NV.  
  
    The command  
  
      void GetVertexAttribPointervNV(uint index,  
                                     enum pname, void **pointer);  
      
    obtains the pointer named pname in the array params for vertex  
    attribute numbered index.  pname must be ATTRIB_ARRAY_POINTER_NV.  
    The INVALID_VALUE error is generated if index greater than 15.  
  
    The command  
  
      boolean IsProgramNV(uint id);  
  
    returns TRUE if program is the name of a program object.  If program  
    is zero or is a non-zero value that is not the name of a program  
    object, or if an error condition occurs, IsProgramNV returns FALSE.  
    A name returned by GenProgramsNV but not yet loaded with a program  
    is not the name of a program object."  
  
 --  NEW Section 6.1.14 "Querying Current Matrix State"  
  
    "Instead of providing distinct symbolic tokens for querying each  
    matrix and matrix stack depth, the symbolic tokens CURRENT_MATRIX_NV  
    and CURRENT_MATRIX_STACK_DEPTH_NV in conjunction with the GetBooleanv,  
    GetIntegerv, GetFloatv, and GetDoublev return the respective state  
    of the current matrix given the current matrix mode.  
  
    Querying CURRENT_MATRIX_NV  and CURRENT_MATRIX_STACK_DEPTH_NV is  
    the only means for querying the matrix and matrix stack depth of  
    the tracking matrices described in section 2.14.5."  
  
homeprevnext Additions to Appendix A of the OpenGL 1.2.1 Specification (Invariance)
  
    Add the following rule:  
  
    "Rule X  Vertex program and vertex state program instructions not  
    relevant to the calculation of any result must have no effect on  
    that result.  
  
    Rules X+1  Vertex program and vertex state program instructions  
    relevant to the calculation of any result must always produce the  
    identical result.  In particular, the same instruction with the same  
    source inputs must produce the identical result whether executed by  
    a vertex program or a vertex state program.  
  
    Instructions relevant to the calculation of a result are any  
    instructions in a sequence of instructions that eventually determine  
    the source values for the calculation under consideration.  
  
    There is no guaranteed invariance between vertices transformed by  
    conventional GL vertex transform mode and vertices transformed by  
    vertex program mode.  Multi-pass rendering algorithms that require  
    rendering invariances to operate correctly should not mix conventional  
    GL vertex transform mode with vertex program mode for different  
    rendering passes.  However such algorithms will operate correctly  
    if the algorithms limit themselves to a single mode of vertex  
    transformation."  
  
homeprevnext Additions to the AGL/GLX/WGL Specifications
  
    Program objects are shared between AGL/GLX/WGL rendering contexts if  
    and only if the rendering contexts share display lists.  No change  
    is made to the AGL/GLX/WGL API.  
  
homeprevnext Dependencies on EXT_vertex_weighting
  
    If the EXT_vertex_weighting extension is not supported, there is no  
    aliasing between vertex attribute 1 and the current vertex weight.  
    Replace the contents of the last three columns in row 5 of table  
    X.2 with dashes.  
  
homeprevnext Dependencies on EXT_point_parameters
  
    When EXT_point_parameters is supported, the amended discussion  
    of point size determination should be further amended with the  
    language from the EXT_point_parameters specification though the point  
    parameters functionality only applies when vertex program mode is  
    disabled.  
  
    Even if the EXT_point_parameters extension is not supported, the  
    PSIZ vertex result register must operate as specified.  
  
homeprevnext Dependencies on ARB_multitexture
  
    ARB_multitexture is required to support NV_vertex_program and the  
    value of MAX_TEXTURE_UNITS_ARB must be at least 2.  If more than 8  
    texture units are supported, only the first 8 texture units can be  
    assigned texture coordinates when vertex program mode is enabled.  
    Texture units beyond 8 are implicitly disabled when vertex program  
    mode is enabled.  
  
homeprevnext Dependencies on EXT_fog_coord
  
    If the EXT_fog_coord extension is not supported, there is no  
    aliasing between vertex attribute 5 and the current fog coordinate.  
    Replace the contents of the last three columns in row 5 of table  
    X.2 with dashes.  
  
    Even if the EXT_fog_coord extension is not supported, the FOGC  
    vertex result register must operate as specified.  Note that the  
    FOGC vertex result register behaves identically to the EXT_fog_coord  
    extension's FOG_COORDINATE_SOURCE_EXT being FOG_COORDINATE_EXT.  
    This means that the functionality of EXT_fog_coord is required to  
    implement NV_vertex_program even if the EXT_fog_coord extension is  
    not supported.  
  
    If the EXT_fog_coord extension is supported, the state of  
    FOG_COORDINATE_SOURCE_EXT only applies when vertex program mode is  
    disabled and the discussion in section 3.10 is further amended by  
    the discussion of FOG_COORDINATE_SOURCE_EXT in the EXT_fog_coord  
    specification.  
  
homeprevnext Dependencies on EXT_secondary_color
  
    If the EXT_secondary_color extension is not supported, there is no  
    aliasing between vertex attribute 4 and the current secondary color.  
    Replace the contents of the last three columns in row 4 of table  
    X.2 with dashes.  
  
    Even if the EXT_secondary_color extension is not supported, the COL1  
    and BFC1 vertex result registers must operate as specified.  
    These vertex result registers are required to implement OpenGL 1.2's  
    separate specular mode within a vertex program.  
  
homeprevnext GLX Protocol
  
    Forty-five new GL commands are added.  
  
    The following thirty-five rendering commands are sent to the sever  
    as part of a glXRender request:  
  
        BindProgramNV  
            2           12              rendering command length  
            2           4180            rendering command opcode  
            4           ENUM            target  
            4           CARD32          id  
  
        ExecuteProgramNV  
            2           12+4*n          rendering command length  
            2           4181            rendering command opcode  
            4           ENUM            target  
                        0x8621  n=4     GL_VERTEX_STATE_PROGRAM_NV  
                        else    n=0     command is erroneous  
            4           CARD32          id  
            4*n         LISTofFLOAT32   params  
  
        RequestResidentProgramsNV  
            2           8+4*n           rendering command length  
            2           4182            rendering command opcode  
            4           INT32           n  
            n*4         CARD32          programs  
  
        LoadProgramNV  
            2           16+n+p          rendering command length  
            2           4183            rendering command opcode  
            4           ENUM            target  
            4           CARD32          id  
            4           INT32           len  
            n           LISTofCARD8     n  
            p                           unused, p=pad(n)  
  
        ProgramParameter4fvNV  
            2           32              rendering command length  
            2           4184            rendering command opcode  
            4           ENUM            target  
            4           CARD32          index  
            4           FLOAT32         params[0]  
            4           FLOAT32         params[1]  
            4           FLOAT32         params[2]  
            4           FLOAT32         params[3]  
  
        ProgramParameter4dvNV  
            2           44              rendering command length  
            2           4185            rendering command opcode  
            4           ENUM            target  
            4           CARD32          index  
            8           FLOAT64         params[0]  
            8           FLOAT64         params[1]  
            8           FLOAT64         params[2]  
            8           FLOAT64         params[3]  
  
        ProgramParameters4fvNV  
            2           16+16*n         rendering command length  
            2           4186            rendering command opcode  
            4           ENUM            target  
            4           CARD32          index  
            4           CARD32          n  
            16*n        FLOAT32         params  
  
        ProgramParameters4dvNV  
            2           16+32*n         rendering command length  
            2           4187            rendering command opcode  
            4           ENUM            target  
            4           CARD32          index  
            4           CARD32          n  
            32*n        FLOAT64         params  
  
        TrackMatrixNV  
            2           20              rendering command length  
            2           4188            rendering command opcode  
            4           ENUM            target  
            4           CARD32          address  
            4           ENUM            matrix  
            4           ENUM            transform  
  
        VertexAttribPointerNV is an entirely client-side command  
  
        VertexAttrib1svNV  
            2           12              rendering command length  
            2           4189            rendering command opcode  
            4           CARD32          index  
            2           INT16           v[0]  
            2                           unused  
  
        VertexAttrib2svNV  
            2           12              rendering command length  
            2           4190            rendering command opcode  
            4           CARD32          index  
            2           INT16           v[0]  
            2           INT16           v[1]  
  
        VertexAttrib3svNV  
            2           12              rendering command length  
            2           4191            rendering command opcode  
            4           CARD32          index  
            2           INT16           v[0]  
            2           INT16           v[1]  
            2           INT16           v[2]  
            2                           unused  
  
        VertexAttrib4svNV  
            2           12              rendering command length  
            2           4192            rendering command opcode  
            4           CARD32          index  
            2           INT16           v[0]  
            2           INT16           v[1]  
            2           INT16           v[2]  
            2           INT16           v[3]  
  
        VertexAttrib1fvNV  
            2           12              rendering command length  
            2           4193            rendering command opcode  
            4           CARD32          index  
            4           FLOAT32         v[0]  
  
        VertexAttrib2fvNV  
            2           16              rendering command length  
            2           4194            rendering command opcode  
            4           CARD32          index  
            4           FLOAT32         v[0]  
            4           FLOAT32         v[1]  
  
        VertexAttrib3fvNV  
            2           20              rendering command length  
            2           4195            rendering command opcode  
            4           CARD32          index  
            4           FLOAT32         v[0]  
            4           FLOAT32         v[1]  
            4           FLOAT32         v[2]  
  
        VertexAttrib4fvNV  
            2           24              rendering command length  
            2           4196            rendering command opcode  
            4           CARD32          index  
            4           FLOAT32         v[0]  
            4           FLOAT32         v[1]  
            4           FLOAT32         v[2]  
            4           FLOAT32         v[3]  
  
        VertexAttrib1dvNV  
            2           16              rendering command length  
            2           4197            rendering command opcode  
            4           CARD32          index  
            8           FLOAT64         v[0]  
  
        VertexAttrib2dvNV  
            2           24              rendering command length  
            2           4198            rendering command opcode  
            4           CARD32          index  
            8           FLOAT64         v[0]  
            8           FLOAT64         v[1]  
  
        VertexAttrib3dvNV  
            2           32              rendering command length  
            2           4199            rendering command opcode  
            4           CARD32          index  
            8           FLOAT64         v[0]  
            8           FLOAT64         v[1]  
            8           FLOAT64         v[2]  
  
        VertexAttrib4dvNV  
            2           40              rendering command length  
            2           4200            rendering command opcode  
            4           CARD32          index  
            8           FLOAT64         v[0]  
            8           FLOAT64         v[1]  
            8           FLOAT64         v[2]  
            8           FLOAT64         v[3]  
  
        VertexAttrib4ubvNV  
            2           12              rendering command length  
            2           4201            rendering command opcode  
            4           CARD32          index  
            1           CARD8           v[0]  
            1           CARD8           v[1]  
            1           CARD8           v[2]  
            1           CARD8           v[3]  
  
        VertexAttribs1svNV  
            2           12+2*n+p        rendering command length  
            2           4202            rendering command opcode  
            4           CARD32          index  
            4           CARD32          n  
            2*n         INT16           v  
            p                           unused, p=pad(2*n)  
  
        VertexAttribs2svNV  
            2           12+4*n          rendering command length  
            2           4203            rendering command opcode  
            4           CARD32          index  
            4           CARD32          n  
            4*n         INT16           v  
  
        VertexAttribs3svNV  
            2           12+6*n+p        rendering command length  
            2           4204            rendering command opcode  
            4           CARD32          index  
            4           CARD32          n  
            6*n         INT16           v  
            p                           unused, p=pad(6*n)  
  
        VertexAttribs4svNV  
            2           12+8*n          rendering command length  
            2           4205            rendering command opcode  
            4           CARD32          index  
            4           CARD32          n  
            8*n         INT16           v  
  
        VertexAttribs1fvNV  
            2           12+4*n          rendering command length  
            2           4206            rendering command opcode  
            4           CARD32          index  
            4           CARD32          n  
            4*n         FLOAT32         v  
  
        VertexAttribs2fvNV  
            2           12+8*n          rendering command length  
            2           4207            rendering command opcode  
            4           CARD32          index  
            4           CARD32          n  
            8*n         FLOAT32         v  
  
        VertexAttribs3fvNV  
            2           12+12*n         rendering command length  
            2           4208            rendering command opcode  
            4           CARD32          index  
            4           CARD32          n  
            12*n        FLOAT32         v  
  
        VertexAttribs4fvNV  
            2           12+16*n         rendering command length  
            2           4209            rendering command opcode  
            4           CARD32          index  
            4           CARD32          n  
            16*n        FLOAT32         v  
  
        VertexAttribs1dvNV  
            2           12+8*n          rendering command length  
            2           4210            rendering command opcode  
            4           CARD32          index  
            4           CARD32          n  
            8*n         FLOAT64         v  
  
        VertexAttribs2dvNV  
            2           12+16*n         rendering command length  
            2           4211            rendering command opcode  
            4           CARD32          index  
            4           CARD32          n  
            16*n        FLOAT64         v  
  
        VertexAttribs3dvNV  
            2           12+24*n         rendering command length  
            2           4212            rendering command opcode  
            4           CARD32          index  
            4           CARD32          n  
            24*n        FLOAT64         v  
  
        VertexAttribs4dvNV  
            2           12+32*n         rendering command length  
            2           4213            rendering command opcode  
            4           CARD32          index  
            4           CARD32          n  
            32*n        FLOAT64         v  
  
        VertexAttribs4ubvNV  
            2           12+4*n          rendering command length  
            2           4214            rendering command opcode  
            4           CARD32          index  
            4           CARD32          n  
            4*n         CARD8           v  
  
    The remaining twelve commands are non-rendering commands.  These commands  
    are sent separately (i.e., not as part of a glXRender or glXRenderLarge  
    request), using the glXVendorPrivateWithReply request:  
  
        AreProgramsResidentNV  
            1           CARD8           opcode (X assigned)  
            1           17              GLX opcode (glXVendorPrivateWithReply)  
            2           4+n             request length  
            4           1293            vendor specific opcode  
            4           GLX_CONTEXT_TAG context tag  
            4           INT32           n  
            n*4         LISTofCARD32    programs  
          =>  
            1           1               reply  
            1                           unused  
            2           CARD16          sequence number  
            4           (n+p)/4         reply length  
            4           BOOL32          return value  
            20                          unused  
            n           LISTofBOOL      programs  
            p                           unused, p=pad(n)  
  
        DeleteProgramsNV  
            1           CARD8           opcode (X assigned)  
            1           17              GLX opcode (glXVendorPrivateWithReply)  
            2           4+n             request length  
            4           1294            vendor specific opcode  
            4           GLX_CONTEXT_TAG context tag  
            4           INT32           n  
            n*4         LISTofCARD32    programs  
  
        GenProgramsNV  
            1           CARD8           opcode (X assigned)  
            1           17              GLX opcode (glXVendorPrivateWithReply)  
            2           4               request length  
            4           1295            vendor specific opcode  
            4           GLX_CONTEXT_TAG context tag  
            4           INT32           n  
          =>  
            1           1               reply  
            1                           unused  
            2           CARD16          sequence number  
            4           n               reply length  
            24                          unused  
            n*4         LISTofCARD322   programs  
  
        GetProgramParameterfvNV  
            1           CARD8           opcode (X assigned)  
            1           17              GLX opcode (glXVendorPrivateWithReply)  
            2           6               request length  
            4           1296            vendor specific opcode  
            4           GLX_CONTEXT_TAG context tag  
            4           ENUM            target  
            4           CARD32          index  
            4           ENUM            pname  
          =>  
            1           1               reply  
            1                           unused  
            2           CARD16          sequence number  
            4           m               reply length, m=(n==1?0:n)  
            4                           unused  
            4           CARD32          n  
  
            if (n=1) this follows:  
  
            4           FLOAT32         params  
            12                          unused  
  
            otherwise this follows:  
  
            16                          unused  
            n*4         LISTofFLOAT32   params  
  
        GetProgramParameterdvNV  
            1           CARD8           opcode (X assigned)  
            1           17              GLX opcode (glXVendorPrivateWithReply)  
            2           6               request length  
            4           1297            vendor specific opcode  
            4           GLX_CONTEXT_TAG context tag  
            4           ENUM            target  
            4           CARD32          index  
            4           ENUM            pname  
          =>  
            1           1               reply  
            1                           unused  
            2           CARD16          sequence number  
            4           m               reply length, m=(n==1?0:n*2)  
            4                           unused  
            4           CARD32          n  
  
            if (n=1) this follows:  
  
            8           FLOAT64         params  
            8                           unused  
  
            otherwise this follows:  
  
            16                          unused  
            n*8         LISTofFLOAT64   params  
  
        GetProgramivNV  
            1           CARD8           opcode (X assigned)  
            1           17              GLX opcode (glXVendorPrivateWithReply)  
            2           5               request length  
            4           1298            vendor specific opcode  
            4           GLX_CONTEXT_TAG context tag  
            4           CARD32          id  
            4           ENUM            pname  
          =>  
            1           1               reply  
            1                           unused  
            2           CARD16          sequence number  
            4           m               reply length, m=(n==1?0:n)  
            4                           unused  
            4           CARD32          n  
  
            if (n=1) this follows:  
  
            4           INT32           params  
            12                          unused  
  
            otherwise this follows:  
  
            16                          unused  
            n*4         LISTofINT32     params  
  
        GetProgramStringNV  
            1           CARD8           opcode (X assigned)  
            1           17              GLX opcode (glXVendorPrivateWithReply)  
            2           5               request length  
            4           1299            vendor specific opcode  
            4           GLX_CONTEXT_TAG context tag  
            4           CARD32          id  
            4           ENUM            pname  
          =>  
            1           1               reply  
            1                           unused  
            2           CARD16          sequence number  
            4           (n+p)/4         reply length  
            4                           unused  
            4           CARD32          n  
            16                          unused  
            n           STRING          program  
            p                           unused, p=pad(n)  
  
        GetTrackMatrixivNV  
            1           CARD8           opcode (X assigned)  
            1           17              GLX opcode (glXVendorPrivateWithReply)  
            2           6               request length  
            4           1300            vendor specific opcode  
            4           GLX_CONTEXT_TAG context tag  
            4           ENUM            target  
            4           CARD32          address  
            4           ENUM            pname  
          =>  
            1           1               reply  
            1                           unused  
            2           CARD16          sequence number  
            4           m               reply length, m=(n==1?0:n)  
            4                           unused  
            4           CARD32          n  
  
            if (n=1) this follows:  
  
            4           INT32           params  
            12                          unused  
  
            otherwise this follows:  
  
            16                          unused  
            n*4         LISTofINT32     params  
  
        Note that ATTRIB_ARRAY_SIZE_NV, ATTRIB_ARRAY_STRIDE_NV, and  
        ATTRIB_ARRAY_TYPE_NV may be queried by GetVertexAttribNV but  
        return client-side state.  
  
        GetVertexAttribdvNV  
            1           CARD8           opcode (X assigned)  
            1           17              GLX opcode (glXVendorPrivateWithReply)  
            2           5               request length  
            4           1301            vendor specific opcode  
            4           GLX_CONTEXT_TAG context tag  
            4           INT32           index  
            4           ENUM            pname  
          =>  
            1           1               reply  
            1                           unused  
            2           CARD16          sequence number  
            4           m               reply length, m=(n==1?0:n*2)  
            4                           unused  
            4           CARD32          n  
  
            if (n=1) this follows:  
  
            8           FLOAT64         params  
            8                           unused  
  
            otherwise this follows:  
  
            16                          unused  
            n*8         LISTofFLOAT64   params  
  
        GetVertexAttribfvNV  
            1           CARD8           opcode (X assigned)  
            1           17              GLX opcode (glXVendorPrivateWithReply)  
            2           5               request length  
            4           1302            vendor specific opcode  
            4           GLX_CONTEXT_TAG context tag  
            4           INT32           index  
            4           ENUM            pname  
          =>  
            1           1               reply  
            1                           unused  
            2           CARD16          sequence number  
            4           m               reply length, m=(n==1?0:n)  
            4                           unused  
            4           CARD32          n  
  
            if (n=1) this follows:  
  
            4           FLOAT32         params  
            12                          unused  
  
            otherwise this follows:  
  
            16                          unused  
            n*4         LISTofFLOAT32   params  
  
        GetVertexAttribivNV  
            1           CARD8           opcode (X assigned)  
            1           17              GLX opcode (glXVendorPrivateWithReply)  
            2           5               request length  
            4           1303            vendor specific opcode  
            4           GLX_CONTEXT_TAG context tag  
            4           INT32           index  
            4           ENUM            pname  
          =>  
            1           1               reply  
            1                           unused  
            2           CARD16          sequence number  
            4           m               reply length, m=(n==1?0:n)  
            4                           unused  
            4           CARD32          n  
  
            if (n=1) this follows:  
  
            4           INT32           params  
            12                          unused  
  
            otherwise this follows:  
  
            16                          unused  
            n*4         LISTofINT32     params  
  
        GetVertexAttribPointervNV is an entirely client-side command  
  
        IsProgramNV  
            1           CARD8           opcode (X assigned)  
            1           17              GLX opcode (glXVendorPrivateWithReply)  
            2           4               request length  
            4           1304            vendor specific opcode  
            4           GLX_CONTEXT_TAG context tag  
            4           INT32           n  
          =>  
            1           1               reply  
            1                           unused  
            2           CARD16          sequence number  
            4           0               reply length  
            4           BOOL32          return value  
            20                          unused  
  
homeprevnext Errors
  
    The error INVALID_VALUE is generated if VertexAttribNV is called  
    where index is greater than 15.  
  
    The error INVALID_VALUE is generated if any ProgramParameterNV has  
    an index is greater than 95.  
  
    The error INVALID_VALUE is generated if VertexAttribPointerNV  
    is called where index is greater than 15.  
  
    The error INVALID_VALUE is generated if VertexAttribPointerNV  
    is called where size is not one of 1, 2, 3, or 4.  
  
    The error INVALID_VALUE is generated if VertexAttribPointerNV  
    is called where stride is negative.  
  
    The error INVALID_OPERATION is generated if VertexAttribPointerNV  
    is called where type is UNSIGNED_BYTE and size is not 4.  
  
    The error INVALID_VALUE is generated if LoadProgramNV is used to load a  
    program with an id of zero.  
  
    The error INVALID_OPERATION is generated if LoadProgramNV is used  
    to load an id that is currently loaded with a program of a different  
    program target.  
  
    The error INVALID_OPERATION is generated if the program passed to  
    LoadProgramNV fails to load because it is not syntactically correct  
    based on the specified target.  The value of PROGRAM_ERROR_POSITION_NV  
    is still updated when this error is generated.  
  
    The error INVALID_OPERATION is generated if LoadProgramNV has a  
    target of VERTEX_PROGRAM_NV and the specified program fails to  
    load because it does not write the HPOS register at least once.  
    The value of PROGRAM_ERROR_POSITION_NV is still updated when this  
    error is generated.  
  
    The error INVALID_OPERATION is generated if LoadProgramNV has a target  
    of VERTEX_STATE_PROGRAM_NV and the specified program fails to load  
    because it does not write at least one program parameter register.  
    The value of PROGRAM_ERROR_POSITION_NV is still updated when this  
    error is generated.  
  
    The error INVALID_OPERATION is generated if the vertex program  
    or vertex state program passed to LoadProgramNV fails to load  
    because it contains more than 128 instructions.  The value of  
    PROGRAM_ERROR_POSITION_NV is still updated when this error is  
    generated.  
  
    The error INVALID_OPERATION is generated if a program is loaded with  
    LoadProgramNV for id when id is currently loaded with a program of  
    a different target.  
  
    The error INVALID_OPERATION is generated if BindProgramNV attempts  
    to bind to a program name that is not a vertex program (for example,  
    if the program is a vertex state program).  
  
    The error INVALID_VALUE is generated if GenProgramsNV is called  
    where n is negative.  
  
    The error INVALID_VALUE is generated if AreProgramsResidentNV is  
    called and any of the queried programs are zero or do not exist.  
  
    The error INVALID_OPERATION is generated if ExecuteProgramNV executes  
    a program that does not exist.  
  
    The error INVALID_OPERATION is generated if ExecuteProgramNV executes  
    a program that is not a vertex state program.  
  
    The error INVALID_OPERATION is generated if Begin, RasterPos, or a  
    command that performs an explicit Begin is called when vertex program  
    mode is enabled and the currently bound vertex program writes program  
    parameters that are currently being tracked.    
  
    The error INVALID_OPERATION is generated if ExecuteProgramNV is called  
    and the vertex state program to execute writes program parameters  
    that are currently being tracked.    
  
    The error INVALID_VALUE is generated if TrackMatrixNV has a target  
    of VERTEX_PROGRAM_NV and attempts to track an address is not a  
    multiple of four.  
  
    The error INVALID_VALUE is generated if GetProgramParameterNV is  
    called to query an index greater than 95.  
  
    The error INVALID_VALUE is generated if GetVertexAttribNV is called  
    to query an <index> greater than 15, or if <index> is zero and <pname>  
    is CURRENT_ATTRIB_NV.  
  
    The error INVALID_VALUE is generated if GetVertexAttribPointervNV  
    is called to query an index greater than 15.  
  
    The error INVALID_OPERATION is generated if GetProgramivNV is called  
    and the program named id does not exist.  
  
    The error INVALID_OPERATION is generated if GetProgramStringNV is called  
    and the program named <program> does not exist.  
  
    The error INVALID_VALUE is generated if GetTrackMatrixivNV is called  
    with an <address> that is not divisible by four and not less than 96.  
  
    The error INVALID_VALUE is generated if AreProgramsResidentNV,  
    DeleteProgramsNV, GenProgramsNV, or RequestResidentProgramsNV are  
    called where <n> is negative.  
  
    The error INVALID_VALUE is generated if LoadProgramNV is called  
    where <len> is negative.  
  
    The error INVALID_VALUE is generated if ProgramParameters4dvNV or  
    ProgramParameters4fvNV are called where <count> is negative.  
  
    The error INVALID_VALUE is generated if  
    VertexAttribs{1,2,3,4}{d,f,s}vNV is called where <count> is negative.  
  
    The error INVALID_ENUM is generated if BindProgramNV,  
    GetProgramParameterfvNV, GetProgramParameterdvNV, GetTrackMatrixivNV,  
    ProgramParameter4fNV, ProgramParameter4dNV, ProgramParameter4fvNV,  
    ProgramParameter4dvNV, ProgramParameters4fvNV, ProgramParameters4dvNV,  
    or TrackMatrixNV are called where <target> is not VERTEX_PROGRAM_NV.  
  
    The error INVALID_ENUM is generated if LoadProgramNV or  
    ExecuteProgramNV are called where <target> is not either  
    VERTEX_PROGRAM_NV or VERTEX_STATE_PROGRAM_NV.  
  
homeprevnext New State
  
update table 6.22 (page 212) so that all the "9"s are "25"s because there  
are 9 conventional map targets and 16 vertex attribute map targets making  
a total of 25.  
  
Get Value                     Type    Get Command                  Initial Value  Description         Sec       Attribute  
----------------------------  ------  ---------------------------  -------------  ------------------  --------  ------------  
VERTEX_PROGRAM_NV             B       IsEnabled                    False          vertex program      2.10      enable  
                                                                                  enable  
VERTEX_PROGRAM_POINT_SIZE_NV  B       IsEnabled                    False          program-specified   2.14.1.5  enable  
                                                                                  point size mode  
VERTEX_PROGRAM_TWO_SIDE_NV    B       IsEnabled                    False          two-sided color     2.14.1.5  enable  
                                                                                  mode  
PROGRAM_ERROR_POSITION_NV     Z       GetIntegerv                  -1             last program        2.14.1.7  -  
                                                                                  error position  
PROGRAM_PARAMETER_NV          96xR4   GetProgramParameterNV        (0,0,0,0)      program parameters  2.14.1.2  -  
CURRENT_ATTRIB_NV             16xR4   GetVertexAttribNV            see 2.14.6     vertex attributes   2.14.1.1  current  
                                      but zero cannot be queried,  
                                      aliased with per-vertex  
                                      parameters  
TRACK_MATRIX_NV               24xZ8+  GetTrackMatrixivNV           NONE           track matrix        2.14.5    -  
TRACK_MATRIX_TRANSFORM_NV     24xZ8+  GetTrackMatrixivNV           IDENTITY_NV    track matrix        2.14.5    -  
                                                                                  transform  
VERTEX_PROGRAM_BINDING_NV     Z+      GetIntegerv                  0              bound vertex        2.14.1.8  -  
                                                                                  program  
VERTEX_ATTRIB_ARRAYn_NV       16xB    IsEnabled                    False          vertex attrib       2.14.3    vertex-array  
                                                                                  array enable  
ATTRIB_ARRAY_SIZE_NV          16xZ    GetVertexAttribNV            4              vertex attrib       2.14.3    vertex-array  
                                                                                  array size  
ATTRIB_ARRAY_STRIDE_NV        16xZ+   GetVertexAttribNV            0              vertex attrib       2.14.3    vertex-array  
                                                                                  array stride  
ATTRIB_ARRAY_TYPE_NV          16xZ4   GetVertexAttribNV            FLOAT          vertex attrib       2.14.3    vertex-array  
                                                                                  array type  
  
Table X.5.  New State Introduced by NV_vertex_program.  
  
  
Get Value            Type    Get Command          Initial Value  Description         Sec       Attribute  
-------------------  ------  ------------------   -------------  ------------------  --------  ---------  
PROGRAM_TARGET_NV    Z2      GetProgramivNV       0              program target      6.1.13    -  
PROGRAM_LENGTH_NV    Z+      GetProgramivNV       0              program length      6.1.13    -  
PROGRAM_RESIDENT_NV  Z2      GetProgramivNV       False          program residency   6.1.13    -  
PROGRAM_STRING_NV    ubxn    GetProgramStringNV   ""             program string      6.1.13    -  
  
Table X.6.  Program Object State.  
  
  
Get Value    Type    Get Command   Initial Value  Description              Sec       Attribute  
---------    ------  -----------   -------------  -----------------------  --------  ---------  
-            12xR4   -             (0,0,0,0)      temporary registers      2.14.1.4  -  
-            15xR4   -             (0,0,0,1)      vertex result registers  2.14.1.4  -  
             Z4      -             (0,0,0,0)      vertex program           2.14.1.3  -  
                                                  address register  
  
Table X.7.  Vertex Program Per-vertex Execution State.  
  
  
Get Value                         Type      Get Command      Initial Value  Description          Sec      Attribute  
-----------------------------     --------  --------------   -------------  -------------------  -------  ---------  
CURRENT_MATRIX_STACK_DEPTH_NV     m*Z+      GetIntegerv      1              current stack depth  6.1.14   -  
CURRENT_MATRIX_NV                 m*n*xM^4  GetFloatv        Identity       current matrix       6.1.14   -  
  
Table X.8.  Current matrix state where m is the total number of matrices  
including texture matrices and tracking matrices and n is the number of  
matrices on each particular matrix stack.  Note that this state is  
aliased with existing matrix state.  
  
  
homeprevnext New Implementation Dependent State
                                                        Minimum  
Get Value                         Type    Get Command   Value       Description         Sec     Attribute  
--------------------------------  ----    -----------   ----------  ------------------  ------  ---------  
MAX_TRACK_MATRIX_STACK_DEPTH_NV   Z+      GetIntegerv   1           maximum tracking    2.14.5  -  
                                                                    matrix stack depth  
MAX_TRACK_MATRICES_NV             Z+      GetIntegerv   8 (not to   maximum number of   2.14.5  -  
                                                        exceed 32)  tracking matrices  
  
Table X.9.  New Implementation-Dependent Values Introduced by NV_vertex_program.  
  
  
homeprevnext Revision History
  
    Version 1.1:  
  
      Added normalization example to Issues.  
  
      Fix explanation of EXP and ARL floor equivalence.  
  
      Clarify that vertex state programs fail if they load more than  
      one vertex attribute (though only one is possible).  
  
    Version 1.2  
  
      Add GLX protocol for VertexAttrib4ubvNV and VertexAttribs4ubvNV  
  
      Add issue about TrackMatrixNV transform behavior with example  
  
      Fix the C code specifying VertexAttribsvNV  
  
    Version 1.3  
  
      Dropped support for INT typed vertex attrib arrays.  
  
      Clarify that when ArrayElement is executed and vertex program  
      mode is enabled and the vertex attrib 0 array is enabled, the  
      vertex attrib 0 array command is executed last.  However when  
      ArrayElement is executed and vertex program mode is enabled and the  
      vertex attrib 0 array is disabled and the vertex array is enabled,  
      the vertex array command is executed last.  
  
    Version 1.4  
  
      Allow TEXTUREi_ARB for the track matrix.  This allows matrix  
      tracking of a particular texture matrix without reference to active  
      texture (set by glActiveTextureARB) state.  
  
      Early NVIDIA drivers (prior to October 5, 2001) have a bug  
      in their handling of tracking matrices specified with TEXTURE.  
      Rather than tracking the particular texture matrix indicated  
      by the active texture state when TrackMatrixNV is called, these  
      early drivers incorrectly track matrix the active texture's texture  
      matrix _at track matrix validation time_.  In practice this means,  
      every tracked matrix defined with TEXTURE tracks the same matrix  
      values; you cannot track distinct texture matrices at the same  
      time and the texture matrix you actually track depends on the  
      active texture matrix at validation time.  This is a driver bug.  
  
      Drivers after October 5, 2001 properly track the texture matrix  
      specified by active texture when TrackMatrix is called.  
  
      The new correct drivers can be distinguished from the old drivers  
      at run time with the following code:  
  
         while (glGetError() != GL_NO_ERROR);  // Clear any pre-existing OpenGL errors.  
         glTrackMatrixNV(GL_VERTEX_PROGRAM_NV, 8, GL_TEXTURE0_ARB, GL_IDENTITY_NV);  
         if (glGetError() != GL_NO_ERROR) {  
           // Old buggy pre-version 1.4 drivers with GL_TEXTURE  
           // glTrackMatrixNV bug.  
         } else {  
           // Correct new version 1.4 drivers (or later) with GL_TEXTURE  
           // glTrackMatrixNV bug fixed and GL_TEXTUREi_NV support.  
  
           // Note: you may want to untrack the matrix at this point.  
         }  
  
    Version 1.5  
  
      Earlier versions of this specification claimed for  
      GetVertexAttribARB that it is an error to query any vertex attrib  
      state for vertex attrib array zero.  In fact, it should only be  
      an error to query the CURRENT_ATTRIB_ARB state for vertex attrib  
      zero; the size, stride, and type of vertex attrib array zero may  
      be queried.  Version 1.5 specifies the correct behavior.  
  
      Early NVIDIA drivers (prior to January 11, 2002) did not implement  
      generate error when querying vertex attrib array zero state (ie,  
      did the right thing for size, stride, and type) but not create an  
      error when querying the current attribute values for vertex attrib  
      array zero either.  
  
    Version 1.6  
  
      GLX opcodes and vendorpriv values assigned.  
  
    Version 1.7  
  
      Corrected matrix tracking example in the issues list to properly  
      document row vs. column-major differences.  
  
    Version 1.8  
  
      Corrected EXP instruction; W component of result is always 1.0.  
  
    Version 1.9  
  
      Added language that for SGE and SLT, -NaN < -Inf and +NaN > +Inf.  
      Added language that for SGE and SLT, -NaN < -Inf and +NaN > +Inf.  
Valid XHTML 1.1! Valid CSS! Last update: November 14, 2006.
Cette page doit être lue avec un navigateur récent respectant le standard XHTML 1.1.