Skip to content

MrMartyK/vksdl

Repository files navigation

VKSDL

Vulkan without the 800 lines of boilerplate before your first triangle.

C++20 Vulkan 1.3 SDL3 License: Zlib Version Tests

Website · Getting Started · Examples · API Reference


Overview

vksdl is a C++20 wrapper library for Vulkan 1.3 and SDL3 that eliminates the repetitive setup code — instance creation, device selection, swapchain management, synchronization, pipeline construction — while leaving the actual rendering entirely in your hands.

One #include. Raw VkCommandBuffer inside. Full escape hatches everywhere.

Why vksdl?

Vulkan is explicit by design, and that is its strength. But a significant portion of any Vulkan application is pure ceremony: code that has exactly one correct answer. vksdl wraps that ceremony and leaves the real decisions to you.

  • ~17,000 lines of C++20 across 56 public headers
  • 43 tests, 20 working examples
  • Vulkan 1.3 core: dynamic rendering, synchronization2, timeline semaphores
  • Zero per-frame allocations in the hot path
  • SDL3 windowing: Windows, Linux, and macOS from a single codebase
  • No legacy render passes, no compatibility mode

Getting Started

Prerequisites

  • Vulkan SDK 1.3+
  • CMake 3.21+
  • C++20 compiler (GCC 14+, Clang 18+, MSVC 2022+)

Build

git clone --recursive https://github.com/MrMartyK/vksdl.git
cd vksdl
cmake -B build -S . -DCMAKE_TOOLCHAIN_FILE=vcpkg/scripts/buildsystems/vcpkg.cmake
cmake --build build
cd build && ctest --output-on-failure

All dependencies (SDL3, VMA, stb, cgltf, tinyobjloader) are fetched automatically via the bundled vcpkg submodule.

Quick Start

Setup is roughly 15 lines. The rest is your Vulkan code.

auto app       = vksdl::App::create().value();
auto window    = app.createWindow("Triangle", 1280, 720).value();
auto instance  = vksdl::InstanceBuilder{}.appName("tri")
    .requireVulkan(1, 3).enableWindowSupport().build().value();
auto surface   = vksdl::Surface::create(instance, window).value();
auto device    = vksdl::DeviceBuilder(instance, surface)
    .needSwapchain().needDynamicRendering().needSync2()
    .preferDiscreteGpu().build().value();
auto swapchain = vksdl::SwapchainBuilder(device, surface)
    .size(window.pixelSize()).build().value();
auto frames    = vksdl::FrameSync::create(device, swapchain.imageCount()).value();
auto pipeline  = vksdl::PipelineBuilder(device)
    .vertexShader("shaders/triangle.vert.spv")
    .fragmentShader("shaders/triangle.frag.spv")
    .colorFormat(swapchain).build().value();

The render loop is standard Vulkan. You own the command buffer.

auto [frame, img] = vksdl::acquireFrame(swapchain, frames, device, window).value();
vksdl::beginOneTimeCommands(frame.cmd);

vksdl::transitionToColorAttachment(frame.cmd, img.image);
// vkCmdBeginRendering, vkCmdDraw, vkCmdEndRendering — your code, your decisions
vksdl::transitionToPresent(frame.cmd, img.image);

vksdl::endCommands(frame.cmd);
vksdl::presentFrame(device, swapchain, window, frame, img,
                    VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);

The full triangle example is 113 lines, including the render loop and resize handling. The raw Vulkan equivalent is 800+.

What Gets Wrapped vs. What Stays Raw

vksdl handles You write
Instance, validation, debug messenger Nothing — one builder call
GPU selection, queue families, feature chains needSwapchain(), needRayTracingPipeline()
Swapchain format/present mode, image views, resize recreate() on window resize
Fences, semaphores, round-robin acquire Nothing — acquireFrame() / presentFrame()
SPIR-V loading, pipeline layout, blend/cull defaults Record commands, bind, draw
VMA allocation, typed buffer/image builders Choose usage, upload data
BLAS/TLAS construction, SBT layout, RT pipeline Trace rays, write shaders
Render graph: barriers, resource lifetime, toposort Declare passes, record in callbacks

Every RAII object exposes its raw Vulkan handle — vkDevice(), vkPipeline(), vkBuffer(), vkImage() — so you can drop to the Vulkan API directly anywhere vksdl does not cover your use case.

Examples

Example What It Demonstrates Lines
triangle Window, device, swapchain, pipeline, render loop 113
quad Vertex/index buffers, VMA staged uploads ~145
compute Compute shader, storage image, blit to swapchain 129
cube 3D depth, uniform buffers, descriptor sets ~200
textured_cube Texture loading, mipmaps, samplers ~250
multi_object Dynamic UBOs, multiple descriptor sets, debug names ~300
msaa MSAA with inline resolve, dynamic recreation ~180
model glTF/OBJ loading, PBR materials, directional lighting ~220
rt_triangle Minimal ray tracing: BLAS, TLAS, SBT, traceRays ~300
rt_spheres Path tracer: 475 spheres, GGX, physical sky, DOF 593
deferred 40-pass render graph: shadow, G-buffer, lighting, tonemap 709
pipeline_compiler GPL fast-linking, async compile, pipeline feedback 1339
8 more examples

Pipeline cache, timeline sync, dynamic state, descriptor pools, async transfer, unified layouts, shader reflection, and device fault diagnostics.

Ray tracing spheres example rendered with vksdl

The rt_spheres example: 475 spheres with GGX materials, physical sky, and depth of field in 593 lines of C++.

API at a Glance

Core types (60+)

All types are RAII, move-only, and return Result<T> by default. orThrow() is available as an escape hatch — it throws when exceptions are enabled and fail-fasts when they are disabled.

InitializationApp, InstanceBuilder, Surface, DeviceBuilder

PresentationSwapchainBuilder, FrameSync, acquireFrame, presentFrame

PipelinesPipelineBuilder, ComputePipelineBuilder, RTPipelineBuilder, PipelineCache

ResourcesBuffer, Image, Sampler, DescriptorSetLayout, DescriptorPool

Ray TracingBlas, Tlas, ShaderBindingTable

Render GraphRenderGraph, RenderPass, automatic barrier insertion, topological sort

UtilitiesShaderModule, TimelineSemaphore, QueryPool, DebugName

Design Philosophy

Wrap ceremony. Leave intent raw.

Ceremony is code with one correct answer: creating an instance, selecting a GPU, destroying objects in the right order. vksdl wraps that.

Intent is code where you make real choices: recording commands, choosing wait stages, structuring submissions. vksdl leaves that alone.

The test: if two experienced Vulkan developers would write the same boilerplate identically, vksdl should eliminate it. If they would write it differently, vksdl stays out of the way.

Platform Support

Platform Compiler Status
Windows 11 GCC 15.2 (MSYS2 MinGW) Tested, RTX 3060
Linux GCC 14 / Clang 18 Tested via CI
macOS Clang (via SDL3) Expected to work, not yet tested

Project Status

v0.12.0 — The core API is stable across 60+ wrapped types. The render graph and pipeline model are functional and tested but still evolving. See the changelog for release history.

License

Released under the Zlib License.

About

C++20 Vulkan 1.3 wrapper with SDL3 backend. Handles windowing, WSI, resource management, render graph, ray tracing, and pipeline compilation while exposing raw Vulkan handles for full control.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors