Search code examples
glslatomicvulkan

Adding support for floating point atomic operations in Vulkan


Recently the extension VK_EXT_shader_atomic_float has been added. I'm trying to figure out how to use it.

I've added the appropriate flag to my shader

#version 450
#extension GL_EXT_shader_atomic_float : enable

and I also added VK_EXT_shader_atomic_float to the device extensions

const char* extension_names[] = {"VK_EXT_shader_atomic_float", ... other extensions ...};
struct VkDeviceCreateInfo createInfo;
createInfo.enabledExtensionCount = 4;
createInfo.ppEnabledExtensionNames = extension_names;

Unfortunately I still get

[Debug][Error][Validation]"Validation Error: [ VUID-VkShaderModuleCreateInfo-pCode-01091 ] Object 0: handle = 0x55967fac1038, type = VK_OBJECT_TYPE_DEVICE; | MessageID = 0xa7bb8db6 | vkCreateShaderModule(): The SPIR-V Capability (AtomicFloat32AddEXT) was declared, but none of the requirements were met to use it. The Vulkan spec states: If pCode declares any of the capabilities listed in the SPIR-V Environment appendix, one of the corresponding requirements must be satisfied (https://vulkan.lunarg.com/doc/view/1.2.182.0/linux/1.2-extensions/vkspec.html#VUID-VkShaderModuleCreateInfo-pCode-01091)"

I suppose I should add something to vkShaderModuleCreateInfo.pNext, but I'm not sure what exactly.


Solution

  • If you go here

    https://vulkan.lunarg.com/doc/view/1.2.182.0/linux/1.2-extensions/vkspec.html#spirvenv-capabilities

    you can scroll down to the desired extension. In this case it's

    AtomicFloat32AddEXT
                    VkPhysicalDeviceShaderAtomicFloatFeaturesEXT::shaderBufferFloat32AtomicAdd
                    VkPhysicalDeviceShaderAtomicFloatFeaturesEXT::shaderSharedFloat32AtomicAdd
                    VkPhysicalDeviceShaderAtomicFloatFeaturesEXT::shaderImageFloat32AtomicAdd
                    VkPhysicalDeviceShaderAtomicFloatFeaturesEXT::sparseImageFloat32AtomicAdd
    

    This tells you that you need to use VkPhysicalDeviceShaderAtomicFloatFeaturesEXT structure and set it's corresponding flag. The structure is defined as

    typedef struct VkPhysicalDeviceShaderAtomicFloatFeaturesEXT {
        VkStructureType    sType;
        void*              pNext;
        VkBool32           shaderBufferFloat32Atomics;
        VkBool32           shaderBufferFloat32AtomicAdd;
        VkBool32           shaderBufferFloat64Atomics;
        VkBool32           shaderBufferFloat64AtomicAdd;
        VkBool32           shaderSharedFloat32Atomics;
        VkBool32           shaderSharedFloat32AtomicAdd;
        VkBool32           shaderSharedFloat64Atomics;
        VkBool32           shaderSharedFloat64AtomicAdd;
        VkBool32           shaderImageFloat32Atomics;
        VkBool32           shaderImageFloat32AtomicAdd;
        VkBool32           sparseImageFloat32Atomics;
        VkBool32           sparseImageFloat32AtomicAdd;
    } VkPhysicalDeviceShaderAtomicFloatFeaturesEXT;
    

    So the complete code would looks more or less like this

    VkPhysicalDeviceShaderAtomicFloatFeaturesEXT floatFeatures;
    floatFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_FEATURES_EXT;
    floatFeatures.shaderBufferFloat32AtomicAdd = true; // this allows to perform atomic operations on storage buffers
    
    const char* extension_names[] = {"VK_EXT_shader_atomic_float", ... other extensions ...};
    VkDeviceCreateInfo createInfo;
    createInfo.enabledExtensionCount = 4;
    createInfo.ppEnabledExtensionNames = extension_names;
    createInfo.pNext = &floatFeatures;