This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
- CMake 3.16+
- Vulkan SDK
- SDL2 and SDL2_image libraries
- GLM (OpenGL Mathematics library)
macOS:
# Install via Homebrew
brew install vulkan-headers vulkan-loader molten-vk sdl2 sdl2_image glmWindows:
- Install Vulkan SDK from https://vulkan.lunarg.com/
- Use vcpkg for dependencies:
vcpkg install sdl2 sdl2-image glm vulkanLinux/Ubuntu:
sudo apt-get update
sudo apt-get install vulkan-tools libvulkan-dev vulkan-validationlayers-dev
sudo apt-get install libsdl2-dev libsdl2-image-dev libglm-dev
sudo apt-get install build-essential cmake pkg-configRaspberry Pi 5:
# Same as Linux, plus ARM64-specific packages
sudo apt-get install gcc-aarch64-linux-gnu g++-aarch64-linux-gnuAll Platforms:
cd TestHarness
mkdir -p build && cd build
cmake ..
cmake --build . -j$(nproc)Windows (Visual Studio):
cd TestHarness
mkdir build && cd build
cmake .. -G "Visual Studio 16 2019" -A x64
cmake --build . --config ReleaseThe built executable will be located at:
- macOS/Linux:
TestHarness/build/VulkanTester - Windows:
TestHarness/build/Release/VulkanTester.exe
TestHarness uses organized directory structure:
TestHarness/src/- Source files (.cpp)TestHarness/include/- Header files (.h)TestHarness/src/shaders/- SPIR-V compiled shaders (.spv)
- macOS: Uses MoltenVK for Vulkan support, requires portability extensions
- Windows: Direct Vulkan support, uses Win32 platform extensions
- Linux: Direct Vulkan support, uses XCB platform extensions
- Raspberry Pi 5: ARM64 optimizations enabled automatically
The build system automatically copies pre-compiled SPIR-V shaders from src/shaders/*.spv to the appropriate runtime directory during the build process.
Note: This module is typically used as a submodule by projects like HelloVulkanSDL which provide additional shader compilation infrastructure.
VulkanModule is a reusable foundation for Vulkan graphics projects, providing object-oriented encapsulation of Vulkan's initialization and setup requirements.
Objects/ - Encapsulates Vulkan subsystems in RAII fashion:
VulkanInstance- Manages VkInstanceGraphicsDevice- Manages VkDevice/VkPhysicalDevice selection and queuesSwapchain- Handles swapchain creation and recreation on resizeRenderPass,GraphicsPipeline,Framebuffers- Core rendering pipelineWindowSurface- Platform surface abstractionSyncObjects- Semaphores and fences for GPU/CPU synchronization
Setup/ - Orchestrates initialization:
VulkanSetup- Main initialization class that creates all Vulkan objects in dependency orderVulkanConfigure- Configuration managementShader- Shader module loading
Adjunct/ - Higher-level abstractions:
Renderables/- Base classes for drawable objects (FixedRenderable, DynamicRenderable)ShaderCache- Shared shader management with reference counting to eliminate redundant shader loading
VertexTypes/- Various vertex format definitionsTextureImage,UniformBuffer- Resource managementDynamicUniformBuffer- Efficient per-object uniform data using dynamic offsets for rendering thousands of objects
Platform/ - Platform abstraction layer:
OSAbstraction/PlatformSDL- SDL2 window/input handling (primary platform)FileSystem/- File I/O with conventions for shader/texture/model pathsImageHandling/- Image loading via SDL_image or STB
- RAII Resource Management: Objects manage their Vulkan resources through constructors/destructors
- Recreate Pattern: Objects support
Recreate()for handling window resize/minimize events - Dependency Order: VulkanSetup instantiates objects in strict dependency order
- Platform Abstraction: iPlatform interface allows different windowing systems (SDL2, GLFW, XCB)
- Resource Sharing: ShaderCache enables sharing ShaderModules across renderables to eliminate redundant loads
- Dynamic Uniform Buffers: Support for VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC with per-object offsets for efficient multi-object rendering
- Vulkan SDK (headers and loader)
- SDL2 and SDL2_image
- GLM (math library)
- Optional: Dear ImGui for debug UI (stubbed if not used)
The TestHarness directory contains a minimal test application demonstrating module usage. The main class VulkanTester shows the typical initialization pattern:
- Create platform (SDL)
- Instantiate VulkanSetup with platform and configuration
- Store references to key objects for rendering loop
Dynamic Uniform Buffers enable efficient rendering of large numbers of objects by using a single shared buffer with dynamic offsets instead of creating individual UniformBuffer objects per renderable.
Usage:
// 1. Create DynamicUniformBuffer (typically in application initialization)
const uint32_t MAX_OBJECTS = 1000;
const uint32_t FRAMES_IN_FLIGHT = swapchain.getNumImages();
DynamicUniformBuffer* dynamicUBO = new DynamicUniformBuffer(MAX_OBJECTS, FRAMES_IN_FLIGHT, device);
// 2. Configure drawable to use dynamic UBO
drawable->pUBOs = {
camera.uboMVP, // Binding 0: Static camera matrices
UBO(dynamicUBO) // Binding 1: Dynamic per-object transforms
};
// 3. Set dynamic offset on renderable
FixedRenderable fixedRenderable(*drawable, vulkan, platform);
fixedRenderable.hasDynamicOffset = true;
fixedRenderable.dynamicOffset = dynamicUBO->getDynamicOffset(objectIndex);
// 4. Update per-object transforms each frame
dynamicUBO->updateObjectTransform(frameIndex, objectIndex, modelMatrix);Benefits:
- Renders thousands of objects with minimal overhead
- Single buffer allocation instead of hundreds/thousands of individual buffers
- Reduced descriptor set updates
- Lower memory fragmentation
Implementation Details:
- Automatically adds
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMICto descriptor pool FixedRenderablecheckshasDynamicOffsetand passes offset array tovkCmdBindDescriptorSets()- Update transforms before recording command buffers each frame
ShaderCache eliminates redundant shader loading when multiple renderables use the same shaders, crucial for scenes with thousands of objects.
Usage:
// 1. Create ShaderCache (typically in application initialization)
ShaderCache* shaderCache = new ShaderCache(vulkan.device);
// 2. Get or create shared shaders for a drawable
ShaderModules* pSharedShaders = shaderCache->getOrCreate(drawable->shaders);
drawable->pSharedShaderModules = pSharedShaders;
shaderCache->addRef(pSharedShaders);
// 3. Create renderable (will use shared shaders)
FixedRenderable fixedRenderable(*drawable, vulkan, platform);
// 4. ShaderCache handles cleanup automatically via reference counting
// When last renderable using a shader set is destroyed, shaders are freedBenefits:
- Shaders loaded once and shared across all renderables using the same shader set
- Automatic reference counting prevents premature deletion
- Reduced I/O and memory usage
- Faster scene initialization
Implementation Details:
- Shaders are cached by a key generated from shader file names and types
iRenderablecheckspSharedShaderModulesand uses it if provided, otherwise creates its ownownsShaderModulesflag prevents double-deletion- Reference counting ensures shaders persist until last user is destroyed