mirror of
https://github.com/Kbz-8/Pulse.git
synced 2026-01-11 15:33:34 +00:00
adding command list Vulkan support
This commit is contained in:
@@ -3,29 +3,47 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#define CHECK_PULSE_HANDLE_RETVAL(handle, retval) \
|
||||||
|
if(handle == PULSE_NULL_HANDLE) \
|
||||||
|
{ \
|
||||||
|
fprintf(stderr, "Error: %s", PulseVerbaliseErrorType(PulseGetLastErrorType())); \
|
||||||
|
return retval; \
|
||||||
|
} \
|
||||||
|
|
||||||
void DebugCallBack(PulseDebugMessageSeverity severity, const char* message)
|
void DebugCallBack(PulseDebugMessageSeverity severity, const char* message)
|
||||||
{
|
{
|
||||||
if(severity == PULSE_DEBUG_MESSAGE_SEVERITY_ERROR)
|
if(severity == PULSE_DEBUG_MESSAGE_SEVERITY_ERROR)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Pulse Error: %s", message);
|
fprintf(stderr, "Pulse Error: %s\n", message);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
else if(severity == PULSE_DEBUG_MESSAGE_SEVERITY_WARNING)
|
else if(severity == PULSE_DEBUG_MESSAGE_SEVERITY_WARNING)
|
||||||
fprintf(stderr, "Pulse Warning: %s", message);
|
fprintf(stderr, "Pulse Warning: %s\n", message);
|
||||||
else
|
else
|
||||||
printf("Pulse: %s", message);
|
printf("Pulse: %s\n", message);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
PulseBackend backend = PulseLoadBackend(PULSE_BACKEND_VULKAN, PULSE_SHADER_FORMAT_SPIRV_BIT, PULSE_NO_DEBUG);
|
PulseBackend backend = PulseLoadBackend(PULSE_BACKEND_VULKAN, PULSE_SHADER_FORMAT_SPIRV_BIT, PULSE_HIGH_DEBUG);
|
||||||
if(backend == PULSE_NULL_HANDLE)
|
CHECK_PULSE_HANDLE_RETVAL(backend, 1);
|
||||||
{
|
|
||||||
fprintf(stderr, "Pulse: could not create backend");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
PulseSetDebugCallback(backend, DebugCallBack);
|
PulseSetDebugCallback(backend, DebugCallBack);
|
||||||
PulseDevice device = PulseCreateDevice(backend, NULL, 0);
|
PulseDevice device = PulseCreateDevice(backend, NULL, 0);
|
||||||
|
CHECK_PULSE_HANDLE_RETVAL(device, 1);
|
||||||
|
|
||||||
|
PulseFence fence = PulseCreateFence(device);
|
||||||
|
CHECK_PULSE_HANDLE_RETVAL(fence, 1);
|
||||||
|
PulseCommandList cmd = PulseRequestCommandList(device, PULSE_COMMAND_LIST_GENERAL);
|
||||||
|
CHECK_PULSE_HANDLE_RETVAL(cmd, 1);
|
||||||
|
|
||||||
|
|
||||||
|
if(!PulseSubmitCommandList(device, cmd, fence))
|
||||||
|
fprintf(stderr, "Could not submit command list, %s\n", PulseVerbaliseErrorType(PulseGetLastErrorType()));
|
||||||
|
if(!PulseWaitForFences(device, &fence, 1, true))
|
||||||
|
fprintf(stderr, "Could not wait for fences, %s\n", PulseVerbaliseErrorType(PulseGetLastErrorType()));
|
||||||
|
|
||||||
|
PulseReleaseCommandList(device, cmd);
|
||||||
|
PulseDestroyFence(device, fence);
|
||||||
|
|
||||||
PulseDestroyDevice(device);
|
PulseDestroyDevice(device);
|
||||||
PulseUnloadBackend(backend);
|
PulseUnloadBackend(backend);
|
||||||
|
|||||||
@@ -25,11 +25,9 @@ typedef uint32_t PulseFlags;
|
|||||||
PULSE_DEFINE_NULLABLE_HANDLE(PulseBackend);
|
PULSE_DEFINE_NULLABLE_HANDLE(PulseBackend);
|
||||||
PULSE_DEFINE_NULLABLE_HANDLE(PulseBuffer);
|
PULSE_DEFINE_NULLABLE_HANDLE(PulseBuffer);
|
||||||
PULSE_DEFINE_NULLABLE_HANDLE(PulseCommandList);
|
PULSE_DEFINE_NULLABLE_HANDLE(PulseCommandList);
|
||||||
PULSE_DEFINE_NULLABLE_HANDLE(PulseComputePass);
|
|
||||||
PULSE_DEFINE_NULLABLE_HANDLE(PulseComputePipeline);
|
PULSE_DEFINE_NULLABLE_HANDLE(PulseComputePipeline);
|
||||||
PULSE_DEFINE_NULLABLE_HANDLE(PulseDevice);
|
PULSE_DEFINE_NULLABLE_HANDLE(PulseDevice);
|
||||||
PULSE_DEFINE_NULLABLE_HANDLE(PulseFence);
|
PULSE_DEFINE_NULLABLE_HANDLE(PulseFence);
|
||||||
PULSE_DEFINE_NULLABLE_HANDLE(PulseGeneralPass);
|
|
||||||
PULSE_DEFINE_NULLABLE_HANDLE(PulseImage);
|
PULSE_DEFINE_NULLABLE_HANDLE(PulseImage);
|
||||||
|
|
||||||
// Flags
|
// Flags
|
||||||
@@ -75,12 +73,18 @@ typedef enum PulseShaderFormatsBits
|
|||||||
typedef PulseFlags PulseShaderFormatsFlags;
|
typedef PulseFlags PulseShaderFormatsFlags;
|
||||||
|
|
||||||
// Enums
|
// Enums
|
||||||
|
typedef enum PulseCommandListUsage
|
||||||
|
{
|
||||||
|
PULSE_COMMAND_LIST_GENERAL,
|
||||||
|
PULSE_COMMAND_LIST_TRANSFER_ONLY
|
||||||
|
} PulseCommandListUsage;
|
||||||
|
|
||||||
typedef enum PulseDebugLevel
|
typedef enum PulseDebugLevel
|
||||||
{
|
{
|
||||||
PULSE_NO_DEBUG,
|
PULSE_NO_DEBUG = 0,
|
||||||
PULSE_LOW_DEBUG,
|
PULSE_LOW_DEBUG = 1,
|
||||||
PULSE_HIGH_DEBUG,
|
PULSE_HIGH_DEBUG = 2,
|
||||||
PULSE_PARANOID_DEBUG // Causes every warning to be treated as error
|
PULSE_PARANOID_DEBUG = 3 // Causes every warning to be treated as error
|
||||||
} PulseDebugLevel;
|
} PulseDebugLevel;
|
||||||
|
|
||||||
typedef enum PulseDebugMessageSeverity
|
typedef enum PulseDebugMessageSeverity
|
||||||
@@ -90,6 +94,18 @@ typedef enum PulseDebugMessageSeverity
|
|||||||
PULSE_DEBUG_MESSAGE_SEVERITY_ERROR
|
PULSE_DEBUG_MESSAGE_SEVERITY_ERROR
|
||||||
} PulseDebugMessageSeverity;
|
} PulseDebugMessageSeverity;
|
||||||
|
|
||||||
|
typedef enum PulseErrorType
|
||||||
|
{
|
||||||
|
PULSE_ERROR_NONE,
|
||||||
|
PULSE_ERROR_BACKENDS_CANDIDATES_SHADER_FORMAT_MISMATCH,
|
||||||
|
PULSE_ERROR_INITIALIZATION_FAILED,
|
||||||
|
PULSE_ERROR_INVALID_HANDLE,
|
||||||
|
PULSE_ERROR_CPU_ALLOCATION_FAILED,
|
||||||
|
PULSE_ERROR_DEVICE_ALLOCATION_FAILED,
|
||||||
|
PULSE_ERROR_DEVICE_LOST,
|
||||||
|
PULSE_ERROR_INVALID_INTERNAL_POINTER,
|
||||||
|
} PulseErrorType;
|
||||||
|
|
||||||
typedef enum PulseImageType
|
typedef enum PulseImageType
|
||||||
{
|
{
|
||||||
PULSE_IMAGE_TYPE_2D,
|
PULSE_IMAGE_TYPE_2D,
|
||||||
@@ -249,26 +265,22 @@ typedef struct PulseImageRegion
|
|||||||
// Functions
|
// Functions
|
||||||
typedef void (*PulseDebugCallbackPFN)(PulseDebugMessageSeverity, const char*);
|
typedef void (*PulseDebugCallbackPFN)(PulseDebugMessageSeverity, const char*);
|
||||||
|
|
||||||
|
PULSE_API bool PulseSupportsBackend(PulseBackendFlags backend_candidates, PulseShaderFormatsFlags shader_formats_used);
|
||||||
|
|
||||||
PULSE_API PulseBackend PulseLoadBackend(PulseBackendFlags backend_candidates, PulseShaderFormatsFlags shader_formats_used, PulseDebugLevel debug_level);
|
PULSE_API PulseBackend PulseLoadBackend(PulseBackendFlags backend_candidates, PulseShaderFormatsFlags shader_formats_used, PulseDebugLevel debug_level);
|
||||||
PULSE_API void PulseUnloadBackend(PulseBackend backend);
|
PULSE_API void PulseUnloadBackend(PulseBackend backend);
|
||||||
|
PULSE_API PulseBackendFlags PulseGetBackendType(PulseBackend backend);
|
||||||
PULSE_API void PulseSetDebugCallback(PulseBackend backend, PulseDebugCallbackPFN callback);
|
PULSE_API void PulseSetDebugCallback(PulseBackend backend, PulseDebugCallbackPFN callback);
|
||||||
|
|
||||||
PULSE_API PulseDevice PulseCreateDevice(PulseBackend backend, PulseDevice* forbiden_devices, uint32_t forbiden_devices_count);
|
PULSE_API PulseDevice PulseCreateDevice(PulseBackend backend, PulseDevice* forbiden_devices, uint32_t forbiden_devices_count);
|
||||||
PULSE_API void PulseDestroyDevice(PulseDevice device);
|
PULSE_API void PulseDestroyDevice(PulseDevice device);
|
||||||
PULSE_API PulseBackendBits PulseGetBackendInUseByDevice(PulseDevice device);
|
PULSE_API PulseBackendBits PulseGetBackendInUseByDevice(PulseDevice device);
|
||||||
PULSE_API bool PulseSupportsBackend(PulseBackendFlags backend_candidates, PulseShaderFormatsFlags shader_formats_used);
|
|
||||||
PULSE_API bool PulseDeviceSupportsShaderFormats(PulseDevice device, PulseShaderFormatsFlags shader_formats_used);
|
PULSE_API bool PulseDeviceSupportsShaderFormats(PulseDevice device, PulseShaderFormatsFlags shader_formats_used);
|
||||||
|
|
||||||
PULSE_API PulseCommandList PulseRequestCommandList(PulseDevice device);
|
PULSE_API PulseCommandList PulseRequestCommandList(PulseDevice device, PulseCommandListUsage usage);
|
||||||
PULSE_API bool PulseSubmitCommandList(PulseDevice device, PulseCommandList cmd, PulseFence fence);
|
PULSE_API bool PulseSubmitCommandList(PulseDevice device, PulseCommandList cmd, PulseFence fence);
|
||||||
PULSE_API void PulseReleaseCommandList(PulseDevice device, PulseCommandList cmd);
|
PULSE_API void PulseReleaseCommandList(PulseDevice device, PulseCommandList cmd);
|
||||||
|
|
||||||
PULSE_API PulseComputePass PulseBeginComputePass(PulseCommandList cmd);
|
|
||||||
PULSE_API void PulseEndComputePass(PulseComputePass pass);
|
|
||||||
|
|
||||||
PULSE_API PulseGeneralPass PulseBeginGeneralPass(PulseCommandList cmd);
|
|
||||||
PULSE_API void PulseEndGeneralPass(PulseGeneralPass pass);
|
|
||||||
|
|
||||||
PULSE_API PulseFence PulseCreateFence(PulseDevice device);
|
PULSE_API PulseFence PulseCreateFence(PulseDevice device);
|
||||||
PULSE_API void PulseDestroyFence(PulseDevice device, PulseFence fence);
|
PULSE_API void PulseDestroyFence(PulseDevice device, PulseFence fence);
|
||||||
PULSE_API bool PulseIsFenceReady(PulseDevice device, PulseFence fence);
|
PULSE_API bool PulseIsFenceReady(PulseDevice device, PulseFence fence);
|
||||||
@@ -276,7 +288,10 @@ PULSE_API bool PulseWaitForFences(PulseDevice device, const PulseFence* fences,
|
|||||||
|
|
||||||
PULSE_API PulseComputePipeline PulseCreateComputePipeline(PulseDevice device, const PulseComputePipelineCreateInfo* info);
|
PULSE_API PulseComputePipeline PulseCreateComputePipeline(PulseDevice device, const PulseComputePipelineCreateInfo* info);
|
||||||
PULSE_API void PulseDestroyComputePipeline(PulseDevice device, PulseComputePipeline pipeline);
|
PULSE_API void PulseDestroyComputePipeline(PulseDevice device, PulseComputePipeline pipeline);
|
||||||
PULSE_API void PulseBindComputePipeline(PulseComputePass pass, PulseComputePipeline pipeline);
|
PULSE_API void PulseBindComputePipeline(PulseComputePipeline pipeline);
|
||||||
|
|
||||||
|
PULSE_API PulseErrorType PulseGetLastErrorType(); // /!\ Warning /!\ Call to this function resets the internal last error variable
|
||||||
|
PULSE_API const char* PulseVerbaliseErrorType(PulseErrorType error);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,6 +55,39 @@ void VulkanUnloadBackend(PulseBackend backend)
|
|||||||
VulkanLoaderShutdown();
|
VulkanLoaderShutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* VulkanVerbaliseResult(VkResult res)
|
||||||
|
{
|
||||||
|
switch(res)
|
||||||
|
{
|
||||||
|
case VK_SUCCESS: return "Success";
|
||||||
|
case VK_NOT_READY: return "A fence or query has not yet completed";
|
||||||
|
case VK_TIMEOUT: return "A wait operation has not completed in the specified time";
|
||||||
|
case VK_EVENT_SET: return "An event is signaled";
|
||||||
|
case VK_EVENT_RESET: return "An event is unsignaled";
|
||||||
|
case VK_INCOMPLETE: return "A return array was too small for the result";
|
||||||
|
case VK_ERROR_OUT_OF_HOST_MEMORY: return "A host memory allocation has failed";
|
||||||
|
case VK_ERROR_OUT_OF_DEVICE_MEMORY: return "A device memory allocation has failed";
|
||||||
|
case VK_ERROR_INITIALIZATION_FAILED: return "Initialization of an object could not be completed for implementation-specific reasons";
|
||||||
|
case VK_ERROR_DEVICE_LOST: return "The logical or physical device has been lost";
|
||||||
|
case VK_ERROR_MEMORY_MAP_FAILED: return "Mapping of a memory object has failed";
|
||||||
|
case VK_ERROR_LAYER_NOT_PRESENT: return "A requested layer is not present or could not be loaded";
|
||||||
|
case VK_ERROR_EXTENSION_NOT_PRESENT: return "A requested extension is not supported";
|
||||||
|
case VK_ERROR_FEATURE_NOT_PRESENT: return "A requested feature is not supported";
|
||||||
|
case VK_ERROR_INCOMPATIBLE_DRIVER: return "The requested version of Vulkan is not supported by the driver or is otherwise incompatible";
|
||||||
|
case VK_ERROR_TOO_MANY_OBJECTS: return "Too many objects of the type have already been created";
|
||||||
|
case VK_ERROR_FORMAT_NOT_SUPPORTED: return "A requested format is not supported on this device";
|
||||||
|
case VK_ERROR_SURFACE_LOST_KHR: return "A surface is no longer available";
|
||||||
|
case VK_SUBOPTIMAL_KHR: return "A swapchain no longer matches the surface properties exactly, but can still be used";
|
||||||
|
case VK_ERROR_OUT_OF_DATE_KHR: return "A surface has changed in such a way that it is no longer compatible with the swapchain";
|
||||||
|
case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR: return "The display used by a swapchain does not use the same presentable image layout";
|
||||||
|
case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: return "The requested window is already connected to a VkSurfaceKHR, or to some other non-Vulkan API";
|
||||||
|
case VK_ERROR_VALIDATION_FAILED_EXT: return "A validation layer found an error";
|
||||||
|
|
||||||
|
default: return "Unknown Vulkan error";
|
||||||
|
}
|
||||||
|
return "Unknown Vulkan error"; // Just to avoid warnings
|
||||||
|
}
|
||||||
|
|
||||||
PulseBackendHandler VulkanDriver = {
|
PulseBackendHandler VulkanDriver = {
|
||||||
.PFN_LoadBackend = VulkanLoadBackend,
|
.PFN_LoadBackend = VulkanLoadBackend,
|
||||||
.PFN_UnloadBackend = VulkanUnloadBackend,
|
.PFN_UnloadBackend = VulkanUnloadBackend,
|
||||||
|
|||||||
@@ -16,14 +16,16 @@
|
|||||||
|
|
||||||
#define VULKAN_RETRIEVE_DRIVER_DATA_AS(handle, cast) ((cast)handle->driver_data)
|
#define VULKAN_RETRIEVE_DRIVER_DATA_AS(handle, cast) ((cast)handle->driver_data)
|
||||||
|
|
||||||
#define CHECK_VK_RETVAL(res, error, retval) \
|
#define CHECK_VK_RETVAL(backend, res, error, retval) \
|
||||||
if((res) != VK_SUCCESS) \
|
if((res) != VK_SUCCESS) \
|
||||||
{ \
|
{ \
|
||||||
|
if(backend != PULSE_NULL_HANDLE && PULSE_IS_BACKEND_LOW_LEVEL_DEBUG(backend)) \
|
||||||
|
PulseLogErrorFmt(backend, "(Vulkan) Call to Vulkan function failed due to %s", VulkanVerbaliseResult(res)); \
|
||||||
PulseSetInternalError(error); \
|
PulseSetInternalError(error); \
|
||||||
return retval; \
|
return retval; \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define CHECK_VK(res, error) CHECK_VK_RETVAL(res, error, )
|
#define CHECK_VK(backend, res, error) CHECK_VK_RETVAL(backend, res, error, )
|
||||||
|
|
||||||
typedef struct VulkanGlobal
|
typedef struct VulkanGlobal
|
||||||
{
|
{
|
||||||
@@ -39,6 +41,8 @@ typedef struct VulkanDriverData
|
|||||||
|
|
||||||
VulkanGlobal* VulkanGetGlobal();
|
VulkanGlobal* VulkanGetGlobal();
|
||||||
|
|
||||||
|
const char* VulkanVerbaliseResult(VkResult res);
|
||||||
|
|
||||||
PulseBackendFlags VulkanCheckSupport(PulseBackendFlags candidates, PulseShaderFormatsFlags shader_formats_used); // Return PULSE_BACKEND_VULKAN in case of success and PULSE_BACKEND_INVALID otherwise
|
PulseBackendFlags VulkanCheckSupport(PulseBackendFlags candidates, PulseShaderFormatsFlags shader_formats_used); // Return PULSE_BACKEND_VULKAN in case of success and PULSE_BACKEND_INVALID otherwise
|
||||||
|
|
||||||
#endif // PULSE_VULKAN_H_
|
#endif // PULSE_VULKAN_H_
|
||||||
|
|||||||
171
Sources/Backends/Vulkan/VulkanCommandList.c
git.filemode.normal_file
171
Sources/Backends/Vulkan/VulkanCommandList.c
git.filemode.normal_file
@@ -0,0 +1,171 @@
|
|||||||
|
// 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 "VulkanCommandList.h"
|
||||||
|
#include "VulkanCommandPool.h"
|
||||||
|
#include "VulkanDevice.h"
|
||||||
|
#include "VulkanQueue.h"
|
||||||
|
|
||||||
|
static void VulkanInitCommandList(VulkanCommandPool* pool, PulseCommandList cmd)
|
||||||
|
{
|
||||||
|
PULSE_CHECK_PTR(pool);
|
||||||
|
PULSE_CHECK_PTR(cmd);
|
||||||
|
|
||||||
|
VulkanDevice* vulkan_device = VULKAN_RETRIEVE_DRIVER_DATA_AS(pool->device, VulkanDevice*);
|
||||||
|
VulkanCommandList* vulkan_cmd = VULKAN_RETRIEVE_DRIVER_DATA_AS(cmd, VulkanCommandList*);
|
||||||
|
|
||||||
|
vulkan_cmd->pool = pool;
|
||||||
|
|
||||||
|
VkCommandBufferAllocateInfo info = {};
|
||||||
|
info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||||
|
info.commandPool = pool->pool;
|
||||||
|
info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
pool->available_command_lists[pool->available_command_lists_size] = cmd;
|
||||||
|
pool->available_command_lists_size++;
|
||||||
|
}
|
||||||
|
|
||||||
|
PulseCommandList VulkanRequestCommandList(PulseDevice device, PulseCommandListUsage usage)
|
||||||
|
{
|
||||||
|
PULSE_CHECK_HANDLE_RETVAL(device, PULSE_NULL_HANDLE);
|
||||||
|
|
||||||
|
VulkanCommandPool* pool;
|
||||||
|
switch(usage)
|
||||||
|
{
|
||||||
|
case PULSE_COMMAND_LIST_TRANSFER_ONLY: pool = VulkanRequestCmdPoolFromDevice(device, VULKAN_QUEUE_TRANSFER); break;
|
||||||
|
case PULSE_COMMAND_LIST_GENERAL: // fallthrough
|
||||||
|
default: pool = VulkanRequestCmdPoolFromDevice(device, VULKAN_QUEUE_COMPUTE); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
PULSE_CHECK_PTR_RETVAL(pool, PULSE_NULL_HANDLE);
|
||||||
|
|
||||||
|
PulseCommandList cmd = PULSE_NULL_HANDLE;
|
||||||
|
|
||||||
|
for(uint32_t i = 0; i < pool->available_command_lists_size; i++)
|
||||||
|
{
|
||||||
|
if(pool->available_command_lists[i]->is_available)
|
||||||
|
{
|
||||||
|
cmd = pool->available_command_lists[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(cmd == PULSE_NULL_HANDLE)
|
||||||
|
{
|
||||||
|
cmd = (PulseCommandList)calloc(1, sizeof(PulseCommandListHandler));
|
||||||
|
PULSE_CHECK_ALLOCATION_RETVAL(cmd, PULSE_NULL_HANDLE);
|
||||||
|
|
||||||
|
VulkanCommandList* vulkan_cmd = (VulkanCommandList*)calloc(1, sizeof(VulkanCommandList));
|
||||||
|
PULSE_CHECK_ALLOCATION_RETVAL(vulkan_cmd, PULSE_NULL_HANDLE);
|
||||||
|
|
||||||
|
cmd->usage = usage;
|
||||||
|
cmd->device = device;
|
||||||
|
cmd->driver_data = vulkan_cmd;
|
||||||
|
cmd->thread_id = pool->thread_id;
|
||||||
|
|
||||||
|
VulkanInitCommandList(pool, cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd->compute_pipelines_bound_size = 0;
|
||||||
|
cmd->state = PULSE_COMMAND_LIST_STATE_EMPTY;
|
||||||
|
cmd->is_available = false;
|
||||||
|
cmd->is_compute_pipeline_bound = false;
|
||||||
|
|
||||||
|
VulkanDevice* vulkan_device = VULKAN_RETRIEVE_DRIVER_DATA_AS(device, VulkanDevice*);
|
||||||
|
VulkanCommandList* vulkan_cmd = VULKAN_RETRIEVE_DRIVER_DATA_AS(cmd, VulkanCommandList*);
|
||||||
|
|
||||||
|
CHECK_VK_RETVAL(device->backend, vulkan_device->vkResetCommandBuffer(vulkan_cmd->cmd, 0), PULSE_ERROR_DEVICE_ALLOCATION_FAILED, PULSE_NULL_HANDLE);
|
||||||
|
|
||||||
|
VkCommandBufferBeginInfo begin_info = {};
|
||||||
|
begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||||
|
begin_info.flags = 0;
|
||||||
|
VkResult res = vulkan_device->vkBeginCommandBuffer(vulkan_cmd->cmd, &begin_info);
|
||||||
|
switch(res)
|
||||||
|
{
|
||||||
|
case VK_SUCCESS: break;
|
||||||
|
case VK_ERROR_OUT_OF_HOST_MEMORY: PulseSetInternalError(PULSE_ERROR_CPU_ALLOCATION_FAILED); return PULSE_NULL_HANDLE;
|
||||||
|
case VK_ERROR_OUT_OF_DEVICE_MEMORY: PulseSetInternalError(PULSE_ERROR_DEVICE_ALLOCATION_FAILED); return PULSE_NULL_HANDLE;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
return cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VulkanSubmitCommandList(PulseDevice device, PulseCommandList cmd, PulseFence fence)
|
||||||
|
{
|
||||||
|
PULSE_UNUSED(device);
|
||||||
|
PULSE_CHECK_HANDLE_RETVAL(cmd, false);
|
||||||
|
|
||||||
|
VulkanDevice* vulkan_device = VULKAN_RETRIEVE_DRIVER_DATA_AS(device, VulkanDevice*);
|
||||||
|
VulkanCommandList* vulkan_cmd = VULKAN_RETRIEVE_DRIVER_DATA_AS(cmd, VulkanCommandList*);
|
||||||
|
|
||||||
|
VkResult res = vulkan_device->vkEndCommandBuffer(vulkan_cmd->cmd);
|
||||||
|
switch(res)
|
||||||
|
{
|
||||||
|
case VK_SUCCESS: break;
|
||||||
|
case VK_ERROR_OUT_OF_HOST_MEMORY: PulseSetInternalError(PULSE_ERROR_CPU_ALLOCATION_FAILED); return false;
|
||||||
|
case VK_ERROR_OUT_OF_DEVICE_MEMORY: PulseSetInternalError(PULSE_ERROR_DEVICE_ALLOCATION_FAILED); return false;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkFence vulkan_fence;
|
||||||
|
if(fence != PULSE_NULL_HANDLE)
|
||||||
|
{
|
||||||
|
vulkan_fence = VULKAN_RETRIEVE_DRIVER_DATA_AS(device, VkFence);
|
||||||
|
vulkan_device->vkResetFences(vulkan_device->device, 1, &vulkan_fence);
|
||||||
|
}
|
||||||
|
|
||||||
|
VulkanQueue* vulkan_queue;
|
||||||
|
switch(cmd->usage)
|
||||||
|
{
|
||||||
|
case PULSE_COMMAND_LIST_TRANSFER_ONLY: vulkan_queue = vulkan_device->queues[VULKAN_QUEUE_TRANSFER]; break;
|
||||||
|
case PULSE_COMMAND_LIST_GENERAL: // fallthrough
|
||||||
|
default: vulkan_queue = vulkan_device->queues[VULKAN_QUEUE_COMPUTE]; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
PULSE_CHECK_PTR_RETVAL(vulkan_queue, false);
|
||||||
|
|
||||||
|
VkSubmitInfo submit_info = {};
|
||||||
|
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||||
|
submit_info.commandBufferCount = 1;
|
||||||
|
submit_info.pCommandBuffers = &vulkan_cmd->cmd;
|
||||||
|
res = vulkan_device->vkQueueSubmit(vulkan_queue->queue, 1, &submit_info, vulkan_fence);
|
||||||
|
switch(res)
|
||||||
|
{
|
||||||
|
case VK_SUCCESS: return true;
|
||||||
|
|
||||||
|
case VK_ERROR_OUT_OF_HOST_MEMORY: PulseSetInternalError(PULSE_ERROR_CPU_ALLOCATION_FAILED); return false;
|
||||||
|
case VK_ERROR_OUT_OF_DEVICE_MEMORY: PulseSetInternalError(PULSE_ERROR_DEVICE_ALLOCATION_FAILED); return false;
|
||||||
|
case VK_ERROR_DEVICE_LOST: PulseSetInternalError(PULSE_ERROR_DEVICE_LOST); return false;
|
||||||
|
|
||||||
|
default: return false;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VulkanReleaseCommandList(PulseDevice device, PulseCommandList cmd)
|
||||||
|
{
|
||||||
|
PULSE_CHECK_HANDLE(device);
|
||||||
|
|
||||||
|
VulkanCommandList* vulkan_cmd = VULKAN_RETRIEVE_DRIVER_DATA_AS(cmd, VulkanCommandList*);
|
||||||
|
|
||||||
|
for(uint32_t i = 0; i < vulkan_cmd->pool->available_command_lists_size; i++)
|
||||||
|
{
|
||||||
|
if(vulkan_cmd->pool->available_command_lists[i] == cmd)
|
||||||
|
{
|
||||||
|
cmd->is_available = true;
|
||||||
|
cmd->state = PULSE_COMMAND_LIST_STATE_INVALID;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,22 +10,17 @@
|
|||||||
#include <vulkan/vulkan_core.h>
|
#include <vulkan/vulkan_core.h>
|
||||||
|
|
||||||
#include <Pulse.h>
|
#include <Pulse.h>
|
||||||
#include "../../PulseInternal.h"
|
|
||||||
#include "VulkanCommandPool.h"
|
#include "VulkanCommandPool.h"
|
||||||
|
|
||||||
typedef struct VulkanCommandList
|
typedef struct VulkanCommandList
|
||||||
{
|
{
|
||||||
PulseDevice device;
|
|
||||||
VulkanCommandPool* pool;
|
VulkanCommandPool* pool;
|
||||||
PulseThreadID thread_id;
|
|
||||||
VkCommandBuffer cmd;
|
VkCommandBuffer cmd;
|
||||||
|
|
||||||
PulseComputePipeline* compute_pipelines_bound;
|
|
||||||
uint32_t compute_pipelines_bound_capacity;
|
|
||||||
uint32_t compute_pipelines_bound_size;
|
|
||||||
} VulkanCommandList;
|
} VulkanCommandList;
|
||||||
|
|
||||||
void VulkanInitCommandList(VulkanCommandPool* pool);
|
PulseCommandList VulkanRequestCommandList(PulseDevice device, PulseCommandListUsage usage);
|
||||||
|
bool VulkanSubmitCommandList(PulseDevice device, PulseCommandList cmd, PulseFence fence);
|
||||||
|
void VulkanReleaseCommandList(PulseDevice device, PulseCommandList cmd);
|
||||||
|
|
||||||
#endif // PULSE_VULKAN_COMMAND_LIST_H_
|
#endif // PULSE_VULKAN_COMMAND_LIST_H_
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ bool VulkanInitCommandPool(PulseDevice device, VulkanCommandPool* pool, VulkanQu
|
|||||||
create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
|
create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
|
||||||
create_info.queueFamilyIndex = vulkan_device->queues[queue_type]->queue_family_index;
|
create_info.queueFamilyIndex = vulkan_device->queues[queue_type]->queue_family_index;
|
||||||
create_info.pNext = PULSE_NULLPTR;
|
create_info.pNext = PULSE_NULLPTR;
|
||||||
CHECK_VK_RETVAL(vulkan_device->vkCreateCommandPool(vulkan_device->device, &create_info, PULSE_NULLPTR, &pool->pool), PULSE_ERROR_INITIALIZATION_FAILED, false);
|
CHECK_VK_RETVAL(device->backend, vulkan_device->vkCreateCommandPool(vulkan_device->device, &create_info, PULSE_NULLPTR, &pool->pool), PULSE_ERROR_INITIALIZATION_FAILED, false);
|
||||||
|
|
||||||
pool->thread_id = PulseGetThreadID();
|
pool->thread_id = PulseGetThreadID();
|
||||||
|
|
||||||
|
|||||||
17
Sources/Backends/Vulkan/VulkanComputePipeline.c
git.filemode.normal_file
17
Sources/Backends/Vulkan/VulkanComputePipeline.c
git.filemode.normal_file
@@ -0,0 +1,17 @@
|
|||||||
|
// Copyright (C) 2024 kanel
|
||||||
|
// This file is part of "Pulse"
|
||||||
|
// For conditions of distribution and use, see copyright notice in LICENSE
|
||||||
|
|
||||||
|
#include "VulkanComputePipeline.h"
|
||||||
|
|
||||||
|
PulseComputePipeline VulkanCreateComputePipeline(PulseDevice device, const PulseComputePipelineCreateInfo* info)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void VulkanBindComputePipeline(PulseComputePass pass, PulseComputePipeline pipeline)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void VulkanDestroyComputePipeline(PulseDevice device, PulseComputePipeline pipeline)
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -16,7 +16,7 @@ typedef struct VulkanComputePipeline
|
|||||||
} VulkanComputePipeline;
|
} VulkanComputePipeline;
|
||||||
|
|
||||||
PulseComputePipeline VulkanCreateComputePipeline(PulseDevice device, const PulseComputePipelineCreateInfo* info);
|
PulseComputePipeline VulkanCreateComputePipeline(PulseDevice device, const PulseComputePipelineCreateInfo* info);
|
||||||
void VulkanBindComputePipeline(PulseComputePass pass, PulseComputePipeline pipeline);
|
void VulkanBindComputePipeline(PulseComputePipeline pipeline);
|
||||||
void VulkanDestroyComputePipeline(PulseDevice device, PulseComputePipeline pipeline);
|
void VulkanDestroyComputePipeline(PulseDevice device, PulseComputePipeline pipeline);
|
||||||
|
|
||||||
#endif // PULSE_VULKAN_COMPUTE_PIPELINE_H_
|
#endif // PULSE_VULKAN_COMPUTE_PIPELINE_H_
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include "Pulse.h"
|
#include "Pulse.h"
|
||||||
#include "Vulkan.h"
|
#include "Vulkan.h"
|
||||||
#include "VulkanComputePipeline.h"
|
#include "VulkanComputePipeline.h"
|
||||||
|
#include "VulkanCommandList.h"
|
||||||
#include "VulkanDevice.h"
|
#include "VulkanDevice.h"
|
||||||
#include "VulkanFence.h"
|
#include "VulkanFence.h"
|
||||||
#include "VulkanInstance.h"
|
#include "VulkanInstance.h"
|
||||||
@@ -175,9 +176,11 @@ PulseDevice VulkanCreateDevice(PulseBackend backend, PulseDevice* forbiden_devic
|
|||||||
create_info.flags = 0;
|
create_info.flags = 0;
|
||||||
create_info.pNext = PULSE_NULLPTR;
|
create_info.pNext = PULSE_NULLPTR;
|
||||||
|
|
||||||
CHECK_VK_RETVAL(instance->vkCreateDevice(device->physical, &create_info, PULSE_NULLPTR, &device->device), PULSE_ERROR_INITIALIZATION_FAILED, PULSE_NULLPTR);
|
CHECK_VK_RETVAL(backend, instance->vkCreateDevice(device->physical, &create_info, PULSE_NULLPTR, &device->device), PULSE_ERROR_INITIALIZATION_FAILED, PULSE_NULLPTR);
|
||||||
if(!VulkanLoadDevice(instance, device))
|
if(!VulkanLoadDevice(instance, device))
|
||||||
{
|
{
|
||||||
|
if(PULSE_IS_BACKEND_LOW_LEVEL_DEBUG(backend))
|
||||||
|
PulseLogInfoFmt(backend, "(Vulkan) Could not load device functions from %s", device->properties.deviceName);
|
||||||
PulseSetInternalError(PULSE_ERROR_INITIALIZATION_FAILED);
|
PulseSetInternalError(PULSE_ERROR_INITIALIZATION_FAILED);
|
||||||
return PULSE_NULLPTR;
|
return PULSE_NULLPTR;
|
||||||
}
|
}
|
||||||
@@ -217,11 +220,14 @@ PulseDevice VulkanCreateDevice(PulseBackend backend, PulseDevice* forbiden_devic
|
|||||||
allocator_create_info.instance = instance->instance;
|
allocator_create_info.instance = instance->instance;
|
||||||
allocator_create_info.pVulkanFunctions = &vma_vulkan_func;
|
allocator_create_info.pVulkanFunctions = &vma_vulkan_func;
|
||||||
|
|
||||||
CHECK_VK_RETVAL(vmaCreateAllocator(&allocator_create_info, &device->allocator), PULSE_ERROR_INITIALIZATION_FAILED, PULSE_NULLPTR);
|
CHECK_VK_RETVAL(backend, vmaCreateAllocator(&allocator_create_info, &device->allocator), PULSE_ERROR_INITIALIZATION_FAILED, PULSE_NULLPTR);
|
||||||
|
|
||||||
pulse_device->driver_data = device;
|
pulse_device->driver_data = device;
|
||||||
pulse_device->backend = backend;
|
pulse_device->backend = backend;
|
||||||
PULSE_LOAD_DRIVER_DEVICE(Vulkan);
|
PULSE_LOAD_DRIVER_DEVICE(Vulkan);
|
||||||
|
|
||||||
|
if(PULSE_IS_BACKEND_HIGH_LEVEL_DEBUG(backend))
|
||||||
|
PulseLogInfoFmt(backend, "(Vulkan) Created device from %s", device->properties.deviceName);
|
||||||
return pulse_device;
|
return pulse_device;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -230,8 +236,35 @@ void VulkanDestroyDevice(PulseDevice device)
|
|||||||
VulkanDevice* vulkan_device = VULKAN_RETRIEVE_DRIVER_DATA_AS(device, VulkanDevice*);
|
VulkanDevice* vulkan_device = VULKAN_RETRIEVE_DRIVER_DATA_AS(device, VulkanDevice*);
|
||||||
if(vulkan_device == PULSE_NULLPTR || vulkan_device->device == VK_NULL_HANDLE)
|
if(vulkan_device == PULSE_NULLPTR || vulkan_device->device == VK_NULL_HANDLE)
|
||||||
return;
|
return;
|
||||||
|
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);
|
vmaDestroyAllocator(vulkan_device->allocator);
|
||||||
vulkan_device->vkDestroyDevice(vulkan_device->device, PULSE_NULLPTR);
|
vulkan_device->vkDestroyDevice(vulkan_device->device, PULSE_NULLPTR);
|
||||||
|
if(PULSE_IS_BACKEND_HIGH_LEVEL_DEBUG(device->backend))
|
||||||
|
PulseLogInfoFmt(device->backend, "(Vulkan) Destroyed device created from %s", vulkan_device->properties.deviceName);
|
||||||
|
free(vulkan_device->cmd_pools);
|
||||||
free(vulkan_device);
|
free(vulkan_device);
|
||||||
free(device);
|
free(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VulkanCommandPool* VulkanRequestCmdPoolFromDevice(PulseDevice device, VulkanQueueType queue_type)
|
||||||
|
{
|
||||||
|
PULSE_CHECK_HANDLE_RETVAL(device, PULSE_NULLPTR);
|
||||||
|
VulkanDevice* vulkan_device = VULKAN_RETRIEVE_DRIVER_DATA_AS(device, VulkanDevice*);
|
||||||
|
if(vulkan_device == PULSE_NULLPTR || vulkan_device->device == VK_NULL_HANDLE)
|
||||||
|
return PULSE_NULLPTR;
|
||||||
|
|
||||||
|
PulseThreadID thread_id = PulseGetThreadID();
|
||||||
|
|
||||||
|
for(uint32_t i = 0; i < vulkan_device->cmd_pools_size; i++)
|
||||||
|
{
|
||||||
|
if(thread_id == vulkan_device->cmd_pools[i].thread_id && queue_type == vulkan_device->cmd_pools[i].queue_type)
|
||||||
|
return &vulkan_device->cmd_pools[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
vulkan_device->cmd_pools_size++;
|
||||||
|
vulkan_device->cmd_pools = (VulkanCommandPool*)realloc(vulkan_device->cmd_pools, vulkan_device->cmd_pools_size * sizeof(VulkanCommandPool));
|
||||||
|
if(!VulkanInitCommandPool(device, &vulkan_device->cmd_pools[vulkan_device->cmd_pools_size - 1], queue_type))
|
||||||
|
return PULSE_NULLPTR;
|
||||||
|
return &vulkan_device->cmd_pools[vulkan_device->cmd_pools_size - 1];
|
||||||
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ struct VulkanQueue;
|
|||||||
typedef struct VulkanDevice
|
typedef struct VulkanDevice
|
||||||
{
|
{
|
||||||
VulkanCommandPool* cmd_pools;
|
VulkanCommandPool* cmd_pools;
|
||||||
|
uint32_t cmd_pools_size;
|
||||||
|
|
||||||
struct VulkanQueue* queues[VULKAN_QUEUE_END_ENUM];
|
struct VulkanQueue* queues[VULKAN_QUEUE_END_ENUM];
|
||||||
|
|
||||||
@@ -43,6 +44,7 @@ typedef struct VulkanDevice
|
|||||||
|
|
||||||
PulseDevice VulkanCreateDevice(PulseBackend backend, PulseDevice* forbiden_devices, uint32_t forbiden_devices_count);
|
PulseDevice VulkanCreateDevice(PulseBackend backend, PulseDevice* forbiden_devices, uint32_t forbiden_devices_count);
|
||||||
void VulkanDestroyDevice(PulseDevice device);
|
void VulkanDestroyDevice(PulseDevice device);
|
||||||
|
VulkanCommandPool* VulkanRequestCmdPoolFromDevice(PulseDevice device, VulkanQueueType queue_type);
|
||||||
|
|
||||||
#endif // PULSE_VULKAN_DEVICE_H_
|
#endif // PULSE_VULKAN_DEVICE_H_
|
||||||
|
|
||||||
|
|||||||
@@ -10,12 +10,14 @@
|
|||||||
|
|
||||||
PulseFence VulkanCreateFence(PulseDevice device)
|
PulseFence VulkanCreateFence(PulseDevice device)
|
||||||
{
|
{
|
||||||
|
PULSE_CHECK_HANDLE_RETVAL(device, PULSE_NULL_HANDLE);
|
||||||
|
|
||||||
VkFenceCreateInfo fence_info = {};
|
VkFenceCreateInfo fence_info = {};
|
||||||
fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
||||||
fence_info.flags = VK_FENCE_CREATE_SIGNALED_BIT;
|
fence_info.flags = VK_FENCE_CREATE_SIGNALED_BIT;
|
||||||
VkFence vulkan_fence;
|
VkFence vulkan_fence;
|
||||||
VulkanDevice* vulkan_device = VULKAN_RETRIEVE_DRIVER_DATA_AS(device, VulkanDevice*);
|
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);
|
CHECK_VK_RETVAL(device->backend, 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));
|
PulseFenceHandler* fence = (PulseFenceHandler*)malloc(sizeof(PulseFenceHandler));
|
||||||
PULSE_CHECK_ALLOCATION_RETVAL(fence, PULSE_NULL_HANDLE);
|
PULSE_CHECK_ALLOCATION_RETVAL(fence, PULSE_NULL_HANDLE);
|
||||||
@@ -25,6 +27,15 @@ PulseFence VulkanCreateFence(PulseDevice device)
|
|||||||
|
|
||||||
void VulkanDestroyFence(PulseDevice device, PulseFence fence)
|
void VulkanDestroyFence(PulseDevice device, PulseFence fence)
|
||||||
{
|
{
|
||||||
|
PULSE_CHECK_HANDLE(device);
|
||||||
|
|
||||||
|
if(fence == PULSE_NULL_HANDLE)
|
||||||
|
{
|
||||||
|
if(PULSE_IS_BACKEND_LOW_LEVEL_DEBUG(device->backend))
|
||||||
|
PulseLogWarning(device->backend, "fence is NULL, this may be a bug in your application");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
VulkanDevice* vulkan_device = VULKAN_RETRIEVE_DRIVER_DATA_AS(device, VulkanDevice*);
|
VulkanDevice* vulkan_device = VULKAN_RETRIEVE_DRIVER_DATA_AS(device, VulkanDevice*);
|
||||||
if(vulkan_device == PULSE_NULLPTR || vulkan_device->device == VK_NULL_HANDLE)
|
if(vulkan_device == PULSE_NULLPTR || vulkan_device->device == VK_NULL_HANDLE)
|
||||||
return;
|
return;
|
||||||
@@ -37,6 +48,9 @@ void VulkanDestroyFence(PulseDevice device, PulseFence fence)
|
|||||||
|
|
||||||
bool VulkanIsFenceReady(PulseDevice device, PulseFence fence)
|
bool VulkanIsFenceReady(PulseDevice device, PulseFence fence)
|
||||||
{
|
{
|
||||||
|
PULSE_CHECK_HANDLE_RETVAL(device, false);
|
||||||
|
PULSE_CHECK_HANDLE_RETVAL(fence, false);
|
||||||
|
|
||||||
VulkanDevice* vulkan_device = VULKAN_RETRIEVE_DRIVER_DATA_AS(device, VulkanDevice*);
|
VulkanDevice* vulkan_device = VULKAN_RETRIEVE_DRIVER_DATA_AS(device, VulkanDevice*);
|
||||||
if(vulkan_device == PULSE_NULLPTR || vulkan_device->device == VK_NULL_HANDLE)
|
if(vulkan_device == PULSE_NULLPTR || vulkan_device->device == VK_NULL_HANDLE)
|
||||||
return false;
|
return false;
|
||||||
@@ -66,7 +80,7 @@ bool VulkanWaitForFences(PulseDevice device, const PulseFence* fences, uint32_t
|
|||||||
VkFence* vulkan_fences = (VkFence*)calloc(fences_count, sizeof(VkFence));
|
VkFence* vulkan_fences = (VkFence*)calloc(fences_count, sizeof(VkFence));
|
||||||
PULSE_CHECK_ALLOCATION_RETVAL(vulkan_fences, false);
|
PULSE_CHECK_ALLOCATION_RETVAL(vulkan_fences, false);
|
||||||
for(uint32_t i = 0; i < fences_count; i++)
|
for(uint32_t i = 0; i < fences_count; i++)
|
||||||
vulkan_fences[i] = VULKAN_RETRIEVE_DRIVER_DATA_AS(((PulseFence)fences + i), VkFence);
|
vulkan_fences[i] = VULKAN_RETRIEVE_DRIVER_DATA_AS(((PulseFence)fences[i]), VkFence);
|
||||||
VkResult result = vulkan_device->vkWaitForFences(vulkan_device->device, fences_count, vulkan_fences, wait_for_all, UINT64_MAX);
|
VkResult result = vulkan_device->vkWaitForFences(vulkan_device->device, fences_count, vulkan_fences, wait_for_all, UINT64_MAX);
|
||||||
free(vulkan_fences);
|
free(vulkan_fences);
|
||||||
switch(result)
|
switch(result)
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ static VkInstance VulkanCreateInstance(const char** extensions_enabled, uint32_t
|
|||||||
create_info.flags = 0;
|
create_info.flags = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
CHECK_VK_RETVAL(VulkanGetGlobal()->vkCreateInstance(&create_info, PULSE_NULLPTR, &instance), PULSE_ERROR_INITIALIZATION_FAILED, VK_NULL_HANDLE);
|
CHECK_VK_RETVAL(PULSE_NULL_HANDLE, VulkanGetGlobal()->vkCreateInstance(&create_info, PULSE_NULLPTR, &instance), PULSE_ERROR_INITIALIZATION_FAILED, VK_NULL_HANDLE);
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,8 @@
|
|||||||
// This file is part of "Pulse"
|
// This file is part of "Pulse"
|
||||||
// For conditions of distribution and use, see copyright notice in LICENSE
|
// For conditions of distribution and use, see copyright notice in LICENSE
|
||||||
|
|
||||||
#include <string.h>
|
#include <stdio.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
#include <Pulse.h>
|
#include <Pulse.h>
|
||||||
#include "PulseInternal.h"
|
#include "PulseInternal.h"
|
||||||
@@ -25,36 +26,41 @@ static const PulseCheckBackendSupportPFN backends_supports[] = {
|
|||||||
PULSE_NULLPTR
|
PULSE_NULLPTR
|
||||||
};
|
};
|
||||||
|
|
||||||
struct
|
static PulseErrorType last_error = PULSE_ERROR_NONE;
|
||||||
{
|
|
||||||
char file[1024];
|
|
||||||
char function[1024];
|
|
||||||
PulseErrorType type;
|
|
||||||
int line;
|
|
||||||
} last_error = { .file = { 0 }, .function = { 0 }, .type = PULSE_ERROR_NONE, .line = -1 };
|
|
||||||
|
|
||||||
void PulseSetInternalErrorBackend(PulseErrorType error, const char* file, const char* function, int line)
|
void PulseSetInternalError(PulseErrorType error)
|
||||||
{
|
{
|
||||||
strcpy(last_error.file, file);
|
last_error = error;
|
||||||
strcpy(last_error.function, function);
|
|
||||||
last_error.type = error;
|
|
||||||
last_error.line = line;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PulseLogErrorBackend(PulseBackend backend, PulseErrorType error, const char* file, const char* function, int line)
|
#define LOG_MESSAGE_MAX_LENGTH 4096
|
||||||
|
|
||||||
|
void PulseLogBackend(PulseBackend backend, PulseDebugMessageSeverity type, const char* message, const char* file, const char* function, int line, ...)
|
||||||
{
|
{
|
||||||
|
(void)file; // May be used later
|
||||||
if(backend == PULSE_NULL_HANDLE)
|
if(backend == PULSE_NULL_HANDLE)
|
||||||
return;
|
return;
|
||||||
if(!backend->PFN_UserDebugCallback)
|
if(!backend->PFN_UserDebugCallback)
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
void PulseLogWarningBackend(PulseBackend backend, PulseWarningType warning, const char* file, const char* function, int line)
|
va_list argptr;
|
||||||
{
|
va_start(argptr, line);
|
||||||
}
|
|
||||||
|
|
||||||
void PulseLogInfoBackend(PulseBackend backend, const char* message, const char* file, const char* function, int line)
|
char complete_message[LOG_MESSAGE_MAX_LENGTH] = { 0 };
|
||||||
{
|
|
||||||
|
int shift = 0;
|
||||||
|
|
||||||
|
if(type != PULSE_DEBUG_MESSAGE_SEVERITY_INFO)
|
||||||
|
{
|
||||||
|
shift = snprintf(complete_message, LOG_MESSAGE_MAX_LENGTH, "[%s:%d] ", function, line);
|
||||||
|
if(backend->debug_level == PULSE_PARANOID_DEBUG && type == PULSE_DEBUG_MESSAGE_SEVERITY_WARNING)
|
||||||
|
type = PULSE_DEBUG_MESSAGE_SEVERITY_ERROR;
|
||||||
|
if(shift == -1)
|
||||||
|
shift = 0;
|
||||||
|
}
|
||||||
|
vsnprintf(complete_message + shift, LOG_MESSAGE_MAX_LENGTH - shift, message, argptr);
|
||||||
|
backend->PFN_UserDebugCallback(type, complete_message);
|
||||||
|
va_end(argptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static PulseBackendFlags PulseSelectBackend(PulseBackendFlags backend_candidates, PulseShaderFormatsFlags shader_formats_used)
|
static PulseBackendFlags PulseSelectBackend(PulseBackendFlags backend_candidates, PulseShaderFormatsFlags shader_formats_used)
|
||||||
@@ -74,10 +80,6 @@ static PulseBackendFlags PulseSelectBackend(PulseBackendFlags backend_candidates
|
|||||||
return PULSE_BACKEND_INVALID;
|
return PULSE_BACKEND_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char* PulseVerbaliseErrorType(PulseErrorType error)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static PulseBackend PulseGetBackendFromFlag(PulseBackendBits flag)
|
static PulseBackend PulseGetBackendFromFlag(PulseBackendBits flag)
|
||||||
{
|
{
|
||||||
switch(flag)
|
switch(flag)
|
||||||
@@ -86,7 +88,7 @@ static PulseBackend PulseGetBackendFromFlag(PulseBackendBits flag)
|
|||||||
case PULSE_BACKEND_VULKAN: return &VulkanDriver;
|
case PULSE_BACKEND_VULKAN: return &VulkanDriver;
|
||||||
#endif
|
#endif
|
||||||
#ifdef PULSE_ENABLE_D3D11_BACKEND
|
#ifdef PULSE_ENABLE_D3D11_BACKEND
|
||||||
case PULSE_BACKEND_VULKAN: return &D3D11Driver;
|
case PULSE_BACKEND_D3D11: return &D3D11Driver;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
default: break;
|
default: break;
|
||||||
@@ -106,6 +108,7 @@ PULSE_API PulseBackend PulseLoadBackend(PulseBackendFlags backend_candidates, Pu
|
|||||||
if(!backend->PFN_LoadBackend(debug_level))
|
if(!backend->PFN_LoadBackend(debug_level))
|
||||||
return PULSE_NULL_HANDLE;
|
return PULSE_NULL_HANDLE;
|
||||||
backend->PFN_UserDebugCallback = PULSE_NULLPTR;
|
backend->PFN_UserDebugCallback = PULSE_NULLPTR;
|
||||||
|
backend->debug_level = debug_level;
|
||||||
return (PulseBackend)backend;
|
return (PulseBackend)backend;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,6 +118,12 @@ PULSE_API void PulseUnloadBackend(PulseBackend backend)
|
|||||||
backend->PFN_UnloadBackend(backend);
|
backend->PFN_UnloadBackend(backend);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PULSE_API PulseBackendFlags PulseGetBackendType(PulseBackend backend)
|
||||||
|
{
|
||||||
|
PULSE_CHECK_HANDLE_RETVAL(backend, PULSE_BACKEND_INVALID);
|
||||||
|
return backend->backend;
|
||||||
|
}
|
||||||
|
|
||||||
PULSE_API bool PulseSupportsBackend(PulseBackendFlags backend_candidates, PulseShaderFormatsFlags shader_formats_used)
|
PULSE_API bool PulseSupportsBackend(PulseBackendFlags backend_candidates, PulseShaderFormatsFlags shader_formats_used)
|
||||||
{
|
{
|
||||||
if((backend_candidates & PULSE_BACKEND_INVALID) != 0)
|
if((backend_candidates & PULSE_BACKEND_INVALID) != 0)
|
||||||
@@ -133,3 +142,27 @@ PULSE_API void PulseSetDebugCallback(PulseBackend backend, PulseDebugCallbackPFN
|
|||||||
PULSE_CHECK_HANDLE(backend);
|
PULSE_CHECK_HANDLE(backend);
|
||||||
backend->PFN_UserDebugCallback = callback;
|
backend->PFN_UserDebugCallback = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PULSE_API PulseErrorType PulseGetLastErrorType()
|
||||||
|
{
|
||||||
|
PulseErrorType error = last_error;
|
||||||
|
last_error = PULSE_ERROR_NONE;
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
PULSE_API const char* PulseVerbaliseErrorType(PulseErrorType error)
|
||||||
|
{
|
||||||
|
switch(error)
|
||||||
|
{
|
||||||
|
case PULSE_ERROR_NONE: return "no 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_CPU_ALLOCATION_FAILED: return "an internal CPU allocation failed";
|
||||||
|
case PULSE_ERROR_DEVICE_ALLOCATION_FAILED: return "a device allocation failed";
|
||||||
|
case PULSE_ERROR_DEVICE_LOST: return "device has been lost";
|
||||||
|
case PULSE_ERROR_INVALID_INTERNAL_POINTER: return "invalid internal pointer";
|
||||||
|
|
||||||
|
default: return "invalid error type";
|
||||||
|
};
|
||||||
|
return PULSE_NULLPTR; // To avoid warnings, should be unreachable
|
||||||
|
}
|
||||||
|
|||||||
71
Sources/PulseCommandList.c
git.filemode.normal_file
71
Sources/PulseCommandList.c
git.filemode.normal_file
@@ -0,0 +1,71 @@
|
|||||||
|
// Copyright (C) 2024 kanel
|
||||||
|
// This file is part of "Pulse"
|
||||||
|
// For conditions of distribution and use, see copyright notice in LICENSE
|
||||||
|
|
||||||
|
#include "PulseDefs.h"
|
||||||
|
#include "PulseInternal.h"
|
||||||
|
|
||||||
|
PULSE_API PulseCommandList PulseRequestCommandList(PulseDevice device, PulseCommandListUsage usage)
|
||||||
|
{
|
||||||
|
PULSE_CHECK_HANDLE_RETVAL(device, PULSE_NULL_HANDLE);
|
||||||
|
return device->PFN_RequestCommandList(device, usage);
|
||||||
|
}
|
||||||
|
|
||||||
|
PULSE_API bool PulseSubmitCommandList(PulseDevice device, PulseCommandList cmd, PulseFence fence)
|
||||||
|
{
|
||||||
|
PULSE_CHECK_HANDLE_RETVAL(device, false);
|
||||||
|
PULSE_CHECK_HANDLE_RETVAL(cmd, false);
|
||||||
|
|
||||||
|
if(cmd->state != PULSE_COMMAND_LIST_STATE_READY)
|
||||||
|
{
|
||||||
|
switch(cmd->state)
|
||||||
|
{
|
||||||
|
case PULSE_COMMAND_LIST_STATE_INVALID:
|
||||||
|
if(PULSE_IS_BACKEND_LOW_LEVEL_DEBUG(device->backend))
|
||||||
|
PulseLogError(device->backend, "command list is in invalid state");
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case PULSE_COMMAND_LIST_STATE_EMPTY:
|
||||||
|
if(PULSE_IS_BACKEND_LOW_LEVEL_DEBUG(device->backend))
|
||||||
|
PulseLogWarning(device->backend, "command list is empty");
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case PULSE_COMMAND_LIST_STATE_RECORDING:
|
||||||
|
if(PULSE_IS_BACKEND_LOW_LEVEL_DEBUG(device->backend))
|
||||||
|
PulseLogError(device->backend, "command list is in recording state");
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case PULSE_COMMAND_LIST_STATE_SENT:
|
||||||
|
if(PULSE_IS_BACKEND_LOW_LEVEL_DEBUG(device->backend))
|
||||||
|
PulseLogWarning(device->backend, "command list has already been submitted");
|
||||||
|
return false;
|
||||||
|
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return device->PFN_SubmitCommandList(device, cmd, fence);
|
||||||
|
}
|
||||||
|
|
||||||
|
PULSE_API void PulseReleaseCommandList(PulseDevice device, PulseCommandList cmd)
|
||||||
|
{
|
||||||
|
PULSE_CHECK_HANDLE(device);
|
||||||
|
|
||||||
|
if(cmd == PULSE_NULL_HANDLE)
|
||||||
|
{
|
||||||
|
if(PULSE_IS_BACKEND_LOW_LEVEL_DEBUG(device->backend))
|
||||||
|
PulseLogWarning(device->backend, "command list is NULL, this may be a bug in your application");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(cmd->state)
|
||||||
|
{
|
||||||
|
case PULSE_COMMAND_LIST_STATE_RECORDING:
|
||||||
|
if(PULSE_IS_BACKEND_LOW_LEVEL_DEBUG(device->backend))
|
||||||
|
PulseLogWarning(device->backend, "command list is in recording state");
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
return device->PFN_ReleaseCommandList(device, cmd);
|
||||||
|
}
|
||||||
@@ -10,9 +10,8 @@ PULSE_API PulseComputePipeline PulseCreateComputePipeline(PulseDevice device, co
|
|||||||
PULSE_CHECK_HANDLE_RETVAL(device, PULSE_NULL_HANDLE);
|
PULSE_CHECK_HANDLE_RETVAL(device, PULSE_NULL_HANDLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
PULSE_API void PulseBindComputePipeline(PulseComputePass pass, PulseComputePipeline pipeline)
|
PULSE_API void PulseBindComputePipeline(PulseComputePipeline pipeline)
|
||||||
{
|
{
|
||||||
PULSE_CHECK_HANDLE(pass);
|
|
||||||
PULSE_CHECK_HANDLE(pipeline);
|
PULSE_CHECK_HANDLE(pipeline);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,30 +3,3 @@
|
|||||||
// For conditions of distribution and use, see copyright notice in LICENSE
|
// For conditions of distribution and use, see copyright notice in LICENSE
|
||||||
|
|
||||||
#include <PulseProfile.h>
|
#include <PulseProfile.h>
|
||||||
#include "PulseDebug.h"
|
|
||||||
|
|
||||||
const char* PulseVerbaliseErrorType(PulseErrorType error)
|
|
||||||
{
|
|
||||||
switch(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_CPU_ALLOCATION_FAILED: return "a CPU allocation failed";
|
|
||||||
case PULSE_ERROR_DEVICE_ALLOCATION_FAILED: return "a device allocation failed";
|
|
||||||
case PULSE_ERROR_DEVICE_LOST: return "device has been lost";
|
|
||||||
case PULSE_ERROR_INVALID_INTERNAL_POINTER: return "invalid internal pointer";
|
|
||||||
case PULSE_ERROR_INVALID_HANDLE: return "invalid handle";
|
|
||||||
|
|
||||||
default: return "invalid error type";
|
|
||||||
};
|
|
||||||
return PULSE_NULLPTR; // To avoid warnings, should be unreachable
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* PulseVerbaliseWarningType(PulseWarningType warning)
|
|
||||||
{
|
|
||||||
switch(warning)
|
|
||||||
{
|
|
||||||
default: return "invalid warning type";
|
|
||||||
};
|
|
||||||
return PULSE_NULLPTR; // To avoid warnings, should be unreachable
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
// Copyright (C) 2024 kanel
|
|
||||||
// This file is part of "Pulse"
|
|
||||||
// For conditions of distribution and use, see copyright notice in LICENSE
|
|
||||||
|
|
||||||
#ifndef PULSE_DEBUG_H_
|
|
||||||
#define PULSE_DEBUG_H_
|
|
||||||
|
|
||||||
#include "PulseEnums.h"
|
|
||||||
|
|
||||||
const char* PulseVerbaliseErrorType(PulseErrorType error);
|
|
||||||
const char* PulseVerbaliseWarningType(PulseWarningType warning);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -40,6 +40,13 @@
|
|||||||
} \
|
} \
|
||||||
} while(0); \
|
} while(0); \
|
||||||
|
|
||||||
|
#define PULSE_UNUSED(x) ((void)x)
|
||||||
|
|
||||||
|
#define PULSE_CHECK_BACKEND_DEBUG_LEVEL(backend, level) (backend != PULSE_NULL_HANDLE && ((PulseBackend)backend)->debug_level >= level)
|
||||||
|
|
||||||
|
#define PULSE_IS_BACKEND_LOW_LEVEL_DEBUG(backend) PULSE_CHECK_BACKEND_DEBUG_LEVEL(backend, PULSE_LOW_DEBUG)
|
||||||
|
#define PULSE_IS_BACKEND_HIGH_LEVEL_DEBUG(backend) PULSE_CHECK_BACKEND_DEBUG_LEVEL(backend, PULSE_HIGH_DEBUG)
|
||||||
|
|
||||||
#define PULSE_CHECK_PTR(handle) PULSE_CHECK_PTR_RETVAL(handle, )
|
#define PULSE_CHECK_PTR(handle) PULSE_CHECK_PTR_RETVAL(handle, )
|
||||||
|
|
||||||
#define PULSE_LOAD_DRIVER_DEVICE_FUNCTION(fn, _namespace) pulse_device->PFN_##fn = _namespace##fn;
|
#define PULSE_LOAD_DRIVER_DEVICE_FUNCTION(fn, _namespace) pulse_device->PFN_##fn = _namespace##fn;
|
||||||
@@ -52,5 +59,8 @@
|
|||||||
PULSE_LOAD_DRIVER_DEVICE_FUNCTION(DestroyFence, _namespace) \
|
PULSE_LOAD_DRIVER_DEVICE_FUNCTION(DestroyFence, _namespace) \
|
||||||
PULSE_LOAD_DRIVER_DEVICE_FUNCTION(IsFenceReady, _namespace) \
|
PULSE_LOAD_DRIVER_DEVICE_FUNCTION(IsFenceReady, _namespace) \
|
||||||
PULSE_LOAD_DRIVER_DEVICE_FUNCTION(WaitForFences, _namespace) \
|
PULSE_LOAD_DRIVER_DEVICE_FUNCTION(WaitForFences, _namespace) \
|
||||||
|
PULSE_LOAD_DRIVER_DEVICE_FUNCTION(RequestCommandList, _namespace) \
|
||||||
|
PULSE_LOAD_DRIVER_DEVICE_FUNCTION(SubmitCommandList, _namespace) \
|
||||||
|
PULSE_LOAD_DRIVER_DEVICE_FUNCTION(ReleaseCommandList, _namespace) \
|
||||||
|
|
||||||
#endif // PULSE_DEFS_H_
|
#endif // PULSE_DEFS_H_
|
||||||
|
|||||||
@@ -14,22 +14,4 @@ typedef enum PulseCommandListState
|
|||||||
PULSE_COMMAND_LIST_STATE_SENT
|
PULSE_COMMAND_LIST_STATE_SENT
|
||||||
} PulseCommandListState;
|
} PulseCommandListState;
|
||||||
|
|
||||||
typedef enum PulseErrorType
|
|
||||||
{
|
|
||||||
PULSE_ERROR_NONE,
|
|
||||||
|
|
||||||
PULSE_ERROR_DEVICE_LOST,
|
|
||||||
PULSE_ERROR_INVALID_HANDLE,
|
|
||||||
PULSE_ERROR_INVALID_INTERNAL_POINTER,
|
|
||||||
PULSE_ERROR_INITIALIZATION_FAILED,
|
|
||||||
PULSE_ERROR_CPU_ALLOCATION_FAILED,
|
|
||||||
PULSE_ERROR_DEVICE_ALLOCATION_FAILED,
|
|
||||||
PULSE_ERROR_BACKENDS_CANDIDATES_SHADER_FORMAT_MISMATCH,
|
|
||||||
} PulseErrorType;
|
|
||||||
|
|
||||||
typedef enum PulseWarningType
|
|
||||||
{
|
|
||||||
PULSE_WARNING_NONE,
|
|
||||||
} PulseWarningType;
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
32
Sources/PulseFence.c
git.filemode.normal_file
32
Sources/PulseFence.c
git.filemode.normal_file
@@ -0,0 +1,32 @@
|
|||||||
|
// Copyright (C) 2024 kanel
|
||||||
|
// This file is part of "Pulse"
|
||||||
|
// For conditions of distribution and use, see copyright notice in LICENSE
|
||||||
|
|
||||||
|
#include "PulseDefs.h"
|
||||||
|
#include "PulseInternal.h"
|
||||||
|
|
||||||
|
PULSE_API PulseFence PulseCreateFence(PulseDevice device)
|
||||||
|
{
|
||||||
|
PULSE_CHECK_HANDLE_RETVAL(device, PULSE_NULL_HANDLE);
|
||||||
|
return device->PFN_CreateFence(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
PULSE_API void PulseDestroyFence(PulseDevice device, PulseFence fence)
|
||||||
|
{
|
||||||
|
PULSE_CHECK_HANDLE(device);
|
||||||
|
return device->PFN_DestroyFence(device, fence);
|
||||||
|
}
|
||||||
|
|
||||||
|
PULSE_API bool PulseIsFenceReady(PulseDevice device, PulseFence fence)
|
||||||
|
{
|
||||||
|
PULSE_CHECK_HANDLE_RETVAL(device, false);
|
||||||
|
PULSE_CHECK_HANDLE_RETVAL(fence, false);
|
||||||
|
return device->PFN_IsFenceReady(device, fence);
|
||||||
|
}
|
||||||
|
|
||||||
|
PULSE_API bool PulseWaitForFences(PulseDevice device, const PulseFence* fences, uint32_t fences_count, bool wait_for_all)
|
||||||
|
{
|
||||||
|
PULSE_CHECK_HANDLE_RETVAL(device, false);
|
||||||
|
PULSE_CHECK_PTR_RETVAL(fences, false);
|
||||||
|
return device->PFN_WaitForFences(device, fences, fences_count, wait_for_all);
|
||||||
|
}
|
||||||
@@ -25,6 +25,7 @@ typedef struct PulseBackendHandler
|
|||||||
PulseShaderFormatsFlags supported_shader_formats;
|
PulseShaderFormatsFlags supported_shader_formats;
|
||||||
void* driver_data;
|
void* driver_data;
|
||||||
PulseDebugCallbackPFN PFN_UserDebugCallback;
|
PulseDebugCallbackPFN PFN_UserDebugCallback;
|
||||||
|
PulseDebugLevel debug_level;
|
||||||
} PulseBackendHandler;
|
} PulseBackendHandler;
|
||||||
|
|
||||||
typedef struct PulseBufferHandler
|
typedef struct PulseBufferHandler
|
||||||
@@ -36,15 +37,16 @@ typedef struct PulseCommandListHandler
|
|||||||
{
|
{
|
||||||
PulseDevice device;
|
PulseDevice device;
|
||||||
void* driver_data;
|
void* driver_data;
|
||||||
|
PulseThreadID thread_id;
|
||||||
|
PulseComputePipeline* compute_pipelines_bound;
|
||||||
|
uint32_t compute_pipelines_bound_capacity;
|
||||||
|
uint32_t compute_pipelines_bound_size;
|
||||||
PulseCommandListState state;
|
PulseCommandListState state;
|
||||||
|
PulseCommandListUsage usage;
|
||||||
bool is_compute_pipeline_bound;
|
bool is_compute_pipeline_bound;
|
||||||
|
bool is_available;
|
||||||
} PulseCommandListHandler;
|
} PulseCommandListHandler;
|
||||||
|
|
||||||
typedef struct PulseComputePassHandler
|
|
||||||
{
|
|
||||||
void* driver_data;
|
|
||||||
} PulseComputePassHandler;
|
|
||||||
|
|
||||||
typedef struct PulseComputePipelineHandler
|
typedef struct PulseComputePipelineHandler
|
||||||
{
|
{
|
||||||
void* driver_data;
|
void* driver_data;
|
||||||
@@ -61,6 +63,9 @@ typedef struct PulseDeviceHandler
|
|||||||
PulseDestroyFencePFN PFN_DestroyFence;
|
PulseDestroyFencePFN PFN_DestroyFence;
|
||||||
PulseIsFenceReadyPFN PFN_IsFenceReady;
|
PulseIsFenceReadyPFN PFN_IsFenceReady;
|
||||||
PulseWaitForFencesPFN PFN_WaitForFences;
|
PulseWaitForFencesPFN PFN_WaitForFences;
|
||||||
|
PulseRequestCommandListPFN PFN_RequestCommandList;
|
||||||
|
PulseSubmitCommandListPFN PFN_SubmitCommandList;
|
||||||
|
PulseReleaseCommandListPFN PFN_ReleaseCommandList;
|
||||||
|
|
||||||
// Attributes
|
// Attributes
|
||||||
void* driver_data;
|
void* driver_data;
|
||||||
@@ -72,11 +77,6 @@ typedef struct PulseFenceHandler
|
|||||||
void* driver_data;
|
void* driver_data;
|
||||||
} PulseFenceHandler;
|
} PulseFenceHandler;
|
||||||
|
|
||||||
typedef struct PulseGeneralPassHandler
|
|
||||||
{
|
|
||||||
void* driver_data;
|
|
||||||
} PulseGeneralPassHandler;
|
|
||||||
|
|
||||||
typedef struct PulseImageHandler
|
typedef struct PulseImageHandler
|
||||||
{
|
{
|
||||||
void* driver_data;
|
void* driver_data;
|
||||||
@@ -84,13 +84,17 @@ typedef struct PulseImageHandler
|
|||||||
|
|
||||||
PulseThreadID PulseGetThreadID();
|
PulseThreadID PulseGetThreadID();
|
||||||
|
|
||||||
void PulseLogErrorBackend(PulseBackend backend, PulseErrorType error, const char* file, const char* function, int line);
|
void PulseSetInternalError(PulseErrorType error);
|
||||||
void PulseLogWarningBackend(PulseBackend backend, PulseWarningType warning, const char* file, const char* function, int line);
|
|
||||||
void PulseLogInfoBackend(PulseBackend backend, const char* message, const char* file, const char* function, int line);
|
|
||||||
|
|
||||||
#define PulseLogError(backend, type) PulseSetInternalErrorBackend(backend, type, __FILE__, __FUNCTION__, __LINE__)
|
void PulseLogBackend(PulseBackend backend, PulseDebugMessageSeverity type, const char* message, const char* file, const char* function, int line, ...);
|
||||||
#define PulseLogWarning(backend, type) PulseSetInternalErrorBackend(backend, type, __FILE__, __FUNCTION__, __LINE__)
|
|
||||||
#define PulseLogInfo(backend, msg) PulseSetInternalErrorBackend(backend, msg, __FILE__, __FUNCTION__, __LINE__)
|
#define PulseLogError(backend, msg) PulseLogBackend(backend, PULSE_DEBUG_MESSAGE_SEVERITY_ERROR, msg, __FILE__, __FUNCTION__, __LINE__)
|
||||||
|
#define PulseLogWarning(backend, msg) PulseLogBackend(backend, PULSE_DEBUG_MESSAGE_SEVERITY_WARNING, msg, __FILE__, __FUNCTION__, __LINE__)
|
||||||
|
#define PulseLogInfo(backend, msg) PulseLogBackend(backend, PULSE_DEBUG_MESSAGE_SEVERITY_INFO, msg, __FILE__, __FUNCTION__, __LINE__)
|
||||||
|
|
||||||
|
#define PulseLogErrorFmt(backend, msg, ...) PulseLogBackend(backend, PULSE_DEBUG_MESSAGE_SEVERITY_ERROR, msg, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__)
|
||||||
|
#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__)
|
||||||
|
|
||||||
#ifdef PULSE_ENABLE_VULKAN_BACKEND
|
#ifdef PULSE_ENABLE_VULKAN_BACKEND
|
||||||
extern PulseBackendHandler VulkanDriver;
|
extern PulseBackendHandler VulkanDriver;
|
||||||
|
|||||||
@@ -15,11 +15,14 @@ typedef PulseDevice (*PulseCreateDevicePFN)(PulseBackend, PulseDevice*, uint32_t
|
|||||||
|
|
||||||
typedef void (*PulseDestroyDevicePFN)(PulseDevice);
|
typedef void (*PulseDestroyDevicePFN)(PulseDevice);
|
||||||
typedef PulseComputePipeline (*PulseCreateComputePipelinePFN)(PulseDevice, const PulseComputePipelineCreateInfo*);
|
typedef PulseComputePipeline (*PulseCreateComputePipelinePFN)(PulseDevice, const PulseComputePipelineCreateInfo*);
|
||||||
typedef void (*PulseBindComputePipelinePFN)(PulseComputePass, PulseComputePipeline);
|
typedef void (*PulseBindComputePipelinePFN)(PulseComputePipeline);
|
||||||
typedef void (*PulseDestroyComputePipelinePFN)(PulseDevice, PulseComputePipeline);
|
typedef void (*PulseDestroyComputePipelinePFN)(PulseDevice, PulseComputePipeline);
|
||||||
typedef PulseFence (*PulseCreateFencePFN)(PulseDevice);
|
typedef PulseFence (*PulseCreateFencePFN)(PulseDevice);
|
||||||
typedef void (*PulseDestroyFencePFN)(PulseDevice, PulseFence);
|
typedef void (*PulseDestroyFencePFN)(PulseDevice, PulseFence);
|
||||||
typedef bool (*PulseIsFenceReadyPFN)(PulseDevice, PulseFence);
|
typedef bool (*PulseIsFenceReadyPFN)(PulseDevice, PulseFence);
|
||||||
typedef bool (*PulseWaitForFencesPFN)(PulseDevice, const PulseFence*, uint32_t, bool);
|
typedef bool (*PulseWaitForFencesPFN)(PulseDevice, const PulseFence*, uint32_t, bool);
|
||||||
|
typedef PulseCommandList (*PulseRequestCommandListPFN)(PulseDevice, PulseCommandListUsage);
|
||||||
|
typedef bool (*PulseSubmitCommandListPFN)(PulseDevice, PulseCommandList, PulseFence);
|
||||||
|
typedef void (*PulseReleaseCommandListPFN)(PulseDevice, PulseCommandList);
|
||||||
|
|
||||||
#endif // PULSE_PFNS_H_
|
#endif // PULSE_PFNS_H_
|
||||||
|
|||||||
42
Tests/Vulkan/Backend.c
git.filemode.normal_file
42
Tests/Vulkan/Backend.c
git.filemode.normal_file
@@ -0,0 +1,42 @@
|
|||||||
|
#include "Common.h"
|
||||||
|
|
||||||
|
#include <unity/unity.h>
|
||||||
|
#include <Pulse.h>
|
||||||
|
|
||||||
|
void DumbDebugCallBack(PulseDebugMessageSeverity severity, const char* message)
|
||||||
|
{
|
||||||
|
(void)severity;
|
||||||
|
(void)message;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestBackendSetup()
|
||||||
|
{
|
||||||
|
PulseBackend backend = PulseLoadBackend(PULSE_BACKEND_VULKAN, PULSE_SHADER_FORMAT_SPIRV_BIT, PULSE_HIGH_DEBUG);
|
||||||
|
TEST_ASSERT_NOT_EQUAL_MESSAGE(backend, PULSE_NULL_HANDLE, PulseVerbaliseErrorType(PulseGetLastErrorType()));
|
||||||
|
PulseSetDebugCallback(backend, DumbDebugCallBack);
|
||||||
|
PulseUnloadBackend(backend);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestBackendAnySetup()
|
||||||
|
{
|
||||||
|
PulseBackend backend = PulseLoadBackend(PULSE_BACKEND_ANY, PULSE_SHADER_FORMAT_SPIRV_BIT, PULSE_HIGH_DEBUG);
|
||||||
|
TEST_ASSERT_NOT_EQUAL_MESSAGE(backend, PULSE_NULL_HANDLE, PulseVerbaliseErrorType(PulseGetLastErrorType()));
|
||||||
|
TEST_ASSERT_EQUAL(PulseGetBackendType(backend), PULSE_BACKEND_VULKAN);
|
||||||
|
PulseSetDebugCallback(backend, DumbDebugCallBack);
|
||||||
|
PulseUnloadBackend(backend);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestWrongBackendSetup()
|
||||||
|
{
|
||||||
|
PulseBackend backend = PulseLoadBackend(PULSE_BACKEND_VULKAN, PULSE_SHADER_FORMAT_DXBC_BIT, PULSE_HIGH_DEBUG);
|
||||||
|
TEST_ASSERT_EQUAL(backend, PULSE_NULL_HANDLE);
|
||||||
|
PulseSetDebugCallback(backend, DumbDebugCallBack);
|
||||||
|
PulseUnloadBackend(backend);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestBackend()
|
||||||
|
{
|
||||||
|
RUN_TEST(TestBackendSetup);
|
||||||
|
RUN_TEST(TestBackendAnySetup);
|
||||||
|
RUN_TEST(TestWrongBackendSetup);
|
||||||
|
}
|
||||||
28
Tests/Vulkan/Common.c
git.filemode.normal_file
28
Tests/Vulkan/Common.c
git.filemode.normal_file
@@ -0,0 +1,28 @@
|
|||||||
|
#include "Common.h"
|
||||||
|
#include <unity/unity.h>
|
||||||
|
|
||||||
|
void DebugCallBack(PulseDebugMessageSeverity severity, const char* message)
|
||||||
|
{
|
||||||
|
if(severity == PULSE_DEBUG_MESSAGE_SEVERITY_ERROR)
|
||||||
|
TEST_FAIL_MESSAGE(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define LOG_MESSAGE_MAX_LENGTH 4096
|
||||||
|
|
||||||
|
void SetupPulse(PulseBackend* backend)
|
||||||
|
{
|
||||||
|
*backend = PulseLoadBackend(PULSE_BACKEND_VULKAN, PULSE_SHADER_FORMAT_SPIRV_BIT, PULSE_PARANOID_DEBUG);
|
||||||
|
if(*backend == PULSE_NULL_HANDLE)
|
||||||
|
{
|
||||||
|
char complete_message[LOG_MESSAGE_MAX_LENGTH] = { 0 };
|
||||||
|
snprintf(complete_message, LOG_MESSAGE_MAX_LENGTH, "Fatal Error: could not load Pulse using Vulkan due to %s", PulseVerbaliseErrorType(PulseGetLastErrorType()));
|
||||||
|
TEST_FAIL_MESSAGE(complete_message);
|
||||||
|
TEST_ABORT();
|
||||||
|
}
|
||||||
|
PulseSetDebugCallback(*backend, DebugCallBack);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CleanupPulse(PulseBackend backend)
|
||||||
|
{
|
||||||
|
PulseUnloadBackend(backend);
|
||||||
|
}
|
||||||
26
Tests/Vulkan/Common.h
git.filemode.normal_file
26
Tests/Vulkan/Common.h
git.filemode.normal_file
@@ -0,0 +1,26 @@
|
|||||||
|
#ifndef TEST_COMMON_H_
|
||||||
|
#define TEST_COMMON_H_
|
||||||
|
|
||||||
|
#define RUN_TEST_AT_LINE(fn, line) \
|
||||||
|
{ \
|
||||||
|
Unity.TestFile = __FILE__; \
|
||||||
|
Unity.CurrentTestName = #fn; \
|
||||||
|
Unity.CurrentTestLineNumber = line; \
|
||||||
|
Unity.NumberOfTests++; \
|
||||||
|
UNITY_CLR_DETAILS(); \
|
||||||
|
UNITY_EXEC_TIME_START(); \
|
||||||
|
if(TEST_PROTECT()) \
|
||||||
|
fn(); \
|
||||||
|
UNITY_EXEC_TIME_STOP(); \
|
||||||
|
UnityConcludeTest(); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define RUN_TEST(fn) RUN_TEST_AT_LINE(fn, __LINE__);
|
||||||
|
|
||||||
|
#include <Pulse.h>
|
||||||
|
|
||||||
|
void DebugCallBack(PulseDebugMessageSeverity severity, const char* message);
|
||||||
|
void SetupPulse(PulseBackend* backend);
|
||||||
|
void CleanupPulse(PulseBackend backend);
|
||||||
|
|
||||||
|
#endif
|
||||||
75
Tests/Vulkan/Device.c
git.filemode.normal_file
75
Tests/Vulkan/Device.c
git.filemode.normal_file
@@ -0,0 +1,75 @@
|
|||||||
|
#include "Common.h"
|
||||||
|
|
||||||
|
#include <unity/unity.h>
|
||||||
|
#include <Pulse.h>
|
||||||
|
|
||||||
|
void TestDeviceSetup()
|
||||||
|
{
|
||||||
|
PulseBackend backend;
|
||||||
|
SetupPulse(&backend);
|
||||||
|
|
||||||
|
PulseDevice device = PulseCreateDevice(backend, NULL, 0);
|
||||||
|
TEST_ASSERT_NOT_EQUAL_MESSAGE(device, PULSE_NULL_HANDLE, PulseVerbaliseErrorType(PulseGetLastErrorType()));
|
||||||
|
PulseDestroyDevice(device);
|
||||||
|
|
||||||
|
CleanupPulse(backend);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestForbiddenDeviceSetup()
|
||||||
|
{
|
||||||
|
PulseBackend backend;
|
||||||
|
SetupPulse(&backend);
|
||||||
|
|
||||||
|
PulseDevice device1 = PulseCreateDevice(backend, NULL, 0);
|
||||||
|
TEST_ASSERT_NOT_EQUAL_MESSAGE(device1, PULSE_NULL_HANDLE, PulseVerbaliseErrorType(PulseGetLastErrorType()));
|
||||||
|
|
||||||
|
PulseDevice device2 = PulseCreateDevice(backend, &device1, 1);
|
||||||
|
TEST_ASSERT_NOT_EQUAL(device2, device1);
|
||||||
|
|
||||||
|
PulseDestroyDevice(device2);
|
||||||
|
PulseDestroyDevice(device1);
|
||||||
|
|
||||||
|
CleanupPulse(backend);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestInvalidBackendDeviceSetup()
|
||||||
|
{
|
||||||
|
PulseDevice device= PulseCreateDevice(PULSE_NULL_HANDLE, NULL, 0);
|
||||||
|
TEST_ASSERT_EQUAL(device, PULSE_NULL_HANDLE);
|
||||||
|
PulseDestroyDevice(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestBackendInUse()
|
||||||
|
{
|
||||||
|
PulseBackend backend;
|
||||||
|
SetupPulse(&backend);
|
||||||
|
|
||||||
|
PulseDevice device = PulseCreateDevice(backend, NULL, 0);
|
||||||
|
TEST_ASSERT_NOT_EQUAL_MESSAGE(device, PULSE_NULL_HANDLE, PulseVerbaliseErrorType(PulseGetLastErrorType()));
|
||||||
|
TEST_ASSERT_EQUAL(PulseGetBackendInUseByDevice(device), PULSE_BACKEND_VULKAN);
|
||||||
|
PulseDestroyDevice(device);
|
||||||
|
|
||||||
|
CleanupPulse(backend);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestShaderFormatSupport()
|
||||||
|
{
|
||||||
|
PulseBackend backend;
|
||||||
|
SetupPulse(&backend);
|
||||||
|
|
||||||
|
PulseDevice device = PulseCreateDevice(backend, NULL, 0);
|
||||||
|
TEST_ASSERT_NOT_EQUAL_MESSAGE(device, PULSE_NULL_HANDLE, PulseVerbaliseErrorType(PulseGetLastErrorType()));
|
||||||
|
TEST_ASSERT_TRUE(PulseDeviceSupportsShaderFormats(device, PULSE_SHADER_FORMAT_SPIRV_BIT));
|
||||||
|
PulseDestroyDevice(device);
|
||||||
|
|
||||||
|
CleanupPulse(backend);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestDevice()
|
||||||
|
{
|
||||||
|
RUN_TEST(TestDeviceSetup);
|
||||||
|
RUN_TEST(TestForbiddenDeviceSetup);
|
||||||
|
RUN_TEST(TestInvalidBackendDeviceSetup);
|
||||||
|
RUN_TEST(TestBackendInUse);
|
||||||
|
RUN_TEST(TestShaderFormatSupport);
|
||||||
|
}
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
#include <unity/unity.h>
|
|
||||||
#include <Pulse.h>
|
|
||||||
|
|
||||||
extern PulseBackend backend;
|
|
||||||
|
|
||||||
void TestDeviceSetup()
|
|
||||||
{
|
|
||||||
PulseDevice device = PulseCreateDevice(backend, NULL, 0);
|
|
||||||
TEST_ASSERT_NOT_EQUAL_MESSAGE(device, PULSE_NULL_HANDLE, PulseVerbaliseErrorType(PulseGetLastErrorType()));
|
|
||||||
PulseDestroyDevice(device);
|
|
||||||
}
|
|
||||||
@@ -3,39 +3,13 @@
|
|||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
PulseBackend backend;
|
extern void TestBackend();
|
||||||
|
extern void TestDevice();
|
||||||
extern void TestDeviceSetup();
|
|
||||||
|
|
||||||
bool SetupPulse()
|
|
||||||
{
|
|
||||||
backend = PulseLoadBackend(PULSE_BACKEND_VULKAN, PULSE_SHADER_FORMAT_SPIRV_BIT, PULSE_NO_DEBUG);
|
|
||||||
if(backend == PULSE_NULL_HANDLE)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "Fatal Error: could not load Pulse using Vulkan due to %s", PulseVerbaliseErrorType(PulseGetLastErrorType()));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
puts("Pulse loaded using Vulkan");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
int RunUnitTests()
|
|
||||||
{
|
|
||||||
UNITY_BEGIN();
|
|
||||||
RUN_TEST(TestDeviceSetup);
|
|
||||||
return UNITY_END();
|
|
||||||
}
|
|
||||||
|
|
||||||
void UnloadPulse()
|
|
||||||
{
|
|
||||||
PulseUnloadBackend(backend);
|
|
||||||
puts("Pulse unloaded");
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
SetupPulse();
|
UNITY_BEGIN();
|
||||||
int result = RunUnitTests();
|
TestBackend();
|
||||||
UnloadPulse();
|
TestDevice();
|
||||||
return result;
|
return UNITY_END();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user