Skip to content

Instantly share code, notes, and snippets.

@Themaister
Last active October 9, 2025 21:22
Show Gist options
  • Save Themaister/dfeee47c193427f5e9dc397ff951b0ee to your computer and use it in GitHub Desktop.
Save Themaister/dfeee47c193427f5e9dc397ff951b0ee to your computer and use it in GitHub Desktop.
Bringup sample #1 - simple buffer copy
#!/bin/bash
git clone https://github.com/Themaister/Granite
cd Granite
git submodule update --init
cmake_minimum_required(VERSION 3.6)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_C_STANDARD 99)
project(Vulkan-Bringup LANGUAGES CXX C)
# Don't want to build tons of unrelated cruft when building.
add_subdirectory(Granite EXCLUDE_FROM_ALL)
# Wrapper for add_executable plus linking some of the most basic libs like Vulkan backend.
add_granite_offline_tool(test test.cpp)
#include "device.hpp"
#include "context.hpp"
#include <stdlib.h>
static void run_some_code(Vulkan::Device &dev)
{
Vulkan::BufferCreateInfo info = {};
info.size = 64;
// Memory should live in VRAM.
info.domain = Vulkan::BufferDomain::Device;
info.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
// Make it more obvious in the capture when memory gets copied over.
info.misc = Vulkan::BUFFER_MISC_ZERO_INITIALIZE_BIT;
auto gpu_buffer = dev.create_buffer(info);
dev.set_name(*gpu_buffer, "gpu-buffer");
// Memory should live in system memory. For "write-only" memory like this,
// write-combined memory is the way to go. CachedHost is important for reading.
info.domain = Vulkan::BufferDomain::Host;
info.misc = 0;
uint32_t initial_data[16];
for (uint32_t i = 0; i < 16; i++)
initial_data[i] = i;
auto cpu_buffer = dev.create_buffer(info, initial_data);
dev.set_name(*cpu_buffer, "cpu-buffer");
// Copy CPU memory into VRAM.
Vulkan::CommandBufferHandle cmd = dev.request_command_buffer(Vulkan::CommandBuffer::Type::Generic);
cmd->copy_buffer(*gpu_buffer, *cpu_buffer);
dev.submit(cmd);
// This functions as garbage collection. Memory is not reclaimed unless this is called regularly.
dev.next_frame_context();
}
int main()
{
// Loads the Vulkan loader dynamically.
// The loader is the entry point to figure out
// which drivers are available on the system.
// The default is:
// - libvulkan.so.1 on Linux (installed with vulkan-icd-loader)
// - vulkan-1.dll (Installed on Windows by your driver or standalone with Vulkan SDK)
// - libvulkan.so on Android (included on OS if it's not comically old)
if (!Vulkan::Context::init_loader(nullptr))
return EXIT_FAILURE;
// The context owns a VkInstance, VkPhysicalDevice and VkDevice.
// Don't enable any optional extensions and fancy features for now.
Vulkan::Context ctx;
if (!ctx.init_instance_and_device(nullptr, 0, nullptr, 0, 0))
return EXIT_FAILURE;
// Doesn't do much real work, but instantiates a logical device that borrows the handles from Context.
Vulkan::Device dev;
dev.set_context(ctx);
// Capturing Vulkan in debuggers is typically done in two ways:
// - Frame captures. Requires the debugger to understand what a "frame" is, typically requires presenting on screen,
// which we're not going to do.
// - Using the RenderDoc API to trigger captures programmatically.
// Needs RenderDoc to be loaded into the process already.
bool has_rdoc = Vulkan::Device::init_renderdoc_capture();
if (has_rdoc)
dev.begin_renderdoc_capture();
run_some_code(dev);
if (has_rdoc)
dev.end_renderdoc_capture();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment