• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1Name
2
3    NV_viewport_swizzle
4
5Name Strings
6
7    GL_NV_viewport_swizzle
8
9Contact
10
11    Jeff Bolz, NVIDIA Corporation (jbolz 'at' nvidia.com)
12    Pat Brown, NVIDIA Corporation (pbrown 'at' nvidia.com)
13
14Contributors
15
16    Mathias Heyer, NVIDIA
17
18Status
19
20    Shipping.
21
22Version
23
24    Last Modified Date:         April 7, 2015
25    Revision:                   1
26
27Number
28
29    OpenGL Extension #483
30    OpenGL ES Extension #258
31
32Dependencies
33
34    This extension is written against the OpenGL 4.3 specification
35    (Compatibility Profile).
36
37    This extension interacts with the OpenGL ES 3.1 (March 17, 2014)
38    specification.
39
40    This extension interacts with NV_viewport_array2.
41
42Overview
43
44    This extension provides a new per-viewport swizzle that can modify the
45    position of primitives sent to each viewport.  New viewport swizzle state
46    is added for each viewport, and a new position vector is computed for each
47    vertex by selecting from and optionally negating any of the four
48    components of the original position vector.
49
50    This new viewport swizzle is useful for a number of algorithms, including
51    single-pass cubemap rendering (broadcasting a primitive to multiple faces
52    and reorienting the vertex position for each face) and voxel
53    rasterization.  The per-viewport component remapping and negation provided
54    by the swizzle allows application code to re-orient three-dimensional
55    geometry with a view along any of the X, Y, or Z axes.  If a perspective
56    projection and depth buffering is required, 1/W buffering should be used,
57    as described in the single-pass cubemap rendering example in the "Issues"
58    section below.
59
60New Procedures and Functions
61
62    void ViewportSwizzleNV(uint index,
63                           enum swizzlex, enum swizzley,
64                           enum swizzlez, enum swizzlew);
65
66New Tokens
67
68    Accepted by the <swizzlex>, <swizzley>, <swizzlez>, and <swizzlew>
69    parameters of ViewportSwizzleNV:
70
71        VIEWPORT_SWIZZLE_POSITIVE_X_NV                  0x9350
72        VIEWPORT_SWIZZLE_NEGATIVE_X_NV                  0x9351
73        VIEWPORT_SWIZZLE_POSITIVE_Y_NV                  0x9352
74        VIEWPORT_SWIZZLE_NEGATIVE_Y_NV                  0x9353
75        VIEWPORT_SWIZZLE_POSITIVE_Z_NV                  0x9354
76        VIEWPORT_SWIZZLE_NEGATIVE_Z_NV                  0x9355
77        VIEWPORT_SWIZZLE_POSITIVE_W_NV                  0x9356
78        VIEWPORT_SWIZZLE_NEGATIVE_W_NV                  0x9357
79
80    Accepted by the <pname> parameter of GetBooleani_v, GetDoublei_v,
81    GetIntegeri_v, GetFloati_v, and GetInteger64i_v:
82
83        VIEWPORT_SWIZZLE_X_NV                           0x9358
84        VIEWPORT_SWIZZLE_Y_NV                           0x9359
85        VIEWPORT_SWIZZLE_Z_NV                           0x935A
86        VIEWPORT_SWIZZLE_W_NV                           0x935B
87
88Additions to Chapter 13 of the OpenGL 4.3 (Compatibility Profile)
89Specification (Fixed-Function Vertex Post-Processing)
90
91    Modify Section 13.2 (Transform Feedback), p. 453
92
93    Modify the first paragraph:
94
95    ...The vertices are fed back after vertex color clamping, but before
96    viewport swizzling and viewport mask expansion, flatshading, and
97    clipping. ...
98
99
100    Add a new Section 13.X (Viewport Swizzle) after 13.3 (Primitive Queries)
101
102    Each primitive sent to a given viewport has a swizzle and optional
103    negation applied to its clip coordinates.  The swizzle that is applied
104    depends on the viewport index, and is controlled by the command
105
106        void ViewportSwizzleNV(uint index,
107                               enum swizzlex, enum swizzley,
108                               enum swizzlez, enum swizzlew);
109
110    The viewport specified by <index> has its x,y,z,w swizzle state set to the
111    corresponding <swizzlex>, <swizzley>, <swizzlez>, <swizzlew> value. If the
112    value of VIEWPORT_SWIZZLE_X_NV is denoted by <swizzlex>, swizzling computes
113    the new x component of the position as
114
115        if (swizzlex == VIEWPORT_SWIZZLE_POSITIVE_X_NV) x' = x;
116        if (swizzlex == VIEWPORT_SWIZZLE_NEGATIVE_X_NV) x' = -x;
117        if (swizzlex == VIEWPORT_SWIZZLE_POSITIVE_Y_NV) x' = y;
118        if (swizzlex == VIEWPORT_SWIZZLE_NEGATIVE_Y_NV) x' = -y;
119        if (swizzlex == VIEWPORT_SWIZZLE_POSITIVE_Z_NV) x' = z;
120        if (swizzlex == VIEWPORT_SWIZZLE_NEGATIVE_Z_NV) x' = -z;
121        if (swizzlex == VIEWPORT_SWIZZLE_POSITIVE_W_NV) x' = w;
122        if (swizzlex == VIEWPORT_SWIZZLE_NEGATIVE_W_NV) x' = -w;
123
124    Similar selections are performed for the y, z, and w coordinates. This
125    swizzling is applied after transform feedback, but before clipping and
126    perspective divide.
127
128    Errors:
129
130    - The error INVALID_VALUE is generated if <index> is greater than or equal
131      to the value of MAX_VIEWPORTS.
132
133    - The error INVALID_ENUM is generated if any of <swizzlex>, <swizzley>,
134      <swizzlez>, or <swizzlew> are not one of
135      VIEWPORT_SWIZZLE_{POSITIVE,NEGATIVE}_{X,Y,Z,W}.
136
137
138    Modify Section 13.6.1 (Controlling the Viewport)
139
140    (modify the first paragraph, p. 470, as edited by NV_viewport_array2,
141    using "transformed and swizzled" instead of "transformed")
142
143    Multiple viewports are available ... The primitive is transformed and
144    swizzled using the state of the selected viewport. ...
145
146    ... If bit <i> is set in the mask, the primitive is emitted to viewport
147    <i> and transformed and swizzled using the state of viewport <i>. ...
148
149
150New Implementation Dependent State
151
152    None.
153
154New State
155
156    Get Value                       Get Command    Type    Initial Value        Description                 Sec.    Attribute
157    ---------                       -----------    ----    -------------        -----------                 ----    ---------
158    VIEWPORT_SWIZZLE_X_NV           GetIntegeri_v  nxZ8    VIEWPORT_SWIZZLE-    coordinate and sign for     13.X    viewport
159                                                           POSITIVE_X           viewport swizzling
160    VIEWPORT_SWIZZLE_Y_NV           GetIntegeri_v  nxZ8    VIEWPORT_SWIZZLE-    coordinate and sign for     13.X    viewport
161                                                           POSITIVE_Y           viewport swizzling
162    VIEWPORT_SWIZZLE_Z_NV           GetIntegeri_v  nxZ8    VIEWPORT_SWIZZLE-    coordinate and sign for     13.X    viewport
163                                                           POSITIVE_Z           viewport swizzling
164    VIEWPORT_SWIZZLE_W_NV           GetIntegeri_v  nxZ8    VIEWPORT_SWIZZLE-    coordinate and sign for     13.X    viewport
165                                                           POSITIVE_W           viewport swizzling
166
167Additions to the AGL/GLX/WGL Specifications
168
169    None.
170
171GLX Protocol
172
173    None.
174
175Errors
176
177    The error INVALID_VALUE is generated by ViewportSwizzleNV if <index> is
178    greater than or equal to the value of MAX_VIEWPORTS.
179
180    The error INVALID_ENUM is generated by ViewportSwizzleNV if any of
181    <swizzlex>, <swizzley>, <swizzlez>, or <swizzlew> are not one of
182    VIEWPORT_SWIZZLE_{POSITIVE,NEGATIVE}_{X,Y,Z,W}.
183
184Interactions with OpenGL ES 3.1
185
186    Remove references to GetDoublei_v and GetBooleani_v.  Also remove the
187    reference to 'vertex color clamping'.
188
189Interactions with NV_viewport_array2
190
191    This specification modifies language added/changed by NV_viewport_array2.
192    There are no functional interactions between the two extensions, though we
193    expect that all implementations of this extension will support
194    NV_viewport_array2 or similar functionality.
195
196Issues
197
198    (1) Where does viewport swizzling occur in the pipeline?
199
200    RESOLVED: Despite being associated with the viewport, viewport swizzling
201    must happen prior to the viewport transform.  In particular, it needs to
202    be performed before clipping and perspective division.
203
204    The viewport mask expansion (NV_viewport_array2) and the viewport swizzle
205    could potentially be performed before or after transform feedback, but
206    feeding back several viewports worth of primitives with different swizzles
207    doesn't seem particularly useful.  This specification applies the viewport
208    mask and swizzle after transform feedback, and makes primitive queries
209    only count each primitive once.
210
211    (2) Any interesting examples of how this extension, NV_viewport_array2,
212    and NV_geometry_shader_passthrough can be used together in practice?
213
214    RESOLVED:  One interesting use case for this extension is for single-pass
215    rendering to a cubemap.  In this example, the application would attach a
216    cubemap texture to a layered FBO where the six cube faces are treated as
217    layers.  Vertices are sent through the vertex shader without applying a
218    projection matrix, where the gl_Position output is (x,y,z,1) and the
219    center of the cubemap is at (0,0,0).  With unextended OpenGL, one could
220    have a conventional instanced geometry shader that looks something like
221    the following:
222
223      layout(invocations = 6) in;     // separate invocation per face
224      layout(triangles) in;
225      layout(triangle_strip) out;
226      layout(max_vertices = 3) out;
227
228      in Inputs {
229        vec2 texcoord;
230        vec3 normal;
231        vec4 baseColor;
232      } v[];
233
234      out Outputs {
235        vec2 texcoord;
236        vec3 normal;
237        vec4 baseColor;
238      };
239
240      void main()
241      {
242        int face = gl_InvocationID;  // which face am I?
243
244        // Project gl_Position for each vertex onto the cube map face.
245        vec4 positions[3];
246        for (int i = 0; i < 3; i++) {
247          positions[i] = rotate(gl_in[i].gl_Position, face);
248        }
249
250        // If the primitive doesn't project onto this face, we're done.
251        if (shouldCull(positions)) {
252          return;
253        }
254
255        // Otherwise, emit a copy of the input primitive to the
256        // appropriate face (using gl_Layer).
257        for (int i = 0; i < 3; i++) {
258          gl_Layer = face;
259          gl_Position = positions[i];
260          texcoord = v[i].texcoord;
261          normal = v[i].normal;
262          baseColor = v[i].baseColor;
263          EmitVertex();
264        }
265      }
266
267    With passthrough geometry shaders, this can be done using a much simpler
268    shader:
269
270      layout(triangles) in;
271      layout(passthrough) in Inputs {
272        vec2 texcoord;
273        vec3 normal;
274        vec4 baseColor;
275      }
276      layout(passthrough) in gl_PerVertex {
277        vec4 gl_Position;
278      } gl_in[];
279      layout(viewport_relative) out int gl_Layer;
280
281      void main()
282      {
283        // Figure out which faces the primitive projects onto and
284        // generate a corresponding viewport mask.
285        uint mask = 0;
286        for (int i = 0; i < 6; i++) {
287          if (!shouldCull(face)) {
288            mask |= 1U << i;
289          }
290        }
291        gl_ViewportMask = mask;
292        gl_Layer = 0;
293      }
294
295    The application code is set up so that each of the six cube faces has a
296    separate viewport (numbered 0..5).  Each face also has a separate swizzle,
297    programmed via the ViewportSwizzleNV() command.  The viewport swizzle
298    feature performs the coordinate transformation handled by the rotate()
299    function in the original shader.  The "viewport_relative" layout qualifier
300    says that the viewport number (0..5) is added to the base gl_Layer value
301    of zero to determine which layer (cube face) the primitive should be sent
302    to.
303
304    Note that the use of the passed through input <normal> in this example
305    suggests that the fragment shader in this example would perform an
306    operation like per-fragment lighting.  The viewport swizzle would
307    transform the position to be face-relative, but <normal> would remain in
308    the original coordinate system.  It seems likely that the fragment shader
309    in either version of the example would want to perform lighting in the
310    original coordinate system.  It would likely do this by reconstructing the
311    position of the fragment in the original coordinate system using
312    gl_FragCoord, a constant or uniform holding the size of the cube face, and
313    the input gl_ViewportIndex (or gl_Layer), which identifies the cube face.
314    Since the value of <normal> is in the original coordinate system, it would
315    not need to be modified as part of this coordinate transformation.
316
317    Note that while the rotate() operation in the regular geometry shader
318    above could include an arbitrary post-rotation projection matrix, the
319    viewport swizzle does not support arbitrary math.  To get proper
320    projection, 1/W buffering should be used.  To do this:
321
322      (1) Program the viewport swizzles to move the pre-projection W eye
323      coordinate (typically 1.0) into the Z coordinate of the swizzle output
324      and the eye coordinate component used for depth into the W coordinate.
325      For example, the viewport corresponding to the +Z face might use a
326      swizzle of (+X, -Y, +W, +Z).  The Z normalized device coordinate
327      computed after swizzling would then be z'/w' = 1/Z_eye.
328
329      (2a) On NVIDIA implementations supporting floating-point depth buffers
330      with values outside [0,1], prevent unwanted near plane clipping by
331      enabling DEPTH_CLAMP.  Ensure that the depth clamp doesn't mess up depth
332      testing by programming the depth range to very large values, such as
333      glDepthRangedNV(-z, +z), where z == 2^127.  It should be possible to use
334      IEEE infinity encodings also (0xFF800000 for -INF, 0x7F800000 for +INF).
335      Even when near/far clipping is disabled, primitives extending behind the
336      eye will still be clipped because one or more vertices will have a
337      negative W coordinate and fail X/Y clipping tests.
338
339      (2b) On other implementations, scale X, Y, and Z eye coordinates so that
340      vertices on the near plane have a post-swizzle W coordinate of 1.0.  For
341      example, if the near plane is at Z_eye = 1/256, scale X, Y, and Z by
342      256.  Also, ideally, program the depth range transformation to be a NOP
343      by using a clip control depth mode (OpenGL 4.5) of ZERO_TO_ONE.
344
345      (3) Adjust depth testing to reflect the fact that 1/W values are large
346      near the eye and small away from the eye.  Clear the depth buffer to
347      zero (infinitely far away) and use a depth test of GREATER instead of
348      LESS.
349
350Revision History
351
352    Revision 1
353    - Internal revisions.
354