From 6a40074c083bdf7f12b9153fdf4f137fa2299b5c Mon Sep 17 00:00:00 2001 From: Kbz-8 Date: Sun, 26 Jan 2025 00:35:06 +0100 Subject: [PATCH] working on vulkan descriptor sets --- Examples/Vulkan/main.c | 7 +- Includes/Pulse.h | 33 +++-- Sources/Backends/Vulkan/VulkanBuffer.c | 2 +- Sources/Backends/Vulkan/VulkanCommandList.c | 38 +++++- Sources/Backends/Vulkan/VulkanCommandList.h | 12 ++ .../Backends/Vulkan/VulkanComputePipeline.c | 39 ++++-- .../Backends/Vulkan/VulkanComputePipeline.h | 6 +- Sources/Backends/Vulkan/VulkanDescriptor.c | 129 +++++++++++++++++- Sources/Backends/Vulkan/VulkanDescriptor.h | 22 ++- Sources/Backends/Vulkan/VulkanDevice.c | 5 + Sources/Backends/Vulkan/VulkanDevice.h | 4 + .../Backends/Vulkan/VulkanDevicePrototypes.h | 1 + Sources/Backends/Vulkan/VulkanEnums.h | 9 -- Sources/Backends/Vulkan/VulkanImage.c | 28 +++- Sources/PulseCommandList.c | 50 +++++++ Sources/PulseComputePipeline.c | 84 +++++++----- Sources/PulseDefs.h | 32 ++++- Sources/PulseImage.c | 40 ++++++ Sources/PulseInternal.h | 55 ++++++-- Sources/PulsePFNs.h | 8 +- Tests/Vulkan/Buffer.c | 6 - Tests/Vulkan/Pipeline.c | 20 +++ xmake.lua | 2 +- 23 files changed, 518 insertions(+), 114 deletions(-) create mode 100644 Tests/Vulkan/Pipeline.c diff --git a/Examples/Vulkan/main.c b/Examples/Vulkan/main.c index fa50cc5..7db5179 100644 --- a/Examples/Vulkan/main.c +++ b/Examples/Vulkan/main.c @@ -56,7 +56,12 @@ int main(void) PulseCommandList cmd = PulseRequestCommandList(device, PULSE_COMMAND_LIST_GENERAL); CHECK_PULSE_HANDLE_RETVAL(cmd, 1); - PulseDispatchComputePipeline(pipeline, cmd, 8, 8, 8); + PulseComputePass pass = PulseBeginComputePass(cmd); + CHECK_PULSE_HANDLE_RETVAL(pass, 1); + PulseBindStorageBuffers(pass, 0, &buffer, 1); + PulseBindComputePipeline(pass, pipeline); + PulseDispatchComputations(pass, 8, 8, 8); + PulseEndComputePass(pass); if(!PulseSubmitCommandList(device, cmd, fence)) fprintf(stderr, "Could not submit command list, %s\n", PulseVerbaliseErrorType(PulseGetLastErrorType())); diff --git a/Includes/Pulse.h b/Includes/Pulse.h index 8ab0d09..58e3afb 100644 --- a/Includes/Pulse.h +++ b/Includes/Pulse.h @@ -29,14 +29,15 @@ PULSE_DEFINE_NULLABLE_HANDLE(PulseComputePipeline); PULSE_DEFINE_NULLABLE_HANDLE(PulseDevice); PULSE_DEFINE_NULLABLE_HANDLE(PulseFence); PULSE_DEFINE_NULLABLE_HANDLE(PulseImage); +PULSE_DEFINE_NULLABLE_HANDLE(PulseComputePass); // Flags typedef enum PulseBackendBits { PULSE_BACKEND_INVALID = PULSE_BIT(1), - PULSE_BACKEND_ANY = PULSE_BIT(2), - PULSE_BACKEND_VULKAN = PULSE_BIT(3), - PULSE_BACKEND_METAL = PULSE_BIT(4), + PULSE_BACKEND_ANY = PULSE_BIT(2), + PULSE_BACKEND_VULKAN = PULSE_BIT(3), + PULSE_BACKEND_METAL = PULSE_BIT(4), // More to come } PulseBackendBits; typedef PulseFlags PulseBackendFlags; @@ -47,7 +48,6 @@ typedef enum PulseBufferUsageBits PULSE_BUFFER_USAGE_TRANSFER_DOWNLOAD = PULSE_BIT(2), PULSE_BUFFER_USAGE_STORAGE_READ = PULSE_BIT(3), PULSE_BUFFER_USAGE_STORAGE_WRITE = PULSE_BIT(4), - PULSE_BUFFER_USAGE_UNIFORM_ACCESS = PULSE_BIT(5), } PulseShaderFormatBits; typedef PulseFlags PulseBufferUsageFlags; @@ -67,9 +67,9 @@ typedef PulseFlags PulseImageUsageFlags; typedef enum PulseShaderFormatsBits { - PULSE_SHADER_FORMAT_SPIRV_BIT = PULSE_BIT(1), // Can be used by Vulkan - PULSE_SHADER_FORMAT_MSL_BIT = PULSE_BIT(2), // Can be used by Metal - PULSE_SHADER_FORMAT_METALLIB_BIT = PULSE_BIT(3), // Can be used by Metal + PULSE_SHADER_FORMAT_SPIRV_BIT = PULSE_BIT(1), // Can be used by Vulkan + PULSE_SHADER_FORMAT_MSL_BIT = PULSE_BIT(2), // Can be used by Metal + PULSE_SHADER_FORMAT_METALLIB_BIT = PULSE_BIT(3), // Can be used by Metal // More to come } PulseShaderFormatsBits; typedef PulseFlags PulseShaderFormatsFlags; @@ -133,7 +133,7 @@ typedef enum PulseImageFormat PULSE_IMAGE_FORMAT_R16G16_UNORM, PULSE_IMAGE_FORMAT_R16G16B16A16_UNORM, PULSE_IMAGE_FORMAT_R10G10B10A2_UNORM, - PULSE_IMAGE_FORMAT_B5G6R5_UNORM, + PULSE_IMAGE_FORMAT_B5G6R5_UNORM, PULSE_IMAGE_FORMAT_B5G5R5A1_UNORM, PULSE_IMAGE_FORMAT_B4G4R4A4_UNORM, PULSE_IMAGE_FORMAT_B8G8R8A8_UNORM, @@ -184,14 +184,6 @@ typedef enum PulseImageFormat PULSE_IMAGE_FORMAT_R32_INT, PULSE_IMAGE_FORMAT_R32G32_INT, PULSE_IMAGE_FORMAT_R32G32B32A32_INT, - // SRGB Unsigned Normalized Color Formats - PULSE_IMAGE_FORMAT_R8G8B8A8_UNORM_SRGB, - PULSE_IMAGE_FORMAT_B8G8R8A8_UNORM_SRGB, - // Compressed SRGB Unsigned Normalized Color Formats - PULSE_IMAGE_FORMAT_BC1_RGBA_UNORM_SRGB, - PULSE_IMAGE_FORMAT_BC2_RGBA_UNORM_SRGB, - PULSE_IMAGE_FORMAT_BC3_RGBA_UNORM_SRGB, - PULSE_IMAGE_FORMAT_BC7_RGBA_UNORM_SRGB, PULSE_IMAGE_FORMAT_MAX_ENUM // For internal use only } PulseImageFormat; @@ -283,9 +275,16 @@ PULSE_API bool PulseIsFenceReady(PulseDevice device, PulseFence fence); PULSE_API bool PulseWaitForFences(PulseDevice device, const PulseFence* fences, uint32_t fences_count, bool wait_for_all); PULSE_API PulseComputePipeline PulseCreateComputePipeline(PulseDevice device, const PulseComputePipelineCreateInfo* info); -PULSE_API void PulseDispatchComputePipeline(PulseComputePipeline pipeline, PulseCommandList cmd, uint32_t groupcount_x, uint32_t groupcount_y, uint32_t groupcount_z); PULSE_API void PulseDestroyComputePipeline(PulseDevice device, PulseComputePipeline pipeline); +PULSE_API PulseComputePass PulseBeginComputePass(PulseCommandList cmd); +PULSE_API void PulseBindStorageBuffers(PulseComputePass pass, uint32_t starting_slot, PulseBuffer* const* buffers, uint32_t num_buffers); +PULSE_API void PulseBindUniformData(PulseComputePass pass, uint32_t slot, const void* data, uint32_t data_size); +PULSE_API void PulseBindStorageImages(PulseComputePass pass, uint32_t starting_slot, PulseImage* const* images, uint32_t num_images); +PULSE_API void PulseBindComputePipeline(PulseComputePass pass, PulseComputePipeline pipeline); +PULSE_API void PulseDispatchComputations(PulseComputePass pass, uint32_t groupcount_x, uint32_t groupcount_y, uint32_t groupcount_z); +PULSE_API void PulseEndComputePass(PulseComputePass pass); + PULSE_API PulseErrorType PulseGetLastErrorType(); // Call to this function resets the internal last error variable PULSE_API const char* PulseVerbaliseErrorType(PulseErrorType error); diff --git a/Sources/Backends/Vulkan/VulkanBuffer.c b/Sources/Backends/Vulkan/VulkanBuffer.c index 1a16362..bed7d75 100644 --- a/Sources/Backends/Vulkan/VulkanBuffer.c +++ b/Sources/Backends/Vulkan/VulkanBuffer.c @@ -37,7 +37,7 @@ PulseBuffer VulkanCreateBuffer(PulseDevice device, const PulseBufferCreateInfo* vulkan_buffer->usage |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; allocation_create_info.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT; } - if(buffer->usage & PULSE_BUFFER_USAGE_UNIFORM_ACCESS) + if(buffer->usage & PULSE_INTERNAL_BUFFER_USAGE_UNIFORM_ACCESS) { vulkan_buffer->usage |= VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; allocation_create_info.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT; diff --git a/Sources/Backends/Vulkan/VulkanCommandList.c b/Sources/Backends/Vulkan/VulkanCommandList.c index 25ccb4b..796b343 100644 --- a/Sources/Backends/Vulkan/VulkanCommandList.c +++ b/Sources/Backends/Vulkan/VulkanCommandList.c @@ -26,16 +26,31 @@ static void VulkanInitCommandList(VulkanCommandPool* pool, PulseCommandList cmd) info.commandBufferCount = 1; CHECK_VK(pool->device->backend, vulkan_device->vkAllocateCommandBuffers(vulkan_device->device, &info, &vulkan_cmd->cmd), PULSE_ERROR_INITIALIZATION_FAILED); - if(pool->available_command_lists_size == pool->available_command_lists_capacity) - { - pool->available_command_lists_capacity += 5; - pool->available_command_lists = (PulseCommandList*)realloc(pool->available_command_lists, pool->available_command_lists_capacity * sizeof(PulseCommandList)); - PULSE_CHECK_ALLOCATION(pool->available_command_lists); - } + PULSE_EXPAND_ARRAY_IF_NEEDED(pool->available_command_lists, PulseCommandList, pool->available_command_lists_size, pool->available_command_lists_capacity, 5); pool->available_command_lists[pool->available_command_lists_size] = cmd; pool->available_command_lists_size++; } +PulseComputePass VulkanCreateComputePass(PulseDevice device, PulseCommandList cmd) +{ + PulseComputePass pass = (PulseComputePass)calloc(1, sizeof(PulseComputePassHandler)); + PULSE_CHECK_ALLOCATION_RETVAL(pass, PULSE_NULL_HANDLE); + + VulkanComputePass* vulkan_pass = (VulkanComputePass*)calloc(1, sizeof(VulkanComputePass)); + PULSE_CHECK_ALLOCATION_RETVAL(vulkan_pass, PULSE_NULL_HANDLE); + + VulkanDevice* vulkan_device = VULKAN_RETRIEVE_DRIVER_DATA_AS(device, VulkanDevice*); + +// vulkan_pass->read_only_descriptor_set = VulkanRequestDescriptorSetFromPool( +// VulkanGetAvailableDescriptorSetPool(&vulkan_device->descriptor_set_pool_manager), +// VulkanGetDescriptorSetLayout(&vulkan_device->descriptor_set_layout_manager, )); + + pass->cmd = cmd; + pass->driver_data = vulkan_pass; + + return pass; +} + PulseCommandList VulkanRequestCommandList(PulseDevice device, PulseCommandListUsage usage) { PULSE_CHECK_HANDLE_RETVAL(device, PULSE_NULL_HANDLE); @@ -77,7 +92,7 @@ PulseCommandList VulkanRequestCommandList(PulseDevice device, PulseCommandListUs VulkanInitCommandList(pool, cmd); } - cmd->compute_pipelines_bound_size = 0; + cmd->pass = VulkanCreateComputePass(device, cmd); cmd->state = PULSE_COMMAND_LIST_STATE_RECORDING; cmd->is_available = false; @@ -169,3 +184,12 @@ void VulkanReleaseCommandList(PulseDevice device, PulseCommandList cmd) } } } + +PulseComputePass VulkanBeginComputePass(PulseCommandList cmd) +{ + return cmd->pass; +} + +void VulkanEndComputePass(PulseComputePass pass) +{ +} diff --git a/Sources/Backends/Vulkan/VulkanCommandList.h b/Sources/Backends/Vulkan/VulkanCommandList.h index 70651ea..8a69d4d 100644 --- a/Sources/Backends/Vulkan/VulkanCommandList.h +++ b/Sources/Backends/Vulkan/VulkanCommandList.h @@ -10,7 +10,9 @@ #include #include +#include "VulkanBuffer.h" #include "VulkanCommandPool.h" +#include "VulkanDescriptor.h" typedef struct VulkanCommandList { @@ -18,9 +20,19 @@ typedef struct VulkanCommandList VkCommandBuffer cmd; } VulkanCommandList; +typedef struct VulkanComputePass +{ + VulkanDescriptorSet* read_only_descriptor_set; + VulkanDescriptorSet* read_write_descriptor_set; + VulkanDescriptorSet* uniform_descriptor_set; + PulseBuffer uniform_buffer; +} VulkanComputePass; + PulseCommandList VulkanRequestCommandList(PulseDevice device, PulseCommandListUsage usage); bool VulkanSubmitCommandList(PulseDevice device, PulseCommandList cmd, PulseFence fence); void VulkanReleaseCommandList(PulseDevice device, PulseCommandList cmd); +PulseComputePass VulkanBeginComputePass(PulseCommandList cmd); +void VulkanEndComputePass(PulseComputePass pass); #endif // PULSE_VULKAN_COMMAND_LIST_H_ diff --git a/Sources/Backends/Vulkan/VulkanComputePipeline.c b/Sources/Backends/Vulkan/VulkanComputePipeline.c index a213842..bd410a0 100644 --- a/Sources/Backends/Vulkan/VulkanComputePipeline.c +++ b/Sources/Backends/Vulkan/VulkanComputePipeline.c @@ -60,16 +60,6 @@ PulseComputePipeline VulkanCreateComputePipeline(PulseDevice device, const Pulse return pipeline; } -void VulkanDispatchComputePipeline(PulseComputePipeline pipeline, PulseCommandList cmd, uint32_t groupcount_x, uint32_t groupcount_y, uint32_t groupcount_z) -{ - VulkanComputePipeline* vulkan_pipeline = VULKAN_RETRIEVE_DRIVER_DATA_AS(pipeline, VulkanComputePipeline*); - VulkanDevice* vulkan_device = VULKAN_RETRIEVE_DRIVER_DATA_AS(cmd->device, VulkanDevice*); - VulkanCommandList* vulkan_cmd = VULKAN_RETRIEVE_DRIVER_DATA_AS(cmd, VulkanCommandList*); - - vulkan_device->vkCmdBindPipeline(vulkan_cmd->cmd, VK_PIPELINE_BIND_POINT_COMPUTE, vulkan_pipeline->pipeline); - vulkan_device->vkCmdDispatch(vulkan_cmd->cmd, groupcount_x, groupcount_y, groupcount_z); -} - void VulkanDestroyComputePipeline(PulseDevice device, PulseComputePipeline pipeline) { if(pipeline == PULSE_NULL_HANDLE) @@ -91,3 +81,32 @@ void VulkanDestroyComputePipeline(PulseDevice device, PulseComputePipeline pipel if(PULSE_IS_BACKEND_HIGH_LEVEL_DEBUG(device->backend)) PulseLogInfoFmt(device->backend, "(Vulkan) destroyed compute pipeline %p", pipeline); } + +void VulkanBindStorageBuffers(PulseComputePass pass, uint32_t starting_slot, PulseBuffer* const* buffers, uint32_t num_buffers) +{ +} + +void VulkanBindUniformData(PulseComputePass pass, uint32_t slot, const void* data, uint32_t data_size) +{ +} + +void VulkanBindStorageImages(PulseComputePass pass, uint32_t starting_slot, PulseImage* const* images, uint32_t num_images) +{ +} + +void VulkanBindComputePipeline(PulseComputePass pass, PulseComputePipeline pipeline) +{ + VulkanComputePipeline* vulkan_pipeline = VULKAN_RETRIEVE_DRIVER_DATA_AS(pipeline, VulkanComputePipeline*); + VulkanDevice* vulkan_device = VULKAN_RETRIEVE_DRIVER_DATA_AS(pass->cmd->device, VulkanDevice*); + VulkanCommandList* vulkan_cmd = VULKAN_RETRIEVE_DRIVER_DATA_AS(pass->cmd, VulkanCommandList*); + + vulkan_device->vkCmdBindPipeline(vulkan_cmd->cmd, VK_PIPELINE_BIND_POINT_COMPUTE, vulkan_pipeline->pipeline); +} + +void VulkanDispatchComputations(PulseComputePass pass, uint32_t groupcount_x, uint32_t groupcount_y, uint32_t groupcount_z) +{ + VulkanDevice* vulkan_device = VULKAN_RETRIEVE_DRIVER_DATA_AS(pass->cmd->device, VulkanDevice*); + VulkanCommandList* vulkan_cmd = VULKAN_RETRIEVE_DRIVER_DATA_AS(pass->cmd, VulkanCommandList*); + + vulkan_device->vkCmdDispatch(vulkan_cmd->cmd, groupcount_x, groupcount_y, groupcount_z); +} diff --git a/Sources/Backends/Vulkan/VulkanComputePipeline.h b/Sources/Backends/Vulkan/VulkanComputePipeline.h index a1be7eb..ff3512e 100644 --- a/Sources/Backends/Vulkan/VulkanComputePipeline.h +++ b/Sources/Backends/Vulkan/VulkanComputePipeline.h @@ -19,8 +19,12 @@ typedef struct VulkanComputePipeline } VulkanComputePipeline; PulseComputePipeline VulkanCreateComputePipeline(PulseDevice device, const PulseComputePipelineCreateInfo* info); -void VulkanDispatchComputePipeline(PulseComputePipeline pipeline, PulseCommandList cmd, uint32_t groupcount_x, uint32_t groupcount_y, uint32_t groupcount_z); void VulkanDestroyComputePipeline(PulseDevice device, PulseComputePipeline pipeline); +void VulkanBindStorageBuffers(PulseComputePass pass, uint32_t starting_slot, PulseBuffer* const* buffers, uint32_t num_buffers); +void VulkanBindUniformData(PulseComputePass pass, uint32_t slot, const void* data, uint32_t data_size); +void VulkanBindStorageImages(PulseComputePass pass, uint32_t starting_slot, PulseImage* const* images, uint32_t num_images); +void VulkanBindComputePipeline(PulseComputePass pass, PulseComputePipeline pipeline); +void VulkanDispatchComputations(PulseComputePass pass, uint32_t groupcount_x, uint32_t groupcount_y, uint32_t groupcount_z); #endif // PULSE_VULKAN_COMPUTE_PIPELINE_H_ diff --git a/Sources/Backends/Vulkan/VulkanDescriptor.c b/Sources/Backends/Vulkan/VulkanDescriptor.c index b0efafd..59af17e 100644 --- a/Sources/Backends/Vulkan/VulkanDescriptor.c +++ b/Sources/Backends/Vulkan/VulkanDescriptor.c @@ -10,28 +10,145 @@ #include "VulkanDevice.h" #include "VulkanDescriptor.h" +#undef NDEBUG +#include + +void VulkanInitDescriptorSetLayoutManager(VulkanDescriptorSetLayoutManager* manager, PulseDevice device) +{ + memset(manager, 0, sizeof(VulkanDescriptorSetLayoutManager)); + manager->device = 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 write_storage_images_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]; + 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) + { + return layout; + } + } + + 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]; + + 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); + + // Category 1 + for(uint32_t i = 0; i < read_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 = read_storage_images_count; i < read_storage_images_count + read_storage_buffers_count; i++) + { + 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 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++) + { + 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_DYNAMIC; + 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.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; + 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; + + return layout; +} + +void VulkanDestroyDescriptorSetLayout(VulkanDescriptorSetLayout* layout, PulseDevice device) +{ + VulkanDevice* vulkan_device = VULKAN_RETRIEVE_DRIVER_DATA_AS(device, VulkanDevice*); + vulkan_device->vkDestroyDescriptorSetLayout(vulkan_device->device, layout->layout, PULSE_NULLPTR); +} + +void VulkanDestroyDescriptorSetLayoutManager(VulkanDescriptorSetLayoutManager* manager) +{ + for(uint32_t i = 0; i < manager->layouts_size; i++) + { + VulkanDestroyDescriptorSetLayout(&manager->layouts[i], manager->device); + } + free(manager->layouts); + memset(manager, 0, sizeof(VulkanDescriptorSetPoolManager)); +} + void VulkanInitDescriptorSetPool(VulkanDescriptorSetPool* pool, PulseDevice device) { VulkanDevice* vulkan_device = VULKAN_RETRIEVE_DRIVER_DATA_AS(device, VulkanDevice*); memset(pool, 0, sizeof(VulkanDescriptorSetPool)); pool->device = device; + pool->thread_id = PulseGetThreadID(); VkDescriptorPoolSize pool_sizes[ - PULSE_MAX_STORAGE_TEXTURES_BOUND + - PULSE_MAX_STORAGE_BUFFERS_BOUND + + 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]; uint32_t i = 0; - for(uint32_t start = i; i < start + PULSE_MAX_STORAGE_TEXTURES_BOUND; i++) + 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].descriptorCount = VULKAN_POOL_SIZE; } - for(uint32_t start = i; i < start + PULSE_MAX_STORAGE_BUFFERS_BOUND; i++) + for(uint32_t start = i; i < start + PULSE_MAX_READ_BUFFERS_BOUND; i++) { pool_sizes[i].type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; pool_sizes[i].descriptorCount = VULKAN_POOL_SIZE; @@ -146,7 +263,6 @@ void VulkanDestroyDescriptorSetPool(VulkanDescriptorSetPool* pool) memset(pool, 0, sizeof(VulkanDescriptorSetPool)); } - void VulkanInitDescriptorSetPoolManager(VulkanDescriptorSetPoolManager* manager, PulseDevice device) { memset(manager, 0, sizeof(VulkanDescriptorSetPoolManager)); @@ -155,9 +271,10 @@ void VulkanInitDescriptorSetPoolManager(VulkanDescriptorSetPoolManager* manager, VulkanDescriptorSetPool* VulkanGetAvailableDescriptorSetPool(VulkanDescriptorSetPoolManager* manager) { + PulseThreadID thread_id = PulseGetThreadID(); for(uint32_t i = 0; i < manager->pools_size; i++) { - if(manager->pools[i]->allocations_count < VULKAN_POOL_SIZE || manager->pools[i]->free_sets[0] != PULSE_NULLPTR) + if(thread_id == manager->pools[i]->thread_id && (manager->pools[i]->allocations_count < VULKAN_POOL_SIZE || manager->pools[i]->free_sets[0] != PULSE_NULLPTR)) return manager->pools[i]; } PULSE_EXPAND_ARRAY_IF_NEEDED(manager->pools, VulkanDescriptorSetPool*, manager->pools_size, manager->pools_capacity, 1); diff --git a/Sources/Backends/Vulkan/VulkanDescriptor.h b/Sources/Backends/Vulkan/VulkanDescriptor.h index 108c640..0f8c780 100644 --- a/Sources/Backends/Vulkan/VulkanDescriptor.h +++ b/Sources/Backends/Vulkan/VulkanDescriptor.h @@ -10,6 +10,7 @@ #include #include +#include "../../PulseInternal.h" #include "VulkanEnums.h" @@ -18,7 +19,6 @@ typedef struct VulkanDescriptorSetLayout { VkDescriptorSetLayout layout; - VulkanDescriptorSetType type; union { @@ -55,6 +55,7 @@ typedef struct VulkanDescriptorSetPool uint32_t free_index; PulseDevice device; VkDescriptorPool pool; + PulseThreadID thread_id; uint32_t allocations_count; } VulkanDescriptorSetPool; @@ -66,10 +67,25 @@ typedef struct VulkanDescriptorSetPoolManager uint32_t pools_size; } VulkanDescriptorSetPoolManager; -void VulkanInitDescriptorSetPool(VulkanDescriptorSetPool* pool, PulseDevice device); +typedef struct VulkanDescriptorSetLayoutManager +{ + PulseDevice device; + 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 write_storage_images_count, + uint32_t uniform_buffers_count); +void VulkanDestroyDescriptorSetLayoutManager(VulkanDescriptorSetLayoutManager* manager); + VulkanDescriptorSet* VulkanRequestDescriptorSetFromPool(VulkanDescriptorSetPool* pool, const VulkanDescriptorSetLayout* layout); void VulkanReturnDescriptorSetToPool(VulkanDescriptorSetPool* pool, const VulkanDescriptorSet* set); -void VulkanDestroyDescriptorSetPool(VulkanDescriptorSetPool* pool); void VulkanInitDescriptorSetPoolManager(VulkanDescriptorSetPoolManager* manager, PulseDevice device); VulkanDescriptorSetPool* VulkanGetAvailableDescriptorSetPool(VulkanDescriptorSetPoolManager* manager); diff --git a/Sources/Backends/Vulkan/VulkanDevice.c b/Sources/Backends/Vulkan/VulkanDevice.c index a78c80f..e1eb387 100644 --- a/Sources/Backends/Vulkan/VulkanDevice.c +++ b/Sources/Backends/Vulkan/VulkanDevice.c @@ -228,6 +228,9 @@ PulseDevice VulkanCreateDevice(PulseBackend backend, PulseDevice* forbiden_devic pulse_device->backend = backend; PULSE_LOAD_DRIVER_DEVICE(Vulkan); + VulkanInitDescriptorSetPoolManager(&device->descriptor_set_pool_manager, pulse_device); + VulkanInitDescriptorSetLayoutManager(&device->descriptor_set_layout_manager, pulse_device); + if(PULSE_IS_BACKEND_HIGH_LEVEL_DEBUG(backend)) PulseLogInfoFmt(backend, "(Vulkan) created device from %s", device->properties.deviceName); return pulse_device; @@ -238,6 +241,8 @@ void VulkanDestroyDevice(PulseDevice device) VulkanDevice* vulkan_device = VULKAN_RETRIEVE_DRIVER_DATA_AS(device, VulkanDevice*); if(vulkan_device == PULSE_NULLPTR || vulkan_device->device == VK_NULL_HANDLE) return; + VulkanDestroyDescriptorSetPoolManager(&vulkan_device->descriptor_set_pool_manager); + VulkanDestroyDescriptorSetLayoutManager(&vulkan_device->descriptor_set_layout_manager); for(uint32_t i = 0; i < vulkan_device->cmd_pools_size; i++) vulkan_device->vkDestroyCommandPool(vulkan_device->device, vulkan_device->cmd_pools[i].pool, PULSE_NULLPTR); vmaDestroyAllocator(vulkan_device->allocator); diff --git a/Sources/Backends/Vulkan/VulkanDevice.h b/Sources/Backends/Vulkan/VulkanDevice.h index 18c2898..1a6d257 100644 --- a/Sources/Backends/Vulkan/VulkanDevice.h +++ b/Sources/Backends/Vulkan/VulkanDevice.h @@ -17,12 +17,16 @@ #include #include "VulkanEnums.h" +#include "VulkanDescriptor.h" #include "VulkanCommandPool.h" struct VulkanQueue; typedef struct VulkanDevice { + VulkanDescriptorSetPoolManager descriptor_set_pool_manager; + VulkanDescriptorSetLayoutManager descriptor_set_layout_manager; + VulkanCommandPool* cmd_pools; uint32_t cmd_pools_size; diff --git a/Sources/Backends/Vulkan/VulkanDevicePrototypes.h b/Sources/Backends/Vulkan/VulkanDevicePrototypes.h index dc0a16f..3f20b43 100644 --- a/Sources/Backends/Vulkan/VulkanDevicePrototypes.h +++ b/Sources/Backends/Vulkan/VulkanDevicePrototypes.h @@ -19,6 +19,7 @@ PULSE_VULKAN_DEVICE_FUNCTION(vkCmdBindPipeline) PULSE_VULKAN_DEVICE_FUNCTION(vkCmdCopyBuffer) PULSE_VULKAN_DEVICE_FUNCTION(vkCmdCopyBufferToImage) + PULSE_VULKAN_DEVICE_FUNCTION(vkCmdCopyImageToBuffer) PULSE_VULKAN_DEVICE_FUNCTION(vkCmdDispatch) PULSE_VULKAN_DEVICE_FUNCTION(vkCmdDispatchIndirect) PULSE_VULKAN_DEVICE_FUNCTION(vkCmdExecuteCommands) diff --git a/Sources/Backends/Vulkan/VulkanEnums.h b/Sources/Backends/Vulkan/VulkanEnums.h index 99bf924..b7d8923 100644 --- a/Sources/Backends/Vulkan/VulkanEnums.h +++ b/Sources/Backends/Vulkan/VulkanEnums.h @@ -15,15 +15,6 @@ typedef enum VulkanQueueType VULKAN_QUEUE_END_ENUM // For internal use only } VulkanQueueType; -typedef enum VulkanDescriptorSetType -{ - VULKAN_DESCRIPTOR_SET_READ_ONLY = 0, - VULKAN_DESCRIPTOR_SET_READ_WRITE, - VULKAN_DESCRIPTOR_SET_UNIFORM, - - VULKAN_DESCRIPTOR_SET_END_ENUM // For internal use only -} VulkanDescriptorSetType; - #endif // PULSE_VULKAN_ENUMS_H_ #endif // PULSE_ENABLE_VULKAN_BACKEND diff --git a/Sources/Backends/Vulkan/VulkanImage.c b/Sources/Backends/Vulkan/VulkanImage.c index d11c5c7..f0ea39f 100644 --- a/Sources/Backends/Vulkan/VulkanImage.c +++ b/Sources/Backends/Vulkan/VulkanImage.c @@ -5,8 +5,9 @@ #include "Pulse.h" #include "Vulkan.h" #include "VulkanImage.h" +#include "VulkanBuffer.h" #include "VulkanDevice.h" -#include +#include "VulkanCommandList.h" static VkFormat PulseImageFormatToVkFormat[] = { VK_FORMAT_UNDEFINED, // INVALID @@ -61,12 +62,6 @@ static VkFormat PulseImageFormatToVkFormat[] = { VK_FORMAT_R32_SINT, // R32_INT VK_FORMAT_R32G32_SINT, // R32G32_INT VK_FORMAT_R32G32B32A32_SINT, // R32G32B32A32_INT - VK_FORMAT_R8G8B8A8_SRGB, // R8G8B8A8_UNORM_SRGB - VK_FORMAT_B8G8R8A8_SRGB, // B8G8R8A8_UNORM_SRGB - VK_FORMAT_BC1_RGBA_SRGB_BLOCK, // BC1_UNORM_SRGB - VK_FORMAT_BC2_SRGB_BLOCK, // BC3_UNORM_SRGB - VK_FORMAT_BC3_SRGB_BLOCK, // BC3_UNORM_SRGB - VK_FORMAT_BC7_SRGB_BLOCK, // BC7_UNORM_SRGB }; PULSE_STATIC_ASSERT(PulseImageFormatToVkFormat, (sizeof(PulseImageFormatToVkFormat) / sizeof(VkFormat)) == PULSE_IMAGE_FORMAT_MAX_ENUM); @@ -189,6 +184,25 @@ bool VulkanIsImageFormatValid(PulseDevice device, PulseImageFormat format, Pulse bool VulkanCopyImageToBuffer(PulseCommandList cmd, const PulseImageRegion* src, const PulseBufferRegion* dst) { + VulkanDevice* vulkan_device = VULKAN_RETRIEVE_DRIVER_DATA_AS(src->image->device, VulkanDevice*); + VulkanImage* vulkan_image = VULKAN_RETRIEVE_DRIVER_DATA_AS(src->image, VulkanImage*); + VulkanBuffer* vulkan_buffer = VULKAN_RETRIEVE_DRIVER_DATA_AS(dst->buffer, VulkanBuffer*); + VulkanCommandList* vulkan_cmd = VULKAN_RETRIEVE_DRIVER_DATA_AS(cmd, VulkanCommandList*); + + VkOffset3D offset = { src->x, src->y, src->z }; + VkExtent3D extent = { src->width, src->height, src->depth }; + VkBufferImageCopy region = {}; + region.bufferOffset = dst->offset; + region.bufferRowLength = 0; + region.bufferImageHeight = 0; + region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + region.imageSubresource.mipLevel = 0; + region.imageSubresource.baseArrayLayer = 0; + region.imageSubresource.layerCount = 1; + region.imageOffset = offset; + region.imageExtent = extent; + vulkan_device->vkCmdCopyImageToBuffer(vulkan_cmd->cmd, vulkan_image->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, vulkan_buffer->buffer, 1, ®ion); + return true; } bool VulkanBlitImage(PulseCommandList cmd, const PulseImageRegion* src, const PulseImageRegion* dst) diff --git a/Sources/PulseCommandList.c b/Sources/PulseCommandList.c index 5a67bc7..83a2814 100644 --- a/Sources/PulseCommandList.c +++ b/Sources/PulseCommandList.c @@ -2,6 +2,7 @@ // This file is part of "Pulse" // For conditions of distribution and use, see copyright notice in LICENSE +#include #include "PulseDefs.h" #include "PulseInternal.h" @@ -39,6 +40,16 @@ PULSE_API bool PulseSubmitCommandList(PulseDevice device, PulseCommandList cmd, } } + if(cmd->pass->is_recording) + { + if(PULSE_IS_BACKEND_LOW_LEVEL_DEBUG(device->backend)) + PulseLogWarning(device->backend, "submitting command list with a recording compute pass, stopping record"); + PulseEndComputePass(cmd->pass); + } + + memset(cmd->pass->compute_pipelines_bound, 0, sizeof(PulseComputePipeline) * cmd->pass->compute_pipelines_bound_size); + cmd->pass->compute_pipelines_bound_size = 0; + return device->PFN_SubmitCommandList(device, cmd, fence); } @@ -64,3 +75,42 @@ PULSE_API void PulseReleaseCommandList(PulseDevice device, PulseCommandList cmd) } return device->PFN_ReleaseCommandList(device, cmd); } + +PULSE_API PulseComputePass PulseBeginComputePass(PulseCommandList cmd) +{ + PULSE_CHECK_HANDLE_RETVAL(cmd, PULSE_NULL_HANDLE); + PULSE_CHECK_HANDLE_RETVAL(cmd->device, PULSE_NULL_HANDLE); + + PULSE_CHECK_COMMAND_LIST_STATE_RETVAL(cmd, PULSE_NULL_HANDLE); + PulseComputePass pass = cmd->device->PFN_BeginComputePass(cmd); + if(pass->is_recording == true) + { + if(PULSE_IS_BACKEND_LOW_LEVEL_DEBUG(cmd->device->backend)) + PulseLogWarning(cmd->device->backend, "a compute pass is already recording in this command buffer, please call PulseEndComputePass before beginning a new one"); + return PULSE_NULL_HANDLE; + } + pass->is_recording = true; + return pass; +} + +PULSE_API void PulseEndComputePass(PulseComputePass pass) +{ + if(pass == PULSE_NULL_HANDLE) + { + PULSE_CHECK_HANDLE(pass->cmd); + PULSE_CHECK_HANDLE(pass->cmd->device); + if(PULSE_IS_BACKEND_LOW_LEVEL_DEBUG(pass->cmd->device->backend)) + PulseLogWarning(pass->cmd->device->backend, "command list is NULL, this may be a bug in your application"); + return; + } + PULSE_CHECK_COMMAND_LIST_STATE(pass->cmd); + + memset(pass->readonly_images, 0, PULSE_MAX_READ_TEXTURES_BOUND * sizeof(PulseImage)); + memset(pass->readwrite_images, 0, PULSE_MAX_WRITE_TEXTURES_BOUND * sizeof(PulseImage)); + memset(pass->readonly_storage_buffers, 0, PULSE_MAX_READ_BUFFERS_BOUND * sizeof(PulseBuffer)); + memset(pass->readwrite_storage_buffers, 0, PULSE_MAX_WRITE_BUFFERS_BOUND * sizeof(PulseBuffer)); + + pass->current_pipeline = PULSE_NULL_HANDLE; + + pass->is_recording = false; +} diff --git a/Sources/PulseComputePipeline.c b/Sources/PulseComputePipeline.c index ed1d888..04b2914 100644 --- a/Sources/PulseComputePipeline.c +++ b/Sources/PulseComputePipeline.c @@ -5,54 +5,74 @@ #include "PulseDefs.h" #include "PulseInternal.h" + PULSE_API PulseComputePipeline PulseCreateComputePipeline(PulseDevice device, const PulseComputePipelineCreateInfo* info) { PULSE_CHECK_HANDLE_RETVAL(device, PULSE_NULL_HANDLE); if(info == PULSE_NULLPTR && PULSE_IS_BACKEND_LOW_LEVEL_DEBUG(device->backend)) PulseLogError(device->backend, "null infos pointer"); PULSE_CHECK_PTR_RETVAL(info, PULSE_NULL_HANDLE); - return device->PFN_CreateComputePipeline(device, info); + PulseComputePipeline pipeline = device->PFN_CreateComputePipeline(device, info); + if(pipeline == PULSE_NULL_HANDLE) + 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_buffers = info->num_readwrite_storage_buffers; + pipeline->num_uniform_buffers = info->num_uniform_buffers; + return pipeline; } -PULSE_API void PulseDispatchComputePipeline(PulseComputePipeline pipeline, PulseCommandList cmd, uint32_t groupcount_x, uint32_t groupcount_y, uint32_t groupcount_z) +PULSE_API void PulseBindStorageBuffers(PulseComputePass pass, uint32_t starting_slot, PulseBuffer* const* buffers, uint32_t num_buffers) { + PULSE_CHECK_HANDLE(pass); + + PULSE_CHECK_COMMAND_LIST_STATE(pass->cmd); + + pass->cmd->device->PFN_BindStorageBuffers(pass, starting_slot, buffers, num_buffers); +} + +PULSE_API void PulseBindUniformData(PulseComputePass pass, uint32_t slot, const void* data, uint32_t data_size) +{ + PULSE_CHECK_HANDLE(pass); + + PULSE_CHECK_COMMAND_LIST_STATE(pass->cmd); + + pass->cmd->device->PFN_BindUniformData(pass, slot, data, data_size); +} + +PULSE_API void PulseBindStorageImages(PulseComputePass pass, uint32_t starting_slot, PulseImage* const* images, uint32_t num_images) +{ + PULSE_CHECK_HANDLE(pass); + + PULSE_CHECK_COMMAND_LIST_STATE(pass->cmd); + + pass->cmd->device->PFN_BindStorageImages(pass, starting_slot, images, num_images); +} + +PULSE_API void PulseBindComputePipeline(PulseComputePass pass, PulseComputePipeline pipeline) +{ + PULSE_CHECK_HANDLE(pass); PULSE_CHECK_HANDLE(pipeline); - PULSE_CHECK_HANDLE(cmd); - if(cmd->state != PULSE_COMMAND_LIST_STATE_RECORDING) - { - switch(cmd->state) - { - case PULSE_COMMAND_LIST_STATE_INVALID: - if(PULSE_IS_BACKEND_LOW_LEVEL_DEBUG(cmd->device->backend)) - PulseLogError(cmd->device->backend, "command list is in invalid state"); - return; + PULSE_CHECK_COMMAND_LIST_STATE(pass->cmd); - case PULSE_COMMAND_LIST_STATE_READY: - if(PULSE_IS_BACKEND_LOW_LEVEL_DEBUG(cmd->device->backend)) - PulseLogError(cmd->device->backend, "command list is not recording"); - return; + pass->cmd->device->PFN_BindComputePipeline(pass, pipeline); - case PULSE_COMMAND_LIST_STATE_SENT: - if(PULSE_IS_BACKEND_LOW_LEVEL_DEBUG(cmd->device->backend)) - PulseLogWarning(cmd->device->backend, "command list has already been submitted"); - return; + pass->current_pipeline = pipeline; - default: break; - } - } + PULSE_EXPAND_ARRAY_IF_NEEDED(pass->compute_pipelines_bound, PulseComputePipeline, pass->compute_pipelines_bound_size, pass->compute_pipelines_bound_capacity, 2); + pass->compute_pipelines_bound[pass->compute_pipelines_bound_size] = pipeline; + pass->compute_pipelines_bound_size++; +} - cmd->device->PFN_DispatchComputePipeline(pipeline, cmd, groupcount_x, groupcount_y, groupcount_z); - pipeline->cmd = cmd; +PULSE_API void PulseDispatchComputations(PulseComputePass pass, uint32_t groupcount_x, uint32_t groupcount_y, uint32_t groupcount_z) +{ + PULSE_CHECK_HANDLE(pass); - if(cmd->compute_pipelines_bound_size == cmd->compute_pipelines_bound_capacity) - { - cmd->compute_pipelines_bound_capacity += 5; - cmd->compute_pipelines_bound = (PulseComputePipeline*)realloc(cmd->compute_pipelines_bound, cmd->compute_pipelines_bound_capacity * sizeof(PulseComputePipeline)); - PULSE_CHECK_ALLOCATION(cmd->compute_pipelines_bound); - } - cmd->compute_pipelines_bound[cmd->compute_pipelines_bound_size] = pipeline; - cmd->compute_pipelines_bound_size++; + PULSE_CHECK_COMMAND_LIST_STATE(pass->cmd); + + pass->cmd->device->PFN_DispatchComputations(pass, groupcount_x, groupcount_y, groupcount_z); } PULSE_API void PulseDestroyComputePipeline(PulseDevice device, PulseComputePipeline pipeline) diff --git a/Sources/PulseDefs.h b/Sources/PulseDefs.h index 670a1e6..957b2cf 100644 --- a/Sources/PulseDefs.h +++ b/Sources/PulseDefs.h @@ -62,6 +62,29 @@ for(size_t defrag_i = start; defrag_i < size - 1; defrag_i++) \ array[defrag_i] = array[defrag_i + 1]; \ +#define PULSE_CHECK_COMMAND_LIST_STATE_RETVAL(cmd, retval) \ + if(cmd->state != PULSE_COMMAND_LIST_STATE_RECORDING) \ + { \ + switch(cmd->state) \ + { \ + case PULSE_COMMAND_LIST_STATE_INVALID: \ + if(PULSE_IS_BACKEND_LOW_LEVEL_DEBUG(cmd->device->backend)) \ + PulseLogError(cmd->device->backend, "command list is in invalid state"); \ + return retval; \ + case PULSE_COMMAND_LIST_STATE_READY: \ + if(PULSE_IS_BACKEND_LOW_LEVEL_DEBUG(cmd->device->backend)) \ + PulseLogError(cmd->device->backend, "command list is not recording"); \ + return retval; \ + case PULSE_COMMAND_LIST_STATE_SENT: \ + if(PULSE_IS_BACKEND_LOW_LEVEL_DEBUG(cmd->device->backend)) \ + PulseLogWarning(cmd->device->backend, "command list has already been submitted"); \ + return retval; \ + default: break; \ + } \ + } \ + +#define PULSE_CHECK_COMMAND_LIST_STATE(cmd) PULSE_CHECK_COMMAND_LIST_STATE_RETVAL(cmd, ) + #ifndef PULSE_STATIC_ASSERT #ifdef __cplusplus #if __cplusplus >= 201103L @@ -81,7 +104,7 @@ PULSE_LOAD_DRIVER_DEVICE_FUNCTION(DestroyDevice, _namespace) \ PULSE_LOAD_DRIVER_DEVICE_FUNCTION(CreateComputePipeline, _namespace) \ PULSE_LOAD_DRIVER_DEVICE_FUNCTION(DestroyComputePipeline, _namespace) \ - PULSE_LOAD_DRIVER_DEVICE_FUNCTION(DispatchComputePipeline, _namespace) \ + PULSE_LOAD_DRIVER_DEVICE_FUNCTION(DispatchComputations, _namespace) \ PULSE_LOAD_DRIVER_DEVICE_FUNCTION(CreateFence, _namespace) \ PULSE_LOAD_DRIVER_DEVICE_FUNCTION(DestroyFence, _namespace) \ PULSE_LOAD_DRIVER_DEVICE_FUNCTION(IsFenceReady, _namespace) \ @@ -100,5 +123,12 @@ PULSE_LOAD_DRIVER_DEVICE_FUNCTION(CopyImageToBuffer, _namespace) \ PULSE_LOAD_DRIVER_DEVICE_FUNCTION(BlitImage, _namespace) \ PULSE_LOAD_DRIVER_DEVICE_FUNCTION(DestroyImage, _namespace) \ + PULSE_LOAD_DRIVER_DEVICE_FUNCTION(BeginComputePass, _namespace) \ + PULSE_LOAD_DRIVER_DEVICE_FUNCTION(EndComputePass, _namespace) \ + PULSE_LOAD_DRIVER_DEVICE_FUNCTION(BindStorageBuffers, _namespace) \ + PULSE_LOAD_DRIVER_DEVICE_FUNCTION(BindUniformData, _namespace) \ + PULSE_LOAD_DRIVER_DEVICE_FUNCTION(BindStorageImages, _namespace) \ + PULSE_LOAD_DRIVER_DEVICE_FUNCTION(BindStorageImages, _namespace) \ + PULSE_LOAD_DRIVER_DEVICE_FUNCTION(BindComputePipeline, _namespace) \ #endif // PULSE_DEFS_H_ diff --git a/Sources/PulseImage.c b/Sources/PulseImage.c index fb0c11a..2ca761a 100644 --- a/Sources/PulseImage.c +++ b/Sources/PulseImage.c @@ -124,6 +124,46 @@ PULSE_API bool PulseIsImageFormatValid(PulseDevice device, PulseImageFormat form PULSE_API bool PulseCopyImageToBuffer(PulseCommandList cmd, const PulseImageRegion* src, const PulseBufferRegion* dst) { + PULSE_CHECK_PTR_RETVAL(src, false); + PULSE_CHECK_HANDLE_RETVAL(src->image, false); + PULSE_CHECK_PTR_RETVAL(dst, false); + PULSE_CHECK_HANDLE_RETVAL(dst->buffer, false); + + PulseBackend backend = src->image->device->backend; + + if(src->image->device != dst->buffer->device) + { + if(PULSE_IS_BACKEND_LOW_LEVEL_DEBUG(backend)) + PulseLogErrorFmt(backend, "source image has been created on a different device (%p) than the destination buffer (%p)", src->image->device, dst->buffer->device); + PulseSetInternalError(PULSE_ERROR_INVALID_DEVICE); + return false; + } + + if(dst->size + dst->offset > dst->buffer->size) + { + if(PULSE_IS_BACKEND_LOW_LEVEL_DEBUG(backend)) + PulseLogErrorFmt(backend, "destination buffer region (%lld) is bigger than the buffer size (%lld)", dst->size + dst->offset, dst->buffer->size); + PulseSetInternalError(PULSE_ERROR_INVALID_REGION); + return false; + } + + if(src->width > src->image->width) + { + if(PULSE_IS_BACKEND_LOW_LEVEL_DEBUG(backend)) + PulseLogErrorFmt(backend, "source image region width (%lld) is bigger than image width (%lld)", src->width, src->image->width); + PulseSetInternalError(PULSE_ERROR_INVALID_REGION); + return false; + } + + if(src->height > src->image->height) + { + if(PULSE_IS_BACKEND_LOW_LEVEL_DEBUG(backend)) + PulseLogErrorFmt(backend, "source image region height (%lld) is bigger than image height (%lld)", src->height, src->image->height); + PulseSetInternalError(PULSE_ERROR_INVALID_REGION); + return false; + } + + return src->image->device->PFN_CopyImageToBuffer(cmd, src, dst); } PULSE_API bool PulseBlitImage(PulseCommandList cmd, const PulseImageRegion* src, const PulseImageRegion* dst) diff --git a/Sources/PulseInternal.h b/Sources/PulseInternal.h index 69bb396..8bbb7a0 100644 --- a/Sources/PulseInternal.h +++ b/Sources/PulseInternal.h @@ -11,6 +11,17 @@ #include "PulseDefs.h" #include "PulseEnums.h" +#define PULSE_MAX_READ_TEXTURES_BOUND 8 +#define PULSE_MAX_READ_BUFFERS_BOUND 8 +#define PULSE_MAX_WRITE_TEXTURES_BOUND 8 +#define PULSE_MAX_WRITE_BUFFERS_BOUND 8 +#define PULSE_MAX_UNIFORM_BUFFERS_BOUND 8 + +typedef enum PulseInternalBufferUsageBits +{ + PULSE_INTERNAL_BUFFER_USAGE_UNIFORM_ACCESS = PULSE_BIT(31) +} PulseInternalBufferUsageBits; + typedef uint64_t PulseThreadID; typedef struct PulseBackendHandler @@ -40,11 +51,9 @@ typedef struct PulseBufferHandler typedef struct PulseCommandListHandler { PulseDevice device; + PulseComputePass pass; void* driver_data; PulseThreadID thread_id; - PulseComputePipeline* compute_pipelines_bound; - uint32_t compute_pipelines_bound_capacity; - uint32_t compute_pipelines_bound_size; PulseCommandListState state; PulseCommandListUsage usage; bool is_available; @@ -52,8 +61,12 @@ typedef struct PulseCommandListHandler typedef struct PulseComputePipelineHandler { - PulseCommandList cmd; void* driver_data; + 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; } PulseComputePipelineHandler; typedef struct PulseDeviceHandler @@ -61,7 +74,7 @@ typedef struct PulseDeviceHandler // PFNs PulseDestroyDevicePFN PFN_DestroyDevice; PulseCreateComputePipelinePFN PFN_CreateComputePipeline; - PulseDispatchComputePipelinePFN PFN_DispatchComputePipeline; + PulseDispatchComputationsPFN PFN_DispatchComputations; PulseDestroyComputePipelinePFN PFN_DestroyComputePipeline; PulseCreateFencePFN PFN_CreateFence; PulseDestroyFencePFN PFN_DestroyFence; @@ -81,6 +94,12 @@ typedef struct PulseDeviceHandler PulseCopyImageToBufferPFN PFN_CopyImageToBuffer; PulseBlitImagePFN PFN_BlitImage; PulseDestroyImagePFN PFN_DestroyImage; + PulseBeginComputePassPFN PFN_BeginComputePass; + PulseBindStorageBuffersPFN PFN_BindStorageBuffers; + PulseBindUniformDataPFN PFN_BindUniformData; + PulseBindStorageImagesPFN PFN_BindStorageImages; + PulseBindComputePipelinePFN PFN_BindComputePipeline; + PulseEndComputePassPFN PFN_EndComputePass; // Attributes void* driver_data; @@ -113,6 +132,26 @@ typedef struct PulseImageHandler uint32_t layer_count_or_depth; } PulseImageHandler; +typedef struct PulseComputePassHandler +{ + PulseBuffer readonly_storage_buffers[PULSE_MAX_READ_BUFFERS_BOUND]; + PulseBuffer readwrite_storage_buffers[PULSE_MAX_WRITE_BUFFERS_BOUND]; + + PulseImage readonly_images[PULSE_MAX_READ_TEXTURES_BOUND]; + PulseImage readwrite_images[PULSE_MAX_WRITE_TEXTURES_BOUND]; + + PulseCommandList cmd; + PulseComputePipeline current_pipeline; + + void* driver_data; + + PulseComputePipeline* compute_pipelines_bound; + uint32_t compute_pipelines_bound_capacity; + uint32_t compute_pipelines_bound_size; + + bool is_recording; +} PulseComputePassHandler; + PulseThreadID PulseGetThreadID(); void PulseSetInternalError(PulseErrorType error); @@ -127,12 +166,6 @@ void PulseLogBackend(PulseBackend backend, PulseDebugMessageSeverity type, const #define PulseLogWarningFmt(backend, msg, ...) PulseLogBackend(backend, PULSE_DEBUG_MESSAGE_SEVERITY_WARNING, msg, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__) #define PulseLogInfoFmt(backend, msg, ...) PulseLogBackend(backend, PULSE_DEBUG_MESSAGE_SEVERITY_INFO, msg, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__) -#define PULSE_MAX_STORAGE_TEXTURES_BOUND 8 -#define PULSE_MAX_STORAGE_BUFFERS_BOUND 8 -#define PULSE_MAX_UNIFORM_BUFFERS_BOUND 4 -#define PULSE_MAX_WRITE_TEXTURES_BOUND 8 -#define PULSE_MAX_WRITE_BUFFERS_BOUND 8 - #ifdef PULSE_ENABLE_VULKAN_BACKEND extern PulseBackendHandler VulkanDriver; #endif // PULSE_ENABLE_VULKAN_BACKEND diff --git a/Sources/PulsePFNs.h b/Sources/PulsePFNs.h index e9855f3..5a6ec80 100644 --- a/Sources/PulsePFNs.h +++ b/Sources/PulsePFNs.h @@ -15,7 +15,7 @@ typedef PulseDevice (*PulseCreateDevicePFN)(PulseBackend, PulseDevice*, uint32_t typedef void (*PulseDestroyDevicePFN)(PulseDevice); typedef PulseComputePipeline (*PulseCreateComputePipelinePFN)(PulseDevice, const PulseComputePipelineCreateInfo*); -typedef void (*PulseDispatchComputePipelinePFN)(PulseComputePipeline, PulseCommandList, uint32_t, uint32_t, uint32_t); +typedef void (*PulseDispatchComputationsPFN)(PulseComputePass, uint32_t, uint32_t, uint32_t); typedef void (*PulseDestroyComputePipelinePFN)(PulseDevice, PulseComputePipeline); typedef PulseFence (*PulseCreateFencePFN)(PulseDevice); typedef void (*PulseDestroyFencePFN)(PulseDevice, PulseFence); @@ -35,5 +35,11 @@ typedef bool (*PulseCopyBufferToBufferPFN)(PulseCommandList, const PulseBufferRe typedef bool (*PulseCopyBufferToImageFN)(PulseCommandList, const PulseBufferRegion*, const PulseImageRegion*); typedef bool (*PulseCopyImageToBufferPFN)(PulseCommandList, const PulseImageRegion*, const PulseBufferRegion*); typedef bool (*PulseBlitImagePFN)(PulseCommandList, const PulseImageRegion*, const PulseImageRegion*); +typedef PulseComputePass (*PulseBeginComputePassPFN)(PulseCommandList); +typedef void (*PulseBindStorageBuffersPFN)(PulseComputePass, uint32_t, PulseBuffer* const*, uint32_t); +typedef void (*PulseBindUniformDataPFN)(PulseComputePass, uint32_t, const void*, uint32_t); +typedef void (*PulseBindStorageImagesPFN)(PulseComputePass, uint32_t, PulseImage* const*, uint32_t); +typedef void (*PulseBindComputePipelinePFN)(PulseComputePass, PulseComputePipeline); +typedef void (*PulseEndComputePassPFN)(PulseComputePass); #endif // PULSE_PFNS_H_ diff --git a/Tests/Vulkan/Buffer.c b/Tests/Vulkan/Buffer.c index d2c8eca..b836126 100644 --- a/Tests/Vulkan/Buffer.c +++ b/Tests/Vulkan/Buffer.c @@ -36,12 +36,6 @@ void TestBufferCreation() TEST_ASSERT_NOT_EQUAL_MESSAGE(buffer, PULSE_NULL_HANDLE, PulseVerbaliseErrorType(PulseGetLastErrorType())); PulseDestroyBuffer(device, buffer); - buffer_create_info.size = 1024; - buffer_create_info.usage = PULSE_BUFFER_USAGE_UNIFORM_ACCESS; - buffer = PulseCreateBuffer(device, &buffer_create_info); - TEST_ASSERT_NOT_EQUAL_MESSAGE(buffer, PULSE_NULL_HANDLE, PulseVerbaliseErrorType(PulseGetLastErrorType())); - PulseDestroyBuffer(device, buffer); - buffer_create_info.size = 1024; buffer_create_info.usage = PULSE_BUFFER_USAGE_STORAGE_READ | PULSE_BUFFER_USAGE_STORAGE_WRITE; buffer = PulseCreateBuffer(device, &buffer_create_info); diff --git a/Tests/Vulkan/Pipeline.c b/Tests/Vulkan/Pipeline.c new file mode 100644 index 0000000..3773a8f --- /dev/null +++ b/Tests/Vulkan/Pipeline.c @@ -0,0 +1,20 @@ +#include "Common.h" + +#include +#include + +void TestPipelineSetup() +{ + PulseBackend backend; + SetupPulse(&backend); + PulseDevice device; + SetupDevice(backend, &device); + + CleanupDevice(device); + CleanupPulse(backend); +} + +void TestPipeline() +{ + RUN_TEST(TestPipelineSetup); +} diff --git a/xmake.lua b/xmake.lua index 02bf62d..25bfb57 100644 --- a/xmake.lua +++ b/xmake.lua @@ -43,7 +43,7 @@ end add_rules("mode.debug", "mode.release") add_includedirs("Includes") -set_languages("c11", "cxx20") +set_languages("c17", "cxx20") set_encodings("utf-8") set_warnings("allextra")