diff --git a/CMakeLists.txt b/CMakeLists.txt index ee719f6887..8effd233c8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -564,6 +564,8 @@ set(VIDEO_CORE src/video_core/amdgpu/liverpool.cpp src/video_core/renderer_vulkan/vk_master_semaphore.h src/video_core/renderer_vulkan/vk_pipeline_cache.cpp src/video_core/renderer_vulkan/vk_pipeline_cache.h + src/video_core/renderer_vulkan/vk_pipeline_common.cpp + src/video_core/renderer_vulkan/vk_pipeline_common.h src/video_core/renderer_vulkan/vk_platform.cpp src/video_core/renderer_vulkan/vk_platform.h src/video_core/renderer_vulkan/vk_rasterizer.cpp diff --git a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp index c6dfd68e7e..e06443ada1 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include + #include "common/alignment.h" #include "video_core/buffer_cache/buffer_cache.h" #include "video_core/renderer_vulkan/vk_compute_pipeline.h" @@ -15,7 +16,7 @@ ComputePipeline::ComputePipeline(const Instance& instance_, Scheduler& scheduler DescriptorHeap& desc_heap_, vk::PipelineCache pipeline_cache, u64 compute_key_, const Shader::Info& info_, vk::ShaderModule module) - : instance{instance_}, scheduler{scheduler_}, desc_heap{desc_heap_}, compute_key{compute_key_}, + : Pipeline{instance_, scheduler_, desc_heap_, pipeline_cache}, compute_key{compute_key_}, info{&info_} { const vk::PipelineShaderStageCreateInfo shader_ci = { .stage = vk::ShaderStageFlagBits::eCompute, @@ -213,32 +214,8 @@ bool ComputePipeline::BindResources(VideoCore::BufferCache& buffer_cache, }); } - for (const auto& image_desc : info->images) { - const auto tsharp = image_desc.GetSharp(*info); - if (tsharp.GetDataFmt() != AmdGpu::DataFormat::FormatInvalid) { - VideoCore::ImageInfo image_info{tsharp, image_desc.is_depth}; - VideoCore::ImageViewInfo view_info{tsharp, image_desc.is_storage}; - const auto& image_view = texture_cache.FindTexture(image_info, view_info); - const auto& image = texture_cache.GetImage(image_view.image_id); - image_infos.emplace_back(VK_NULL_HANDLE, *image_view.image_view, - image.last_state.layout); - } else { - image_infos.emplace_back(VK_NULL_HANDLE, VK_NULL_HANDLE, vk::ImageLayout::eGeneral); - } - set_writes.push_back({ - .dstSet = VK_NULL_HANDLE, - .dstBinding = binding++, - .dstArrayElement = 0, - .descriptorCount = 1, - .descriptorType = image_desc.is_storage ? vk::DescriptorType::eStorageImage - : vk::DescriptorType::eSampledImage, - .pImageInfo = &image_infos.back(), - }); + BindTextures(texture_cache, *info, binding, set_writes); - if (texture_cache.IsMeta(tsharp.Address())) { - LOG_WARNING(Render_Vulkan, "Unexpected metadata read by a CS shader (texture)"); - } - } for (const auto& sampler : info->samplers) { const auto ssharp = sampler.GetSharp(*info); if (ssharp.force_degamma) { diff --git a/src/video_core/renderer_vulkan/vk_compute_pipeline.h b/src/video_core/renderer_vulkan/vk_compute_pipeline.h index 8a6213a29c..f1bc7285a9 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pipeline.h +++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.h @@ -3,9 +3,8 @@ #pragma once -#include -#include "shader_recompiler/info.h" #include "video_core/renderer_vulkan/vk_common.h" +#include "video_core/renderer_vulkan/vk_pipeline_common.h" namespace VideoCore { class BufferCache; @@ -18,27 +17,17 @@ class Instance; class Scheduler; class DescriptorHeap; -class ComputePipeline { +class ComputePipeline : public Pipeline { public: - explicit ComputePipeline(const Instance& instance, Scheduler& scheduler, - DescriptorHeap& desc_heap, vk::PipelineCache pipeline_cache, - u64 compute_key, const Shader::Info& info, vk::ShaderModule module); + ComputePipeline(const Instance& instance, Scheduler& scheduler, DescriptorHeap& desc_heap, + vk::PipelineCache pipeline_cache, u64 compute_key, const Shader::Info& info, + vk::ShaderModule module); ~ComputePipeline(); - [[nodiscard]] vk::Pipeline Handle() const noexcept { - return *pipeline; - } - bool BindResources(VideoCore::BufferCache& buffer_cache, VideoCore::TextureCache& texture_cache) const; private: - const Instance& instance; - Scheduler& scheduler; - DescriptorHeap& desc_heap; - vk::UniquePipeline pipeline; - vk::UniquePipelineLayout pipeline_layout; - vk::UniqueDescriptorSetLayout desc_layout; u64 compute_key; const Shader::Info* info; bool uses_push_descriptors{}; diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index 3df222a69c..15d0b65fbd 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp @@ -21,7 +21,7 @@ GraphicsPipeline::GraphicsPipeline(const Instance& instance_, Scheduler& schedul vk::PipelineCache pipeline_cache, std::span infos, std::span modules) - : instance{instance_}, scheduler{scheduler_}, desc_heap{desc_heap_}, key{key_} { + : Pipeline{instance_, scheduler_, desc_heap_, pipeline_cache}, key{key_} { const vk::Device device = instance.GetDevice(); std::ranges::copy(infos, stages.begin()); BuildDescSetLayout(); @@ -450,41 +450,15 @@ void GraphicsPipeline::BindResources(const Liverpool::Regs& regs, }); } - boost::container::static_vector tsharps; - for (const auto& image_desc : stage->images) { - const auto tsharp = image_desc.GetSharp(*stage); - if (tsharp.GetDataFmt() != AmdGpu::DataFormat::FormatInvalid) { - tsharps.emplace_back(tsharp); - VideoCore::ImageInfo image_info{tsharp, image_desc.is_depth}; - VideoCore::ImageViewInfo view_info{tsharp, image_desc.is_storage}; - const auto& image_view = texture_cache.FindTexture(image_info, view_info); - const auto& image = texture_cache.GetImage(image_view.image_id); - image_infos.emplace_back(VK_NULL_HANDLE, *image_view.image_view, - image.last_state.layout); - } else { - image_infos.emplace_back(VK_NULL_HANDLE, VK_NULL_HANDLE, vk::ImageLayout::eGeneral); - } - set_writes.push_back({ - .dstSet = VK_NULL_HANDLE, - .dstBinding = binding++, - .dstArrayElement = 0, - .descriptorCount = 1, - .descriptorType = image_desc.is_storage ? vk::DescriptorType::eStorageImage - : vk::DescriptorType::eSampledImage, - .pImageInfo = &image_infos.back(), - }); + BindTextures(texture_cache, *stage, binding, set_writes); - if (texture_cache.IsMeta(tsharp.Address())) { - LOG_WARNING(Render_Vulkan, "Unexpected metadata read by a PS shader (texture)"); - } - } for (const auto& sampler : stage->samplers) { auto ssharp = sampler.GetSharp(*stage); if (ssharp.force_degamma) { LOG_WARNING(Render_Vulkan, "Texture requires gamma correction"); } if (sampler.disable_aniso) { - const auto& tsharp = tsharps[sampler.associated_image]; + const auto& tsharp = stage->images[sampler.associated_image].GetSharp(*stage); if (tsharp.base_level == 0 && tsharp.last_level == 0) { ssharp.max_aniso.Assign(AmdGpu::AnisoRatio::One); } diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h index 7778c41787..d349fd6f12 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h @@ -5,7 +5,7 @@ #include "common/types.h" #include "video_core/renderer_vulkan/liverpool_to_vk.h" #include "video_core/renderer_vulkan/vk_common.h" -#include "video_core/renderer_vulkan/vk_compute_pipeline.h" +#include "video_core/renderer_vulkan/vk_pipeline_common.h" namespace VideoCore { class BufferCache; @@ -57,26 +57,17 @@ struct GraphicsPipelineKey { } }; -class GraphicsPipeline { +class GraphicsPipeline : public Pipeline { public: - explicit GraphicsPipeline(const Instance& instance, Scheduler& scheduler, - DescriptorHeap& desc_heap, const GraphicsPipelineKey& key, - vk::PipelineCache pipeline_cache, - std::span stages, - std::span modules); + GraphicsPipeline(const Instance& instance, Scheduler& scheduler, DescriptorHeap& desc_heap, + const GraphicsPipelineKey& key, vk::PipelineCache pipeline_cache, + std::span stages, + std::span modules); ~GraphicsPipeline(); void BindResources(const Liverpool::Regs& regs, VideoCore::BufferCache& buffer_cache, VideoCore::TextureCache& texture_cache) const; - vk::Pipeline Handle() const noexcept { - return *pipeline; - } - - vk::PipelineLayout GetLayout() const { - return *pipeline_layout; - } - const Shader::Info& GetStage(Shader::Stage stage) const noexcept { return *stages[u32(stage)]; } @@ -98,12 +89,6 @@ class GraphicsPipeline { void BuildDescSetLayout(); private: - const Instance& instance; - Scheduler& scheduler; - DescriptorHeap& desc_heap; - vk::UniquePipeline pipeline; - vk::UniquePipelineLayout pipeline_layout; - vk::UniqueDescriptorSetLayout desc_layout; std::array stages{}; GraphicsPipelineKey key; bool uses_push_descriptors{}; diff --git a/src/video_core/renderer_vulkan/vk_pipeline_common.cpp b/src/video_core/renderer_vulkan/vk_pipeline_common.cpp new file mode 100644 index 0000000000..2a14c9bf58 --- /dev/null +++ b/src/video_core/renderer_vulkan/vk_pipeline_common.cpp @@ -0,0 +1,72 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include + +#include "video_core/renderer_vulkan/vk_instance.h" +#include "video_core/renderer_vulkan/vk_pipeline_common.h" +#include "video_core/renderer_vulkan/vk_scheduler.h" +#include "video_core/texture_cache/texture_cache.h" + +namespace Vulkan { + +Pipeline::Pipeline(const Instance& instance_, Scheduler& scheduler_, DescriptorHeap& desc_heap_, + vk::PipelineCache pipeline_cache) + : instance{instance_}, scheduler{scheduler_}, desc_heap{desc_heap_} {} + +Pipeline::~Pipeline() = default; + +void Pipeline::BindTextures(VideoCore::TextureCache& texture_cache, const Shader::Info& stage, + u32& binding, DescriptorWrites& set_writes) const { + static boost::container::static_vector image_infos; + image_infos.clear(); + + using ImageBindingInfo = std::tuple; + boost::container::static_vector image_bindings; + + for (const auto& image_desc : stage.images) { + const auto tsharp = image_desc.GetSharp(stage); + if (tsharp.GetDataFmt() != AmdGpu::DataFormat::FormatInvalid) { + VideoCore::ImageInfo image_info{tsharp, image_desc.is_depth}; + VideoCore::ImageViewInfo view_info{tsharp, image_desc.is_storage}; + auto& image_view = texture_cache.FindTexture(image_info, view_info); + auto& image = texture_cache.GetImage(image_view.image_id); + image.flags |= VideoCore::ImageFlagBits::Bound; + image_bindings.emplace_back(&image, &image_view, image_desc.is_storage); + } else { + image_bindings.emplace_back(nullptr, nullptr, image_desc.is_storage); + } + + if (texture_cache.IsMeta(tsharp.Address())) { + LOG_WARNING(Render_Vulkan, "Unexpected metadata read by a PS shader (texture)"); + } + } + + // Second pass to re-bind images that were updated after binding + for (auto& [image, image_view, is_storage] : image_bindings) { + if (!image || !image_view) { + image_infos.emplace_back(VK_NULL_HANDLE, VK_NULL_HANDLE, vk::ImageLayout::eGeneral); + } else { + vk::ImageLayout layout = image->last_state.layout; + if (True(image->flags & VideoCore::ImageFlagBits::NeedsRebind)) { + image_view = &texture_cache.FindTexture(image->info, image_view->info); + layout = texture_cache.GetImage(image_view->image_id).last_state.layout; + } + image_infos.emplace_back(VK_NULL_HANDLE, *image_view->image_view, layout); + image->flags &= + ~(VideoCore::ImageFlagBits::NeedsRebind | VideoCore::ImageFlagBits::Bound); + } + + set_writes.push_back({ + .dstSet = VK_NULL_HANDLE, + .dstBinding = binding++, + .dstArrayElement = 0, + .descriptorCount = 1, + .descriptorType = + is_storage ? vk::DescriptorType::eStorageImage : vk::DescriptorType::eSampledImage, + .pImageInfo = &image_infos.back(), + }); + } +} + +} // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/vk_pipeline_common.h b/src/video_core/renderer_vulkan/vk_pipeline_common.h new file mode 100644 index 0000000000..90fe3afceb --- /dev/null +++ b/src/video_core/renderer_vulkan/vk_pipeline_common.h @@ -0,0 +1,47 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "shader_recompiler/info.h" +#include "video_core/renderer_vulkan/vk_common.h" + +namespace VideoCore { +class BufferCache; +class TextureCache; +} // namespace VideoCore + +namespace Vulkan { + +class Instance; +class Scheduler; +class DescriptorHeap; + +class Pipeline { +public: + Pipeline(const Instance& instance, Scheduler& scheduler, DescriptorHeap& desc_heap, + vk::PipelineCache pipeline_cache); + virtual ~Pipeline(); + + vk::Pipeline Handle() const noexcept { + return *pipeline; + } + + vk::PipelineLayout GetLayout() const noexcept { + return *pipeline_layout; + } + + using DescriptorWrites = boost::container::small_vector; + void BindTextures(VideoCore::TextureCache& texture_cache, const Shader::Info& stage, + u32& binding, DescriptorWrites& set_writes) const; + +protected: + const Instance& instance; + Scheduler& scheduler; + DescriptorHeap& desc_heap; + vk::UniquePipeline pipeline; + vk::UniquePipelineLayout pipeline_layout; + vk::UniqueDescriptorSetLayout desc_layout; +}; + +} // namespace Vulkan diff --git a/src/video_core/texture_cache/image.h b/src/video_core/texture_cache/image.h index e644b81c06..acdd2e6322 100644 --- a/src/video_core/texture_cache/image.h +++ b/src/video_core/texture_cache/image.h @@ -32,6 +32,8 @@ enum ImageFlagBits : u32 { Registered = 1 << 6, ///< True when the image is registered Picked = 1 << 7, ///< Temporary flag to mark the image as picked MetaRegistered = 1 << 8, ///< True when metadata for this surface is known and registered + Bound = 1 << 9, ///< True when the image is bound to a descriptor set + NeedsRebind = 1 << 10, ///< True when the image needs to be rebound }; DECLARE_ENUM_FLAG_OPERATORS(ImageFlagBits) diff --git a/src/video_core/texture_cache/texture_cache.cpp b/src/video_core/texture_cache/texture_cache.cpp index 465975736b..97875f0ff6 100644 --- a/src/video_core/texture_cache/texture_cache.cpp +++ b/src/video_core/texture_cache/texture_cache.cpp @@ -173,6 +173,10 @@ ImageId TextureCache::ExpandImage(const ImageInfo& info, ImageId image_id) { src_image.Transit(vk::ImageLayout::eTransferSrcOptimal, vk::AccessFlagBits2::eTransferRead, {}); new_image.CopyImage(src_image); + if (True(src_image.flags & ImageFlagBits::Bound)) { + src_image.flags |= ImageFlagBits::NeedsRebind; + } + FreeImage(image_id); TrackImage(new_image_id);