Name
ARB_viewport_array
Name Strings
GL_ARB_viewport_array
Contributors
Graham Sellers, AMD
Mark Young, AMD
Nick Haemel, AMD
Bill Licea-Kane, AMD
Jeff Bolz, NVIDIA
Daniel Koch, TransGaming
Pat Brown, NVIDIA
Bruce Merry, ARM
Ian Stewart, NVIDIA
Contact
Graham Sellers, AMD (graham.sellers 'at' amd.com)
Notice
Copyright (c) 2010-2013 The Khronos Group Inc. Copyright terms at
http://www.khronos.org/registry/speccopyright.html
Status
Complete. Approved by the ARB on June 9, 2010.
Approved by the Khronos Board of Promoters on July 23, 2010.
Version
Last Modified Date: 06/25/2012
Author Revision: 18
Number
ARB Extension #100
Dependencies
OpenGL 1.0 is required.
OpenGL 3.2 or the EXT_geometry_shader4 or ARB_geometry_shader4 extensions
are required.
This extension is written against the OpenGL 3.2 (Compatibility)
Specification.
This extension is written against the OpenGL Shading Language Specification
version 1.50.09.
Overview
OpenGL 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.
IP Status
No known IP claims.
New Procedures and Functions
void ViewportArrayv(uint first, sizei count, const float * v);
void ViewportIndexedf(uint index, float x, float y, float w, float h);
void ViewportIndexedfv(uint index, const float * v);
void ScissorArrayv(uint first, sizei count, const int * v);
void ScissorIndexed(uint index, int left, int bottom, sizei width, sizei height);
void ScissorIndexedv(uint index, const int * v);
void DepthRangeArrayv(uint first, sizei count, const clampd * v);
void DepthRangeIndexed(uint index, clampd n, clampd f);
void GetFloati_v(enum target, uint index, float *data);
void GetDoublei_v(enum target, uint index, double *data);
void GetIntegerIndexedvEXT(enum target, uint index, int * v);
void EnableIndexedEXT(enum target, uint index);
void DisableIndexedEXT(enum target, uint index);
boolean IsEnabledIndexedEXT(enum target, uint index);
Note that GetIntegerIndexedvEXT, EnableIndexedEXT, DisableIndexedEXT and
IsEnabledIndexedEXT are introduced by other OpenGL extensions such as
EXT_draw_buffers2. If this extension is implemented against an earlier
version of OpenGL that does not support GetIntegeri_v and so on, the
'Indexed' versions of these functions may be used in their place.
New Tokens
Accepted by the parameter of GetBooleanv, GetIntegerv, GetFloatv,
GetDoublev and GetInteger64v:
MAX_VIEWPORTS 0x825B
VIEWPORT_SUBPIXEL_BITS 0x825C
VIEWPORT_BOUNDS_RANGE 0x825D
LAYER_PROVOKING_VERTEX 0x825E
VIEWPORT_INDEX_PROVOKING_VERTEX 0x825F
Accepted by the parameter of GetIntegeri_v:
SCISSOR_BOX 0x0C10
Accepted by the parameter of GetFloati_v:
VIEWPORT 0x0BA2
Accepted by the parameter of GetDoublei_v:
DEPTH_RANGE 0x0B70
Accepted by the parameter of Enablei, Disablei, and IsEnabledi:
SCISSOR_TEST 0x0C11
Returned in the parameter from a Get query with a of
LAYER_PROVOKING_VERTEX or VIEWPORT_INDEX_PROVOKING_VERTEX:
FIRST_VERTEX_CONVENTION 0x8E4D
LAST_VERTEX_CONVENTION 0x8E4E
PROVOKING_VERTEX 0x8E4F
UNDEFINED_VERTEX 0x8260
Additions to Chapter 2 of the OpenGL 3.2 (Compatibility) Specification (OpenGL
Operation)
Modifications to Section 2.15.4, Geometry Shader Execution Environment
Add a paragraph after the description of gl_Layer, page 124.
The built-in special variable gl_ViewportIndex is used to direct
rendering to one of several viewports and is discussed in the section
entitled "Layer and Viewport Selection", below.
Rename the the "Layered Rendering" subsection to "Layer and Viewport
Selection" and append the following:
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.
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,
respectively. For either value, if the value returned is
PROVOKING_VERTEX, then vertex selection follows the convention
specified by ProvokingVertex (see section 2.21). If the value
returned is FIRST_VERTEX_CONVENTION, selection is always taken from
the first vertex of a primitive. If the value returned is
LAST_VERTEX_CONVENTION, the selection is always taken from the last
vertex of a primitive. If the value returned is UNDEFINED_VERTEX,
the selection is not guaranteed to be taken from any specific vertex
in the primitive. The vertex considered the provoking vertex for
particular primitive types is given in Table 2.15.
Modify section 2.16.1 "Controlling the Viewport", page 126.
Change the first paragraph of section 2.16.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 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 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 DepthRangeArrayv(uint first, sizei count, const clampd * v);
void DepthRangeIndexed(uint index, clampd n, clampd f);
void DepthRange(clampd n, clampd f);
DepthRangeArrayv 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. If
( + ) is greater than the value of MAX_VIEWPORTS then
an INVALID_VALUE error will be generated. Viewports whose indices
lie outside the range [, + ) are not modified.
The parameter contains the address of an array of clampd types
specifying near (n) and far (f) for each viewport in that order.
DepthRangeIndexed specifies the depth range for a single viewport
and is equivalent (assuming no errors are generated) to:
clampd v[] = { n, f };
DepthRangeArrayv(index, 1, v);
DepthRange 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; i++)
DepthRangeIndexed(i, n, f);
Z_w is represented as either ...
Replace the end of section 2.16.1, starting from "Viewport transformation
parameters are specified using..."
Viewport transformation parameters are specified using
void ViewportArrayv(uint first, sizei count, const float * v);
void Viewport(int x, int y, sizei w, sizei h);
void ViewportIndexedf(uint index, float x, float y, float w, float h);
void ViewportIndexedfv(uint index, const float * v);
ViewportArrayv specifies parameters for multiple viewports
simultaneously. specifies the index of the first viewport to
modify and specifies the number of viewports. If ( +
) is greater than the value of MAX_VIEWPORTS then an
INVALID_VALUE error will be generated. 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.
ViewportIndexedf and ViewportIndexedfv specify parameters for a
single viewport and are equivalent (assuming no errors are
generated) to:
float v[4] = { x, y, w, h };
ViewportArrayv(index, 1, v);
and
ViewportArrayv(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; i++)
ViewportIndexedf(i, 1, (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 = 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
(see section 6.1).
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 4). 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
4), 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.
Additions to Chapter 3 of the OpenGL 3.2 (Compatibility) Specification
(Rasterization)
None.
Additions to Chapter 4 of the OpenGL 3.2 (Compatibility) Specification (Per-
Fragment Operations and the Framebuffer)
Replace section 4.1.2 "Scissor Test", page 284.
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 ScissorArrayv(uint first, sizei count, const int * v);
void ScissorIndexed(uint index, int left, int bottom, sizei width, sizei height);
void ScissorIndexedv(uint index, int * v);
void Scissor(int left, int bottom, sizei width, sizei height);
ScissorArrayv defines a set of scissor rectangles that are each
applied to the corresponding viewport (see section 2.16.1
"Controlling the Viewport"). specifies the index of the
first scissor rectangle to modify, and specifies the number
of scissor rectangles. If ( + ) is greater than the
value of MAX_VIEWPORTS, then an INVALID_VALUE error is generated.
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 2.16.1).
For pixel rectangles and bitmaps, the scissor rectangle numbered
zero is used for the scissor test.
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 symbolic
constant, but no 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 Enablei,
Disablei or IsEnabledi is greater or equal to the value of
MAX_VIEWPORTS, 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 4), then with and height are initially set to zero.
Initially, the scissor test is disabled for all viewports.
ScissorIndexed and ScissorIndexedv specify the scissor rectangle for
a single viewport and are equivalent (assuming no errors are
generated) to:
int v[] = { left, bottom, width, height };
ScissorArrayv(index, 1, v);
and
ScissorArrayv(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; i++) {
ScissorIndexed(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; i++) {
Enablei(SCISSOR_TEST, i);
/* or */
Disablei(SCISSOR_TEST, i);
}
Additions to Chapter 5 of the OpenGL 3.2 (Compatibility) Specification (Special
Functions)
None.
Additions to Chapter 6 of the OpenGL 3.2 (Compatibility) Specification (State
and State Requests)
Modifications to Section 6.1.1 Simple Queries
Add to the list of indexed query functions:
void GetFloati_v(enum target, uint index, float *data);
void GetDoublei_v(enum target, uint index, float *data);
Additions to the OpenGL Shading Language Version 1.50.09 Specification
Add a new Section 3.3.x, GL_ARB_viewport_array Extension (p. 13)
3.3.x GL_ARB_viewport_array Extension
To use the GL_ARB_viewport_array extension in a shader it must be
enabled using the #extension directive.
The shading language preprocessor #define GL_ARB_viewport_array will
be defined to 1 if the GL_ARB_viewport_array extension is supported.
Additions to Section 7.1 "Vertex and Geometry Shader Special Variables"
Add a paragraph after the paragraph describing gl_Layer, starting "The
built-in output variable gl_Layer is available only in the geometry
language, and provides the number of the layer of textures attached to a
FBO to direct rendering to.":
The built-in output variable gl_ViewportIndex is available only in the
geometry language, and 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
2.15.4, under "Geometry Shader Outputs" for more information.
Add to the list of geometry shader built-in variables on p. 69:
out int gl_ViewportIndex; // may be written to
Modify the description of EmitVertex() in Section 8.10, "Geometry Shader
Functions", page 104:
The function EmitVertex() specifies that a vertex is completed. A vertex
is added to the current output primitive using the current values of the
geometry shader's output variables, including gl_PointSize, gl_ClipDistance,
gl_Layer, gl_Position, gl_PrimitiveID and gl_ViewportIndex. The values
of all these...
Add to the list of built in constants available to geometry shaders in
Section 7.4:
const int gl_MaxViewports = 16;
Additions to the AGL/GLX/WGL Specifications
None.
GLX Protocol
TBD.
Errors
INVALID_VALUE is generated by ViewportArrayv if + is
greater than or equal to the value of MAX_VIEWPORTS, or if any
viewport's width or height is less than 0.
INVALID_VALUE is generated by ScissorArrayv if + is
greater than or equal to the value of MAX_VIEWPORTS, or if any
scissor rectangle's width or height is less than zero.
INVALID_VALUE is generated by DepthRangeArrayv if + is
greater than or equal to the vaue of MAX_VIEWPORTS.
INVALID_VALUE is generated by Enablei, Disablei and IsEnabledi if
is greater than or equal to the value of MAX_VIEWPORTS.
New State
Table 6.13 (p. 405)
Get Value Type Get Command Initial Value Description Sec Attribute
------------------------ ---------------- ------------ ------------- ------------------------ ----- ---------
VIEWPORT 16* x 4 x R GetFloati_v See 2.11.1 Viewport origin & extent 2.11.1 viewport
DEPTH_RANGE 16* x 2 x R[0,1] GetDoublei_v See 2.16.1 Depth range near & far 2.16.1 viewport
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 6.26 (p. 418)
Get Value Type Get Command Initial Value Description Sec Attribute
------------------------ ---------- ------------- ------------- ------------------- ----- ---------
SCISSOR_TEST 16* x B IsEnabledi FALSE Scissoring enabled 4.1.2 scissor/enable
SCISSOR_BOX 16* x 4 x Z GetIntegeri_v See 4.1.2 Scissor box 4.1.2 scissor
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 2.16.1
MAX_VIEWPORTS Z+ GetIntegerv 16 Maximum number of 2.16.1
active viewports
VIEWPORT_SUBPIXEL_BITS Z+ GetIntegerv 0 Number of bits of sub-pixel 2.16.1
precision for viewport bounds
VIEWPORT_BOUNDS_RANGE 2 x R GetFloatv (NOTE 2) Viewport bounds range [min,max] 2.16.1
LAYER_PROVOKING_VERTEX Z_4 GetIntegerv -- (NOTE 3) vertex convention followed by 2.15.4
the gl_Layer GLSL variable
VIEWPORT_INDEX_PROVOKING_VERTEX Z_4 GetIntegerv -- (NOTE 3) vertex convention followed by 2.15.4
the gl_ViewportIndex GLSL
variable
NOTE 1: The recommended get command is changed from GetIntegerv to GetFloatv.
NOTE 2: range for viewport bounds:
* On GL3-capable hardware the VIEWPORT_BOUNDS_RANGE should be at least
[-16384, 16383].
* On GL4-capable hardware the VIEWPORT_BOUNDS_RANGE should be at least
[-32768, 32767].
NOTE 3: Valid values are: FIRST_VERTEX_CONVENTION,
LAST_VERTEX_CONVENTION, PROVOKING_VERTEX, UNDEFINED_VERTEX.
Interactions with NV_depth_buffer_float
If NV_depth_buffer_float is supported, add the following commands:
void DepthRangeArraydvNV(uint first, sizei count, const double * v);
void DepthRangeIndexeddNV(uint index, double n, double f);
These functions are equivalent to the corresponding DepthRange*
functions, except the the parameters are clamped to [0, 1] when using
DepthRange*, but not when using DepthRange*dNV. When and are
applied to , they are clamped to the range appropriate given the
depth buffer's representation.
Interactions with ARB_provoking_vertex, EXT_provoking_vertex, and OpenGL 3.2 or later
If none of ARB_provoking_vertex, EXT_provoking_vertex or OpenGL 3.2
or later are supported, ignore all references to ProvokingVertex and
PROVOKING_VERTEX. This extension will continue to require support
for the LAYER_PROVOKING_VERTEX and VIEWPORT_INDEX_PROVOKING_VERTEX
queries, but only FIRST_VERTEX_CONVENTION, LAST_VERTEX_CONVENTION,
or UNDEFINED_VERTEX will be enumerated.
Dependencies on compatibitliy profile contexts
Pixel rectangle primitives and bitmaps are available only in
compatibility profile contexts. In the core profile, references to
pixel rectangles and bitmaps are removed from the description of
scissor rectangles in section 4.1.2.
Interactions with NV_geometry_program4
If NV_geometry_program4 is supported and the "ARB_viewport_array" program
option is specified, geometry result variable "result.viewport" can be
used to specify the viewport array index to use for primitive viewport
transformations and scissoring.
(add the following rule to the NV_geometry_program4 grammar)
::= ...
| "viewport"
(add the following to Table X.3, Geometry Program Result Variable Bindings)
Binding Components Description
----------------------------- ---------- ----------------------------
result.viewport (v,*,*,*) viewport array index
(add the following to Section 2.X.2, Program Grammar)
If a result variable binding matches "result.viewport", updates to the "x"
component of the result variable provide a single integer that serves as a
viewport index specifier for viewport arrays. The index must be written as
an integer value; writing a floating-point value will produce undefined
results. If a value outside the range [0, MAX_VIEWPORTS-1] is given, the
behavior is to proceed as if viewport index 0 was selected. If the
"ARB_viewport_array" program option is not specified, the "result.viewport"
binding is unavailable.
(add the following to Section 2.X.6.Y, Geometry Program Options)
+ Viewport Array (ARB_viewport_array)
If a geometry program specifies the "ARB_viewport_array" option, the
result binding "result.viewport" will be available to specify the viewport
index to use for primitive viewport transformations and scissoring as
described in section 2.X.2.
Issues
1) The name glViewportArray infers dynamic behavior and that the GL
may use values that present in the array at draw time. Would it be
more consistent to call this glViewportiv or glViewportv?
UNRESOLVED: For now, we'll leave it as glViewportArray.
2) Should we provide a mechanism to write gl_ViewportIndex in the vertex
shader? This would allow an application to assign gl_ViewportIndex
based on the value of a uniform, or from data read through an attribute,
for example.
RESOLVED: No. While it may be possible, there is no compelling use case,
and gl_Layer whose precedent we follow here, is not writable in the
vertex shader.
3) Does legacy glViewport update just the first viewport, or all of them?
RESOLVED: glViewport is equivalent to calling glViewportArray with
an array containing a single viewport once for each supported viewport.
It therefore defines all viewports in a single call. This is also true
for the legacy glScissor, glDepthRange, glEnable and glDisable functions.
4) When EXT_provoking_vertex is supported, is the provoking vertex convention
honored when selecting which vertex the gl_ViewportIndex property is to use?
RESOLVED: It is desirable that the provoking vertex convention
should be honored when selecting the vertex which gl_ViewportIndex is
obtained from (and similarly for gl_Layer). Other APIs require that these
properties should be taken from the "leading vertex", and this for
maximum content portability, it is desireable to be able to configure the
pipeline in the same way. However, there exists hardware which would
otherwise be able to support these features which does not have the
capability to configure which vertex this is selected from (even though
it may be doing so in a content-portable way). The
LAYER_PROVOKING_VERTEX and VIEWPORT_INDEX_PROVOKING_VERTEX
queries have been added to allow applications to determine if the
provoking vertex convention is being followed, and if not, which
convention is being used (if any). Note that applications which are
creating new content are advised that writing the same
gl_ViewportIndex and gl_Layer to all the vertices of a primitive is
the only portable solution.
5) Why glViewportIndex rather than glEnablei, and so on?
DISCUSSION: This extension follows the precedent of extensions such as
EXT_draw_buffers2, which introduced glEnableIndexed. These 'indexed'
functions since have been promoted to core OpenGL as glEnablei. If
this extension is used on an implementation supporting the glEnablei style
indexed functions, those may be used instead of, or in conjunction with
the glXXXXIndexed style indexed functions.
6) What happens if the viewport bounds lie on exact half-pixel coordinates?
For example, on a multi-sample surface, which samples should be considered
'inside' the viewport?
DISCUSSION: The viewport transformation includes clipping. Assuming this
clipping has similar precision to the viewport transform itself, then
the resulting clipped primitives should cut through partial pixels,
lighting only some of the samples within the pixel.
FEEDBACK FROM PAT:
This discussion is technically incorrect -- the viewport
transformation technically does *NOT* include any clipping. However, for
geometric primitives, the viewport transformation is applied to vertices
post-clipping (despite the fact that it precedes clipping in the spec), so
there is some clipping in the vicinity of the viewport transformation.
"Guardband clipping" is an alternate implementation, producing nearly
equivalent results to those specified by OpenGL. When using guardband
clipping, primitives are not clipped tightly to the view volume in X/Y:
-w <= x <= w
-w <= y <= w
Instead, looser (or no) clipping is applied, for example:
-8w <= x <= 8w
-8w <= y <= 8w
Since primitives are clipped far less aggressively, something has to be done
to produce results similar to those with aggressive clipping. To do this,
such implementations will enable per-pixel scissoring to the viewport
rectangle.
There are several areas of difference that implementations using guardband
clipping need to deal with (or ignore):
* line- and point-mode polygons: The OpenGL spec says that lines should be
drawn along the edges of polygons clipped to the frustum. If you don't clip
tightly, you can't draw those edges. (NOTE: The behavior specified by
OpenGL ends up being somewhat shitty. Let's say you have a line-mode
primitive clipped by both the left and right side of the frustum, which
implies that you should have vertical edges on the left and right side of
the viewport. With integer viewport coordinates, both edges will be exactly
between pixel centers. In practice, implementations' tiebreaking rules will
have either the left or right edge light up pixels outside the viewport. If
the viewport is the full window, this means that one of those lines won't be
visible.
* wide points and lines: According to the OpenGL spec, line or point
primitives on or near the edge of the viewport should technically extend
outside the viewport. For example, a four-pixel point on the left edge of
the viewport should light up eight pixels (2x4) outside the left edge of the
viewport. The scissoring used for guardband clipping will discard those
pixels. In my opinion, the scissored results are preferable to those called
for by the spec. Of course, with the OpenGL spec behavior, there are no
visible artifacts if: (a) the viewport covers the entire window or (b) the
application scissors manually itself.
Fractional viewports make things more complicated, particularly if the
implementation doesn't scissor at a per-sample granularity. In this case,
tight view volume clipping will result in primitives that are fully contained
within the fractional viewport (to the limits of clipping math, at least).
Guardband clipping will have primitives that extend beyond the viewport and
probably cover full pixels at the boundary of the viewport. (This discussion
assumes that a guardband implementation with fractional viewports extends its
viewport clip to pass on pixels containing any fraction of the floating-point
viewport.)
Direct3D 11 specifies that rasterization along the one-pixel edges of
fractional viewports to be undefined. If implementations want defined
behavior with fractional viewports, they can program a slightly wider viewport
and scissor away the pixels along the edge of the expanded viewport.
My recommendation is as follows:
(1) Edit the clipping section of the spec to explicitly permit implementations
to clip to larger view volume extents in (x,y) and instead scissor to the
viewport rectangle. Note that this scissor rectangle needs to either be
separate from the API-level scissor rectangle, or intersected with it. This
scissoring would always have to be enabled, regardless of the SCISSOR enabled.
(2) Edit the viewport section of the spec to briefly discuss the implications
of fractional viewports on the newly permitted scissoring.
7) What is the VIEWPORT_SUBPIXEL_BITS implementation defined value for?
This allows an application to query the precision of the viewport
transform. More specifically, if VIEWPORT_SUBPIXEL_BITS is zero, then
this indicates that the viewport bounds are likely implemented using
integers in hardware. If there are more bits (such as fixed point) then
this value will be non-zero. If the implementation truely has floating
point viewport bounds, it may report a sufficiently high value to
indicate this.
8) What happened to glGetIntegerv(GL_VIEWPORT, v)?
It still works. You can query floating point state with an integer query.
You'll get a rounded version of the state. You can also query indexed
state with a non-indexed query - you'll get the state for index 0. Thus
glGetIntegerv(GL_VIEWPORT, v) is the same as
glGetIntegeri_v(GL_VIEWPORT, 0, v), which is legal.
Revision History
Rev. Date Author Changes
---- -------- -------- -----------------------------------------
18 06/25/2012 Jon Leech Fixed GetIntegerIndexedivEXT ->
GetIntegerIndexedvEXT typo (Bug 6694).
17 07/25/2010 Jon Leech Fix typo in ViewportArrayv pseudocode
(Bug 6682).
16 07/19/2010 Jon Leech Add GetDoublei_v entry point and change
state for DEPTH_RANGE to be indexed and
queryable with this command (Bug 6495).
Reflow a few paragraphs and sync
language with 4.1 API spec.
15 06/16/2010 istewart Add interaction with NV_geometry_program4.
14 05/26/2010 Jon Leech Fix minor typos, remove tabs, make language
more consistent with GL core spec in
some places, and reflow paragraphs
following changes.
13 05/18/2010 gsellers Rename to ARB_viewport_array.
ARBify. Remove suffixes for Core 4.1.
12 05/17/2010 gsellers Error is not generated for viewport bounds
outside VIEWPORT_BOUNDS_RANGE.
Incoporate feedback from pbrown.
11 05/11/2010 gsellers Incorporate feedback from bmerry.
10 05/10/2010 dgkoch allow UNDEFINED_VERTEX_EXT for compatibility
9 05/10/2010 dgkoch add VIEWPORT_BOUNDS_RANGE and clarify the
valid values for the viewport location.
added queries to determing layer and viewport
index provoking vertex convention.
updated issue 4.
8 05/06/2010 gsellers Remove error if viewport > MAX_VIEWPORT_DIMS.
Fix typo in definition of glScissorIndexedv.
Update description of ViewportArrayv to accept
an array of floats, rather than an array of
integers.
7 04/29/2010 gsellers Updates and clarifications.
6 04/15/2010 gsellers Add interaction with NV_depth_range.
Change viewport bounds to floating point values.
Add viewport subpixel precision query.
Chage function names to ...Indexed.
Add issues 6 and 7.
5 01/07/2010 gsellers Change from AMD to EXT
Change function prototypes
Add glViewporti{_v}.
Add glScissorArray, glScissori{_v}.
Add glDepthRangeArrayv, glDepthRangei.
4 07/16/2009 gsellers Document EXT_provoking_vertex interaction.
Change 'leading vertex' to 'provoking vertex'.
Clarify interaction with glViewport.
Add multiple scissor rectangles.
3 07/14/2009 gsellers Updates from nickh and wwlk
2 07/08/2009 gsellers Updates from myoung
1 07/06/2009 gsellers Initial draft