| // Copyright 2015-2023 The Khronos Group Inc. |
| // |
| // SPDX-License-Identifier: CC-BY-4.0 |
| |
| [appendix] |
| [[invariance]] |
| = Invariance |
| |
| The Vulkan specification is not pixel exact. |
| It therefore does not guarantee an exact match between images produced by |
| different Vulkan implementations. |
| However, the specification does specify exact matches, in some cases, for |
| images produced by the same implementation. |
| The purpose of this appendix is to identify and provide justification for |
| those cases that require exact matches. |
| |
| == Repeatability |
| |
| The obvious and most fundamental case is repeated issuance of a series of |
| Vulkan commands. |
| For any given Vulkan and framebuffer state vector, and for any Vulkan |
| command, the resulting Vulkan and framebuffer state must: be identical |
| whenever the command is executed on that initial Vulkan and framebuffer |
| state. |
| This repeatability requirement does not apply when using shaders containing |
| side effects (image and buffer variable stores and atomic operations), |
| because these memory operations are not guaranteed to be processed in a |
| defined order. |
| |
| ifdef::VK_AMD_rasterization_order[] |
| The repeatability requirement does not apply for rendering done using a |
| graphics pipeline that uses ename:VK_RASTERIZATION_ORDER_RELAXED_AMD. |
| endif::VK_AMD_rasterization_order[] |
| |
| One purpose of repeatability is avoidance of visual artifacts when a |
| double-buffered scene is redrawn. |
| If rendering is not repeatable, swapping between two buffers rendered with |
| the same command sequence may: result in visible changes in the image. |
| Such false motion is distracting to the viewer. |
| Another reason for repeatability is testability. |
| |
| Repeatability, while important, is a weak requirement. |
| Given only repeatability as a requirement, two scenes rendered with one |
| (small) polygon changed in position might differ at every pixel. |
| Such a difference, while within the law of repeatability, is certainly not |
| within its spirit. |
| Additional invariance rules are desirable to ensure useful operation. |
| |
| |
| == Multi-pass Algorithms |
| |
| Invariance is necessary for a whole set of useful multi-pass algorithms. |
| Such algorithms render multiple times, each time with a different Vulkan |
| mode vector, to eventually produce a result in the framebuffer. |
| Examples of these algorithms include: |
| |
| * "`Erasing`" a primitive from the framebuffer by redrawing it, either in |
| a different color or using the XOR logical operation. |
| * Using stencil operations to compute capping planes. |
| |
| |
| == Invariance Rules |
| |
| For a given Vulkan device: |
| |
| *Rule 1* _For any given Vulkan and framebuffer state vector, and for any |
| given Vulkan command, the resulting Vulkan and framebuffer state must: be |
| identical each time the command is executed on that initial Vulkan and |
| framebuffer state._ |
| |
| *Rule 2* _Changes to the following state values have no side effects (the |
| use of any other state value is not affected by the change):_ |
| |
| *Required:* |
| |
| * _Color and depth/stencil attachment contents_ |
| * _Scissor parameters (other than enable)_ |
| * _Write masks (color, depth, stencil)_ |
| * _Clear values (color, depth, stencil)_ |
| |
| *Strongly suggested:* |
| |
| * _Stencil parameters (other than enable)_ |
| * _Depth test parameters (other than enable)_ |
| * _Blend parameters (other than enable)_ |
| * _Logical operation parameters (other than enable)_ |
| |
| *Corollary 1* _Fragment generation is invariant with respect to the state |
| values listed in Rule 2._ |
| |
| *Rule 3* _The arithmetic of each per-fragment operation is invariant except |
| with respect to parameters that directly control it._ |
| |
| *Corollary 2* _Images rendered into different color attachments of the same |
| framebuffer, either simultaneously or separately using the same command |
| sequence, are pixel identical._ |
| |
| *Rule 4* _Identical pipelines will produce the same result when run multiple |
| times with the same input. |
| The wording "`Identical pipelines`" means slink:VkPipeline objects that have |
| been created with identical SPIR-V binaries and identical state, which are |
| then used by commands executed using the same Vulkan state vector. |
| Invariance is relaxed for shaders with side effects, such as performing |
| stores or atomics._ |
| |
| *Rule 5* _All fragment shaders that either conditionally or unconditionally |
| assign_ code:FragCoord.z _to_ code:FragDepth _are depth-invariant with |
| respect to each other, for those fragments where the assignment to_ |
| code:FragDepth _actually is done._ |
| |
| If a sequence of Vulkan commands specifies primitives to be rendered with |
| shaders containing side effects (image and buffer variable stores and atomic |
| operations), invariance rules are relaxed. |
| In particular, rule 1, corollary 2, and rule 4 do not apply in the presence |
| of shader side effects. |
| |
| The following weaker versions of rules 1 and 4 apply to Vulkan commands |
| involving shader side effects: |
| |
| *Rule 6* _For any given Vulkan and framebuffer state vector, and for any |
| given Vulkan command, the contents of any framebuffer state not directly or |
| indirectly affected by results of shader image or buffer variable stores or |
| atomic operations must: be identical each time the command is executed on |
| that initial Vulkan and framebuffer state._ |
| |
| *Rule 7* _Identical pipelines will produce the same result when run multiple |
| times with the same input as long as:_ |
| |
| * _shader invocations do not use image atomic operations;_ |
| * _no framebuffer memory is written to more than once by image stores, |
| unless all such stores write the same value; and_ |
| * _no shader invocation, or other operation performed to process the |
| sequence of commands, reads memory written to by an image store._ |
| |
| |
| [NOTE] |
| .Note |
| ==== |
| The OpenGL specification has the following invariance rule: Consider a |
| primitive p' obtained by translating a primitive p through an offset (x, y) |
| in window coordinates, where x and y are integers. |
| As long as neither p' nor p is clipped, it must: be the case that each |
| fragment f' produced from p' is identical to a corresponding fragment f from |
| p except that the center of f' is offset by (x, y) from the center of f. |
| |
| This rule does not apply to Vulkan and is an intentional difference from |
| OpenGL. |
| ==== |
| |
| When any sequence of Vulkan commands triggers shader invocations that |
| perform image stores or atomic operations, and subsequent Vulkan commands |
| read the memory written by those shader invocations, these operations must: |
| be explicitly synchronized. |
| |
| |
| == Tessellation Invariance |
| |
| When using a pipeline containing tessellation evaluation shaders, the |
| fixed-function tessellation primitive generator consumes the input patch |
| specified by an application and emits a new set of primitives. |
| The following invariance rules are intended to provide repeatability |
| guarantees. |
| Additionally, they are intended to allow an application with a carefully |
| crafted tessellation evaluation shader to ensure that the sets of triangles |
| generated for two adjacent patches have identical vertices along shared |
| patch edges, avoiding "`cracks`" caused by minor differences in the |
| positions of vertices along shared edges. |
| |
| *Rule 1* _When processing two patches with identical outer and inner |
| tessellation levels, the tessellation primitive generator will emit an |
| identical set of point, line, or triangle primitives as long as the pipeline |
| used to process the patch primitives has tessellation evaluation shaders |
| specifying the same tessellation mode, spacing, vertex order, and point mode |
| decorations. |
| Two sets of primitives are considered identical if and only if they contain |
| the same number and type of primitives and the generated tessellation |
| coordinates for the vertex numbered m of the primitive numbered n are |
| identical for all values of m and n._ |
| |
| *Rule 2* _The set of vertices generated along the outer edge of the |
| subdivided primitive in triangle and quad tessellation, and the tessellation |
| coordinates of each, depend only on the corresponding outer tessellation |
| level and the spacing decorations in the tessellation shaders of the |
| pipeline._ |
| |
| *Rule 3* _The set of vertices generated when subdividing any outer primitive |
| edge is always symmetric. |
| For triangle tessellation, if the subdivision generates a vertex with |
| tessellation coordinates of the form (0, x, 1-x), (x, 0, 1-x), or (x, 1-x, |
| 0), it will also generate a vertex with coordinates of exactly (0, 1-x, x), |
| (1-x, 0, x), or (1-x, x, 0), respectively. |
| For quad tessellation, if the subdivision generates a vertex with |
| coordinates of (x, 0) or (0, x), it will also generate a vertex with |
| coordinates of exactly (1-x, 0) or (0, 1-x), respectively. |
| For isoline tessellation, if it generates vertices at (0, x) and (1, x) |
| where x is not zero, it will also generate vertices at exactly (0, 1-x) and |
| (1, 1-x), respectively._ |
| |
| *Rule 4* _The set of vertices generated when subdividing outer edges in |
| triangular and quad tessellation must: be independent of the specific edge |
| subdivided, given identical outer tessellation levels and spacing. |
| For example, if vertices at (x, 1 - x, 0) and (1-x, x, 0) are generated when |
| subdividing the w = 0 edge in triangular tessellation, vertices must: be |
| generated at (x, 0, 1-x) and (1-x, 0, x) when subdividing an otherwise |
| identical v = 0 edge. |
| For quad tessellation, if vertices at (x, 0) and (1-x, 0) are generated when |
| subdividing the v = 0 edge, vertices must: be generated at (0, x) and (0, |
| 1-x) when subdividing an otherwise identical u = 0 edge._ |
| |
| *Rule 5* _When processing two patches that are identical in all respects |
| enumerated in rule 1 except for vertex order, the set of triangles generated |
| for triangle and quad tessellation must: be identical except for vertex and |
| triangle order. |
| For each triangle n1 produced by processing the first patch, there must: be |
| a triangle n2 produced when processing the second patch each of whose |
| vertices has the same tessellation coordinates as one of the vertices in |
| n1._ |
| |
| *Rule 6* _When processing two patches that are identical in all respects |
| enumerated in rule 1 other than matching outer tessellation levels and/or |
| vertex order, the set of interior triangles generated for triangle and quad |
| tessellation must: be identical in all respects except for vertex and |
| triangle order. |
| For each interior triangle n1 produced by processing the first patch, there |
| must: be a triangle n2 produced when processing the second patch each of |
| whose vertices has the same tessellation coordinates as one of the vertices |
| in n1. |
| A triangle produced by the tessellator is considered an interior triangle if |
| none of its vertices lie on an outer edge of the subdivided primitive._ |
| |
| *Rule 7* _For quad and triangle tessellation, the set of triangles |
| connecting an inner and outer edge depends only on the inner and outer |
| tessellation levels corresponding to that edge and the spacing decorations._ |
| |
| *Rule 8* _The value of all defined components of_ code:TessCoord _will be in |
| the range [0, 1]. |
| Additionally, for any defined component x of_ code:TessCoord, _the results |
| of computing 1.0-x in a tessellation evaluation shader will be exact. |
| If any floating-point values in the range [0, 1] fail to satisfy this |
| property, such values must: not be used as tessellation coordinate |
| components._ |