diff --git a/drivers/vulkan/vulkan_context.cpp b/drivers/vulkan/vulkan_context.cpp index 7db2a9cd661a..9ffe7389aab9 100644 --- a/drivers/vulkan/vulkan_context.cpp +++ b/drivers/vulkan/vulkan_context.cpp @@ -42,6 +42,7 @@ #include #include #include +#include #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) #define APP_SHORT_NAME "GodotEngine" @@ -1794,6 +1795,22 @@ Error VulkanContext::_create_semaphores() { /*pNext*/ nullptr, /*flags*/ 0, }; + // Create compute semaphore that can be polled to determine whether + // a given compute block has finished. + // Every time a compute call finishes, we'll increment the value + // of this semaphore by one, so we can check the status + VkSemaphoreTypeCreateInfo timelineCreateInfo = { + /*sType*/ VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO, + /*pNext*/ nullptr, + /*semaphoreType*/ VK_SEMAPHORE_TYPE_TIMELINE, + /*initialValue*/ 0, + }; + + VkSemaphoreCreateInfo computeSemaphoreCreateInfo = { + /*sType*/ VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, + /*pNext*/ &timelineCreateInfo, + /*flags*/ 0, + }; // Create fences that we can use to throttle if we get too far // ahead of the image presents. @@ -1816,6 +1833,9 @@ Error VulkanContext::_create_semaphores() { } frame_index = 0; + err = vkCreateSemaphore(device, &computeSemaphoreCreateInfo, nullptr, &compute_semaphore[0]); + ERR_FAIL_COND_V(err, ERR_CANT_CREATE); + // Get Memory information and properties. vkGetPhysicalDeviceMemoryProperties(gpu, &memory_properties); @@ -2781,16 +2801,26 @@ void VulkanContext::local_device_push_command_buffers(RID p_local_device, const LocalDevice *ld = local_device_owner.get_or_null(p_local_device); ERR_FAIL_COND(ld->waiting); + compute_semaphore_signal_value += 1; + + VkTimelineSemaphoreSubmitInfo signal_info; + signal_info.sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO; + signal_info.pNext = nullptr; + signal_info.waitSemaphoreValueCount = 0; + signal_info.signalSemaphoreValueCount = 1; + signal_info.pSignalSemaphoreValues = &compute_semaphore_signal_value; + VkSubmitInfo submit_info; submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submit_info.pNext = nullptr; + submit_info.pNext = &signal_info; submit_info.pWaitDstStageMask = nullptr; submit_info.waitSemaphoreCount = 0; submit_info.pWaitSemaphores = nullptr; submit_info.commandBufferCount = p_count; submit_info.pCommandBuffers = (const VkCommandBuffer *)p_buffers; - submit_info.signalSemaphoreCount = 0; - submit_info.pSignalSemaphores = nullptr; + submit_info.signalSemaphoreCount = 1; + submit_info.pSignalSemaphores = &compute_semaphore[0]; + VkResult err = vkQueueSubmit(ld->queue, 1, &submit_info, VK_NULL_HANDLE); if (err == VK_ERROR_OUT_OF_HOST_MEMORY) { @@ -2813,8 +2843,18 @@ void VulkanContext::local_device_sync(RID p_local_device) { vkDeviceWaitIdle(ld->device); ld->waiting = false; + } +bool VulkanContext::local_device_check_status(RID p_local_device) { + LocalDevice *ld = local_device_owner.get_or_null(p_local_device); + ERR_FAIL_COND_V(!ld->waiting, false); + uint64_t out = 0; + vkGetSemaphoreCounterValue(ld->device, compute_semaphore[0], &out); + return out >= compute_semaphore_signal_value; +} + + void VulkanContext::local_device_free(RID p_local_device) { LocalDevice *ld = local_device_owner.get_or_null(p_local_device); memdelete(ld->driver); @@ -2901,6 +2941,7 @@ VulkanContext::~VulkanContext() { vkDestroySemaphore(device, image_ownership_semaphores[i], nullptr); } } + vkDestroySemaphore(device, compute_semaphore[0], nullptr); if (inst_initialized && is_instance_extension_enabled(VK_EXT_DEBUG_UTILS_EXTENSION_NAME)) { DestroyDebugUtilsMessengerEXT(inst, dbg_messenger, nullptr); } diff --git a/drivers/vulkan/vulkan_context.h b/drivers/vulkan/vulkan_context.h index cbb6cf326fa7..9816fbc0b581 100644 --- a/drivers/vulkan/vulkan_context.h +++ b/drivers/vulkan/vulkan_context.h @@ -40,6 +40,7 @@ #include "rendering_device_driver_vulkan.h" #include "servers/display_server.h" #include "servers/rendering/renderer_rd/api_context_rd.h" +#include #ifdef USE_VOLK #include @@ -133,6 +134,8 @@ class VulkanContext : public ApiContextRD { VkFormat format; VkSemaphore draw_complete_semaphores[FRAME_LAG]; VkSemaphore image_ownership_semaphores[FRAME_LAG]; + VkSemaphore compute_semaphore[1]; + uint64_t compute_semaphore_signal_value = 0; int frame_index = 0; VkFence fences[FRAME_LAG]; VkPhysicalDeviceMemoryProperties memory_properties; @@ -313,6 +316,7 @@ class VulkanContext : public ApiContextRD { virtual RID local_device_create() override final; virtual void local_device_push_command_buffers(RID p_local_device, const RDD::CommandBufferID *p_buffers, int p_count) override final; virtual void local_device_sync(RID p_local_device) override final; + virtual bool local_device_check_status(RID p_local_device) override final; virtual void local_device_free(RID p_local_device) override final; VkFormat get_screen_format() const; diff --git a/servers/rendering/renderer_rd/api_context_rd.h b/servers/rendering/renderer_rd/api_context_rd.h index fd3be8060529..67e15a888b25 100644 --- a/servers/rendering/renderer_rd/api_context_rd.h +++ b/servers/rendering/renderer_rd/api_context_rd.h @@ -54,6 +54,7 @@ class ApiContextRD { virtual RID local_device_create() = 0; virtual void local_device_push_command_buffers(RID p_local_device, const RDD::CommandBufferID *p_buffers, int p_count) = 0; virtual void local_device_sync(RID p_local_device) = 0; + virtual bool local_device_check_status(RID p_local_device) = 0; virtual void local_device_free(RID p_local_device) = 0; virtual void set_setup_buffer(RDD::CommandBufferID p_command_buffer) = 0; diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp index 0c95301402e4..744e2f3ca65e 100644 --- a/servers/rendering/rendering_device.cpp +++ b/servers/rendering/rendering_device.cpp @@ -29,6 +29,7 @@ /**************************************************************************/ #include "rendering_device.h" +#include "core/os/thread_safe.h" #include "rendering_device.compat.inc" #include "rendering_device_binds.h" @@ -4659,6 +4660,12 @@ void RenderingDevice::sync() { local_device_processing = false; } +bool RenderingDevice::check_status(){ + _THREAD_SAFE_METHOD_ + + return context->local_device_check_status(local_device); +} + void RenderingDevice::_free_pending_resources(int p_frame) { // Free in dependency usage order, so nothing weird happens. // Pipelines. @@ -5340,6 +5347,7 @@ void RenderingDevice::_bind_methods() { ClassDB::bind_method(D_METHOD("get_frame_delay"), &RenderingDevice::get_frame_delay); ClassDB::bind_method(D_METHOD("submit"), &RenderingDevice::submit); ClassDB::bind_method(D_METHOD("sync"), &RenderingDevice::sync); + ClassDB::bind_method(D_METHOD("check_status"), &RenderingDevice::check_status); #ifndef DISABLE_DEPRECATED ClassDB::bind_method(D_METHOD("barrier", "from", "to"), &RenderingDevice::barrier, DEFVAL(BARRIER_MASK_ALL_BARRIERS), DEFVAL(BARRIER_MASK_ALL_BARRIERS)); diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h index 2ccef6630833..db0d009ce195 100644 --- a/servers/rendering/rendering_device.h +++ b/servers/rendering/rendering_device.h @@ -1333,6 +1333,7 @@ class RenderingDevice : public RenderingDeviceCommons { void submit(); void sync(); + bool check_status(); enum MemoryType { MEMORY_TEXTURES,