Overview

GPULang is designed from the ground up to make shader development more efficient and maintainable. This guide covers integration patterns, performance optimization, and best practices for using GPULang in real-time rendering applications.

Loading a GPULang output file and extracting a single program

struct Program
{
    char* memory;
    GPULang::Loader loader;
    GPULang::VulkanPipelineInfo pipelineInfo;
};

//------------------------------------------------------------------------------
/**
*/
Program
LoadShader(char* fileBuffer, size_t fileBufferSize, VkDevice device, std::string shader)
{
    GPULang::Loader loader;
    loader.Load(fileBuffer, fileBufferSize);

    auto prog = loader.Get("TestProgram");

    GPULang::VulkanPipelineInfo vulkanPipeline = GPULang::SetupVulkan(
        device
        , prog
        , loader.variables.data()
        , loader.variables.size()
        , GPULang::VulkanFunctions{ .vkCreateShaderModule = vkCreateShaderModule, .vkCreatePipelineLayout = vkCreatePipelineLayout, .vkCreateDescriptorSetLayout = vkCreateDescriptorSetLayout }
    );
    Program ret;

    ret.pipelineInfo = vulkanPipeline;
    ret.memory = buf;
    ret.loader = loader;
    return ret;
}

//------------------------------------------------------------------------------
/**
*/
void main()
{
    ... // Setup vulkan
    Program computeProgram = LoadShader(device, "computewithstore.gplb");
    VkComputePipelineCreateInfo cmpPsoInfo = GPULang::GetComputePipeline(computeProgram.pipelineInfo);
}

Iterate and and setup dynamically

//------------------------------------------------------------------------------
/**
*/
Program
LoadShader(char* fileBuffer, size_t fileBufferSize, VkDevice device, std::string shader)
{
    GPULang::Loader loader;
    loader.Load(fileBuffer, fileBufferSize);

    // Map for looking up symbols by name
    for (auto& [name, object] : info.loader->nameToObject)
    {
        if (object->type == GPULang::Serialize::Type::VariableType)
        {
            auto variable = (GPULang::Deserialize::Variable*)object;

            // If variable is a uniform buffer, store it in the reflection data
            if (variable->bindingType == GPULang::BindingType::Buffer)
            {
                // Setup read-only buffer (uniform/constant)
            }
            else if (variable->bindingType == GPULang::BindingType::MutableBuffer)
            {
                // Setup writeable buffer (storage/rw)
            }
        }
        if (object->type == GPULang::Serialize::Type::ProgramType)
        {
            auto program = (GPULang::Deserialize::Program*)object;
            VkShaderModule vs,hs,ds,gs,ps,cs;
            VulkanCreateShader(device, &vs, program->shaders[GPULang::Deserialize::Program::ShaderStages::VertexShader]);
            VulkanCreateShader(device, &hs, program->shaders[GPULang::Deserialize::Program::ShaderStages::HullShader]);
            VulkanCreateShader(device, &ds, program->shaders[GPULang::Deserialize::Program::ShaderStages::DomainShader]);
            VulkanCreateShader(device, &gs, program->shaders[GPULang::Deserialize::Program::ShaderStages::GeometryShader]);
            VulkanCreateShader(device, &ps, program->shaders[GPULang::Deserialize::Program::ShaderStages::PixelShader]);
            VulkanCreateShader(device, &cs, program->shaders[GPULang::Deserialize::Program::ShaderStages::ComputeShader]);
        }
    }
}

Using static reflection

#include "histogram.h"
//------------------------------------------------------------------------------
/**
*/
void
BindHistogram(const std::vector<VkDescriptorSet>& sets, VkBuffer buf)
{
    WriteDescriptor(sets[Histogram::HistogramBuffer::GROUP], Histogram::HistogramBuffer::BINDING, buf);
}

//------------------------------------------------------------------------------
/**
*/
void
RunHistogram(VkCmdBuffer& cmd, int ScreenSize[2])
{
    vkCmdDispatch(cmd
        , HistogramProgram::csMain::WORKGROUP_SIZE[0] / ScreenSize[0]
        , HistogramProgram::csMain::WORKGROUP_SIZE[1] / ScreenSize[1]
        , HistogramProgram::csMain::WORKGROUP_SIZE[2]
    )
}