diff --git a/src/video_core/texture_cache/image.cpp b/src/video_core/texture_cache/image.cpp index 522e6fd5b..8522f1307 100644 --- a/src/video_core/texture_cache/image.cpp +++ b/src/video_core/texture_cache/image.cpp @@ -14,62 +14,6 @@ namespace VideoCore { using namespace Vulkan; -bool ImageInfo::IsBlockCoded() const { - switch (pixel_format) { - case vk::Format::eBc1RgbaSrgbBlock: - case vk::Format::eBc1RgbaUnormBlock: - case vk::Format::eBc1RgbSrgbBlock: - case vk::Format::eBc1RgbUnormBlock: - case vk::Format::eBc2SrgbBlock: - case vk::Format::eBc2UnormBlock: - case vk::Format::eBc3SrgbBlock: - case vk::Format::eBc3UnormBlock: - case vk::Format::eBc4SnormBlock: - case vk::Format::eBc4UnormBlock: - case vk::Format::eBc5SnormBlock: - case vk::Format::eBc5UnormBlock: - case vk::Format::eBc6HSfloatBlock: - case vk::Format::eBc6HUfloatBlock: - case vk::Format::eBc7SrgbBlock: - case vk::Format::eBc7UnormBlock: - return true; - default: - return false; - } -} - -bool ImageInfo::IsPacked() const { - switch (pixel_format) { - case vk::Format::eB5G5R5A1UnormPack16: - [[fallthrough]]; - case vk::Format::eB5G6R5UnormPack16: - return true; - default: - return false; - } -} - -bool ImageInfo::IsDepthStencil() const { - switch (pixel_format) { - case vk::Format::eD16Unorm: - case vk::Format::eD16UnormS8Uint: - case vk::Format::eD32Sfloat: - case vk::Format::eD32SfloatS8Uint: - return true; - default: - return false; - } -} - -bool ImageInfo::HasStencil() const { - if (pixel_format == vk::Format::eD32SfloatS8Uint || - pixel_format == vk::Format::eD24UnormS8Uint || - pixel_format == vk::Format::eD16UnormS8Uint) { - return true; - } - return false; -} - static vk::ImageUsageFlags ImageUsageFlags(const ImageInfo& info) { vk::ImageUsageFlags usage = vk::ImageUsageFlagBits::eTransferSrc | vk::ImageUsageFlagBits::eTransferDst | @@ -161,6 +105,9 @@ Image::Image(const Vulkan::Instance& instance_, Vulkan::Scheduler& scheduler_, if (info.props.is_volume) { flags |= vk::ImageCreateFlagBits::e2DArrayCompatible; } + if (info.props.is_block) { + flags |= vk::ImageCreateFlagBits::eBlockTexelViewCompatible; + } usage_flags = ImageUsageFlags(info); format_features = FormatFeatureFlags(usage_flags); @@ -372,9 +319,9 @@ void Image::CopyImage(const Image& image) { boost::container::small_vector image_copy{}; for (u32 m = 0; m < image.info.resources.levels; ++m) { - const auto mip_w = std::max(info.size.width >> m, 1u); - const auto mip_h = std::max(info.size.height >> m, 1u); - const auto mip_d = std::max(info.size.depth >> m, 1u); + const auto mip_w = std::max(image.info.size.width >> m, 1u); + const auto mip_h = std::max(image.info.size.height >> m, 1u); + const auto mip_d = std::max(image.info.size.depth >> m, 1u); image_copy.emplace_back(vk::ImageCopy{ .srcSubresource{ diff --git a/src/video_core/texture_cache/image_info.cpp b/src/video_core/texture_cache/image_info.cpp index 7fa65c6d7..769c4211f 100644 --- a/src/video_core/texture_cache/image_info.cpp +++ b/src/video_core/texture_cache/image_info.cpp @@ -152,6 +152,80 @@ ImageInfo::ImageInfo(const AmdGpu::Image& image, const Shader::ImageResource& de UpdateSize(); } +bool ImageInfo::IsBlockCoded() const { + switch (pixel_format) { + case vk::Format::eBc1RgbaSrgbBlock: + case vk::Format::eBc1RgbaUnormBlock: + case vk::Format::eBc1RgbSrgbBlock: + case vk::Format::eBc1RgbUnormBlock: + case vk::Format::eBc2SrgbBlock: + case vk::Format::eBc2UnormBlock: + case vk::Format::eBc3SrgbBlock: + case vk::Format::eBc3UnormBlock: + case vk::Format::eBc4SnormBlock: + case vk::Format::eBc4UnormBlock: + case vk::Format::eBc5SnormBlock: + case vk::Format::eBc5UnormBlock: + case vk::Format::eBc6HSfloatBlock: + case vk::Format::eBc6HUfloatBlock: + case vk::Format::eBc7SrgbBlock: + case vk::Format::eBc7UnormBlock: + return true; + default: + return false; + } +} + +bool ImageInfo::IsPacked() const { + switch (pixel_format) { + case vk::Format::eB5G5R5A1UnormPack16: + [[fallthrough]]; + case vk::Format::eB5G6R5UnormPack16: + return true; + default: + return false; + } +} + +bool ImageInfo::IsDepthStencil() const { + switch (pixel_format) { + case vk::Format::eD16Unorm: + case vk::Format::eD16UnormS8Uint: + case vk::Format::eD32Sfloat: + case vk::Format::eD32SfloatS8Uint: + return true; + default: + return false; + } +} + +bool ImageInfo::HasStencil() const { + if (pixel_format == vk::Format::eD32SfloatS8Uint || + pixel_format == vk::Format::eD24UnormS8Uint || + pixel_format == vk::Format::eD16UnormS8Uint) { + return true; + } + return false; +} + +bool ImageInfo::IsCompatible(const ImageInfo& info) const { + return (pixel_format == info.pixel_format && num_samples == info.num_samples && + num_bits == info.num_bits); +} + +bool ImageInfo::IsTilingCompatible(u32 lhs, u32 rhs) const { + if (lhs == rhs) { + return true; + } + if (lhs == 0x0e && rhs == 0x0d) { + return true; + } + if (lhs == 0x0d && rhs == 0x0e) { + return true; + } + return false; +} + void ImageInfo::UpdateSize() { mips_layout.clear(); MipInfo mip_info{}; diff --git a/src/video_core/texture_cache/image_info.h b/src/video_core/texture_cache/image_info.h index ca4d9f5e9..47718a095 100644 --- a/src/video_core/texture_cache/image_info.h +++ b/src/video_core/texture_cache/image_info.h @@ -25,6 +25,11 @@ struct ImageInfo { bool IsTiled() const { return tiling_mode != AmdGpu::TilingMode::Display_Linear; } + Extent3D BlockDim() const { + const u32 shift = props.is_block ? 2 : 0; + return Extent3D{size.width >> shift, size.height >> shift, size.depth}; + } + bool IsBlockCoded() const; bool IsPacked() const; bool IsDepthStencil() const; @@ -33,24 +38,8 @@ struct ImageInfo { s32 MipOf(const ImageInfo& info) const; s32 SliceOf(const ImageInfo& info, s32 mip) const; - /// Verifies if images are compatible for subresource merging. - bool IsCompatible(const ImageInfo& info) const { - return (pixel_format == info.pixel_format && num_samples == info.num_samples && - num_bits == info.num_bits); - } - - bool IsTilingCompatible(u32 lhs, u32 rhs) const { - if (lhs == rhs) { - return true; - } - if (lhs == 0x0e && rhs == 0x0d) { - return true; - } - if (lhs == 0x0d && rhs == 0x0e) { - return true; - } - return false; - } + bool IsCompatible(const ImageInfo& info) const; + bool IsTilingCompatible(u32 lhs, u32 rhs) const; void UpdateSize(); diff --git a/src/video_core/texture_cache/texture_cache.cpp b/src/video_core/texture_cache/texture_cache.cpp index 25af3181b..ce06d219b 100644 --- a/src/video_core/texture_cache/texture_cache.cpp +++ b/src/video_core/texture_cache/texture_cache.cpp @@ -199,7 +199,8 @@ std::tuple TextureCache::ResolveOverlap(const ImageInfo& imag scheduler.CurrentTick() - tex_cache_image.tick_accessed_last > NumFramesBeforeRemoval; if (image_info.guest_address == tex_cache_image.info.guest_address) { // Equal address - if (image_info.size != tex_cache_image.info.size) { + if (image_info.BlockDim() != tex_cache_image.info.BlockDim() || + image_info.num_bits != tex_cache_image.info.num_bits) { // Very likely this kind of overlap is caused by allocation from a pool. if (safe_to_delete) { FreeImage(cache_image_id); @@ -211,6 +212,12 @@ std::tuple TextureCache::ResolveOverlap(const ImageInfo& imag return {depth_image_id, -1, -1}; } + if (image_info.IsBlockCoded() && !tex_cache_image.info.IsBlockCoded()) { + // Compressed view of uncompressed image with same block size. + // We need to recreate the image with compressed format and copy. + return {ExpandImage(image_info, cache_image_id), -1, -1}; + } + if (image_info.pixel_format != tex_cache_image.info.pixel_format || image_info.guest_size <= tex_cache_image.info.guest_size) { auto result_id = merged_image_id ? merged_image_id : cache_image_id;