Name

    OES_viewport_array

Name Strings

    GL_OES_viewport_array

Contributors

    Contributors to NV_viewport_array
    Daniel Koch, NVIDIA
    Jeff Leger, Qualcomm

Contact

    Tobias Hector, Imagination Technologies (tobias.hector 'at' imgtec.com)

Notice

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

Specification Update Policy

    Khronos-approved extension specifications are updated in response to
    issues and bugs prioritized by the Khronos OpenGL ES Working Group. For
    extensions which have been promoted to a core Specification, fixes will
    first appear in the latest version of that core Specification, and will
    eventually be backported to the extension document. This policy is
    described in more detail at
        https://www.khronos.org/registry/OpenGL/docs/update_policy.php

Status

    Approved by the OpenGL ES Working Group on April 20, 2016
    Ratified by the Khronos Board of Promoters on July 22, 2016

Version

    Last Modified Date:         2023/09/13
    Author Revision:            6

Number

    Open GL ES Extension #267

Dependencies

    OpenGL ES 3.2, EXT_geometry_shader or OES_geometry_shader is required.

    This extension is written against the OpenGL ES 3.2 Specification (August
    10, 2015)

    This extension is written against the OpenGL ES Shading Language 3.20.2
    Specification (August 6, 2015)

    This extension has interactions with EXT_draw_buffers_indexed, OES_draw_buffers_indexed and ES3.2

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 ES should draw primitives. Unextended OpenGL ES implementations provide a
    single viewport per context. In order to draw primitives into multiple
    viewports, the OpenGL ES 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 ES viewport.

    This extension enhances OpenGL ES 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.

IP Status

    No known IP claims.

New Procedures and Functions

    void ViewportArrayvOES(uint first, sizei count, const float * v);
    void ViewportIndexedfOES(uint index, float x, float y, float w, float h);
    void ViewportIndexedfvOES(uint index, const float * v);
    void ScissorArrayvOES(uint first, sizei count, const int * v);
    void ScissorIndexedOES(uint index, int left, int bottom, sizei width, sizei height);
    void ScissorIndexedvOES(uint index, const int * v);
    void DepthRangeArrayfvOES(uint first, sizei count, const float * v);
    void DepthRangeIndexedfOES(uint index, float n, float f);
    void GetFloati_vOES(enum target, uint index, float *data);

    [[If none of OpenGL ES 3.2, EXT_draw_buffers_indexed or OES_draw_buffers_indexed are supported]]
    void EnableiOES(enum target, uint index);
    void DisableiOES(enum target, uint index);
    boolean IsEnablediOES(enum target, uint index);

New Tokens

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

        MAX_VIEWPORTS_OES                               0x825B
        VIEWPORT_SUBPIXEL_BITS_OES                      0x825C
        VIEWPORT_BOUNDS_RANGE_OES                       0x825D
        VIEWPORT_INDEX_PROVOKING_VERTEX_OES             0x825F

    Accepted by the <pname> parameter of GetIntegeri_v:

        SCISSOR_BOX                                     0x0C10

    Accepted by the <pname> parameter of GetFloati_vOES:

        VIEWPORT                                        0x0BA2
        DEPTH_RANGE                                     0x0B70

    Accepted by the <pname> parameter of Enablei, Disablei, and IsEnabledi:

        SCISSOR_TEST                                    0x0C11

Additions to Chapter 11 of the OpenGL ES 3.2 Specification (Programmable Vertex
Post-Processing)

    Modifications to Section 11.3.4.5, Layer Selection

    Rename the section to "Layer and Viewport Selection".

    Add the following paragraph after the first paragraph:

    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 last 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 and VIEWPORT_INDEX_PROVOKING_VERTEX_OES,
    respectively.

Additions to Chapter 12 of the OpenGL ES 3.2 Specification (Fixed-Function
Vertex Post-Processing)

    Modifications to section 12.5.1 "Controlling the Viewport"

    Replace the entire section 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_OES 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_OES 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 DepthRangeArrayfvOES(uint first, sizei count, const float * v);
        void DepthRangeIndexedfOES(uint index, float n, float f);
        void DepthRangef(float n, float f);

    DepthRangeArrayfvOES 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.
    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. Values in <v> and the parameters <n> and <f> are clamped to
    the range [0, 1] when specified.

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

        float v[] = { n, f };
        DepthRangeArrayfvOES(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_OES; i++)
            DepthRangeIndexedfOES(i, n, f);

    Z_w is represented as either ...

    Errors

        An INVALID_VALUE error is generated if the sum of <first> and <count> is
        greater than the value of MAX_VIEWPORTS_OES.

        An INVALID_VALUE error is generated if <count> is negative.

        An INVALID_VALUE error is generated if <index> is greater than or equal to
        the value of MAX_VIEWPORTS_OES.

    Viewport transformation parameters are specified using

        void ViewportArrayvOES(uint first, sizei count, const float * v);
        void Viewport(int x, int y, sizei w, sizei h);
        void ViewportIndexedfOES(uint index, float x, float y, float w, float h);
        void ViewportIndexedfvOES(uint index, const float * v);

    ViewportArrayvOES specifies parameters for multiple viewports
    simultaneously. <first> specifies the index of the first viewport to
    modify and <count> specifies the number of viewports. 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.

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

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

    and

        ViewportArrayvOES(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_OES; i++)
            ViewportIndexedfOES(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_OES
    (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).

    Errors

        An INVALID_VALUE error is generated if the sum of <first> and <count> is
        greater than the value of MAX_VIEWPORTS_OES.

        An INVALID_VALUE error is generated if <count> is negative>.

        An INVALID_VALUE error is generated if <index> is greater than or equal to
        the value of MAX_VIEWPORTS_OES.

        An INVALID_VALUE error is generated if any <w> or <h> value 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_OES.

Additions to Chapter 13 of the OpenGL ES 3.2 Specification (Fixed-Function
Primitive Assembly and Rasterization)

    Replace section 13.8.2 "Scissor Test" with the following:

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

        void ScissorArrayvOES(uint first, sizei count, const int * v);
        void ScissorIndexedOES(uint index, int left, int bottom, sizei width, sizei height);
        void ScissorIndexedvOES(uint index, int * v);
        void Scissor(int left, int bottom, sizei width, sizei height);

    ScissorArrayvOES 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.  <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 Enablei or
    Disablei 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 IsEnabledi 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 <target>,
    but no <index> parameter.

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

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

    and

        ScissorArrayvOES(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_OES; i++) {
            ScissorIndexedOES(i, left, bottom, width, height);
        }

    Calling Enable or Disable with <target> SCISSOR_TEST is
    equivalent, assuming no errors, to:

    for (uint i = 0; i < MAX_VIEWPORTS_OES; i++) {
        Enablei(SCISSOR_TEST, i);
        /* or */
        Disablei(SCISSOR_TEST, i);
    }

    Errors

        An INVALID_VALUE error is generated if the sum of <first> and <count> is
        greater than the value of MAX_VIEWPORTS_OES.

        An INVALID_VALUE error is generated if <index> is greater than or equal to
        the value of MAX_VIEWPORTS_OES.

        An INVALID_VALUE error is generated if any <width> or <height> value is
        negative.

    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.

Additions to Chapter 20 of the OpenGL ES 3.2 Specification (Context State
Queries)

    Modifications to Section 20.1 Simple Queries

        Add to the list of indexed query functions:

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

Additions to Chapter 3 of the OpenGL ES Shading Language Specification

    Add a new Section 3.4.x, GL_OES_viewport_array Extension

    3.4.x GL_OES_viewport_array Extension

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

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

Additions to Chapter 7 of the OpenGL ES Shading Language Specification

    Add the following built-in to section 7.1.4, Geometry Shader Special
    Variables:

        out highp int gl_ViewportIndex;

    Add the following paragraph to the end of Section 7.1.4.2, Geometry Shader
    Output Variables:

    gl_ViewportIndex 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 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 determined as discussed in section 11.3.4.5 of the OpenGL ES
    Specification, but may be undefined, so it is best to write 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 statically 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.3.4.5 "Layer
    and Viewport Selection" of the OpenGL ES Specification for more information.

    Add the following build-in to section 7.1.5 "Fragment Shader Special
    Variables:

        in highp int gl_ViewportIndex;

    Add the following paragraph to the end of section 7.1.5 "Fragment Shader
    Special Variables:

    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 value
    in the fragment stage is undefined. Otherwise, the fragment stage will read
    the same value written by the geometry stage, unless it is out of range,
    in which case it is undefined. 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 the following built-in to section 7.2 "Built-In Constants":

        const highp int gl_MaxViewports = 16;

Errors

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

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

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

    An INVALID_VALUE error is generated by Enablei, Disablei and IsEnabledi if
    <target> is SCISSOR_TEST and <index> is greater than or equal to the value
    of MAX_VIEWPORTS_OES

New State

    Table 21.6:

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

NOTE: The changes are that VIEWPORT and DEPTH_RANGE are extended to
accommodate 16* copies. Viewport now consists of floating-point values.

    Table 21.13:

    Get Value                 Type        Get Command           Initial Value   Description               Sec
    ------------------------  ----------  -------------         -------------   -------------------       ------
    SCISSOR_TEST              16* x B     IsEnabledi            FALSE           Scissoring enabled        13.8.2
    SCISSOR_BOX               16* x 4 x Z GetIntegeri_v         See 13.8.2      Scissor box               13.8.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 12.5.1      Maximum viewport dimensions     12.5.1
    MAX_VIEWPORTS_OES                    Z+     GetIntegerv     16              Maximum number of               12.5.1
                                                                                active viewports
    VIEWPORT_SUBPIXEL_BITS_OES           Z+     GetIntegerv     0               Number of bits of sub-pixel     12.5.1
                                                                                precision for viewport bounds
    VIEWPORT_BOUNDS_RANGE_OES            2 x R  GetFloatv       [-32768, 32767] Viewport bounds range [min,max] 12.5.1
    VIEWPORT_INDEX_PROVOKING_VERTEX_OES  Z_4    GetIntegerv     -- (NOTE 2)     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: Valid values are: FIRST_VERTEX_CONVENTION,
LAST_VERTEX_CONVENTION, PROVOKING_VERTEX, UNDEFINED_VERTEX.

Interactions with EXT_draw_buffers_indexed, OES_draw_buffers_indexed and OpenGL ES 3.2

    If EXT_draw_buffers_indexed is supported, EnableiEXT, DisableiEXT and
    IsEnablediEXT can be used in place of their core counterparts.

    If only EXT_draw_buffers_indexed is supported, replace all mentions
    of Enablei, Disablei and IsEnabledi with their EXT suffixed counterparts.

    If OES_draw_buffers_indexed is supported, EnableiOES, DisableiOES and
    IsEnablediOES can be used in place of their core counterparts.

    If only OES_draw_buffers_indexed is supported, replace all mentions
    of Enablei, Disablei and IsEnabledi with their OES suffixed counterparts.

    If none of these are supported, then the EnableiOES, DisableiOES and
    IsEnablediOES functions are added, with exactly the same specification as
    the equivalently named core functions in OpenGL ES 3.2. Replace all mentions
    of Enablei, Disablei and IsEnabledi with their OES suffixed counterparts.

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
    glDepthRangeArrayfvOES and DepthRangeIndexedfOES 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.
    - Unlike ARB_fragment_layer_viewport, the value of gl_ViewportIndex is undefined
    if it wasn't written by the geometry shader.


Revision History

    Rev.    Date      Author    Changes
    ----  --------    --------  -----------------------------------------
     1    10/12/2015  thector   Initial draft
     2    23/03/2016  thector   Changed to EXT
     3    06/04/2016  thector   Made gl_ViewportIndex undefined in a fragment shader if not previously written
     4    13/04/2016  thector   Changed to OES
                                Added interactions with OES_draw_buffers_indexed
                                Allowed dependency on OES_geometry_shader as well as EXT_geometry_shader
     5    19/04/2016  dkoch     Typographical fixes.
                                Sync some additional language with GL 4.5 and GLSL 4.50.
     6    13/09/2023  zmike     opengl/api/196: Clarify gl_ViewportIndex and gl_Layer
                                out of range values in fragment shader
