Name

    NV_viewport_array

Name Strings

    GL_NV_viewport_array

Contributors

    Contributors to ARB_viewport_array
    Mathias Heyer, NVIDIA
    James Helferty, NVIDIA
    Daniel Koch, NVIDIA

Contact

    Mathias Heyer, NVIDIA (mheyer 'at' nvidia.com)

Notice

    Copyright (c) 2010-2014 The Khronos Group Inc. Copyright terms at
        http://www.khronos.org/registry/speccopyright.html

    Portions Copyright (c) 2014 NVIDIA Corporation.

Status

    Complete

Version

    Last Modified Date:         10/24/2014
    Author Revision:            5

Number

    OpenGL ES Extension #202

Dependencies

    This extension is written against the OpenGL ES 3.1 (March 14, 2014)
    Specification.

    This extension is written against the OpenGL ES Shading Language
    Specification version 3.10 (March 14, 2014)

    OpenGL ES 3.1 and the EXT_geometry_shader extension are required.

    This extension interacts with EXT_draw_buffers_indexed.

Overview

    OpenGL ES is modeled on a pipeline of operations. The final stage in this
    pipeline before rasterization is the viewport transformation. This stage
    transforms vertices from view space into window coordinates and allows the
    application to specify a rectangular region of screen space into which
    OpenGL should draw primitives. Unextended OpenGL implementations provide a
    single viewport per context. In order to draw primitives into multiple
    viewports, the OpenGL viewport may be changed between several draw calls.
    With the advent of Geometry Shaders, it has become possible for an
    application to amplify geometry and produce multiple output primitives for
    each primitive input to the Geometry Shader. It is possible to direct these
    primitives to render into a selected render target. However, all render
    targets share the same, global OpenGL viewport.

    This extension enhances OpenGL by providing a mechanism to expose multiple
    viewports. Each viewport is specified as a rectangle. The destination
    viewport may be selected per-primitive by the geometry shader. This allows
    the Geometry Shader to produce different versions of primitives destined
    for separate viewport rectangles on the same surface. Additionally, when
    combined with multiple framebuffer attachments, it allows a different
    viewport rectangle to be selected for each. This extension also exposes a
    separate scissor rectangle for each viewport. Finally, the viewport bounds
    are now floating point quantities allowing fractional pixel offsets to be
    applied during the viewport transform.

New Procedures and Functions

    void ViewportArrayvNV(uint first, sizei count, const float * v);
    void ViewportIndexedfNV(uint index, float x, float y, float w, float h);
    void ViewportIndexedfvNV(uint index, const float * v);
    void ScissorArrayvNV(uint first, sizei count, const int * v);
    void ScissorIndexedNV(uint index, int left, int bottom, sizei width, sizei height);
    void ScissorIndexedvNV(uint index, const int * v);
    void DepthRangeArrayfvNV(uint first, sizei count, const float * v);
    void DepthRangeIndexedfNV(uint index, float n, float f);
    void GetFloati_vNV(enum target, uint index, float *data);

    void EnableiNV(enum target, uint index);
    void DisableiNV(enum target, uint index);
    boolean IsEnablediNV(enum target, uint index);

New Tokens

    Accepted by the <pname> parameter of GetBooleanv, GetIntegerv, GetFloatv,
    and GetInteger64v:

        MAX_VIEWPORTS_NV                                0x825B
        VIEWPORT_SUBPIXEL_BITS_NV                       0x825C
        VIEWPORT_BOUNDS_RANGE_NV                        0x825D
        VIEWPORT_INDEX_PROVOKING_VERTEX_NV              0x825F

    Accepted by the <pname> parameter of GetIntegeri_v:

        SCISSOR_BOX                                     0x0C10

    Accepted by the <pname> parameter of GetFloati_vNV:

        VIEWPORT                                        0x0BA2
        DEPTH_RANGE                                     0x0B70

    Accepted by the <pname> parameter of EnableiNV, DisableiNV,
    and IsEnablediNV:

        SCISSOR_TEST                                    0x0C11

Additions to Chapter 11 of the OpenGL ES 3.1 Specification
(Programmable Vertex Processing)

    Modify section Section 11.1gs.4.5 Layer Selection

    Rename the the "Layer Selection" subsection to "Layer and Viewport
    Selection".

    After the first paragraph, insert:

    Geometry shaders may also select the destination viewport for each
    output primitive. The destination viewport for a primitive may be
    selected in the geometry shader by writing to the built-in output
    variable gl_ViewportIndex. This functionality allows a geometry
    shader to direct its output to a different viewport for each
    primitive, or to draw multiple versions of a primitive into several
    different viewports.

    Replace the first two sentences of the second paragraph with:

    The specific vertex of a primitive that is used to select the
    rendering layer or viewport index is implementation-dependent and
    thus portable applications will assign the same layer and viewport
    index for all vertices in a primitive. The vertex conventions
    followed for gl_Layer and gl_ViewportIndex may be determined by
    calling GetIntegerv with the symbolic constants
    LAYER_PROVOKING_VERTEX_EXT and VIEWPORT_INDEX_PROVOKING_VERTEX_NV,
    respectively.

    Modify section 12.5.1 "Controlling the Viewport", page 284.

    Change the first paragraph of section 12.5.1 to read

    The viewport transformation is determined by the selected viewport's
    width and height in pixels, p_x and p_y, respectively, and its
    center (o_x,o_y) (also in pixels) ...

        { leave equations intact }

    Multiple viewports are available and are numbered zero through the
    value of MAX_VIEWPORTS_NV minus one. If a geometry shader is active
    and writes to gl_ViewportIndex, the viewport transformation uses the
    viewport corresponding to the value assigned to gl_ViewportIndex
    taken from an implementation-dependent primitive vertex. If the
    value of the viewport index is outside the range zero to the value
    of MAX_VIEWPORTS_NV minus one, the results of the viewport
    transformation are undefined. If no geometry shader is active, or if
    the active geometry shader does not write to gl_ViewportIndex, the
    viewport numbered zero is used by the viewport transformation.

    A single vertex may be used in more than one individual primitive, in
    primitives such as TRIANGLE_STRIP.  In this case, the viewport
    transformation is applied separately for each primitive.

    The factor and offset applied to Z_d for each viewport encoded by n
    and f are set using

        void DepthRangeArrayfvNV(uint first, sizei count, const float * v);
        void DepthRangeIndexedfNV(uint index, float n, float f);
        void DepthRangef(float n, float f);

    DepthRangeArrayfvNV is used to specify the depth range for multiple
    viewports simultaneously. <first> specifies the index of the first
    viewport to modify and <count> specifies the number of viewports. If
    (<first> + <count>) is greater than the value of MAX_VIEWPORTS_NV then
    an INVALID_VALUE error will be generated. Viewports whose indices
    lie outside the range [<first>, <first> + <count>) are not modified.
    The <v> parameter contains the address of an array of float types
    specifying near (n) and far (f) for each viewport in that order.
    (n) and (f) of each viewport will be clamped to [0.0, 1.0].

    DepthRangeIndexedfNV specifies the depth range for a single viewport
    and is equivalent (assuming no errors are generated) to:

        float v[] = { n, f };
        DepthRangeArrayfvNV(index, 1, v);

    DepthRangef sets the depth range for all viewports to the same values
    and is equivalent (assuming no errors are generated) to:

        for (uint i = 0; i < MAX_VIEWPORTS_NV; i++)
            DepthRangeIndexedfNV(i, n, f);

    Z_w is represented as either ...

    Replace the end of section 12.5.1, starting from "Viewport transformation
    parameters are specified using..."

    Viewport transformation parameters are specified using

        void ViewportArrayvNV(uint first, sizei count, const float * v);
        void Viewport(int x, int y, sizei w, sizei h);
        void ViewportIndexedfNV(uint index, float x, float y, float w, float h);
        void ViewportIndexedfvNV(uint index, const float * v);

    ViewportArrayvNV specifies parameters for multiple viewports
    simultaneously. <first> specifies the index of the first viewport to
    modify and <count> specifies the number of viewports. If (<first> +
    <count>) is greater than the value of MAX_VIEWPORTS_NV then an
    INVALID_VALUE error will be generated. Viewports whose indices lie
    outside the range [<first>, <first> + <count>) are not modified.
    <v> contains the address of an array of floating point values
    specifying the left (x), bottom (y), width (w) and height (h) of
    each viewport, in that order. <x> and <y> give the location of the
    viewport's lower left corner and <w> and <h> give the viewport's
    width and height, respectively.

    ViewportIndexedfNV and ViewportIndexedfvNV specify parameters for a
    single viewport and are equivalent (assuming no errors are
    generated) to:

        float v[4] = { x, y, w, h };
        ViewportArrayvNV(index, 1, v);

    and

        ViewportArrayvNV(index, 1, v);

    respectively.

    Viewport sets the parameters for all viewports to the same values
    and is equivalent (assuming no errors are generated) to:

        for (uint i = 0; i < MAX_VIEWPORTS_NV; i++)
            ViewportIndexedfNV(i, (float)x, (float)y, (float)w, (float)h);

    The viewport parameters shown in the above equations are found from these
    values as

        o_x = x + w /2,
        o_y = y + h / 2,
        p_x = w,
        p_y = h.

    The location of the viewport's bottom-left corner, given by (x,y), are
    clamped to be within the implementation-dependent viewport bounds range.
    The viewport bounds range [min, max] tuple may be determined by
    calling GetFloatv with the symbolic constant VIEWPORT_BOUNDS_RANGE_NV
    (see chapter 20).

    Viewport width and height are clamped to implementation-dependent maximums
    when specified. The maximum width and height may be found by calling
    GetFloatv with the symbolic constant MAX_VIEWPORT_DIMS. The maximum
    viewport dimensions must be greater than or equal to the larger of
    the visible dimensions of the display being rendered to (if a
    display exists), and the largest renderbuffer image which can be
    successfully created and attached to a framebuffer object (see
    chapter 9). INVALID_VALUE is generated if either w or h is negative.

    The state required to implement the viewport transformations is four
    floating-point values and two clamped floating-point values for each
    viewport. In the initial state, w and h for each viewport are set to
    the width and height, respectively, of the window into which the GL
    is to do its rendering. If the default framebuffer is bound but no
    default framebuffer is associated with the GL context (see chapter
    9), then w and h are initially set to zero. o_x and o_y are set to
    w/2 and h/2, respectively. n and f are set to 0.0 and 1.0,
    respectively.

    The precision with which the GL interprets the floating point viewport
    bounds is implementation-dependent and may be determined by querying the
    implementation-defined constant VIEWPORT_SUBPIXEL_BITS_NV.

Additions to Chapter 15 of the OpenGL ES 3.1 Specification (Writing
Fragments and Samples to the Framebuffer)

    Replace section 15.1.2 "Scissor Test", page 309.

    The scissor test determines if (xw, yw) lies within the scissor rectangle
    defined by four values for each viewport. These values are set with

        void ScissorArrayvNV(uint first, sizei count, const int * v);
        void ScissorIndexedNV(uint index, int left, int bottom, sizei width, sizei height);
        void ScissorIndexedvNV(uint index, int * v);
        void Scissor(int left, int bottom, sizei width, sizei height);

    ScissorArrayvNV defines a set of scissor rectangles that are each
    applied to the corresponding viewport (see section 12.5.1
    "Controlling the Viewport"). <first> specifies the index of the
    first scissor rectangle to modify, and <count> specifies the number
    of scissor rectangles. If (<first> + <count>) is greater than the
    value of MAX_VIEWPORTS_NV, then an INVALID_VALUE error is generated.
    <v> contains the address of an array of integers containing the
    left, bottom, width and height of the scissor rectangles, in that
    order.

    If left <= x_w < left + width and bottom <= y_w < bottom + height
    for the selected scissor rectangle, then the scissor test passes.
    Otherwise, the test fails and the fragment is discarded. For points,
    lines, and polygons, the scissor rectangle for a primitive is
    selected in the same manner as the viewport (see section 12.5.1).

    The scissor test is enabled or disabled for all viewports using
    Enable or Disable with the symbolic constant SCISSOR_TEST. The test
    is enabled or disabled for a specific viewport using EnableiNV or
    DisableiNV with the constant SCISSOR_TEST and the index of the
    selected viewport. When disabled, it is as if the scissor test
    always passes. The value of the scissor test enable for viewport <i>
    can be queried by calling IsEnablediNV with <target> SCISSOR_TEST and
    <index> <i>. The value of the scissor test enable for viewport zero
    may also be queried by calling IsEnabled with the same symbolic
    constant, but no <index> parameter. If either width or height is
    less than zero for any scissor rectangle, then an INVALID_VALUE
    error is generated. If the viewport index specified to EnableiNV,
    DisableiNV or IsEnablediNV is greater or equal to the value of
    MAX_VIEWPORTS_NV, then an INVALID_VALUE error is generated.

    The state required consists of four integer values per viewport, and
    a bit indicating whether the test is enabled or disabled for each
    viewport. In the initial state, left = bottom = 0, and width and
    height are determined by the size of the window into which the GL is
    to do its rendering for all viewports. If the default framebuffer is
    bound but no default framebuffer is associated with the GL context
    (see chapter 9), then with and height are initially set to zero.
    Initially, the scissor test is disabled for all viewports.

    ScissorIndexedNV and ScissorIndexedvNV specify the scissor rectangle for
    a single viewport and are equivalent (assuming no errors are
    generated) to:

        int v[] = { left, bottom, width, height };
        ScissorArrayvNV(index, 1, v);

    and

        ScissorArrayvNV(index, 1, v);

    respectively.

    Scissor sets the scissor rectangle for all viewports to the same
    values and is equivalent (assuming no errors are generated) to:

        for (uint i = 0; i < MAX_VIEWPORTS_NV; i++) {
            ScissorIndexedNV(i, left, bottom, width, height);
        }

    Calling Enable or Disable with the symbolic constant SCISSOR_TEST is
    equivalent, assuming no errors, to:

    for (uint i = 0; i < MAX_VIEWPORTS_NV; i++) {
        EnableiNV(SCISSOR_TEST, i);
        /* or */
        DisableiNV(SCISSOR_TEST, i);
    }

Additions to Chapter 19 of the OpenGL ES 3.1 Specification (Context State
Queries)

    Modifications to Section 19.1 Simple Queries

        Add to the list of indexed query functions:

        void GetFloati_vNV(enum target, uint index, float *data);

Additions to the OpenGL ES Shading Language Version 3.10 Specification

    Add a new Section 3.4.x, GL_NV_viewport_array Extension (p. 13)

    3.4.x GL_NV_viewport_array Extension

    To use the GL_NV_viewport_array extension in a shader it must be
    enabled using the #extension directive.

    The shading language preprocessor #define GL_NV_viewport_array will
    be defined to 1 if the GL_NV_viewport_array extension is supported.

    Modify Section 7.1.1gs, "Geometry Shader Special Variables"

    Add to the list of geometry shader built-in variables:

        out highp int gl_ViewportIndex;    // may be written to


    Additions to Section 7.1.1gs.2, "Geometry Shader Output Variables"

    Add a paragraph after the paragraph describing gl_Layer, starting
    "gl_Layer is used to select a specific layer (or face and layer of a
    cube map) of a multi-layer framebuffer attachment.":

    The built-in variable gl_ViewportIndex is available as an output variable
    in the geometry shader and an input variable in the fragment shader. In the
    geometry shader it provides the index of the viewport to which the next
    primitive emitted from the geometry shader should be drawn. Primitives
    generated by the geometry shader will undergo viewport transformation and
    scissor testing using the viewport transformation and scissor rectangle
    selected by the value of gl_ViewportIndex. The viewport index used will
    come from one of the vertices in the primitive being shaded. Which vertex
    the viewport index comes from is implementation-dependent, so it is best to
    use the same viewport index for all vertices of the primitive. If a
    geometry shader does not assign a value to gl_ViewportIndex, viewport
    transform and scissor rectangle zero will be used. If a geometry shader
    assigns a value to gl_ViewportIndex and there is a path through the shader
    that does not set gl_ViewportIndex, then the value of gl_ViewportIndex is
    undefined for executions of the shader that take that path. See section
    11.1gs.4 "Geometry Shader Outputs" of the OpenGL ES Specification for more
    information.

    Modify section 7.1.2 "Fragment Shader Special Variables", as modified by
    EXT_geometry_shader:

    Add to the list of built-in variables:

        in highp int gl_ViewportIndex;

    Add description of the variable:

    The input variable gl_ViewportIndex will have the same value that was
    written to the output variable gl_ViewportIndex in the geometry stage. If
    the geometry stage does not dynamically assign to gl_ViewportIndex, the
    value of gl_ViewportIndex in the fragment shader will be undefined. If the
    geometry stage makes no static assignment to gl_ViewportIndex, the fragment
    stage will read zero. Otherwise, the fragment stage will read the same
    value written by the geometry stage, even if that value is out of range. If
    a fragment shader contains a static access to gl_ViewportIndex, it will
    count against the implementation defined limit for the maximum number of
    inputs to the fragment stage.

    Add to Section 7.2 "Built-In Constants", as modified by
    EXT_geometry_shader, to the list of built-in constants matching the
    corresponding API implementation-dependent limits:

        const highp int gl_MaxViewports = 16;

Errors

    INVALID_VALUE is generated by ViewportArrayvNV if <first> + <count> is
    greater than or equal to the value of MAX_VIEWPORTS_NV, or if any
    viewport's width or height is less than 0.

    INVALID_VALUE is generated by ScissorArrayvNV if <first> + <count> is
    greater than or equal to the value of MAX_VIEWPORTS_NV, or if any
    scissor rectangle's width or height is less than zero.

    INVALID_VALUE is generated by DepthRangeArrayfvNV if <first> + <count> is
    greater than or equal to the vaue of MAX_VIEWPORTS_NV.

    INVALID_VALUE is generated by EnableiNV, DisableiNV and IsEnablediNV if
    <index> is greater than or equal to the value of MAX_VIEWPORTS_NV.

New State

    Table 20.5 (p. 356)

    Get Value                 Type             Get Command       Initial Value   Description                 Sec
    ------------------------  ---------------- ------------      -------------   --------------------------  -----
    VIEWPORT                  16* x 4 x R      GetFloati_vNV       See 2.11.1      Viewport origin & extent  12.5.1
    DEPTH_RANGE               16* x 2 x R[0,1] GetFloati_vNV       See 2.16.1      Depth range near & far    12.5.1

NOTE: The changes are that VIEWPORT and DEPTH_RANGE are extended to
accommodate 16* copies and now consist of floating-point and
double-precision values, respectively.

    Table 20.12 (p. 363)

    Get Value                 Type        Get Command           Initial Value   Description               Sec
    ------------------------  ----------  -------------         -------------   -------------------       ------
    SCISSOR_TEST              16* x B     IsEnablediNV          FALSE           Scissoring enabled        15.1.2
    SCISSOR_BOX               16* x 4 x Z GetIntegeri_v         See 4.1.2       Scissor box               15.1.2

NOTE: The only change is that SCISSOR_TEST and SCISSOR_BOX are extended
to accommodate 16* copies.

New Implementation Dependent State

    Get Value                          Type   Get Command     Minimum Value   Description                     Sec.
    ---------                          ----   -----------     -------------   -------------------             -----
    MAX_VIEWPORT_DIMS    (NOTE 1)      2 x Z+ GetFloatv       See 2.16.1      Maximum viewport dimensions     12.5.1
    MAX_VIEWPORTS_NV                   Z+     GetIntegerv     16              Maximum number of               12.5.1
                                                                              active viewports
    VIEWPORT_SUBPIXEL_BITS_NV          Z+     GetIntegerv     0               Number of bits of sub-pixel     12.5.1
                                                                              precision for viewport bounds
    VIEWPORT_BOUNDS_RANGE_NV           2 x R  GetFloatv       (NOTE 2)        Viewport bounds range [min,max] 12.5.1
    LAYER_PROVOKING_VERTEX_NV          Z_4    GetIntegerv     -- (NOTE 3)     vertex convention followed by   12.5.1
                                                                              the gl_Layer GLSL variable
    VIEWPORT_INDEX_PROVOKING_VERTEX_NV Z_4    GetIntegerv     -- (NOTE 3)     vertex convention followed by   12.5.1
                                                                              the gl_ViewportIndex GLSL
                                                                              variable

NOTE 1: The recommended get command is changed from GetIntegerv to GetFloatv.
NOTE 2: range for viewport bounds:
  * On ES3.1-capable hardware the VIEWPORT_BOUNDS_RANGE_NV should be at least
    [-32768, 32767].
NOTE 3: Valid values are: FIRST_VERTEX_CONVENTION_NV,
LAST_VERTEX_CONVENTION_NV, UNDEFINED_VERTEX_NV.


Interactions with EXT_draw_buffers_indexed

    If EXT_draw_buffers_indexed is supported, EnableiNV, DisableiNV and
    IsEnablediNV alias EnableiEXT, DisableiEXT and IsEnablediEXT, respectively.


Issues

    See issues section in ARB_viewport_array.

    #1 What are the differences from ARB_viewport_array?

    - OpenGL ES does not support the double datatype. The changed interfaces of
    glDepthRangeArrayfvNV and DepthRangeIndexedfNV reflect that. 'float' is
    being used instead of 'clampf', with additional constraints in the text
    that the values will get clamped.
    - The ability to access gl_ViewportIndex from the fragment shader was added
    from ARB_fragment_layer_viewport.


Revision History

    Rev.    Date      Author    Changes
    ----  --------    --------  -----------------------------------------
     1    06/18/2014  mheyer    Based on ARB_viewport_array, stripped for ES3.1
                                - replaced clampd with float for glDepthRangef
                                - instead of EnableIndexed and DisableIndexed, use
                                  Enablei and Disablei
                                - PROVOKING_VERTEX_NV removed
     2    07/24/2014  mheyer    Minor edits.
     3    08/10/2014  mheyer    Edit for consistency.
     4    09/04/2014  jhelferty Add viewport part of ARB_fragment_layer_viewport
                                as was done with layer in EXT_geometry_shader
     5    10/24/2014  dkoch     Cleanup for publishing.
