diff options
author | Mitya Selivanov <automainint@guattari.tech> | 2024-02-11 00:23:20 +0100 |
---|---|---|
committer | Mitya Selivanov <automainint@guattari.tech> | 2024-02-11 00:23:20 +0100 |
commit | 6cb08bbe4937f9122b0b6712d8674c3085b57349 (patch) | |
tree | c3f35955404784f72cdcb86e5857c2ac94c0b204 | |
download | vulkan_compute_minimal_example-6cb08bbe4937f9122b0b6712d8674c3085b57349.zip |
Add code
-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 | 489 |
4 files changed, 560 insertions, 0 deletions
@@ -0,0 +1,52 @@ +#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 new file mode 100644 index 0000000..a28192c --- /dev/null +++ b/compute_module.comp @@ -0,0 +1,11 @@ +#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 new file mode 100644 index 0000000..11783a4 --- /dev/null +++ b/compute_module.inl.h @@ -0,0 +1,8 @@ +#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 @@ -0,0 +1,489 @@ +#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 signed 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; + +int main(int argc, char **argv) { + // Create instance + // + { + VkApplicationInfo info_application = { + .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, + .apiVersion = VK_API_VERSION_1_1, + }; + + VkInstanceCreateInfo info_instance_create = { + .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, + .pApplicationInfo = &info_application, + }; + + if (vkCreateInstance(&info_instance_create, 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 + // + { + VkDeviceQueueCreateInfo info_queue_create = { + .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, + .queueCount = 1, + .pQueuePriorities = queue_priorities, + .queueFamilyIndex = queue_family_index, + }; + + VkPhysicalDeviceFeatures device_features; + memset(&device_features, 0, sizeof device_features); + + VkDeviceCreateInfo info_device_create = { + .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, + .pQueueCreateInfos = &info_queue_create, + .queueCreateInfoCount = 1, + .pEnabledFeatures = &device_features, + }; + + if (vkCreateDevice(physical_device, &info_device_create, NULL, + &device) != VK_SUCCESS) { + printf("vkCreateDevice failed.\n"); + return -1; + } + + vkGetDeviceQueue(device, queue_family_index, 0, &queue); + } + + // Create buffer + // + { + VkBufferCreateInfo info_buffer_create = { + .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, + .size = BUFFER_SIZE, + .usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, + .sharingMode = VK_SHARING_MODE_EXCLUSIVE, + }; + + if (vkCreateBuffer(device, &info_buffer_create, NULL, &buffer) != + VK_SUCCESS) { + printf("vkCreateBuffer failed.\n"); + return -1; + } + + VkMemoryRequirements memory_requirements; + VkPhysicalDeviceMemoryProperties memory_properties; + + vkGetBufferMemoryRequirements(device, buffer, + &memory_requirements); + + VkMemoryAllocateInfo info_allocate = { + .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, + .allocationSize = memory_requirements.size, + }; + + vkGetPhysicalDeviceMemoryProperties(physical_device, + &memory_properties); + + u32 i = 0; + u32 properties = VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; + + for (; i < memory_properties.memoryTypeCount; ++i) + if ((memory_requirements.memoryTypeBits & (1 << i)) && + ((memory_properties.memoryTypes[i].propertyFlags & + properties) == properties)) { + info_allocate.memoryTypeIndex = i; + break; + } + + if (i >= memory_properties.memoryTypeCount) { + printf("Compatible memory properties not found.\n"); + return -1; + } + + if (vkAllocateMemory(device, &info_allocate, 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 + // + { + VkDescriptorSetLayoutBinding descriptor_set_layout_binding = { + .binding = 0, + .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .descriptorCount = 1, + .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT, + }; + + VkDescriptorSetLayoutCreateInfo + info_descriptor_set_layout_create = { + .sType = + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, + .bindingCount = 1, + .pBindings = &descriptor_set_layout_binding, + }; + + if (vkCreateDescriptorSetLayout( + device, &info_descriptor_set_layout_create, NULL, + &descriptor_set_layout) != VK_SUCCESS) { + printf("vkCreateDescriptorSetLayout failed.\n"); + return -1; + } + } + + // Create descriptor set + // + { + VkDescriptorPoolSize descriptor_pool_size = { + .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .descriptorCount = 1, + }; + + VkDescriptorPoolCreateInfo info_descriptor_pool_create = { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, + .maxSets = 1, + .poolSizeCount = 1, + .pPoolSizes = &descriptor_pool_size, + }; + + if (vkCreateDescriptorPool(device, &info_descriptor_pool_create, + NULL, + &descriptor_pool) != VK_SUCCESS) { + printf("vkCreateDescriptorPool failed.\n"); + return -1; + } + + VkDescriptorSetAllocateInfo info_descriptor_set_allocate = { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, + .descriptorPool = descriptor_pool, + .descriptorSetCount = 1, + .pSetLayouts = &descriptor_set_layout, + }; + + if (vkAllocateDescriptorSets(device, + &info_descriptor_set_allocate, + &descriptor_set) != VK_SUCCESS) { + printf("vkAllocateDescriptorSets failed.\n"); + return -1; + } + + VkDescriptorBufferInfo info_descriptor_buffer = { + .buffer = buffer, + .offset = 0, + .range = BUFFER_SIZE, + }; + + VkWriteDescriptorSet write_descriptor_set = { + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .dstSet = descriptor_set, + .dstBinding = 0, + .descriptorCount = 1, + .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .pBufferInfo = &info_descriptor_buffer, + }; + + vkUpdateDescriptorSets(device, 1, &write_descriptor_set, 0, NULL); + } + + // Create compute pipeline + // + { + VkShaderModuleCreateInfo info_module_create = { + .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, + .pCode = COMPUTE_MODULE_CODE, + .codeSize = sizeof COMPUTE_MODULE_CODE, + }; + + if (vkCreateShaderModule(device, &info_module_create, NULL, + &compute_module) != VK_SUCCESS) { + printf("vkCreateShaderModule failed.\n"); + return -1; + } + + VkPipelineShaderStageCreateInfo info_shader_stage_create = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .stage = VK_SHADER_STAGE_COMPUTE_BIT, + .module = compute_module, + .pName = "main", + }; + + VkPipelineLayoutCreateInfo info_pipeline_layout_create = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, + .setLayoutCount = 1, + .pSetLayouts = &descriptor_set_layout, + }; + + if (vkCreatePipelineLayout(device, &info_pipeline_layout_create, + NULL, + &pipeline_layout) != VK_SUCCESS) { + printf("vkCreatePipelineLayout failed.\n"); + return -1; + } + + VkComputePipelineCreateInfo info_pipeline_create = { + .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, + .stage = info_shader_stage_create, + .layout = pipeline_layout, + }; + + if (vkCreateComputePipelines(device, VK_NULL_HANDLE, 1, + &info_pipeline_create, NULL, + &pipeline)) { + printf("vkCreateComputePipelines failed.\n"); + return 0; + } + } + + // Create command buffer + // + { + VkCommandPoolCreateInfo info_command_pool_create = { + .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, + .queueFamilyIndex = queue_family_index, + }; + + if (vkCreateCommandPool(device, &info_command_pool_create, NULL, + &command_pool) != VK_SUCCESS) { + printf("vkCreateCommandPool failed.\n"); + return -1; + } + + VkCommandBufferAllocateInfo info_command_buffer_allocate = { + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, + .commandPool = command_pool, + .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, + .commandBufferCount = 1, + }; + + if (vkAllocateCommandBuffers(device, + &info_command_buffer_allocate, + &command_buffer) != VK_SUCCESS) { + printf("vkAllocateCommandBuffers failed.\n"); + return -1; + } + + VkCommandBufferBeginInfo info_begin = { + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, + .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, + }; + + if (vkBeginCommandBuffer(command_buffer, &info_begin) != + 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 + // + { + VkSubmitInfo info_submit = { + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, + .commandBufferCount = 1, + .pCommandBuffers = &command_buffer, + }; + + VkFenceCreateInfo info_fence_create = { + .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, + }; + + VkFence fence; + + if (vkCreateFence(device, &info_fence_create, NULL, &fence) != + VK_SUCCESS) { + printf("vkCreateFence failed.\n"); + return -1; + } + + if (vkQueueSubmit(queue, 1, &info_submit, 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; +} |