Skip to content

Instantly share code, notes, and snippets.

@Themaister
Created October 5, 2025 11:39
Show Gist options
  • Save Themaister/dcbcb8dfaa4c1e9877008895f501e6b6 to your computer and use it in GitHub Desktop.
Save Themaister/dcbcb8dfaa4c1e9877008895f501e6b6 to your computer and use it in GitHub Desktop.
Bringup sample #4 - Mandelbulb
#include "device.hpp"
#include "context.hpp"
#include "logging.hpp"
#include <stdlib.h>
static const uint32_t mandelbulb_shader[] =
#include "mandelbulb.h"
;
static void run_some_code(Vulkan::Device &dev)
{
auto info = Vulkan::ImageCreateInfo::immutable_2d_image(1280, 720, VK_FORMAT_R8G8B8A8_UNORM);
info.usage = VK_IMAGE_USAGE_STORAGE_BIT;
// Image layouts comes into play later.
info.initial_layout = VK_IMAGE_LAYOUT_GENERAL;
Vulkan::ImageHandle img = dev.create_image(info);
Vulkan::Program *prog = dev.request_program(mandelbulb_shader, sizeof(mandelbulb_shader));
// Copy CPU memory into VRAM, but using shaders.
Vulkan::CommandBufferHandle cmd = dev.request_command_buffer(Vulkan::CommandBuffer::Type::Generic);
cmd->set_program(prog);
cmd->set_storage_texture(0, 0, img->get_view());
constexpr uint32_t workgroup_size_x = 8;
constexpr uint32_t workgroup_size_y = 8;
struct
{
float width, height;
float time;
} push = {};
push.width = info.width;
push.height = info.height;
push.time = 4.55f;
cmd->push_constants(&push, 0, sizeof(push));
cmd->dispatch(1280 / workgroup_size_x, 720 / workgroup_size_y, 1);
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))
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