texture_cache: Handle compressed views of uncompressed images

This commit is contained in:
IndecisiveTurtle 2025-06-08 19:28:43 +03:00
parent 70c7fd4fab
commit a7f91d8ff5
4 changed files with 95 additions and 78 deletions

View File

@ -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<vk::ImageCopy, 14> 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{

View File

@ -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{};

View File

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

View File

@ -199,7 +199,8 @@ std::tuple<ImageId, int, int> 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<ImageId, int, int> 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;