mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-06-09 20:23:14 +00:00
Image subresources barriers (#904)
* video_core: texture: image subresources state tracking * shader_recompiler: use one binding if the same image is read and written * video_core: added rebinding of changed textures after overlap resolve * don't use pointers; slight `FindTexture` refactoring * video_core: buffer_cache: don't copy over the image size * redundant barriers removed; fixes * regression fixes * texture_cache: 3d texture layers count fixup * shader_recompiler: support for partially bound cubemaps * added support for cubemap arrays * don't bind unused color buffers * fixed depth promotion to do not use stencil * doors * bonfire lit * cubemap array index calculation * final touches
This commit is contained in:
parent
913a46173a
commit
5f4ddc14fc
35 changed files with 495 additions and 283 deletions
|
@ -2,6 +2,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#define VULKAN_HPP_NO_EXCEPTIONS
|
||||
#include <ranges>
|
||||
#include "common/assert.h"
|
||||
#include "video_core/renderer_vulkan/liverpool_to_vk.h"
|
||||
#include "video_core/renderer_vulkan/vk_instance.h"
|
||||
|
@ -124,7 +125,7 @@ Image::Image(const Vulkan::Instance& instance_, Vulkan::Scheduler& scheduler_,
|
|||
// the texture cache should re-create the resource with the usage requested
|
||||
vk::ImageCreateFlags flags{vk::ImageCreateFlagBits::eMutableFormat |
|
||||
vk::ImageCreateFlagBits::eExtendedUsage};
|
||||
if (info.props.is_cube) {
|
||||
if (info.props.is_cube || (info.type == vk::ImageType::e2D && info.resources.layers >= 6)) {
|
||||
flags |= vk::ImageCreateFlagBits::eCubeCompatible;
|
||||
} else if (info.props.is_volume) {
|
||||
flags |= vk::ImageCreateFlagBits::e2DArrayCompatible;
|
||||
|
@ -179,52 +180,132 @@ Image::Image(const Vulkan::Instance& instance_, Vulkan::Scheduler& scheduler_,
|
|||
info.guest_size_bytes);
|
||||
}
|
||||
|
||||
void Image::Transit(vk::ImageLayout dst_layout, vk::Flags<vk::AccessFlagBits> dst_mask,
|
||||
vk::CommandBuffer cmdbuf) {
|
||||
if (dst_layout == layout && dst_mask == access_mask) {
|
||||
return;
|
||||
boost::container::small_vector<vk::ImageMemoryBarrier2, 32> Image::GetBarriers(
|
||||
vk::ImageLayout dst_layout, vk::Flags<vk::AccessFlagBits2> dst_mask,
|
||||
vk::PipelineStageFlags2 dst_stage, std::optional<SubresourceRange> subres_range) {
|
||||
const bool needs_partial_transition =
|
||||
subres_range &&
|
||||
(subres_range->base != SubresourceBase{} || subres_range->extent != info.resources);
|
||||
const bool partially_transited = !subresource_states.empty();
|
||||
|
||||
boost::container::small_vector<vk::ImageMemoryBarrier2, 32> barriers{};
|
||||
if (needs_partial_transition || partially_transited) {
|
||||
if (!partially_transited) {
|
||||
subresource_states.resize(info.resources.levels * info.resources.layers);
|
||||
std::fill(subresource_states.begin(), subresource_states.end(), last_state);
|
||||
}
|
||||
|
||||
// In case of partial transition, we need to change the specified subresources only.
|
||||
// Otherwise all subresources need to be set to the same state so we can use a full
|
||||
// resource transition for the next time.
|
||||
const auto mips =
|
||||
needs_partial_transition
|
||||
? std::ranges::views::iota(subres_range->base.level,
|
||||
subres_range->base.level + subres_range->extent.levels)
|
||||
: std::views::iota(0u, info.resources.levels);
|
||||
const auto layers =
|
||||
needs_partial_transition
|
||||
? std::ranges::views::iota(subres_range->base.layer,
|
||||
subres_range->base.layer + subres_range->extent.layers)
|
||||
: std::views::iota(0u, info.resources.layers);
|
||||
|
||||
for (u32 mip : mips) {
|
||||
for (u32 layer : layers) {
|
||||
// NOTE: these loops may produce a lot of small barriers.
|
||||
// If this becomes a problem, we can optimize it by merging adjacent barriers.
|
||||
const auto subres_idx = mip * info.resources.layers + layer;
|
||||
ASSERT(subres_idx < subresource_states.size());
|
||||
auto& state = subresource_states[subres_idx];
|
||||
|
||||
if (state.layout != dst_layout || state.access_mask != dst_mask) {
|
||||
barriers.emplace_back(vk::ImageMemoryBarrier2{
|
||||
.srcStageMask = state.pl_stage,
|
||||
.srcAccessMask = state.access_mask,
|
||||
.dstStageMask = dst_stage,
|
||||
.dstAccessMask = dst_mask,
|
||||
.oldLayout = state.layout,
|
||||
.newLayout = dst_layout,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.image = image,
|
||||
.subresourceRange{
|
||||
.aspectMask = aspect_mask,
|
||||
.baseMipLevel = mip,
|
||||
.levelCount = 1,
|
||||
.baseArrayLayer = layer,
|
||||
.layerCount = 1,
|
||||
},
|
||||
});
|
||||
state.layout = dst_layout;
|
||||
state.access_mask = dst_mask;
|
||||
state.pl_stage = dst_stage;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!needs_partial_transition) {
|
||||
subresource_states.clear();
|
||||
}
|
||||
} else { // Full resource transition
|
||||
if (last_state.layout == dst_layout && last_state.access_mask == dst_mask) {
|
||||
return {};
|
||||
}
|
||||
|
||||
barriers.emplace_back(vk::ImageMemoryBarrier2{
|
||||
.srcStageMask = last_state.pl_stage,
|
||||
.srcAccessMask = last_state.access_mask,
|
||||
.dstStageMask = dst_stage,
|
||||
.dstAccessMask = dst_mask,
|
||||
.oldLayout = last_state.layout,
|
||||
.newLayout = dst_layout,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.image = image,
|
||||
.subresourceRange{
|
||||
.aspectMask = aspect_mask,
|
||||
.baseMipLevel = 0,
|
||||
.levelCount = VK_REMAINING_MIP_LEVELS,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = VK_REMAINING_ARRAY_LAYERS,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const vk::ImageMemoryBarrier barrier = {
|
||||
.srcAccessMask = access_mask,
|
||||
.dstAccessMask = dst_mask,
|
||||
.oldLayout = layout,
|
||||
.newLayout = dst_layout,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.image = image,
|
||||
.subresourceRange{
|
||||
.aspectMask = aspect_mask,
|
||||
.baseMipLevel = 0,
|
||||
.levelCount = VK_REMAINING_MIP_LEVELS,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = VK_REMAINING_ARRAY_LAYERS,
|
||||
},
|
||||
};
|
||||
last_state.layout = dst_layout;
|
||||
last_state.access_mask = dst_mask;
|
||||
last_state.pl_stage = dst_stage;
|
||||
|
||||
return barriers;
|
||||
}
|
||||
|
||||
void Image::Transit(vk::ImageLayout dst_layout, vk::Flags<vk::AccessFlagBits2> dst_mask,
|
||||
std::optional<SubresourceRange> range, vk::CommandBuffer cmdbuf /*= {}*/) {
|
||||
// Adjust pipieline stage
|
||||
const vk::PipelineStageFlags dst_pl_stage =
|
||||
(dst_mask == vk::AccessFlagBits::eTransferRead ||
|
||||
dst_mask == vk::AccessFlagBits::eTransferWrite)
|
||||
? vk::PipelineStageFlagBits::eTransfer
|
||||
: vk::PipelineStageFlagBits::eAllGraphics | vk::PipelineStageFlagBits::eComputeShader;
|
||||
const vk::PipelineStageFlags2 dst_pl_stage =
|
||||
(dst_mask == vk::AccessFlagBits2::eTransferRead ||
|
||||
dst_mask == vk::AccessFlagBits2::eTransferWrite)
|
||||
? vk::PipelineStageFlagBits2::eTransfer
|
||||
: vk::PipelineStageFlagBits2::eAllGraphics | vk::PipelineStageFlagBits2::eComputeShader;
|
||||
|
||||
const auto barriers = GetBarriers(dst_layout, dst_mask, dst_pl_stage, range);
|
||||
if (barriers.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!cmdbuf) {
|
||||
// When using external cmdbuf you are responsible for ending rp.
|
||||
scheduler->EndRendering();
|
||||
cmdbuf = scheduler->CommandBuffer();
|
||||
}
|
||||
cmdbuf.pipelineBarrier(pl_stage, dst_pl_stage, vk::DependencyFlagBits::eByRegion, {}, {},
|
||||
barrier);
|
||||
|
||||
layout = dst_layout;
|
||||
access_mask = dst_mask;
|
||||
pl_stage = dst_pl_stage;
|
||||
cmdbuf.pipelineBarrier2(vk::DependencyInfo{
|
||||
.imageMemoryBarrierCount = static_cast<u32>(barriers.size()),
|
||||
.pImageMemoryBarriers = barriers.data(),
|
||||
});
|
||||
}
|
||||
|
||||
void Image::Upload(vk::Buffer buffer, u64 offset) {
|
||||
scheduler->EndRendering();
|
||||
Transit(vk::ImageLayout::eTransferDstOptimal, vk::AccessFlagBits::eTransferWrite);
|
||||
Transit(vk::ImageLayout::eTransferDstOptimal, vk::AccessFlagBits2::eTransferWrite, {});
|
||||
|
||||
// Copy to the image.
|
||||
const auto aspect = aspect_mask & vk::ImageAspectFlagBits::eStencil
|
||||
|
@ -248,12 +329,12 @@ void Image::Upload(vk::Buffer buffer, u64 offset) {
|
|||
cmdbuf.copyBufferToImage(buffer, image, vk::ImageLayout::eTransferDstOptimal, image_copy);
|
||||
|
||||
Transit(vk::ImageLayout::eGeneral,
|
||||
vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eTransferRead);
|
||||
vk::AccessFlagBits2::eShaderRead | vk::AccessFlagBits2::eTransferRead, {});
|
||||
}
|
||||
|
||||
void Image::CopyImage(const Image& image) {
|
||||
scheduler->EndRendering();
|
||||
Transit(vk::ImageLayout::eTransferDstOptimal, vk::AccessFlagBits::eTransferWrite);
|
||||
Transit(vk::ImageLayout::eTransferDstOptimal, vk::AccessFlagBits2::eTransferWrite, {});
|
||||
|
||||
auto cmdbuf = scheduler->CommandBuffer();
|
||||
|
||||
|
@ -279,15 +360,16 @@ void Image::CopyImage(const Image& image) {
|
|||
.extent = {mip_w, mip_h, mip_d},
|
||||
});
|
||||
}
|
||||
cmdbuf.copyImage(image.image, image.layout, this->image, this->layout, image_copy);
|
||||
cmdbuf.copyImage(image.image, image.last_state.layout, this->image, this->last_state.layout,
|
||||
image_copy);
|
||||
|
||||
Transit(vk::ImageLayout::eGeneral,
|
||||
vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eTransferRead);
|
||||
vk::AccessFlagBits2::eShaderRead | vk::AccessFlagBits2::eTransferRead, {});
|
||||
}
|
||||
|
||||
void Image::CopyMip(const Image& image, u32 mip) {
|
||||
scheduler->EndRendering();
|
||||
Transit(vk::ImageLayout::eTransferDstOptimal, vk::AccessFlagBits::eTransferWrite);
|
||||
Transit(vk::ImageLayout::eTransferDstOptimal, vk::AccessFlagBits2::eTransferWrite, {});
|
||||
|
||||
auto cmdbuf = scheduler->CommandBuffer();
|
||||
|
||||
|
@ -313,10 +395,11 @@ void Image::CopyMip(const Image& image, u32 mip) {
|
|||
},
|
||||
.extent = {mip_w, mip_h, mip_d},
|
||||
};
|
||||
cmdbuf.copyImage(image.image, image.layout, this->image, this->layout, image_copy);
|
||||
cmdbuf.copyImage(image.image, image.last_state.layout, this->image, this->last_state.layout,
|
||||
image_copy);
|
||||
|
||||
Transit(vk::ImageLayout::eGeneral,
|
||||
vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eTransferRead);
|
||||
vk::AccessFlagBits2::eShaderRead | vk::AccessFlagBits2::eTransferRead, {});
|
||||
}
|
||||
|
||||
Image::~Image() = default;
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
@ -91,8 +93,11 @@ struct Image {
|
|||
return image_view_ids[std::distance(image_view_infos.begin(), it)];
|
||||
}
|
||||
|
||||
void Transit(vk::ImageLayout dst_layout, vk::Flags<vk::AccessFlagBits> dst_mask,
|
||||
vk::CommandBuffer cmdbuf = {});
|
||||
boost::container::small_vector<vk::ImageMemoryBarrier2, 32> GetBarriers(
|
||||
vk::ImageLayout dst_layout, vk::Flags<vk::AccessFlagBits2> dst_mask,
|
||||
vk::PipelineStageFlags2 dst_stage, std::optional<SubresourceRange> subres_range);
|
||||
void Transit(vk::ImageLayout dst_layout, vk::Flags<vk::AccessFlagBits2> dst_mask,
|
||||
std::optional<SubresourceRange> range, vk::CommandBuffer cmdbuf = {});
|
||||
void Upload(vk::Buffer buffer, u64 offset);
|
||||
|
||||
void CopyImage(const Image& image);
|
||||
|
@ -111,10 +116,14 @@ struct Image {
|
|||
|
||||
// Resource state tracking
|
||||
vk::ImageUsageFlags usage;
|
||||
vk::Flags<vk::PipelineStageFlagBits> pl_stage = vk::PipelineStageFlagBits::eAllCommands;
|
||||
vk::Flags<vk::AccessFlagBits> access_mask = vk::AccessFlagBits::eNone;
|
||||
vk::ImageLayout layout = vk::ImageLayout::eUndefined;
|
||||
boost::container::small_vector<u64, 14> mip_hashes;
|
||||
struct State {
|
||||
vk::Flags<vk::PipelineStageFlagBits2> pl_stage = vk::PipelineStageFlagBits2::eAllCommands;
|
||||
vk::Flags<vk::AccessFlagBits2> access_mask = vk::AccessFlagBits2::eNone;
|
||||
vk::ImageLayout layout = vk::ImageLayout::eUndefined;
|
||||
};
|
||||
State last_state{};
|
||||
std::vector<State> subresource_states{};
|
||||
boost::container::small_vector<u64, 14> mip_hashes{};
|
||||
u64 tick_accessed_last{0};
|
||||
};
|
||||
|
||||
|
|
|
@ -200,18 +200,12 @@ ImageInfo::ImageInfo(const AmdGpu::Liverpool::DepthBuffer& buffer, u32 num_slice
|
|||
mips_layout.emplace_back(depth_slice_sz, pitch, 0);
|
||||
}
|
||||
|
||||
ImageInfo::ImageInfo(const AmdGpu::Image& image, bool force_depth /*= false*/) noexcept {
|
||||
ImageInfo::ImageInfo(const AmdGpu::Image& image, const Shader::ImageResource& desc) noexcept {
|
||||
tiling_mode = image.GetTilingMode();
|
||||
pixel_format = LiverpoolToVK::SurfaceFormat(image.GetDataFmt(), image.GetNumberFmt());
|
||||
// Override format if image is forced to be a depth target
|
||||
if (force_depth) {
|
||||
if (pixel_format == vk::Format::eR32Sfloat || pixel_format == vk::Format::eR8Unorm) {
|
||||
pixel_format = vk::Format::eD32SfloatS8Uint;
|
||||
} else if (pixel_format == vk::Format::eR16Unorm) {
|
||||
pixel_format = vk::Format::eD16UnormS8Uint;
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
if (desc.is_depth) {
|
||||
pixel_format = LiverpoolToVK::PromoteFormatToDepth(pixel_format);
|
||||
}
|
||||
type = ConvertImageType(image.GetType());
|
||||
props.is_tiled = image.IsTiled();
|
||||
|
@ -224,7 +218,7 @@ ImageInfo::ImageInfo(const AmdGpu::Image& image, bool force_depth /*= false*/) n
|
|||
size.depth = props.is_volume ? image.depth + 1 : 1;
|
||||
pitch = image.Pitch();
|
||||
resources.levels = image.NumLevels();
|
||||
resources.layers = image.NumLayers();
|
||||
resources.layers = image.NumLayers(desc.is_array);
|
||||
num_bits = NumBits(image.GetDataFmt());
|
||||
usage.texture = true;
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "common/types.h"
|
||||
#include "core/libraries/videoout/buffer.h"
|
||||
#include "shader_recompiler/info.h"
|
||||
#include "video_core/amdgpu/liverpool.h"
|
||||
#include "video_core/texture_cache/types.h"
|
||||
|
||||
|
@ -19,7 +20,7 @@ struct ImageInfo {
|
|||
const AmdGpu::Liverpool::CbDbExtent& hint = {}) noexcept;
|
||||
ImageInfo(const AmdGpu::Liverpool::DepthBuffer& buffer, u32 num_slices, VAddr htile_address,
|
||||
const AmdGpu::Liverpool::CbDbExtent& hint = {}) noexcept;
|
||||
ImageInfo(const AmdGpu::Image& image, bool force_depth = false) noexcept;
|
||||
ImageInfo(const AmdGpu::Image& image, const Shader::ImageResource& desc) noexcept;
|
||||
|
||||
bool IsTiled() const {
|
||||
return tiling_mode != AmdGpu::TilingMode::Display_Linear;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "shader_recompiler/info.h"
|
||||
#include "video_core/amdgpu/resource.h"
|
||||
#include "video_core/renderer_vulkan/liverpool_to_vk.h"
|
||||
#include "video_core/renderer_vulkan/vk_instance.h"
|
||||
|
@ -66,19 +67,40 @@ vk::Format TrySwizzleFormat(vk::Format format, u32 dst_sel) {
|
|||
return format;
|
||||
}
|
||||
|
||||
ImageViewInfo::ImageViewInfo(const AmdGpu::Image& image, bool is_storage_) noexcept
|
||||
: is_storage{is_storage_} {
|
||||
type = ConvertImageViewType(image.GetType());
|
||||
ImageViewInfo::ImageViewInfo(const AmdGpu::Image& image, const Shader::ImageResource& desc) noexcept
|
||||
: is_storage{desc.is_storage} {
|
||||
const auto dfmt = image.GetDataFmt();
|
||||
auto nfmt = image.GetNumberFmt();
|
||||
if (is_storage && nfmt == AmdGpu::NumberFormat::Srgb) {
|
||||
nfmt = AmdGpu::NumberFormat::Unorm;
|
||||
}
|
||||
format = Vulkan::LiverpoolToVK::SurfaceFormat(dfmt, nfmt);
|
||||
if (desc.is_depth) {
|
||||
format = Vulkan::LiverpoolToVK::PromoteFormatToDepth(format);
|
||||
}
|
||||
range.base.level = image.base_level;
|
||||
range.base.layer = image.base_array;
|
||||
range.extent.levels = image.last_level + 1;
|
||||
range.extent.layers = image.last_array + 1;
|
||||
range.extent.levels = image.last_level - image.base_level + 1;
|
||||
range.extent.layers = image.last_array - image.base_array + 1;
|
||||
type = ConvertImageViewType(image.GetType());
|
||||
|
||||
// Adjust view type for partial cubemaps and arrays
|
||||
if (image.IsPartialCubemap()) {
|
||||
type = vk::ImageViewType::e2DArray;
|
||||
}
|
||||
if (type == vk::ImageViewType::eCube) {
|
||||
if (desc.is_array) {
|
||||
type = vk::ImageViewType::eCubeArray;
|
||||
} else {
|
||||
// Some games try to bind an array of cubemaps while shader reads only single one.
|
||||
range.extent.layers = std::min(range.extent.layers, 6u);
|
||||
}
|
||||
}
|
||||
if (type == vk::ImageViewType::e3D && range.extent.layers > 1) {
|
||||
// Some games pass incorrect layer count for 3D textures so we need to fixup it.
|
||||
range.extent.layers = 1;
|
||||
}
|
||||
|
||||
if (!is_storage) {
|
||||
mapping.r = ConvertComponentSwizzle(image.dst_sel_x);
|
||||
mapping.g = ConvertComponentSwizzle(image.dst_sel_y);
|
||||
|
@ -103,7 +125,7 @@ ImageViewInfo::ImageViewInfo(const AmdGpu::Liverpool::ColorBuffer& col_buffer,
|
|||
const auto base_format =
|
||||
Vulkan::LiverpoolToVK::SurfaceFormat(col_buffer.info.format, col_buffer.NumFormat());
|
||||
range.base.layer = col_buffer.view.slice_start;
|
||||
range.extent.layers = col_buffer.NumSlices();
|
||||
range.extent.layers = col_buffer.NumSlices() - range.base.layer;
|
||||
format = Vulkan::LiverpoolToVK::AdjustColorBufferFormat(
|
||||
base_format, col_buffer.info.comp_swap.Value(), is_vo_surface);
|
||||
}
|
||||
|
@ -115,7 +137,7 @@ ImageViewInfo::ImageViewInfo(const AmdGpu::Liverpool::DepthBuffer& depth_buffer,
|
|||
depth_buffer.stencil_info.format);
|
||||
is_storage = ctl.depth_write_enable;
|
||||
range.base.layer = view.slice_start;
|
||||
range.extent.layers = view.NumSlices();
|
||||
range.extent.layers = view.NumSlices() - range.base.layer;
|
||||
}
|
||||
|
||||
ImageView::ImageView(const Vulkan::Instance& instance, const ImageViewInfo& info_, Image& image,
|
||||
|
@ -147,9 +169,9 @@ ImageView::ImageView(const Vulkan::Instance& instance, const ImageViewInfo& info
|
|||
.subresourceRange{
|
||||
.aspectMask = aspect,
|
||||
.baseMipLevel = info.range.base.level,
|
||||
.levelCount = info.range.extent.levels - info.range.base.level,
|
||||
.levelCount = info.range.extent.levels,
|
||||
.baseArrayLayer = info.range.base.layer,
|
||||
.layerCount = info.range.extent.layers - info.range.base.layer,
|
||||
.layerCount = info.range.extent.layers,
|
||||
},
|
||||
};
|
||||
image_view = instance.GetDevice().createImageViewUnique(image_view_ci);
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "shader_recompiler/info.h"
|
||||
#include "video_core/amdgpu/liverpool.h"
|
||||
#include "video_core/amdgpu/resource.h"
|
||||
#include "video_core/renderer_vulkan/vk_common.h"
|
||||
|
@ -17,7 +18,7 @@ namespace VideoCore {
|
|||
|
||||
struct ImageViewInfo {
|
||||
ImageViewInfo() = default;
|
||||
ImageViewInfo(const AmdGpu::Image& image, bool is_storage) noexcept;
|
||||
ImageViewInfo(const AmdGpu::Image& image, const Shader::ImageResource& desc) noexcept;
|
||||
ImageViewInfo(const AmdGpu::Liverpool::ColorBuffer& col_buffer, bool is_vo_surface) noexcept;
|
||||
ImageViewInfo(const AmdGpu::Liverpool::DepthBuffer& depth_buffer,
|
||||
AmdGpu::Liverpool::DepthView view, AmdGpu::Liverpool::DepthControl ctl);
|
||||
|
|
|
@ -87,8 +87,7 @@ ImageId TextureCache::ResolveDepthOverlap(const ImageInfo& requested_info, Image
|
|||
auto new_image_id = slot_images.insert(instance, scheduler, requested_info);
|
||||
RegisterImage(new_image_id);
|
||||
|
||||
// auto& new_image = slot_images[new_image_id];
|
||||
// TODO: need to run a helper for depth copy here
|
||||
// TODO: perform a depth copy here
|
||||
|
||||
FreeImage(cache_image_id);
|
||||
return new_image_id;
|
||||
|
@ -98,7 +97,11 @@ ImageId TextureCache::ResolveDepthOverlap(const ImageInfo& requested_info, Image
|
|||
!requested_info.usage.depth_target &&
|
||||
(requested_info.usage.texture || requested_info.usage.storage);
|
||||
if (cache_info.usage.depth_target && should_bind_as_texture) {
|
||||
return cache_image_id;
|
||||
if (cache_info.resources == requested_info.resources) {
|
||||
return cache_image_id;
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
|
@ -154,7 +157,7 @@ ImageId TextureCache::ResolveOverlap(const ImageInfo& image_info, ImageId cache_
|
|||
|
||||
if (tex_cache_image.info.IsMipOf(image_info)) {
|
||||
tex_cache_image.Transit(vk::ImageLayout::eTransferSrcOptimal,
|
||||
vk::AccessFlagBits::eTransferRead);
|
||||
vk::AccessFlagBits2::eTransferRead, {});
|
||||
|
||||
const auto num_mips_to_copy = tex_cache_image.info.resources.levels;
|
||||
ASSERT(num_mips_to_copy == 1);
|
||||
|
@ -176,9 +179,13 @@ ImageId TextureCache::ExpandImage(const ImageInfo& info, ImageId image_id) {
|
|||
auto& src_image = slot_images[image_id];
|
||||
auto& new_image = slot_images[new_image_id];
|
||||
|
||||
src_image.Transit(vk::ImageLayout::eTransferSrcOptimal, vk::AccessFlagBits::eTransferRead);
|
||||
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);
|
||||
|
@ -255,21 +262,21 @@ ImageView& TextureCache::RegisterImageView(ImageId image_id, const ImageViewInfo
|
|||
return slot_image_views[view_id];
|
||||
}
|
||||
|
||||
ImageView& TextureCache::FindTexture(const ImageInfo& info, const ImageViewInfo& view_info) {
|
||||
const ImageId image_id = FindImage(info);
|
||||
ImageView& TextureCache::FindTexture(ImageId image_id, const ImageViewInfo& view_info) {
|
||||
Image& image = slot_images[image_id];
|
||||
UpdateImage(image_id);
|
||||
auto& usage = image.info.usage;
|
||||
|
||||
if (view_info.is_storage) {
|
||||
image.Transit(vk::ImageLayout::eGeneral,
|
||||
vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eShaderWrite);
|
||||
vk::AccessFlagBits2::eShaderRead | vk::AccessFlagBits2::eShaderWrite,
|
||||
view_info.range);
|
||||
usage.storage = true;
|
||||
} else {
|
||||
const auto new_layout = image.info.IsDepthStencil()
|
||||
? vk::ImageLayout::eDepthStencilReadOnlyOptimal
|
||||
: vk::ImageLayout::eShaderReadOnlyOptimal;
|
||||
image.Transit(new_layout, vk::AccessFlagBits::eShaderRead);
|
||||
image.Transit(new_layout, vk::AccessFlagBits2::eShaderRead, view_info.range);
|
||||
usage.texture = true;
|
||||
}
|
||||
|
||||
|
@ -284,8 +291,9 @@ ImageView& TextureCache::FindRenderTarget(const ImageInfo& image_info,
|
|||
UpdateImage(image_id);
|
||||
|
||||
image.Transit(vk::ImageLayout::eColorAttachmentOptimal,
|
||||
vk::AccessFlagBits::eColorAttachmentWrite |
|
||||
vk::AccessFlagBits::eColorAttachmentRead);
|
||||
vk::AccessFlagBits2::eColorAttachmentWrite |
|
||||
vk::AccessFlagBits2::eColorAttachmentRead,
|
||||
view_info.range);
|
||||
|
||||
// Register meta data for this color buffer
|
||||
if (!(image.flags & ImageFlagBits::MetaRegistered)) {
|
||||
|
@ -330,8 +338,10 @@ ImageView& TextureCache::FindDepthTarget(const ImageInfo& image_info,
|
|||
: vk::ImageLayout::eDepthAttachmentOptimal
|
||||
: has_stencil ? vk::ImageLayout::eDepthStencilReadOnlyOptimal
|
||||
: vk::ImageLayout::eDepthReadOnlyOptimal;
|
||||
image.Transit(new_layout, vk::AccessFlagBits::eDepthStencilAttachmentWrite |
|
||||
vk::AccessFlagBits::eDepthStencilAttachmentRead);
|
||||
image.Transit(new_layout,
|
||||
vk::AccessFlagBits2::eDepthStencilAttachmentWrite |
|
||||
vk::AccessFlagBits2::eDepthStencilAttachmentRead,
|
||||
view_info.range);
|
||||
|
||||
// Register meta data for this depth buffer
|
||||
if (!(image.flags & ImageFlagBits::MetaRegistered)) {
|
||||
|
@ -404,7 +414,8 @@ void TextureCache::RefreshImage(Image& image, Vulkan::Scheduler* custom_schedule
|
|||
sched_ptr->EndRendering();
|
||||
|
||||
const auto cmdbuf = sched_ptr->CommandBuffer();
|
||||
image.Transit(vk::ImageLayout::eTransferDstOptimal, vk::AccessFlagBits::eTransferWrite, cmdbuf);
|
||||
image.Transit(vk::ImageLayout::eTransferDstOptimal, vk::AccessFlagBits2::eTransferWrite, {},
|
||||
cmdbuf);
|
||||
|
||||
const VAddr image_addr = image.info.guest_address;
|
||||
const size_t image_size = image.info.guest_size_bytes;
|
||||
|
|
|
@ -59,9 +59,8 @@ public:
|
|||
/// Retrieves the image handle of the image with the provided attributes.
|
||||
[[nodiscard]] ImageId FindImage(const ImageInfo& info, FindFlags flags = {});
|
||||
|
||||
/// Retrieves an image view with the properties of the specified image descriptor.
|
||||
[[nodiscard]] ImageView& FindTexture(const ImageInfo& image_info,
|
||||
const ImageViewInfo& view_info);
|
||||
/// Retrieves an image view with the properties of the specified image id.
|
||||
[[nodiscard]] ImageView& FindTexture(ImageId image_id, const ImageViewInfo& view_info);
|
||||
|
||||
/// Retrieves the render target with specified properties
|
||||
[[nodiscard]] ImageView& FindRenderTarget(const ImageInfo& image_info,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue