Skip to content

KDGpu::ShaderModule

Module: Public API

Represents compiled shader code (SPIR-V) for a pipeline stage. More...

#include <KDGpu/shader_module.h>

Public Functions

Name
ShaderModule()
~ShaderModule()
ShaderModule(ShaderModule && other)
ShaderModule & operator=(ShaderModule && other)
ShaderModule(const ShaderModule & ) =delete
ShaderModule & operator=(const ShaderModule & ) =delete
Handle< ShaderModule_t > handle() const
bool isValid() const
operator Handle< ShaderModule_t >() const

Friends

Name
class Device

Detailed Description

1
class KDGpu::ShaderModule;

Represents compiled shader code (SPIR-V) for a pipeline stage.

Vulkan equivalent:VkShaderModule

ShaderModule wraps compiled SPIR-V shader bytecode. Shaders are written in GLSL or HLSL, compiled to SPIR-V format, and then loaded into shader modules for use in graphics or compute pipelines.

Key features:

  • Encapsulates SPIR-V bytecode
  • Reusable across multiple pipelines
  • Supports all shader stages
  • Entry point specification

Lifetime: ShaderModules are created by Device and must remain valid during pipeline creation. ShaderModules can be destroyed after all pipelines that use them have been created. They use RAII and clean up automatically.

Usage

Loading shader from file:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
std::vector<uint32_t> loadSpirv(const std::string &filepath)
{
    std::ifstream file(filepath, std::ios::binary | std::ios::ate);
    if (!file.is_open())
        return {};
    size_t fileSize = static_cast<size_t>(file.tellg());
    std::vector<uint32_t> buffer(fileSize / sizeof(uint32_t));
    file.seekg(0);
    file.read(reinterpret_cast<char *>(buffer.data()), fileSize);
    return buffer;
}

Filename: kdgpu_doc_snippets.cpp

1
2
    std::vector<uint32_t> spirvCode = loadSpirv("shader.vert.spv");
    KDGpu::ShaderModule shader = device.createShaderModule(spirvCode);

Filename: kdgpu_doc_snippets.cpp

KDGpuExample::readShaderFile

Loading shader from SPIR-V data in memory:

1
2
    std::vector<uint32_t> vertexSpirv = { /* SPIR-V bytecode */ };
    KDGpu::ShaderModule vertexShader = device.createShaderModule(vertexSpirv);

Filename: kdgpu_doc_snippets.cpp

Creating graphics pipeline with shaders:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
    KDGpu::ShaderModule vertShader = device.createShaderModule(loadSpirv("shader.vert.spv"));
    KDGpu::ShaderModule fragShader = device.createShaderModule(loadSpirv("shader.frag.spv"));

    KDGpu::PipelineLayout pipelineLayout;
    KDGpu::GraphicsPipeline pipelineShaders = device.createGraphicsPipeline(KDGpu::GraphicsPipelineOptions{
            .shaderStages = {
                    {
                            .shaderModule = vertShader,
                            .stage = KDGpu::ShaderStageFlagBits::VertexBit,
                    },
                    {
                            .shaderModule = fragShader,
                            .stage = KDGpu::ShaderStageFlagBits::FragmentBit,
                    },
            },
            .layout = pipelineLayout,
            // ... other pipeline options ...
    });

Filename: kdgpu_doc_snippets.cpp

Creating compute pipeline with shader:

1
2
3
4
5
6
7
8
    KDGpu::ShaderModule computeShader = device.createShaderModule(loadSpirv("compute.comp.spv"));

    KDGpu::ComputePipeline computePipeline = device.createComputePipeline(KDGpu::ComputePipelineOptions{
            .layout = pipelineLayout,
            .shaderStage = {
                    .shaderModule = computeShader,
            },
    });

Filename: kdgpu_doc_snippets.cpp

Using specialization constants:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
    KDGpu::ShaderModule shaderSpec = device.createShaderModule(loadSpirv("shader.frag.spv"));

    KDGpu::GraphicsPipeline pipelineSpec = device.createGraphicsPipeline(KDGpu::GraphicsPipelineOptions{
            .shaderStages = {
                    {
                            .shaderModule = shaderSpec.handle(),
                            .stage = KDGpu::ShaderStageFlagBits::FragmentBit,
                            .specializationConstants = {
                                    { .constantId = 0, .value = 4u }, // NUM_LIGHTS
                                    { .constantId = 1, .value = true }, // ENABLE_SHADOWS
                                    { .constantId = 2, .value = 2.2f }, // GAMMA
                            },
                    },
            },
            .layout = pipelineLayout,
            // ... other options ...
    });

Filename: kdgpu_doc_snippets.cpp

Reusing shaders across pipelines:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
    KDGpu::ShaderModule vertShader = device.createShaderModule(vertSpirv);
    KDGpu::ShaderModule fragShader = device.createShaderModule(fragSpirv);

    // Use same shaders for multiple pipelines with different state
    KDGpu::PipelineLayout pipelineLayout;
    KDGpu::Format swapchainFormat = KDGpu::Format::B8G8R8A8_SRGB;

    KDGpu::GraphicsPipeline opaquePipeline = device.createGraphicsPipeline(KDGpu::GraphicsPipelineOptions{
            .shaderStages = {
                    {
                            .shaderModule = vertShader,
                            .stage = KDGpu::ShaderStageFlagBits::VertexBit,
                    },
                    {
                            .shaderModule = fragShader,
                            .stage = KDGpu::ShaderStageFlagBits::FragmentBit,
                    },
            },
            .layout = pipelineLayout,
            .renderTargets = {
                    {
                            .format = swapchainFormat,
                    },
            },
    });

    KDGpu::GraphicsPipeline transparentPipeline = device.createGraphicsPipeline(KDGpu::GraphicsPipelineOptions{
            .shaderStages = {
                    {
                            .shaderModule = vertShader,
                            .stage = KDGpu::ShaderStageFlagBits::VertexBit,
                    },
                    {
                            .shaderModule = fragShader,
                            .stage = KDGpu::ShaderStageFlagBits::FragmentBit,
                    },
            },
            .layout = pipelineLayout,
            .renderTargets = {
                    {
                            .format = swapchainFormat,
                    },
            },
    });

Filename: kdgpu_doc_snippets.cpp

Geometry shader example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
    KDGpu::ShaderModule geomShader = device.createShaderModule(geomSpirv);

    KDGpu::GraphicsPipeline pipeline = device.createGraphicsPipeline(KDGpu::GraphicsPipelineOptions{
            .shaderStages = {
                    {
                            .shaderModule = vertShader,
                            .stage = KDGpu::ShaderStageFlagBits::VertexBit,
                    },
                    {
                            .shaderModule = geomShader,
                            .stage = KDGpu::ShaderStageFlagBits::GeometryBit,
                    },
                    {
                            .shaderModule = fragShader,
                            .stage = KDGpu::ShaderStageFlagBits::FragmentBit,
                    },
            },
            .layout = pipelineLayout,
            .renderTargets = {
                    {
                            .format = swapchainFormat,
                    },
            },
    });

Filename: kdgpu_doc_snippets.cpp

Compiling GLSL to SPIR-V:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# Using glslangValidator
glslangValidator -V shader.vert -o shader.vert.spv
glslangValidator -V shader.frag -o shader.frag.spv
glslangValidator -V shader.comp -o shader.comp.spv

# Using glslc (from shaderc)
glslc shader.vert -o shader.vert.spv
glslc shader.frag -o shader.frag.spv

# Using KDGpu cmake helpers in a CMakeLists.txt
kdgpu_compileshader(ComputeShaderTarget particles.comp particles.comp.spv)
kdgpu_compileshaderset(VertexFragmentShaderTarget vertex) # looks for vertex.vert and vertex.frag, compiles to vertex.vert.spv and vertex.frag.spv
kdgpu_compilegeomshaderset(VertexGeomFragmentShaderTarget geom) # looks for geom.vert geom.geom and geom.frag, compiles to geom.vert.spv, geom.geom.spv and geom.frag.spv
kdgpu_compilemeshtaskshader(MeshShaderTarget mesh_shader.mesh mesh_shader.mesh.spv)
kdgpu_compilertshader(RtGenShaderTarget raygen.rgen raygen.spv)

Vulkan mapping:

  • ShaderModule creation -> vkCreateShaderModule()
  • Used in VkPipelineShaderStageCreateInfo

See also:

GraphicsPipeline, ComputePipeline, Device, PipelineLayout

KDGpu API Overview

KDGpu to Vulkan API Mapping

Public Functions Documentation

function ShaderModule

1
ShaderModule()

function ~ShaderModule

1
~ShaderModule()

function ShaderModule

1
2
3
ShaderModule(
    ShaderModule && other
)

function operator=

1
2
3
ShaderModule & operator=(
    ShaderModule && other
)

function ShaderModule

1
2
3
ShaderModule(
    const ShaderModule & 
) =delete

function operator=

1
2
3
ShaderModule & operator=(
    const ShaderModule & 
) =delete

function handle

1
inline Handle< ShaderModule_t > handle() const

function isValid

1
inline bool isValid() const

function operator Handle< ShaderModule_t >

1
inline operator Handle< ShaderModule_t >() const

Friends

friend Device

1
2
3
friend class Device(
    Device 
);

Updated on 2026-03-31 at 00:02:07 +0000