How GL_KHR_vulkan_glsl Targets Vulkan in GLSL
This article explains how the GL_KHR_vulkan_glsl
preprocessor macro functions within the OpenGL Shading Language (GLSL)
to target the Vulkan graphics API. When compiling shaders to SPIR-V for
Vulkan, compilers automatically define this macro to enable
Vulkan-specific syntax, semantics, and resource models while disabling
legacy OpenGL constructs. Understanding this macro allows developers to
write dual-compatible shader codebases that adapt cleanly between OpenGL
and Vulkan environments.
The Role of the Preprocessor Macro
When a shader compiler such as glslangValidator or
glslc is configured to target Vulkan (typically via the
-V or --target-env=vulkan flags), it
implicitly sets the GL_KHR_vulkan_glsl preprocessor macro
to an integer value of 100. In addition to this macro,
compilers commonly define the standard shorthand macro
VULKAN with the value 100.
The presence of GL_KHR_vulkan_glsl informs the
compilation pipeline that the shader must adhere to the rules defined in
the GL_KHR_vulkan_glsl extension specification rather than
traditional OpenGL GLSL specifications.
Feature Adjustments and Vulkan Syntax
Defining this macro changes how the compiler parses resources and keywords:
- Descriptor Sets: It enables the
setlayout qualifier, allowing constructs such aslayout(set = 0, binding = 0) uniform buffer, which are fundamental to Vulkan’s descriptor set model but absent in core OpenGL. - Push Constants: It activates the
layout(push_constant)layout identifier, enabling memory blocks to receive push constant data directly from Vulkan command buffers. - Subpass Inputs: It provides access to subpass input
types (such as
subpassInputandsubpassInputMS) alongside their associated fetch functions for reading directly from attachments in a render pass. - Combined vs. Separate Samplers: It supports
explicit separation of textures and samplers (
texture2Dandsampler) via Vulkan SPIR-V capabilities, distinct from combined image-samplers (sampler2D). - Removal of Incompatible Features: The compiler disables OpenGL-only conventions, such as default-block uniform variables without explicit bindings, atomic counter types, and specific fixed-function inputs.
Conditional Compilation Example
Developers leverage the macro to write shaders that compile seamlessly for both standard OpenGL and Vulkan targets using conditional compilation blocks:
#version 450
#if defined(GL_KHR_vulkan_glsl)
// Vulkan-specific resource binding
layout(set = 0, binding = 0) uniform CameraData {
mat4 viewProjection;
} camera;
#else
// Standard OpenGL resource binding
layout(binding = 0) uniform CameraData {
mat4 viewProjection;
} camera;
#endif
void main() {
// Shared shader logic
}By querying #if defined(GL_KHR_vulkan_glsl) or
#if defined(VULKAN), the preprocessor selectively includes
API-specific qualifiers before the code is transformed into the final
intermediate representation or driver-level assembly.