[D3D12] Allow different loading modes for unsigned and signed textures

This commit is contained in:
Triang3l 2018-11-14 13:51:20 +03:00
parent b4706054d0
commit 8ff03bcfa0
2 changed files with 339 additions and 229 deletions

View File

@ -43,6 +43,7 @@ namespace d3d12 {
#include "xenia/gpu/d3d12/shaders/dxbc/texture_load_dxt5_rgba8_cs.h" #include "xenia/gpu/d3d12/shaders/dxbc/texture_load_dxt5_rgba8_cs.h"
#include "xenia/gpu/d3d12/shaders/dxbc/texture_load_dxt5a_r8_cs.h" #include "xenia/gpu/d3d12/shaders/dxbc/texture_load_dxt5a_r8_cs.h"
#include "xenia/gpu/d3d12/shaders/dxbc/texture_load_r11g11b10_rgba16_cs.h" #include "xenia/gpu/d3d12/shaders/dxbc/texture_load_r11g11b10_rgba16_cs.h"
#include "xenia/gpu/d3d12/shaders/dxbc/texture_load_r11g11b10_rgba16_snorm_cs.h"
#include "xenia/gpu/d3d12/shaders/dxbc/texture_tile_128bpp_cs.h" #include "xenia/gpu/d3d12/shaders/dxbc/texture_tile_128bpp_cs.h"
#include "xenia/gpu/d3d12/shaders/dxbc/texture_tile_16bpp_cs.h" #include "xenia/gpu/d3d12/shaders/dxbc/texture_tile_16bpp_cs.h"
#include "xenia/gpu/d3d12/shaders/dxbc/texture_tile_16bpp_rgba_cs.h" #include "xenia/gpu/d3d12/shaders/dxbc/texture_tile_16bpp_rgba_cs.h"
@ -55,280 +56,283 @@ constexpr uint32_t TextureCache::LoadConstants::kGuestPitchTiled;
const TextureCache::HostFormat TextureCache::host_formats_[64] = { const TextureCache::HostFormat TextureCache::host_formats_[64] = {
// k_1_REVERSE // k_1_REVERSE
{DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, {DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown,
LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown}, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown},
// k_1 // k_1
{DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, {DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown,
LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown}, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown},
// k_8 // k_8
{DXGI_FORMAT_R8_TYPELESS, DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8_SNORM, {DXGI_FORMAT_R8_TYPELESS, DXGI_FORMAT_R8_UNORM, LoadMode::k8bpb,
LoadMode::k8bpb, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_R8_SNORM, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_R8_UNORM, ResolveTileMode::k8bpp}, LoadMode::kUnknown, DXGI_FORMAT_R8_UNORM, ResolveTileMode::k8bpp},
// k_1_5_5_5 // k_1_5_5_5
{DXGI_FORMAT_B5G5R5A1_UNORM, DXGI_FORMAT_B5G5R5A1_UNORM, {DXGI_FORMAT_B5G5R5A1_UNORM, DXGI_FORMAT_B5G5R5A1_UNORM, LoadMode::k16bpb,
DXGI_FORMAT_UNKNOWN, LoadMode::k16bpb, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN,
LoadMode::kUnknown, DXGI_FORMAT_R8G8B8A8_UNORM, LoadMode::kUnknown, DXGI_FORMAT_R8G8B8A8_UNORM,
ResolveTileMode::k16bppRGBA}, ResolveTileMode::k16bppRGBA},
// k_5_6_5 // k_5_6_5
{DXGI_FORMAT_B5G6R5_UNORM, DXGI_FORMAT_B5G6R5_UNORM, DXGI_FORMAT_UNKNOWN, {DXGI_FORMAT_B5G6R5_UNORM, DXGI_FORMAT_B5G6R5_UNORM, LoadMode::k16bpb,
LoadMode::k16bpb, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_B5G6R5_UNORM, ResolveTileMode::k16bpp}, LoadMode::kUnknown, DXGI_FORMAT_B5G6R5_UNORM, ResolveTileMode::k16bpp},
// k_6_5_5 // k_6_5_5
{DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, {DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown,
LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown}, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown},
// k_8_8_8_8 // k_8_8_8_8
{DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_UNORM, {DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_UNORM,
DXGI_FORMAT_R8G8B8A8_SNORM, LoadMode::k32bpb, DXGI_FORMAT_UNKNOWN, LoadMode::k32bpb, DXGI_FORMAT_R8G8B8A8_SNORM, LoadMode::kUnknown,
LoadMode::kUnknown, DXGI_FORMAT_R8G8B8A8_UNORM, ResolveTileMode::k32bpp}, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_R8G8B8A8_UNORM,
ResolveTileMode::k32bpp},
// k_2_10_10_10 // k_2_10_10_10
{DXGI_FORMAT_R10G10B10A2_TYPELESS, DXGI_FORMAT_R10G10B10A2_UNORM, {DXGI_FORMAT_R10G10B10A2_TYPELESS, DXGI_FORMAT_R10G10B10A2_UNORM,
DXGI_FORMAT_UNKNOWN, LoadMode::k32bpb, DXGI_FORMAT_UNKNOWN, LoadMode::k32bpb, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown,
LoadMode::kUnknown, DXGI_FORMAT_R10G10B10A2_UNORM, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_R10G10B10A2_UNORM,
ResolveTileMode::k32bpp}, ResolveTileMode::k32bpp},
// k_8_A // k_8_A
{DXGI_FORMAT_R8_TYPELESS, DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8_SNORM, {DXGI_FORMAT_R8_TYPELESS, DXGI_FORMAT_R8_UNORM, LoadMode::k8bpb,
LoadMode::k8bpb, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_R8_SNORM, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_R8_UNORM, ResolveTileMode::k8bpp}, LoadMode::kUnknown, DXGI_FORMAT_R8_UNORM, ResolveTileMode::k8bpp},
// k_8_B // k_8_B
{DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, {DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown,
LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown}, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown},
// k_8_8 // k_8_8
{DXGI_FORMAT_R8G8_TYPELESS, DXGI_FORMAT_R8G8_UNORM, DXGI_FORMAT_R8G8_SNORM, {DXGI_FORMAT_R8G8_TYPELESS, DXGI_FORMAT_R8G8_UNORM, LoadMode::k16bpb,
LoadMode::k16bpb, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_R8G8_SNORM, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_R8G8_UNORM, ResolveTileMode::k16bpp}, LoadMode::kUnknown, DXGI_FORMAT_R8G8_UNORM, ResolveTileMode::k16bpp},
// k_Cr_Y1_Cb_Y0_REP // k_Cr_Y1_Cb_Y0_REP
{DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, {DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown,
LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown}, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown},
// k_Y1_Cr_Y0_Cb_REP // k_Y1_Cr_Y0_Cb_REP
{DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, {DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown,
LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown}, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown},
// k_16_16_EDRAM // k_16_16_EDRAM
// Not usable as a texture, also has -32...32 range. // Not usable as a texture, also has -32...32 range.
{DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, {DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown,
LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown}, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown},
// k_8_8_8_8_A // k_8_8_8_8_A
{DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, {DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown,
LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown}, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown},
// k_4_4_4_4 // k_4_4_4_4
{DXGI_FORMAT_B4G4R4A4_UNORM, DXGI_FORMAT_B4G4R4A4_UNORM, {DXGI_FORMAT_B4G4R4A4_UNORM, DXGI_FORMAT_B4G4R4A4_UNORM, LoadMode::k16bpb,
DXGI_FORMAT_UNKNOWN, LoadMode::k16bpb, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN,
LoadMode::kUnknown, DXGI_FORMAT_R8G8B8A8_UNORM, LoadMode::kUnknown, DXGI_FORMAT_R8G8B8A8_UNORM,
ResolveTileMode::k16bppRGBA}, ResolveTileMode::k16bppRGBA},
// k_10_11_11 // k_10_11_11
{DXGI_FORMAT_R16G16B16A16_TYPELESS, DXGI_FORMAT_R16G16B16A16_UNORM, {DXGI_FORMAT_R16G16B16A16_TYPELESS, DXGI_FORMAT_R16G16B16A16_UNORM,
DXGI_FORMAT_UNKNOWN, LoadMode::kR11G11B10ToRGBA16, DXGI_FORMAT_UNKNOWN, LoadMode::kR11G11B10ToRGBA16, DXGI_FORMAT_R16G16B16A16_SNORM,
LoadMode::kUnknown, DXGI_FORMAT_R16G16B16A16_UNORM, LoadMode::kR11G11B10ToRGBA16SNorm, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown,
ResolveTileMode::kR11G11B10AsRGBA16}, DXGI_FORMAT_R16G16B16A16_UNORM, ResolveTileMode::kR11G11B10AsRGBA16},
// k_11_11_10 // k_11_11_10
{DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, {DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown,
LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown}, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown},
// k_DXT1 // k_DXT1
{DXGI_FORMAT_BC1_UNORM, DXGI_FORMAT_BC1_UNORM, DXGI_FORMAT_UNKNOWN, {DXGI_FORMAT_BC1_UNORM, DXGI_FORMAT_BC1_UNORM, LoadMode::k64bpb,
LoadMode::k64bpb, DXGI_FORMAT_R8G8B8A8_UNORM, LoadMode::kDXT1ToRGBA8, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_R8G8B8A8_UNORM,
DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown}, LoadMode::kDXT1ToRGBA8, DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown},
// k_DXT2_3 // k_DXT2_3
{DXGI_FORMAT_BC2_UNORM, DXGI_FORMAT_BC2_UNORM, DXGI_FORMAT_UNKNOWN, {DXGI_FORMAT_BC2_UNORM, DXGI_FORMAT_BC2_UNORM, LoadMode::k128bpb,
LoadMode::k128bpb, DXGI_FORMAT_R8G8B8A8_UNORM, LoadMode::kDXT3ToRGBA8, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_R8G8B8A8_UNORM,
DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown}, LoadMode::kDXT3ToRGBA8, DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown},
// k_DXT4_5 // k_DXT4_5
{DXGI_FORMAT_BC3_UNORM, DXGI_FORMAT_BC3_UNORM, DXGI_FORMAT_UNKNOWN, {DXGI_FORMAT_BC3_UNORM, DXGI_FORMAT_BC3_UNORM, LoadMode::k128bpb,
LoadMode::k128bpb, DXGI_FORMAT_R8G8B8A8_UNORM, LoadMode::kDXT5ToRGBA8, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_R8G8B8A8_UNORM,
DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown}, LoadMode::kDXT5ToRGBA8, DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown},
// k_16_16_16_16_EDRAM // k_16_16_16_16_EDRAM
// Not usable as a texture, also has -32...32 range. // Not usable as a texture, also has -32...32 range.
{DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, {DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown,
LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown}, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown},
// R32_FLOAT for depth because shaders would require an additional SRV to // R32_FLOAT for depth because shaders would require an additional SRV to
// sample stencil, which we don't provide. // sample stencil, which we don't provide.
// k_24_8 // k_24_8
{DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_R32_FLOAT, {DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_R32_FLOAT, LoadMode::kDepthUnorm,
LoadMode::kDepthUnorm, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_R32_FLOAT, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown}, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown},
// k_24_8_FLOAT // k_24_8_FLOAT
{DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_R32_FLOAT, {DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_R32_FLOAT, LoadMode::kDepthFloat,
LoadMode::kDepthFloat, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_R32_FLOAT, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown}, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown},
// k_16 // k_16
{DXGI_FORMAT_R16_TYPELESS, DXGI_FORMAT_R16_UNORM, DXGI_FORMAT_R16_SNORM, {DXGI_FORMAT_R16_TYPELESS, DXGI_FORMAT_R16_UNORM, LoadMode::k16bpb,
LoadMode::k16bpb, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_R16_SNORM, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_R16_UNORM, ResolveTileMode::k16bpp}, LoadMode::kUnknown, DXGI_FORMAT_R16_UNORM, ResolveTileMode::k16bpp},
// k_16_16 // k_16_16
// TODO(Triang3l): Check if this is the correct way of specifying a signed // TODO(Triang3l): Check if this is the correct way of specifying a signed
// resolve destination format. // resolve destination format.
{DXGI_FORMAT_R16G16_TYPELESS, DXGI_FORMAT_R16G16_UNORM, {DXGI_FORMAT_R16G16_TYPELESS, DXGI_FORMAT_R16G16_UNORM, LoadMode::k32bpb,
DXGI_FORMAT_R16G16_SNORM, LoadMode::k32bpb, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R16G16_SNORM, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN,
LoadMode::kUnknown, DXGI_FORMAT_R16G16_SNORM, ResolveTileMode::k32bpp}, LoadMode::kUnknown, DXGI_FORMAT_R16G16_SNORM, ResolveTileMode::k32bpp},
// k_16_16_16_16 // k_16_16_16_16
// TODO(Triang3l): Check if this is the correct way of specifying a signed // TODO(Triang3l): Check if this is the correct way of specifying a signed
// resolve destination format. // resolve destination format.
{DXGI_FORMAT_R16G16B16A16_TYPELESS, DXGI_FORMAT_R16G16B16A16_UNORM, {DXGI_FORMAT_R16G16B16A16_TYPELESS, DXGI_FORMAT_R16G16B16A16_UNORM,
DXGI_FORMAT_R16G16B16A16_SNORM, LoadMode::k64bpb, DXGI_FORMAT_UNKNOWN, LoadMode::k64bpb, DXGI_FORMAT_R16G16B16A16_SNORM, LoadMode::kUnknown,
LoadMode::kUnknown, DXGI_FORMAT_R16G16B16A16_SNORM, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_R16G16B16A16_SNORM,
ResolveTileMode::k64bpp}, ResolveTileMode::k64bpp},
// k_16_EXPAND // k_16_EXPAND
{DXGI_FORMAT_R16_FLOAT, DXGI_FORMAT_R16_FLOAT, DXGI_FORMAT_R16_FLOAT, {DXGI_FORMAT_R16_FLOAT, DXGI_FORMAT_R16_FLOAT, LoadMode::k16bpb,
LoadMode::k16bpb, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_R16_FLOAT, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_R16_FLOAT, ResolveTileMode::k16bpp}, LoadMode::kUnknown, DXGI_FORMAT_R16_FLOAT, ResolveTileMode::k16bpp},
// k_16_16_EXPAND // k_16_16_EXPAND
{DXGI_FORMAT_R16G16_FLOAT, DXGI_FORMAT_R16G16_FLOAT, {DXGI_FORMAT_R16G16_FLOAT, DXGI_FORMAT_R16G16_FLOAT, LoadMode::k32bpb,
DXGI_FORMAT_R16G16_FLOAT, LoadMode::k32bpb, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R16G16_FLOAT, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN,
LoadMode::kUnknown, DXGI_FORMAT_R16G16_FLOAT, ResolveTileMode::k32bpp}, LoadMode::kUnknown, DXGI_FORMAT_R16G16_FLOAT, ResolveTileMode::k32bpp},
// k_16_16_16_16_EXPAND // k_16_16_16_16_EXPAND
{DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, {DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT,
DXGI_FORMAT_R16G16B16A16_FLOAT, LoadMode::k64bpb, DXGI_FORMAT_UNKNOWN, LoadMode::k64bpb, DXGI_FORMAT_R16G16B16A16_FLOAT, LoadMode::kUnknown,
LoadMode::kUnknown, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_R16G16B16A16_FLOAT,
ResolveTileMode::k64bpp}, ResolveTileMode::k64bpp},
// k_16_FLOAT // k_16_FLOAT
{DXGI_FORMAT_R16_FLOAT, DXGI_FORMAT_R16_FLOAT, DXGI_FORMAT_R16_FLOAT, {DXGI_FORMAT_R16_FLOAT, DXGI_FORMAT_R16_FLOAT, LoadMode::k16bpb,
LoadMode::k16bpb, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_R16_FLOAT, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_R16_FLOAT, ResolveTileMode::k16bpp}, LoadMode::kUnknown, DXGI_FORMAT_R16_FLOAT, ResolveTileMode::k16bpp},
// k_16_16_FLOAT // k_16_16_FLOAT
{DXGI_FORMAT_R16G16_FLOAT, DXGI_FORMAT_R16G16_FLOAT, {DXGI_FORMAT_R16G16_FLOAT, DXGI_FORMAT_R16G16_FLOAT, LoadMode::k32bpb,
DXGI_FORMAT_R16G16_FLOAT, LoadMode::k32bpb, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R16G16_FLOAT, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN,
LoadMode::kUnknown, DXGI_FORMAT_R16G16_FLOAT, ResolveTileMode::k32bpp}, LoadMode::kUnknown, DXGI_FORMAT_R16G16_FLOAT, ResolveTileMode::k32bpp},
// k_16_16_16_16_FLOAT // k_16_16_16_16_FLOAT
{DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, {DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT,
DXGI_FORMAT_R16G16B16A16_FLOAT, LoadMode::k64bpb, DXGI_FORMAT_UNKNOWN, LoadMode::k64bpb, DXGI_FORMAT_R16G16B16A16_FLOAT, LoadMode::kUnknown,
LoadMode::kUnknown, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_R16G16B16A16_FLOAT,
ResolveTileMode::k64bpp}, ResolveTileMode::k64bpp},
// k_32 // k_32
{DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, {DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown,
LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown}, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown},
// k_32_32 // k_32_32
{DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, {DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown,
LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown}, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown},
// k_32_32_32_32 // k_32_32_32_32
{DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, {DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown,
LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown}, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown},
// k_32_FLOAT // k_32_FLOAT
{DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_R32_FLOAT, {DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_R32_FLOAT, LoadMode::k32bpb,
LoadMode::k32bpb, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_R32_FLOAT, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_R32_FLOAT, ResolveTileMode::k32bpp}, LoadMode::kUnknown, DXGI_FORMAT_R32_FLOAT, ResolveTileMode::k32bpp},
// k_32_32_FLOAT // k_32_32_FLOAT
{DXGI_FORMAT_R32G32_FLOAT, DXGI_FORMAT_R32G32_FLOAT, {DXGI_FORMAT_R32G32_FLOAT, DXGI_FORMAT_R32G32_FLOAT, LoadMode::k64bpb,
DXGI_FORMAT_R32G32_FLOAT, LoadMode::k64bpb, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R32G32_FLOAT, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN,
LoadMode::kUnknown, DXGI_FORMAT_R32G32_FLOAT, ResolveTileMode::k64bpp}, LoadMode::kUnknown, DXGI_FORMAT_R32G32_FLOAT, ResolveTileMode::k64bpp},
// k_32_32_32_32_FLOAT // k_32_32_32_32_FLOAT
{DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, {DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT,
DXGI_FORMAT_R32G32B32A32_FLOAT, LoadMode::k128bpb, DXGI_FORMAT_UNKNOWN, LoadMode::k128bpb, DXGI_FORMAT_R32G32B32A32_FLOAT, LoadMode::kUnknown,
LoadMode::kUnknown, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_R32G32B32A32_FLOAT,
ResolveTileMode::k128bpp}, ResolveTileMode::k128bpp},
// k_32_AS_8 // k_32_AS_8
{DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, {DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown,
LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown}, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown},
// k_32_AS_8_8 // k_32_AS_8_8
{DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, {DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown,
LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown}, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown},
// k_16_MPEG // k_16_MPEG
{DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, {DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown,
LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown}, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown},
// k_16_16_MPEG // k_16_16_MPEG
{DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, {DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown,
LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown}, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown},
// k_8_INTERLACED // k_8_INTERLACED
{DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, {DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown,
LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown}, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown},
// k_32_AS_8_INTERLACED // k_32_AS_8_INTERLACED
{DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, {DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown,
LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown}, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown},
// k_32_AS_8_8_INTERLACED // k_32_AS_8_8_INTERLACED
{DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, {DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown,
LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown}, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown},
// k_16_INTERLACED // k_16_INTERLACED
{DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, {DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown,
LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown}, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown},
// k_16_MPEG_INTERLACED // k_16_MPEG_INTERLACED
{DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, {DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown,
LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown}, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown},
// k_16_16_MPEG_INTERLACED // k_16_16_MPEG_INTERLACED
{DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, {DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown,
LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown}, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown},
// k_DXN // k_DXN
{DXGI_FORMAT_BC5_UNORM, DXGI_FORMAT_BC5_UNORM, DXGI_FORMAT_UNKNOWN, {DXGI_FORMAT_BC5_UNORM, DXGI_FORMAT_BC5_UNORM, LoadMode::k128bpb,
LoadMode::k128bpb, DXGI_FORMAT_R8G8_UNORM, LoadMode::kDXNToRG8, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_R8G8_UNORM,
DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown}, LoadMode::kDXNToRG8, DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown},
// k_8_8_8_8_AS_16_16_16_16 // k_8_8_8_8_AS_16_16_16_16
{DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_UNORM, {DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_UNORM,
DXGI_FORMAT_R8G8B8A8_SNORM, LoadMode::k32bpb, DXGI_FORMAT_UNKNOWN, LoadMode::k32bpb, DXGI_FORMAT_R8G8B8A8_SNORM, LoadMode::kUnknown,
LoadMode::kUnknown, DXGI_FORMAT_R8G8B8A8_UNORM, ResolveTileMode::k32bpp}, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_R8G8B8A8_UNORM,
ResolveTileMode::k32bpp},
// k_DXT1_AS_16_16_16_16 // k_DXT1_AS_16_16_16_16
{DXGI_FORMAT_BC1_UNORM, DXGI_FORMAT_BC1_UNORM, DXGI_FORMAT_UNKNOWN, {DXGI_FORMAT_BC1_UNORM, DXGI_FORMAT_BC1_UNORM, LoadMode::k64bpb,
LoadMode::k64bpb, DXGI_FORMAT_R8G8B8A8_UNORM, LoadMode::kDXT1ToRGBA8, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_R8G8B8A8_UNORM,
DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown}, LoadMode::kDXT1ToRGBA8, DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown},
// k_DXT2_3_AS_16_16_16_16 // k_DXT2_3_AS_16_16_16_16
{DXGI_FORMAT_BC2_UNORM, DXGI_FORMAT_BC2_UNORM, DXGI_FORMAT_UNKNOWN, {DXGI_FORMAT_BC2_UNORM, DXGI_FORMAT_BC2_UNORM, LoadMode::k128bpb,
LoadMode::k128bpb, DXGI_FORMAT_R8G8B8A8_UNORM, LoadMode::kDXT3ToRGBA8, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_R8G8B8A8_UNORM,
DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown}, LoadMode::kDXT3ToRGBA8, DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown},
// k_DXT4_5_AS_16_16_16_16 // k_DXT4_5_AS_16_16_16_16
{DXGI_FORMAT_BC3_UNORM, DXGI_FORMAT_BC3_UNORM, DXGI_FORMAT_UNKNOWN, {DXGI_FORMAT_BC3_UNORM, DXGI_FORMAT_BC3_UNORM, LoadMode::k128bpb,
LoadMode::k128bpb, DXGI_FORMAT_R8G8B8A8_UNORM, LoadMode::kDXT5ToRGBA8, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_R8G8B8A8_UNORM,
DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown}, LoadMode::kDXT5ToRGBA8, DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown},
// k_2_10_10_10_AS_16_16_16_16 // k_2_10_10_10_AS_16_16_16_16
{DXGI_FORMAT_R10G10B10A2_UNORM, DXGI_FORMAT_R10G10B10A2_UNORM, {DXGI_FORMAT_R10G10B10A2_UNORM, DXGI_FORMAT_R10G10B10A2_UNORM,
DXGI_FORMAT_UNKNOWN, LoadMode::k32bpb, DXGI_FORMAT_UNKNOWN, LoadMode::k32bpb, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown,
LoadMode::kUnknown, DXGI_FORMAT_R10G10B10A2_UNORM, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_R10G10B10A2_UNORM,
ResolveTileMode::k32bpp}, ResolveTileMode::k32bpp},
// k_10_11_11_AS_16_16_16_16 // k_10_11_11_AS_16_16_16_16
{DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, {DXGI_FORMAT_R16G16B16A16_TYPELESS, DXGI_FORMAT_R16G16B16A16_UNORM,
LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, LoadMode::kR11G11B10ToRGBA16, DXGI_FORMAT_R16G16B16A16_SNORM,
DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown}, LoadMode::kR11G11B10ToRGBA16SNorm, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown,
DXGI_FORMAT_R16G16B16A16_UNORM, ResolveTileMode::kR11G11B10AsRGBA16},
// k_11_11_10_AS_16_16_16_16 // k_11_11_10_AS_16_16_16_16
{DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, {DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown,
LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown}, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown},
// k_32_32_32_FLOAT // k_32_32_32_FLOAT
{DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, {DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown,
LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown}, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown},
// k_DXT3A // k_DXT3A
{DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_UNKNOWN, {DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8_UNORM, LoadMode::kDXT3A,
LoadMode::kDXT3A, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown}, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown},
// k_DXT5A // k_DXT5A
{DXGI_FORMAT_BC4_UNORM, DXGI_FORMAT_BC4_UNORM, DXGI_FORMAT_UNKNOWN, {DXGI_FORMAT_BC4_UNORM, DXGI_FORMAT_BC4_UNORM, LoadMode::k64bpb,
LoadMode::k64bpb, DXGI_FORMAT_R8_UNORM, LoadMode::kDXT5AToR8, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_R8_UNORM,
DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown}, LoadMode::kDXT5AToR8, DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown},
// k_CTX1 // k_CTX1
{DXGI_FORMAT_R8G8_UNORM, DXGI_FORMAT_R8G8_UNORM, DXGI_FORMAT_UNKNOWN, {DXGI_FORMAT_R8G8_UNORM, DXGI_FORMAT_R8G8_UNORM, LoadMode::kCTX1,
LoadMode::kCTX1, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown}, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown},
// k_DXT3A_AS_1_1_1_1 // k_DXT3A_AS_1_1_1_1
{DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, {DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown,
LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown}, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown},
// k_8_8_8_8_GAMMA_EDRAM // k_8_8_8_8_GAMMA_EDRAM
// Not usable as a texture. // Not usable as a texture.
{DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, {DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown,
LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown}, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown},
// k_2_10_10_10_FLOAT_EDRAM // k_2_10_10_10_FLOAT_EDRAM
// Not usable as a texture. // Not usable as a texture.
{DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, {DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown,
LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown}, LoadMode::kUnknown, DXGI_FORMAT_UNKNOWN, ResolveTileMode::kUnknown},
}; };
const char* const TextureCache::dimension_names_[4] = {"1D", "2D", "3D", const char* const TextureCache::dimension_names_[4] = {"1D", "2D", "3D",
@ -342,6 +346,8 @@ const TextureCache::LoadModeInfo TextureCache::load_mode_info_[] = {
{texture_load_128bpb_cs, sizeof(texture_load_128bpb_cs)}, {texture_load_128bpb_cs, sizeof(texture_load_128bpb_cs)},
{texture_load_r11g11b10_rgba16_cs, {texture_load_r11g11b10_rgba16_cs,
sizeof(texture_load_r11g11b10_rgba16_cs)}, sizeof(texture_load_r11g11b10_rgba16_cs)},
{texture_load_r11g11b10_rgba16_snorm_cs,
sizeof(texture_load_r11g11b10_rgba16_snorm_cs)},
{texture_load_dxt1_rgba8_cs, sizeof(texture_load_dxt1_rgba8_cs)}, {texture_load_dxt1_rgba8_cs, sizeof(texture_load_dxt1_rgba8_cs)},
{texture_load_dxt3_rgba8_cs, sizeof(texture_load_dxt3_rgba8_cs)}, {texture_load_dxt3_rgba8_cs, sizeof(texture_load_dxt3_rgba8_cs)},
{texture_load_dxt5_rgba8_cs, sizeof(texture_load_dxt5_rgba8_cs)}, {texture_load_dxt5_rgba8_cs, sizeof(texture_load_dxt5_rgba8_cs)},
@ -556,19 +562,60 @@ void TextureCache::RequestTextures(uint32_t used_vertex_texture_mask,
auto group = auto group =
reinterpret_cast<const xenos::xe_gpu_fetch_group_t*>(&regs.values[r]); reinterpret_cast<const xenos::xe_gpu_fetch_group_t*>(&regs.values[r]);
TextureKey old_key = binding.key; TextureKey old_key = binding.key;
bool old_has_unsigned = binding.has_unsigned;
bool old_has_signed = binding.has_signed;
BindingInfoFromFetchConstant(group->texture_fetch, binding.key, BindingInfoFromFetchConstant(group->texture_fetch, binding.key,
&binding.swizzle, &binding.has_unsigned, &binding.swizzle, &binding.has_unsigned,
&binding.has_signed); &binding.has_signed);
texture_keys_in_sync_ |= index_bit; texture_keys_in_sync_ |= index_bit;
if (binding.key.IsInvalid()) { if (binding.key.IsInvalid()) {
binding.texture = nullptr; binding.texture = nullptr;
binding.texture_signed = nullptr;
continue; continue;
} }
if (binding.key != old_key) {
// Check if need to load the unsigned and the signed versions of the texture
// (if the format is emulated with different host bit representations for
// signed and unsigned - otherwise only the unsigned one is loaded).
bool key_changed = binding.key != old_key;
bool load_unsigned_data = false, load_signed_data = false;
if (IsSignedVersionSeparate(binding.key.format)) {
// Can reuse previously loaded unsigned/signed versions if the key is the
// same and the texture was previously bound as unsigned/signed
// respectively (checking the previous values of has_unsigned/has_signed
// rather than binding.texture != nullptr and binding.texture_signed !=
// nullptr also prevents repeated attempts to load the texture if it has
// failed to load).
if (binding.has_unsigned) {
if (key_changed || !old_has_unsigned) {
binding.texture = FindOrCreateTexture(binding.key); binding.texture = FindOrCreateTexture(binding.key);
if (binding.texture != nullptr) { load_unsigned_data = true;
}
} else {
binding.texture = nullptr;
}
if (binding.has_signed) {
if (key_changed || !old_has_signed) {
TextureKey signed_key = binding.key;
signed_key.signed_separate = 1;
binding.texture_signed = FindOrCreateTexture(signed_key);
load_signed_data = true;
}
} else {
binding.texture_signed = nullptr;
}
} else {
if (key_changed) {
binding.texture = FindOrCreateTexture(binding.key);
load_unsigned_data = true;
}
binding.texture_signed = nullptr;
}
if (load_unsigned_data && binding.texture != nullptr) {
LoadTextureData(binding.texture); LoadTextureData(binding.texture);
} }
if (load_signed_data && binding.texture_signed != nullptr) {
LoadTextureData(binding.texture_signed);
} }
} }
@ -577,10 +624,7 @@ void TextureCache::RequestTextures(uint32_t used_vertex_texture_mask,
while (xe::bit_scan_forward(used_texture_mask, &index)) { while (xe::bit_scan_forward(used_texture_mask, &index)) {
uint32_t index_bit = 1u << index; uint32_t index_bit = 1u << index;
used_texture_mask &= ~index_bit; used_texture_mask &= ~index_bit;
Texture* texture = texture_bindings_[index].texture;
if (texture == nullptr) {
continue;
}
D3D12_RESOURCE_STATES state = D3D12_RESOURCE_STATES(0); D3D12_RESOURCE_STATES state = D3D12_RESOURCE_STATES(0);
if (used_vertex_texture_mask & index_bit) { if (used_vertex_texture_mask & index_bit) {
state |= D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE; state |= D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
@ -588,9 +632,19 @@ void TextureCache::RequestTextures(uint32_t used_vertex_texture_mask,
if (used_pixel_texture_mask & index_bit) { if (used_pixel_texture_mask & index_bit) {
state |= D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE; state |= D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
} }
command_processor_->PushTransitionBarrier(texture->resource, texture->state,
TextureBinding& binding = texture_bindings_[index];
if (binding.texture != nullptr) {
command_processor_->PushTransitionBarrier(binding.texture->resource,
binding.texture->state, state);
binding.texture->state = state;
}
if (binding.texture_signed != nullptr) {
command_processor_->PushTransitionBarrier(
binding.texture_signed->resource, binding.texture_signed->state,
state); state);
texture->state = state; binding.texture_signed->state = state;
}
} }
} }
@ -621,19 +675,33 @@ uint64_t TextureCache::GetDescriptorHashForActiveTextures(
void TextureCache::WriteTextureSRV(const D3D12Shader::TextureSRV& texture_srv, void TextureCache::WriteTextureSRV(const D3D12Shader::TextureSRV& texture_srv,
D3D12_CPU_DESCRIPTOR_HANDLE handle) { D3D12_CPU_DESCRIPTOR_HANDLE handle) {
const TextureBinding& binding = texture_bindings_[texture_srv.fetch_constant];
ID3D12Resource* resource =
binding.texture != nullptr ? binding.texture->resource : nullptr;
D3D12_SHADER_RESOURCE_VIEW_DESC desc; D3D12_SHADER_RESOURCE_VIEW_DESC desc;
desc.Format = DXGI_FORMAT_UNKNOWN; desc.Format = DXGI_FORMAT_UNKNOWN;
Dimension binding_dimension;
uint32_t mip_max_level, array_size;
ID3D12Resource* resource = nullptr;
const TextureBinding& binding = texture_bindings_[texture_srv.fetch_constant];
if (!binding.key.IsInvalid()) {
TextureFormat format = binding.key.format;
const Texture* texture;
if (IsSignedVersionSeparate(format) && texture_srv.is_signed) {
texture = binding.texture_signed;
} else {
texture = binding.texture;
}
if (texture != nullptr) {
resource = texture->resource;
}
if (texture_srv.is_signed) { if (texture_srv.is_signed) {
// Not supporting signed compressed textures - hopefully DXN and DXT5A are // Not supporting signed compressed textures - hopefully DXN and DXT5A are
// not used as signed. // not used as signed.
if (binding.has_signed || texture_srv.is_sign_required) { if (binding.has_signed || texture_srv.is_sign_required) {
desc.Format = desc.Format = host_formats_[uint32_t(format)].dxgi_format_snorm;
host_formats_[uint32_t(binding.key.format)].dxgi_format_snorm;
if (desc.Format == DXGI_FORMAT_UNKNOWN) { if (desc.Format == DXGI_FORMAT_UNKNOWN) {
unsupported_format_features_used_[uint32_t(binding.key.format)] |= unsupported_format_features_used_[uint32_t(format)] |=
kUnsupportedSnormBit; kUnsupportedSnormBit;
} }
} }
@ -641,28 +709,43 @@ void TextureCache::WriteTextureSRV(const D3D12Shader::TextureSRV& texture_srv,
if (binding.has_unsigned || texture_srv.is_sign_required) { if (binding.has_unsigned || texture_srv.is_sign_required) {
desc.Format = GetDXGIUnormFormat(binding.key); desc.Format = GetDXGIUnormFormat(binding.key);
if (desc.Format == DXGI_FORMAT_UNKNOWN) { if (desc.Format == DXGI_FORMAT_UNKNOWN) {
unsupported_format_features_used_[uint32_t(binding.key.format)] |= unsupported_format_features_used_[uint32_t(format)] |=
kUnsupportedUnormBit; kUnsupportedUnormBit;
} }
} }
} }
if (desc.Format == DXGI_FORMAT_UNKNOWN) {
// A null descriptor must still have a valid format. binding_dimension = binding.key.dimension;
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; mip_max_level = binding.key.mip_max_level;
resource = nullptr; array_size = binding.key.depth;
}
// XE_GPU_SWIZZLE and D3D12_SHADER_COMPONENT_MAPPING are the same except for // XE_GPU_SWIZZLE and D3D12_SHADER_COMPONENT_MAPPING are the same except for
// one bit. // one bit.
desc.Shader4ComponentMapping = desc.Shader4ComponentMapping =
binding.swizzle | binding.swizzle |
D3D12_SHADER_COMPONENT_MAPPING_ALWAYS_SET_BIT_AVOIDING_ZEROMEM_MISTAKES; D3D12_SHADER_COMPONENT_MAPPING_ALWAYS_SET_BIT_AVOIDING_ZEROMEM_MISTAKES;
} else {
binding_dimension = Dimension::k2D;
mip_max_level = 0;
array_size = 1;
desc.Shader4ComponentMapping = D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(
D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0,
D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0,
D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0,
D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0);
}
if (desc.Format == DXGI_FORMAT_UNKNOWN) {
// A null descriptor must still have a valid format.
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
resource = nullptr;
}
switch (texture_srv.dimension) { switch (texture_srv.dimension) {
case TextureDimension::k3D: case TextureDimension::k3D:
desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D; desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D;
desc.Texture3D.MostDetailedMip = 0; desc.Texture3D.MostDetailedMip = 0;
desc.Texture3D.MipLevels = binding.key.mip_max_level + 1; desc.Texture3D.MipLevels = mip_max_level + 1;
desc.Texture3D.ResourceMinLODClamp = 0.0f; desc.Texture3D.ResourceMinLODClamp = 0.0f;
if (binding.key.dimension != Dimension::k3D) { if (binding_dimension != Dimension::k3D) {
// Create a null descriptor so it's safe to sample this texture even // Create a null descriptor so it's safe to sample this texture even
// though it has different dimensions. // though it has different dimensions.
resource = nullptr; resource = nullptr;
@ -671,22 +754,22 @@ void TextureCache::WriteTextureSRV(const D3D12Shader::TextureSRV& texture_srv,
case TextureDimension::kCube: case TextureDimension::kCube:
desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE; desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE;
desc.TextureCube.MostDetailedMip = 0; desc.TextureCube.MostDetailedMip = 0;
desc.TextureCube.MipLevels = binding.key.mip_max_level + 1; desc.TextureCube.MipLevels = mip_max_level + 1;
desc.TextureCube.ResourceMinLODClamp = 0.0f; desc.TextureCube.ResourceMinLODClamp = 0.0f;
if (binding.key.dimension != Dimension::kCube) { if (binding_dimension != Dimension::kCube) {
resource = nullptr; resource = nullptr;
} }
break; break;
default: default:
desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY; desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY;
desc.Texture2DArray.MostDetailedMip = 0; desc.Texture2DArray.MostDetailedMip = 0;
desc.Texture2DArray.MipLevels = binding.key.mip_max_level + 1; desc.Texture2DArray.MipLevels = mip_max_level + 1;
desc.Texture2DArray.FirstArraySlice = 0; desc.Texture2DArray.FirstArraySlice = 0;
desc.Texture2DArray.ArraySize = binding.key.depth; desc.Texture2DArray.ArraySize = array_size;
desc.Texture2DArray.PlaneSlice = 0; desc.Texture2DArray.PlaneSlice = 0;
desc.Texture2DArray.ResourceMinLODClamp = 0.0f; desc.Texture2DArray.ResourceMinLODClamp = 0.0f;
if (binding.key.dimension == Dimension::k3D || if (binding_dimension == Dimension::k3D ||
binding.key.dimension == Dimension::kCube) { binding_dimension == Dimension::kCube) {
resource = nullptr; resource = nullptr;
} }
break; break;
@ -1278,10 +1361,17 @@ bool TextureCache::LoadTextureData(Texture* texture) {
TextureFormat guest_format = texture->key.format; TextureFormat guest_format = texture->key.format;
uint32_t width = texture->key.width; uint32_t width = texture->key.width;
uint32_t height = texture->key.height; uint32_t height = texture->key.height;
bool decompress = IsDecompressionNeeded(guest_format, width, height);
const HostFormat& host_format = host_formats_[uint32_t(guest_format)]; const HostFormat& host_format = host_formats_[uint32_t(guest_format)];
LoadMode load_mode = LoadMode load_mode;
decompress ? host_format.decompress_mode : host_format.load_mode; if (texture->key.signed_separate) {
load_mode = host_format.load_mode_snorm;
} else {
if (IsDecompressionNeeded(guest_format, width, height)) {
load_mode = host_format.decompress_mode;
} else {
load_mode = host_format.load_mode;
}
}
if (load_mode == LoadMode::kUnknown) { if (load_mode == LoadMode::kUnknown) {
return false; return false;
} }

View File

@ -148,6 +148,7 @@ class TextureCache {
k64bpb, k64bpb,
k128bpb, k128bpb,
kR11G11B10ToRGBA16, kR11G11B10ToRGBA16,
kR11G11B10ToRGBA16SNorm,
kDXT1ToRGBA8, kDXT1ToRGBA8,
kDXT3ToRGBA8, kDXT3ToRGBA8,
kDXT5ToRGBA8, kDXT5ToRGBA8,
@ -166,9 +167,6 @@ class TextureCache {
struct LoadModeInfo { struct LoadModeInfo {
const void* shader; const void* shader;
size_t shader_size; size_t shader_size;
// TODO(Triang3l): Whether signed and integer textures need to be separate
// resources loaded differently than unorm textures (k_10_11_11,
// k_11_11_10 because they are expanded to R16G16B16A16).
}; };
// Tiling modes for storing textures after resolving - needed only for the // Tiling modes for storing textures after resolving - needed only for the
@ -206,9 +204,16 @@ class TextureCache {
DXGI_FORMAT dxgi_format_resource; DXGI_FORMAT dxgi_format_resource;
// DXGI format for unsigned normalized or unsigned/signed float SRV. // DXGI format for unsigned normalized or unsigned/signed float SRV.
DXGI_FORMAT dxgi_format_unorm; DXGI_FORMAT dxgi_format_unorm;
// The regular load mode, used when special modes (like signed-specific or
// decompressing) aren't needed.
LoadMode load_mode;
// DXGI format for signed normalized or unsigned/signed float SRV. // DXGI format for signed normalized or unsigned/signed float SRV.
DXGI_FORMAT dxgi_format_snorm; DXGI_FORMAT dxgi_format_snorm;
LoadMode load_mode; // If the signed version needs a different bit representation on the host,
// this is the load mode for the signed version. Otherwise the regular
// load_mode will be used for the signed version, and a single copy will be
// created if both unsigned and signed are used.
LoadMode load_mode_snorm;
// TODO(Triang3l): Integer formats. // TODO(Triang3l): Integer formats.
@ -247,6 +252,9 @@ class TextureCache {
uint32_t mip_max_level : 4; // 78 uint32_t mip_max_level : 4; // 78
TextureFormat format : 6; // 84 TextureFormat format : 6; // 84
Endian endianness : 2; // 86 Endian endianness : 2; // 86
// Whether this texture is signed and has a different host representation
// than an unsigned view of the same guest texture.
uint32_t signed_separate : 1; // 87
}; };
struct { struct {
// The key used for unordered_multimap lookup. Single uint32_t instead of // The key used for unordered_multimap lookup. Single uint32_t instead of
@ -279,7 +287,7 @@ class TextureCache {
map_key[0] = uint32_t(key); map_key[0] = uint32_t(key);
map_key[1] = uint32_t(key >> 32); map_key[1] = uint32_t(key >> 32);
} }
inline bool IsInvalid() { inline bool IsInvalid() const {
// Zero base and zero width is enough for a binding to be invalid. // Zero base and zero width is enough for a binding to be invalid.
return map_key[0] == 0; return map_key[0] == 0;
} }
@ -377,9 +385,21 @@ class TextureCache {
bool has_unsigned; bool has_unsigned;
// Whether the fetch has signed components. // Whether the fetch has signed components.
bool has_signed; bool has_signed;
// Unsigned version of the texture (or signed if they have the same data).
Texture* texture; Texture* texture;
// Signed version of the texture if the data in the signed version is
// different on the host.
Texture* texture_signed;
}; };
// Whether the signed version of the texture has a different representation on
// the host than its unsigned version (for example, if it's a normalized or an
// integer texture emulated with a larger host pixel format).
static inline bool IsSignedVersionSeparate(TextureFormat format) {
const HostFormat& host_format = host_formats_[uint32_t(format)];
return host_format.load_mode_snorm != LoadMode::kUnknown &&
host_format.load_mode_snorm != host_format.load_mode;
}
// Whether decompression is needed on the host (Direct3D only allows creation // Whether decompression is needed on the host (Direct3D only allows creation
// of block-compressed textures with 4x4-aligned dimensions on PC). // of block-compressed textures with 4x4-aligned dimensions on PC).
static bool IsDecompressionNeeded(TextureFormat format, uint32_t width, static bool IsDecompressionNeeded(TextureFormat format, uint32_t width,