0

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() {
    ...
}
Ryoku
  • 397
  • 2
  • 16

1 Answers1

3

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.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • Since the bit sizes are added once when the graphics pipeline is created, is it safe to assume that padding is not added (for alignment requirements) until that stage as well? In the [Vulkan Specification](https://www.khronos.org/registry/vulkan/specs/1.0/html/vkspec.html#interfaces-resources-layout) it states that the alignment of a vector has scalar alignment equal to its component type. Does this mean that, for the sake of non uniforms, the graphics card will not add padding to the variables. For example it won't have two 32 bit vectors with LSBs set to 4 bits each of the 8 provided – Ryoku Jan 23 '21 at 20:53
  • @Ryoku: "*for the sake of non uniforms*" What does that mean in this context? If you're not talking about buffer-backed interface blocks of some kind, then "alignment" is irrelevant. It is whatever the driver wants it to be. – Nicol Bolas Jan 23 '21 at 21:11
  • Reading the Vulkan specification I saw that there were three kinds of alignments: scalar, base and extended. I said uniform because I know that uniforms must go by the extended alignment which is then rounded up to a multiple of 16. I couldn't find clarity on when the other alignments were used though. By the sounds of your response it seems we would be going with base alignment and, as with compilers, the driver can change the implementation so long as observable behavior wasn't effected, in this case so long as it takes in 8 bits and provides the 4 bits individually when necessary. – Ryoku Jan 23 '21 at 21:57
  • AFAIK those alignments are all options for how to align the interior of a UBO or SSBO and correspond to GLSL layout qualifiers. – Andrea Jan 24 '21 at 00:10
  • @Andrea I'm not quite sure to be honest, the part that leads me to believe that there are specific rules for UBOs is this part here found _Standard Buffer Layout_ section: "Members of an OpTypeStruct that is required to be explicitly laid out must be aligned according to the first matching rule as follows. If the struct is contained in pointer types of multiple storage classes, it must satisfy the requirements for every storage class used to reference it. **1.** If the scalarBlockLayout feature is enabled; every member must be aligned according to its scalar alignment. – Ryoku Jan 24 '21 at 03:32
  • **2.** Vectors must be aligned according to their scalar alignment. **3.** If the uniformBufferStandardLayout feature is not enabled; any member of an OpTypeStruct with a storage class of Uniform and a decoration of Block must be aligned according to its extended alignment. **4.** Every other member must be aligned according to its base alignment." But maybe your right because the quote starts by saying **Members of an OpTypeStruct that is required to be explicitly laid out must be aligned according to the first matching rule as follows** – Ryoku Jan 24 '21 at 03:32