summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMitya Selivanov <automainint@guattari.tech>2025-02-12 04:45:59 +0100
committerMitya Selivanov <automainint@guattari.tech>2025-02-12 04:45:59 +0100
commit20ab9d8de6b5e0422af539276c0b1798021cb0a5 (patch)
tree03916cb29fddf97bb2539fe799b2a78c221679f6
parentc6a68596f1b1b37df6db28583137b6f5868c9028 (diff)
downloadvulkan_compute_minimal_example-20ab9d8de6b5e0422af539276c0b1798021cb0a5.zip
Refactor
-rw-r--r--.gitattributes1
-rw-r--r--.gitignore2
-rw-r--r--LICENSE19
-rw-r--r--_gen.c52
-rw-r--r--compute_module.comp11
-rw-r--r--compute_module.inl.h8
-rw-r--r--main.c479
-rwxr-xr-xvulkan_compute_minimal_example.c470
8 files changed, 470 insertions, 572 deletions
diff --git a/.gitattributes b/.gitattributes
deleted file mode 100644
index 176a458..0000000
--- a/.gitattributes
+++ /dev/null
@@ -1 +0,0 @@
-* text=auto
diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index 000224f..0000000
--- a/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-/out_*/
-*.swp
diff --git a/LICENSE b/LICENSE
deleted file mode 100644
index e6cc819..0000000
--- a/LICENSE
+++ /dev/null
@@ -1,19 +0,0 @@
-Copyright (c) 2024 Mitya Selivanov
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/_gen.c b/_gen.c
deleted file mode 100644
index b1e9d30..0000000
--- a/_gen.c
+++ /dev/null
@@ -1,52 +0,0 @@
-#if 0
-SRC=${0##*/}
-BIN=${SRC%.*}
-glslc compute_module.comp -o COMPUTE_MODULE.tmp
-gcc $SRC -o $BIN -lm -lvulkan && ./$BIN && rm $BIN
-rm COMPUTE_MODULE.tmp
-exit 0
-#endif
-
-#include <stdio.h>
-
-int main(int argc, char **argv) {
- FILE *in = fopen("COMPUTE_MODULE.tmp", "rb");
-
- if (in == NULL) {
- printf("Cannot open compiled module code.\n");
- return -1;
- }
-
- FILE *out = fopen("compute_module.inl.h", "wb");
-
- if (out == NULL) {
- printf("Cannot write compiled module inlined data.\n");
- return -1;
- }
-
- fprintf(out, "#ifndef SAMPLE_COMPUTE_COMPUTE_MODULE_INL_H\n");
- fprintf(out, "#define SAMPLE_COMPUTE_COMPUTE_MODULE_INL_H\n");
-
- fprintf(out, "\n");
- fprintf(out, "unsigned COMPUTE_MODULE_CODE[] = {\n ");
-
- while (!feof(in)) {
- int x = 0;
-
- int n = fread(&x, 1, 4, in);
-
- if (n <= 0)
- break;
-
- fprintf(out, " %d,", x);
- }
-
- fprintf(out, "\n};\n\n");
-
- fprintf(out, "#endif\n");
-
- fclose(in);
- fclose(out);
-
- return 0;
-}
diff --git a/compute_module.comp b/compute_module.comp
deleted file mode 100644
index a28192c..0000000
--- a/compute_module.comp
+++ /dev/null
@@ -1,11 +0,0 @@
-#version 450
-
-layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
-
-layout(binding = 0) buffer output_buffer {
- uint values_out[16];
-};
-
-void main() {
- for (uint i = 0; i < 16; i++) values_out[i] = i;
-}
diff --git a/compute_module.inl.h b/compute_module.inl.h
deleted file mode 100644
index 11783a4..0000000
--- a/compute_module.inl.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef SAMPLE_COMPUTE_COMPUTE_MODULE_INL_H
-#define SAMPLE_COMPUTE_COMPUTE_MODULE_INL_H
-
-unsigned COMPUTE_MODULE_CODE[] = {
- 119734787, 65536, 851979, 35, 0, 131089, 1, 393227, 1, 1280527431, 1685353262, 808793134, 0, 196622, 0, 1, 327695, 5, 4, 1852399981, 0, 393232, 4, 17, 1, 1, 1, 196611, 2, 450, 655364, 1197427783, 1279741775, 1885560645, 1953718128, 1600482425, 1701734764, 1919509599, 1769235301, 25974, 524292, 1197427783, 1279741775, 1852399429, 1685417059, 1768185701, 1952671090, 6649449, 262149, 4, 1852399981, 0, 196613, 8, 105, 393221, 20, 1886680431, 1650422901, 1701209717, 114, 393222, 20, 0, 1970037110, 1868526437, 29813, 196613, 22, 0, 262215, 19, 6, 4, 327752, 20, 0, 35, 0, 196679, 20, 3, 262215, 22, 34, 0, 262215, 22, 33, 0, 262215, 34, 11, 25, 131091, 2, 196641, 3, 2, 262165, 6, 32, 0, 262176, 7, 7, 6, 262187, 6, 9, 0, 262187, 6, 16, 16, 131092, 17, 262172, 19, 6, 16, 196638, 20, 19, 262176, 21, 2, 20, 262203, 21, 22, 2, 262165, 23, 32, 1, 262187, 23, 24, 0, 262176, 27, 2, 6, 262187, 23, 30, 1, 262167, 32, 6, 3, 262187, 6, 33, 1, 393260, 32, 34, 33, 33, 33, 327734, 2, 4, 0, 3, 131320, 5, 262203, 7, 8, 7, 196670, 8, 9, 131321, 10, 131320, 10, 262390, 12, 13, 0, 131321, 14, 131320, 14, 262205, 6, 15, 8, 327856, 17, 18, 15, 16, 262394, 18, 11, 12, 131320, 11, 262205, 6, 25, 8, 262205, 6, 26, 8, 393281, 27, 28, 22, 24, 25, 196670, 28, 26, 131321, 13, 131320, 13, 262205, 6, 29, 8, 327808, 6, 31, 29, 30, 196670, 8, 31, 131321, 10, 131320, 12, 65789, 65592,
-};
-
-#endif
diff --git a/main.c b/main.c
deleted file mode 100644
index 05e9999..0000000
--- a/main.c
+++ /dev/null
@@ -1,479 +0,0 @@
-#if 0
-SRC=${0##*/}
-BIN=${SRC%.*}
-gcc $SRC -o $BIN -lm -lvulkan && ./$BIN && rm $BIN
-exit 0
-#endif
-
-#include <string.h>
-#include <stdio.h>
-
-#include <vulkan/vulkan.h>
-
-#include "compute_module.inl.h"
-
-typedef signed char i8;
-typedef signed short i16;
-typedef signed int i32;
-typedef signed long long i64;
-typedef unsigned char u8;
-typedef unsigned short u16;
-typedef unsigned int u32;
-typedef unsigned long long u64;
-typedef float f32;
-typedef double f64;
-typedef char c8;
-
-enum {
- MAX_DEVICE_COUNT = 16,
- MAX_QUEUE_FAMILY_COUNT = 64,
- BUFFER_SIZE = 64,
- GROUP_COUNT_X = 1,
- GROUP_COUNT_Y = 1,
- GROUP_COUNT_Z = 1,
-};
-
-f32 queue_priorities[] = {
- 1.f,
-};
-
-u32 queue_family_index = 0;
-
-VkInstance instance;
-VkPhysicalDevice physical_device;
-VkDevice device;
-VkQueue queue;
-VkBuffer buffer;
-VkDeviceMemory buffer_memory;
-VkDescriptorSetLayout descriptor_set_layout;
-VkDescriptorPool descriptor_pool;
-VkDescriptorSet descriptor_set;
-VkShaderModule compute_module;
-VkPipelineLayout pipeline_layout;
-VkPipeline pipeline;
-VkCommandPool command_pool;
-VkCommandBuffer command_buffer;
-
-i32 main(i32 argc, c8 **argv) {
- // Create instance
- //
- if (vkCreateInstance(
- &(VkInstanceCreateInfo) {
- .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
- .pApplicationInfo =
- &(VkApplicationInfo) {
- .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
- .apiVersion = VK_API_VERSION_1_1,
- },
- },
- NULL, &instance) != VK_SUCCESS) {
- printf("vkCreateInstance failed.\n");
- return -1;
- }
-
- // Find physical device
- //
- {
- u32 device_count = MAX_DEVICE_COUNT;
- VkPhysicalDevice devices[MAX_DEVICE_COUNT];
-
- VkResult res = vkEnumeratePhysicalDevices(instance, &device_count,
- devices);
-
- if (res != VK_SUCCESS && res != VK_INCOMPLETE) {
- printf("vkEnumeratePhysicalDevices failed.\n");
- return -1;
- }
-
- if (device_count <= 0) {
- printf("Compatible physical device not found.\n");
- return -1;
- }
-
- u32 i = 0;
- VkPhysicalDeviceProperties properties;
-
- for (; i < device_count; ++i) {
- vkGetPhysicalDeviceProperties(devices[i], &properties);
-
- if (strstr(properties.deviceName, "NVIDIA") != NULL ||
- strstr(properties.deviceName, "AMD") != NULL) {
- physical_device = devices[i];
- break;
- }
- }
-
- if (i >= device_count)
- physical_device = devices[0];
-
- vkGetPhysicalDeviceProperties(physical_device, &properties);
-
- printf("Physical device selected: %s\n", properties.deviceName);
- }
-
- // Find queue family
- //
- {
- u32 queue_family_count = MAX_QUEUE_FAMILY_COUNT;
- VkQueueFamilyProperties queue_families[MAX_QUEUE_FAMILY_COUNT];
-
- vkGetPhysicalDeviceQueueFamilyProperties(
- physical_device, &queue_family_count, queue_families);
-
- u32 index = 0;
-
- for (; index < queue_family_count; ++index)
- if (queue_families[index].queueCount > 0 &&
- (queue_families[index].queueFlags & VK_QUEUE_COMPUTE_BIT))
- break;
-
- if (index >= queue_family_count) {
- printf("Compatible queue family not found.\n");
- return -1;
- }
-
- queue_family_index = index;
- }
-
- // Create logical device
- //
- {
- VkPhysicalDeviceFeatures device_features;
- memset(&device_features, 0, sizeof device_features);
-
- if (vkCreateDevice(
- physical_device,
- &(VkDeviceCreateInfo) {
- .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
- .pQueueCreateInfos =
- &(VkDeviceQueueCreateInfo) {
- .sType =
- VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
- .queueCount = 1,
- .pQueuePriorities = queue_priorities,
- .queueFamilyIndex = queue_family_index,
- },
- .queueCreateInfoCount = 1,
- .pEnabledFeatures = &device_features,
- },
- NULL, &device) != VK_SUCCESS) {
- printf("vkCreateDevice failed.\n");
- return -1;
- }
-
- vkGetDeviceQueue(device, queue_family_index, 0, &queue);
- }
-
- // Create buffer
- //
- {
- if (vkCreateBuffer(
- device,
- &(VkBufferCreateInfo) {
- .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
- .size = BUFFER_SIZE,
- .usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
- .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
- },
- NULL, &buffer) != VK_SUCCESS) {
- printf("vkCreateBuffer failed.\n");
- return -1;
- }
-
- VkMemoryRequirements memory_requirements;
- VkPhysicalDeviceMemoryProperties memory_properties;
-
- vkGetBufferMemoryRequirements(device, buffer,
- &memory_requirements);
-
- vkGetPhysicalDeviceMemoryProperties(physical_device,
- &memory_properties);
-
- u32 i = 0;
- u32 properties = VK_MEMORY_PROPERTY_HOST_COHERENT_BIT |
- VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
- u32 memory_type_index = 0;
-
- for (; i < memory_properties.memoryTypeCount; ++i)
- if ((memory_requirements.memoryTypeBits & (1 << i)) &&
- ((memory_properties.memoryTypes[i].propertyFlags &
- properties) == properties)) {
- memory_type_index = i;
- break;
- }
-
- if (i >= memory_properties.memoryTypeCount) {
- printf("Compatible memory properties not found.\n");
- return -1;
- }
-
- if (vkAllocateMemory(
- device,
- &(VkMemoryAllocateInfo) {
- .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
- .allocationSize = memory_requirements.size,
- .memoryTypeIndex = memory_type_index,
- },
- NULL, &buffer_memory) != VK_SUCCESS) {
- printf("vkAllocateMemory failed.\n");
- return -1;
- }
-
- if (vkBindBufferMemory(device, buffer, buffer_memory, 0) !=
- VK_SUCCESS) {
- printf("vkBindBufferMemory failed.\n");
- return -1;
- }
- }
-
- // Create descriptor set layout
- //
- if (vkCreateDescriptorSetLayout(
- device,
- &(VkDescriptorSetLayoutCreateInfo) {
- .sType =
- VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
- .bindingCount = 1,
- .pBindings =
- &(VkDescriptorSetLayoutBinding) {
- .binding = 0,
- .descriptorType =
- VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
- .descriptorCount = 1,
- .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
- },
- },
- NULL, &descriptor_set_layout) != VK_SUCCESS) {
- printf("vkCreateDescriptorSetLayout failed.\n");
- return -1;
- }
-
- // Create descriptor set
- //
- {
- if (vkCreateDescriptorPool(
- device,
- &(VkDescriptorPoolCreateInfo) {
- .sType =
- VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
- .maxSets = 1,
- .poolSizeCount = 1,
- .pPoolSizes =
- &(VkDescriptorPoolSize) {
- .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
- .descriptorCount = 1,
- },
- },
- NULL, &descriptor_pool) != VK_SUCCESS) {
- printf("vkCreateDescriptorPool failed.\n");
- return -1;
- }
-
- if (vkAllocateDescriptorSets(
- device,
- &(VkDescriptorSetAllocateInfo) {
- .sType =
- VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
- .descriptorPool = descriptor_pool,
- .descriptorSetCount = 1,
- .pSetLayouts = &descriptor_set_layout,
- },
- &descriptor_set) != VK_SUCCESS) {
- printf("vkAllocateDescriptorSets failed.\n");
- return -1;
- }
-
- vkUpdateDescriptorSets(
- device, 1,
- &(VkWriteDescriptorSet) {
- .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
- .dstSet = descriptor_set,
- .dstBinding = 0,
- .descriptorCount = 1,
- .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
- .pBufferInfo =
- &(VkDescriptorBufferInfo) {
- .buffer = buffer,
- .offset = 0,
- .range = BUFFER_SIZE,
- },
- },
- 0, NULL);
- }
-
- // Create compute pipeline
- //
- {
- if (vkCreateShaderModule(
- device,
- &(VkShaderModuleCreateInfo) {
- .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
- .pCode = COMPUTE_MODULE_CODE,
- .codeSize = sizeof COMPUTE_MODULE_CODE,
- },
- NULL, &compute_module) != VK_SUCCESS) {
- printf("vkCreateShaderModule failed.\n");
- return -1;
- }
-
- if (vkCreatePipelineLayout(
- device,
- &(VkPipelineLayoutCreateInfo) {
- .sType =
- VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
- .setLayoutCount = 1,
- .pSetLayouts = &descriptor_set_layout,
- },
- NULL, &pipeline_layout) != VK_SUCCESS) {
- printf("vkCreatePipelineLayout failed.\n");
- return -1;
- }
-
- if (vkCreateComputePipelines(
- device,
- VK_NULL_HANDLE,
- 1,
- &(VkComputePipelineCreateInfo) {
- .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
- .stage = {
- .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
- .stage = VK_SHADER_STAGE_COMPUTE_BIT,
- .module = compute_module,
- .pName = "main",
- },
- .layout = pipeline_layout,
- },
- NULL,
- &pipeline
- ) != VK_SUCCESS) {
- printf("vkCreateComputePipelines failed.\n");
- return 0;
- }
- }
-
- // Create command buffer
- //
- {
- if (vkCreateCommandPool(
- device,
- &(VkCommandPoolCreateInfo) {
- .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
- .queueFamilyIndex = queue_family_index,
- },
- NULL, &command_pool) != VK_SUCCESS) {
- printf("vkCreateCommandPool failed.\n");
- return -1;
- }
-
- if (vkAllocateCommandBuffers(
- device,
- &(VkCommandBufferAllocateInfo) {
- .sType =
- VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
- .commandPool = command_pool,
- .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
- .commandBufferCount = 1,
- },
- &command_buffer) != VK_SUCCESS) {
- printf("vkAllocateCommandBuffers failed.\n");
- return -1;
- }
-
- if (vkBeginCommandBuffer(
- command_buffer,
- &(VkCommandBufferBeginInfo) {
- .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
- .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
- }) != VK_SUCCESS) {
- printf("vkBeginCommandBuffer failed.\n");
- return -1;
- }
-
- vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE,
- pipeline);
-
- vkCmdBindDescriptorSets(
- command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE,
- pipeline_layout, 0, 1, &descriptor_set, 0, NULL);
-
- vkCmdDispatch(command_buffer, GROUP_COUNT_X, GROUP_COUNT_Y,
- GROUP_COUNT_Z);
-
- if (vkEndCommandBuffer(command_buffer) != VK_SUCCESS) {
- printf("vkEndCommandBuffer failed.\n");
- return -1;
- }
- }
-
- // Run command buffer
- //
- {
- VkFence fence;
-
- if (vkCreateFence(
- device,
- &(VkFenceCreateInfo) {
- .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
- },
- NULL, &fence) != VK_SUCCESS) {
- printf("vkCreateFence failed.\n");
- return -1;
- }
-
- if (vkQueueSubmit(queue, 1,
- &(VkSubmitInfo) {
- .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
- .commandBufferCount = 1,
- .pCommandBuffers = &command_buffer,
- },
- fence) != VK_SUCCESS) {
- printf("vkQueueSubmit failed.\n");
- return -1;
- }
-
- if (vkWaitForFences(device, 1, &fence, VK_TRUE, 100000000000) !=
- VK_SUCCESS) {
- printf("vkWaitForFences failed.\n");
- return -1;
- }
-
- vkDestroyFence(device, fence, NULL);
- }
-
- // Read output buffer
- //
- {
- u32 *p = NULL;
-
- if (vkMapMemory(device, buffer_memory, 0, BUFFER_SIZE, 0,
- (void **) &p) != VK_SUCCESS) {
- printf("vkMapMemory failed.\n");
- return -1;
- }
-
- printf("Data:");
- for (u32 i = 0; i < BUFFER_SIZE / 4; i++)
- printf(" %2d", (int) p[i]);
- printf("\n");
-
- vkUnmapMemory(device, buffer_memory);
- }
-
- // Cleanup
- //
- {
- vkFreeMemory(device, buffer_memory, NULL);
- vkDestroyBuffer(device, buffer, NULL);
- vkDestroyShaderModule(device, compute_module, NULL);
- vkDestroyDescriptorPool(device, descriptor_pool, NULL);
- vkDestroyDescriptorSetLayout(device, descriptor_set_layout, NULL);
- vkDestroyPipelineLayout(device, pipeline_layout, NULL);
- vkDestroyPipeline(device, pipeline, NULL);
- vkDestroyCommandPool(device, command_pool, NULL);
- vkDestroyDevice(device, NULL);
- vkDestroyInstance(instance, NULL);
- }
-
- printf("OK\n");
- return 0;
-}
diff --git a/vulkan_compute_minimal_example.c b/vulkan_compute_minimal_example.c
new file mode 100755
index 0000000..26f7e34
--- /dev/null
+++ b/vulkan_compute_minimal_example.c
@@ -0,0 +1,470 @@
+#if 0 /*
+#/ ================================================================
+#/
+#/ vulkan_compute_minimal_example.c
+#/
+#/ ----------------------------------------------------------------
+#/
+#/ (C) 2025 Mitya Selivanov <guattari.tech>
+#/
+#/ ================================================================
+#/
+#/ COMPUTE SHADER SOURCE CODE
+#/
+#/ ================================================================
+cat <<EOF >~module.comp
+
+#version 450
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+layout(binding = 0) buffer output_buffer {
+ uint values_out[16];
+};
+void main() {
+ for (uint i = 0; i < 16; i++) values_out[i] = i;
+}
+
+EOF
+#/ ================================================================
+#/
+#/ BUILD AND RUN SCRIPT
+#/
+#/ ================================================================
+
+SRC=${0##*./}
+BIN=${SRC%.*}
+glslc ~module.comp -o ~module.spv && gcc $SRC -o $BIN -lm -lvulkan && ./$BIN
+STATUS=$?
+rm -f $BIN
+rm -f ~module.comp
+rm -f ~module.spv
+exit $STATUS # */
+#endif
+
+// ================================================================
+//
+// C SOURCE CODE
+//
+// ================================================================
+
+#include <string.h>
+#include <stdio.h>
+
+#include <vulkan/vulkan.h>
+
+typedef signed i32;
+typedef unsigned u32;
+typedef float f32;
+typedef char c8;
+
+enum {
+ MAX_DEVICE_COUNT = 16,
+ MAX_QUEUE_FAMILY_COUNT = 64,
+ BUFFER_SIZE = 64,
+ GROUP_COUNT_X = 1,
+ GROUP_COUNT_Y = 1,
+ GROUP_COUNT_Z = 1,
+};
+
+i32 main(i32 argc, c8 **argv) {
+ i32 status = 0;
+ u32 queue_family_index = 0;
+
+ VkInstance instance = NULL;
+ VkPhysicalDevice physical_device = NULL;
+ VkDevice device = NULL;
+ VkQueue queue = NULL;
+ VkBuffer buffer = NULL;
+ VkDeviceMemory buffer_memory = NULL;
+ VkDescriptorSetLayout descriptor_set_layout = NULL;
+ VkDescriptorPool descriptor_pool = NULL;
+ VkDescriptorSet descriptor_set = NULL;
+ VkShaderModule compute_module = NULL;
+ VkPipelineLayout pipeline_layout = NULL;
+ VkPipeline pipeline = NULL;
+ VkCommandPool command_pool = NULL;
+ VkCommandBuffer command_buffer = NULL;
+ VkFence fence = NULL;
+
+ if (vkCreateInstance(&(VkInstanceCreateInfo) {
+ .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
+ .pApplicationInfo = &(VkApplicationInfo) {
+ .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
+ .apiVersion = VK_API_VERSION_1_1,
+ },
+ }, NULL, &instance) != VK_SUCCESS) {
+ printf("vkCreateInstance failed.\n");
+ status = -1;
+ goto _cleanup;
+ }
+
+ // Find physical device
+ {
+ u32 device_count = MAX_DEVICE_COUNT;
+ VkPhysicalDevice devices[MAX_DEVICE_COUNT];
+
+ VkResult res = vkEnumeratePhysicalDevices(instance, &device_count, devices);
+
+ if (res != VK_SUCCESS && res != VK_INCOMPLETE) {
+ printf("vkEnumeratePhysicalDevices failed.\n");
+ status = -1;
+ goto _cleanup;
+ }
+
+ if (device_count <= 0) {
+ printf("Compatible physical device not found.\n");
+ status = -1;
+ goto _cleanup;
+ }
+
+ u32 i = 0;
+ VkPhysicalDeviceProperties properties;
+
+ for (; i < device_count; ++i) {
+ vkGetPhysicalDeviceProperties(devices[i], &properties);
+
+ if (strstr(properties.deviceName, "NVIDIA") != NULL || strstr(properties.deviceName, "AMD") != NULL) {
+ physical_device = devices[i];
+ break;
+ }
+ }
+
+ if (i >= device_count)
+ physical_device = devices[0];
+
+ vkGetPhysicalDeviceProperties(physical_device, &properties);
+
+ printf("Physical device selected: %s\n", properties.deviceName);
+ }
+
+ // Find queue family
+ {
+ u32 queue_family_count = MAX_QUEUE_FAMILY_COUNT;
+ VkQueueFamilyProperties queue_families[MAX_QUEUE_FAMILY_COUNT];
+
+ vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_family_count, queue_families);
+
+ u32 index = 0;
+
+ for (; index < queue_family_count; ++index)
+ if (queue_families[index].queueCount > 0 && (queue_families[index].queueFlags & VK_QUEUE_COMPUTE_BIT))
+ break;
+
+ if (index >= queue_family_count) {
+ printf("Compatible queue family not found.\n");
+ status = -1;
+ goto _cleanup;
+ }
+
+ queue_family_index = index;
+ }
+
+ // Create logical device
+ {
+ VkPhysicalDeviceFeatures device_features;
+ memset(&device_features, 0, sizeof device_features);
+
+ if (vkCreateDevice(physical_device, &(VkDeviceCreateInfo) {
+ .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
+ .pQueueCreateInfos = &(VkDeviceQueueCreateInfo) {
+ .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
+ .queueCount = 1,
+ .pQueuePriorities = (f32[1]) { 1.f, },
+ .queueFamilyIndex = queue_family_index,
+ },
+ .queueCreateInfoCount = 1,
+ .pEnabledFeatures = &device_features,
+ }, NULL, &device) != VK_SUCCESS) {
+ printf("vkCreateDevice failed.\n");
+ status = -1;
+ goto _cleanup;
+ }
+
+ vkGetDeviceQueue(device, queue_family_index, 0, &queue);
+ }
+
+ // Create buffer
+ {
+ if (vkCreateBuffer(device, &(VkBufferCreateInfo) {
+ .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
+ .size = BUFFER_SIZE,
+ .usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
+ .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
+ }, NULL, &buffer) != VK_SUCCESS) {
+ printf("vkCreateBuffer failed.\n");
+ status = -1;
+ goto _cleanup;
+ }
+
+ VkMemoryRequirements memory_requirements;
+ VkPhysicalDeviceMemoryProperties memory_properties;
+
+ vkGetBufferMemoryRequirements(device, buffer, &memory_requirements);
+ vkGetPhysicalDeviceMemoryProperties(physical_device, &memory_properties);
+
+ u32 i = 0;
+ u32 properties = VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
+ u32 memory_type_index = 0;
+
+ for (; i < memory_properties.memoryTypeCount; ++i)
+ if ((memory_requirements.memoryTypeBits & (1 << i)) && ((memory_properties.memoryTypes[i].propertyFlags & properties) == properties)) {
+ memory_type_index = i;
+ break;
+ }
+
+ if (i >= memory_properties.memoryTypeCount) {
+ printf("Compatible memory properties not found.\n");
+ status = -1;
+ goto _cleanup;
+ }
+
+ if (vkAllocateMemory(device, &(VkMemoryAllocateInfo) {
+ .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
+ .allocationSize = memory_requirements.size,
+ .memoryTypeIndex = memory_type_index,
+ }, NULL, &buffer_memory) != VK_SUCCESS) {
+ printf("vkAllocateMemory failed.\n");
+ status = -1;
+ goto _cleanup;
+ }
+
+ if (vkBindBufferMemory(device, buffer, buffer_memory, 0) != VK_SUCCESS) {
+ printf("vkBindBufferMemory failed.\n");
+ status = -1;
+ goto _cleanup;
+ }
+ }
+
+ if (vkCreateDescriptorSetLayout(device, &(VkDescriptorSetLayoutCreateInfo) {
+ .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
+ .bindingCount = 1,
+ .pBindings = &(VkDescriptorSetLayoutBinding) {
+ .binding = 0,
+ .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
+ .descriptorCount = 1,
+ .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
+ },
+ }, NULL, &descriptor_set_layout) != VK_SUCCESS) {
+ printf("vkCreateDescriptorSetLayout failed.\n");
+ status = -1;
+ goto _cleanup;
+ }
+
+ // Create descriptor set
+ {
+ if (vkCreateDescriptorPool(device, &(VkDescriptorPoolCreateInfo) {
+ .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
+ .maxSets = 1,
+ .poolSizeCount = 1,
+ .pPoolSizes = &(VkDescriptorPoolSize) {
+ .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
+ .descriptorCount = 1,
+ },
+ }, NULL, &descriptor_pool) != VK_SUCCESS) {
+ printf("vkCreateDescriptorPool failed.\n");
+ status = -1;
+ goto _cleanup;
+ }
+
+ if (vkAllocateDescriptorSets(device, &(VkDescriptorSetAllocateInfo) {
+ .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
+ .descriptorPool = descriptor_pool,
+ .descriptorSetCount = 1,
+ .pSetLayouts = &descriptor_set_layout,
+ }, &descriptor_set) != VK_SUCCESS) {
+ printf("vkAllocateDescriptorSets failed.\n");
+ status = -1;
+ goto _cleanup;
+ }
+
+ vkUpdateDescriptorSets(device, 1, &(VkWriteDescriptorSet) {
+ .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
+ .dstSet = descriptor_set,
+ .dstBinding = 0,
+ .descriptorCount = 1,
+ .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
+ .pBufferInfo = &(VkDescriptorBufferInfo) {
+ .buffer = buffer,
+ .offset = 0,
+ .range = BUFFER_SIZE,
+ },
+ }, 0, NULL);
+ }
+
+ // Create compute pipeline
+ {
+ FILE *f = fopen("~module.spv", "rb");
+ if (f == NULL) {
+ printf("fopen failed.\n");
+ status = -1;
+ goto _cleanup;
+ }
+ static u32 code[4096];
+ u32 n = fread(code, 1, sizeof code, f);
+ fclose(f);
+
+ if (vkCreateShaderModule(device, &(VkShaderModuleCreateInfo) {
+ .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
+ .pCode = code,
+ .codeSize = n,
+ }, NULL, &compute_module) != VK_SUCCESS) {
+ printf("vkCreateShaderModule failed.\n");
+ status = -1;
+ goto _cleanup;
+ }
+
+ if (vkCreatePipelineLayout(device, &(VkPipelineLayoutCreateInfo) {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
+ .setLayoutCount = 1,
+ .pSetLayouts = &descriptor_set_layout,
+ }, NULL, &pipeline_layout) != VK_SUCCESS) {
+ printf("vkCreatePipelineLayout failed.\n");
+ status = -1;
+ goto _cleanup;
+ }
+
+ if (vkCreateComputePipelines(device, VK_NULL_HANDLE, 1, &(VkComputePipelineCreateInfo) {
+ .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
+ .stage = {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
+ .stage = VK_SHADER_STAGE_COMPUTE_BIT,
+ .module = compute_module,
+ .pName = "main",
+ },
+ .layout = pipeline_layout,
+ }, NULL, &pipeline) != VK_SUCCESS) {
+ printf("vkCreateComputePipelines failed.\n");
+ status = -1;
+ goto _cleanup;
+ }
+ }
+
+ // Create command buffer
+ {
+ if (vkCreateCommandPool(device, &(VkCommandPoolCreateInfo) {
+ .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
+ .queueFamilyIndex = queue_family_index,
+ }, NULL, &command_pool) != VK_SUCCESS) {
+ printf("vkCreateCommandPool failed.\n");
+ status = -1;
+ goto _cleanup;
+ }
+
+ if (vkAllocateCommandBuffers(device, &(VkCommandBufferAllocateInfo) {
+ .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
+ .commandPool = command_pool,
+ .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
+ .commandBufferCount = 1,
+ }, &command_buffer) != VK_SUCCESS) {
+ printf("vkAllocateCommandBuffers failed.\n");
+ status = -1;
+ goto _cleanup;
+ }
+
+ if (vkBeginCommandBuffer(command_buffer, &(VkCommandBufferBeginInfo) {
+ .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
+ .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
+ }) != VK_SUCCESS) {
+ printf("vkBeginCommandBuffer failed.\n");
+ status = -1;
+ goto _cleanup;
+ }
+
+ vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline);
+ vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout, 0, 1, &descriptor_set, 0, NULL);
+ vkCmdDispatch(command_buffer, GROUP_COUNT_X, GROUP_COUNT_Y, GROUP_COUNT_Z);
+
+ if (vkEndCommandBuffer(command_buffer) != VK_SUCCESS) {
+ printf("vkEndCommandBuffer failed.\n");
+ status = -1;
+ goto _cleanup;
+ }
+ }
+
+ // Run command buffer
+ {
+ if (vkCreateFence(device, &(VkFenceCreateInfo) { .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, }, NULL, &fence) != VK_SUCCESS) {
+ printf("vkCreateFence failed.\n");
+ status = -1;
+ goto _cleanup;
+ }
+
+ if (vkQueueSubmit(queue, 1, &(VkSubmitInfo) {
+ .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
+ .commandBufferCount = 1,
+ .pCommandBuffers = &command_buffer,
+ }, fence) != VK_SUCCESS) {
+ printf("vkQueueSubmit failed.\n");
+ status = -1;
+ goto _cleanup;
+ }
+
+ if (vkWaitForFences(device, 1, &fence, VK_TRUE, 100000000000) != VK_SUCCESS) {
+ printf("vkWaitForFences failed.\n");
+ status = -1;
+ goto _cleanup;
+ }
+ }
+
+ // Read output buffer
+ {
+ u32 *p = NULL;
+
+ if (vkMapMemory(device, buffer_memory, 0, BUFFER_SIZE, 0, (void **) &p) != VK_SUCCESS) {
+ printf("vkMapMemory failed.\n");
+ status = -1;
+ goto _cleanup;
+ }
+
+ printf("Data:");
+ for (u32 i = 0; i < BUFFER_SIZE / 4; i++)
+ printf(" %2d", (int) p[i]);
+ printf("\n");
+
+ vkUnmapMemory(device, buffer_memory);
+ }
+
+_cleanup:
+ {
+ if (fence != NULL)
+ vkDestroyFence(device, fence, NULL);
+ if (buffer_memory != NULL)
+ vkFreeMemory(device, buffer_memory, NULL);
+ if (buffer != NULL)
+ vkDestroyBuffer(device, buffer, NULL);
+ if (compute_module != NULL)
+ vkDestroyShaderModule(device, compute_module, NULL);
+ if (descriptor_pool != NULL)
+ vkDestroyDescriptorPool(device, descriptor_pool, NULL);
+ if (descriptor_set_layout != NULL)
+ vkDestroyDescriptorSetLayout(device, descriptor_set_layout, NULL);
+ if (pipeline_layout != NULL)
+ vkDestroyPipelineLayout(device, pipeline_layout, NULL);
+ if (pipeline != NULL)
+ vkDestroyPipeline(device, pipeline, NULL);
+ if (command_pool != NULL)
+ vkDestroyCommandPool(device, command_pool, NULL);
+ if (device != NULL)
+ vkDestroyDevice(device, NULL);
+ if (instance != NULL)
+ vkDestroyInstance(instance, NULL);
+
+ instance = NULL;
+ physical_device = NULL;
+ device = NULL;
+ queue = NULL;
+ buffer = NULL;
+ buffer_memory = NULL;
+ descriptor_set_layout = NULL;
+ descriptor_pool = NULL;
+ descriptor_set = NULL;
+ compute_module = NULL;
+ pipeline_layout = NULL;
+ pipeline = NULL;
+ command_pool = NULL;
+ command_buffer = NULL;
+ fence = NULL;
+ }
+
+ printf("OK\n");
+ return status;
+}