diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h index 4be81a79f28..ec439a129b0 100644 --- a/intern/ghost/GHOST_C-api.h +++ b/intern/ghost/GHOST_C-api.h @@ -1277,13 +1277,17 @@ int GHOST_XrGetControllerModelData(GHOST_XrContextHandle xr_context, * \param r_queue: After calling this function the VkQueue * referenced by this parameter will contain the VKQueue handle * of the context associated with the `context` parameter. + * \param r_queue_mutex: After calling this function the std::mutex referred + * by this parameter will contain the mutex of the context associated + * with the context parameter. */ void GHOST_GetVulkanHandles(GHOST_ContextHandle context, void *r_instance, void *r_physical_device, void *r_device, uint32_t *r_graphic_queue_family, - void *r_queue); + void *r_queue, + void **r_queue_mutex); /** * Set the pre and post callbacks for vulkan swap chain in the given context. diff --git a/intern/ghost/GHOST_IContext.hh b/intern/ghost/GHOST_IContext.hh index 17c47c3784d..8814a86e3d1 100644 --- a/intern/ghost/GHOST_IContext.hh +++ b/intern/ghost/GHOST_IContext.hh @@ -68,12 +68,16 @@ class GHOST_IContext { * \param r_queue: After calling this function the VkQueue * referenced by this parameter will contain the VKQueue handle * of the context associated with the `context` parameter. + * \param r_queue_mutex: After calling this function the std::mutex referred + * by this parameter will contain the mutex of the context associated + * with the context parameter. */ virtual GHOST_TSuccess getVulkanHandles(void *r_instance, void *r_physical_device, void *r_device, uint32_t *r_graphic_queue_family, - void *r_queue) = 0; + void *r_queue, + void **r_queue_mutex) = 0; /** * Acquire the current swap chain format. diff --git a/intern/ghost/intern/GHOST_C-api.cc b/intern/ghost/intern/GHOST_C-api.cc index 5fd0186f457..4337c94b35c 100644 --- a/intern/ghost/intern/GHOST_C-api.cc +++ b/intern/ghost/intern/GHOST_C-api.cc @@ -1256,11 +1256,12 @@ void GHOST_GetVulkanHandles(GHOST_ContextHandle contexthandle, void *r_physical_device, void *r_device, uint32_t *r_graphic_queue_family, - void *r_queue) + void *r_queue, + void **r_queue_mutex) { GHOST_IContext *context = (GHOST_IContext *)contexthandle; context->getVulkanHandles( - r_instance, r_physical_device, r_device, r_graphic_queue_family, r_queue); + r_instance, r_physical_device, r_device, r_graphic_queue_family, r_queue, r_queue_mutex); } void GHOST_SetVulkanSwapBuffersCallbacks( diff --git a/intern/ghost/intern/GHOST_Context.hh b/intern/ghost/intern/GHOST_Context.hh index 54374bea171..1a46fc14a81 100644 --- a/intern/ghost/intern/GHOST_Context.hh +++ b/intern/ghost/intern/GHOST_Context.hh @@ -154,6 +154,9 @@ class GHOST_Context : public GHOST_IContext { * \param r_queue: After calling this function the VkQueue * referenced by this parameter will contain the VKQueue handle * of the context associated with the `context` parameter. + * \param r_queue_mutex: After calling this function the std::mutex referred + * by this parameter will contain the mutex of the context associated + * with the context parameter. * \returns GHOST_kFailure when context isn't a Vulkan context. * GHOST_kSuccess when the context is a Vulkan context and the * handles have been set. @@ -162,7 +165,8 @@ class GHOST_Context : public GHOST_IContext { void * /*r_physical_device*/, void * /*r_device*/, uint32_t * /*r_graphic_queue_family*/, - void * /*r_queue*/) override + void * /*r_queue*/, + void ** /*r_queue_mutex*/) override { return GHOST_kFailure; }; diff --git a/intern/ghost/intern/GHOST_ContextVK.cc b/intern/ghost/intern/GHOST_ContextVK.cc index 46d41d30b0c..21b4c625994 100644 --- a/intern/ghost/intern/GHOST_ContextVK.cc +++ b/intern/ghost/intern/GHOST_ContextVK.cc @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -136,6 +137,9 @@ class GHOST_DeviceVK { int users = 0; + /** Mutex to externally synchronize access to queue. */ + std::mutex queue_mutex; + public: GHOST_DeviceVK(VkInstance vk_instance, VkPhysicalDevice vk_physical_device) : instance(vk_instance), physical_device(vk_physical_device) @@ -420,7 +424,7 @@ static GHOST_TSuccess ensure_vulkan_device(VkInstance vk_instance, return GHOST_kFailure; } - vulkan_device = std::make_optional(vk_instance, best_physical_device); + vulkan_device.emplace(vk_instance, best_physical_device); return GHOST_kSuccess; } @@ -564,7 +568,11 @@ GHOST_TSuccess GHOST_ContextVK::swapBuffers() present_info.pImageIndices = &s_currentImage; present_info.pResults = nullptr; - VkResult result = vkQueuePresentKHR(m_present_queue, &present_info); + VkResult result = VK_SUCCESS; + { + std::scoped_lock lock(vulkan_device->queue_mutex); + result = vkQueuePresentKHR(m_present_queue, &present_info); + } if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) { /* Swap-chain is out of date. Recreate swap-chain and skip this frame. */ destroySwapchain(); @@ -608,7 +616,8 @@ GHOST_TSuccess GHOST_ContextVK::getVulkanHandles(void *r_instance, void *r_physical_device, void *r_device, uint32_t *r_graphic_queue_family, - void *r_queue) + void *r_queue, + void **r_queue_mutex) { *((VkInstance *)r_instance) = VK_NULL_HANDLE; *((VkPhysicalDevice *)r_physical_device) = VK_NULL_HANDLE; @@ -619,6 +628,8 @@ GHOST_TSuccess GHOST_ContextVK::getVulkanHandles(void *r_instance, *((VkPhysicalDevice *)r_physical_device) = vulkan_device->physical_device; *((VkDevice *)r_device) = vulkan_device->device; *r_graphic_queue_family = vulkan_device->generic_queue_family; + std::mutex **queue_mutex = (std::mutex **)r_queue_mutex; + *queue_mutex = &vulkan_device->queue_mutex; } *((VkQueue *)r_queue) = m_graphic_queue; diff --git a/intern/ghost/intern/GHOST_ContextVK.hh b/intern/ghost/intern/GHOST_ContextVK.hh index c262c197219..26746eef2b7 100644 --- a/intern/ghost/intern/GHOST_ContextVK.hh +++ b/intern/ghost/intern/GHOST_ContextVK.hh @@ -127,7 +127,8 @@ class GHOST_ContextVK : public GHOST_Context { void *r_physical_device, void *r_device, uint32_t *r_graphic_queue_family, - void *r_queue) override; + void *r_queue, + void **r_queue_mutex) override; GHOST_TSuccess getVulkanSwapChainFormat(GHOST_VulkanSwapChainData *r_swap_chain_data) override; diff --git a/source/blender/gpu/vulkan/render_graph/vk_command_buffer_wrapper.cc b/source/blender/gpu/vulkan/render_graph/vk_command_buffer_wrapper.cc index e15cd65f0ce..175410c539a 100644 --- a/source/blender/gpu/vulkan/render_graph/vk_command_buffer_wrapper.cc +++ b/source/blender/gpu/vulkan/render_graph/vk_command_buffer_wrapper.cc @@ -94,7 +94,10 @@ void VKCommandBufferWrapper::submit_with_cpu_synchronization() { VKDevice &device = VKBackend::get().device; vkResetFences(device.vk_handle(), 1, &vk_fence_); - vkQueueSubmit(device.queue_get(), 1, &vk_submit_info_, vk_fence_); + { + std::scoped_lock lock(device.queue_mutex_get()); + vkQueueSubmit(device.queue_get(), 1, &vk_submit_info_, vk_fence_); + } } void VKCommandBufferWrapper::wait_for_cpu_synchronization() diff --git a/source/blender/gpu/vulkan/vk_device.cc b/source/blender/gpu/vulkan/vk_device.cc index 96501ea4298..cb576ba3172 100644 --- a/source/blender/gpu/vulkan/vk_device.cc +++ b/source/blender/gpu/vulkan/vk_device.cc @@ -75,12 +75,15 @@ bool VKDevice::is_initialized() const void VKDevice::init(void *ghost_context) { BLI_assert(!is_initialized()); + void *queue_mutex = nullptr; GHOST_GetVulkanHandles((GHOST_ContextHandle)ghost_context, &vk_instance_, &vk_physical_device_, &vk_device_, &vk_queue_family_, - &vk_queue_); + &vk_queue_, + &queue_mutex); + queue_mutex_ = static_cast(queue_mutex); init_physical_device_properties(); init_physical_device_memory_properties(); diff --git a/source/blender/gpu/vulkan/vk_device.hh b/source/blender/gpu/vulkan/vk_device.hh index f12709b8482..3280c162e73 100644 --- a/source/blender/gpu/vulkan/vk_device.hh +++ b/source/blender/gpu/vulkan/vk_device.hh @@ -134,6 +134,7 @@ class VKDevice : public NonCopyable { VkDevice vk_device_ = VK_NULL_HANDLE; uint32_t vk_queue_family_ = 0; VkQueue vk_queue_ = VK_NULL_HANDLE; + std::mutex *queue_mutex_ = nullptr; VKSamplers samplers_; VKDescriptorSetLayouts descriptor_set_layouts_; @@ -233,6 +234,10 @@ class VKDevice : public NonCopyable { { return vk_queue_; } + std::mutex &queue_mutex_get() + { + return *queue_mutex_; + } const uint32_t queue_family_get() const {