glslvulkanspir-v

How to Use Vulkan SPIR-V Data Formats in GLSL


SPIR-V allows for very verbose data formats.

GLSL has only basic data types (Chapter 4) that do not specify bit length.

As far as I am aware the most convenient way to program shaders for Vulkan is to program them in GLSL, then use the Vulkan SDK provided compiler (glslc.exe) to convert the file into a SPIR-V binary.

My question is how does one use these verbose data formats such as the VK_FORMAT_R4G4_UNORM_PACK8 (found in the SPIR-V link above) In GLSL while using glslc.exe to compile our shader code. Are there special data types that the compiler allows for? If not is there an alternative higher level language that one could use and then compile into the binary?

For example if this was the attribute descriptions used in the graphics pipeline:

struct Attributes {
   vec2 pos;
   char flags;
};

static inline std::array<VkVertexInputAttributeDescription, 3> getAttributeDescriptions() {
   std::array<VkVertexInputAttributeDescription, 3> attributeDescriptions{};
   attributeDescriptions[0].binding = 0;
   attributeDescriptions[0].location = 0;
   attributeDescriptions[0].format = VK_FORMAT_R32G32_SFLOAT;
   attributeDescriptions[0].offset = offsetof(Attributes, pos);

   attributeDescriptions[1].binding = 0;
   attributeDescriptions[1].location = 1;
   attributeDescriptions[1].format = VK_FORMAT_R4G4_UNORM_PACK8;
   attributeDescriptions[1].offset = offsetof(Attributes, flags);

return attributeDescriptions;

The proceeding GLSL shader code would look something like this:

#version 450
#extension GL_ARB_separate_shader_objects : enable

//Instance Attributes
layout(location = 0) in vec2 pos;
layout(location = 1) in 4BitVec2DataType flags;         
//4BitVec2DataType is a placeholder for whatever GLSL's equivalent of SPIR-V's VK_FORMAT_R4G4_UNORM_PACK8 would be

void main() {
    ...
}

Solution

  • The proceeding GLSL shader code would look something like this:

    No, it wouldn't. You would receive a vec2 in the shader, because that's how vertex attributes work. The vertex format is not meant to exactly match the data format; the data will be converted from that format to the shader-expected bitdepth. Unsigned normalized values are floating-point data, so a 2-vector UNORM maps to a GLSL vec2.

    And BTW, SPIR-V does not change this. The shader's input size need not exactly match the given data size; any conversion is just baked into the shader (this is also part of why the vertex format is part of the pipeline).

    The GL_EXT_shader_16bit_storage extension offers more flexibility in GLSL for creating unusual sizes of data types within buffer-backed interface blocks. But these are specifically for data in UBOs/SSBOs, not vertex formats. However, this extension requires the SPV_KHR_16bit_storage and SPV_KHR_8bit_storage SPIR-V extensions.