Created
October 4, 2025 11:01
-
-
Save Themaister/a60044a1fd292621bb08cd200e871016 to your computer and use it in GitHub Desktop.
Bringup sample #2 - Most basic compute
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #version 460 | |
| // The version doesn't matter as much in Vulkan GLSL. This is the last version. | |
| // In GLSL we have to enable special features as we use them. | |
| #extension GL_EXT_buffer_reference : require | |
| // For every workgroup, there is 16 threads. | |
| layout(local_size_x = 16) in; | |
| // Declares a pointer to data. | |
| layout(buffer_reference, buffer_reference_align = 16) writeonly buffer Output | |
| { | |
| uint data[]; | |
| }; | |
| layout(buffer_reference, buffer_reference_align = 16) readonly buffer Input | |
| { | |
| uint data[]; | |
| }; | |
| // Push constants is the most straight forward way to send data to a dispatch. | |
| layout(push_constant) uniform Registers | |
| { | |
| Output o; // 64-bit pointers. | |
| Input i; | |
| }; | |
| void main() | |
| { | |
| o.data[gl_GlobalInvocationID.x] = i.data[gl_GlobalInvocationID.x]; | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include "device.hpp" | |
| #include "context.hpp" | |
| #include "logging.hpp" | |
| #include <stdlib.h> | |
| static const uint32_t copy_shader[] = | |
| #include "copy.h" | |
| ; | |
| static void run_some_code(Vulkan::Device &dev) | |
| { | |
| if (!dev.get_device_features().vk12_features.bufferDeviceAddress) | |
| { | |
| LOGE("This device does not support BDA for some reason ...\n"); | |
| return; | |
| } | |
| Vulkan::BufferCreateInfo info = {}; | |
| info.size = 64; | |
| // Memory should live in VRAM. | |
| info.domain = Vulkan::BufferDomain::Device; | |
| info.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; | |
| 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"); | |
| Vulkan::Program *prog = dev.request_program(copy_shader, sizeof(copy_shader)); | |
| struct | |
| { | |
| VkDeviceAddress dst_addr; // GPU pointers are always 64-bit. | |
| VkDeviceAddress src_addr; | |
| } push = {}; | |
| // Copy CPU memory into VRAM, but using shaders. | |
| Vulkan::CommandBufferHandle cmd = dev.request_command_buffer(Vulkan::CommandBuffer::Type::Generic); | |
| cmd->set_program(prog); | |
| // Send GPU pointers as push parameters. | |
| // We can send at least 128 bytes this way. | |
| // We're juggling with scissors now. If this goes wrong, we can crash the GPU. | |
| push.dst_addr = gpu_buffer->get_device_address(); | |
| push.src_addr = cpu_buffer->get_device_address(); | |
| cmd->push_constants(&push, 0, sizeof(push)); | |
| cmd->dispatch(1, 1, 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, 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