| Name | 
 |  | 
 |     NV_vertex_array_range | 
 |  | 
 | Name Strings | 
 |  | 
 |     GL_NV_vertex_array_range | 
 |  | 
 | Contact | 
 |  | 
 |     Mark J. Kilgard, NVIDIA Corporation (mjk 'at' nvidia.com) | 
 |  | 
 | Notice | 
 |  | 
 |     Copyright NVIDIA Corporation, 1999, 2000, 2001. | 
 |  | 
 | IP Status | 
 |  | 
 |     NVIDIA Proprietary. | 
 |  | 
 | Status | 
 |  | 
 |     Shipping (version 1.1) | 
 |  | 
 |     Existing functionality is augmented by NV_vertex_array_range2. | 
 |  | 
 | Version | 
 |  | 
 |     NVIDIA Date: September 17, 2001 (version 1.1) | 
 |  | 
 | Number | 
 |  | 
 |     190 | 
 |  | 
 | Dependencies | 
 |  | 
 |     None | 
 |  | 
 | Overview | 
 |  | 
 |     The goal of this extension is to permit extremely high vertex | 
 |     processing rates via OpenGL vertex arrays even when the CPU lacks | 
 |     the necessary data movement bandwidth to keep up with the rate | 
 |     at which the vertex engine can consume vertices.  CPUs can keep | 
 |     up if they can just pass vertex indices to the hardware and | 
 |     let the hardware "pull" the actual vertex data via Direct Memory | 
 |     Access (DMA).  Unfortunately, the current OpenGL 1.1 vertex array | 
 |     functionality has semantic constraints that make such an approach | 
 |     hard.  Hence, the vertex array range extension. | 
 |  | 
 |     This extension provides a mechanism for deferring the pulling of | 
 |     vertex array elements to facilitate DMAed pulling of vertices for | 
 |     fast, efficient vertex array transfers.  The OpenGL client need only | 
 |     pass vertex indices to the hardware which can DMA the actual index's | 
 |     vertex data directly out of the client address space. | 
 |  | 
 |     The OpenGL 1.1 vertex array functionality specifies a fairly strict | 
 |     coherency model for when OpenGL extracts vertex data from a vertex | 
 |     array and when the application can update the in memory | 
 |     vertex array data.  The OpenGL 1.1 specification says "Changes | 
 |     made to array data between the execution of Begin and the | 
 |     corresponding execution of End may affect calls to ArrayElement | 
 |     that are made within the same Begin/End period in non-sequential | 
 |     ways.  That is, a call to ArrayElement that precedes a change to | 
 |     array data may access the changed data, and a call that follows | 
 |     a change to array data may access the original data." | 
 |  | 
 |     This means that by the time End returns (and DrawArrays and | 
 |     DrawElements return since they have implicit Ends), the actual vertex | 
 |     array data must be transferred to OpenGL.  This strict coherency model | 
 |     prevents us from simply passing vertex element indices to the hardware | 
 |     and having the hardware "pull" the vertex data out (which is often | 
 |     long after the End for the primitive has returned to the application). | 
 |  | 
 |     Relaxing this coherency model and bounding the range from which | 
 |     vertex array data can be pulled is key to making OpenGL vertex | 
 |     array transfers faster and more efficient. | 
 |  | 
 |     The first task of the vertex array range extension is to relax | 
 |     the coherency model so that hardware can indeed "pull" vertex | 
 |     data from the OpenGL client's address space long after the application | 
 |     has completed sending the geometry primitives requiring the vertex | 
 |     data. | 
 |  | 
 |     The second problem with the OpenGL 1.1 vertex array functionality is | 
 |     the lack of any guidance from the API about what region of memory | 
 |     vertices can be pulled from.  There is no size limit for OpenGL 1.1 | 
 |     vertex arrays.  Any vertex index that points to valid data in all | 
 |     enabled arrays is fair game.  This makes it hard for a vertex DMA | 
 |     engine to pull vertices since they can be potentially pulled from | 
 |     anywhere in the OpenGL client address space. | 
 |  | 
 |     The vertex array range extension specifies a range of the OpenGL | 
 |     client's address space where vertices can be pulled.  Vertex indices | 
 |     that access any array elements outside the vertex array range | 
 |     are specified to be undefined.  This permits hardware to DMA from | 
 |     finite regions of OpenGL client address space, making DMA engine | 
 |     implementation tractable. | 
 |  | 
 |     The extension is specified such that an (error free) OpenGL client | 
 |     using the vertex array range functionality could no-op its vertex | 
 |     array range commands and operate equivalently to using (if slower | 
 |     than) the vertex array range functionality. | 
 |  | 
 |     Because different memory types (local graphics memory, AGP memory) | 
 |     have different DMA bandwidths and caching behavior, this extension | 
 |     includes a window system dependent memory allocator to allocate | 
 |     cleanly the most appropriate memory for constructing a vertex array | 
 |     range.  The memory allocator provided allows the application to | 
 |     tradeoff the desired CPU read frequency, CPU write frequency, and | 
 |     memory priority while still leaving it up to OpenGL implementation | 
 |     the exact memory type to be allocated. | 
 |  | 
 | Issues | 
 |  | 
 |     How does this extension interact with the compiled_vertex_array | 
 |     extension?   | 
 |  | 
 |        I think they should be independent and not interfere with | 
 |        each other.  In practice, if you use NV_vertex_array_range, | 
 |        you can surpass the performance of compiled_vertex_array | 
 |  | 
 |     Should some explanation be added about what happens when an OpenGL | 
 |     application updates its address space in regions overlapping with | 
 |     the currently configured vertex array range? | 
 |  | 
 |        RESOLUTION:  I think the right thing is to say that you get | 
 |        non-sequential results.  In practice, you'll be using an old | 
 |        context DMA pointing to the old pages. | 
 |  | 
 |        If the application change's its address space within the | 
 |        vertex array range, the application should call | 
 |        glVertexArrayRangeNV again.  That will re-make a new vertex | 
 |        array range context DMA for the application's current address | 
 |        space. | 
 |  | 
 |     If we are falling back to software transformation, do we still need to | 
 |     abide by leaving "undefined" vertices outside the vertex array range? | 
 |     For example, pointers that are not 32-bit aligned would likely cause | 
 |     a fall back. | 
 |  | 
 |        RESOLUTION:  No.  The fact that vertex is "undefined" means we | 
 |        can do anything we want (as long as we send a vertex and do not | 
 |        crash) so it is perfectly fine for the software puller to | 
 |        grab vertex information not available to the hardware puller. | 
 |  | 
 |     Should we give a programmer a sense of how big a vertex array | 
 |     range they can specify? | 
 |  | 
 |        RESOLUTION:  No.  Just document it if there are limitations. | 
 |        Probably very hardware and operating system dependent. | 
 |  | 
 |     Is it clear enough that language about ArrayElement | 
 |     also applies to DrawArrays and DrawElements? | 
 |  | 
 |        Maybe not, but OpenGL 1.1 spec is clear that DrawArrays and | 
 |        DrawElements are defined in terms of ArrayElement. | 
 |  | 
 |     Should glFlush be the same as glVertexArrayRangeFlush? | 
 |  | 
 |        RESOLUTION:  No.  A glFlush is cheaper than a glVertexArrayRangeFlush | 
 |        though a glVertexArrayRangeFlushNV should do a flush. | 
 |  | 
 |     If any the data for any enabled array for a given array element index | 
 |     falls outside of the vertex array range, what happens? | 
 |  | 
 |        RESOLUTION:  An undefined vertex is generated. | 
 |  | 
 |     What error is generated in this case? | 
 |  | 
 |        I don't know yet.  We should make sure the hardware really does | 
 |        let us know when vertices are undefined. | 
 |  | 
 |        Note that this is a little weird for OpenGL since most errors | 
 |        in OpenGL result in the command being ignored.  Not in this | 
 |        case though. | 
 |  | 
 |     Should this extension support an interface for allocating video | 
 |     and AGP memory? | 
 |  | 
 |        RESOLUTION:  YES.  It seems like we should be able to leave | 
 |        the task of memory allocation to DirectDraw, but DirectDraw's | 
 |        asynchronous unmapping behavior and having to hold locks to | 
 |        update DirectDraw surfaces makes that mechanism to cumbersome. | 
 |  | 
 |        Plus the API is a lot easier if we do it ourselves. | 
 |  | 
 |     How do we decide what type of memory to allocate for the application? | 
 |  | 
 |        RESOLUTION:  Usage hints.  The application rates the read | 
 |        frequency (how often will they read the memory), the write | 
 |        frequency (how often will they write the memory), and the | 
 |        priority (how important is this memory relative to other | 
 |        uses for the memory such as texturing) on a scale of 1.0 | 
 |        to 0.0.  Using these hints and the size of the memory requsted, | 
 |        the OpenGL implementation decides where to allocate the memory. | 
 |  | 
 |        We try to not directly expose particular types of memory | 
 |        (AGP, local memory, cached/uncached, etc) so future memory | 
 |        types can be supported by merely updating the OpenGL | 
 |        implementation. | 
 |  | 
 |     Should the memory allocator functionality be available be a part | 
 |     of the GL or window system dependent (GLX or WGL) APIs? | 
 |  | 
 |        RESOLUTION:  The window system dependent API. | 
 |  | 
 |        The memory allocator should be considered a window system/ | 
 |        operating system dependent operation.  This also permits | 
 |        memory to be allocated when no OpenGL rendering contexts | 
 |        exist yet. | 
 |  | 
 | New Procedures and Functions | 
 |  | 
 |     void VertexArrayRangeNV(sizei length, void *pointer) | 
 |     void FlushVertexArrayRangeNV(void) | 
 |  | 
 | New Tokens | 
 |  | 
 |     Accepted by the <cap> parameter of EnableClientState, | 
 |     DisableClientState, and IsEnabled: | 
 |  | 
 |         VERTEX_ARRAY_RANGE_NV              0x851D | 
 |  | 
 |     Accepted by the <pname> parameter of GetBooleanv, GetIntegerv, | 
 |     GetFloatv, and GetDoublev: | 
 |  | 
 |         VERTEX_ARRAY_RANGE_LENGTH_NV       0x851E | 
 |         VERTEX_ARRAY_RANGE_VALID_NV        0x851F | 
 |         MAX_VERTEX_ARRAY_RANGE_ELEMENT_NV  0x8520 | 
 |  | 
 |     Accepted by the <pname> parameter of GetPointerv: | 
 |  | 
 |         VERTEX_ARRAY_RANGE_POINTER_NV      0x8521 | 
 |  | 
 | Additions to Chapter 2 of the OpenGL 1.1 Specification (OpenGL Operation) | 
 |  | 
 |     After the discussion of vertex arrays (Section 2.8) add a | 
 |     description of the vertex array range: | 
 |  | 
 |     "The command  | 
 |  | 
 |        void VertexArrayRangeNV(sizei length, void *pointer) | 
 |  | 
 |     specifies the current vertex array range.  When the vertex array | 
 |     range is enabled and valid, vertex array vertex transfers from within | 
 |     the vertex array range are potentially faster.  The vertex array | 
 |     range is a contiguous region of (virtual) address space for placing | 
 |     vertex arrays.  The "pointer" parameter is a pointer to the base of | 
 |     the vertex array range.  The "length" pointer is the length of the | 
 |     vertex array range in basic machine units (typically unsigned bytes). | 
 |  | 
 |     The vertex array range address space region extends from "pointer" | 
 |     to "pointer + length - 1" inclusive.  When specified and enabled, | 
 |     vertex array vertex transfers from within the vertex array range | 
 |     are potentially faster. | 
 |  | 
 |     There is some system burden associated with establishing a vertex | 
 |     array range (typically, the memory range must be locked down). | 
 |     If either the vertex array range pointer or size is set to zero, | 
 |     the previously established vertex array range is released (typically, | 
 |     unlocking the memory). | 
 |  | 
 |     The vertex array range may not be established for operating system | 
 |     dependent reasons, and therefore, not valid.  Reasons that a vertex | 
 |     array range cannot be established include spanning different memory | 
 |     types, the memory could not be locked down, alignment restrictions | 
 |     are not met, etc. | 
 |  | 
 |     The vertex array range is enabled or disabled by calling | 
 |     EnableClientState or DisableClientState with the symbolic | 
 |     constant VERTEX_ARRAY_RANGE_NV. | 
 |  | 
 |     The vertex array range is either valid or invalid and this state can | 
 |     be determined by querying VERTEX_ARRAY_RANGE_VALID_NV.  The vertex | 
 |     array range is valid when the following conditions are met: | 
 |  | 
 |       o  VERTEX_ARRAY_RANGE_NV is enabled. | 
 |  | 
 |       o  VERTEX_ARRAY is enabled. | 
 |  | 
 |       o  VertexArrayRangeNV has been called with a non-null pointer and | 
 |          non-zero size. | 
 |  | 
 |       o  The vertex array range has been established. | 
 |  | 
 |       o  An implementation-dependent validity check based on the | 
 |          pointer alignment, size, and underlying memory type of the | 
 |          vertex array range region of memory. | 
 |  | 
 |       o  An implementation-dependent validity check based on | 
 |          the current vertex array state including the strides, sizes, | 
 |          types, and pointer alignments (but not pointer value) for | 
 |          currently enabled vertex arrays. | 
 |  | 
 |       o  Other implementation-dependent validaity checks based on | 
 |          other OpenGL rendering state. | 
 |  | 
 |     Otherwise, the vertex array range is not valid.  If the vertex array | 
 |     range is not valid, vertex array transfers will not be faster. | 
 |  | 
 |     When the vertex array range is valid, ArrayElement commands may | 
 |     generate undefined vertices if and only if any indexed elements of | 
 |     the enabled arrays are not within the vertex array range or if the | 
 |     index is negative or greater or equal to the implementation-dependent | 
 |     value of MAX_VERTEX_ARRAY_RANGE_ELEMENT_NV.  If an undefined vertex | 
 |     is generated, an INVALID_OPERATION error may or may not be generated. | 
 |  | 
 |     The vertex array cohenecy model specifies when vertex data must be | 
 |     be extracted from the vertex array memory.  When the vertex array | 
 |     range is not valid, (quoting the specification) `Changes made to | 
 |     array data between the execution of Begin and the corresponding | 
 |     execution of End may effect calls to ArrayElement that are made | 
 |     within the same Begin/End period in non-sequential ways.  That is, | 
 |     a call to ArrayElement that precedes a change to array data may | 
 |     access the changed data, and a call that follows a change to array | 
 |     data may access the original data.' | 
 |  | 
 |     When the vertex array range is valid, the vertex array coherency | 
 |     model is relaxed so that changes made to array data until the next | 
 |     "vertex array range flush" may affects calls to ArrayElement in | 
 |     non-sequential ways.  That is a call to ArrayElement that precedes | 
 |     a change to array data (without an intervening "vertex array range | 
 |     flush") may access the changed data, and a call that follows a change | 
 |     (without an intervening "vertex array range flush") to array data | 
 |     may access original data. | 
 |  | 
 |     A 'vertex array range flush' occurs when one of the following | 
 |     operations occur: | 
 |  | 
 |        o  Finish returns. | 
 |  | 
 |        o  FlushVertexArrayRangeNV returns. | 
 |  | 
 |        o  VertexArrayRangeNV returns. | 
 |  | 
 |        o  DisableClientState of VERTEX_ARRAY_RANGE_NV returns. | 
 |  | 
 |        o  EnableClientState of VERTEX_ARRAY_RANGE_NV returns. | 
 |  | 
 |        o  Another OpenGL context is made current. | 
 |  | 
 |     The client state required to implement the vertex array range | 
 |     consists of an enable bit, a memory pointer, an integer size, | 
 |     and a valid bit. | 
 |  | 
 |     If the memory mapping of pages within the vertex array range changes, | 
 |     using the vertex array range may or may not result in undefined data | 
 |     being fetched from the vertex arrays when the vertex array range is | 
 |     enabled and valid.  To ensure that the vertex array range reflects | 
 |     the address space's current state, the application is responsible | 
 |     for calling VertexArrayRange again after any memory mapping changes | 
 |     within the vertex array range."llo | 
 |  | 
 | Additions to Chapter 5 of the OpenGL 1.1 Specification (Special Functions) | 
 |  | 
 |     Add to the end of Section 5.4 "Display Lists" | 
 |  | 
 |     "VertexArrayRangeNV and FlushVertexArrayRangeNV are not complied | 
 |     into display lists but are executed immediately. | 
 |  | 
 |     If a display list is compiled while VERTEX_ARRAY_RANGE_NV is | 
 |     enabled, the commands ArrayElement, DrawArrays, DrawElements, | 
 |     and DrawRangeElements are accumulated into a display list as | 
 |     if VERTEX_ARRAY_RANGE_NV is disabled." | 
 |  | 
 | Additions to the WGL interface: | 
 |  | 
 |     "When establishing a vertex array range, certain types of memory | 
 |     may be more efficient than other types of memory.  The commands | 
 |       | 
 |        void *wglAllocateMemoryNV(sizei size, | 
 |                                  float readFrequency, | 
 |                                  float writeFrequency, | 
 |                                  float priority) | 
 |        void wglFreeMemoryNV(void *pointer) | 
 |      | 
 |     allocate and free memory that may be more suitable for establishing | 
 |     an efficient vertex array range than memory allocated by other means. | 
 |     The wglAllocateMemoryNV command allocates <size> bytes of contiguous | 
 |     memory.   | 
 |  | 
 |     The <readFrequency>, <writeFrequency>, and <priority> parameters are | 
 |     usage hints that the OpenGL implementation can use to determine the | 
 |     best type of memory to allocate.  These parameters range from 0.0 | 
 |     to 1.0.  A <readFrequency> of 1.0 indicates that the application | 
 |     intends to frequently read the allocated memory; a <readFrequency> | 
 |     of 0.0 indicates that the application will rarely or never read the | 
 |     memory.  A <writeFrequency> of 1.0 indicates that the application | 
 |     intends to frequently write the allocated memory; a <writeFrequency> | 
 |     of 0.0 indicates that the application will rarely write the memory. | 
 |     A <priority> parameter of 1.0 indicates that memory type should be | 
 |     the most efficient available memory, even at the expense of (for | 
 |     example) available texture memory; a <priority> of 0.0 indicates that | 
 |     the vertex array range does not require an efficient memory type | 
 |     (for example, so that more efficient memory is available for other | 
 |     purposes such as texture memory). | 
 |  | 
 |     The OpenGL implementation is free to use the <size>, <readFrequency>, | 
 |     <writeFrequency>, and <priority> parameters to determine what memory | 
 |     type should be allocated.  The memory types available and how the | 
 |     memory type is determined is implementation dependent (and the | 
 |     implementation is free to ignore any or all of the above parameters). | 
 |  | 
 |     Possible memory types that could be allocated are uncached memory, | 
 |     write-combined memory, graphics hardware memory, etc.  The intent | 
 |     of the wglAllocateMemoryNV command is to permit the allocation of | 
 |     memory for efficient vertex array range usage.  However, there is | 
 |     no requirement that memory allocated by wglAllocateMemoryNV must be | 
 |     used to allocate memory for vertex array ranges. | 
 |  | 
 |     If the memory cannot be allocated, a NULL pointer is returned (and | 
 |     no OpenGL error is generated).  An implementation that does not | 
 |     support this extension's memory allocation interface is free to | 
 |     never allocate memory (always return NULL). | 
 |  | 
 |     The wglFreeMemoryNV command frees memory allocated with | 
 |     wglAllocateMemoryNV.  The <pointer> should be a pointer returned by | 
 |     wglAllocateMemoryNV and not previously freed.  If a pointer is passed | 
 |     to wglFreeMemoryNV that was not allocated via wglAllocateMemoryNV | 
 |     or was previously freed (without being reallocated), the free is | 
 |     ignored with no error reported. | 
 |  | 
 |     The memory allocated by wglAllocateMemoryNV should be available to | 
 |     all other threads in the address space where the memory is allocated | 
 |     (the memory is not private to a single thread).  Any thread in the | 
 |     address space (not simply the thread that allocated the memory) | 
 |     may use wglFreeMemoryNV to free memory allocated by itself or any | 
 |     other thread. | 
 |  | 
 |     Because wglAllocateMemoryNV and wglFreeMemoryNV are not OpenGL | 
 |     rendering commands, these commands do not require a current context. | 
 |     They operate normally even if called within a Begin/End or while | 
 |     compiling a display list." | 
 |  | 
 | Additions to the GLX Specification | 
 |  | 
 |     Same language as the "Additions to the WGL Specification" section | 
 |     except all references to wglAllocateMemoryNV and wglFreeMemoryNV | 
 |     should be replaced with glXAllocateMemoryNV and glXFreeMemoryNV | 
 |     respectively. | 
 |  | 
 |     Additional language: | 
 |  | 
 |     "OpenGL implementations using GLX indirect rendering should fail | 
 |     to set up the vertex array range (failing to set the vertex array | 
 |     valid bit so the vertex array range functionality is not usable). | 
 |     Additionally, glXAllocateMemoryNV always fails to allocate memory | 
 |     (returns NULL) when used with an indirect rendering context." | 
 |  | 
 | GLX Protocol | 
 |  | 
 |     None | 
 |  | 
 | Errors | 
 |  | 
 |     INVALID_OPERATION is generated if VertexArrayRange or | 
 |     FlushVertexArrayRange is called between the execution of Begin | 
 |     and the corresponding execution of End. | 
 |  | 
 |     INVALID_OPERATION may be generated if an undefined vertex is | 
 |     generated. | 
 |  | 
 | New State | 
 |  | 
 |                                                             Initial | 
 |    Get Value                       Get Command     Type    Value    Attrib | 
 |    ---------                       -----------     ----    -------  ------------ | 
 |    VERTEX_ARRAY_RANGE_NV           IsEnabled       B       False    vertex-array | 
 |    VERTEX_ARRAY_RANGE_POINTER_NV   GetPointerv     Z+      0        vertex-array | 
 |    VERTEX_ARRAY_RANGE_LENGTH_NV    GetIntegerv     Z+      0        vertex-array | 
 |    VERTEX_ARRAY_RANGE_VALID_NV     GetBooleanv     B       False    vertex-array | 
 |  | 
 | New Implementation Dependent State | 
 |  | 
 |     Get Value                           Get Command     Type    Minimum Value | 
 |     ---------                           -----------     -----   ------------- | 
 |     MAX_VERTEX_ARRAY_RANGE_ELEMENT_NV   GetIntegerv     Z+      65535 | 
 |  | 
 | NV10 Implementation Details | 
 |  | 
 |     This section describes implementation-defined limits for NV10: | 
 |  | 
 |          The value of MAX_VERTEX_ARRAY_RANGE_ELEMENT_NV is 65535. | 
 |  | 
 |     This section describes bugs in the NV10 vertex array range.  These | 
 |     bugs will be fixed in a future hardware release: | 
 |  | 
 |          If VERTEX_ARRAY is enabled with a format of GL_SHORT and the | 
 |          vertex array range is valid, a vertex array vertex with an X, | 
 |          Y, Z, or W coordinate of -32768 is wrongly interpreted as zero. | 
 |          Example: the X,Y coordinate (-32768,-32768) is incorrectly read | 
 |          as (0,0) from the vertex array. | 
 |  | 
 |          If TEXTURE_COORD_ARRAY is enabled with a format of GL_SHORT | 
 |          and the vertex array range is valid, a vertex array texture | 
 |          coord with an S, T, R, or Q coordinate of -32768 is wrongly | 
 |          interpreted as zero.  Example: the S,T coordinate (-32768,-32768) | 
 |          is incorrectly read as (0,0) from the texture coord array. | 
 |  | 
 |     This section describes the implementation-dependent validity | 
 |     checks for NV10. | 
 |       | 
 |       o  For the NV10 implementation-dependent validity check for the | 
 |          vertex array range region of memory to be true, all of the | 
 |          following must be true: | 
 |  | 
 |          1.  The <pointer> must be 32-byte aligned. | 
 |  | 
 |          2.  The underlying memory types must all be the same (all | 
 |              standard system memory -OR- all AGP memory -OR- all video | 
 |              memory). | 
 |  | 
 |      o  For the NV10 implementation-dependent validity check for the | 
 |         vertex array state to be true, all of the following must be | 
 |         true: | 
 |  | 
 |         1.  ( VERTEX_ARRAY must be enabled -AND- | 
 |               The vertex array stride must be less than 256 -AND- | 
 |               ( ( The vertex array type must be FLOAT -AND- | 
 |                   The vertex array stride must be a multiple of 4 bytes -AND- | 
 |                   The vertex array pointer must be 4-byte aligned -AND- | 
 |                   The vertex array size must be 2, 3, or 4 ) -OR- | 
 |                 ( The vertex array type must be SHORT -AND- | 
 |                   The vertex array stride must be a multiple of 4 bytes -AND- | 
 |                   The vertex array pointer must be 4-byte aligned. -AND- | 
 |                   The vertex array size must be 2 ) -OR- | 
 |                 ( The vertex array type must be SHORT -AND- | 
 |                   The vertex array stride must be a multiple of 8 bytes -AND- | 
 |                   The vertex array pointer must be 8-byte aligned. -AND- | 
 |                   The vertex array size must be 3 or 4 ) ) ) | 
 |  | 
 |         2.  ( NORMAL_ARRAY must be disabled. ) -OR - | 
 |             ( NORMAL_ARRAY must be enabled -AND- | 
 |               The normal array size must be 3 -AND- | 
 |               The normal array stride must be less than 256 -AND- | 
 |               ( ( The normal array type must be FLOAT -AND- | 
 |                   The normal array stride must be a multiple of 4 bytes -AND- | 
 |                   The normal array pointer must be 4-byte aligned. ) -OR- | 
 |                 ( The normal array type must be SHORT -AND- | 
 |                   The normal array stride must be a multiple of 8 bytes -AND- | 
 |                   The normal array pointer must be 8-byte aligned. ) ) ) | 
 |                     | 
 |         3.  ( COLOR_ARRAY must be disabled. ) -OR - | 
 |             ( COLOR_ARRAY must be enabled -AND- | 
 |               The color array type must be FLOAT or UNSIGNED_BYTE -AND- | 
 |               The color array stride must be a multiple of 4 bytes -AND- | 
 |               The color array stride must be less than 256 -AND- | 
 |               The color array pointer must be 4-byte aligned -AND- | 
 |               The color array size must be 3 or 4 ) | 
 |  | 
 |         4.  ( SECONDARY_COLOR_ARRAY must be disabled. ) -OR - | 
 |             ( SECONDARY_COLOR_ARRAY must be enabled -AND- | 
 |               The secondary color array type must be FLOAT or UNSIGNED_BYTE -AND- | 
 |               The secondary color array stride must be a multiple of 4 bytes -AND- | 
 |               The secondary color array stride must be less than 256 -AND- | 
 |               The secondary color array pointer must be 4-byte aligned -AND- | 
 |               The secondary color array size must be 3 or 4 ) | 
 |  | 
 |         5.  For texture units zero and one: | 
 |  | 
 |             ( TEXTURE_COORD_ARRAY must be disabled. ) -OR - | 
 |             ( TEXTURE_COORD_ARRAY must be enabled -AND- | 
 |               The texture coord array stride must be less than 256 -AND- | 
 |               ( ( The texture coord array type must be FLOAT -AND- | 
 |                   The texture coord array pointer must be 4-byte aligned. )  | 
 |                   The texture coord array stride must be a multiple of 4 bytes -AND- | 
 |                   The texture coord array size must be 1, 2, 3, or 4 ) -OR- | 
 |                 ( The texture coord array type must be SHORT -AND- | 
 |                   The texture coord array pointer must be 4-byte aligned. )  | 
 |                   The texture coord array stride must be a multiple of 4 bytes -AND- | 
 |                   The texture coord array size must be 1 ) -OR- | 
 |                 ( The texture coord array type must be SHORT -AND- | 
 |                   The texture coord array pointer must be 4-byte aligned. )  | 
 |                   The texture coord array stride must be a multiple of 4 bytes -AND- | 
 |                   The texture coord array size must be 2 ) -OR- | 
 |                 ( The texture coord array type must be SHORT -AND- | 
 |                   The texture coord array pointer must be 8-byte aligned. )  | 
 |                   The texture coord array stride must be a multiple of 8 bytes -AND- | 
 |                   The texture coord array size must be 3 ) -OR- | 
 |                 ( The texture coord array type must be SHORT -AND- | 
 |                   The texture coord array pointer must be 8-byte aligned. )  | 
 |                   The texture coord array stride must be a multiple of 8 bytes -AND- | 
 |                   The texture coord array size must be 4 ) ) ) | 
 |              | 
 |         6.  ( EDGE_FLAG_ARRAY must be disabled. ) | 
 |  | 
 |         7.  ( VERTEX_WEIGHT_ARRAY_NV must be disabled. ) -OR - | 
 |             ( VERTEX_WEIGHT_ARRAY_NV must be enabled. -AND - | 
 |               The vertex weight array type must be FLOAT -AND- | 
 |               The vertex weight array size must be 1 -AND- | 
 |               The vertex weight array stride must be a multiple of 4 bytes -AND- | 
 |               The vertex weight array stride must be less than 256 -AND- | 
 |               The vertex weight array pointer must be 4-byte aligned ) | 
 |  | 
 |         8.  ( FOG_COORDINATE_ARRAY must be disabled. ) -OR - | 
 |             ( FOG_COORDINATE_ARRAY must be enabled -AND- | 
 |               The chip in use must be an NV11 or NV15, not NV10 -AND- | 
 |               The fog coordinate array type must be FLOAT -AND- | 
 |               The fog coordinate array size must be 1 -AND- | 
 |               The fog coordinate array stride must be a multiple of 4 bytes -AND- | 
 |               The fog coordinate array stride must be less than 256 -AND- | 
 |               The fog coordinate array pointer must be 4-byte aligned ) | 
 |  | 
 |      o  For the NV10 the implementation-dependent validity check based on | 
 |         other OpenGL rendering state is FALSE if any of the following are true: | 
 |  | 
 |         1.  ( COLOR_LOGIC_OP is enabled -AND- | 
 |               The logic op is not COPY ), except in the case of Quadro2 | 
 |             (Quadro2 Pro, Quadro2 MXR) products. | 
 |  | 
 |         2.  ( LIGHT_MODEL_TWO_SIDE is true. ) | 
 |  | 
 |         3.  Either texture unit is enabled and active with a texture | 
 |             with a non-zero border. | 
 |  | 
 |         4.  VERTEX_PROGRAM_NV is enabled. | 
 |  | 
 |         5.  Several other obscure unspecified reasons. | 
 |  | 
 | NV20 Implementation Details | 
 |  | 
 |     This section describes implementation-defined limits for NV20: | 
 |  | 
 |          The value of MAX_VERTEX_ARRAY_RANGE_ELEMENT_NV is 1048575. | 
 |  | 
 |     This section describes the implementation-dependent validity | 
 |     checks for NV20. | 
 |  | 
 |       o  For the NV20 implementation-dependent validity check for the | 
 |          vertex array range region of memory to be true, all of the | 
 |          following must be true: | 
 |  | 
 |          1.  The <pointer> must be 32-byte aligned. | 
 |  | 
 |          2.  The underlying memory types must all be the same (all | 
 |              standard system memory -OR- all AGP memory -OR- all video | 
 |              memory). | 
 |  | 
 |      o  To determine whether the NV20 implementation-dependent validity | 
 |         check for the vertex array state is true, the following algorithm | 
 |         is used: | 
 |  | 
 |         The currently enabled arrays and their pointers, strides, and | 
 |         types are first determined using the value of VERTEX_PROGRAM_NV. | 
 |         If VERTEX_PROGRAM_NV is disabled, the standard GL vertex arrays | 
 |         are used.  If VERTEX_PROGRAM_NV is enabled, the vertex attribute | 
 |         arrays take precedence over the standard vertex arrays.  The | 
 |         following table, taken from the NV_vertex_program specification, | 
 |         shows the aliasing between the standard and attribute arrays: | 
 |  | 
 | 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 | 
 |  | 
 |         For the validity check to be TRUE, the following must all be | 
 |         true: | 
 |  | 
 |         1.  Vertex attribute 0's array must be enabled. | 
 |         2.  EDGE_FLAG_ARRAY must be disabled. | 
 |         3.  For all enabled arrays, all of the following must be true: | 
 |             - the stride must be less than 256 | 
 |             - the type must be FLOAT, SHORT, or UNSIGNED_BYTE | 
 |  | 
 |      o  For the NV20 the implementation-dependent validity check based on | 
 |         other OpenGL rendering state is FALSE only for a few obscure and | 
 |         unspecified reasons. | 
 |  | 
 | Revision History | 
 |  | 
 |     January 10, 2001 - Added NV20 implementation details.  Made several | 
 |     corrections to the NV10 implementation details.  Specifically, noted | 
 |     that on the NV11 and NV15 architectures, the fog coordinate array may | 
 |     be used, and updated the section on other state that may cause the | 
 |     vertex array range to be invalid.  Only drivers built after this date | 
 |     will support fog coordinate arrays on NV11 and NV15.  Also fixed a | 
 |     few typos in the spec. | 
 |  | 
 |     September 17, 2001 - Modified NV20 implementation details to remove | 
 |     all the pointer and stride restrictions, none of which are actually | 
 |     required.  Only drivers built after this date will support arbitrary | 
 |     pointer offsets and strides.  Also removed NV10 rules on non-zero | 
 |     strides, which cannot be used in OpenGL anyhow, and fixed a few other | 
 |     typos. |