video_core: Rework tile manager (#3374)

* video_core: Rework detiling

* video_core: Support tiling and macrotile detiling

* clang format

* image_info: Cleanups

* resource: Revert some changes

* texture_cache: Fix small error

* image_info: Set depth flag on depth promote

* buffer_cache: Remove level check

* tile_manager: Handle case of staging buffer causing flush

* image_info: Add 2D thick array mode

* image_info: Add slices to mip size

* tile_manager: Set bank swizzle

* buffer_cache: Support image copies from DmaData

* vk_rasterizer: Accelerate trivial render target copies with compute

Before tiling PR compute image copies were done with the following sequence

vkCmdCopyImageToBuffer (in SynchronizeBufferFromImage)  -> vkCmdDispatch (copy) -> vkCmdCopyBufferToImage (in RefreshImage)

With the tiling PR it added extra tiling/detiling steps

vkCmdCopyImageToBuffer -> vkCmdDispatch (tiling) -> vkCmdDispatch (copy) -> vkCmdDispatch (detiling) -> vkCmdCopyBufferToImage

This is quite a bit of overhead for a simple image copy. This commit tries to detect trivial image copies i.e cs shaders that copy the full source image to all of the destination.
So now all this sequence is just a vkCmdCopyImage. How much it triggers depends on the guest

* texture_cache: Fix build

* image: Copy all subresources with buffer too
This commit is contained in:
TheTurtle
2025-08-08 15:27:11 +03:00
committed by GitHub
parent befc5ec17b
commit d9108cd39a
30 changed files with 1999 additions and 797 deletions

View File

@@ -22,7 +22,7 @@
#include "common/unique_function.h"
#include "shader_recompiler/params.h"
#include "video_core/amdgpu/pixel_format.h"
#include "video_core/amdgpu/resource.h"
#include "video_core/amdgpu/tiling.h"
#include "video_core/amdgpu/types.h"
namespace Vulkan {
@@ -426,7 +426,7 @@ struct Liverpool {
BitField<0, 2, ZFormat> format;
BitField<2, 2, u32> num_samples;
BitField<13, 3, u32> tile_split;
BitField<20, 3, u32> tile_mode_index;
BitField<20, 3, TileMode> tile_mode_index;
BitField<23, 4, u32> decompress_on_n_zplanes;
BitField<27, 1, u32> allow_expclear;
BitField<28, 1, u32> read_size;
@@ -502,6 +502,14 @@ struct Liverpool {
const auto bpe = NumBits() >> 3; // in bytes
return (depth_slice.tile_max + 1) * 64 * bpe * NumSamples();
}
TileMode GetTileMode() const {
return z_info.tile_mode_index.Value();
}
bool IsTiled() const {
return GetTileMode() != TileMode::DisplayLinearAligned;
}
};
enum class ClipSpace : u32 {
@@ -888,7 +896,7 @@ struct Liverpool {
u32 u32all;
} info;
union Color0Attrib {
BitField<0, 5, TilingMode> tile_mode_index;
BitField<0, 5, TileMode> tile_mode_index;
BitField<5, 5, u32> fmask_tile_mode_index;
BitField<10, 2, u32> fmask_bank_height;
BitField<12, 3, u32> num_samples_log2;
@@ -949,13 +957,13 @@ struct Liverpool {
return slice_size;
}
TilingMode GetTilingMode() const {
return info.linear_general ? TilingMode::Display_Linear
TileMode GetTileMode() const {
return info.linear_general ? TileMode::DisplayLinearAligned
: attrib.tile_mode_index.Value();
}
bool IsTiled() const {
return GetTilingMode() != TilingMode::Display_Linear;
return GetTileMode() != TileMode::DisplayLinearAligned;
}
[[nodiscard]] DataFormat GetDataFmt() const {

View File

@@ -178,7 +178,7 @@ static constexpr std::array BITS_PER_BLOCK = {
64, // 12 Format16_16_16_16
96, // 13 Format32_32_32
128, // 14 Format32_32_32_32
0, // 15
-1, // 15
16, // 16 Format5_6_5
16, // 17 Format1_5_5_5
16, // 18 Format5_5_5_1
@@ -186,15 +186,15 @@ static constexpr std::array BITS_PER_BLOCK = {
32, // 20 Format8_24
32, // 21 Format24_8
64, // 22 FormatX24_8_32
0, // 23
0, // 24
0, // 25
0, // 26
0, // 27
0, // 28
0, // 29
0, // 30
0, // 31
-1, // 23
-1, // 24
-1, // 25
-1, // 26
-1, // 27
-1, // 28
-1, // 29
-1, // 30
-1, // 31
16, // 32 FormatGB_GR
16, // 33 FormatBG_RG
32, // 34 Format5_9_9_9
@@ -213,4 +213,55 @@ u32 NumBitsPerBlock(DataFormat format) {
return BITS_PER_BLOCK[index];
}
static constexpr std::array BITS_PER_ELEMENT = {
0, // 0 FormatInvalid
8, // 1 Format8
16, // 2 Format16
16, // 3 Format8_8
32, // 4 Format32
32, // 5 Format16_16
32, // 6 Format10_11_11
32, // 7 Format11_11_10
32, // 8 Format10_10_10_2
32, // 9 Format2_10_10_10
32, // 10 Format8_8_8_8
64, // 11 Format32_32
64, // 12 Format16_16_16_16
96, // 13 Format32_32_32
128, // 14 Format32_32_32_32
-1, // 15
16, // 16 Format5_6_5
16, // 17 Format1_5_5_5
16, // 18 Format5_5_5_1
16, // 19 Format4_4_4_4
32, // 20 Format8_24
32, // 21 Format24_8
64, // 22 FormatX24_8_32
-1, // 23
-1, // 24
-1, // 25
-1, // 26
-1, // 27
-1, // 28
-1, // 29
-1, // 30
-1, // 31
16, // 32 FormatGB_GR
16, // 33 FormatBG_RG
32, // 34 Format5_9_9_9
4, // 35 FormatBc1
8, // 36 FormatBc2
8, // 37 FormatBc3
4, // 38 FormatBc4
8, // 39 FormatBc5
8, // 40 FormatBc6
8, // 41 FormatBc7
};
u32 NumBitsPerElement(DataFormat format) {
const u32 index = static_cast<u32>(format);
ASSERT_MSG(index < BITS_PER_ELEMENT.size(), "Invalid data format = {}", format);
return BITS_PER_ELEMENT[index];
}
} // namespace AmdGpu

View File

@@ -85,7 +85,7 @@ enum class NumberClass {
Uint,
};
enum class CompSwizzle : u8 {
enum class CompSwizzle : u32 {
Zero = 0,
One = 1,
Red = 4,
@@ -313,7 +313,11 @@ constexpr NumberClass GetNumberClass(const NumberFormat nfmt) {
}
constexpr bool IsInteger(const NumberFormat nfmt) {
return nfmt == AmdGpu::NumberFormat::Sint || nfmt == AmdGpu::NumberFormat::Uint;
return nfmt == NumberFormat::Sint || nfmt == NumberFormat::Uint;
}
constexpr bool IsBlockCoded(DataFormat format) {
return format >= DataFormat::FormatBc1 && format <= DataFormat::FormatBc7;
}
std::string_view NameOf(DataFormat fmt);
@@ -321,6 +325,7 @@ std::string_view NameOf(NumberFormat fmt);
u32 NumComponents(DataFormat format);
u32 NumBitsPerBlock(DataFormat format);
u32 NumBitsPerElement(DataFormat format);
} // namespace AmdGpu

View File

@@ -7,6 +7,7 @@
#include "common/assert.h"
#include "common/bit_field.h"
#include "video_core/amdgpu/pixel_format.h"
#include "video_core/amdgpu/tiling.h"
namespace AmdGpu {
@@ -138,37 +139,6 @@ constexpr std::string_view NameOf(ImageType type) {
}
}
enum class TilingMode : u32 {
Depth_MacroTiled = 0u,
Display_Linear = 0x8u,
Display_MicroTiled = 0x9u,
Display_MacroTiled = 0xAu,
Texture_MicroTiled = 0xDu,
Texture_MacroTiled = 0xEu,
Texture_Volume = 0x13u,
};
constexpr std::string_view NameOf(TilingMode type) {
switch (type) {
case TilingMode::Depth_MacroTiled:
return "Depth_MacroTiled";
case TilingMode::Display_Linear:
return "Display_Linear";
case TilingMode::Display_MicroTiled:
return "Display_MicroTiled";
case TilingMode::Display_MacroTiled:
return "Display_MacroTiled";
case TilingMode::Texture_MicroTiled:
return "Texture_MicroTiled";
case TilingMode::Texture_MacroTiled:
return "Texture_MacroTiled";
case TilingMode::Texture_Volume:
return "Texture_Volume";
default:
return "Unknown";
}
}
struct Image {
u64 base_address : 38;
u64 mtype_l2 : 2;
@@ -212,28 +182,15 @@ struct Image {
u64 alt_tile_mode : 1;
u64 : 39;
static constexpr Image Null() {
static constexpr Image Null(bool is_depth) {
Image image{};
image.data_format = u64(DataFormat::Format8_8_8_8);
image.num_format = u64(NumberFormat::Unorm);
image.data_format = u64(is_depth ? DataFormat::Format32 : DataFormat::Format8_8_8_8);
image.num_format = u64(is_depth ? NumberFormat::Float : NumberFormat::Unorm);
image.dst_sel_x = u64(CompSwizzle::Red);
image.dst_sel_y = u64(CompSwizzle::Green);
image.dst_sel_z = u64(CompSwizzle::Blue);
image.dst_sel_w = u64(CompSwizzle::Alpha);
image.tiling_index = u64(TilingMode::Texture_MicroTiled);
image.type = u64(ImageType::Color2D);
return image;
}
static constexpr Image NullDepth() {
Image image{};
image.data_format = u64(DataFormat::Format32);
image.num_format = u64(NumberFormat::Float);
image.dst_sel_x = u64(CompSwizzle::Red);
image.dst_sel_y = u64(CompSwizzle::Green);
image.dst_sel_z = u64(CompSwizzle::Blue);
image.dst_sel_w = u64(CompSwizzle::Alpha);
image.tiling_index = u64(TilingMode::Texture_MicroTiled);
image.tiling_index = u64(TileMode::Thin1DThin);
image.type = u64(ImageType::Color2D);
return image;
}
@@ -314,16 +271,26 @@ struct Image {
return MapNumberConversion(NumberFormat(num_format), DataFormat(data_format));
}
TilingMode GetTilingMode() const {
if (tiling_index >= 0 && tiling_index <= 7) {
return tiling_index == 5 ? TilingMode::Texture_MicroTiled
: TilingMode::Depth_MacroTiled;
}
return static_cast<TilingMode>(tiling_index);
TileMode GetTileMode() const {
return static_cast<TileMode>(tiling_index);
}
bool IsTiled() const {
return GetTilingMode() != TilingMode::Display_Linear;
return GetTileMode() != TileMode::DisplayLinearAligned &&
GetTileMode() != TileMode::DisplayLinearGeneral;
}
u8 GetBankSwizzle() const {
const auto tile_mode = GetTileMode();
const auto array_mode = GetArrayMode(tile_mode);
const auto dfmt = GetDataFmt();
if (!alt_tile_mode || dfmt == DataFormat::FormatInvalid || !IsMacroTiled(array_mode)) {
return 0;
}
const u32 bpp = NumBitsPerElement(dfmt);
const auto macro_tile_mode = CalculateMacrotileMode(tile_mode, bpp, NumSamples());
const u32 banks = GetAltNumBanks(macro_tile_mode);
return (((banks - 1) << 4) & base_address) >> 4;
}
bool IsFmask() const noexcept {
@@ -331,7 +298,21 @@ struct Image {
GetDataFmt() <= DataFormat::FormatFmask64_8;
}
[[nodiscard]] ImageType GetViewType(const bool is_array) const noexcept {
ImageType GetBaseType() const noexcept {
const auto base_type = GetType();
if (base_type == ImageType::Color1DArray) {
return ImageType::Color1D;
}
if (base_type == ImageType::Color2DArray) {
return ImageType::Color2D;
}
if (base_type == ImageType::Color2DMsaa || base_type == ImageType::Color2DMsaaArray) {
return ImageType::Color2D;
}
return base_type;
}
ImageType GetViewType(const bool is_array) const noexcept {
const auto base_type = GetType();
if (IsCube()) {
// Cube needs to remain array type regardless of instruction array specifier.
@@ -422,13 +403,7 @@ enum class Filter : u64 {
};
constexpr bool IsAnisoFilter(const Filter filter) {
switch (filter) {
case Filter::AnisoPoint:
case Filter::AnisoLinear:
return true;
default:
return false;
}
return filter == Filter::AnisoPoint || filter == Filter::AnisoLinear;
}
enum class MipFilter : u64 {
@@ -495,7 +470,7 @@ struct Sampler {
}
float LodBias() const noexcept {
return static_cast<float>(static_cast<int16_t>((lod_bias.Value() ^ 0x2000u) - 0x2000u)) /
return static_cast<float>(static_cast<s16>((lod_bias.Value() ^ 0x2000u) - 0x2000u)) /
256.0f;
}

View File

@@ -0,0 +1,554 @@
// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/assert.h"
#include "video_core/amdgpu/tiling.h"
#include <magic_enum/magic_enum.hpp>
namespace AmdGpu {
static constexpr u32 MICROTILE_SIZE = 8;
static constexpr u32 DRAM_ROW_SIZE = 1024;
std::string_view NameOf(TileMode tile_mode) {
return magic_enum::enum_name(tile_mode);
}
ArrayMode GetArrayMode(TileMode tile_mode) {
switch (tile_mode) {
case TileMode::Depth1DThin:
case TileMode::Display1DThin:
case TileMode::Thin1DThin:
return ArrayMode::Array1DTiledThin1;
case TileMode::Depth2DThin64:
case TileMode::Depth2DThin128:
case TileMode::Depth2DThin256:
case TileMode::Depth2DThin512:
case TileMode::Depth2DThin1K:
case TileMode::Display2DThin:
case TileMode::Thin2DThin:
return ArrayMode::Array2DTiledThin1;
case TileMode::DisplayThinPrt:
case TileMode::ThinThinPrt:
return ArrayMode::ArrayPrtTiledThin1;
case TileMode::Depth2DThinPrt256:
case TileMode::Depth2DThinPrt1K:
case TileMode::Display2DThinPrt:
case TileMode::Thin2DThinPrt:
return ArrayMode::ArrayPrt2DTiledThin1;
case TileMode::Thin3DThin:
case TileMode::Thin3DThinPrt:
return ArrayMode::Array3DTiledThin1;
case TileMode::Thick1DThick:
return ArrayMode::Array1DTiledThick;
case TileMode::Thick2DThick:
return ArrayMode::Array2DTiledThick;
case TileMode::Thick3DThick:
return ArrayMode::Array3DTiledThick;
case TileMode::ThickThickPrt:
return ArrayMode::ArrayPrtTiledThick;
case TileMode::Thick2DThickPrt:
return ArrayMode::ArrayPrt2DTiledThick;
case TileMode::Thick3DThickPrt:
return ArrayMode::ArrayPrt3DTiledThick;
case TileMode::Thick2DXThick:
return ArrayMode::Array2DTiledXThick;
case TileMode::Thick3DXThick:
return ArrayMode::Array3DTiledXThick;
case TileMode::DisplayLinearAligned:
return ArrayMode::ArrayLinearAligned;
case TileMode::DisplayLinearGeneral:
return ArrayMode::ArrayLinearGeneral;
default:
UNREACHABLE_MSG("Unknown tile mode = {}", u32(tile_mode));
}
}
MicroTileMode GetMicroTileMode(TileMode tile_mode) {
switch (tile_mode) {
case TileMode::Depth2DThin64:
case TileMode::Depth2DThin128:
case TileMode::Depth2DThin256:
case TileMode::Depth2DThin512:
case TileMode::Depth2DThin1K:
case TileMode::Depth1DThin:
case TileMode::Depth2DThinPrt256:
case TileMode::Depth2DThinPrt1K:
return MicroTileMode::Depth;
case TileMode::DisplayLinearAligned:
case TileMode::Display1DThin:
case TileMode::Display2DThin:
case TileMode::DisplayThinPrt:
case TileMode::Display2DThinPrt:
case TileMode::DisplayLinearGeneral:
return MicroTileMode::Display;
case TileMode::Thin1DThin:
case TileMode::Thin2DThin:
case TileMode::Thin3DThin:
case TileMode::ThinThinPrt:
case TileMode::Thin2DThinPrt:
case TileMode::Thin3DThinPrt:
return MicroTileMode::Thin;
case TileMode::Thick1DThick:
case TileMode::Thick2DThick:
case TileMode::Thick3DThick:
case TileMode::ThickThickPrt:
case TileMode::Thick2DThickPrt:
case TileMode::Thick3DThickPrt:
case TileMode::Thick2DXThick:
case TileMode::Thick3DXThick:
return MicroTileMode::Thick;
default:
UNREACHABLE_MSG("Unknown tile mode = {}", u32(tile_mode));
}
}
PipeConfig GetPipeConfig(TileMode tile_mode) {
switch (tile_mode) {
case TileMode::Depth2DThin64:
case TileMode::Depth2DThin128:
case TileMode::Depth2DThin256:
case TileMode::Depth2DThin512:
case TileMode::Depth2DThin1K:
case TileMode::Depth1DThin:
case TileMode::Depth2DThinPrt256:
case TileMode::Depth2DThinPrt1K:
case TileMode::DisplayLinearAligned:
case TileMode::Display1DThin:
case TileMode::Display2DThin:
case TileMode::Display2DThinPrt:
case TileMode::Thin1DThin:
case TileMode::Thin2DThin:
case TileMode::Thin2DThinPrt:
case TileMode::Thin3DThinPrt:
case TileMode::Thick1DThick:
case TileMode::Thick2DThick:
case TileMode::Thick2DThickPrt:
case TileMode::Thick2DXThick:
return PipeConfig::P8_32x32_16x16;
case TileMode::DisplayThinPrt:
case TileMode::Thin3DThin:
case TileMode::ThinThinPrt:
case TileMode::Thick3DThick:
case TileMode::ThickThickPrt:
case TileMode::Thick3DThickPrt:
case TileMode::Thick3DXThick:
return PipeConfig::P8_32x32_8x16;
case TileMode::DisplayLinearGeneral:
return PipeConfig::P2;
default:
UNREACHABLE_MSG("Unknown tile mode = {}", u32(tile_mode));
}
}
PipeConfig GetAltPipeConfig(TileMode tile_mode) {
switch (tile_mode) {
case TileMode::Depth2DThin64:
case TileMode::Depth2DThin128:
case TileMode::Depth2DThin256:
case TileMode::Depth2DThin512:
case TileMode::Depth2DThin1K:
case TileMode::Depth1DThin:
case TileMode::Depth2DThinPrt256:
case TileMode::Depth2DThinPrt1K:
case TileMode::DisplayLinearAligned:
case TileMode::Display1DThin:
case TileMode::Display2DThin:
case TileMode::DisplayThinPrt:
case TileMode::Display2DThinPrt:
case TileMode::Thin1DThin:
case TileMode::Thin2DThin:
case TileMode::Thin3DThin:
case TileMode::ThinThinPrt:
case TileMode::Thin2DThinPrt:
case TileMode::Thin3DThinPrt:
case TileMode::Thick1DThick:
case TileMode::Thick2DThick:
case TileMode::Thick3DThick:
case TileMode::ThickThickPrt:
case TileMode::Thick2DThickPrt:
case TileMode::Thick3DThickPrt:
case TileMode::Thick2DXThick:
case TileMode::Thick3DXThick:
return PipeConfig::P16_32x32_8x16;
case TileMode::DisplayLinearGeneral:
return PipeConfig::P2;
default:
UNREACHABLE_MSG("Unknown tile mode = {}", u32(tile_mode));
}
}
u32 GetSampleSplit(TileMode tile_mode) {
switch (tile_mode) {
case TileMode::Depth2DThin64:
case TileMode::Depth2DThin128:
case TileMode::Depth2DThin256:
case TileMode::Depth2DThin512:
case TileMode::Depth2DThin1K:
case TileMode::Depth1DThin:
case TileMode::Depth2DThinPrt256:
case TileMode::Depth2DThinPrt1K:
case TileMode::DisplayLinearAligned:
case TileMode::Display1DThin:
case TileMode::Thin1DThin:
case TileMode::Thick1DThick:
case TileMode::Thick2DThick:
case TileMode::Thick3DThick:
case TileMode::ThickThickPrt:
case TileMode::Thick2DThickPrt:
case TileMode::Thick3DThickPrt:
case TileMode::Thick2DXThick:
case TileMode::Thick3DXThick:
case TileMode::DisplayLinearGeneral:
return 1;
case TileMode::Display2DThin:
case TileMode::DisplayThinPrt:
case TileMode::Display2DThinPrt:
case TileMode::Thin2DThin:
case TileMode::Thin3DThin:
case TileMode::ThinThinPrt:
case TileMode::Thin2DThinPrt:
case TileMode::Thin3DThinPrt:
return 2;
default:
UNREACHABLE_MSG("Unknown tile mode = {}", u32(tile_mode));
}
}
u32 GetTileSplit(TileMode tile_mode) {
switch (tile_mode) {
case TileMode::Depth2DThin64:
case TileMode::Depth1DThin:
case TileMode::DisplayLinearAligned:
case TileMode::Display1DThin:
case TileMode::Display2DThin:
case TileMode::DisplayThinPrt:
case TileMode::Display2DThinPrt:
case TileMode::Thin1DThin:
case TileMode::Thin2DThin:
case TileMode::Thin3DThin:
case TileMode::ThinThinPrt:
case TileMode::Thin2DThinPrt:
case TileMode::Thin3DThinPrt:
case TileMode::Thick1DThick:
case TileMode::Thick2DThick:
case TileMode::Thick3DThick:
case TileMode::ThickThickPrt:
case TileMode::Thick2DThickPrt:
case TileMode::Thick3DThickPrt:
case TileMode::Thick2DXThick:
case TileMode::Thick3DXThick:
case TileMode::DisplayLinearGeneral:
return 64;
case TileMode::Depth2DThin128:
return 128;
case TileMode::Depth2DThin256:
case TileMode::Depth2DThinPrt256:
return 256;
case TileMode::Depth2DThin512:
return 512;
case TileMode::Depth2DThin1K:
case TileMode::Depth2DThinPrt1K:
return 1024;
default:
UNREACHABLE_MSG("Unknown tile mode = {}", u32(tile_mode));
}
}
u32 GetBankWidth(MacroTileMode mode) {
switch (mode) {
case MacroTileMode::Mode_1x4_16:
case MacroTileMode::Mode_1x2_16:
case MacroTileMode::Mode_1x1_16:
case MacroTileMode::Mode_1x1_16_Dup:
case MacroTileMode::Mode_1x1_8:
case MacroTileMode::Mode_1x1_4:
case MacroTileMode::Mode_1x1_2:
case MacroTileMode::Mode_1x1_2_Dup:
case MacroTileMode::Mode_1x8_16:
case MacroTileMode::Mode_1x4_16_Dup:
case MacroTileMode::Mode_1x2_16_Dup:
case MacroTileMode::Mode_1x1_16_Dup2:
case MacroTileMode::Mode_1x1_8_Dup:
case MacroTileMode::Mode_1x1_4_Dup:
case MacroTileMode::Mode_1x1_2_Dup2:
case MacroTileMode::Mode_1x1_2_Dup3:
return 1;
default:
UNREACHABLE_MSG("Unknown macro tile mode = {}", u32(mode));
}
}
u32 GetBankHeight(MacroTileMode mode) {
switch (mode) {
case MacroTileMode::Mode_1x1_16:
case MacroTileMode::Mode_1x1_16_Dup:
case MacroTileMode::Mode_1x1_8:
case MacroTileMode::Mode_1x1_4:
case MacroTileMode::Mode_1x1_2:
case MacroTileMode::Mode_1x1_2_Dup:
case MacroTileMode::Mode_1x1_16_Dup2:
case MacroTileMode::Mode_1x1_8_Dup:
case MacroTileMode::Mode_1x1_4_Dup:
case MacroTileMode::Mode_1x1_2_Dup2:
case MacroTileMode::Mode_1x1_2_Dup3:
return 1;
case MacroTileMode::Mode_1x2_16:
case MacroTileMode::Mode_1x2_16_Dup:
return 2;
case MacroTileMode::Mode_1x4_16:
case MacroTileMode::Mode_1x4_16_Dup:
return 4;
case MacroTileMode::Mode_1x8_16:
return 8;
default:
UNREACHABLE_MSG("Unknown macro tile mode = {}", u32(mode));
}
}
u32 GetNumBanks(MacroTileMode mode) {
switch (mode) {
case MacroTileMode::Mode_1x1_2:
case MacroTileMode::Mode_1x1_2_Dup:
case MacroTileMode::Mode_1x1_2_Dup2:
case MacroTileMode::Mode_1x1_2_Dup3:
return 2;
case MacroTileMode::Mode_1x1_4:
case MacroTileMode::Mode_1x1_4_Dup:
return 4;
case MacroTileMode::Mode_1x1_8:
case MacroTileMode::Mode_1x1_8_Dup:
return 8;
case MacroTileMode::Mode_1x4_16:
case MacroTileMode::Mode_1x2_16:
case MacroTileMode::Mode_1x1_16:
case MacroTileMode::Mode_1x1_16_Dup:
case MacroTileMode::Mode_1x8_16:
case MacroTileMode::Mode_1x4_16_Dup:
case MacroTileMode::Mode_1x2_16_Dup:
case MacroTileMode::Mode_1x1_16_Dup2:
return 16;
default:
UNREACHABLE_MSG("Unknown macro tile mode = {}", u32(mode));
}
}
u32 GetMacrotileAspect(MacroTileMode mode) {
switch (mode) {
case MacroTileMode::Mode_1x1_8:
case MacroTileMode::Mode_1x1_4:
case MacroTileMode::Mode_1x1_2:
case MacroTileMode::Mode_1x1_2_Dup:
case MacroTileMode::Mode_1x1_8_Dup:
case MacroTileMode::Mode_1x1_4_Dup:
case MacroTileMode::Mode_1x1_2_Dup2:
case MacroTileMode::Mode_1x1_2_Dup3:
return 1;
case MacroTileMode::Mode_1x2_16:
case MacroTileMode::Mode_1x1_16:
case MacroTileMode::Mode_1x1_16_Dup:
case MacroTileMode::Mode_1x2_16_Dup:
case MacroTileMode::Mode_1x1_16_Dup2:
return 2;
case MacroTileMode::Mode_1x4_16:
case MacroTileMode::Mode_1x8_16:
case MacroTileMode::Mode_1x4_16_Dup:
return 4;
default:
UNREACHABLE_MSG("Unknown macro tile mode = {}", u32(mode));
}
}
u32 GetAltBankHeight(MacroTileMode mode) {
switch (mode) {
case MacroTileMode::Mode_1x1_8:
case MacroTileMode::Mode_1x1_4:
case MacroTileMode::Mode_1x1_2:
case MacroTileMode::Mode_1x1_2_Dup:
case MacroTileMode::Mode_1x1_16_Dup2:
case MacroTileMode::Mode_1x1_8_Dup:
case MacroTileMode::Mode_1x1_4_Dup:
case MacroTileMode::Mode_1x1_2_Dup2:
case MacroTileMode::Mode_1x1_2_Dup3:
return 1;
case MacroTileMode::Mode_1x1_16:
case MacroTileMode::Mode_1x1_16_Dup:
case MacroTileMode::Mode_1x2_16_Dup:
return 2;
case MacroTileMode::Mode_1x4_16:
case MacroTileMode::Mode_1x2_16:
case MacroTileMode::Mode_1x8_16:
case MacroTileMode::Mode_1x4_16_Dup:
return 4;
default:
UNREACHABLE_MSG("Unknown macro tile mode = {}", u32(mode));
}
}
u32 GetAltNumBanks(MacroTileMode mode) {
switch (mode) {
case MacroTileMode::Mode_1x1_2_Dup:
case MacroTileMode::Mode_1x1_2_Dup2:
case MacroTileMode::Mode_1x1_2_Dup3:
return 2;
case MacroTileMode::Mode_1x1_2:
case MacroTileMode::Mode_1x1_8_Dup:
case MacroTileMode::Mode_1x1_4_Dup:
return 4;
case MacroTileMode::Mode_1x4_16:
case MacroTileMode::Mode_1x2_16:
case MacroTileMode::Mode_1x1_16:
case MacroTileMode::Mode_1x1_16_Dup:
case MacroTileMode::Mode_1x1_8:
case MacroTileMode::Mode_1x1_4:
case MacroTileMode::Mode_1x4_16_Dup:
case MacroTileMode::Mode_1x2_16_Dup:
case MacroTileMode::Mode_1x1_16_Dup2:
return 8;
case MacroTileMode::Mode_1x8_16:
return 16;
default:
UNREACHABLE_MSG("Unknown macro tile mode = {}", u32(mode));
}
}
u32 GetAltMacrotileAspect(MacroTileMode mode) {
switch (mode) {
case MacroTileMode::Mode_1x1_16:
case MacroTileMode::Mode_1x1_16_Dup:
case MacroTileMode::Mode_1x1_8:
case MacroTileMode::Mode_1x1_4:
case MacroTileMode::Mode_1x1_2:
case MacroTileMode::Mode_1x1_2_Dup:
case MacroTileMode::Mode_1x2_16_Dup:
case MacroTileMode::Mode_1x1_16_Dup2:
case MacroTileMode::Mode_1x1_8_Dup:
case MacroTileMode::Mode_1x1_4_Dup:
case MacroTileMode::Mode_1x1_2_Dup2:
case MacroTileMode::Mode_1x1_2_Dup3:
return 1;
case MacroTileMode::Mode_1x4_16:
case MacroTileMode::Mode_1x2_16:
case MacroTileMode::Mode_1x8_16:
case MacroTileMode::Mode_1x4_16_Dup:
return 2;
default:
UNREACHABLE_MSG("Unknown macro tile mode = {}", u32(mode));
}
}
bool IsMacroTiled(ArrayMode array_mode) {
switch (array_mode) {
case ArrayMode::ArrayLinearGeneral:
case ArrayMode::ArrayLinearAligned:
case ArrayMode::Array1DTiledThin1:
case ArrayMode::Array1DTiledThick:
return false;
case ArrayMode::Array2DTiledThin1:
case ArrayMode::ArrayPrtTiledThin1:
case ArrayMode::ArrayPrt2DTiledThin1:
case ArrayMode::Array2DTiledThick:
case ArrayMode::Array2DTiledXThick:
case ArrayMode::ArrayPrtTiledThick:
case ArrayMode::ArrayPrt2DTiledThick:
case ArrayMode::ArrayPrt3DTiledThin1:
case ArrayMode::Array3DTiledThin1:
case ArrayMode::Array3DTiledThick:
case ArrayMode::Array3DTiledXThick:
case ArrayMode::ArrayPrt3DTiledThick:
return true;
default:
UNREACHABLE_MSG("Unknown array mode = {}", u32(array_mode));
}
}
bool IsPrt(ArrayMode array_mode) {
switch (array_mode) {
case ArrayMode::ArrayPrtTiledThin1:
case ArrayMode::ArrayPrtTiledThick:
case ArrayMode::ArrayPrt2DTiledThin1:
case ArrayMode::ArrayPrt2DTiledThick:
case ArrayMode::ArrayPrt3DTiledThin1:
case ArrayMode::ArrayPrt3DTiledThick:
return true;
case ArrayMode::ArrayLinearGeneral:
case ArrayMode::ArrayLinearAligned:
case ArrayMode::Array1DTiledThin1:
case ArrayMode::Array1DTiledThick:
case ArrayMode::Array2DTiledThin1:
case ArrayMode::Array2DTiledThick:
case ArrayMode::Array2DTiledXThick:
case ArrayMode::Array3DTiledThin1:
case ArrayMode::Array3DTiledThick:
case ArrayMode::Array3DTiledXThick:
return false;
default:
UNREACHABLE_MSG("Unknown array mode = {}", u32(array_mode));
}
}
u32 GetMicroTileThickness(ArrayMode array_mode) {
switch (array_mode) {
case ArrayMode::ArrayLinearGeneral:
case ArrayMode::ArrayLinearAligned:
case ArrayMode::Array1DTiledThin1:
case ArrayMode::Array2DTiledThin1:
case ArrayMode::ArrayPrtTiledThin1:
case ArrayMode::ArrayPrt2DTiledThin1:
case ArrayMode::ArrayPrt3DTiledThin1:
case ArrayMode::Array3DTiledThin1:
return 1;
case ArrayMode::Array1DTiledThick:
case ArrayMode::Array2DTiledThick:
case ArrayMode::Array3DTiledThick:
case ArrayMode::ArrayPrtTiledThick:
case ArrayMode::ArrayPrt2DTiledThick:
case ArrayMode::ArrayPrt3DTiledThick:
return 4;
case ArrayMode::Array2DTiledXThick:
case ArrayMode::Array3DTiledXThick:
return 8;
default:
UNREACHABLE_MSG("Unknown array mode = {}", u32(array_mode));
}
}
u32 GetPipeCount(PipeConfig pipe_cfg) {
switch (pipe_cfg) {
case PipeConfig::P2:
return 2;
case PipeConfig::P8_32x32_8x16:
case PipeConfig::P8_32x32_16x16:
return 8;
case PipeConfig::P16_32x32_8x16:
return 16;
default:
UNREACHABLE_MSG("Unknown pipe config = {}", u32(pipe_cfg));
}
}
MacroTileMode CalculateMacrotileMode(TileMode tile_mode, u32 bpp, u32 num_samples) {
ASSERT_MSG(std::has_single_bit(num_samples) && num_samples <= 16, "Invalid sample count {}",
num_samples);
ASSERT_MSG(bpp >= 1 && bpp <= 128, "Invalid bpp {}", bpp);
const ArrayMode array_mode = GetArrayMode(tile_mode);
ASSERT_MSG(IsMacroTiled(array_mode), "Tile mode not macro tiled");
const MicroTileMode micro_tile_mode = GetMicroTileMode(tile_mode);
const u32 sample_split = GetSampleSplit(tile_mode);
const u32 tile_split_hw = GetTileSplit(tile_mode);
const u32 tile_thickness = GetMicroTileThickness(array_mode);
const u32 tile_bytes_1x = bpp * MICROTILE_SIZE * MICROTILE_SIZE * tile_thickness / 8;
const u32 color_tile_split = std::max(256U, sample_split * tile_bytes_1x);
const u32 tile_split =
micro_tile_mode == MicroTileMode::Depth ? tile_split_hw : color_tile_split;
const u32 tilesplic = std::min(DRAM_ROW_SIZE, tile_split);
const u32 tile_bytes = std::min(tilesplic, num_samples * tile_bytes_1x);
const u32 mtm_idx = std::bit_width(tile_bytes / 64) - 1;
return IsPrt(array_mode) ? MacroTileMode(mtm_idx + 8) : MacroTileMode(mtm_idx);
}
} // namespace AmdGpu

View File

@@ -0,0 +1,149 @@
// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <string_view>
#include "common/types.h"
namespace AmdGpu {
struct Image;
static constexpr size_t NUM_TILE_MODES = 32;
enum class PipeConfig : u32 {
P2 = 0,
P4_8x16 = 4,
P4_16x16 = 5,
P4_16x32 = 6,
P4_32x32 = 7,
P8_16x16_8x16 = 8,
P8_16x32_8x16 = 9,
P8_32x32_8x16 = 10,
P8_16x32_16x16 = 11,
P8_32x32_16x16 = 12,
P8_32x32_16x32 = 13,
P8_32x64_32x32 = 14,
P16_32x32_8x16 = 16,
P16_32x32_16x16 = 17,
P16 = 18,
};
enum class MicroTileMode : u32 {
Display = 0,
Thin = 1,
Depth = 2,
Rotated = 3,
Thick = 4,
};
enum class MacroTileMode : u32 {
Mode_1x4_16 = 0,
Mode_1x2_16 = 1,
Mode_1x1_16 = 2,
Mode_1x1_16_Dup = 3,
Mode_1x1_8 = 4,
Mode_1x1_4 = 5,
Mode_1x1_2 = 6,
Mode_1x1_2_Dup = 7,
Mode_1x8_16 = 8,
Mode_1x4_16_Dup = 9,
Mode_1x2_16_Dup = 10,
Mode_1x1_16_Dup2 = 11,
Mode_1x1_8_Dup = 12,
Mode_1x1_4_Dup = 13,
Mode_1x1_2_Dup2 = 14,
Mode_1x1_2_Dup3 = 15,
};
enum class ArrayMode : u32 {
ArrayLinearGeneral = 0,
ArrayLinearAligned = 1,
Array1DTiledThin1 = 2,
Array1DTiledThick = 3,
Array2DTiledThin1 = 4,
ArrayPrtTiledThin1 = 5,
ArrayPrt2DTiledThin1 = 6,
Array2DTiledThick = 7,
Array2DTiledXThick = 8,
ArrayPrtTiledThick = 9,
ArrayPrt2DTiledThick = 10,
ArrayPrt3DTiledThin1 = 11,
Array3DTiledThin1 = 12,
Array3DTiledThick = 13,
Array3DTiledXThick = 14,
ArrayPrt3DTiledThick = 15,
};
enum class TileMode : u32 {
Depth2DThin64 = 0,
Depth2DThin128 = 1,
Depth2DThin256 = 2,
Depth2DThin512 = 3,
Depth2DThin1K = 4,
Depth1DThin = 5,
Depth2DThinPrt256 = 6,
Depth2DThinPrt1K = 7,
DisplayLinearAligned = 8,
Display1DThin = 9,
Display2DThin = 10,
DisplayThinPrt = 11,
Display2DThinPrt = 12,
Thin1DThin = 13,
Thin2DThin = 14,
Thin3DThin = 15,
ThinThinPrt = 16,
Thin2DThinPrt = 17,
Thin3DThinPrt = 18,
Thick1DThick = 19,
Thick2DThick = 20,
Thick3DThick = 21,
ThickThickPrt = 22,
Thick2DThickPrt = 23,
Thick3DThickPrt = 24,
Thick2DXThick = 25,
Thick3DXThick = 26,
DisplayLinearGeneral = 31,
};
std::string_view NameOf(TileMode tile_mode);
ArrayMode GetArrayMode(TileMode tile_mode);
MicroTileMode GetMicroTileMode(TileMode tile_mode);
PipeConfig GetPipeConfig(TileMode tile_mode);
PipeConfig GetAltPipeConfig(TileMode tile_mode);
u32 GetSampleSplit(TileMode tile_mode);
u32 GetTileSplit(TileMode tile_mode);
u32 GetBankWidth(MacroTileMode mode);
u32 GetBankHeight(MacroTileMode mode);
u32 GetNumBanks(MacroTileMode mode);
u32 GetMacrotileAspect(MacroTileMode mode);
u32 GetAltBankHeight(MacroTileMode mode);
u32 GetAltNumBanks(MacroTileMode mode);
u32 GetAltMacrotileAspect(MacroTileMode mode);
bool IsMacroTiled(ArrayMode array_mode);
bool IsPrt(ArrayMode array_mode);
u32 GetMicroTileThickness(ArrayMode array_mode);
u32 GetPipeCount(PipeConfig pipe_cfg);
MacroTileMode CalculateMacrotileMode(TileMode tile_mode, u32 bpp, u32 num_samples);
} // namespace AmdGpu