video_core: added rebinding of changed textures after overlap resolve

This commit is contained in:
psucien 2024-09-13 22:26:42 +02:00
parent 3d2ea32dae
commit e1a7c737d8
9 changed files with 150 additions and 100 deletions

View file

@ -579,6 +579,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

View file

@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include <boost/container/small_vector.hpp>
#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,36 +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 if (instance.IsNullDescriptorSupported()) {
image_infos.emplace_back(VK_NULL_HANDLE, VK_NULL_HANDLE, vk::ImageLayout::eGeneral);
} else {
auto& null_image = texture_cache.GetImageView(VideoCore::NULL_IMAGE_VIEW_ID);
image_infos.emplace_back(VK_NULL_HANDLE, *null_image.image_view,
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) {

View file

@ -3,9 +3,8 @@
#pragma once
#include <boost/container/small_vector.hpp>
#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{};

View file

@ -21,7 +21,7 @@ GraphicsPipeline::GraphicsPipeline(const Instance& instance_, Scheduler& schedul
vk::PipelineCache pipeline_cache,
std::span<const Shader::Info*, MaxShaderStages> infos,
std::span<const vk::ShaderModule> 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();
@ -444,45 +444,15 @@ void GraphicsPipeline::BindResources(const Liverpool::Regs& regs,
});
}
boost::container::static_vector<AmdGpu::Image, 32> 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 if (instance.IsNullDescriptorSupported()) {
image_infos.emplace_back(VK_NULL_HANDLE, VK_NULL_HANDLE, vk::ImageLayout::eGeneral);
} else {
auto& null_image = texture_cache.GetImageView(VideoCore::NULL_IMAGE_VIEW_ID);
image_infos.emplace_back(VK_NULL_HANDLE, *null_image.image_view,
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);
}

View file

@ -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;
@ -50,26 +50,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<const Shader::Info*, MaxShaderStages> stages,
std::span<const vk::ShaderModule> modules);
GraphicsPipeline(const Instance& instance, Scheduler& scheduler, DescriptorHeap& desc_heap,
const GraphicsPipelineKey& key, vk::PipelineCache pipeline_cache,
std::span<const Shader::Info*, MaxShaderStages> stages,
std::span<const vk::ShaderModule> 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)];
}
@ -91,12 +82,6 @@ private:
void BuildDescSetLayout();
private:
const Instance& instance;
Scheduler& scheduler;
DescriptorHeap& desc_heap;
vk::UniquePipeline pipeline;
vk::UniquePipelineLayout pipeline_layout;
vk::UniqueDescriptorSetLayout desc_layout;
std::array<const Shader::Info*, MaxShaderStages> stages{};
GraphicsPipelineKey key;
bool uses_push_descriptors{};

View file

@ -0,0 +1,78 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <boost/container/static_vector.hpp>
#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<vk::DescriptorImageInfo, 32> image_infos;
image_infos.clear();
using ImageBindingInfo = std::tuple<VideoCore::Image*, VideoCore::ImageView*, bool>;
boost::container::static_vector<ImageBindingInfo, 32> 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) {
if (instance.IsNullDescriptorSupported()) {
image_infos.emplace_back(VK_NULL_HANDLE, VK_NULL_HANDLE, vk::ImageLayout::eGeneral);
} else {
auto& null_image = texture_cache.GetImageView(VideoCore::NULL_IMAGE_VIEW_ID);
image_infos.emplace_back(VK_NULL_HANDLE, *null_image.image_view,
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

View file

@ -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<vk::WriteDescriptorSet, 16>;
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

View file

@ -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)

View file

@ -179,6 +179,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);