diff --git a/Examples/Vulkan/main.c b/Examples/Vulkan/main.c index 2d46e07..baf8594 100644 --- a/Examples/Vulkan/main.c +++ b/Examples/Vulkan/main.c @@ -35,16 +35,17 @@ int main(void) #include "shader.spv.h" }; - PulseComputePipelineCreateInfo info = {}; + PulseComputePipelineCreateInfo info = { 0 }; info.code_size = sizeof(shader_bytecode); info.code = shader_bytecode; info.entrypoint = "main"; info.format = PULSE_SHADER_FORMAT_SPIRV_BIT; + info.num_readwrite_storage_buffers = 1; PulseComputePipeline pipeline = PulseCreateComputePipeline(device, &info); CHECK_PULSE_HANDLE_RETVAL(pipeline, 1); - PulseBufferCreateInfo buffer_create_info = {}; + PulseBufferCreateInfo buffer_create_info = { 0 }; buffer_create_info.size = 1024; buffer_create_info.usage = PULSE_BUFFER_USAGE_STORAGE_READ | PULSE_BUFFER_USAGE_STORAGE_WRITE | PULSE_BUFFER_USAGE_TRANSFER_DOWNLOAD; @@ -68,6 +69,13 @@ int main(void) if(!PulseWaitForFences(device, &fence, 1, true)) fprintf(stderr, "Could not wait for fences, %s\n", PulseVerbaliseErrorType(PulseGetLastErrorType())); + void* ptr; + PulseMapBuffer(buffer, &ptr); + for(uint32_t i = 0; i < 1024; i++) + printf("%d, ", ((int32_t*)ptr)[i]); + puts(""); + PulseUnmapBuffer(buffer); + PulseReleaseCommandList(device, cmd); PulseDestroyFence(device, fence); PulseDestroyComputePipeline(device, pipeline); diff --git a/Examples/Vulkan/shader.nzsl b/Examples/Vulkan/shader.nzsl index 875b41a..7fd42e7 100644 --- a/Examples/Vulkan/shader.nzsl +++ b/Examples/Vulkan/shader.nzsl @@ -14,12 +14,12 @@ struct SSBO external { - [set(0), binding(0)] ssbo: storage[SSBO], + [set(1), binding(0)] ssbo: storage[SSBO], } [entry(compute)] [workgroup(32, 32, 1)] fn main(input: Input) { - ssbo.data[input.indices.x * input.indices.y] = 1; + ssbo.data[input.indices.x * input.indices.y] = i32(input.indices.x * input.indices.y); } diff --git a/Sources/Backends/Vulkan/VulkanBuffer.c b/Sources/Backends/Vulkan/VulkanBuffer.c index 8a72dc2..f69442b 100644 --- a/Sources/Backends/Vulkan/VulkanBuffer.c +++ b/Sources/Backends/Vulkan/VulkanBuffer.c @@ -79,7 +79,7 @@ bool VulkanCopyBufferToBuffer(PulseCommandList cmd, const PulseBufferRegion* src VulkanDevice* vulkan_device = VULKAN_RETRIEVE_DRIVER_DATA_AS(src->buffer->device, VulkanDevice*); VulkanCommandList* vulkan_cmd = VULKAN_RETRIEVE_DRIVER_DATA_AS(cmd, VulkanCommandList*); - VkBufferCopy copy_region = {}; + VkBufferCopy copy_region = { 0 }; copy_region.srcOffset = src->offset; copy_region.dstOffset = dst->offset; copy_region.size = (src->size < dst->size ? src->size : dst->size); diff --git a/Sources/Backends/Vulkan/VulkanCommandList.c b/Sources/Backends/Vulkan/VulkanCommandList.c index dabd28a..57b68ea 100644 --- a/Sources/Backends/Vulkan/VulkanCommandList.c +++ b/Sources/Backends/Vulkan/VulkanCommandList.c @@ -20,7 +20,7 @@ static void VulkanInitCommandList(VulkanCommandPool* pool, PulseCommandList cmd) vulkan_cmd->pool = pool; - VkCommandBufferAllocateInfo info = {}; + VkCommandBufferAllocateInfo info = { 0 }; info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; info.commandPool = pool->pool; info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; @@ -82,7 +82,7 @@ PulseCommandList VulkanRequestCommandList(PulseDevice device, PulseCommandListUs CHECK_VK_RETVAL(device->backend, vulkan_device->vkResetCommandBuffer(vulkan_cmd->cmd, 0), PULSE_ERROR_DEVICE_ALLOCATION_FAILED, PULSE_NULL_HANDLE); - VkCommandBufferBeginInfo begin_info = {}; + VkCommandBufferBeginInfo begin_info = { 0 }; begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; begin_info.flags = 0; VkResult res = vulkan_device->vkBeginCommandBuffer(vulkan_cmd->cmd, &begin_info); @@ -130,7 +130,7 @@ bool VulkanSubmitCommandList(PulseDevice device, PulseCommandList cmd, PulseFenc PULSE_CHECK_PTR_RETVAL(vulkan_queue, false); - VkSubmitInfo submit_info = {}; + VkSubmitInfo submit_info = { 0 }; submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submit_info.commandBufferCount = 1; submit_info.pCommandBuffers = &vulkan_cmd->cmd; diff --git a/Sources/Backends/Vulkan/VulkanCommandPool.c b/Sources/Backends/Vulkan/VulkanCommandPool.c index bf36d01..737d51f 100644 --- a/Sources/Backends/Vulkan/VulkanCommandPool.c +++ b/Sources/Backends/Vulkan/VulkanCommandPool.c @@ -15,7 +15,7 @@ bool VulkanInitCommandPool(PulseDevice device, VulkanCommandPool* pool, VulkanQu VulkanDevice* vulkan_device = VULKAN_RETRIEVE_DRIVER_DATA_AS(device, VulkanDevice*); - VkCommandPoolCreateInfo create_info = {}; + VkCommandPoolCreateInfo create_info = { 0 }; create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; create_info.queueFamilyIndex = vulkan_device->queues[queue_type]->queue_family_index; diff --git a/Sources/Backends/Vulkan/VulkanComputePass.c b/Sources/Backends/Vulkan/VulkanComputePass.c index 3a0442a..d7222a1 100644 --- a/Sources/Backends/Vulkan/VulkanComputePass.c +++ b/Sources/Backends/Vulkan/VulkanComputePass.c @@ -37,7 +37,7 @@ void VulkanDestroyComputePass(PulseDevice device, PulseComputePass pass) void VulkanBindStorageBuffers(PulseComputePass pass, uint32_t starting_slot, const PulseBuffer* buffers, uint32_t num_buffers) { PulseBufferUsageFlags usage = buffers[0]->usage; - PulseBuffer* array = ((usage & PULSE_BUFFER_USAGE_STORAGE_WRITE) == 1) ? pass->readwrite_storage_buffers : pass->readonly_storage_buffers; + PulseBuffer* array = ((usage & PULSE_BUFFER_USAGE_STORAGE_WRITE) != 0) ? pass->readwrite_storage_buffers : pass->readonly_storage_buffers; VulkanComputePass* vulkan_pass = VULKAN_RETRIEVE_DRIVER_DATA_AS(pass, VulkanComputePass*); for(uint32_t i = 0; i < num_buffers; i++) @@ -46,7 +46,7 @@ void VulkanBindStorageBuffers(PulseComputePass pass, uint32_t starting_slot, con continue; array[starting_slot + i] = buffers[i]; - if((usage & PULSE_BUFFER_USAGE_STORAGE_WRITE) == 1) + if((usage & PULSE_BUFFER_USAGE_STORAGE_WRITE) != 0) vulkan_pass->should_recreate_write_descriptor_sets = true; else vulkan_pass->should_recreate_read_only_descriptor_sets = true; @@ -60,7 +60,7 @@ void VulkanBindUniformData(PulseComputePass pass, uint32_t slot, const void* dat void VulkanBindStorageImages(PulseComputePass pass, uint32_t starting_slot, const PulseImage* images, uint32_t num_images) { PulseImageUsageFlags usage = images[0]->usage; - PulseImage* array = ((usage & PULSE_IMAGE_USAGE_STORAGE_WRITE) == 1) ? pass->readwrite_images : pass->readonly_images; + PulseImage* array = ((usage & PULSE_IMAGE_USAGE_STORAGE_WRITE) != 0) ? pass->readwrite_images : pass->readonly_images; VulkanComputePass* vulkan_pass = VULKAN_RETRIEVE_DRIVER_DATA_AS(pass, VulkanComputePass*); for(uint32_t i = 0; i < num_images; i++) @@ -69,7 +69,7 @@ void VulkanBindStorageImages(PulseComputePass pass, uint32_t starting_slot, cons continue; array[starting_slot + i] = images[i]; - if((usage & PULSE_IMAGE_USAGE_STORAGE_WRITE) == 1) + if((usage & PULSE_IMAGE_USAGE_STORAGE_WRITE) != 0) vulkan_pass->should_recreate_write_descriptor_sets = true; else vulkan_pass->should_recreate_read_only_descriptor_sets = true; diff --git a/Sources/Backends/Vulkan/VulkanComputePipeline.c b/Sources/Backends/Vulkan/VulkanComputePipeline.c index 41058b2..d378c94 100644 --- a/Sources/Backends/Vulkan/VulkanComputePipeline.c +++ b/Sources/Backends/Vulkan/VulkanComputePipeline.c @@ -29,25 +29,35 @@ PulseComputePipeline VulkanCreateComputePipeline(PulseDevice device, const Pulse PulseLogError(device->backend, "invalid shader format passed to PulseComputePipelineCreateInfo"); } - VkShaderModuleCreateInfo shader_module_create_info = {}; + VkShaderModuleCreateInfo shader_module_create_info = { 0 }; shader_module_create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; shader_module_create_info.codeSize = info->code_size; shader_module_create_info.pCode = (const uint32_t*)info->code; CHECK_VK_RETVAL(device->backend, vulkan_device->vkCreateShaderModule(vulkan_device->device, &shader_module_create_info, PULSE_NULLPTR, &vulkan_pipeline->module), PULSE_ERROR_INITIALIZATION_FAILED, PULSE_NULL_HANDLE); - VkPipelineShaderStageCreateInfo shader_stage_info = {}; + VkPipelineShaderStageCreateInfo shader_stage_info = { 0 }; shader_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; shader_stage_info.stage = VK_SHADER_STAGE_COMPUTE_BIT; shader_stage_info.module = vulkan_pipeline->module; shader_stage_info.pName = info->entrypoint; - VkPipelineLayoutCreateInfo pipeline_layout_info = {}; + vulkan_pipeline->read_only_descriptor_set_layout = VulkanGetDescriptorSetLayout(&vulkan_device->descriptor_set_layout_manager, info->num_readonly_storage_images, info->num_readonly_storage_buffers, 0, 0, 0); + vulkan_pipeline->read_write_descriptor_set_layout = VulkanGetDescriptorSetLayout(&vulkan_device->descriptor_set_layout_manager, 0, 0, info->num_readwrite_storage_images, info->num_readwrite_storage_buffers, 0); + vulkan_pipeline->uniform_descriptor_set_layout = VulkanGetDescriptorSetLayout(&vulkan_device->descriptor_set_layout_manager, 0, 0, 0, 0, info->num_uniform_buffers); + + VkDescriptorSetLayout descriptor_set_layouts[3] = { + vulkan_pipeline->read_only_descriptor_set_layout->layout, + vulkan_pipeline->read_write_descriptor_set_layout->layout, + vulkan_pipeline->uniform_descriptor_set_layout->layout, + }; + + VkPipelineLayoutCreateInfo pipeline_layout_info = { 0 }; pipeline_layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; - pipeline_layout_info.setLayoutCount = 0; - pipeline_layout_info.pSetLayouts = PULSE_NULLPTR; // will change + pipeline_layout_info.setLayoutCount = 3; + pipeline_layout_info.pSetLayouts = descriptor_set_layouts; CHECK_VK_RETVAL(device->backend, vulkan_device->vkCreatePipelineLayout(vulkan_device->device, &pipeline_layout_info, PULSE_NULLPTR, &vulkan_pipeline->layout), PULSE_ERROR_INITIALIZATION_FAILED, PULSE_NULL_HANDLE); - VkComputePipelineCreateInfo pipeline_info = {}; + VkComputePipelineCreateInfo pipeline_info = { 0 }; pipeline_info.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO; pipeline_info.layout = vulkan_pipeline->layout; pipeline_info.stage = shader_stage_info; @@ -71,6 +81,9 @@ void VulkanDestroyComputePipeline(PulseDevice device, PulseComputePipeline pipel VulkanComputePipeline* vulkan_pipeline = VULKAN_RETRIEVE_DRIVER_DATA_AS(pipeline, VulkanComputePipeline*); VulkanDevice* vulkan_device = VULKAN_RETRIEVE_DRIVER_DATA_AS(device, VulkanDevice*); + vulkan_pipeline->read_only_descriptor_set_layout->is_used = false; + vulkan_pipeline->read_write_descriptor_set_layout->is_used = false; + vulkan_pipeline->uniform_descriptor_set_layout->is_used = false; vulkan_device->vkDeviceWaitIdle(vulkan_device->device); vulkan_device->vkDestroyShaderModule(vulkan_device->device, vulkan_pipeline->module, PULSE_NULLPTR); vulkan_device->vkDestroyPipelineLayout(vulkan_device->device, vulkan_pipeline->layout, PULSE_NULLPTR); diff --git a/Sources/Backends/Vulkan/VulkanComputePipeline.h b/Sources/Backends/Vulkan/VulkanComputePipeline.h index 31abdb1..a6b3975 100644 --- a/Sources/Backends/Vulkan/VulkanComputePipeline.h +++ b/Sources/Backends/Vulkan/VulkanComputePipeline.h @@ -10,12 +10,17 @@ #include #include +#include "VulkanDescriptor.h" typedef struct VulkanComputePipeline { VkShaderModule module; VkPipelineLayout layout; VkPipeline pipeline; + + VulkanDescriptorSetLayout* read_only_descriptor_set_layout; + VulkanDescriptorSetLayout* read_write_descriptor_set_layout; + VulkanDescriptorSetLayout* uniform_descriptor_set_layout; } VulkanComputePipeline; PulseComputePipeline VulkanCreateComputePipeline(PulseDevice device, const PulseComputePipelineCreateInfo* info); diff --git a/Sources/Backends/Vulkan/VulkanDescriptor.c b/Sources/Backends/Vulkan/VulkanDescriptor.c index c62f3ae..52fedda 100644 --- a/Sources/Backends/Vulkan/VulkanDescriptor.c +++ b/Sources/Backends/Vulkan/VulkanDescriptor.c @@ -7,9 +7,12 @@ #include "Pulse.h" #include "PulseProfile.h" #include "Vulkan.h" +#include "VulkanBuffer.h" +#include "VulkanImage.h" #include "VulkanDevice.h" #include "VulkanDescriptor.h" #include "VulkanComputePass.h" +#include "VulkanComputePipeline.h" void VulkanInitDescriptorSetLayoutManager(VulkanDescriptorSetLayoutManager* manager, PulseDevice device) { @@ -18,85 +21,105 @@ void VulkanInitDescriptorSetLayoutManager(VulkanDescriptorSetLayoutManager* mana } VulkanDescriptorSetLayout* VulkanGetDescriptorSetLayout(VulkanDescriptorSetLayoutManager* manager, - uint32_t read_storage_buffers_count, uint32_t read_storage_images_count, - uint32_t write_storage_buffers_count, + uint32_t read_storage_buffers_count, uint32_t write_storage_images_count, + uint32_t write_storage_buffers_count, uint32_t uniform_buffers_count) { VulkanDevice* vulkan_device = VULKAN_RETRIEVE_DRIVER_DATA_AS(manager->device, VulkanDevice*); for(uint32_t i = 0; i < manager->layouts_size; i++) { - VulkanDescriptorSetLayout* layout = &manager->layouts[i]; + VulkanDescriptorSetLayout* layout = manager->layouts[i]; if( layout->ReadOnly.storage_buffer_count == read_storage_buffers_count && layout->ReadOnly.storage_texture_count == read_storage_images_count && layout->ReadWrite.storage_buffer_count == write_storage_buffers_count && layout->ReadWrite.storage_texture_count == write_storage_images_count && - layout->Uniform.buffer_count == uniform_buffers_count) + layout->Uniform.buffer_count == uniform_buffers_count && + !layout->is_used) { + layout->is_used = true; return layout; } } - PULSE_EXPAND_ARRAY_IF_NEEDED(manager->layouts, VulkanDescriptorSetLayout, manager->layouts_size, manager->layouts_capacity, 1); + PULSE_EXPAND_ARRAY_IF_NEEDED(manager->layouts, VulkanDescriptorSetLayout*, manager->layouts_size, manager->layouts_capacity, 1); PULSE_CHECK_ALLOCATION_RETVAL(manager->layouts, PULSE_NULLPTR); - VulkanDescriptorSetLayout* layout = &manager->layouts[manager->layouts_size]; + VulkanDescriptorSetLayout* layout = (VulkanDescriptorSetLayout*)malloc(sizeof(VulkanDescriptorSetLayout)); + manager->layouts[manager->layouts_size] = layout; + manager->layouts_size++; - VkDescriptorSetLayoutBinding* bindings = (VkDescriptorSetLayoutBinding*)PulseStaticAllocStack(PULSE_MAX_READ_BUFFERS_BOUND + PULSE_MAX_READ_TEXTURES_BOUND + PULSE_MAX_WRITE_BUFFERS_BOUND + PULSE_MAX_WRITE_TEXTURES_BOUND + PULSE_MAX_UNIFORM_BUFFERS_BOUND); + VkDescriptorSetLayoutBinding bindings[PULSE_MAX_READ_BUFFERS_BOUND + PULSE_MAX_READ_TEXTURES_BOUND + PULSE_MAX_WRITE_BUFFERS_BOUND + PULSE_MAX_WRITE_TEXTURES_BOUND + PULSE_MAX_UNIFORM_BUFFERS_BOUND] = { 0 }; - // Category 1 - for(uint32_t i = 0; i < read_storage_images_count; i++) + uint8_t category; + if(uniform_buffers_count != 0) + category = 3; + else if(write_storage_images_count != 0 || write_storage_buffers_count != 0) + category = 2; + else + category = 1; + + uint32_t count = 0; + + if(category == 1) { - bindings[i].binding = i; - bindings[i].descriptorCount = 1; - bindings[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; - bindings[i].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; - bindings[i].pImmutableSamplers = PULSE_NULLPTR; - } + for(uint32_t i = 0; i < read_storage_images_count; i++, count++) + { + bindings[i].binding = i; + bindings[i].descriptorCount = 1; + bindings[i].descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; // Wtf shaders ? + bindings[i].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; + bindings[i].pImmutableSamplers = PULSE_NULLPTR; + } - for(uint32_t i = read_storage_images_count; i < read_storage_images_count + read_storage_buffers_count; i++) + for(uint32_t i = read_storage_images_count; i < read_storage_images_count + read_storage_buffers_count; i++, count++) + { + bindings[i].binding = i; + bindings[i].descriptorCount = 1; + bindings[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + bindings[i].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; + bindings[i].pImmutableSamplers = PULSE_NULLPTR; + } + } + else if(category == 2) { - bindings[i].binding = i; - bindings[i].descriptorCount = 1; - bindings[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - bindings[i].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; - bindings[i].pImmutableSamplers = PULSE_NULLPTR; - } + for(uint32_t i = 0; i < write_storage_images_count; i++, count++) + { + bindings[i].binding = i; + bindings[i].descriptorCount = 1; + bindings[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + bindings[i].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; + bindings[i].pImmutableSamplers = PULSE_NULLPTR; + } - // Category 2 - for(uint32_t i = 0; i < write_storage_images_count; i++) { - bindings[i].binding = i; - bindings[i].descriptorCount = 1; - bindings[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; - bindings[i].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; - bindings[i].pImmutableSamplers = PULSE_NULLPTR; + for(uint32_t i = write_storage_images_count; i < write_storage_images_count + write_storage_buffers_count; i++, count++) + { + bindings[i].binding = i; + bindings[i].descriptorCount = 1; + bindings[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + bindings[i].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; + bindings[i].pImmutableSamplers = PULSE_NULLPTR; + } } - - for(uint32_t i = write_storage_images_count; i < write_storage_images_count + write_storage_buffers_count; i++) + else if(category == 3) { - bindings[i].binding = i; - bindings[i].descriptorCount = 1; - bindings[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - bindings[i].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; - bindings[i].pImmutableSamplers = PULSE_NULLPTR; - } - - // Category 3 - for(uint32_t i = 0; i < uniform_buffers_count; i++) - { - bindings[i].binding = i; - bindings[i].descriptorCount = 1; - bindings[i].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - bindings[i].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; - bindings[i].pImmutableSamplers = PULSE_NULLPTR; + for(uint32_t i = 0; i < uniform_buffers_count; i++, count++) + { + bindings[i].binding = i; + bindings[i].descriptorCount = 1; + bindings[i].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + bindings[i].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; + bindings[i].pImmutableSamplers = PULSE_NULLPTR; + } } VkDescriptorSetLayoutCreateInfo layout_info = { 0 }; layout_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - layout_info.bindingCount = read_storage_buffers_count + read_storage_images_count + write_storage_buffers_count + write_storage_images_count + uniform_buffers_count; + layout_info.bindingCount = count; layout_info.pBindings = bindings; + CHECK_VK_RETVAL(manager->device->backend, vulkan_device->vkCreateDescriptorSetLayout(vulkan_device->device, &layout_info, PULSE_NULLPTR, &layout->layout), PULSE_ERROR_INITIALIZATION_FAILED, PULSE_NULLPTR); layout->ReadOnly.storage_buffer_count = read_storage_buffers_count; @@ -105,6 +128,8 @@ VulkanDescriptorSetLayout* VulkanGetDescriptorSetLayout(VulkanDescriptorSetLayou layout->ReadWrite.storage_texture_count = write_storage_images_count; layout->Uniform.buffer_count = uniform_buffers_count; + layout->is_used = true; + return layout; } @@ -117,9 +142,7 @@ void VulkanDestroyDescriptorSetLayout(VulkanDescriptorSetLayout* layout, PulseDe void VulkanDestroyDescriptorSetLayoutManager(VulkanDescriptorSetLayoutManager* manager) { for(uint32_t i = 0; i < manager->layouts_size; i++) - { - VulkanDestroyDescriptorSetLayout(&manager->layouts[i], manager->device); - } + VulkanDestroyDescriptorSetLayout(manager->layouts[i], manager->device); free(manager->layouts); memset(manager, 0, sizeof(VulkanDescriptorSetPoolManager)); } @@ -131,18 +154,13 @@ void VulkanInitDescriptorSetPool(VulkanDescriptorSetPool* pool, PulseDevice devi pool->device = device; pool->thread_id = PulseGetThreadID(); - VkDescriptorPoolSize pool_sizes[ - PULSE_MAX_READ_TEXTURES_BOUND + - PULSE_MAX_READ_BUFFERS_BOUND + - PULSE_MAX_WRITE_TEXTURES_BOUND + - PULSE_MAX_WRITE_BUFFERS_BOUND + - PULSE_MAX_UNIFORM_BUFFERS_BOUND]; + VkDescriptorPoolSize pool_sizes[PULSE_MAX_READ_BUFFERS_BOUND + PULSE_MAX_READ_TEXTURES_BOUND + PULSE_MAX_WRITE_BUFFERS_BOUND + PULSE_MAX_WRITE_TEXTURES_BOUND + PULSE_MAX_UNIFORM_BUFFERS_BOUND] = { 0 }; uint32_t i = 0; for(uint32_t start = i; i < start + PULSE_MAX_READ_TEXTURES_BOUND; i++) { - pool_sizes[i].type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + pool_sizes[i].type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; pool_sizes[i].descriptorCount = VULKAN_POOL_SIZE; } @@ -166,16 +184,15 @@ void VulkanInitDescriptorSetPool(VulkanDescriptorSetPool* pool, PulseDevice devi for(uint32_t start = i; i < start + PULSE_MAX_UNIFORM_BUFFERS_BOUND; i++) { - pool_sizes[i].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; + pool_sizes[i].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; pool_sizes[i].descriptorCount = VULKAN_POOL_SIZE; } VkDescriptorPoolCreateInfo pool_info = { 0 }; pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; - pool_info.poolSizeCount = sizeof(pool_sizes) / sizeof(pool_sizes[0]); + pool_info.poolSizeCount = i; pool_info.pPoolSizes = pool_sizes; pool_info.maxSets = VULKAN_POOL_SIZE; - pool_info.flags = 0; CHECK_VK(device->backend, vulkan_device->vkCreateDescriptorPool(vulkan_device->device, &pool_info, PULSE_NULLPTR, &pool->pool), PULSE_ERROR_INITIALIZATION_FAILED); } @@ -236,15 +253,14 @@ void VulkanReturnDescriptorSetToPool(VulkanDescriptorSetPool* pool, const Vulkan void VulkanBindDescriptorSets(PulseComputePass pass) { VulkanComputePass* vulkan_pass = VULKAN_RETRIEVE_DRIVER_DATA_AS(pass, VulkanComputePass*); + VulkanDevice* vulkan_device = VULKAN_RETRIEVE_DRIVER_DATA_AS(pass->cmd->device, VulkanDevice*); + VulkanComputePipeline* vulkan_pipeline = VULKAN_RETRIEVE_DRIVER_DATA_AS(pass->current_pipeline, VulkanComputePipeline*); + VulkanCommandList* vulkan_cmd = VULKAN_RETRIEVE_DRIVER_DATA_AS(pass->cmd, VulkanCommandList*); + if(!vulkan_pass->should_recreate_read_only_descriptor_sets && !vulkan_pass->should_recreate_write_descriptor_sets && !vulkan_pass->should_recreate_uniform_descriptor_sets) return; - VkWriteDescriptorSet writes[ - PULSE_MAX_READ_TEXTURES_BOUND + - PULSE_MAX_READ_BUFFERS_BOUND + - PULSE_MAX_WRITE_TEXTURES_BOUND + - PULSE_MAX_WRITE_BUFFERS_BOUND + - PULSE_MAX_UNIFORM_BUFFERS_BOUND]; + VkWriteDescriptorSet writes[PULSE_MAX_READ_BUFFERS_BOUND + PULSE_MAX_READ_TEXTURES_BOUND + PULSE_MAX_WRITE_BUFFERS_BOUND + PULSE_MAX_WRITE_TEXTURES_BOUND + PULSE_MAX_UNIFORM_BUFFERS_BOUND] = { 0 }; VkDescriptorBufferInfo buffer_infos[PULSE_MAX_UNIFORM_BUFFERS_BOUND + PULSE_MAX_WRITE_BUFFERS_BOUND + PULSE_MAX_READ_BUFFERS_BOUND]; VkDescriptorImageInfo image_infos[PULSE_MAX_READ_TEXTURES_BOUND + PULSE_MAX_WRITE_TEXTURES_BOUND]; uint32_t write_count = 0; @@ -253,15 +269,169 @@ void VulkanBindDescriptorSets(PulseComputePass pass) if(vulkan_pass->should_recreate_read_only_descriptor_sets) { + if(vulkan_pass->read_only_descriptor_set != PULSE_NULLPTR) + VulkanReturnDescriptorSetToPool(vulkan_pass->read_only_descriptor_set->pool, vulkan_pass->read_only_descriptor_set); + vulkan_pass->read_only_descriptor_set = VulkanRequestDescriptorSetFromPool(VulkanGetAvailableDescriptorSetPool(&vulkan_device->descriptor_set_pool_manager), vulkan_pipeline->read_only_descriptor_set_layout); + + for(uint32_t i = 0; i < pass->current_pipeline->num_readonly_storage_images; i++) + { + VkWriteDescriptorSet* write_descriptor_set = &writes[write_count]; + + write_descriptor_set->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + write_descriptor_set->pNext = PULSE_NULLPTR; + write_descriptor_set->descriptorCount = 1; + write_descriptor_set->descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; // Wtf shaders ? + write_descriptor_set->dstArrayElement = 0; + write_descriptor_set->dstBinding = i; + write_descriptor_set->dstSet = vulkan_pass->read_only_descriptor_set->set; + write_descriptor_set->pTexelBufferView = PULSE_NULLPTR; + write_descriptor_set->pBufferInfo = PULSE_NULLPTR; + + VulkanImage* vulkan_image = VULKAN_RETRIEVE_DRIVER_DATA_AS(pass->readonly_images[i], VulkanImage*); + + image_infos[image_info_count].sampler = VK_NULL_HANDLE; + image_infos[image_info_count].imageView = vulkan_image->view; + image_infos[image_info_count].imageLayout = VK_IMAGE_LAYOUT_GENERAL; + + write_descriptor_set->pImageInfo = &image_infos[image_info_count]; + + write_count++; + image_info_count++; + } + + for(uint32_t i = 0; i < pass->current_pipeline->num_readonly_storage_buffers; i++) + { + VkWriteDescriptorSet* write_descriptor_set = &writes[write_count]; + + write_descriptor_set->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + write_descriptor_set->pNext = PULSE_NULLPTR; + write_descriptor_set->descriptorCount = 1; + write_descriptor_set->descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + write_descriptor_set->dstArrayElement = 0; + write_descriptor_set->dstBinding = pass->current_pipeline->num_readonly_storage_images + i; + write_descriptor_set->dstSet = vulkan_pass->read_only_descriptor_set->set; + write_descriptor_set->pTexelBufferView = PULSE_NULLPTR; + write_descriptor_set->pBufferInfo = PULSE_NULLPTR; + + VulkanBuffer* vulkan_buffer = VULKAN_RETRIEVE_DRIVER_DATA_AS(pass->readonly_storage_buffers[i], VulkanBuffer*); + + buffer_infos[buffer_info_count].buffer = vulkan_buffer->buffer; + buffer_infos[buffer_info_count].offset = 0; + buffer_infos[buffer_info_count].range = VK_WHOLE_SIZE; + + write_descriptor_set->pBufferInfo = &buffer_infos[buffer_info_count]; + + write_count++; + buffer_info_count++; + } + + vulkan_pass->should_recreate_read_only_descriptor_sets = false; } if(vulkan_pass->should_recreate_write_descriptor_sets) { + if(vulkan_pass->read_write_descriptor_set != PULSE_NULLPTR) + VulkanReturnDescriptorSetToPool(vulkan_pass->read_write_descriptor_set->pool, vulkan_pass->read_write_descriptor_set); + vulkan_pass->read_write_descriptor_set = VulkanRequestDescriptorSetFromPool(VulkanGetAvailableDescriptorSetPool(&vulkan_device->descriptor_set_pool_manager), vulkan_pipeline->read_write_descriptor_set_layout); + + for(uint32_t i = 0; i < pass->current_pipeline->num_readwrite_storage_images; i++) + { + VkWriteDescriptorSet* write_descriptor_set = &writes[write_count]; + + write_descriptor_set->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + write_descriptor_set->pNext = PULSE_NULLPTR; + write_descriptor_set->descriptorCount = 1; + write_descriptor_set->descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + write_descriptor_set->dstArrayElement = 0; + write_descriptor_set->dstBinding = i; + write_descriptor_set->dstSet = vulkan_pass->read_write_descriptor_set->set; + write_descriptor_set->pTexelBufferView = PULSE_NULLPTR; + write_descriptor_set->pBufferInfo = PULSE_NULLPTR; + + VulkanImage* vulkan_image = VULKAN_RETRIEVE_DRIVER_DATA_AS(pass->readwrite_images[i], VulkanImage*); + + image_infos[image_info_count].sampler = VK_NULL_HANDLE; + image_infos[image_info_count].imageView = vulkan_image->view; + image_infos[image_info_count].imageLayout = VK_IMAGE_LAYOUT_GENERAL; + + write_descriptor_set->pImageInfo = &image_infos[image_info_count]; + + write_count++; + image_info_count++; + } + + for(uint32_t i = 0; i < pass->current_pipeline->num_readwrite_storage_buffers; i++) + { + VkWriteDescriptorSet* write_descriptor_set = &writes[write_count]; + + write_descriptor_set->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + write_descriptor_set->pNext = PULSE_NULLPTR; + write_descriptor_set->descriptorCount = 1; + write_descriptor_set->descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + write_descriptor_set->dstArrayElement = 0; + write_descriptor_set->dstBinding = pass->current_pipeline->num_readwrite_storage_images + i; + write_descriptor_set->dstSet = vulkan_pass->read_write_descriptor_set->set; + write_descriptor_set->pTexelBufferView = PULSE_NULLPTR; + write_descriptor_set->pBufferInfo = PULSE_NULLPTR; + + VulkanBuffer* vulkan_buffer = VULKAN_RETRIEVE_DRIVER_DATA_AS(pass->readwrite_storage_buffers[i], VulkanBuffer*); + + buffer_infos[buffer_info_count].buffer = vulkan_buffer->buffer; + buffer_infos[buffer_info_count].offset = 0; + buffer_infos[buffer_info_count].range = VK_WHOLE_SIZE; + + write_descriptor_set->pBufferInfo = &buffer_infos[buffer_info_count]; + + write_count++; + buffer_info_count++; + } + + vulkan_pass->should_recreate_write_descriptor_sets = false; } if(vulkan_pass->should_recreate_uniform_descriptor_sets) { + if(vulkan_pass->uniform_descriptor_set != PULSE_NULLPTR) + VulkanReturnDescriptorSetToPool(vulkan_pass->uniform_descriptor_set->pool, vulkan_pass->uniform_descriptor_set); + vulkan_pass->uniform_descriptor_set = VulkanRequestDescriptorSetFromPool(VulkanGetAvailableDescriptorSetPool(&vulkan_device->descriptor_set_pool_manager), vulkan_pipeline->uniform_descriptor_set_layout); + + for(uint32_t i = 0; i < pass->current_pipeline->num_uniform_buffers; i++) + { + VkWriteDescriptorSet* write_descriptor_set = &writes[write_count]; + + write_descriptor_set->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + write_descriptor_set->pNext = PULSE_NULLPTR; + write_descriptor_set->descriptorCount = 1; + write_descriptor_set->descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + write_descriptor_set->dstArrayElement = 0; + write_descriptor_set->dstBinding = i; + write_descriptor_set->dstSet = vulkan_pass->uniform_descriptor_set->set; + write_descriptor_set->pTexelBufferView = PULSE_NULLPTR; + write_descriptor_set->pBufferInfo = PULSE_NULLPTR; + + VulkanBuffer* vulkan_buffer = VULKAN_RETRIEVE_DRIVER_DATA_AS(pass->uniform_buffers[i], VulkanBuffer*); + + buffer_infos[buffer_info_count].buffer = vulkan_buffer->buffer; + buffer_infos[buffer_info_count].offset = 0; + buffer_infos[buffer_info_count].range = VK_WHOLE_SIZE; + + write_descriptor_set->pBufferInfo = &buffer_infos[buffer_info_count]; + + write_count++; + buffer_info_count++; + } + + vulkan_pass->should_recreate_uniform_descriptor_sets = false; } + + vulkan_device->vkUpdateDescriptorSets(vulkan_device->device, write_count, writes, 0, PULSE_NULLPTR); + + VkDescriptorSet sets[3]; + sets[0] = vulkan_pass->read_only_descriptor_set->set; + sets[1] = vulkan_pass->read_write_descriptor_set->set; + sets[2] = vulkan_pass->uniform_descriptor_set->set; + + vulkan_device->vkCmdBindDescriptorSets(vulkan_cmd->cmd, VK_PIPELINE_BIND_POINT_COMPUTE, vulkan_pipeline->layout, 0, 3, sets, 0, PULSE_NULLPTR); } void VulkanDestroyDescriptorSetPool(VulkanDescriptorSetPool* pool) diff --git a/Sources/Backends/Vulkan/VulkanDescriptor.h b/Sources/Backends/Vulkan/VulkanDescriptor.h index eb29eba..49d52db 100644 --- a/Sources/Backends/Vulkan/VulkanDescriptor.h +++ b/Sources/Backends/Vulkan/VulkanDescriptor.h @@ -37,6 +37,8 @@ typedef struct VulkanDescriptorSetLayout uint32_t buffer_count; } Uniform; }; + + bool is_used; } VulkanDescriptorSetLayout; typedef struct VulkanDescriptorSet @@ -70,17 +72,17 @@ typedef struct VulkanDescriptorSetPoolManager typedef struct VulkanDescriptorSetLayoutManager { PulseDevice device; - VulkanDescriptorSetLayout* layouts; + VulkanDescriptorSetLayout** layouts; uint32_t layouts_capacity; uint32_t layouts_size; } VulkanDescriptorSetLayoutManager; void VulkanInitDescriptorSetLayoutManager(VulkanDescriptorSetLayoutManager* manager, PulseDevice device); VulkanDescriptorSetLayout* VulkanGetDescriptorSetLayout(VulkanDescriptorSetLayoutManager* manager, - uint32_t read_storage_buffers_count, uint32_t read_storage_images_count, - uint32_t write_storage_buffers_count, + uint32_t read_storage_buffers_count, uint32_t write_storage_images_count, + uint32_t write_storage_buffers_count, uint32_t uniform_buffers_count); void VulkanDestroyDescriptorSetLayoutManager(VulkanDescriptorSetLayoutManager* manager); diff --git a/Sources/Backends/Vulkan/VulkanDevice.c b/Sources/Backends/Vulkan/VulkanDevice.c index e64140c..69e8931 100644 --- a/Sources/Backends/Vulkan/VulkanDevice.c +++ b/Sources/Backends/Vulkan/VulkanDevice.c @@ -129,7 +129,7 @@ PulseDevice VulkanCreateDevice(PulseBackend backend, PulseDevice* forbiden_devic const float queue_priority = 1.0f; - VkDeviceQueueCreateInfo* queue_create_infos = (VkDeviceQueueCreateInfo*)PulseStaticAllocStack(VULKAN_QUEUE_END_ENUM * sizeof(VkDeviceQueueCreateInfo)); + VkDeviceQueueCreateInfo queue_create_infos[VULKAN_QUEUE_END_ENUM * sizeof(VkDeviceQueueCreateInfo)] = { 0 }; // No need to check allocation, it is allocated on the stack uint32_t unique_queues_count = 1; @@ -167,7 +167,7 @@ PulseDevice VulkanCreateDevice(PulseBackend backend, PulseDevice* forbiden_devic instance->vkGetPhysicalDeviceMemoryProperties(device->physical, &device->memory_properties); instance->vkGetPhysicalDeviceFeatures(device->physical, &device->features); - VkDeviceCreateInfo create_info = {}; + VkDeviceCreateInfo create_info = { 0 }; create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; create_info.queueCreateInfoCount = unique_queues_count; create_info.pQueueCreateInfos = queue_create_infos; @@ -197,7 +197,7 @@ PulseDevice VulkanCreateDevice(PulseBackend backend, PulseDevice* forbiden_devic } } - VmaVulkanFunctions vma_vulkan_func = {}; + VmaVulkanFunctions vma_vulkan_func = { 0 }; vma_vulkan_func.vkAllocateMemory = device->vkAllocateMemory; vma_vulkan_func.vkBindBufferMemory = device->vkBindBufferMemory; vma_vulkan_func.vkBindImageMemory = device->vkBindImageMemory; @@ -216,7 +216,7 @@ PulseDevice VulkanCreateDevice(PulseBackend backend, PulseDevice* forbiden_devic vma_vulkan_func.vkGetPhysicalDeviceMemoryProperties = instance->vkGetPhysicalDeviceMemoryProperties; vma_vulkan_func.vkGetPhysicalDeviceProperties = instance->vkGetPhysicalDeviceProperties; - VmaAllocatorCreateInfo allocator_create_info = {}; + VmaAllocatorCreateInfo allocator_create_info = { 0 }; allocator_create_info.vulkanApiVersion = VK_API_VERSION_1_0; allocator_create_info.physicalDevice = device->physical; allocator_create_info.device = device->device; diff --git a/Sources/Backends/Vulkan/VulkanFence.c b/Sources/Backends/Vulkan/VulkanFence.c index 14513f5..1c83f1d 100644 --- a/Sources/Backends/Vulkan/VulkanFence.c +++ b/Sources/Backends/Vulkan/VulkanFence.c @@ -12,7 +12,7 @@ PulseFence VulkanCreateFence(PulseDevice device) { PULSE_CHECK_HANDLE_RETVAL(device, PULSE_NULL_HANDLE); - VkFenceCreateInfo fence_info = {}; + VkFenceCreateInfo fence_info = { 0 }; fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; fence_info.flags = VK_FENCE_CREATE_SIGNALED_BIT; VkFence vulkan_fence; diff --git a/Sources/Backends/Vulkan/VulkanImage.c b/Sources/Backends/Vulkan/VulkanImage.c index f0ab95d..ca96b0b 100644 --- a/Sources/Backends/Vulkan/VulkanImage.c +++ b/Sources/Backends/Vulkan/VulkanImage.c @@ -191,7 +191,7 @@ bool VulkanCopyImageToBuffer(PulseCommandList cmd, const PulseImageRegion* src, VkOffset3D offset = { src->x, src->y, src->z }; VkExtent3D extent = { src->width, src->height, src->depth }; - VkBufferImageCopy region = {}; + VkBufferImageCopy region = { 0 }; region.bufferOffset = dst->offset; region.bufferRowLength = 0; region.bufferImageHeight = 0; diff --git a/Sources/Backends/Vulkan/VulkanInstance.c b/Sources/Backends/Vulkan/VulkanInstance.c index 1fa2e7e..fca6bf5 100644 --- a/Sources/Backends/Vulkan/VulkanInstance.c +++ b/Sources/Backends/Vulkan/VulkanInstance.c @@ -104,7 +104,7 @@ static VkInstance VulkanCreateInstance(PulseBackend backend, const char** extens { VkInstance instance = VK_NULL_HANDLE; - VkApplicationInfo app_info = {}; + VkApplicationInfo app_info = { 0 }; app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; app_info.pEngineName = "PulseGPU"; app_info.engineVersion = PULSE_VERSION; diff --git a/Sources/PulseComputePipeline.c b/Sources/PulseComputePipeline.c index f7cd0c5..6d64def 100644 --- a/Sources/PulseComputePipeline.c +++ b/Sources/PulseComputePipeline.c @@ -16,7 +16,7 @@ PULSE_API PulseComputePipeline PulseCreateComputePipeline(PulseDevice device, co return PULSE_NULL_HANDLE; pipeline->num_readonly_storage_images = info->num_readonly_storage_images; pipeline->num_readonly_storage_buffers = info->num_readonly_storage_buffers; - pipeline->num_readwrite_storage_images = info->num_readwrite_storage_buffers; + pipeline->num_readwrite_storage_images = info->num_readwrite_storage_images; pipeline->num_readwrite_storage_buffers = info->num_readwrite_storage_buffers; pipeline->num_uniform_buffers = info->num_uniform_buffers; return pipeline; diff --git a/Sources/PulseDefs.h b/Sources/PulseDefs.h index 3d8363d..3c610d2 100644 --- a/Sources/PulseDefs.h +++ b/Sources/PulseDefs.h @@ -7,8 +7,6 @@ #include -#define PulseStaticAllocStack(size) ((char[size]){ 0 }) - #define PULSE_CHECK_ALLOCATION_RETVAL(ptr, retval) \ do { \ if(ptr == PULSE_NULLPTR) \ diff --git a/Sources/PulseInternal.h b/Sources/PulseInternal.h index 4629366..7764b5a 100644 --- a/Sources/PulseInternal.h +++ b/Sources/PulseInternal.h @@ -140,6 +140,8 @@ typedef struct PulseComputePassHandler PulseImage readonly_images[PULSE_MAX_READ_TEXTURES_BOUND]; PulseImage readwrite_images[PULSE_MAX_WRITE_TEXTURES_BOUND]; + PulseBuffer uniform_buffers[PULSE_MAX_UNIFORM_BUFFERS_BOUND]; + PulseCommandList cmd; PulseComputePipeline current_pipeline; diff --git a/Tests/Vulkan/Buffer.c b/Tests/Vulkan/Buffer.c index b836126..14cd003 100644 --- a/Tests/Vulkan/Buffer.c +++ b/Tests/Vulkan/Buffer.c @@ -271,6 +271,60 @@ void TestBufferCopyImage() CleanupPulse(backend); } +void TestBufferComputeWrite() +{ + PulseBackend backend; + SetupPulse(&backend); + PulseDevice device; + SetupDevice(backend, &device); + + const uint8_t shader_bytecode[] = { + #include "Shaders/SimpleBufferWrite.spv.h" + }; + + PulseBufferCreateInfo buffer_create_info = { 0 }; + buffer_create_info.size = 256 * sizeof(int32_t); + buffer_create_info.usage = PULSE_BUFFER_USAGE_STORAGE_READ | PULSE_BUFFER_USAGE_STORAGE_WRITE | PULSE_BUFFER_USAGE_TRANSFER_DOWNLOAD; + PulseBuffer buffer = PulseCreateBuffer(device, &buffer_create_info); + TEST_ASSERT_NOT_EQUAL_MESSAGE(buffer, PULSE_NULL_HANDLE, PulseVerbaliseErrorType(PulseGetLastErrorType())); + + PulseComputePipeline pipeline; + LoadComputePipeline(device, &pipeline, shader_bytecode, sizeof(shader_bytecode), 0, 0, 0, 1, 0); + + PulseFence fence = PulseCreateFence(device); + TEST_ASSERT_NOT_EQUAL_MESSAGE(fence, PULSE_NULL_HANDLE, PulseVerbaliseErrorType(PulseGetLastErrorType())); + PulseCommandList cmd = PulseRequestCommandList(device, PULSE_COMMAND_LIST_GENERAL); + TEST_ASSERT_NOT_EQUAL_MESSAGE(cmd, PULSE_NULL_HANDLE, PulseVerbaliseErrorType(PulseGetLastErrorType())); + + PulseComputePass pass = PulseBeginComputePass(cmd); + TEST_ASSERT_NOT_EQUAL_MESSAGE(pass, PULSE_NULL_HANDLE, PulseVerbaliseErrorType(PulseGetLastErrorType())); + PulseBindStorageBuffers(pass, 0, &buffer, 1); + PulseBindComputePipeline(pass, pipeline); + PulseDispatchComputations(pass, 32, 32, 1); + PulseEndComputePass(pass); + + TEST_ASSERT_TRUE_MESSAGE(PulseSubmitCommandList(device, cmd, fence), PulseVerbaliseErrorType(PulseGetLastErrorType())); + TEST_ASSERT_TRUE_MESSAGE(PulseWaitForFences(device, &fence, 1, true), PulseVerbaliseErrorType(PulseGetLastErrorType())); + + { + void* ptr; + uint32_t data[256]; + memset(data, 0xFF, 256 * sizeof(uint32_t)); + TEST_ASSERT_NOT_EQUAL_MESSAGE(PulseMapBuffer(buffer, &ptr), false, PulseVerbaliseErrorType(PulseGetLastErrorType())); + TEST_ASSERT_NOT_NULL(ptr); + TEST_ASSERT_EQUAL(memcmp(ptr, data, 256 * sizeof(uint32_t)), 0); + PulseUnmapBuffer(buffer); + } + + PulseReleaseCommandList(device, cmd); + PulseDestroyFence(device, fence); + PulseDestroyBuffer(device, buffer); + + CleanupPipeline(device, pipeline); + CleanupDevice(device); + CleanupPulse(backend); +} + void TestBufferDestruction() { PulseBackend backend; @@ -310,5 +364,6 @@ void TestBuffer() RUN_TEST(TestBufferMapping); RUN_TEST(TestBufferCopy); RUN_TEST(TestBufferCopyImage); + RUN_TEST(TestBufferComputeWrite); RUN_TEST(TestBufferDestruction); } diff --git a/Tests/Vulkan/Common.c b/Tests/Vulkan/Common.c index 378389a..08c7281 100644 --- a/Tests/Vulkan/Common.c +++ b/Tests/Vulkan/Common.c @@ -29,7 +29,7 @@ void SetupPulse(PulseBackend* backend) void SetupDevice(PulseBackend backend, PulseDevice* device) { *device = PulseCreateDevice(backend, NULL, 0); - TEST_ASSERT_NOT_EQUAL_MESSAGE(device, PULSE_NULL_HANDLE, PulseVerbaliseErrorType(PulseGetLastErrorType())); + TEST_ASSERT_NOT_EQUAL_MESSAGE(*device, PULSE_NULL_HANDLE, PulseVerbaliseErrorType(PulseGetLastErrorType())); } void CleanupDevice(PulseDevice device) @@ -41,3 +41,30 @@ void CleanupPulse(PulseBackend backend) { PulseUnloadBackend(backend); } + +void LoadComputePipeline(PulseDevice device, PulseComputePipeline* pipeline, const uint8_t* code, uint32_t code_size, + uint32_t num_readonly_storage_images, + uint32_t num_readonly_storage_buffers, + uint32_t num_readwrite_storage_images, + uint32_t num_readwrite_storage_buffers, + uint32_t num_uniform_buffers) +{ + PulseComputePipelineCreateInfo info = { 0 }; + info.code_size = code_size; + info.code = code; + info.entrypoint = "main"; + info.format = PULSE_SHADER_FORMAT_SPIRV_BIT; + info.num_readonly_storage_images = num_readonly_storage_images; + info.num_readonly_storage_buffers = num_readonly_storage_buffers; + info.num_readwrite_storage_buffers = num_readwrite_storage_buffers; + info.num_readwrite_storage_images = num_readwrite_storage_images; + info.num_uniform_buffers = num_uniform_buffers; + + *pipeline = PulseCreateComputePipeline(device, &info); + TEST_ASSERT_NOT_EQUAL_MESSAGE(*pipeline, PULSE_NULL_HANDLE, PulseVerbaliseErrorType(PulseGetLastErrorType())); +} + +void CleanupPipeline(PulseDevice device, PulseComputePipeline pipeline) +{ + PulseDestroyComputePipeline(device, pipeline); +} diff --git a/Tests/Vulkan/Common.h b/Tests/Vulkan/Common.h index c8773e2..364c94e 100644 --- a/Tests/Vulkan/Common.h +++ b/Tests/Vulkan/Common.h @@ -32,5 +32,12 @@ void SetupPulse(PulseBackend* backend); void SetupDevice(PulseBackend backend, PulseDevice* device); void CleanupDevice(PulseDevice device); void CleanupPulse(PulseBackend backend); +void LoadComputePipeline(PulseDevice device, PulseComputePipeline* pipeline, const uint8_t* code, uint32_t code_size, + uint32_t num_readonly_storage_images, + uint32_t num_readonly_storage_buffers, + uint32_t num_readwrite_storage_images, + uint32_t num_readwrite_storage_buffers, + uint32_t num_uniform_buffers); +void CleanupPipeline(PulseDevice device, PulseComputePipeline pipeline); #endif diff --git a/Tests/Vulkan/Shaders/.gitignore b/Tests/Vulkan/Shaders/.gitignore new file mode 100644 index 0000000..289a601 --- /dev/null +++ b/Tests/Vulkan/Shaders/.gitignore @@ -0,0 +1 @@ +*.spv.h diff --git a/Tests/Vulkan/Shaders/SimpleBufferWrite.nzsl b/Tests/Vulkan/Shaders/SimpleBufferWrite.nzsl new file mode 100644 index 0000000..a5b302d --- /dev/null +++ b/Tests/Vulkan/Shaders/SimpleBufferWrite.nzsl @@ -0,0 +1,25 @@ +[nzsl_version("1.0")] +module; + +struct Input +{ + [builtin(global_invocation_indices)] indices: vec3[u32] +} + +[layout(std430)] +struct SSBO +{ + data: dyn_array[u32] +} + +external +{ + [set(1), binding(0)] ssbo: storage[SSBO], +} + +[entry(compute)] +[workgroup(32, 32, 1)] +fn main(input: Input) +{ + ssbo.data[input.indices.x * input.indices.y] = u32(0xFFFFFFFF); +} diff --git a/Tests/Vulkan/xmake.lua b/Tests/Vulkan/xmake.lua index 48fb84b..d980fe9 100644 --- a/Tests/Vulkan/xmake.lua +++ b/Tests/Vulkan/xmake.lua @@ -1,5 +1,95 @@ option("vulkan-tests", { description = "Build Vulkan tests", default = false }) +add_repositories("nazara-engine-repo https://github.com/NazaraEngine/xmake-repo") + +add_requires("nzsl >=2023.12.31", { configs = { shared = false, nzslc = true } }) + +if is_cross() then + add_requires("nzsl~host", { kind = "binary", host = true }) +end + +-- Yoinked from NZSL xmake repo +rule("find_nzsl") + on_config(function(target) + import("core.project.project") + import("core.tool.toolchain") + import("lib.detect.find_tool") + + local envs + if is_plat("windows") then + local msvc = target:toolchain("msvc") + if msvc and msvc:check() then + envs = msvc:runenvs() + end + elseif is_plat("mingw") then + local mingw = target:toolchain("mingw") + if mingw and mingw:check() then + envs = mingw:runenvs() + end + end + target:data_set("nzsl_envs", envs) + + local nzsl = project.required_package("nzsl~host") or project.required_package("nzsl") + local nzsldir + if nzsl then + nzsldir = path.join(nzsl:installdir(), "bin") + local osenvs = os.getenvs() + envs = envs or {} + for env, values in pairs(nzsl:get("envs")) do + local flatval = path.joinenv(values) + local oldenv = envs[env] or osenvs[env] + if not oldenv or oldenv == "" then + envs[env] = flatval + elseif not oldenv:startswith(flatval) then + envs[env] = flatval .. path.envsep() .. oldenv + end + end + end + + local nzsla = find_tool("nzsla", { version = true, paths = nzsldir, envs = envs }) + local nzslc = find_tool("nzslc", { version = true, paths = nzsldir, envs = envs }) + + target:data_set("nzsla", nzsla) + target:data_set("nzslc", nzslc) + target:data_set("nzsl_runenv", envs) + end) +rule_end() + +rule("compile_shaders") + set_extensions(".nzsl") + add_deps("find_nzsl") + + before_buildcmd_file(function(target, batchcmds, shaderfile, opt) + local outputdir = target:data("nzsl_includedirs") + local nzslc = target:data("nzslc") + local runenvs = target:data("nzsl_runenv") + assert(nzslc, "nzslc not found! please install nzsl package with nzslc enabled") + + batchcmds:show_progress(opt.progress, "${color.build.object}compiling.shader %s", shaderfile) + local argv = { "--compile=spv-header", "--optimize" } + if outputdir then + batchcmds:mkdir(outputdir) + table.insert(argv, "--output=" .. outputdir) + end + + local kind = target:data("plugin.project.kind") or "" + if kind:match("vs") then + table.insert(argv, "--log-format=vs") + end + + table.insert(argv, shaderfile) + + batchcmds:vrunv(nzslc.program, argv, { curdir = ".", envs = runenvs }) + + local outputfile = path.join(outputdir or path.directory(shaderfile), path.basename(shaderfile) .. ".spv.h") + + batchcmds:add_depfiles(shaderfile) + batchcmds:add_depvalues(nzslc.version) + batchcmds:set_depmtime(os.mtime(outputfile)) + batchcmds:set_depcache(target:dependfile(outputfile)) + end) +rule_end() + if has_config("vulkan-tests") then set_group("VulkanTests") add_requires("unity_test") @@ -7,7 +97,9 @@ if has_config("vulkan-tests") then target("VulkanUnitTests") set_kind("binary") add_deps("pulse_gpu") + add_rules("compile_shaders") add_files("**.c") + add_files("**.nzsl") add_packages("unity_test") if is_plat("linux") then set_extension(".x86_64") diff --git a/Xmake/Actions/CheckFiles.lua b/Xmake/Actions/CheckFiles.lua index b81f7c0..08b1e42 100644 --- a/Xmake/Actions/CheckFiles.lua +++ b/Xmake/Actions/CheckFiles.lua @@ -12,8 +12,8 @@ set_menu({ on_run(function() import("core.base.option") - local file_lines = {} - local updated_files = {} + local file_lines = { 0 } + local updated_files = { 0 } local function GetFile(file_path) file_path = path.translate(file_path) @@ -38,7 +38,7 @@ on_run(function() updated_files[file_path] = true end - local checks = {} + local checks = { 0 } -- Remove empty lines at the beginning of files table.insert(checks, { @@ -53,7 +53,7 @@ on_run(function() os.files("Sources/**.cpp") ) - local fixes = {} + local fixes = { 0 } for _, file_path in pairs(files) do local lines = GetFile(file_path) @@ -98,7 +98,7 @@ on_run(function() ) local current_year = os.date("%Y") - local fixes = {} + local fixes = { 0 } -- Headers for _, file_path in pairs(files) do @@ -168,7 +168,7 @@ on_run(function() for _, check in pairs(checks) do print("Running " .. check.Name .. " check...") - local fixes = {} + local fixes = { 0 } table.join2(fixes, check.Check()) if sould_fix then