diff --git a/CMakeLists.txt b/CMakeLists.txt index af616d3e2a..af32e9ec3f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -712,6 +712,8 @@ add_library(Common STATIC Common/GPU/Vulkan/VulkanDebug.h Common/GPU/Vulkan/VulkanContext.cpp Common/GPU/Vulkan/VulkanContext.h + Common/GPU/Vulkan/VulkanDescSet.cpp + Common/GPU/Vulkan/VulkanDescSet.h Common/GPU/Vulkan/VulkanFramebuffer.cpp Common/GPU/Vulkan/VulkanFramebuffer.h Common/GPU/Vulkan/VulkanImage.cpp diff --git a/Common/Common.vcxproj b/Common/Common.vcxproj index e83ebfd5d3..93e91681b0 100644 --- a/Common/Common.vcxproj +++ b/Common/Common.vcxproj @@ -472,6 +472,7 @@ + @@ -900,6 +901,7 @@ + diff --git a/Common/Common.vcxproj.filters b/Common/Common.vcxproj.filters index a0852244ba..73aefb9323 100644 --- a/Common/Common.vcxproj.filters +++ b/Common/Common.vcxproj.filters @@ -515,6 +515,9 @@ Render\Text + + GPU\Vulkan + @@ -966,6 +969,9 @@ Render\Text + + GPU\Vulkan + diff --git a/Common/GPU/Vulkan/VulkanDescSet.cpp b/Common/GPU/Vulkan/VulkanDescSet.cpp new file mode 100644 index 0000000000..b4a654bb67 --- /dev/null +++ b/Common/GPU/Vulkan/VulkanDescSet.cpp @@ -0,0 +1,97 @@ +#include "Common/GPU/Vulkan/VulkanDescSet.h" + +VulkanDescSetPool::~VulkanDescSetPool() { + _assert_msg_(descPool_ == VK_NULL_HANDLE, "VulkanDescSetPool %s never destroyed", tag_); +} + +void VulkanDescSetPool::Create(VulkanContext *vulkan, const VkDescriptorPoolCreateInfo &info, const std::vector &sizes) { + _assert_msg_(descPool_ == VK_NULL_HANDLE, "VulkanDescSetPool::Create when already exists"); + + vulkan_ = vulkan; + info_ = info; + sizes_ = sizes; + + VkResult res = Recreate(false); + _assert_msg_(res == VK_SUCCESS, "Could not create VulkanDescSetPool %s", tag_); +} + +VkDescriptorSet VulkanDescSetPool::Allocate(int n, const VkDescriptorSetLayout *layouts, const char *tag) { + if (descPool_ == VK_NULL_HANDLE || usage_ + n >= info_.maxSets) { + // Missing or out of space, need to recreate. + VkResult res = Recreate(grow_); + _assert_msg_(res == VK_SUCCESS, "Could not grow VulkanDescSetPool %s on usage %d", tag_, (int)usage_); + } + + VkDescriptorSet desc; + VkDescriptorSetAllocateInfo descAlloc{ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO }; + descAlloc.descriptorPool = descPool_; + descAlloc.descriptorSetCount = n; + descAlloc.pSetLayouts = layouts; + VkResult result = vkAllocateDescriptorSets(vulkan_->GetDevice(), &descAlloc, &desc); + + if (result == VK_ERROR_FRAGMENTED_POOL || result < 0) { + // There seems to have been a spec revision. Here we should apparently recreate the descriptor pool, + // so let's do that. See https://www.khronos.org/registry/vulkan/specs/1.0/man/html/vkAllocateDescriptorSets.html + // Fragmentation shouldn't really happen though since we wipe the pool every frame. + VkResult res = Recreate(false); + _assert_msg_(res == VK_SUCCESS, "Ran out of descriptor space (frag?) and failed to recreate a descriptor pool. sz=%d res=%d", usage_, (int)res); + + // Need to update this pointer since we have allocated a new one. + descAlloc.descriptorPool = descPool_; + result = vkAllocateDescriptorSets(vulkan_->GetDevice(), &descAlloc, &desc); + _assert_msg_(result == VK_SUCCESS, "Ran out of descriptor space (frag?) and failed to allocate after recreating a descriptor pool. res=%d", (int)result); + } + + if (result != VK_SUCCESS) { + return VK_NULL_HANDLE; + } + + vulkan_->SetDebugName(desc, VK_OBJECT_TYPE_DESCRIPTOR_SET, tag); + return desc; +} + +void VulkanDescSetPool::Reset() { + _assert_msg_(descPool_ != VK_NULL_HANDLE, "VulkanDescSetPool::Reset without valid pool"); + vkResetDescriptorPool(vulkan_->GetDevice(), descPool_, 0); + + clear_(); + usage_ = 0; +} + +void VulkanDescSetPool::Destroy() { + _assert_msg_(vulkan_ != nullptr, "VulkanDescSetPool::Destroy without VulkanContext"); + + if (descPool_ != VK_NULL_HANDLE) { + vulkan_->Delete().QueueDeleteDescriptorPool(descPool_); + clear_(); + usage_ = 0; + } +} + +VkResult VulkanDescSetPool::Recreate(bool grow) { + _assert_msg_(vulkan_ != nullptr, "VulkanDescSetPool::Recreate without VulkanContext"); + + uint32_t prevSize = info_.maxSets; + if (grow) { + info_.maxSets *= 2; + for (auto &size : sizes_) + size.descriptorCount *= 2; + } + + // Delete the pool if it already exists. + if (descPool_ != VK_NULL_HANDLE) { + DEBUG_LOG(G3D, "Reallocating %s desc pool from %d to %d", tag_, prevSize, info_.maxSets); + vulkan_->Delete().QueueDeleteDescriptorPool(descPool_); + clear_(); + usage_ = 0; + } + + info_.pPoolSizes = &sizes_[0]; + info_.poolSizeCount = (uint32_t)sizes_.size(); + + VkResult result = vkCreateDescriptorPool(vulkan_->GetDevice(), &info_, nullptr, &descPool_); + if (result == VK_SUCCESS) { + vulkan_->SetDebugName(descPool_, VK_OBJECT_TYPE_DESCRIPTOR_POOL, tag_); + } + return result; +} diff --git a/Common/GPU/Vulkan/VulkanDescSet.h b/Common/GPU/Vulkan/VulkanDescSet.h new file mode 100644 index 0000000000..8c9ae70c39 --- /dev/null +++ b/Common/GPU/Vulkan/VulkanDescSet.h @@ -0,0 +1,37 @@ +#pragma once + +#include "Common/Data/Collections/FastVec.h" +#include "Common/GPU/Vulkan/VulkanContext.h" + +#include +#include + +// Only appropriate for use in a per-frame pool. +class VulkanDescSetPool { +public: + VulkanDescSetPool(const char *tag, bool grow) : tag_(tag), grow_(grow) {} + ~VulkanDescSetPool(); + + // Must call this before use: defines how to clear cache of ANY returned values from Allocate(). + void Setup(const std::function &clear) { + clear_ = clear; + } + void Create(VulkanContext *vulkan, const VkDescriptorPoolCreateInfo &info, const std::vector &sizes); + // Allocate a new set, which may resize and empty the current sets. + // Use only for the current frame, unless in a cache cleared by clear_. + VkDescriptorSet Allocate(int n, const VkDescriptorSetLayout *layouts, const char *tag); + void Reset(); + void Destroy(); + +private: + VkResult Recreate(bool grow); + + const char *tag_; + VulkanContext *vulkan_ = nullptr; + VkDescriptorPool descPool_ = VK_NULL_HANDLE; + VkDescriptorPoolCreateInfo info_{}; + std::vector sizes_; + std::function clear_; + uint32_t usage_ = 0; + bool grow_; +}; diff --git a/Common/GPU/Vulkan/VulkanMemory.cpp b/Common/GPU/Vulkan/VulkanMemory.cpp index f29fc33d0b..7f11aabccd 100644 --- a/Common/GPU/Vulkan/VulkanMemory.cpp +++ b/Common/GPU/Vulkan/VulkanMemory.cpp @@ -156,102 +156,6 @@ void VulkanPushBuffer::Unmap() { writePtr_ = nullptr; } -VulkanDescSetPool::~VulkanDescSetPool() { - _assert_msg_(descPool_ == VK_NULL_HANDLE, "VulkanDescSetPool %s never destroyed", tag_); -} - -void VulkanDescSetPool::Create(VulkanContext *vulkan, const VkDescriptorPoolCreateInfo &info, const std::vector &sizes) { - _assert_msg_(descPool_ == VK_NULL_HANDLE, "VulkanDescSetPool::Create when already exists"); - - vulkan_ = vulkan; - info_ = info; - sizes_ = sizes; - - VkResult res = Recreate(false); - _assert_msg_(res == VK_SUCCESS, "Could not create VulkanDescSetPool %s", tag_); -} - -VkDescriptorSet VulkanDescSetPool::Allocate(int n, const VkDescriptorSetLayout *layouts, const char *tag) { - if (descPool_ == VK_NULL_HANDLE || usage_ + n >= info_.maxSets) { - // Missing or out of space, need to recreate. - VkResult res = Recreate(grow_); - _assert_msg_(res == VK_SUCCESS, "Could not grow VulkanDescSetPool %s on usage %d", tag_, (int)usage_); - } - - VkDescriptorSet desc; - VkDescriptorSetAllocateInfo descAlloc{ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO }; - descAlloc.descriptorPool = descPool_; - descAlloc.descriptorSetCount = n; - descAlloc.pSetLayouts = layouts; - VkResult result = vkAllocateDescriptorSets(vulkan_->GetDevice(), &descAlloc, &desc); - - if (result == VK_ERROR_FRAGMENTED_POOL || result < 0) { - // There seems to have been a spec revision. Here we should apparently recreate the descriptor pool, - // so let's do that. See https://www.khronos.org/registry/vulkan/specs/1.0/man/html/vkAllocateDescriptorSets.html - // Fragmentation shouldn't really happen though since we wipe the pool every frame. - VkResult res = Recreate(false); - _assert_msg_(res == VK_SUCCESS, "Ran out of descriptor space (frag?) and failed to recreate a descriptor pool. sz=%d res=%d", usage_, (int)res); - - // Need to update this pointer since we have allocated a new one. - descAlloc.descriptorPool = descPool_; - result = vkAllocateDescriptorSets(vulkan_->GetDevice(), &descAlloc, &desc); - _assert_msg_(result == VK_SUCCESS, "Ran out of descriptor space (frag?) and failed to allocate after recreating a descriptor pool. res=%d", (int)result); - } - - if (result != VK_SUCCESS) { - return VK_NULL_HANDLE; - } - - vulkan_->SetDebugName(desc, VK_OBJECT_TYPE_DESCRIPTOR_SET, tag); - return desc; -} - -void VulkanDescSetPool::Reset() { - _assert_msg_(descPool_ != VK_NULL_HANDLE, "VulkanDescSetPool::Reset without valid pool"); - vkResetDescriptorPool(vulkan_->GetDevice(), descPool_, 0); - - clear_(); - usage_ = 0; -} - -void VulkanDescSetPool::Destroy() { - _assert_msg_(vulkan_ != nullptr, "VulkanDescSetPool::Destroy without VulkanContext"); - - if (descPool_ != VK_NULL_HANDLE) { - vulkan_->Delete().QueueDeleteDescriptorPool(descPool_); - clear_(); - usage_ = 0; - } -} - -VkResult VulkanDescSetPool::Recreate(bool grow) { - _assert_msg_(vulkan_ != nullptr, "VulkanDescSetPool::Recreate without VulkanContext"); - - uint32_t prevSize = info_.maxSets; - if (grow) { - info_.maxSets *= 2; - for (auto &size : sizes_) - size.descriptorCount *= 2; - } - - // Delete the pool if it already exists. - if (descPool_ != VK_NULL_HANDLE) { - DEBUG_LOG(G3D, "Reallocating %s desc pool from %d to %d", tag_, prevSize, info_.maxSets); - vulkan_->Delete().QueueDeleteDescriptorPool(descPool_); - clear_(); - usage_ = 0; - } - - info_.pPoolSizes = &sizes_[0]; - info_.poolSizeCount = (uint32_t)sizes_.size(); - - VkResult result = vkCreateDescriptorPool(vulkan_->GetDevice(), &info_, nullptr, &descPool_); - if (result == VK_SUCCESS) { - vulkan_->SetDebugName(descPool_, VK_OBJECT_TYPE_DESCRIPTOR_POOL, tag_); - } - return result; -} - VulkanPushPool::VulkanPushPool(VulkanContext *vulkan, const char *name, size_t originalBlockSize, VkBufferUsageFlags usage) : vulkan_(vulkan), name_(name), originalBlockSize_(originalBlockSize), usage_(usage) { RegisterGPUMemoryManager(this); diff --git a/Common/GPU/Vulkan/VulkanMemory.h b/Common/GPU/Vulkan/VulkanMemory.h index f218de3605..fc8f9a19fe 100644 --- a/Common/GPU/Vulkan/VulkanMemory.h +++ b/Common/GPU/Vulkan/VulkanMemory.h @@ -176,33 +176,3 @@ private: int curBlockIndex_ = -1; const char *name_; }; - -// Only appropriate for use in a per-frame pool. -class VulkanDescSetPool { -public: - VulkanDescSetPool(const char *tag, bool grow) : tag_(tag), grow_(grow) {} - ~VulkanDescSetPool(); - - // Must call this before use: defines how to clear cache of ANY returned values from Allocate(). - void Setup(const std::function &clear) { - clear_ = clear; - } - void Create(VulkanContext *vulkan, const VkDescriptorPoolCreateInfo &info, const std::vector &sizes); - // Allocate a new set, which may resize and empty the current sets. - // Use only for the current frame, unless in a cache cleared by clear_. - VkDescriptorSet Allocate(int n, const VkDescriptorSetLayout *layouts, const char *tag); - void Reset(); - void Destroy(); - -private: - VkResult Recreate(bool grow); - - const char *tag_; - VulkanContext *vulkan_ = nullptr; - VkDescriptorPool descPool_ = VK_NULL_HANDLE; - VkDescriptorPoolCreateInfo info_{}; - std::vector sizes_; - std::function clear_; - uint32_t usage_ = 0; - bool grow_; -}; diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index c5b4d87876..a4cdeedf8d 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -20,20 +20,19 @@ #include #include +#include "Common/Log.h" +#include "Common/StringUtils.h" #include "Common/System/Display.h" #include "Common/Math/lin/matrix4x4.h" #include "Common/Data/Convert/SmallDataConvert.h" #include "Common/GPU/thin3d.h" #include "Common/GPU/Vulkan/VulkanRenderManager.h" - -#include "Common/Log.h" -#include "Common/StringUtils.h" +#include "Common/GPU/Vulkan/VulkanDescSet.h" #include "Common/GPU/Vulkan/VulkanContext.h" #include "Common/GPU/Vulkan/VulkanImage.h" #include "Common/GPU/Vulkan/VulkanMemory.h" -#include "Common/Thread/Promise.h" - #include "Common/GPU/Vulkan/VulkanLoader.h" +#include "Common/Thread/Promise.h" // We support a frame-global descriptor set, which can be optionally used by other code, // but is not directly used by thin3d. It has to be defined here though, be in set 0 diff --git a/GPU/Vulkan/DrawEngineVulkan.h b/GPU/Vulkan/DrawEngineVulkan.h index ae6124a04c..e98489c7a5 100644 --- a/GPU/Vulkan/DrawEngineVulkan.h +++ b/GPU/Vulkan/DrawEngineVulkan.h @@ -32,7 +32,6 @@ // won't get any bone data, etc. #include "Common/Data/Collections/Hashmaps.h" -#include "Common/GPU/Vulkan/VulkanMemory.h" #include "GPU/Vulkan/VulkanUtil.h" diff --git a/GPU/Vulkan/VulkanUtil.h b/GPU/Vulkan/VulkanUtil.h index 68ff50b68b..f45c816b12 100644 --- a/GPU/Vulkan/VulkanUtil.h +++ b/GPU/Vulkan/VulkanUtil.h @@ -24,7 +24,7 @@ #include "Common/GPU/Vulkan/VulkanContext.h" #include "Common/GPU/Vulkan/VulkanImage.h" #include "Common/GPU/Vulkan/VulkanLoader.h" -#include "Common/GPU/Vulkan/VulkanMemory.h" +#include "Common/GPU/Vulkan/VulkanDescSet.h" #include "Common/GPU/thin3d.h" extern const VkComponentMapping VULKAN_4444_SWIZZLE; diff --git a/android/jni/Android.mk b/android/jni/Android.mk index c70bba4eb4..52698f05a1 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -95,6 +95,7 @@ VULKAN_FILES := \ $(SRC)/Common/GPU/Vulkan/VulkanImage.cpp \ $(SRC)/Common/GPU/Vulkan/VulkanFramebuffer.cpp \ $(SRC)/Common/GPU/Vulkan/VulkanMemory.cpp \ + $(SRC)/Common/GPU/Vulkan/VulkanDescSet.cpp \ $(SRC)/Common/GPU/Vulkan/VulkanProfiler.cpp \ $(SRC)/Common/GPU/Vulkan/VulkanBarrier.cpp diff --git a/libretro/Makefile.common b/libretro/Makefile.common index e8c6ed2d41..a216b5cf97 100644 --- a/libretro/Makefile.common +++ b/libretro/Makefile.common @@ -369,6 +369,7 @@ SOURCES_CXX += \ $(COMMONDIR)/GPU/Vulkan/VulkanImage.cpp \ $(COMMONDIR)/GPU/Vulkan/VulkanFramebuffer.cpp \ $(COMMONDIR)/GPU/Vulkan/VulkanMemory.cpp \ + $(COMMONDIR)/GPU/Vulkan/VulkanDescSet.cpp \ $(COMMONDIR)/GPU/Vulkan/VulkanProfiler.cpp \ $(COMMONDIR)/GPU/Vulkan/VulkanBarrier.cpp \ $(COMMONDIR)/Input/GestureDetector.cpp \