Graphics: resolve equivalent terminal mip views without expanding backing

This commit is contained in:
nmzik
2026-09-27 11:04:19 +04:00
parent 496432bbb4
commit 041874f663
2 changed files with 116 additions and 45 deletions
@@ -514,19 +514,50 @@ static ImageViewInfo TextureViewInfo(const ShaderRecompiler::IR::ImageResource&
return view;
}
static bool TextureViewPreservesMipLayout(const TileSurfaceDescription& description,
uint32_t view_levels) {
static bool ResolveTextureMipView(const TileSurfaceDescription& description, bool metadata,
uint32_t view_levels, uint32_t& levels, uint32_t& base_level) {
TileSurfaceLayout physical {};
TileSurfaceLayout view {};
auto view_description = description;
view_description.levels = view_levels;
return TileGetTiledTextureLayout(description, physical) &&
TileGetTiledTextureLayout(view_description, view) &&
physical.first_tail_level == view.first_tail_level &&
physical.block_slice_size == view.block_slice_size &&
physical.total_size == view.total_size &&
std::equal(std::begin(physical.mips), std::begin(physical.mips) + description.levels,
std::begin(view.mips));
view_description.levels = levels;
if (!TileGetTiledTextureLayout(description, physical) ||
!TileGetTiledTextureLayout(view_description, view)) {
return false;
}
if (physical.first_tail_level == view.first_tail_level &&
physical.block_slice_size == view.block_slice_size &&
physical.total_size == view.total_size &&
std::equal(std::begin(physical.mips), std::begin(physical.mips) + description.levels,
std::begin(view.mips))) {
return true;
}
if (metadata || ((description.layers > 1 || description.depth > 1) &&
physical.block_slice_size != view.block_slice_size)) {
return false;
}
// T# addresses the last mip. A view can select the same stored subresources
// with different mip indices; inaccessible mips need no host representation.
for (uint32_t base = 0; base + view_levels <= description.levels; ++base) {
bool matches = true;
for (uint32_t i = 0; i < view_levels; ++i) {
const auto source = base_level + i;
const auto target = base + i;
if (physical.mips[target] != view.mips[source] ||
(target >= physical.first_tail_level) != (source >= view.first_tail_level) ||
std::max(description.width >> target, 1u) != std::max(description.width >> source, 1u) ||
std::max(description.height >> target, 1u) != std::max(description.height >> source, 1u) ||
std::max(description.depth >> target, 1u) != std::max(description.depth >> source, 1u)) {
matches = false;
break;
}
}
if (matches) {
levels = description.levels;
base_level = base;
return true;
}
}
return false;
}
TextureBinding RenderExecutor::ResolveTexture(const ShaderRecompiler::IR::ImageResource& resource,
@@ -560,7 +591,7 @@ TextureBinding RenderExecutor::ResolveTexture(const ShaderRecompiler::IR::ImageR
const auto view_levels = multisampled || single_storage_mip
? 1u
: static_cast<uint32_t>(last_level - base_level) + 1u;
const auto levels =
auto levels =
multisampled ? 1u : std::max(physical_levels, base_level + view_levels);
const auto tile = descriptor.TileMode();
const bool depth_tile = tile == Prospero::TileMode::kDepth;
@@ -602,12 +633,13 @@ TextureBinding RenderExecutor::ResolveTexture(const ShaderRecompiler::IR::ImageR
type == Prospero::ImageType::kColor2DArray ||
type == Prospero::ImageType::kColor2DMsaaArray;
const auto image_layers = layered ? depth : 1u;
auto view_base = static_cast<uint32_t>(base_level);
if (levels > physical_levels) {
const TileSurfaceDescription physical {
format, tile, volume ? TileSurfaceDimension::Dim3D : TileSurfaceDimension::Dim2D,
width, height, volume ? depth : 1u, physical_levels, image_layers};
// Texture mip views take precedence over the resource count, but must keep its storage layout.
if (!TextureViewPreservesMipLayout(physical, levels)) {
if (!ResolveTextureMipView(physical, !resource.r128 && descriptor.MetaCompress(),
view_levels, levels, view_base)) {
EXIT("unsupported texture mip view changes physical layout: base=%u last=%u max=%u "
"extent=%ux%ux%u tile=%u\n",
base_level, last_level, max_mip, width, height, depth,
@@ -679,6 +711,7 @@ TextureBinding RenderExecutor::ResolveTexture(const ShaderRecompiler::IR::ImageR
}
desc.view_info = TextureViewInfo(resource, descriptor, view_format, surface_format, storage,
view_levels, desc.info.resources.layers);
desc.view_info.base_level = view_base;
desc.type = storage ? TextureCache::BindingType::Storage : TextureCache::BindingType::Texture;
auto id = texture_cache.FindImage(desc, shader_conversion);