When a Vulkan application tries to access (load, store, or perform an atomic on) memory it doesn’t have access to, the implementation must react somehow. In the case where there is no robustness, it is undefined behavior and the implementation is even allowed to terminate the program. If robustness is enabled for the type of memory accessed, then the implementation must behave a certain way as defined by the spec.
The nature of some Vulkan applications requires the ability run shader code that cannot be guaranteed to avoid bad memory accesses. Robustness is needed for these applications.
Note
|
Important
Turning on robustness may incur a runtime performance cost. Application writers should carefully consider the implications of enabling robustness. |
All Vulkan implementations are required to support the robustBufferAccess
feature. The spec describes what is considered out-of-bounds and also how it should be handled. Implementations are given some amount of flexibility for robustBufferAccess
. An example would be accessing a vec4(x,y,z,w)
where the w
value is out-of-bounds as the spec allows the implementation to decide if the x
, y
, and z
are also considered out-of-bounds or not.
If dealing with the update after bind functionality found in VK_EXT_descriptor_indexing
(which is core as of Vulkan 1.2) it is important to be aware of the robustBufferAccessUpdateAfterBind which indicates if an implementation can support both robustBufferAccess
and the ability to update the descriptor after binding it.
The robustBufferAccess
feature has some limitations as it only covers buffers and not images. It also allows out-of-bounds writes and atomics to modify the data of the buffer being accessed. For applications looking for a stronger form of robustness, there is VK_EXT_robustness2.
When images are out-of-bounds core Vulkan provides the guarantee that stores and atomics have no effect on the memory being accessed.
The robustImageAccess feature in VK_EXT_image_robustness enables out-of-bounds checking against the dimensions of the image view being accessed. If there is an out-of-bounds access to any image it will return (0, 0, 0, 0)
or (0, 0, 0, 1)
.
The robustImageAccess
feature provides no guarantees about the values returned for access to an invalid LOD, it is still undefined behavior.
Some applications, such as those being ported from other APIs such as D3D12, require stricter guarantees than robustBufferAccess
and robustImageAccess
provide. The VK_EXT_robustness2 extension adds this by exposing 3 new robustness features, described in the following sections. For some implementations these extra guarantees can come at a performance cost. Applications that don’t need the extra robustness are recommended to use robustBufferAccess
and/or robustImageAccess
instead where possible.
The robustBufferAccess2 feature can be seen as a superset of robustBufferAccess
.
With the feature enabled, it prevents all out-of-bounds writes and atomic from modifying any memory backing buffers. The robustBufferAccess2
feature also enforces the values that must be returned for the various types of buffers when accessed out-of-bounds as described in the spec.
It is important to query the robustUniformBufferAccessSizeAlignment
and robustStorageBufferAccessSizeAlignment
from VkPhysicalDeviceRobustness2PropertiesEXT as the alignment of where buffers are bound-checked is different between implementations.
The robustImageAccess2 feature can be seen as a superset of robustImageAccess
. It builds on the out-of-bounds checking against the dimensions of the image view being accessed, adding stricter requirements on which values may be returned.
With robustImageAccess2
an out-of-bounds access to an R, RG, or RGB format will return (0, 0, 0, 1)
. For an RGBA format, such as VK_FORMAT_R8G8B8A8_UNORM
, it will return (0, 0, 0, 0)
.
For the case of accessing an image LOD outside the supported range, with robustImageAccess2
enabled, it will be considered out of bounds.
Without the nullDescriptor feature enabled, when updating a VkDescriptorSet
, all the resources backing it must be non-null, even if the descriptor is statically not used by the shader. This feature allows descriptors to be backed by null resources or views. Loads from a null descriptor return zero values and stores and atomics to a null descriptor are discarded.
The nullDescriptor
feature also allows accesses to vertex input bindings where vkCmdBindVertexBuffers::pBuffers
is null.
Because robustness can come at a performance cost for some implementations, the VK_EXT_pipeline_robustness extension was added to allow developers to request robustness only where needed.
At VkPipeline
creation time one or more VkPipelineRobustnessCreateInfoEXT
structures can be passed to specify the desired robustness behavior of accesses to buffer, image, and vertex input resources, either for the pipeline as a whole or on a per-pipeline-stage basis.
This extension also provides VkPhysicalDevicePipelineRobustnessPropertiesEXT
which queries the implementation for what behavior it provides as default when no robustness features are enabled.