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 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 parameter of GetIntegeri_v: SCISSOR_BOX 0x0C10 Accepted by the parameter of GetFloati_vOES: VIEWPORT 0x0BA2 DEPTH_RANGE 0x0B70 Accepted by the 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. specifies the index of the first viewport to modify and specifies the number of viewports. Viewports whose indices lie outside the range [, + ) are not modified. The parameter contains the address of an array of float types specifying near (n) and far (f) for each viewport in that order. Values in and the parameters and 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 and is greater than the value of MAX_VIEWPORTS_OES. An INVALID_VALUE error is generated if is negative. An INVALID_VALUE error is generated if 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. specifies the index of the first viewport to modify and specifies the number of viewports. Viewports whose indices lie outside the range [, + ) are not modified. 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. and give the location of the viewport's lower left corner and and 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 and is greater than the value of MAX_VIEWPORTS_OES. An INVALID_VALUE error is generated if is negative>. An INVALID_VALUE error is generated if is greater than or equal to the value of MAX_VIEWPORTS_OES. An INVALID_VALUE error is generated if any or 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"). specifies the index of the first scissor rectangle to modify, and specifies the number of scissor rectangles. 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 can be queried by calling IsEnabledi with SCISSOR_TEST and . The value of the scissor test enable for viewport zero may also be queried by calling IsEnabled with the same , but no 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 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 and is greater than the value of MAX_VIEWPORTS_OES. An INVALID_VALUE error is generated if is greater than or equal to the value of MAX_VIEWPORTS_OES. An INVALID_VALUE error is generated if any or 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 + 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 + 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 + is greater than or equal to the vaue of MAX_VIEWPORTS_OES. An INVALID_VALUE error is generated by Enablei, Disablei and IsEnabledi if is SCISSOR_TEST and 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