Shader Features
There are various reasons why every part of SPIR-V was not exposed to Vulkan 1.0. Over time the Vulkan Working Group has identified use cases where it makes sense to expose a new SPIR-V feature.
Some of the following extensions were added alongside a SPIR-V extension. For example, the VK_KHR_8bit_storage
extension was created in parallel with SPV_KHR_8bit_storage
. The Vulkan extension only purpose is to allow an application to query for SPIR-V support in the implementation. The SPIR-V extension is there to define the changes made to the SPIR-V intermediate representation.
For details how to use SPIR-V extension please read the dedicated Vulkan Guide chapter.
VK_KHR_spirv_1_4
Promoted to core in Vulkan 1.2 |
This extension is designed for a Vulkan 1.1 implementations to expose the SPIR-V 1.4 feature set. Vulkan 1.1 only requires SPIR-V 1.3 and some use cases were found where an implementation might not upgrade to Vulkan 1.2, but still want to offer SPIR-V 1.4 features.
VK_KHR_8bit_storage and VK_KHR_16bit_storage
Both VK_KHR_8bit_storage
(promoted in Vulkan 1.2) and VK_KHR_16bit_storage
(promoted in Vulkan 1.1) were added to allow the ability to use small values as input or output to a SPIR-V storage object. Prior to these extensions, all UBO, SSBO, and push constants needed to consume at least 4 bytes. With this, an application can now use 8-bit or 16-bit values directly from a buffer. It is also commonly paired with the use of VK_KHR_shader_float16_int8
as this extension only deals with the storage interfaces.
The following is an example of using SPV_KHR_8bit_storage
with the GLSL extension:
#version 450
// Without 8-bit storage each block variable has to be 32-bit wide
layout (set = 0, binding = 0) readonly buffer StorageBuffer {
uint data; // 0x0000AABB
} ssbo;
void main() {
uint a = ssbo.data & 0x0000FF00;
uint b = ssbo.data & 0x000000FF;
}
With the extension
#version 450
#extension GL_EXT_shader_8bit_storage : enable
layout (set = 0, binding = 0) readonly buffer StorageBuffer {
uint8_t dataA; // 0xAA
uint8_t dataB; // 0xBB
} ssbo;
void main() {
uint a = uint(ssbo.dataA);
uint b = uint(ssbo.dataB);
}
VK_KHR_shader_float16_int8
Promoted to core in Vulkan 1.2 |
This extension allows the use of 8-bit integer types or 16-bit floating-point types for arithmetic operations. This does not allow for 8-bit integer types or 16-bit floating-point types in any shader input and output interfaces and therefore is commonly paired with the use of VK_KHR_8bit_storage
and VK_KHR_16bit_storage
.
VK_KHR_shader_float_controls
Promoted to core in Vulkan 1.2 |
This extension allows the ability to set how rounding of floats are handled. The VkPhysicalDeviceFloatControlsProperties
shows the full list of features that can be queried. This is useful when converting OpenCL kernels to Vulkan.
VK_KHR_storage_buffer_storage_class
Promoted to core in Vulkan 1.1 |
Originally SPIR-V combined both UBO and SSBO into the 'Uniform' storage classes and differentiated them only through extra decorations. Because some hardware treats UBO and SSBO as two different storage objects, the SPIR-V wanted to reflect that. This extension serves the purpose of extending SPIR-V to have a new StorageBuffer
class.
An example of this can be seen if you take the following GLSL shader snippet:
layout(set = 0, binding = 0) buffer ssbo {
int x;
};
If you target Vulkan 1.0 (which requires SPIR-V 1.0), using glslang --target-env vulkan1.0
, you will get something like:
Decorate 7(ssbo) BufferBlock
8: TypePointer Uniform 7(ssbo)
9: 8(ptr) Variable Uniform
12: TypePointer Uniform 6(int)
Since SPV_KHR_storage_buffer_storage_class
was added to SPIR-V 1.3, if you target Vulkan 1.1 (which requires SPIR-V 1.3) ,using glslang --target-env vulkan1.1
, it will make use of the new StorageBuffer
class.
Decorate 7(ssbo) Block
8: TypePointer StorageBuffer 7(ssbo)
9: 8(ptr) Variable StorageBuffer
12: TypePointer StorageBuffer 6(int)
VK_KHR_variable_pointers
Promoted to core in Vulkan 1.1 |
A Variable pointer
is defined in SPIR-V as
A pointer of logical pointer type that results from one of the following instructions: |
When this extension is enabled, invocation-private pointers can be dynamic and non-uniform. Without this extension a variable pointer must be selected from pointers pointing into the same structure or be OpConstantNull
.
This extension has two levels to it. The first is the variablePointersStorageBuffer
feature bit which allows implementations to support the use of variable pointers into a SSBO only. The variablePointers
feature bit allows the use of variable pointers outside the SSBO as well.
VK_KHR_vulkan_memory_model
Promoted to core in Vulkan 1.2 |
The Vulkan Memory Model formally defines how to synchronize memory accesses to the same memory locations performed by multiple shader invocations and this extension exposes a boolean to let implementations to indicate support for it. This is important because with many things targeting Vulkan/SPIR-V it is important that any memory transfer operations an application might attempt to optimize doesn’t break across implementations.
VK_EXT_shader_viewport_index_layer
Promoted to core in Vulkan 1.2 |
This extension adds the ViewportIndex
, Layer
built-in for exporting from vertex or tessellation shaders.
In GLSL these are represented by gl_ViewportIndex
and gl_Layer
built-ins.
When using Vulkan 1.0 or 1.1 the ShaderViewportIndexLayerEXT
SPIR-V capability is used. Starting in Vulkan 1.2 the ShaderViewportIndexLayerEXT
capability is split into the new ShaderViewportIndex
and ShaderLayer
capability.
VK_KHR_shader_draw_parameters
Promoted to core in Vulkan 1.1 |
This extension adds the BaseInstance
, BaseVertex
, and DrawIndex
built-in for vertex shaders. This was added as there are legitimate use cases for both inclusion and exclusion of the BaseVertex
or BaseInstance
parameters in VertexId
and InstanceId
, respectively.
In GLSL these are represented by gl_BaseInstanceARB
, gl_BaseVertexARB
and gl_BaseInstanceARB
built-ins.
VK_EXT_shader_stencil_export
This extension allows a shader to generate the stencil reference value per invocation. When stencil testing is enabled, this allows the test to be performed against the value generated in the shader.
In GLSL this is represented by a out int gl_FragStencilRefARB
built-in.
VK_EXT_shader_demote_to_helper_invocation
Promoted to core in Vulkan 1.3 |
This extension was created to help with matching the HLSL discard
instruction in SPIR-V by adding a demote
keyword. When using demote
in a fragment shader invocation it becomes a helper invocation. Any stores to memory after this instruction are suppressed and the fragment does not write outputs to the framebuffer.
VK_KHR_shader_clock
This extension allows the shader to read the value of a monotonically incrementing counter provided by the implementation. This can be used as one possible method for debugging by tracking the order of when an invocation executes the instruction. It is worth noting that the addition of the OpReadClockKHR
alters the shader one might want to debug. This means there is a certain level of accuracy representing the order as if the instructions did not exists.
VK_KHR_shader_non_semantic_info
Promoted to core in Vulkan 1.3 |
This extension exposes SPV_KHR_non_semantic_info which adds the ability to declare extended instruction sets that have no semantic impact and can be safely removed from a module.
VK_KHR_shader_terminate_invocation
Promoted to core in Vulkan 1.3 |
This extension adds the new instruction OpTerminateInvocation
to provide a disambiguated functionality compared to the OpKill
instruction.
VK_KHR_workgroup_memory_explicit_layout
This extension provides a way for the shader to define the layout of Workgroup
Storage Class
memory. Workgroup
variables can be declared in blocks, and then use the same explicit layout decorations (e.g. Offset
, ArrayStride
) as other storage classes.
One use case is to do large vector copies (e.g. uvec4
at at a time) from buffer memory into shared memory, even if the shared memory is really a different type (e.g. scalar fp16
).
Another use case is a developers could potentially use this to reuse shared memory and reduce the total shared memory consumption using something such as the following:
pass1 - write shmem using type A
barrier()
pass2 - read shmem using type A
barrier()
pass3 - write shmem using type B
barrier()
pass4 - read shmem using type B
The explicit layout support and some form of aliasing is also required for layering OpenCL on top of Vulkan.
VK_KHR_zero_initialize_workgroup_memory
Promoted to core in Vulkan 1.3 |
This extension allows OpVariable
with a Workgroup
Storage Class
to use the Initializer
operand.
For security reasons, applications running untrusted content (e.g. web browsers) need to be able to zero-initialize workgroup memory at the start of workgroup execution. Adding instructions to set all workgroup variables to zero would be less efficient than what some hardware is capable of, due to poor access patterns.