diff options
author | Mitya Selivanov <automainint@guattari.tech> | 2025-02-12 04:45:59 +0100 |
---|---|---|
committer | Mitya Selivanov <automainint@guattari.tech> | 2025-02-12 04:45:59 +0100 |
commit | 20ab9d8de6b5e0422af539276c0b1798021cb0a5 (patch) | |
tree | 03916cb29fddf97bb2539fe799b2a78c221679f6 | |
parent | c6a68596f1b1b37df6db28583137b6f5868c9028 (diff) | |
download | vulkan_compute_minimal_example-20ab9d8de6b5e0422af539276c0b1798021cb0a5.zip |
Refactor
-rw-r--r-- | .gitattributes | 1 | ||||
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | LICENSE | 19 | ||||
-rw-r--r-- | _gen.c | 52 | ||||
-rw-r--r-- | compute_module.comp | 11 | ||||
-rw-r--r-- | compute_module.inl.h | 8 | ||||
-rw-r--r-- | main.c | 479 | ||||
-rwxr-xr-x | vulkan_compute_minimal_example.c | 470 |
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. @@ -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 @@ -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; +} |