Merge pull request #3276 from ReinUsesLisp/pipeline-reqs
vk_update_descriptor/vk_renderpass_cache: Add pipeline cache dependencies
This commit is contained in:
		| @@ -163,6 +163,8 @@ if (ENABLE_VULKAN) | |||||||
|         renderer_vulkan/vk_image.h |         renderer_vulkan/vk_image.h | ||||||
|         renderer_vulkan/vk_memory_manager.cpp |         renderer_vulkan/vk_memory_manager.cpp | ||||||
|         renderer_vulkan/vk_memory_manager.h |         renderer_vulkan/vk_memory_manager.h | ||||||
|  |         renderer_vulkan/vk_renderpass_cache.cpp | ||||||
|  |         renderer_vulkan/vk_renderpass_cache.h | ||||||
|         renderer_vulkan/vk_resource_manager.cpp |         renderer_vulkan/vk_resource_manager.cpp | ||||||
|         renderer_vulkan/vk_resource_manager.h |         renderer_vulkan/vk_resource_manager.h | ||||||
|         renderer_vulkan/vk_sampler_cache.cpp |         renderer_vulkan/vk_sampler_cache.cpp | ||||||
| @@ -176,7 +178,9 @@ if (ENABLE_VULKAN) | |||||||
|         renderer_vulkan/vk_stream_buffer.cpp |         renderer_vulkan/vk_stream_buffer.cpp | ||||||
|         renderer_vulkan/vk_stream_buffer.h |         renderer_vulkan/vk_stream_buffer.h | ||||||
|         renderer_vulkan/vk_swapchain.cpp |         renderer_vulkan/vk_swapchain.cpp | ||||||
|         renderer_vulkan/vk_swapchain.h) |         renderer_vulkan/vk_swapchain.h | ||||||
|  |         renderer_vulkan/vk_update_descriptor.cpp | ||||||
|  |         renderer_vulkan/vk_update_descriptor.h) | ||||||
|  |  | ||||||
|     target_include_directories(video_core PRIVATE sirit ../../externals/Vulkan-Headers/include) |     target_include_directories(video_core PRIVATE sirit ../../externals/Vulkan-Headers/include) | ||||||
|     target_compile_definitions(video_core PRIVATE HAS_VULKAN) |     target_compile_definitions(video_core PRIVATE HAS_VULKAN) | ||||||
|   | |||||||
							
								
								
									
										100
									
								
								src/video_core/renderer_vulkan/vk_renderpass_cache.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								src/video_core/renderer_vulkan/vk_renderpass_cache.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,100 @@ | |||||||
|  | // Copyright 2019 yuzu Emulator Project | ||||||
|  | // Licensed under GPLv2 or any later version | ||||||
|  | // Refer to the license.txt file included. | ||||||
|  |  | ||||||
|  | #include <memory> | ||||||
|  | #include <vector> | ||||||
|  |  | ||||||
|  | #include "video_core/engines/maxwell_3d.h" | ||||||
|  | #include "video_core/renderer_vulkan/declarations.h" | ||||||
|  | #include "video_core/renderer_vulkan/maxwell_to_vk.h" | ||||||
|  | #include "video_core/renderer_vulkan/vk_device.h" | ||||||
|  | #include "video_core/renderer_vulkan/vk_renderpass_cache.h" | ||||||
|  |  | ||||||
|  | namespace Vulkan { | ||||||
|  |  | ||||||
|  | VKRenderPassCache::VKRenderPassCache(const VKDevice& device) : device{device} {} | ||||||
|  |  | ||||||
|  | VKRenderPassCache::~VKRenderPassCache() = default; | ||||||
|  |  | ||||||
|  | vk::RenderPass VKRenderPassCache::GetRenderPass(const RenderPassParams& params) { | ||||||
|  |     const auto [pair, is_cache_miss] = cache.try_emplace(params); | ||||||
|  |     auto& entry = pair->second; | ||||||
|  |     if (is_cache_miss) { | ||||||
|  |         entry = CreateRenderPass(params); | ||||||
|  |     } | ||||||
|  |     return *entry; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | UniqueRenderPass VKRenderPassCache::CreateRenderPass(const RenderPassParams& params) const { | ||||||
|  |     std::vector<vk::AttachmentDescription> descriptors; | ||||||
|  |     std::vector<vk::AttachmentReference> color_references; | ||||||
|  |  | ||||||
|  |     for (std::size_t rt = 0; rt < params.color_attachments.size(); ++rt) { | ||||||
|  |         const auto attachment = params.color_attachments[rt]; | ||||||
|  |         const auto format = | ||||||
|  |             MaxwellToVK::SurfaceFormat(device, FormatType::Optimal, attachment.pixel_format); | ||||||
|  |         ASSERT_MSG(format.attachable, "Trying to attach a non-attachable format with format={}", | ||||||
|  |                    static_cast<u32>(attachment.pixel_format)); | ||||||
|  |  | ||||||
|  |         // TODO(Rodrigo): Add eMayAlias when it's needed. | ||||||
|  |         const auto color_layout = attachment.is_texception | ||||||
|  |                                       ? vk::ImageLayout::eGeneral | ||||||
|  |                                       : vk::ImageLayout::eColorAttachmentOptimal; | ||||||
|  |         descriptors.emplace_back(vk::AttachmentDescriptionFlagBits::eMayAlias, format.format, | ||||||
|  |                                  vk::SampleCountFlagBits::e1, vk::AttachmentLoadOp::eLoad, | ||||||
|  |                                  vk::AttachmentStoreOp::eStore, vk::AttachmentLoadOp::eDontCare, | ||||||
|  |                                  vk::AttachmentStoreOp::eDontCare, color_layout, color_layout); | ||||||
|  |         color_references.emplace_back(static_cast<u32>(rt), color_layout); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     vk::AttachmentReference zeta_attachment_ref; | ||||||
|  |     if (params.has_zeta) { | ||||||
|  |         const auto format = | ||||||
|  |             MaxwellToVK::SurfaceFormat(device, FormatType::Optimal, params.zeta_pixel_format); | ||||||
|  |         ASSERT_MSG(format.attachable, "Trying to attach a non-attachable format with format={}", | ||||||
|  |                    static_cast<u32>(params.zeta_pixel_format)); | ||||||
|  |  | ||||||
|  |         const auto zeta_layout = params.zeta_texception | ||||||
|  |                                      ? vk::ImageLayout::eGeneral | ||||||
|  |                                      : vk::ImageLayout::eDepthStencilAttachmentOptimal; | ||||||
|  |         descriptors.emplace_back(vk::AttachmentDescriptionFlags{}, format.format, | ||||||
|  |                                  vk::SampleCountFlagBits::e1, vk::AttachmentLoadOp::eLoad, | ||||||
|  |                                  vk::AttachmentStoreOp::eStore, vk::AttachmentLoadOp::eLoad, | ||||||
|  |                                  vk::AttachmentStoreOp::eStore, zeta_layout, zeta_layout); | ||||||
|  |         zeta_attachment_ref = | ||||||
|  |             vk::AttachmentReference(static_cast<u32>(params.color_attachments.size()), zeta_layout); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     const vk::SubpassDescription subpass_description( | ||||||
|  |         {}, vk::PipelineBindPoint::eGraphics, 0, nullptr, static_cast<u32>(color_references.size()), | ||||||
|  |         color_references.data(), nullptr, params.has_zeta ? &zeta_attachment_ref : nullptr, 0, | ||||||
|  |         nullptr); | ||||||
|  |  | ||||||
|  |     vk::AccessFlags access; | ||||||
|  |     vk::PipelineStageFlags stage; | ||||||
|  |     if (!color_references.empty()) { | ||||||
|  |         access |= | ||||||
|  |             vk::AccessFlagBits::eColorAttachmentRead | vk::AccessFlagBits::eColorAttachmentWrite; | ||||||
|  |         stage |= vk::PipelineStageFlagBits::eColorAttachmentOutput; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (params.has_zeta) { | ||||||
|  |         access |= vk::AccessFlagBits::eDepthStencilAttachmentRead | | ||||||
|  |                   vk::AccessFlagBits::eDepthStencilAttachmentWrite; | ||||||
|  |         stage |= vk::PipelineStageFlagBits::eLateFragmentTests; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     const vk::SubpassDependency subpass_dependency(VK_SUBPASS_EXTERNAL, 0, stage, stage, {}, access, | ||||||
|  |                                                    {}); | ||||||
|  |  | ||||||
|  |     const vk::RenderPassCreateInfo create_info({}, static_cast<u32>(descriptors.size()), | ||||||
|  |                                                descriptors.data(), 1, &subpass_description, 1, | ||||||
|  |                                                &subpass_dependency); | ||||||
|  |  | ||||||
|  |     const auto dev = device.GetLogical(); | ||||||
|  |     const auto& dld = device.GetDispatchLoader(); | ||||||
|  |     return dev.createRenderPassUnique(create_info, nullptr, dld); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | } // namespace Vulkan | ||||||
							
								
								
									
										97
									
								
								src/video_core/renderer_vulkan/vk_renderpass_cache.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								src/video_core/renderer_vulkan/vk_renderpass_cache.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,97 @@ | |||||||
|  | // Copyright 2019 yuzu Emulator Project | ||||||
|  | // Licensed under GPLv2 or any later version | ||||||
|  | // Refer to the license.txt file included. | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include <memory> | ||||||
|  | #include <tuple> | ||||||
|  | #include <unordered_map> | ||||||
|  |  | ||||||
|  | #include <boost/container/static_vector.hpp> | ||||||
|  | #include <boost/functional/hash.hpp> | ||||||
|  |  | ||||||
|  | #include "video_core/engines/maxwell_3d.h" | ||||||
|  | #include "video_core/renderer_vulkan/declarations.h" | ||||||
|  | #include "video_core/surface.h" | ||||||
|  |  | ||||||
|  | namespace Vulkan { | ||||||
|  |  | ||||||
|  | class VKDevice; | ||||||
|  |  | ||||||
|  | // TODO(Rodrigo): Optimize this structure for faster hashing | ||||||
|  |  | ||||||
|  | struct RenderPassParams { | ||||||
|  |     struct ColorAttachment { | ||||||
|  |         u32 index = 0; | ||||||
|  |         VideoCore::Surface::PixelFormat pixel_format = VideoCore::Surface::PixelFormat::Invalid; | ||||||
|  |         bool is_texception = false; | ||||||
|  |  | ||||||
|  |         std::size_t Hash() const noexcept { | ||||||
|  |             return static_cast<std::size_t>(pixel_format) | | ||||||
|  |                    static_cast<std::size_t>(is_texception) << 6 | | ||||||
|  |                    static_cast<std::size_t>(index) << 7; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         bool operator==(const ColorAttachment& rhs) const noexcept { | ||||||
|  |             return std::tie(index, pixel_format, is_texception) == | ||||||
|  |                    std::tie(rhs.index, rhs.pixel_format, rhs.is_texception); | ||||||
|  |         } | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     boost::container::static_vector<ColorAttachment, | ||||||
|  |                                     Tegra::Engines::Maxwell3D::Regs::NumRenderTargets> | ||||||
|  |         color_attachments{}; | ||||||
|  |     // TODO(Rodrigo): Unify has_zeta into zeta_pixel_format and zeta_component_type. | ||||||
|  |     VideoCore::Surface::PixelFormat zeta_pixel_format = VideoCore::Surface::PixelFormat::Invalid; | ||||||
|  |     bool has_zeta = false; | ||||||
|  |     bool zeta_texception = false; | ||||||
|  |  | ||||||
|  |     std::size_t Hash() const noexcept { | ||||||
|  |         std::size_t hash = 0; | ||||||
|  |         for (const auto& rt : color_attachments) { | ||||||
|  |             boost::hash_combine(hash, rt.Hash()); | ||||||
|  |         } | ||||||
|  |         boost::hash_combine(hash, zeta_pixel_format); | ||||||
|  |         boost::hash_combine(hash, has_zeta); | ||||||
|  |         boost::hash_combine(hash, zeta_texception); | ||||||
|  |         return hash; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool operator==(const RenderPassParams& rhs) const { | ||||||
|  |         return std::tie(color_attachments, zeta_pixel_format, has_zeta, zeta_texception) == | ||||||
|  |                std::tie(rhs.color_attachments, rhs.zeta_pixel_format, rhs.has_zeta, | ||||||
|  |                         rhs.zeta_texception); | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | } // namespace Vulkan | ||||||
|  |  | ||||||
|  | namespace std { | ||||||
|  |  | ||||||
|  | template <> | ||||||
|  | struct hash<Vulkan::RenderPassParams> { | ||||||
|  |     std::size_t operator()(const Vulkan::RenderPassParams& k) const noexcept { | ||||||
|  |         return k.Hash(); | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | } // namespace std | ||||||
|  |  | ||||||
|  | namespace Vulkan { | ||||||
|  |  | ||||||
|  | class VKRenderPassCache final { | ||||||
|  | public: | ||||||
|  |     explicit VKRenderPassCache(const VKDevice& device); | ||||||
|  |     ~VKRenderPassCache(); | ||||||
|  |  | ||||||
|  |     vk::RenderPass GetRenderPass(const RenderPassParams& params); | ||||||
|  |  | ||||||
|  | private: | ||||||
|  |     UniqueRenderPass CreateRenderPass(const RenderPassParams& params) const; | ||||||
|  |  | ||||||
|  |     const VKDevice& device; | ||||||
|  |     std::unordered_map<RenderPassParams, UniqueRenderPass> cache; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | } // namespace Vulkan | ||||||
							
								
								
									
										57
									
								
								src/video_core/renderer_vulkan/vk_update_descriptor.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								src/video_core/renderer_vulkan/vk_update_descriptor.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,57 @@ | |||||||
|  | // Copyright 2019 yuzu Emulator Project | ||||||
|  | // Licensed under GPLv2 or any later version | ||||||
|  | // Refer to the license.txt file included. | ||||||
|  |  | ||||||
|  | #include <variant> | ||||||
|  | #include <boost/container/static_vector.hpp> | ||||||
|  |  | ||||||
|  | #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_scheduler.h" | ||||||
|  | #include "video_core/renderer_vulkan/vk_update_descriptor.h" | ||||||
|  |  | ||||||
|  | namespace Vulkan { | ||||||
|  |  | ||||||
|  | VKUpdateDescriptorQueue::VKUpdateDescriptorQueue(const VKDevice& device, VKScheduler& scheduler) | ||||||
|  |     : device{device}, scheduler{scheduler} {} | ||||||
|  |  | ||||||
|  | VKUpdateDescriptorQueue::~VKUpdateDescriptorQueue() = default; | ||||||
|  |  | ||||||
|  | void VKUpdateDescriptorQueue::TickFrame() { | ||||||
|  |     payload.clear(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void VKUpdateDescriptorQueue::Acquire() { | ||||||
|  |     entries.clear(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void VKUpdateDescriptorQueue::Send(vk::DescriptorUpdateTemplate update_template, | ||||||
|  |                                    vk::DescriptorSet set) { | ||||||
|  |     if (payload.size() + entries.size() >= payload.max_size()) { | ||||||
|  |         LOG_WARNING(Render_Vulkan, "Payload overflow, waiting for worker thread"); | ||||||
|  |         scheduler.WaitWorker(); | ||||||
|  |         payload.clear(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     const auto payload_start = payload.data() + payload.size(); | ||||||
|  |     for (const auto& entry : entries) { | ||||||
|  |         if (const auto image = std::get_if<vk::DescriptorImageInfo>(&entry)) { | ||||||
|  |             payload.push_back(*image); | ||||||
|  |         } else if (const auto buffer = std::get_if<Buffer>(&entry)) { | ||||||
|  |             payload.emplace_back(*buffer->buffer, buffer->offset, buffer->size); | ||||||
|  |         } else if (const auto texel = std::get_if<vk::BufferView>(&entry)) { | ||||||
|  |             payload.push_back(*texel); | ||||||
|  |         } else { | ||||||
|  |             UNREACHABLE(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     scheduler.Record([dev = device.GetLogical(), payload_start, set, | ||||||
|  |                       update_template]([[maybe_unused]] auto cmdbuf, auto& dld) { | ||||||
|  |         dev.updateDescriptorSetWithTemplate(set, update_template, payload_start, dld); | ||||||
|  |     }); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | } // namespace Vulkan | ||||||
							
								
								
									
										86
									
								
								src/video_core/renderer_vulkan/vk_update_descriptor.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								src/video_core/renderer_vulkan/vk_update_descriptor.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,86 @@ | |||||||
|  | // Copyright 2019 yuzu Emulator Project | ||||||
|  | // Licensed under GPLv2 or any later version | ||||||
|  | // Refer to the license.txt file included. | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include <type_traits> | ||||||
|  | #include <variant> | ||||||
|  | #include <boost/container/static_vector.hpp> | ||||||
|  |  | ||||||
|  | #include "common/common_types.h" | ||||||
|  | #include "video_core/renderer_vulkan/declarations.h" | ||||||
|  |  | ||||||
|  | namespace Vulkan { | ||||||
|  |  | ||||||
|  | class VKDevice; | ||||||
|  | class VKScheduler; | ||||||
|  |  | ||||||
|  | class DescriptorUpdateEntry { | ||||||
|  | public: | ||||||
|  |     explicit DescriptorUpdateEntry() : image{} {} | ||||||
|  |  | ||||||
|  |     DescriptorUpdateEntry(vk::DescriptorImageInfo image) : image{image} {} | ||||||
|  |  | ||||||
|  |     DescriptorUpdateEntry(vk::Buffer buffer, vk::DeviceSize offset, vk::DeviceSize size) | ||||||
|  |         : buffer{buffer, offset, size} {} | ||||||
|  |  | ||||||
|  |     DescriptorUpdateEntry(vk::BufferView texel_buffer) : texel_buffer{texel_buffer} {} | ||||||
|  |  | ||||||
|  | private: | ||||||
|  |     union { | ||||||
|  |         vk::DescriptorImageInfo image; | ||||||
|  |         vk::DescriptorBufferInfo buffer; | ||||||
|  |         vk::BufferView texel_buffer; | ||||||
|  |     }; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | class VKUpdateDescriptorQueue final { | ||||||
|  | public: | ||||||
|  |     explicit VKUpdateDescriptorQueue(const VKDevice& device, VKScheduler& scheduler); | ||||||
|  |     ~VKUpdateDescriptorQueue(); | ||||||
|  |  | ||||||
|  |     void TickFrame(); | ||||||
|  |  | ||||||
|  |     void Acquire(); | ||||||
|  |  | ||||||
|  |     void Send(vk::DescriptorUpdateTemplate update_template, vk::DescriptorSet set); | ||||||
|  |  | ||||||
|  |     void AddSampledImage(vk::Sampler sampler, vk::ImageView image_view) { | ||||||
|  |         entries.emplace_back(vk::DescriptorImageInfo{sampler, image_view, {}}); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void AddImage(vk::ImageView image_view) { | ||||||
|  |         entries.emplace_back(vk::DescriptorImageInfo{{}, image_view, {}}); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void AddBuffer(const vk::Buffer* buffer, u64 offset, std::size_t size) { | ||||||
|  |         entries.push_back(Buffer{buffer, offset, size}); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void AddTexelBuffer(vk::BufferView texel_buffer) { | ||||||
|  |         entries.emplace_back(texel_buffer); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     vk::ImageLayout* GetLastImageLayout() { | ||||||
|  |         return &std::get<vk::DescriptorImageInfo>(entries.back()).imageLayout; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | private: | ||||||
|  |     struct Buffer { | ||||||
|  |         const vk::Buffer* buffer{}; | ||||||
|  |         u64 offset{}; | ||||||
|  |         std::size_t size{}; | ||||||
|  |     }; | ||||||
|  |     using Variant = std::variant<vk::DescriptorImageInfo, Buffer, vk::BufferView>; | ||||||
|  |     // Old gcc versions don't consider this trivially copyable. | ||||||
|  |     // static_assert(std::is_trivially_copyable_v<Variant>); | ||||||
|  |  | ||||||
|  |     const VKDevice& device; | ||||||
|  |     VKScheduler& scheduler; | ||||||
|  |  | ||||||
|  |     boost::container::static_vector<Variant, 0x400> entries; | ||||||
|  |     boost::container::static_vector<DescriptorUpdateEntry, 0x10000> payload; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | } // namespace Vulkan | ||||||
		Reference in New Issue
	
	Block a user