diff --git a/Includes/Pulse.h b/Includes/Pulse.h index d921087..c778521 100644 --- a/Includes/Pulse.h +++ b/Includes/Pulse.h @@ -104,6 +104,7 @@ typedef enum PulseErrorType PULSE_ERROR_INITIALIZATION_FAILED, PULSE_ERROR_INVALID_HANDLE, PULSE_ERROR_ALLOCATION_FAILED, + PULSE_ERROR_DEVICE_LOST, } PulseErrorType; typedef enum PulseImageType diff --git a/Sources/Backends/Vulkan/Vulkan.c b/Sources/Backends/Vulkan/Vulkan.c index d22d2e2..0168acf 100644 --- a/Sources/Backends/Vulkan/Vulkan.c +++ b/Sources/Backends/Vulkan/Vulkan.c @@ -51,7 +51,7 @@ bool VulkanLoadBackend(PulseDebugLevel debug_level) void VulkanUnloadBackend(PulseBackend backend) { - VulkanDestroyInstance(&VULKAN_RETRIEVE_DRIVER_DATA(backend)->instance); + VulkanDestroyInstance(&VULKAN_RETRIEVE_DRIVER_DATA_AS(backend, VulkanDriverData*)->instance); VulkanLoaderShutdown(); } diff --git a/Sources/Backends/Vulkan/Vulkan.h b/Sources/Backends/Vulkan/Vulkan.h index 69281da..d951644 100644 --- a/Sources/Backends/Vulkan/Vulkan.h +++ b/Sources/Backends/Vulkan/Vulkan.h @@ -14,7 +14,7 @@ #include "../../PulseInternal.h" -#define VULKAN_RETRIEVE_DRIVER_DATA(handle) ((VulkanDriverData*)handle->driver_data) +#define VULKAN_RETRIEVE_DRIVER_DATA_AS(handle, cast) ((cast)handle->driver_data) #define CHECK_VK_RETVAL(res, error, retval) \ if((res) != VK_SUCCESS) \ diff --git a/Sources/Backends/Vulkan/VulkanDevice.c b/Sources/Backends/Vulkan/VulkanDevice.c index 6d0d919..4112cca 100644 --- a/Sources/Backends/Vulkan/VulkanDevice.c +++ b/Sources/Backends/Vulkan/VulkanDevice.c @@ -6,6 +6,7 @@ #include "Vulkan.h" #include "VulkanComputePipeline.h" #include "VulkanDevice.h" +#include "VulkanFence.h" #include "VulkanInstance.h" #include "VulkanLoader.h" #include "VulkanQueue.h" @@ -117,7 +118,7 @@ PulseDevice VulkanCreateDevice(PulseBackend backend, PulseDevice* forbiden_devic VulkanDevice* device = (VulkanDevice*)calloc(1, sizeof(VulkanDevice)); PULSE_CHECK_ALLOCATION_RETVAL(device, PULSE_NULLPTR); - VulkanInstance* instance = &VULKAN_RETRIEVE_DRIVER_DATA(backend)->instance; + VulkanInstance* instance = &VULKAN_RETRIEVE_DRIVER_DATA_AS(backend, VulkanDriverData*)->instance; device->physical = VulkanPickPhysicalDevice(instance, forbiden_devices, forbiden_devices_count); PULSE_CHECK_HANDLE_RETVAL(device->physical, PULSE_NULLPTR); @@ -226,12 +227,11 @@ PulseDevice VulkanCreateDevice(PulseBackend backend, PulseDevice* forbiden_devic void VulkanDestroyDevice(PulseDevice device) { - VulkanDevice* vulkan_device = (VulkanDevice*)device->driver_data; + VulkanDevice* vulkan_device = VULKAN_RETRIEVE_DRIVER_DATA_AS(device, VulkanDevice*); if(vulkan_device == PULSE_NULLPTR || vulkan_device->device == VK_NULL_HANDLE) return; vmaDestroyAllocator(vulkan_device->allocator); vulkan_device->vkDestroyDevice(vulkan_device->device, PULSE_NULLPTR); - vulkan_device->device = VK_NULL_HANDLE; free(vulkan_device); free(device); } diff --git a/Sources/Backends/Vulkan/VulkanFence.c b/Sources/Backends/Vulkan/VulkanFence.c new file mode 100644 index 0000000..727b817 --- /dev/null +++ b/Sources/Backends/Vulkan/VulkanFence.c @@ -0,0 +1,59 @@ +// Copyright (C) 2024 kanel +// This file is part of "Pulse" +// For conditions of distribution and use, see copyright notice in LICENSE + +#include "Pulse.h" +#include "Vulkan.h" +#include "VulkanDevice.h" +#include "VulkanFence.h" + +PulseFence VulkanCreateFence(PulseDevice device) +{ + VkFenceCreateInfo fence_info = {}; + fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + fence_info.flags = VK_FENCE_CREATE_SIGNALED_BIT; + VkFence vulkan_fence; + VulkanDevice* vulkan_device = VULKAN_RETRIEVE_DRIVER_DATA_AS(device, VulkanDevice*); + CHECK_VK_RETVAL(vulkan_device->vkCreateFence(vulkan_device->device, &fence_info, PULSE_NULLPTR, &vulkan_fence), PULSE_ERROR_INITIALIZATION_FAILED, PULSE_NULL_HANDLE); + + PulseFenceHandler* fence = (PulseFenceHandler*)malloc(sizeof(PulseFenceHandler)); + PULSE_CHECK_ALLOCATION_RETVAL(fence, PULSE_NULL_HANDLE); + fence->driver_data = vulkan_fence; + return fence; +} + +void VulkanDestroyFence(PulseDevice device, PulseFence fence) +{ + VulkanDevice* vulkan_device = VULKAN_RETRIEVE_DRIVER_DATA_AS(device, VulkanDevice*); + if(vulkan_device == PULSE_NULLPTR || vulkan_device->device == VK_NULL_HANDLE) + return; + VkFence vulkan_fence = VULKAN_RETRIEVE_DRIVER_DATA_AS(fence, VkFence); + if(vulkan_fence == VK_NULL_HANDLE) + return; + vulkan_device->vkDestroyFence(vulkan_device->device, vulkan_fence, PULSE_NULLPTR); + free(fence); +} + +bool VulkanIsFenceReady(PulseDevice device, PulseFence fence) +{ + VulkanDevice* vulkan_device = VULKAN_RETRIEVE_DRIVER_DATA_AS(device, VulkanDevice*); + if(vulkan_device == PULSE_NULLPTR || vulkan_device->device == VK_NULL_HANDLE) + return false; + VkFence vulkan_fence = VULKAN_RETRIEVE_DRIVER_DATA_AS(fence, VkFence); + if(vulkan_fence == VK_NULL_HANDLE) + return false; + VkResult res = vulkan_device->vkGetFenceStatus(vulkan_device->device, vulkan_fence); + switch(res) + { + case VK_ERROR_DEVICE_LOST: PulseSetInternalError(PULSE_ERROR_DEVICE_LOST); return false; + case VK_NOT_READY: return false; + case VK_SUCCESS: return true; + + default: return false; + } + return false; +} + +bool VulkanWaitForFences(PulseDevice device, PulseFence *const *fences, uint32_t fences_count, bool wait_for_all) +{ +} diff --git a/Sources/Backends/Vulkan/VulkanFence.h b/Sources/Backends/Vulkan/VulkanFence.h new file mode 100644 index 0000000..e801a43 --- /dev/null +++ b/Sources/Backends/Vulkan/VulkanFence.h @@ -0,0 +1,22 @@ +// Copyright (C) 2024 kanel +// This file is part of "Pulse" +// For conditions of distribution and use, see copyright notice in LICENSE + +#ifdef PULSE_ENABLE_VULKAN_BACKEND + +#ifndef PULSE_VULKAN_FENCE_H_ +#define PULSE_VULKAN_FENCE_H_ + +#include + +#include +#include "VulkanDevice.h" + +PulseFence VulkanCreateFence(PulseDevice device); +void VulkanDestroyFence(PulseDevice device, PulseFence fence); +bool VulkanIsFenceReady(PulseDevice device, PulseFence fence); +bool VulkanWaitForFences(PulseDevice device, PulseFence *const *fences, uint32_t fences_count, bool wait_for_all); + +#endif // PULSE_VULKAN_FENCE_H_ + +#endif // PULSE_ENABLE_VULKAN_BACKEND diff --git a/Sources/PulseBackend.c b/Sources/PulseBackend.c index 58c6ca9..e29ef12 100644 --- a/Sources/PulseBackend.c +++ b/Sources/PulseBackend.c @@ -111,6 +111,7 @@ PULSE_API const char* PulseVerbaliseErrorType(PulseErrorType error) case PULSE_ERROR_BACKENDS_CANDIDATES_SHADER_FORMAT_MISMATCH: return "no backend candidates support the required shader formats"; case PULSE_ERROR_INITIALIZATION_FAILED: return "initialization of an object could not be completed for implementation-specific reasons"; case PULSE_ERROR_ALLOCATION_FAILED: return "an internal allocation failed"; + case PULSE_ERROR_DEVICE_LOST: return "device has been lost"; default: return "invalid error type"; }; diff --git a/Sources/PulseInternal.h b/Sources/PulseInternal.h index f8dc8e7..8ce3c4d 100644 --- a/Sources/PulseInternal.h +++ b/Sources/PulseInternal.h @@ -45,6 +45,10 @@ typedef void (*PulseDestroyDevicePFN)(PulseDevice); typedef PulseComputePipeline (*PulseCreateComputePipelinePFN)(PulseDevice, const PulseComputePipelineCreateInfo*); typedef void (*PulseBindComputePipelinePFN)(PulseComputePass, PulseComputePipeline); typedef void (*PulseDestroyComputePipelinePFN)(PulseDevice, PulseComputePipeline); +typedef PulseFence (*PulseCreateFencePFN)(PulseDevice device); +typedef void (*PulseDestroyFencePFN)(PulseDevice device, PulseFence fence); +typedef bool (*PulseIsFenceReadyPFN)(PulseDevice device, PulseFence fence); +typedef bool (*PulseWaitForFencesPFN)(PulseDevice device, PulseFence* const* fences, uint32_t fences_count, bool wait_for_all); typedef struct PulseBackendHandler { @@ -66,20 +70,33 @@ typedef struct PulseDeviceHandler PulseCreateComputePipelinePFN PFN_CreateComputePipeline; PulseBindComputePipelinePFN PFN_BindComputePipeline; PulseDestroyComputePipelinePFN PFN_DestroyComputePipeline; + PulseCreateFencePFN PFN_CreateFence; + PulseDestroyFencePFN PFN_DestroyFence; + PulseIsFenceReadyPFN PFN_IsFenceReady; + PulseWaitForFencesPFN PFN_WaitForFences; // Attributes void* driver_data; PulseBackend backend; } PulseDeviceHandler; +typedef struct PulseFenceHandler +{ + void* driver_data; +} PulseFenceHandler; + void PulseSetInternalError(PulseErrorType error); #define PULSE_LOAD_DRIVER_DEVICE_FUNCTION(fn, _namespace) pulse_device->PFN_##fn = _namespace##fn; #define PULSE_LOAD_DRIVER_DEVICE(_namespace) \ PULSE_LOAD_DRIVER_DEVICE_FUNCTION(DestroyDevice, _namespace) \ PULSE_LOAD_DRIVER_DEVICE_FUNCTION(CreateComputePipeline, _namespace) \ - PULSE_LOAD_DRIVER_DEVICE_FUNCTION(BindComputePipeline, _namespace) \ PULSE_LOAD_DRIVER_DEVICE_FUNCTION(DestroyComputePipeline, _namespace) \ + PULSE_LOAD_DRIVER_DEVICE_FUNCTION(BindComputePipeline, _namespace) \ + PULSE_LOAD_DRIVER_DEVICE_FUNCTION(CreateFence, _namespace) \ + PULSE_LOAD_DRIVER_DEVICE_FUNCTION(DestroyFence, _namespace) \ + PULSE_LOAD_DRIVER_DEVICE_FUNCTION(IsFenceReady, _namespace) \ + PULSE_LOAD_DRIVER_DEVICE_FUNCTION(WaitForFences, _namespace) \ #ifdef PULSE_ENABLE_VULKAN_BACKEND extern PulseBackendHandler VulkanDriver;