25. Fixed-Function Vertex Post-Processing
After programmable vertex processing, the following fixed-function operations are applied to vertices of the resulting primitives:
-
Transform feedback (see Transform Feedback)
-
Viewport swizzle (see Viewport Swizzle)
-
Flat shading (see Flat Shading).
-
Primitive clipping, including client-defined half-spaces (see Primitive Clipping).
-
Shader output attribute clipping (see Clipping Shader Outputs).
-
Clip space W scaling (see Controlling Viewport W Scaling).
-
Perspective division on clip coordinates (see Coordinate Transformations).
-
Viewport mapping, including depth range scaling (see Controlling the Viewport).
-
Front face determination for polygon primitives (see Basic Polygon Rasterization).
editing-note
TODO:Odd that this one link to a different chapter is in this list. |
Next, rasterization is performed on primitives as described in chapter Rasterization.
25.1. Transform Feedback
Before any other fixed-function vertex post-processing, vertex outputs from
the last shader in the vertex processing stage can be written out to one or
more transform feedback buffers bound to the command buffer.
To capture vertex outputs the last vertex processing stage shader must be
declared with the Xfb
execution mode.
Outputs decorated with XfbBuffer
will be written out to the
corresponding transform feedback buffers bound to the command buffer when
transform feedback is active.
Transform feedback buffers are bound to the command buffer by using
vkCmdBindTransformFeedbackBuffersEXT.
Transform feedback is made active by calling
vkCmdBeginTransformFeedbackEXT and made inactive by calling
vkCmdEndTransformFeedbackEXT.
After vertex data is written it is possible to use
vkCmdDrawIndirectByteCountEXT to start a new draw where the
vertexCount
is derived from the number of bytes written by a previous
transform feedback.
When an individual point, line, or triangle primitive reaches the transform
feedback stage while transform feedback is active, the values of the
specified output variables are assembled into primitives and appended to the
bound transform feedback buffers.
After activating transform feedback, the values of the first assembled
primitive are written at the starting offsets of the bound transform
feedback buffers, and subsequent primitives are appended to the buffer.
If the optional pCounterBuffers
and pCounterBufferOffsets
parameters are specified, the starting points within the transform feedback
buffers are adjusted so data is appended to the previously written values
indicated by the value stored by the implementation in the counter buffer.
For multi-vertex primitives, all values for a given vertex are written before writing values for any other vertex. Implementations may write out any vertex within the primitive first, but all subsequent vertices for that primitive must be written out in a consistent winding order defined as follows:
-
If neither geometry or tessellation shading is active, vertices within a primitive are appended according to the winding order described by the primitive topology defined by the VkPipelineInputAssemblyStateCreateInfo:
topology
used to execute the drawing command. -
If geometry shading is active, vertices within a primitive are appended according to the winding order described by the primitive topology defined by the
OutputPoints
,OutputLineStrips
, orOutputTriangleStrips
execution mode. -
If tessellation shading is active but geometry shading is not, vertices within a primitive are appended according to the winding order defined by triangle tessellation, quad tessellation, and isoline tessellation.
When capturing vertices, the stride associated with each transform feedback
buffer, as indicated by the XfbStride
decoration, indicates the number
of bytes of storage reserved for each vertex in the transform feedback
buffer.
For every vertex captured, each output attribute with a Offset
decoration will be written to the storage reserved for the vertex at the
associated transform feedback buffer.
When writing output variables that are arrays or structures, individual
array elements or structure members are written tightly packed in order.
For vector types, individual components are written in order.
For matrix types, outputs are written as an array of column vectors.
If any component of an output with an assigned transform feedback offset was not written to by its shader, the value recorded for that component is undefined. All components of an output variable must be written at an offset aligned to the size of the component. The size of each component of an output variable must be at least 32-bits. When capturing a vertex, any portion of the reserved storage not associated with an output variable with an assigned transform feedback offset will be unmodified.
When transform feedback is inactive, no vertices are recorded.
If there is a valid counter buffer handle and counter buffer offset in the
pCounterBuffers
and pCounterBufferOffsets
arrays, writes to the
corresponding transform feedback buffer will start at the byte offset
represented by the value stored in the counter buffer location.
Individual lines or triangles of a strip or fan primitive will be extracted and recorded separately. Incomplete primitives are not recorded.
When using a geometry shader that emits vertices to multiple vertex streams, a primitive will be assembled and output for each stream when there are enough vertices emitted for the output primitive type. All outputs assigned to a given transform feedback buffer are required to come from a single vertex stream.
The sizes of the transform feedback buffers are defined by the
vkCmdBindTransformFeedbackBuffersEXT pSizes
parameter for each
of the bound buffers, or the size of the bound buffer, whichever is the
lesser.
If there is less space remaining in any of the transform feedback buffers
than the size of the all the vertex data for that primitive based on the
XfbStride
for that XfbBuffer
then no vertex data of that primitive
is recorded in any transform feedback buffer, and the value for the number
of primitives written in the corresponding
VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT
query for all transform
feedback buffers is no longer incremented.
Any outputs made to a XfbBuffer
that is not bound to a transform
feedback buffer is ignored.
To bind transform feedback buffers to a command buffer for use in subsequent draw commands, call:
// Provided by VK_EXT_transform_feedback
void vkCmdBindTransformFeedbackBuffersEXT(
VkCommandBuffer commandBuffer,
uint32_t firstBinding,
uint32_t bindingCount,
const VkBuffer* pBuffers,
const VkDeviceSize* pOffsets,
const VkDeviceSize* pSizes);
-
commandBuffer
is the command buffer into which the command is recorded. -
firstBinding
is the index of the first transform feedback binding whose state is updated by the command. -
bindingCount
is the number of transform feedback bindings whose state is updated by the command. -
pBuffers
is a pointer to an array of buffer handles. -
pOffsets
is a pointer to an array of buffer offsets. -
pSizes
is an optional array of buffer sizes, specifying the maximum number of bytes to capture to the corresponding transform feedback buffer. IfpSizes
isNULL
, or the value of thepSizes
array element isVK_WHOLE_SIZE
, then the maximum bytes captured will be the size of the corresponding buffer minus the buffer offset.
The values taken from elements i of pBuffers
, pOffsets
and
pSizes
replace the current state for the transform feedback binding
firstBinding
+ i, for i in [0,
bindingCount
).
The transform feedback binding is updated to start at the offset indicated
by pOffsets
[i] from the start of the buffer pBuffers
[i].
Transform feedback for specific transform feedback buffers is made active by calling:
// Provided by VK_EXT_transform_feedback
void vkCmdBeginTransformFeedbackEXT(
VkCommandBuffer commandBuffer,
uint32_t firstCounterBuffer,
uint32_t counterBufferCount,
const VkBuffer* pCounterBuffers,
const VkDeviceSize* pCounterBufferOffsets);
-
commandBuffer
is the command buffer into which the command is recorded. -
firstCounterBuffer
is the index of the first transform feedback buffer corresponding topCounterBuffers
[0] andpCounterBufferOffsets
[0]. -
counterBufferCount
is the size of thepCounterBuffers
andpCounterBufferOffsets
arrays. -
pCounterBuffers
is an optional array of buffer handles to the counter buffers which contain a 4 byte integer value representing the byte offset from the start of the corresponding transform feedback buffer from where to start capturing vertex data. If the byte offset stored to the counter buffer location was done using vkCmdEndTransformFeedbackEXT it can be used to resume transform feedback from the previous location. IfpCounterBuffers
isNULL
, then transform feedback will start capturing vertex data to byte offset zero in all bound transform feedback buffers. For each element ofpCounterBuffers
that is VK_NULL_HANDLE, transform feedback will start capturing vertex data to byte zero in the corresponding bound transform feedback buffer. -
pCounterBufferOffsets
is an optional array of offsets within each of thepCounterBuffers
where the counter values were previously written. The location in each counter buffer at these offsets must be large enough to contain 4 bytes of data. This data is the number of bytes captured by the previous transform feedback to this buffer. IfpCounterBufferOffsets
isNULL
, then it is assumed the offsets are zero.
The active transform feedback buffers will capture primitives emitted from
the corresponding XfbBuffer
in the bound graphics pipeline.
Any XfbBuffer
emitted that does not output to an active transform
feedback buffer will not be captured.
Transform feedback for specific transform feedback buffers is made inactive by calling:
// Provided by VK_EXT_transform_feedback
void vkCmdEndTransformFeedbackEXT(
VkCommandBuffer commandBuffer,
uint32_t firstCounterBuffer,
uint32_t counterBufferCount,
const VkBuffer* pCounterBuffers,
const VkDeviceSize* pCounterBufferOffsets);
-
commandBuffer
is the command buffer into which the command is recorded. -
firstCounterBuffer
is the index of the first transform feedback buffer corresponding topCounterBuffers
[0] andpCounterBufferOffsets
[0]. -
counterBufferCount
is the size of thepCounterBuffers
andpCounterBufferOffsets
arrays. -
pCounterBuffers
is an optional array of buffer handles to the counter buffers used to record the current byte positions of each transform feedback buffer where the next vertex output data would be captured. This can be used by a subsequent vkCmdBeginTransformFeedbackEXT call to resume transform feedback capture from this position. It can also be used by vkCmdDrawIndirectByteCountEXT to determine the vertex count of the draw call. -
pCounterBufferOffsets
is an optional array of offsets within each of thepCounterBuffers
where the counter values can be written. The location in each counter buffer at these offsets must be large enough to contain 4 bytes of data. The data stored at this location is the byte offset from the start of the transform feedback buffer binding where the next vertex data would be written. IfpCounterBufferOffsets
isNULL
, then it is assumed the offsets are zero.
25.2. Viewport Swizzle
Each primitive sent to a given viewport has a swizzle and optional negation
applied to its clip coordinates.
The swizzle that is applied depends on the viewport index, and is controlled
by the VkPipelineViewportSwizzleStateCreateInfoNV
pipeline state:
// Provided by VK_NV_viewport_swizzle
typedef struct VkPipelineViewportSwizzleStateCreateInfoNV {
VkStructureType sType;
const void* pNext;
VkPipelineViewportSwizzleStateCreateFlagsNV flags;
uint32_t viewportCount;
const VkViewportSwizzleNV* pViewportSwizzles;
} VkPipelineViewportSwizzleStateCreateInfoNV;
-
sType
is the type of this structure. -
pNext
isNULL
or a pointer to a structure extending this structure. -
flags
is reserved for future use. -
viewportCount
is the number of viewport swizzles used by the pipeline. -
pViewportSwizzles
is a pointer to an array of VkViewportSwizzleNV structures, defining the viewport swizzles.
// Provided by VK_NV_viewport_swizzle
typedef VkFlags VkPipelineViewportSwizzleStateCreateFlagsNV;
VkPipelineViewportSwizzleStateCreateFlagsNV
is a bitmask type for
setting a mask, but is currently reserved for future use.
The VkPipelineViewportSwizzleStateCreateInfoNV
state is set by adding
this structure to the pNext
chain of a
VkPipelineViewportStateCreateInfo
structure and setting the graphics
pipeline state with vkCreateGraphicsPipelines.
Each viewport specified from 0 to viewportCount
- 1 has its x,y,z,w
swizzle state set to the corresponding x
, y
, z
and w
in the VkViewportSwizzleNV structure.
Each component is of type VkViewportCoordinateSwizzleNV, which
determines the type of swizzle for that component.
The value of x
computes the new x component of the position as:
if (x == VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_X_NV) x' = x;
if (x == VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_X_NV) x' = -x;
if (x == VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_Y_NV) x' = y;
if (x == VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_Y_NV) x' = -y;
if (x == VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_Z_NV) x' = z;
if (x == VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_Z_NV) x' = -z;
if (x == VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_W_NV) x' = w;
if (x == VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_W_NV) x' = -w;
Similar selections are performed for the y
, z
, and w
coordinates.
This swizzling is applied before clipping and perspective divide.
If the swizzle for an active viewport index is not specified, the swizzle
for x
is VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_X_NV
, y
is VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_Y_NV
, z
is
VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_Z_NV
and w
is
VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_W_NV
.
Viewport swizzle parameters are specified by setting the pNext
pointer
of VkGraphicsPipelineCreateInfo
to point to a
VkPipelineViewportSwizzleStateCreateInfoNV
structure.
VkPipelineViewportSwizzleStateCreateInfoNV uses
VkViewportSwizzleNV
to set the viewport swizzle parameters.
The VkViewportSwizzleNV
structure is defined as:
// Provided by VK_NV_viewport_swizzle
typedef struct VkViewportSwizzleNV {
VkViewportCoordinateSwizzleNV x;
VkViewportCoordinateSwizzleNV y;
VkViewportCoordinateSwizzleNV z;
VkViewportCoordinateSwizzleNV w;
} VkViewportSwizzleNV;
-
x
is a VkViewportCoordinateSwizzleNV value specifying the swizzle operation to apply to the x component of the primitive -
y
is a VkViewportCoordinateSwizzleNV value specifying the swizzle operation to apply to the y component of the primitive -
z
is a VkViewportCoordinateSwizzleNV value specifying the swizzle operation to apply to the z component of the primitive -
w
is a VkViewportCoordinateSwizzleNV value specifying the swizzle operation to apply to the w component of the primitive
Possible values of the VkViewportSwizzleNV::x
, y
, z
,
and w
members, specifying swizzling of the corresponding components of
primitives, are:
// Provided by VK_NV_viewport_swizzle
typedef enum VkViewportCoordinateSwizzleNV {
VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_X_NV = 0,
VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_X_NV = 1,
VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_Y_NV = 2,
VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_Y_NV = 3,
VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_Z_NV = 4,
VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_Z_NV = 5,
VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_W_NV = 6,
VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_W_NV = 7,
} VkViewportCoordinateSwizzleNV;
These values are described in detail in Viewport Swizzle.
25.3. Flat Shading
Flat shading a vertex output attribute means to assign all vertices of the
primitive the same value for that output.
The output values assigned are those of the provoking vertex of the
primitive.
Flat shading is applied to those vertex attributes that
match fragment input attributes which
are decorated as Flat
.
If neither geometry nor tessellation shading
is active, the provoking vertex is determined by the
primitive topology defined by
VkPipelineInputAssemblyStateCreateInfo:topology
used to execute
the drawing command.
If geometry shading is active, the provoking vertex is
determined by the primitive topology
defined by the OutputPoints
,
OutputLineStrips
, or
OutputTriangleStrips
execution mode.
If tessellation shading is active but geometry shading is not, the provoking vertex may be any of the vertices in each primitive.
25.4. Primitive Clipping
Primitives are culled against the cull volume and then clipped to the clip volume. In clip coordinates, the view volume is defined by:
This view volume can be further restricted by as many as
VkPhysicalDeviceLimits
::maxClipDistances
client-defined
half-spaces.
The cull volume is the intersection of up to
VkPhysicalDeviceLimits
::maxCullDistances
client-defined
half-spaces (if no client-defined cull half-spaces are enabled, culling
against the cull volume is skipped).
A shader must write a single cull distance for each enabled cull half-space
to elements of the CullDistance
array.
If the cull distance for any enabled cull half-space is negative for all of
the vertices of the primitive under consideration, the primitive is
discarded.
Otherwise the primitive is clipped against the clip volume as defined below.
The clip volume is the intersection of up to
VkPhysicalDeviceLimits
::maxClipDistances
client-defined
half-spaces with the view volume (if no client-defined clip half-spaces are
enabled, the clip volume is the view volume).
A shader must write a single clip distance for each enabled clip half-space
to elements of the ClipDistance
array.
Clip half-space i is then given by the set of points satisfying the
inequality
-
ci(P) ≥ 0
where ci(P) is the clip distance i at point P. For point primitives, ci(P) is simply the clip distance for the vertex in question. For line and triangle primitives, per-vertex clip distances are interpolated using a weighted mean, with weights derived according to the algorithms described in sections Basic Line Segment Rasterization and Basic Polygon Rasterization, using the perspective interpolation equations.
The number of client-defined clip and cull half-spaces that are enabled is
determined by the explicit size of the built-in arrays ClipDistance
and
CullDistance
, respectively, declared as an output in the interface of
the entry point of the final shader stage before clipping.
If VkPipelineRasterizationDepthClipStateCreateInfoEXT is present in
the graphics pipeline state then depth clipping is disabled if
VkPipelineRasterizationDepthClipStateCreateInfoEXT::depthClipEnable
is VK_FALSE
.
Otherwise, if VkPipelineRasterizationDepthClipStateCreateInfoEXT is
not present, depth clipping is disabled when
VkPipelineRasterizationStateCreateInfo::depthClampEnable
is
VK_TRUE
.
When depth clipping is disabled, the plane equation
-
0 ≤ zc ≤ wc
(see the clip volume definition above) is ignored by view volume clipping (effectively, there is no near or far plane clipping).
If the primitive under consideration is a point or line segment, then clipping passes it unchanged if its vertices lie entirely within the clip volume.
Possible values of
VkPhysicalDevicePointClippingProperties::pointClippingBehavior
,
specifying clipping behavior of a point primitive whose vertex lies outside
the clip volume, are:
// Provided by VK_VERSION_1_1
typedef enum VkPointClippingBehavior {
VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES = 0,
VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY = 1,
// Provided by VK_KHR_maintenance2
VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES_KHR = VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES,
// Provided by VK_KHR_maintenance2
VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY_KHR = VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY,
} VkPointClippingBehavior;
or the equivalent
// Provided by VK_KHR_maintenance2
typedef VkPointClippingBehavior VkPointClippingBehaviorKHR;
-
VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES
specifies that the primitive is discarded if the vertex lies outside any clip plane, including the planes bounding the view volume. -
VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY
specifies that the primitive is discarded only if the vertex lies outside any user clip plane.
If either of a line segment’s vertices lie outside of the clip volume, the line segment may be clipped, with new vertex coordinates computed for each vertex that lies outside the clip volume. A clipped line segment endpoint lies on both the original line segment and the boundary of the clip volume.
This clipping produces a value, 0 ≤ t ≤ 1, for each clipped vertex. If the coordinates of a clipped vertex are P and the original vertices’ coordinates are P1 and P2, then t is given by
-
P = t P1 + (1-t) P2.
editing-note
This is weird - it gives P, not t. |
t is used to clip vertex output attributes as described in Clipping Shader Outputs.
If the primitive is a polygon, it passes unchanged if every one of its edges lie entirely inside the clip volume, and it is discarded if every one of its edges lie entirely outside the clip volume. If the edges of the polygon intersect the boundary of the clip volume, the intersecting edges are reconnected by new edges that lie along the boundary of the clip volume - in some cases requiring the introduction of new vertices into a polygon.
If a polygon intersects an edge of the clip volume’s boundary, the clipped polygon must include a point on this boundary edge.
Primitives rendered with user-defined half-spaces must satisfy a complementarity criterion. Suppose a series of primitives is drawn where each vertex i has a single specified clip distance di (or a number of similarly specified clip distances, if multiple half-spaces are enabled). Next, suppose that the same series of primitives are drawn again with each such clip distance replaced by -di (and the graphics pipeline is otherwise the same). In this case, primitives must not be missing any pixels, and pixels must not be drawn twice in regions where those primitives are cut by the clip planes.
25.5. Clipping Shader Outputs
Next, vertex output attributes are clipped. The output values associated with a vertex that lies within the clip volume are unaffected by clipping. If a primitive is clipped, however, the output values assigned to vertices produced by clipping are clipped.
Let the output values assigned to the two vertices P1 and P2 of an unclipped edge be c1 and c2. The value of t (see Primitive Clipping) for a clipped point P is used to obtain the output value associated with P as
-
c = t c1 + (1-t) c2.
(Multiplying an output value by a scalar means multiplying each of x, y, z, and w by the scalar.)
Since this computation is performed in clip space before division by wc, clipped output values are perspective-correct.
Polygon clipping creates a clipped vertex along an edge of the clip volume’s boundary. This situation is handled by noting that polygon clipping proceeds by clipping against one half-space at a time. Output value clipping is done in the same way, so that clipped points always occur at the intersection of polygon edges (possibly already clipped) with the clip volume’s boundary.
For vertex output attributes whose matching fragment input attributes are
decorated with NoPerspective
, the value of t used to obtain the
output value associated with P will be adjusted to produce results
that vary linearly in framebuffer space.
Output attributes of integer or unsigned integer type must always be flat shaded. Flat shaded attributes are constant over the primitive being rasterized (see Basic Line Segment Rasterization and Basic Polygon Rasterization), and no interpolation is performed. The output value c is taken from either c1 or c2, since flat shading has already occurred and the two values are identical.
25.6. Controlling Viewport W Scaling
If viewport W scaling is enabled, the W component of the clip coordinate is modified by the provided coefficients from the corresponding viewport as follows.
-
wc' = xcoeff xc + ycoeff yc + wc
The VkPipelineViewportWScalingStateCreateInfoNV
structure is defined
as:
// Provided by VK_NV_clip_space_w_scaling
typedef struct VkPipelineViewportWScalingStateCreateInfoNV {
VkStructureType sType;
const void* pNext;
VkBool32 viewportWScalingEnable;
uint32_t viewportCount;
const VkViewportWScalingNV* pViewportWScalings;
} VkPipelineViewportWScalingStateCreateInfoNV;
-
sType
is the type of this structure. -
pNext
isNULL
or a pointer to a structure extending this structure. -
viewportWScalingEnable
controls whether viewport W scaling is enabled. -
viewportCount
is the number of viewports used by W scaling, and must match the number of viewports in the pipeline if viewport W scaling is enabled. -
pViewportWScalings
is a pointer to an array ofVkViewportWScalingNV
structures defining the W scaling parameters for the corresponding viewports. If the viewport W scaling state is dynamic, this member is ignored.
The VkPipelineViewportWScalingStateCreateInfoNV
state is set by adding
this structure to the pNext
chain of a
VkPipelineViewportStateCreateInfo
structure and setting the graphics
pipeline state with vkCreateGraphicsPipelines.
If the bound pipeline state object was not created with the
VK_DYNAMIC_STATE_VIEWPORT_W_SCALING_NV
dynamic state enabled, viewport
W scaling parameters are specified using the pViewportWScalings
member of VkPipelineViewportWScalingStateCreateInfoNV in the pipeline
state object.
If the pipeline state object was created with the
VK_DYNAMIC_STATE_VIEWPORT_W_SCALING_NV
dynamic state enabled, the
viewport transformation parameters are dynamically set and changed with the
command:
// Provided by VK_NV_clip_space_w_scaling
void vkCmdSetViewportWScalingNV(
VkCommandBuffer commandBuffer,
uint32_t firstViewport,
uint32_t viewportCount,
const VkViewportWScalingNV* pViewportWScalings);
-
commandBuffer
is the command buffer into which the command will be recorded. -
firstViewport
is the index of the first viewport whose parameters are updated by the command. -
viewportCount
is the number of viewports whose parameters are updated by the command. -
pViewportWScalings
is a pointer to an array of VkViewportWScalingNV structures specifying viewport parameters.
The viewport parameters taken from element i of
pViewportWScalings
replace the current state for the viewport index
firstViewport
+ i, for i in [0,
viewportCount
).
Both VkPipelineViewportWScalingStateCreateInfoNV and
vkCmdSetViewportWScalingNV use VkViewportWScalingNV
to set the
viewport transformation parameters.
The VkViewportWScalingNV
structure is defined as:
// Provided by VK_NV_clip_space_w_scaling
typedef struct VkViewportWScalingNV {
float xcoeff;
float ycoeff;
} VkViewportWScalingNV;
-
xcoeff
andycoeff
are the viewport’s W scaling factor for x and y respectively.
25.7. Coordinate Transformations
Clip coordinates for a vertex result from shader execution, which yields a
vertex coordinate Position
.
Perspective division on clip coordinates yields normalized device coordinates, followed by a viewport transformation (see Controlling the Viewport) to convert these coordinates into framebuffer coordinates.
If a vertex in clip coordinates has a position given by
then the vertex’s normalized device coordinates are
25.8. Render Pass Transform
A render pass transform can be enabled for render pass instances. The clip coordinates (xc, yc) that result from vertex shader execution are transformed by a rotation of 0, 90, 180, or 270 degrees in the XY plane, centered at the origin.
When Render pass transform is enabled, the transform applies to all primitives for all subpasses of the render pass. The transformed vertex in clip coordinates has a position given by
where
-
θ is 0 degrees for
VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR
-
θ is 90 degrees for
VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR
-
θ is 180 degrees for
VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR
-
θ is 270 degrees for
VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR
The transformed vertex’s normalized device coordinates are
When render pass transform is enabled for a renderpass instance, the following additional features are enabled:
-
Each VkViewport specified by either VkPipelineViewportStateCreateInfo::
pViewports
or vkCmdSetViewport will have its width/height (px, py) and its center (ox, oy) similarly transformed by the implementation. -
Each scissor specified by VkPipelineViewportStateCreateInfo::
pScissors
or vkCmdSetScissor will have its (offsetx, offsety) and (extentx, extenty) similarly transformed by the implementation. -
The
renderArea
specified in VkCommandBufferInheritanceRenderPassTransformInfoQCOM and VkRenderPassBeginInfo will be similarly transformed by the implementation. -
The (x, y) components of shader variables with built-in decorations
FragCoord
,SamplePosition
, orPointCoord
will be similarly transformed by the implementation. -
The (x,y) components of the
offset
operand of theInterpolateAtOffset
extended instruction will be similarly transformed by the implementation. -
The values returned by SPIR-V derivative instructions
OpDPdx
,OpDPdy
,OpDPdxCourse
,OpDPdyCourse
,OpDPdxFine
,OpDPdyFine
will be similarly transformed by the implementation.
The net result of the above, is that applications can act as if the
rendering to a framebuffer oriented with the
VkSurfaceCapabilitiesKHR::currentTransform
, as if the
presentation engine will performing the transformation of the swapchain
image after rendering and prior to presentation to the user.
In fact, the transformation of the various items cited above are being
handled by the implementation as the rendering takes place.
25.9. Controlling the Viewport
The viewport transformation is determined by the selected viewport’s width and height in pixels, px and py, respectively, and its center (ox, oy) (also in pixels), as well as its depth range min and max determining a depth range scale value pz and a depth range bias value oz (defined below). The vertex’s framebuffer coordinates (xf, yf, zf) are given by
-
xf = (px / 2) xd + ox
-
yf = (py / 2) yd + oy
-
zf = pz × zd + oz
Multiple viewports are available, numbered zero up to
VkPhysicalDeviceLimits
::maxViewports
minus one.
The number of viewports used by a pipeline is controlled by the
viewportCount
member of the VkPipelineViewportStateCreateInfo
structure used in pipeline creation.
The VkPipelineViewportStateCreateInfo
structure is defined as:
// Provided by VK_VERSION_1_0
typedef struct VkPipelineViewportStateCreateInfo {
VkStructureType sType;
const void* pNext;
VkPipelineViewportStateCreateFlags flags;
uint32_t viewportCount;
const VkViewport* pViewports;
uint32_t scissorCount;
const VkRect2D* pScissors;
} VkPipelineViewportStateCreateInfo;
-
sType
is the type of this structure. -
pNext
isNULL
or a pointer to a structure extending this structure. -
flags
is reserved for future use. -
viewportCount
is the number of viewports used by the pipeline. -
pViewports
is a pointer to an array of VkViewport structures, defining the viewport transforms. If the viewport state is dynamic, this member is ignored. -
scissorCount
is the number of scissors and must match the number of viewports. -
pScissors
is a pointer to an array of VkRect2D structures defining the rectangular bounds of the scissor for the corresponding viewport. If the scissor state is dynamic, this member is ignored.
If the bound graphics pipeline state was created with the
VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT_EXT
dynamic state enabled then
the viewport count and viewport transformation parameters are set
dynamically by calling:
// Provided by VK_EXT_extended_dynamic_state
void vkCmdSetViewportWithCountEXT(
VkCommandBuffer commandBuffer,
uint32_t viewportCount,
const VkViewport* pViewports);
-
commandBuffer
is the command buffer into which the command will be recorded. -
viewportCount
specifies the viewport count. -
pViewports
specifies the viewports to use for drawing.
If the bound graphics pipeline state was created with the
VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT_EXT
dynamic state enabled then the
scissor count and scissor rectangular bounds are set dynamically by calling:
// Provided by VK_EXT_extended_dynamic_state
void vkCmdSetScissorWithCountEXT(
VkCommandBuffer commandBuffer,
uint32_t scissorCount,
const VkRect2D* pScissors);
-
commandBuffer
is the command buffer into which the command will be recorded. -
scissorCount
specifies the scissor count. -
pScissors
specifies the scissors to use for drawing.
// Provided by VK_VERSION_1_0
typedef VkFlags VkPipelineViewportStateCreateFlags;
VkPipelineViewportStateCreateFlags
is a bitmask type for setting a
mask, but is currently reserved for future use.
A vertex processing stage can direct each primitive to zero or more
viewports.
The destination viewports for a primitive are selected by the last active
vertex processing stage that has an output variable decorated with
ViewportIndex
(selecting a single viewport) or ViewportMaskNV
(selecting multiple viewports).
The viewport transform uses the viewport corresponding to either the value
assigned to ViewportIndex
or one of the bits set in
ViewportMaskNV
, and taken from an implementation-dependent vertex of
each primitive.
If ViewportIndex
or any of the bits in ViewportMaskNV
are outside
the range zero to viewportCount
minus one for a primitive, or if the
last active vertex processing stage did not assign a value to either
ViewportIndex
or ViewportMaskNV
for all vertices of a primitive
due to flow control, the values resulting from the viewport transformation
of the vertices of such primitives are undefined.
If the last vertex processing stage does not have an output decorated with
ViewportIndex
or ViewportMaskNV
, the viewport numbered zero is
used by the viewport transformation.
A single vertex can be used in more than one individual primitive, in
primitives such as VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP
.
In this case, the viewport transformation is applied separately for each
primitive.
If the bound pipeline state object was not created with the
VK_DYNAMIC_STATE_VIEWPORT
dynamic state enabled, viewport
transformation parameters are specified using the pViewports
member of
VkPipelineViewportStateCreateInfo
in the pipeline state object.
If the pipeline state object was created with the
VK_DYNAMIC_STATE_VIEWPORT
dynamic state enabled, the viewport
transformation parameters are dynamically set and changed with the command:
// Provided by VK_VERSION_1_0
void vkCmdSetViewport(
VkCommandBuffer commandBuffer,
uint32_t firstViewport,
uint32_t viewportCount,
const VkViewport* pViewports);
-
commandBuffer
is the command buffer into which the command will be recorded. -
firstViewport
is the index of the first viewport whose parameters are updated by the command. -
viewportCount
is the number of viewports whose parameters are updated by the command. -
pViewports
is a pointer to an array of VkViewport structures specifying viewport parameters.
The viewport parameters taken from element i of pViewports
replace the current state for the viewport index firstViewport
+ i, for i in [0, viewportCount
).
Both VkPipelineViewportStateCreateInfo and vkCmdSetViewport use
VkViewport
to set the viewport transformation parameters.
The VkViewport
structure is defined as:
// Provided by VK_VERSION_1_0
typedef struct VkViewport {
float x;
float y;
float width;
float height;
float minDepth;
float maxDepth;
} VkViewport;
-
x
andy
are the viewport’s upper left corner (x,y). -
width
andheight
are the viewport’s width and height, respectively. -
minDepth
andmaxDepth
are the depth range for the viewport. It is valid forminDepth
to be greater than or equal tomaxDepth
.
The framebuffer depth coordinate z
f may be represented using
either a fixed-point or floating-point representation.
However, a floating-point representation must be used if the depth/stencil
attachment has a floating-point depth component.
If an m-bit fixed-point representation is used, we assume that it
represents each value , where k ∈ {
0, 1, …, 2m-1 }, as k (e.g. 1.0 is represented in binary as a
string of all ones).
The viewport parameters shown in the above equations are found from these values as
-
ox =
x
+width
/ 2 -
oy =
y
+height
/ 2 -
oz =
minDepth
-
px =
width
-
py =
height
-
pz =
maxDepth
-minDepth
.
If a render pass transform is enabled, the values (px,py) and (ox, oy) defining the viewport are transformed as described in render pass transform before participating in the viewport transform.
The application can specify a negative term for height
, which has the
effect of negating the y coordinate in clip space before performing the
transform.
When using a negative height
, the application should also adjust the
y
value to point to the lower left corner of the viewport instead of
the upper left corner.
Using the negative height
allows the application to avoid having to
negate the y component of the Position
output from the last vertex
processing stage in shaders that also target other graphics APIs.
The width and height of the implementation-dependent maximum viewport dimensions must be greater than or equal to the width and height of the largest image which can be created and attached to a framebuffer.
The floating-point viewport bounds are represented with an implementation-dependent precision.