diff --git a/src/video_core/texture_cache/image_info.cpp b/src/video_core/texture_cache/image_info.cpp index b0b272e2f..b15338d16 100644 --- a/src/video_core/texture_cache/image_info.cpp +++ b/src/video_core/texture_cache/image_info.cpp @@ -196,6 +196,32 @@ void ImageInfo::UpdateSize() { mip_w, mip_h, thickness, num_bits, num_samples, tile_mode, mip, alt_tile); break; } + case AmdGpu::ArrayMode::Array3DTiledXThick: { + ASSERT(!props.is_block); + ASSERT(resources.layers == 1); + u32 thickness = 8; + mip_d += (-mip_d) & (thickness - 1); + std::tie(mip_info.pitch, mip_info.height, mip_info.size) = ImageSizeMacroTiled3D( + mip_w, mip_h, mip_d, num_bits, num_samples, tile_mode, mip, alt_tile); + break; + } + case AmdGpu::ArrayMode::Array3DTiledThick: { + ASSERT(!props.is_block); + ASSERT(resources.layers == 1); + u32 thickness = 4; + mip_d += (-mip_d) & (thickness - 1); + std::tie(mip_info.pitch, mip_info.height, mip_info.size) = ImageSizeMacroTiled3D( + mip_w, mip_h, mip_d, num_bits, num_samples, tile_mode, mip, alt_tile); + break; + } + case AmdGpu::ArrayMode::Array3DTiledThin1: { + ASSERT(!props.is_block); + ASSERT(resources.layers == 1); + std::tie(mip_info.pitch, mip_info.height, mip_info.size) = ImageSizeMacroTiled3D( + mip_w, mip_h, mip_d, num_bits, num_samples, tile_mode, mip, alt_tile); + break; + } + default: { UNREACHABLE_MSG("Unknown array mode {}", magic_enum::enum_name(array_mode)); } @@ -204,7 +230,13 @@ void ImageInfo::UpdateSize() { mip_info.pitch = std::max(mip_info.pitch * 4, 32u); mip_info.height = std::max(mip_info.height * 4, 32u); } - mip_info.size *= mip_d * resources.layers; + if (array_mode == AmdGpu::ArrayMode::Array3DTiledThin1 || + array_mode == AmdGpu::ArrayMode::Array3DTiledThick || + array_mode == AmdGpu::ArrayMode::Array3DTiledXThick) { + mip_info.size *= resources.layers; // 3D tiled already includes depth + } else { + mip_info.size *= mip_d * resources.layers; + } mip_info.offset = guest_size; guest_size += mip_info.size; } diff --git a/src/video_core/texture_cache/tile.h b/src/video_core/texture_cache/tile.h index 68c9428fe..bc57c12d9 100644 --- a/src/video_core/texture_cache/tile.h +++ b/src/video_core/texture_cache/tile.h @@ -348,4 +348,40 @@ constexpr std::tuple ImageSizeMacroTiled(u32 pitch, u32 height return {pitch_aligned, height_aligned, (log_sz * bpp + 7) / 8}; } +std::tuple ImageSizeMacroTiled3D(u32 pitch, u32 height, u32 depth, u32 bpp, + u32 num_samples, AmdGpu::TileMode tile_mode, + u32 mip, bool alt) { + + const u32 thickness = (tile_mode == AmdGpu::TileMode::Thick2DXThick || + tile_mode == AmdGpu::TileMode::Thick3DXThick) + ? 8 + : (tile_mode == AmdGpu::TileMode::Thick2DThick || + tile_mode == AmdGpu::TileMode::Thick3DThick || + tile_mode == AmdGpu::TileMode::Thick1DThick) + ? 4 + : 1; + + const auto [pitch_align, height_align] = GetMacroTileExtents(tile_mode, bpp, num_samples, alt); + ASSERT(pitch_align != 0 && height_align != 0); + bool downgrade_to_micro = false; + if (mip > 0) { + const bool is_less_than_tile = pitch < pitch_align || height < height_align; + downgrade_to_micro = is_less_than_tile; + } + + if (downgrade_to_micro) { + const auto [p, h, size2d] = ImageSizeMicroTiled(pitch, height, thickness, bpp, num_samples); + const u32 aligned_d = (depth + thickness - 1) & ~(thickness - 1); + return {p, h, size2d * aligned_d}; + } + + const u32 pitch_aligned = (pitch + pitch_align - 1) & ~(pitch_align - 1); + const u32 height_aligned = (height + height_align - 1) & ~(height_align - 1); + const u32 depth_aligned = (depth + thickness - 1) & ~(thickness - 1); + const size_t slice_size = ((size_t)pitch_aligned * height_aligned * num_samples * bpp + 7) / 8; + const size_t total_size = slice_size * depth_aligned; + + return {pitch_aligned, height_aligned, total_size}; +} + } // namespace VideoCore