Name NV_viewport_array2 Name Strings GL_NV_viewport_array2 Contact Jeff Bolz, NVIDIA Corporation (jbolz 'at' nvidia.com) Pat Brown, NVIDIA Corporation (pbrown 'at' nvidia.com) Contributors Pat Brown, NVIDIA Mathias Heyer, NVIDIA Status Shipping Version Last Modified Date: March 27, 2015 Revision: 2 Number OpenGL Extension #476 OpenGL ES Extension #237 Dependencies This extension is written against the OpenGL 4.3 specification (Compatibility Profile). This extension interacts with the OpenGL ES 3.1 (March 17, 2014) specification. If implemented in OpenGL ES, NV_viewport_array, EXT_geometry_shader and EXT_shader_io_blocks are required. This extension interacts with EXT_tessellation_shader. This extension interacts with NV_geometry_shader_passthrough. This extension interacts with NV_gpu_program4. Overview This extension provides new support allowing a single primitive to be broadcast to multiple viewports and/or multiple layers. A shader output gl_ViewportMask[] is provided, allowing a single primitive to be output to multiple viewports simultaneously. Also, a new shader option is provided to control whether the effective viewport index is added into gl_Layer. These capabilities allow a single primitive to be output to multiple layers simultaneously. The gl_ViewportMask[] output is available in vertex, tessellation control, tessellation evaluation, and geometry shaders. gl_ViewportIndex and gl_Layer are also made available in all these shader stages. The actual viewport index or mask and render target layer values are taken from the last active shader stage from this set of stages. This extension is a superset of the GL_AMD_vertex_shader_layer and GL_AMD_vertex_shader_viewport_index extensions, and thus those extension strings are expected to be exported if GL_NV_viewport_array2 is supported. This extension includes the edits for those extensions, recast against the reorganized OpenGL 4.3 specification. New Procedures and Functions None. New Tokens None. Additions to Chapter 11 of the OpenGL 4.3 (Compatibility Profile) Specification (Programmable Vertex Processing) Add to Section 11.1.3.10 (Shader Outputs) The built-in output variables gl_ViewportIndex, gl_ViewportMask[], and gl_Layer hold the viewport index/mask and render target layer, as described in Section 11.4 (Viewport Index and Layer). Add to Section 11.2.1.2.3 (Tessellation Control Shader Outputs) The built-in output variables gl_ViewportIndex, gl_ViewportMask[], and gl_Layer hold the viewport index/mask and render target layer, as described in Section 11.4 (Viewport Index and Layer). Add to Section 11.2.3.4 (Tessellation Evaluation Shader Outputs) The built-in output variables gl_ViewportIndex, gl_ViewportMask[], and gl_Layer hold the viewport index/mask and render target layer, as described in Section 11.4 (Viewport Index and Layer). Modify Section 11.3.4.5 (Geometry Shader Outputs) Replace the paragraph about gl_ViewportIndex: The built-in output variables gl_ViewportIndex, gl_ViewportMask[], and gl_Layer hold the viewport index/mask and render target layer, as described in Section 11.4 (Viewport Index and Layer). Replace Section 11.3.4.6 (Layer and Viewport Selection) with new Section 11.4 (Layer and Viewport Selection) Geometry may be rendered to one of several different layers of cube map textures, three-dimensional textures, or one- or two-dimensional texture arrays. This functionality allows an application to bind an entire complex texture to a framebuffer object, and render primitives to arbitrary layers computed at run time. For example, it can be used render a scene into multiple layers of an array texture in one pass, or to select a particular layer to render to in shader code. The layer to render to is specified by writing to the built-in output variable gl_Layer. Layered rendering requires the use of framebuffer objects (see section 9.8). Shaders may also direct each primitive to zero or more viewports. The destination viewports for a primitive may be selected in the shader by writing to the built-in output variable gl_ViewportIndex (selecting a single viewport) or gl_ViewportMask[] (selecting multiple viewports). This functionality allows a shader to direct its output to different viewports for each primitive, or to draw multiple versions of a primitive into several different viewports. The specific vertex of a primitive used to select the rendering layer or viewport index/mask 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/gl_ViewportMask[] may be determined by calling GetIntegerv with the symbolic constants LAYER_PROVOKING_VERTEX and VIEWPORT_INDEX_PROVOKING_VERTEX, respectively. For either query, if the value returned is PROVOKING_VERTEX, then vertex selection follows the convention specified by ProvokingVertex (see section 13.4). 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 13.2. The layer selection may be made a function of the viewport index, as described in Section 7.1 of the GLSL specification. The viewport index, viewport mask, and layer outputs are available in vertex, tessellation control, tessellation evaluation, and geometry shaders. Only the last active shader stage (in pipeline order) from this list controls the viewport index/mask and layer; outputs in previous shader stages are not used, even if the last stage fails to write one of the outputs. Additions to Chapter 13 of the OpenGL 4.3 (Compatibility Profile) Specification (Fixed-Function Vertex Post-Processing) Modify Section 13.2 (Transform Feedback), p. 453 Modify the first paragraph: ...The vertices are fed back after vertex color clamping, but before viewport mask expansion, flatshading, and clipping. ... Modify Section 13.6.1 (Controlling the Viewport) Multiple viewports are available and are numbered zero through the value of MAX_VIEWPORTS minus one. If last active vertex, tessellation, or geometry shader writes to gl_ViewportIndex, the primitive is emitted to the viewport corresponding to the value assigned to gl_ViewportIndex, as taken from an implementation-dependent provoking vertex. The primitive is then transformed using the state of the selected viewport. 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 last active vertex, tessellation, or geometry shader writes to gl_ViewportMask[], the primitive is emitted to zero or more viewports. If bit is set in the mask, the primitive is emitted to viewport and transformed using the state of viewport . However, each primitive will still be captured by transform feedback and counted by primitive queries only once. If bits of gl_ViewportMask[] greater than or equal to the value of MAX_VIEWPORTS are set, the number of times the primitive is emitted and which viewport transformations are used are undefined. If neither gl_ViewportIndex nor gl_ViewportMask[] are written, the viewport numbered zero is used by the viewport transformation. Modify Section 14.5.2.1 (Line Stipple) (add to the end of the section) When rasterizing line segments that could be sent to multiple viewports via the gl_ViewportMask[] built-in geometry shader output (section 13.6.1), the line stipple pattern is not guaranteed to be continuous if segments are sent to multiple viewports. If a line segment is not an independent line segment and is not the first in a series of connected segments (where the stipple counter is reset to 0), the initial value of for the segment is undefined unless that line segment and all previous segments in the series were sent to the same single viewport. New Implementation Dependent State None. New State None. Additions to the AGL/GLX/WGL Specifications None. GLX Protocol None. Modifications to the OpenGL Shading Language Specification, Version 4.30 Including the following line in a shader can be used to control the language features described in this extension: #extension GL_NV_viewport_array2 : where is as specified in section 3.3. New preprocessor #defines are added to the OpenGL Shading Language: #define GL_NV_viewport_array2 1 Modify Section 7.1 (Built-In Language Variables), p. 116 Add to the list of vertex shader built-ins: out gl_PerVertex { highp int gl_ViewportIndex; highp int gl_ViewportMask[]; highp int gl_Layer; }; Add to the list of geometry shader built-ins: out highp int gl_ViewportMask[]; Add to the list of tessellation control shader built-ins: out gl_PerVertex { highp int gl_ViewportIndex; highp int gl_ViewportMask[]; highp int gl_Layer; } gl_out[]; Add to the list of tessellation evaluation shader built-ins: out gl_PerVertex { highp int gl_ViewportIndex; highp int gl_ViewportMask[]; highp int gl_Layer; }; Modify descriptions of gl_Layer and gl_ViewportIndex as follows: The variable gl_Layer is available as an output variable in the vertex, tessellation, and geometry (VTG) languages and an input variable in the fragment language. In the VTG languages, it is used to select a specific layer (or face and layer of a cube map) of a multi-layer framebuffer attachment. The actual layer used will come from one of the vertices in the primitive being shaded. Which vertex the layer comes from is undefined, so it is best to write the same layer value for all vertices of a primitive. If a shader statically assigns a value to gl_Layer, layered rendering mode is enabled. See section 11.4 "Layer and Viewport Selection" and section 9.4.9 "Layered Framebuffers" of the OpenGL Graphics System Specification for more information. If a shader statically assigns a value to gl_Layer, and there is an execution path through the shader that does not set gl_Layer, then the value of gl_Layer is undefined for executions of the shader that take that path. ... The input variable gl_Layer in the fragment language will have the same value that was written to the output variable gl_Layer in the VTG languages. If the final VTG stage does not dynamically assign a value to gl_Layer, the value of gl_Layer in the fragment stage will be undefined. If the final VTG stage makes no static assignment to gl_Layer, the input gl_Value in the fragment stage will be zero. Otherwise, the fragment stage will read the same value written by the final VTG stage, even if that value is out of range. If a fragment shader contains a static access to gl_Layer, it will count against the implementation defined limit for the maximum number of inputs to the fragment stage. The variable gl_ViewportIndex is available as an output variable in the VTG languages and an input variable in the fragment language. In the geometry language, it provides the index of the viewport to which the next primitive emitted from the geometry shader should be drawn. In the vertex and tessellation languages, it provides the index of the viewport associated with the vertex being shaded. Primitives 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. However, 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 the final VTG stage does not assign a value to gl_ViewportIndex or gl_ViewportMask[], viewport transform and scissor rectangle zero will be used. If a shader statically assigns a value to gl_ViewportIndex and there is a path through the shader that does not assign a value to gl_ViewportIndex, the value of gl_ViewportIndex is undefined for executions of the shader that take that path. See section 11.4 "Layer and Viewport Selection" of the OpenGL Graphics System Specification for more information. The input variable gl_ViewportIndex in the fragment stage will have the same value that was written to the output variable gl_ViewportIndex in the final VTG stage. If the final VTG stage does not dynamically assign to gl_ViewportIndex, the value of gl_ViewportIndex in the fragment shader will be undefined. If the final VTG 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 final VTG 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. The variable gl_ViewportMask[] is available as an output variable in the VTG languages. The array has ceil(v/32) elements where v is the maximum number of viewports supported by the implementation. When a shader writes this variable, bit B of element M controls whether the primitive is emitted to viewport 32*M+B. If gl_ViewportIndex is written by the final VTG stage, then gl_ViewportIndex in the fragment stage will have the same value. If gl_ViewportMask[] is written by the final VTG stage, then gl_ViewportIndex in the fragment stage will have the index of the viewport that was used in generating that fragment. If a shader statically assigns a value to gl_ViewportIndex, it may not assign a value to any element of gl_ViewportMask[]. If a shader statically writes a value to any element of gl_ViewportMask[], it may not assign a value to gl_ViewportIndex. That is, a shader may assign values to either gl_ViewportIndex or gl_ViewportMask[], but not both. Multiple shaders linked together must also consistently write just one of these variables. These incorrect usages all generate compile-time or link-time errors. The shader output gl_Layer may be redeclared with a layout qualifer as follows: layout (viewport_relative) out highp int gl_Layer; If gl_Layer is , then the viewport index is added to the layer used for rendering (and available in the fragment shader). If the shader writes gl_ViewportMask[], then gl_Layer has a different value for each viewport the primitive is rendered to. If gl_Layer is and the shader writes neither gl_ViewportIndex nor gl_ViewportMask[], a link-error will result. Modify Section 8.15 (Geometry Shader Functions) The function EmitStreamVertex() specifies that a vertex is completed. A vertex is added to the current output primitive in vertex stream using the current values of all output variables associated with . These include gl_PointSize, gl_ClipDistance, gl_Layer, gl_Position, gl_PrimitiveID, gl_ViewportIndex, and gl_ViewportMask[]. The values of all output variables for all output streams are undefined after a call to EmitStreamVertex(). Errors None. Interactions with OpenGL ES 3.1 Unless functionality similar to ARB_provoking_vertex is supported, remove references to PROVOKING_VERTEX and ProvokingVertex(). Also remove reference to 'vertex color clamping'. The modifications to Line Stippling don't apply. Interactions with EXT_tessellation_shader If implemented on OpenGL ES and EXT_tessellation_shader is not supported, remove all language referring to the tesselation control and tessellation evaluation pipeline stages. Interactions with NV_geometry_shader_passthrough If NV_geometry_shader_passthrough is supported, the NV_gpu_program4 and NV_geometry_program4 language describing the PASSTHROUGH declaration statement should be modified to state that "result.viewportmask" may not be used in such a declaration. Interactions with NV_gpu_program4 If NV_gpu_program4 is supported and the "NV_viewport_array2" program option is specified, vertex, tessellation control/evaluation, and geometry program result variable "result.viewportmask" can be used to specify the mask of viewports that the primitive will be emitted to, "result.viewport" can be used to specify the index of the viewport that the primitive will be emitted to, and "result.layer" can be used to specify the layer of a layered framebuffer attachment that the primitive will be emitted to. (add the following rule to the NV_gpu_program4 grammar) ::= ... | "viewportmask" arrayMemAbs | "viewport" | "layer" (add the following to the tables of Vertex, Geometry, and Tessellation Control/Eval Program Result Variable Bindings) Binding Components Description ----------------------------- ---------- ---------------------------- result.viewportmask[] (v,*,*,*) viewport array mask result.viewport (v,*,*,*) viewport array index result.layer (l,*,*,*) layer for cube/array/3D FBOs (add the following to Section 2.X.2, Program Grammar) If a result variable binding matches "result.viewportmask", updates to the "x" component of the result variable provide a single integer that serves as a mask of viewport indices. The mask must be written as an integer value; writing a floating-point value will produce undefined results. If the value has bits greater than or equal to MAX_VIEWPORTS set, the number of viewports the primitive is emitted to and which viewports are used are undefined. If the "NV_viewport_array2" program option is not specified, the "result.viewportmask" binding is unavailable. If both "result.viewport" and "result.viewportmask" are written, compilation will fail. (add the following to Section 2.X.6.Y, Program Options) + Viewport Mask (NV_viewport_array2) If a vertex, geometry, tessellation control, or tessellation evaluation program specifies the "NV_viewport_array2" option, the result binding "result.viewportmask" will be available to specify the mask of viewports to use for primitive viewport transformations and scissoring as described in section 2.X.2. Additionally, the "result.viewport" and "result.layer" result bindings will be available in these same shader stages. If a program specifies the "NV_layer_viewport_relative" option, the result.layer will have the viewport index automatically added to it. If the result.viewportmask is used, the result.layer will be different for each viewport the primitive is emitted to. Issues (1) Where does the viewport mask broadcast occur? RESOLVED: This operation could potentially be performed before or after transform feedback, but feeding back several viewports worth of primitives doesn't seem particularly useful. This specification applies the viewport mask after transform feedback, and makes primitive queries only count each primitive once. Note that it is possible to capture viewport mask shader outputs when transform feedback is active. (2) How does the gl_ViewportIndex fragment input behave? RESOLVED: Whether viewport mask or viewport indices are used in VTG shaders, the fragment shader input gl_ViewportIndex will contain the viewport number for the primitive generating each fragment. If the viewport mask is used to broadcast a single primitive to multiple viewports, and the same pixel is covered by the primitive in each viewport, multiple fragment shader invocations for that pixel will be generated, each with a different value of gl_ViewportIndex. This extension provides no gl_ViewportMask[] input, so a fragment shader is not able to see the original viewport mask for the primitive generating the fragment. If necessary, this value could be passed by a separate shader variable qualified with "flat". (3) How does the viewport mask interact with line stipple? RESOLVED: With viewport mask, it's possible to broadcast line strips to multiple viewports. If line stipple is enabled in the OpenGL compatibility profile, implementations are required to maintain a continuous stipple pattern across the strip. When primitives are broadcast via viewport mask, implementations will not always be able to buffer an entire strip and send it to each viewport in turn. So it will often be necessary to break up a long strip, and send segments to alternating viewports. An implementation could handle this by breaking up the strip and keeping N independent stipple counters, but that seems like overkill. We relax normal spec requirements and require a continuous stipple pattern only if the entire strip if sent to exactly one viewport. If any segment in the strip is sent to multiple viewports, no viewports, or a different viewport than previous segments, the stipple counter for that segment and subsequent segments in the strip is undefined. (4) Can a viewport index or mask written by vertex or tessellation shader be read by downstream tessellation or geometry shaders? RESOLVED: No. The fragment shader is able to read the viewport index, but this extension provides no built-in input allowing VTG shaders to see a viewport index or mask written by a previous shader stage. (5) Can this extension be used to "kill" primitives in a passthrough geometry shader (NV_geometry_shader_passthrough)? RESOLVED: Yes. In regular geometry shaders, input primitives can be killed by returning without emitting any vertices. That's not possible with passthrough geometry shaders, however it is possible to code a passthrough geometry shader like: void main() { if (shouldKillPrimitive()) { // Set the viewport mask to zero. A primitive will still be // emitted from the geometry shader stage, however it will be sent // to no viewports and thus be discarded. Any other per-primitive // outputs will be undefined. gl_ViewportMask[0] = 0; return; } // Since the shader writes the viewport mask in the "kill" path, it // also needs to write it in the non-"kill" path; otherwise, its // value would be undefined and the primitive will be sent to an // undefined set of viewports. Setting the mask to 1 will always // send a primitive to viewport zero. gl_ViewportMask[0] = 1; ... } Without the viewport mask or a similar feature, it is not possible to kill primitives in a passthrough geometry shader. Revision History Revision 2, 2015/03/27 - Add ES interactions Revision 1 - Internal revisions.