mirror of
				https://git.zaroz.cloud/nintendo-back-up/yuzu/yuzu-mainline.git
				synced 2025-03-21 01:53:15 +00:00 
			
		
		
		
	vk_resource_manager: Implement VKResourceManager and fence allocator
CommitFence iterates a pool of fences until one is found. If all fences are being used at the same time, allocate more.
This commit is contained in:
		
							parent
							
								
									aa0b6babda
								
							
						
					
					
						commit
						0ffdd0a683
					
				| @ -4,12 +4,16 @@ | ||||
| 
 | ||||
| #include <algorithm> | ||||
| #include "common/assert.h" | ||||
| #include "common/logging/log.h" | ||||
| #include "video_core/renderer_vulkan/declarations.h" | ||||
| #include "video_core/renderer_vulkan/vk_device.h" | ||||
| #include "video_core/renderer_vulkan/vk_resource_manager.h" | ||||
| 
 | ||||
| namespace Vulkan { | ||||
| 
 | ||||
| // TODO(Rodrigo): Fine tune these numbers.
 | ||||
| constexpr std::size_t FENCES_GROW_STEP = 0x40; | ||||
| 
 | ||||
| VKResource::VKResource() = default; | ||||
| 
 | ||||
| VKResource::~VKResource() = default; | ||||
| @ -117,4 +121,62 @@ void VKFenceWatch::OnFenceRemoval(VKFence* signaling_fence) { | ||||
|     fence = nullptr; | ||||
| } | ||||
| 
 | ||||
| VKResourceManager::VKResourceManager(const VKDevice& device) : device{device} { | ||||
|     GrowFences(FENCES_GROW_STEP); | ||||
| } | ||||
| 
 | ||||
| VKResourceManager::~VKResourceManager() = default; | ||||
| 
 | ||||
| VKFence& VKResourceManager::CommitFence() { | ||||
|     const auto StepFences = [&](bool gpu_wait, bool owner_wait) -> VKFence* { | ||||
|         const auto Tick = [=](auto& fence) { return fence->Tick(gpu_wait, owner_wait); }; | ||||
|         const auto hinted = fences.begin() + fences_iterator; | ||||
| 
 | ||||
|         auto it = std::find_if(hinted, fences.end(), Tick); | ||||
|         if (it == fences.end()) { | ||||
|             it = std::find_if(fences.begin(), hinted, Tick); | ||||
|             if (it == hinted) { | ||||
|                 return nullptr; | ||||
|             } | ||||
|         } | ||||
|         fences_iterator = std::distance(fences.begin(), it) + 1; | ||||
|         if (fences_iterator >= fences.size()) | ||||
|             fences_iterator = 0; | ||||
| 
 | ||||
|         auto& fence = *it; | ||||
|         fence->Commit(); | ||||
|         return fence.get(); | ||||
|     }; | ||||
| 
 | ||||
|     VKFence* found_fence = StepFences(false, false); | ||||
|     if (!found_fence) { | ||||
|         // Try again, this time waiting.
 | ||||
|         found_fence = StepFences(true, false); | ||||
| 
 | ||||
|         if (!found_fence) { | ||||
|             // Allocate new fences and try again.
 | ||||
|             LOG_INFO(Render_Vulkan, "Allocating new fences {} -> {}", fences.size(), | ||||
|                      fences.size() + FENCES_GROW_STEP); | ||||
| 
 | ||||
|             GrowFences(FENCES_GROW_STEP); | ||||
|             found_fence = StepFences(true, false); | ||||
|             ASSERT(found_fence != nullptr); | ||||
|         } | ||||
|     } | ||||
|     return *found_fence; | ||||
| } | ||||
| 
 | ||||
| void VKResourceManager::GrowFences(std::size_t new_fences_count) { | ||||
|     const auto dev = device.GetLogical(); | ||||
|     const auto& dld = device.GetDispatchLoader(); | ||||
|     const vk::FenceCreateInfo fence_ci; | ||||
| 
 | ||||
|     const std::size_t previous_size = fences.size(); | ||||
|     fences.resize(previous_size + new_fences_count); | ||||
| 
 | ||||
|     std::generate(fences.begin() + previous_size, fences.end(), [&]() { | ||||
|         return std::make_unique<VKFence>(device, dev.createFenceUnique(fence_ci, nullptr, dld)); | ||||
|     }); | ||||
| } | ||||
| 
 | ||||
| } // namespace Vulkan
 | ||||
|  | ||||
| @ -4,6 +4,8 @@ | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <cstddef> | ||||
| #include <memory> | ||||
| #include <vector> | ||||
| #include "video_core/renderer_vulkan/declarations.h" | ||||
| 
 | ||||
| @ -116,4 +118,25 @@ private: | ||||
|     VKFence* fence{}; ///< Fence watching this resource. nullptr when the watch is free.
 | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  * The resource manager handles all resources that can be protected with a fence avoiding | ||||
|  * driver-side or GPU-side concurrent usage. Usage is documented in VKFence. | ||||
|  */ | ||||
| class VKResourceManager final { | ||||
| public: | ||||
|     explicit VKResourceManager(const VKDevice& device); | ||||
|     ~VKResourceManager(); | ||||
| 
 | ||||
|     /// Commits a fence. It has to be sent to a queue and released.
 | ||||
|     VKFence& CommitFence(); | ||||
| 
 | ||||
| private: | ||||
|     /// Allocates new fences.
 | ||||
|     void GrowFences(std::size_t new_fences_count); | ||||
| 
 | ||||
|     const VKDevice& device;          ///< Device handler.
 | ||||
|     std::size_t fences_iterator = 0; ///< Index where a free fence is likely to be found.
 | ||||
|     std::vector<std::unique_ptr<VKFence>> fences; ///< Pool of fences.
 | ||||
| }; | ||||
| 
 | ||||
| } // namespace Vulkan
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 ReinUsesLisp
						ReinUsesLisp