mirror of
https://github.com/KillzXGaming/Switch-Toolbox
synced 2024-11-23 13:03:15 +00:00
2698 lines
No EOL
100 KiB
C#
2698 lines
No EOL
100 KiB
C#
using System;
|
|
using System.Linq;
|
|
using System.Collections.Generic;
|
|
|
|
namespace Switch_Toolbox.Library
|
|
{
|
|
//Todo fix swizzle issues with this one
|
|
public class GX2
|
|
{
|
|
public const uint SwizzleMask = 0xFF00FF;
|
|
|
|
//Some enums and parts from https://github.com/jam1garner/Smash-Forge/blob/master/Smash%20Forge/Filetypes/Textures/GTX.cs
|
|
public class GX2Surface
|
|
{
|
|
public uint dim;
|
|
public uint width;
|
|
public uint height;
|
|
public uint depth;
|
|
public uint numMips;
|
|
public uint firstSlice;
|
|
public uint numSlices;
|
|
public uint format;
|
|
public uint aa;
|
|
public uint use;
|
|
public int resourceFlags;
|
|
public uint imageSize;
|
|
public uint imagePtr;
|
|
public int MemPtr;
|
|
public uint mipSize;
|
|
public uint mipPtr;
|
|
public uint tileMode;
|
|
public uint swizzle;
|
|
public uint mip_swizzle; //Used for botw Tex2
|
|
public uint alignment;
|
|
public uint pitch;
|
|
public uint bpp;
|
|
public uint imageCount;
|
|
public uint firstMip;
|
|
public uint numArray;
|
|
|
|
public byte[] data;
|
|
public byte[] mipData;
|
|
|
|
|
|
|
|
public uint[] mipOffset;
|
|
public byte[] compSel;
|
|
public uint[] texRegs;
|
|
};
|
|
|
|
public static uint expPitch = 0;
|
|
public static uint expHeight = 0;
|
|
public static uint expNumSlices = 0;
|
|
|
|
public class surfaceIn
|
|
{
|
|
public uint size = 0;
|
|
public uint tileMode = 0;
|
|
public uint format = 0;
|
|
public uint bpp = 0;
|
|
public uint numSamples = 0;
|
|
public uint width = 0;
|
|
public uint height = 0;
|
|
public uint numSlices = 0;
|
|
public uint slice = 0;
|
|
public uint mipLevel = 0;
|
|
public Flags flags = new Flags();
|
|
public uint numFrags = 0;
|
|
public uint tileType = 0;
|
|
public TileInfo pTileInfo = new TileInfo();
|
|
public int tileIndex = 0;
|
|
}
|
|
public class surfaceOut
|
|
{
|
|
public uint size = 0;
|
|
public uint pitch = 0;
|
|
public uint height = 0;
|
|
public uint depth = 0;
|
|
public long surfSize = 0;
|
|
public uint tileMode = 0;
|
|
public uint baseAlign = 0;
|
|
public uint pitchAlign = 0;
|
|
public uint heightAlign = 0;
|
|
public uint depthAlign = 0;
|
|
public uint bpp = 0;
|
|
public uint pixelPitch = 0;
|
|
public uint pixelHeight = 0;
|
|
public uint pixelBits = 0;
|
|
public uint sliceSize = 0;
|
|
public uint pitchTileMax = 0;
|
|
public uint heightTileMax = 0;
|
|
public uint sliceTileMax = 0;
|
|
public uint tileType = 0;
|
|
public TileInfo pTileInfo = new TileInfo();
|
|
public int tileIndex = 0;
|
|
}
|
|
|
|
public class Flags
|
|
{
|
|
public uint value = 0;
|
|
}
|
|
|
|
public class TileInfo
|
|
{
|
|
public int banks = 0;
|
|
public int bankWidth = 0;
|
|
public int bankHeight = 0;
|
|
public int macroAspectRatio = 0;
|
|
public int tileSplitBytes = 0;
|
|
public int pipeConfig = 0;
|
|
}
|
|
|
|
static surfaceIn pIn = new surfaceIn();
|
|
static surfaceOut pOut = new surfaceOut();
|
|
|
|
public enum GX2SurfaceDimension
|
|
{
|
|
DIM_1D = 0x0,
|
|
DIM_2D = 0x1,
|
|
DIM_3D = 0x2,
|
|
DIM_CUBE = 0x3,
|
|
DIM_1D_ARRAY = 0x4,
|
|
DIM_2D_ARRAY = 0x5,
|
|
DIM_2D_MSAA = 0x6,
|
|
DIM_2D_MSAA_ARRAY = 0x7,
|
|
DIM_FIRST = 0x0,
|
|
DIM_LAST = 0x7,
|
|
};
|
|
public enum GX2SurfaceFormat
|
|
{
|
|
INVALID = 0x0,
|
|
TC_R8_UNORM = 0x1,
|
|
TC_R8_UINT = 0x101,
|
|
TC_R8_SNORM = 0x201,
|
|
TC_R8_SINT = 0x301,
|
|
T_R4_G4_UNORM = 0x2,
|
|
TCD_R16_UNORM = 0x5,
|
|
TC_R16_UINT = 0x105,
|
|
TC_R16_SNORM = 0x205,
|
|
TC_R16_SINT = 0x305,
|
|
TC_R16_FLOAT = 0x806,
|
|
TC_R8_G8_UNORM = 0x7,
|
|
TC_R8_G8_UINT = 0x107,
|
|
TC_R8_G8_SNORM = 0x207,
|
|
TC_R8_G8_SINT = 0x307,
|
|
TCS_R5_G6_B5_UNORM = 0x8,
|
|
TC_R5_G5_B5_A1_UNORM = 0xA,
|
|
TC_R4_G4_B4_A4_UNORM = 0xB,
|
|
TC_A1_B5_G5_R5_UNORM = 0xC,
|
|
TC_R32_UINT = 0x10D,
|
|
TC_R32_SINT = 0x30D,
|
|
TCD_R32_FLOAT = 0x80E,
|
|
TC_R16_G16_UNORM = 0xF,
|
|
TC_R16_G16_UINT = 0x10F,
|
|
TC_R16_G16_SNORM = 0x20F,
|
|
TC_R16_G16_SINT = 0x30F,
|
|
TC_R16_G16_FLOAT = 0x810,
|
|
D_D24_S8_UNORM = 0x11,
|
|
T_R24_UNORM_X8 = 0x11,
|
|
T_X24_G8_UINT = 0x111,
|
|
D_D24_S8_FLOAT = 0x811,
|
|
TC_R11_G11_B10_FLOAT = 0x816,
|
|
TCS_R10_G10_B10_A2_UNORM = 0x19,
|
|
TC_R10_G10_B10_A2_UINT = 0x119,
|
|
T_R10_G10_B10_A2_SNORM = 0x219,
|
|
TC_R10_G10_B10_A2_SNORM = 0x219,
|
|
TC_R10_G10_B10_A2_SINT = 0x319,
|
|
TCS_R8_G8_B8_A8_UNORM = 0x1A,
|
|
TC_R8_G8_B8_A8_UINT = 0x11A,
|
|
TC_R8_G8_B8_A8_SNORM = 0x21A,
|
|
TC_R8_G8_B8_A8_SINT = 0x31A,
|
|
TCS_R8_G8_B8_A8_SRGB = 0x41A,
|
|
TCS_A2_B10_G10_R10_UNORM = 0x1B,
|
|
TC_A2_B10_G10_R10_UINT = 0x11B,
|
|
D_D32_FLOAT_S8_UINT_X24 = 0x81C,
|
|
T_R32_FLOAT_X8_X24 = 0x81C,
|
|
T_X32_G8_UINT_X24 = 0x11C,
|
|
TC_R32_G32_UINT = 0x11D,
|
|
TC_R32_G32_SINT = 0x31D,
|
|
TC_R32_G32_FLOAT = 0x81E,
|
|
TC_R16_G16_B16_A16_UNORM = 0x1F,
|
|
TC_R16_G16_B16_A16_UINT = 0x11F,
|
|
TC_R16_G16_B16_A16_SNORM = 0x21F,
|
|
TC_R16_G16_B16_A16_SINT = 0x31F,
|
|
TC_R16_G16_B16_A16_FLOAT = 0x820,
|
|
TC_R32_G32_B32_A32_UINT = 0x122,
|
|
TC_R32_G32_B32_A32_SINT = 0x322,
|
|
TC_R32_G32_B32_A32_FLOAT = 0x823,
|
|
T_BC1_UNORM = 0x31,
|
|
T_BC1_SRGB = 0x431,
|
|
T_BC2_UNORM = 0x32,
|
|
T_BC2_SRGB = 0x432,
|
|
T_BC3_UNORM = 0x33,
|
|
T_BC3_SRGB = 0x433,
|
|
T_BC4_UNORM = 0x34,
|
|
T_BC4_SNORM = 0x234,
|
|
T_BC5_UNORM = 0x35,
|
|
T_BC5_SNORM = 0x235,
|
|
T_NV12_UNORM = 0x81,
|
|
FIRST = 0x1,
|
|
LAST = 0x83F,
|
|
};
|
|
public enum GX2AAMode
|
|
{
|
|
GX2_AA_MODE_1X = 0x0,
|
|
GX2_AA_MODE_2X = 0x1,
|
|
GX2_AA_MODE_4X = 0x2,
|
|
GX2_AA_MODE_8X = 0x3,
|
|
GX2_AA_MODE_FIRST = 0x0,
|
|
GX2_AA_MODE_LAST = 0x3,
|
|
};
|
|
public enum GX2SurfaceUse : uint
|
|
{
|
|
USE_TEXTURE = 0x1,
|
|
USE_COLOR_BUFFER = 0x2,
|
|
USE_DEPTH_BUFFER = 0x4,
|
|
USE_SCAN_BUFFER = 0x8,
|
|
USE_FTV = 0x80000000,
|
|
USE_COLOR_BUFFER_TEXTURE = 0x3,
|
|
USE_DEPTH_BUFFER_TEXTURE = 0x5,
|
|
USE_COLOR_BUFFER_FTV = 0x80000002,
|
|
USE_COLOR_BUFFER_TEXTURE_FTV = 0x80000003,
|
|
USE_FIRST = 0x1,
|
|
USE_LAST = 0x8,
|
|
};
|
|
public enum GX2RResourceFlags
|
|
{
|
|
GX2R_RESOURCE_FLAGS_NONE = 0x0,
|
|
GX2R_BIND_NONE = 0x0,
|
|
GX2R_BIND_TEXTURE = 0x1,
|
|
GX2R_BIND_COLOR_BUFFER = 0x2,
|
|
GX2R_BIND_DEPTH_BUFFER = 0x4,
|
|
GX2R_BIND_SCAN_BUFFER = 0x8,
|
|
GX2R_BIND_VERTEX_BUFFER = 0x10,
|
|
GX2R_BIND_INDEX_BUFFER = 0x20,
|
|
GX2R_BIND_UNIFORM_BLOCK = 0x40,
|
|
GX2R_BIND_SHADER_PROGRAM = 0x80,
|
|
GX2R_BIND_STREAM_OUTPUT = 0x100,
|
|
GX2R_BIND_DISPLAY_LIST = 0x200,
|
|
GX2R_BIND_GS_RING = 0x400,
|
|
GX2R_USAGE_NONE = 0x0,
|
|
GX2R_USAGE_CPU_READ = 0x800,
|
|
GX2R_USAGE_CPU_WRITE = 0x1000,
|
|
GX2R_USAGE_GPU_READ = 0x2000,
|
|
GX2R_USAGE_GPU_WRITE = 0x4000,
|
|
GX2R_USAGE_DMA_READ = 0x8000,
|
|
GX2R_USAGE_DMA_WRITE = 0x10000,
|
|
GX2R_USAGE_FORCE_MEM1 = 0x20000,
|
|
GX2R_USAGE_FORCE_MEM2 = 0x40000,
|
|
GX2R_USAGE_MEM_DEFAULT = 0x0,
|
|
GX2R_USAGE_CPU_READWRITE = 0x1800,
|
|
GX2R_USAGE_GPU_READWRITE = 0x6000,
|
|
GX2R_USAGE_NON_CPU_WRITE = 0x14000,
|
|
GX2R_OPTION_NONE = 0x0,
|
|
GX2R_OPTION_IGNORE_IN_USE = 0x80000,
|
|
GX2R_OPTION_FIRST = 0x80000,
|
|
GX2R_OPTION_NO_CPU_INVALIDATE = 0x100000,
|
|
GX2R_OPTION_NO_GPU_INVALIDATE = 0x200000,
|
|
GX2R_OPTION_LOCK_READONLY = 0x400000,
|
|
GX2R_OPTION_NO_TOUCH_DESTROY = 0x800000,
|
|
GX2R_OPTION_LAST = 0x800000,
|
|
GX2R_OPTION_NO_INVALIDATE = 0x300000,
|
|
GX2R_OPTION_MASK = 0xF80000,
|
|
GX2R_RESOURCE_FLAG_RESERVED2 = 0x10000000,
|
|
GX2R_RESOURCE_FLAG_RESERVED1 = 0x20000000,
|
|
GX2R_RESOURCE_FLAG_RESERVED0 = 0x40000000,
|
|
};
|
|
public enum GX2TileMode
|
|
{
|
|
MODE_DEFAULT = 0x0,
|
|
MODE_LINEAR_SPECIAL = 0x10,
|
|
MODE_LINEAR_ALIGNED = 0x1,
|
|
MODE_1D_TILED_THIN1 = 0x2,
|
|
MODE_1D_TILED_THICK = 0x3,
|
|
MODE_2D_TILED_THIN1 = 0x4,
|
|
MODE_2D_TILED_THIN2 = 0x5,
|
|
MODE_2D_TILED_THIN4 = 0x6,
|
|
MODE_2D_TILED_THICK = 0x7,
|
|
MODE_2B_TILED_THIN1 = 0x8,
|
|
MODE_2B_TILED_THIN2 = 0x9,
|
|
MODE_2B_TILED_THIN4 = 0xA,
|
|
MODE_2B_TILED_THICK = 0xB,
|
|
MODE_3D_TILED_THIN1 = 0xC,
|
|
MODE_3D_TILED_THICK = 0xD,
|
|
MODE_3B_TILED_THIN1 = 0xE,
|
|
MODE_3B_TILED_THICK = 0xF,
|
|
MODE_LAST = 0x20,
|
|
};
|
|
|
|
public enum AddrTileMode
|
|
{
|
|
ADDR_TM_LINEAR_GENERAL = 0x0,
|
|
ADDR_TM_LINEAR_ALIGNED = 0x1,
|
|
ADDR_TM_1D_TILED_THIN1 = 0x2,
|
|
ADDR_TM_1D_TILED_THICK = 0x3,
|
|
ADDR_TM_2D_TILED_THIN1 = 0x4,
|
|
ADDR_TM_2D_TILED_THIN2 = 0x5,
|
|
ADDR_TM_2D_TILED_THIN4 = 0x6,
|
|
ADDR_TM_2D_TILED_THICK = 0x7,
|
|
ADDR_TM_2B_TILED_THIN1 = 0x8,
|
|
ADDR_TM_2B_TILED_THIN2 = 0x9,
|
|
ADDR_TM_2B_TILED_THIN4 = 0x0A,
|
|
ADDR_TM_2B_TILED_THICK = 0x0B,
|
|
ADDR_TM_3D_TILED_THIN1 = 0x0C,
|
|
ADDR_TM_3D_TILED_THICK = 0x0D,
|
|
ADDR_TM_3B_TILED_THIN1 = 0x0E,
|
|
ADDR_TM_3B_TILED_THICK = 0x0F,
|
|
ADDR_TM_2D_TILED_XTHICK = 0x10,
|
|
ADDR_TM_3D_TILED_XTHICK = 0x11,
|
|
ADDR_TM_POWER_SAVE = 0x12,
|
|
ADDR_TM_COUNT = 0x13,
|
|
}
|
|
public enum AddrTileType
|
|
{
|
|
ADDR_DISPLAYABLE = 0,
|
|
ADDR_NON_DISPLAYABLE = 1,
|
|
ADDR_DEPTH_SAMPLE_ORDER = 2,
|
|
ADDR_THICK_TILING = 3,
|
|
}
|
|
public enum AddrPipeCfg
|
|
{
|
|
ADDR_PIPECFG_INVALID = 0x0,
|
|
ADDR_PIPECFG_P2 = 0x1,
|
|
ADDR_PIPECFG_P4_8x16 = 0x5,
|
|
ADDR_PIPECFG_P4_16x16 = 0x6,
|
|
ADDR_PIPECFG_P4_16x32 = 0x7,
|
|
ADDR_PIPECFG_P4_32x32 = 0x8,
|
|
ADDR_PIPECFG_P8_16x16_8x16 = 0x9,
|
|
ADDR_PIPECFG_P8_16x32_8x16 = 0xA,
|
|
ADDR_PIPECFG_P8_32x32_8x16 = 0xB,
|
|
ADDR_PIPECFG_P8_16x32_16x16 = 0xC,
|
|
ADDR_PIPECFG_P8_32x32_16x16 = 0xD,
|
|
ADDR_PIPECFG_P8_32x32_16x32 = 0xE,
|
|
ADDR_PIPECFG_P8_32x64_32x32 = 0xF,
|
|
ADDR_PIPECFG_MAX = 0x10,
|
|
}
|
|
public enum AddrFormat
|
|
{
|
|
ADDR_FMT_INVALID = 0x0,
|
|
ADDR_FMT_8 = 0x1,
|
|
ADDR_FMT_4_4 = 0x2,
|
|
ADDR_FMT_3_3_2 = 0x3,
|
|
ADDR_FMT_RESERVED_4 = 0x4,
|
|
ADDR_FMT_16 = 0x5,
|
|
ADDR_FMT_16_FLOAT = 0x6,
|
|
ADDR_FMT_8_8 = 0x7,
|
|
ADDR_FMT_5_6_5 = 0x8,
|
|
ADDR_FMT_6_5_5 = 0x9,
|
|
ADDR_FMT_1_5_5_5 = 0xA,
|
|
ADDR_FMT_4_4_4_4 = 0xB,
|
|
ADDR_FMT_5_5_5_1 = 0xC,
|
|
ADDR_FMT_32 = 0xD,
|
|
ADDR_FMT_32_FLOAT = 0xE,
|
|
ADDR_FMT_16_16 = 0xF,
|
|
ADDR_FMT_16_16_FLOAT = 0x10,
|
|
ADDR_FMT_8_24 = 0x11,
|
|
ADDR_FMT_8_24_FLOAT = 0x12,
|
|
ADDR_FMT_24_8 = 0x13,
|
|
ADDR_FMT_24_8_FLOAT = 0x14,
|
|
ADDR_FMT_10_11_11 = 0x15,
|
|
ADDR_FMT_10_11_11_FLOAT = 0x16,
|
|
ADDR_FMT_11_11_10 = 0x17,
|
|
ADDR_FMT_11_11_10_FLOAT = 0x18,
|
|
ADDR_FMT_2_10_10_10 = 0x19,
|
|
ADDR_FMT_8_8_8_8 = 0x1A,
|
|
ADDR_FMT_10_10_10_2 = 0x1B,
|
|
ADDR_FMT_X24_8_32_FLOAT = 0x1C,
|
|
ADDR_FMT_32_32 = 0x1D,
|
|
ADDR_FMT_32_32_FLOAT = 0x1E,
|
|
ADDR_FMT_16_16_16_16 = 0x1F,
|
|
ADDR_FMT_16_16_16_16_FLOAT = 0x20,
|
|
ADDR_FMT_RESERVED_33 = 0x21,
|
|
ADDR_FMT_32_32_32_32 = 0x22,
|
|
ADDR_FMT_32_32_32_32_FLOAT = 0x23,
|
|
ADDR_FMT_RESERVED_36 = 0x24,
|
|
ADDR_FMT_1 = 0x25,
|
|
ADDR_FMT_1_REVERSED = 0x26,
|
|
ADDR_FMT_GB_GR = 0x27,
|
|
ADDR_FMT_BG_RG = 0x28,
|
|
ADDR_FMT_32_AS_8 = 0x29,
|
|
ADDR_FMT_32_AS_8_8 = 0x2A,
|
|
ADDR_FMT_5_9_9_9_SHAREDEXP = 0x2B,
|
|
ADDR_FMT_8_8_8 = 0x2C,
|
|
ADDR_FMT_16_16_16 = 0x2D,
|
|
ADDR_FMT_16_16_16_FLOAT = 0x2E,
|
|
ADDR_FMT_32_32_32 = 0x2F,
|
|
ADDR_FMT_32_32_32_FLOAT = 0x30,
|
|
ADDR_FMT_BC1 = 0x31,
|
|
ADDR_FMT_BC2 = 0x32,
|
|
ADDR_FMT_BC3 = 0x33,
|
|
ADDR_FMT_BC4 = 0x34,
|
|
ADDR_FMT_BC5 = 0x35,
|
|
ADDR_FMT_BC6 = 0x36,
|
|
ADDR_FMT_BC7 = 0x37,
|
|
ADDR_FMT_32_AS_32_32_32_32 = 0x38,
|
|
ADDR_FMT_APC3 = 0x39,
|
|
ADDR_FMT_APC4 = 0x3A,
|
|
ADDR_FMT_APC5 = 0x3B,
|
|
ADDR_FMT_APC6 = 0x3C,
|
|
ADDR_FMT_APC7 = 0x3D,
|
|
ADDR_FMT_CTX1 = 0x3E,
|
|
ADDR_FMT_RESERVED_63 = 0x3F,
|
|
};
|
|
|
|
public static void Debug(surfaceOut surf)
|
|
{
|
|
if (surf == null)
|
|
surf = getSurfaceInfo((GX2SurfaceFormat)0x33, 701, 77, 1, 0, 13, 1, 0);
|
|
|
|
Console.WriteLine($"size {surf.size}");
|
|
Console.WriteLine($"pitch {surf.pitch}");
|
|
Console.WriteLine($"height {surf.height}");
|
|
Console.WriteLine($"depth {surf.depth}");
|
|
Console.WriteLine($"surfSize {surf.surfSize}");
|
|
Console.WriteLine($"tileMode {surf.tileMode}");
|
|
Console.WriteLine($"baseAlign {surf.baseAlign}");
|
|
Console.WriteLine($"pitchAlign {surf.pitchAlign}");
|
|
Console.WriteLine($"heightAlign {surf.heightAlign}");
|
|
Console.WriteLine($"depthAlign {surf.depthAlign}");
|
|
Console.WriteLine($"bpp {surf.bpp}");
|
|
Console.WriteLine($"pixelPitch {surf.pixelPitch}");
|
|
Console.WriteLine($"pixelHeight {surf.pixelHeight}");
|
|
Console.WriteLine($"pixelBits {surf.pixelBits}");
|
|
Console.WriteLine($"sliceSize {surf.sliceSize}");
|
|
Console.WriteLine($"pitchTileMax {surf.pitchTileMax}");
|
|
Console.WriteLine($"heightTileMax {surf.heightTileMax}");
|
|
Console.WriteLine($"sliceTileMax {surf.sliceTileMax}");
|
|
Console.WriteLine($"tileType {surf.tileType}");
|
|
Console.WriteLine($"tileIndex {surf.tileIndex}");
|
|
}
|
|
static bool DebugSurface = false;
|
|
|
|
public static GX2Surface CreateGx2Texture(byte[] imageData, string Name, uint TileMode, uint AAMode,
|
|
uint Width, uint Height, uint Depth, uint Format, uint swizzle, uint SurfaceDim, uint MipCount)
|
|
{
|
|
var surfOut = getSurfaceInfo((GX2SurfaceFormat)Format, Width, Height, Depth, SurfaceDim, TileMode, AAMode, 0);
|
|
Console.WriteLine("Imported surfSize" + surfOut.surfSize);
|
|
Console.WriteLine("Imported data block" + imageData.Length);
|
|
Console.WriteLine("GX2SurfaceFormat " + (GX2SurfaceFormat)Format);
|
|
|
|
uint imageSize = (uint)surfOut.surfSize;
|
|
uint alignment = surfOut.baseAlign;
|
|
uint pitch = surfOut.pitch;
|
|
uint mipSize = 0;
|
|
uint dataSize = (uint)imageData.Length;
|
|
uint bpp = GX2.surfaceGetBitsPerPixel((uint)Format) >> 3;
|
|
int DepthLevel = 1;
|
|
|
|
if (dataSize <= 0)
|
|
throw new Exception($"Image is empty!!");
|
|
|
|
Console.WriteLine("swizzle pattern " + swizzle);
|
|
|
|
uint s = (swizzle << 8);
|
|
|
|
uint blkWidth, blkHeight;
|
|
if (GX2.IsFormatBCN((GX2SurfaceFormat)Format))
|
|
{
|
|
blkWidth = 4;
|
|
blkHeight = 4;
|
|
}
|
|
else
|
|
{
|
|
blkWidth = 1;
|
|
blkHeight = 1;
|
|
}
|
|
|
|
if (TileMode == 0)
|
|
TileMode = GX2.getDefaultGX2TileMode((uint)SurfaceDim, Width, Height, 1, (uint)Format, 0, 1);
|
|
|
|
uint tilingDepth = surfOut.depth;
|
|
|
|
if (TileMode == 3)
|
|
tilingDepth /= 4;
|
|
|
|
if (tilingDepth != 1)
|
|
throw new Exception($"Unsupported Depth {surfOut.depth}!");
|
|
|
|
int tiling1dLevel = 0;
|
|
bool tiling1dLevelSet = false;
|
|
|
|
List<uint> mipOffsets = new List<uint>();
|
|
List<byte[]> Swizzled = new List<byte[]>();
|
|
|
|
if (MipCount == 0)
|
|
MipCount = 1;
|
|
|
|
uint Splice = 0;
|
|
|
|
for (int mipLevel = 0; mipLevel < MipCount; mipLevel++)
|
|
{
|
|
var result = TextureHelper.GetCurrentMipSize(Width, Height, blkWidth, blkHeight, bpp, mipLevel);
|
|
|
|
uint offset = result.Item1;
|
|
uint size = result.Item2;
|
|
|
|
byte[] data_ = new byte[size];
|
|
Array.Copy(imageData, offset, data_, 0, size);
|
|
|
|
uint width_ = Math.Max(1, Width >> mipLevel);
|
|
uint height_ = Math.Max(1, Height >> mipLevel);
|
|
|
|
if (mipLevel != 0)
|
|
{
|
|
surfOut = GX2.getSurfaceInfo((GX2SurfaceFormat)Format, Width, Height, 1, 1, TileMode, 0, mipLevel);
|
|
|
|
if (mipLevel == 1)
|
|
mipOffsets.Add(imageSize);
|
|
else
|
|
mipOffsets.Add(mipSize);
|
|
}
|
|
|
|
data_ = Utils.CombineByteArray(data_, new byte[surfOut.surfSize - size]);
|
|
byte[] dataAlignBytes = new byte[RoundUp(mipSize, surfOut.baseAlign) - mipSize];
|
|
|
|
if (mipLevel != 0)
|
|
mipSize += (uint)(surfOut.surfSize + dataAlignBytes.Length);
|
|
|
|
byte[] SwizzledData = GX2.swizzle(width_, height_, surfOut.depth, surfOut.height, (uint)Format, 0, 1, surfOut.tileMode, s,
|
|
surfOut.pitch, surfOut.bpp, Splice, 0, data_);
|
|
|
|
Swizzled.Add(dataAlignBytes.Concat(SwizzledData).ToArray());
|
|
|
|
if (surfOut.tileMode == 1 || surfOut.tileMode == 2 ||
|
|
surfOut.tileMode == 3 || surfOut.tileMode == 16)
|
|
{
|
|
tiling1dLevelSet = true;
|
|
}
|
|
|
|
if (tiling1dLevelSet == false)
|
|
tiling1dLevel += 1;
|
|
}
|
|
|
|
if (tiling1dLevelSet)
|
|
s |= (uint)(tiling1dLevel << 16);
|
|
else
|
|
s |= (uint)(13 << 16);
|
|
|
|
GX2.GX2Surface surf = new GX2.GX2Surface();
|
|
surf.depth = Depth;
|
|
surf.width = Width;
|
|
surf.height = Height;
|
|
surf.use = 1;
|
|
surf.dim = (uint)SurfaceDim;
|
|
surf.tileMode = TileMode;
|
|
surf.swizzle = s;
|
|
surf.resourceFlags = 0;
|
|
surf.pitch = pitch;
|
|
surf.bpp = bpp;
|
|
surf.format = (uint)Format;
|
|
surf.numMips = MipCount;
|
|
surf.imageCount = MipCount;
|
|
surf.firstSlice = 0;
|
|
surf.firstMip = 0;
|
|
surf.aa = AAMode;
|
|
surf.mipOffset = mipOffsets.ToArray();
|
|
surf.alignment = alignment;
|
|
surf.imageSize = imageSize;
|
|
surf.data = Swizzled[0];
|
|
|
|
List<byte[]> mips = new List<byte[]>();
|
|
for (int mipLevel = 1; mipLevel < Swizzled.Count; mipLevel++)
|
|
{
|
|
mips.Add(Swizzled[mipLevel]);
|
|
Console.WriteLine(Swizzled[mipLevel].Length);
|
|
}
|
|
surf.mipData = Utils.CombineByteArray(mips.ToArray());
|
|
mips.Clear();
|
|
|
|
surf.mipSize = surf.mipData != null ? (uint)surf.mipData.Length : 0;
|
|
|
|
|
|
Console.WriteLine("");
|
|
Console.WriteLine("// ----- GX2Surface Swizzled Info ----- ");
|
|
Console.WriteLine(" dim = 1");
|
|
Console.WriteLine(" width = " + surf.width);
|
|
Console.WriteLine(" height = " + surf.height);
|
|
Console.WriteLine(" depth = 1");
|
|
Console.WriteLine(" numMips = " + surf.numMips);
|
|
Console.WriteLine(" format = " + surf.format);
|
|
Console.WriteLine(" aa = 0");
|
|
Console.WriteLine(" use = 1");
|
|
Console.WriteLine(" imageSize = " + surf.imageSize);
|
|
Console.WriteLine(" mipSize = " + surf.mipSize);
|
|
Console.WriteLine(" tileMode = " + surf.tileMode);
|
|
Console.WriteLine(" swizzle = " + surf.swizzle);
|
|
Console.WriteLine(" alignment = " + surf.alignment);
|
|
Console.WriteLine(" pitch = " + surf.pitch);
|
|
Console.WriteLine(" data = " + surf.data.Length);
|
|
Console.WriteLine(" mipData = " + surf.mipData.Length);
|
|
Console.WriteLine("");
|
|
Console.WriteLine(" GX2 Component Selector:");
|
|
Console.WriteLine("");
|
|
Console.WriteLine(" bits per pixel = " + (surf.bpp << 3));
|
|
Console.WriteLine(" bytes per pixel = " + surf.bpp);
|
|
Console.WriteLine(" realSize = " + imageData.Length);
|
|
|
|
return surf;
|
|
}
|
|
|
|
private static int RoundUp(int X, int Y)
|
|
{
|
|
return ((X - 1) | (Y - 1)) + 1;
|
|
}
|
|
private static uint RoundUp(uint X, uint Y)
|
|
{
|
|
return ((X - 1) | (Y - 1)) + 1;
|
|
}
|
|
|
|
public static byte[] Decode(GX2Surface tex, int ArrayIndex = -1, int MipIndex = -1, string DebugTextureName = "")
|
|
{
|
|
uint blkWidth, blkHeight;
|
|
if (IsFormatBCN((GX2SurfaceFormat)tex.format))
|
|
{
|
|
blkWidth = 4;
|
|
blkHeight = 4;
|
|
}
|
|
else
|
|
{
|
|
blkWidth = 1;
|
|
blkHeight = 1;
|
|
}
|
|
|
|
var surfInfo = getSurfaceInfo((GX2SurfaceFormat)tex.format, tex.width, tex.height, tex.depth, (uint)tex.dim, (uint)tex.tileMode, (uint)tex.aa, 0);
|
|
uint bpp = DIV_ROUND_UP(surfInfo.bpp, 8);
|
|
|
|
if (tex.numArray == 0)
|
|
tex.numArray = 1;
|
|
|
|
byte[] data = new byte[tex.data.Length];
|
|
byte[] mipdata = new byte[tex.mipData.Length];
|
|
|
|
uint mipCount = tex.numMips;
|
|
if (tex.mipData == null || tex.mipData.Length <= 0)
|
|
mipCount = 1;
|
|
|
|
int dataOffset = 0;
|
|
int mipDataOffset = 0;
|
|
int mipSpliceSize = 0;
|
|
|
|
for (int arrayLevel = 0; arrayLevel < tex.depth; arrayLevel++)
|
|
{
|
|
for (int mipLevel = 0; mipLevel < mipCount; mipLevel++)
|
|
{
|
|
bool GetLevel = (arrayLevel == ArrayIndex && mipLevel == MipIndex);
|
|
|
|
uint swizzle = tex.swizzle;
|
|
|
|
uint width_ = (uint)Math.Max(1, tex.width >> mipLevel);
|
|
uint height_ = (uint)Math.Max(1, tex.height >> mipLevel);
|
|
|
|
uint size = DIV_ROUND_UP(width_, blkWidth) * DIV_ROUND_UP(height_, blkHeight) * bpp;
|
|
|
|
uint mipOffset;
|
|
if (mipLevel != 0)
|
|
{
|
|
if (tex.mip_swizzle != 0)
|
|
swizzle = tex.mip_swizzle;
|
|
|
|
mipOffset = (tex.mipOffset[mipLevel - 1]);
|
|
if (mipLevel == 1)
|
|
{
|
|
mipOffset -= (uint)surfInfo.surfSize;
|
|
mipOffset += (uint)mipDataOffset;
|
|
mipSpliceSize += (int)mipOffset;
|
|
}
|
|
|
|
Console.WriteLine("mipOffset " + mipOffset);
|
|
if (GetLevel)
|
|
{
|
|
surfInfo = getSurfaceInfo((GX2SurfaceFormat)tex.format, tex.width, tex.height, tex.depth, (uint)tex.dim, (uint)tex.tileMode, (uint)tex.aa, mipLevel);
|
|
|
|
Array.Copy(tex.mipData, 0, mipdata, 0, tex.mipData.Length);
|
|
Array.Copy(tex.mipData, (int)mipOffset, mipdata, 0, (int)surfInfo.sliceSize);
|
|
data = mipdata;
|
|
}
|
|
}
|
|
else if (GetLevel)
|
|
{
|
|
Array.Copy(tex.data, 0, data, 0, tex.data.Length);
|
|
Array.Copy(tex.data, (uint)dataOffset, data, 0, size);
|
|
}
|
|
|
|
if (GetLevel)
|
|
{
|
|
byte[] deswizzled = deswizzle(width_, height_, surfInfo.depth, surfInfo.height, (uint)tex.format, 0, tex.use,
|
|
surfInfo.tileMode, (uint)swizzle, surfInfo.pitch, surfInfo.bpp, (uint)arrayLevel, 0, data);
|
|
//Create a copy and use that to remove uneeded data
|
|
byte[] result_ = new byte[size];
|
|
Array.Copy(deswizzled, 0, result_, 0, size);
|
|
return result_;
|
|
}
|
|
}
|
|
|
|
dataOffset += (int)surfInfo.sliceSize;
|
|
mipDataOffset += mipSpliceSize;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public static List<List<byte[]>> Decode(GX2Surface tex, string DebugTextureName = "")
|
|
{
|
|
if (tex.data == null || tex.data.Length <= 0)
|
|
throw new Exception("Invalid GX2 surface data. Make sure to not open Tex2 files if this is one. Those will load automatically next to Tex1!");
|
|
|
|
Console.WriteLine("DECODING TEX " + DebugTextureName);
|
|
|
|
var surfdEBUG = getSurfaceInfo((GX2SurfaceFormat)tex.format, tex.width, tex.height, tex.depth, (uint)tex.dim, (uint)tex.tileMode, (uint)tex.aa, 0);
|
|
Debug(surfdEBUG);
|
|
/* Console.WriteLine("");
|
|
Console.WriteLine("// ----- GX2Surface Decode Info ----- ");
|
|
Console.WriteLine(" dim = " + tex.dim);
|
|
Console.WriteLine(" width = " + tex.width);
|
|
Console.WriteLine(" height = " + tex.height);
|
|
Console.WriteLine(" depth = " + tex.depth);
|
|
Console.WriteLine(" numMips = " + tex.numMips);
|
|
Console.WriteLine(" format = " + (GX2SurfaceFormat)tex.format);
|
|
Console.WriteLine(" aa = " + tex.aa);
|
|
Console.WriteLine(" use = " + tex.use);
|
|
Console.WriteLine(" imageSize = " + tex.imageSize);
|
|
Console.WriteLine(" mipSize = " + tex.mipSize);
|
|
Console.WriteLine(" tileMode = " + (GX2TileMode)tex.tileMode);
|
|
Console.WriteLine(" swizzle = " + tex.swizzle);
|
|
Console.WriteLine(" alignment = " + tex.alignment);
|
|
Console.WriteLine(" pitch = " + tex.pitch);
|
|
Console.WriteLine(" bits per pixel = " + (tex.bpp << 3));
|
|
Console.WriteLine(" bytes per pixel = " + tex.bpp);
|
|
Console.WriteLine(" data size = " + tex.data.Length);
|
|
Console.WriteLine(" realSize = " + tex.imageSize);*/
|
|
|
|
uint blkWidth, blkHeight;
|
|
if (IsFormatBCN((GX2SurfaceFormat)tex.format))
|
|
{
|
|
blkWidth = 4;
|
|
blkHeight = 4;
|
|
}
|
|
else
|
|
{
|
|
blkWidth = 1;
|
|
blkHeight = 1;
|
|
}
|
|
|
|
byte[] data = tex.data;
|
|
|
|
var surfInfo = getSurfaceInfo((GX2SurfaceFormat)tex.format, tex.width, tex.height, tex.depth, (uint)tex.dim, (uint)tex.tileMode, (uint)tex.aa, 0);
|
|
uint bpp = DIV_ROUND_UP(surfInfo.bpp, 8);
|
|
|
|
if (surfInfo.depth != 1)
|
|
{
|
|
// System.Windows.Forms.MessageBox.Show($"Unsupported Depth {surfInfo.depth} for texture {DebugTextureName}!");
|
|
// return new List<List<byte[]>>();
|
|
}
|
|
|
|
if (tex.numArray == 0)
|
|
tex.numArray = 1;
|
|
|
|
uint mipCount = tex.numMips;
|
|
if (tex.mipData == null || tex.mipData.Length <= 0)
|
|
mipCount = 1;
|
|
|
|
int ArrayImageize = 0;
|
|
int ArrayMipImageize = 0;
|
|
|
|
if (tex.mipData != null)
|
|
ArrayMipImageize = tex.mipData.Length / (int)tex.depth;
|
|
|
|
int dataOffset = 0;
|
|
int mipDataOffset = 0;
|
|
int TotalImageSize = tex.data.Length;
|
|
|
|
List<List<byte[]>> result = new List<List<byte[]>>();
|
|
for (int arrayLevel = 0; arrayLevel < tex.depth; arrayLevel++)
|
|
{
|
|
List<byte[]> mips = new List<byte[]>();
|
|
for (int mipLevel = 0; mipLevel < mipCount; mipLevel++)
|
|
{
|
|
uint swizzle = tex.swizzle;
|
|
|
|
uint width_ = (uint)Math.Max(1, tex.width >> mipLevel);
|
|
uint height_ = (uint)Math.Max(1, tex.height >> mipLevel);
|
|
|
|
uint size = DIV_ROUND_UP(width_, blkWidth) * DIV_ROUND_UP(height_, blkHeight) * bpp;
|
|
|
|
uint mipOffset;
|
|
if (mipLevel != 0)
|
|
{
|
|
if (tex.mip_swizzle != 0)
|
|
swizzle = tex.mip_swizzle;
|
|
|
|
mipOffset = (tex.mipOffset[mipLevel - 1]);
|
|
if (mipLevel == 1)
|
|
mipOffset -= (uint)surfInfo.sliceSize;
|
|
|
|
surfInfo = getSurfaceInfo((GX2SurfaceFormat)tex.format, tex.width, tex.height, tex.depth, (uint)tex.dim, (uint)tex.tileMode, (uint)tex.aa, mipLevel);
|
|
data = new byte[surfInfo.sliceSize];
|
|
Array.Copy(tex.mipData, (uint)mipDataOffset + mipOffset, data, 0, surfInfo.sliceSize);
|
|
}
|
|
else
|
|
Array.Copy(tex.data, (uint)dataOffset, data, 0, size);
|
|
|
|
byte[] deswizzled = deswizzle(width_, height_, surfInfo.depth, surfInfo.height, (uint)tex.format, 0, tex.use,
|
|
surfInfo.tileMode, (uint)swizzle, surfInfo.pitch, surfInfo.bpp, (uint)arrayLevel, 0, data);
|
|
//Create a copy and use that to remove uneeded data
|
|
byte[] result_ = new byte[size];
|
|
Array.Copy(deswizzled, 0, result_, 0, size);
|
|
mips.Add(result_);
|
|
}
|
|
|
|
result.Add(mips);
|
|
|
|
dataOffset += (int)surfInfo.sliceSize;
|
|
mipDataOffset += (int)surfInfo.sliceSize;
|
|
|
|
}
|
|
|
|
return result;
|
|
}
|
|
private static byte[] SubArray(byte[] data, int offset, int length)
|
|
{
|
|
return data.Skip(offset).Take(length).ToArray();
|
|
}
|
|
private static uint DIV_ROUND_UP(uint n, uint d)
|
|
{
|
|
return (n + d - 1) / d;
|
|
}
|
|
|
|
|
|
/*---------------------------------------
|
|
*
|
|
* Code ported from AboodXD's GTX Extractor:
|
|
* https://github.com/aboood40091/GTX-Extractor/blob/cf1a15c41630745d9a0d370bafe5760c1e5f8cbe/addrlib/addrlib_cy.pyx
|
|
*
|
|
*---------------------------------------*/
|
|
|
|
public static bool IsFormatBCN(GX2SurfaceFormat Format)
|
|
{
|
|
switch (Format)
|
|
{
|
|
case GX2SurfaceFormat.T_BC1_UNORM:
|
|
case GX2SurfaceFormat.T_BC1_SRGB:
|
|
case GX2SurfaceFormat.T_BC2_UNORM:
|
|
case GX2SurfaceFormat.T_BC2_SRGB:
|
|
case GX2SurfaceFormat.T_BC3_UNORM:
|
|
case GX2SurfaceFormat.T_BC3_SRGB:
|
|
case GX2SurfaceFormat.T_BC4_UNORM:
|
|
case GX2SurfaceFormat.T_BC4_SNORM:
|
|
case GX2SurfaceFormat.T_BC5_SNORM:
|
|
case GX2SurfaceFormat.T_BC5_UNORM:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public static byte[] deswizzle(uint width, uint height, uint depth, uint height_, uint format_, uint aa, uint use, uint tileMode, uint swizzle_,
|
|
uint pitch, uint bpp, uint slice, uint sample, byte[] data)
|
|
{
|
|
return swizzleSurf(width, height, depth, format_, aa, use, tileMode, swizzle_, pitch, bpp, slice, sample, data, 0);
|
|
}
|
|
public static byte[] swizzle(uint width, uint height, uint depth, uint height_, uint format_, uint aa, uint use, uint tileMode, uint swizzle_,
|
|
uint pitch, uint bpp, uint slice, uint sample, byte[] data)
|
|
{
|
|
return swizzleSurf(width, height, depth, format_, aa, use, tileMode, swizzle_, pitch, bpp, slice, sample, data, 1);
|
|
}
|
|
|
|
private static byte[] swizzleSurf(uint width, uint height, uint depth, uint format, uint aa, uint use, uint tileMode, uint swizzle_,
|
|
uint pitch, uint bitsPerPixel, uint slice, uint sample, byte[] data, int swizzle)
|
|
{
|
|
uint bytesPerPixel = bitsPerPixel / 8;
|
|
byte[] result = new byte[data.Length];
|
|
|
|
uint pipeSwizzle, bankSwizzle, pos_;
|
|
ulong pos;
|
|
|
|
if (IsFormatBCN((GX2SurfaceFormat)format))
|
|
{
|
|
width = (width + 3) / 4;
|
|
height = (height + 3) / 4;
|
|
}
|
|
|
|
pipeSwizzle = (swizzle_ >> 8) & 1;
|
|
bankSwizzle = (swizzle_ >> 9) & 3;
|
|
|
|
if (depth > 1)
|
|
{
|
|
// bankSwizzle = (uint)(slice % 4);
|
|
}
|
|
|
|
tileMode = GX2TileModeToAddrTileMode(tileMode);
|
|
|
|
bool IsDepth = (use & 4) != 0;
|
|
uint numSamples = (uint)(1 << (int)aa);
|
|
|
|
for (int y = 0; y < height; y++)
|
|
{
|
|
for (int x = 0; x < width; x++)
|
|
{
|
|
if (tileMode == 0 || tileMode == 1)
|
|
{
|
|
pos = computeSurfaceAddrFromCoordLinear((uint)x, (uint)y, slice, sample, bytesPerPixel, pitch, height, depth);
|
|
}
|
|
else if (tileMode == 2 || tileMode == 3)
|
|
{
|
|
pos = computeSurfaceAddrFromCoordMicroTiled((uint)x, (uint)y, slice, bitsPerPixel, pitch, height, (AddrTileMode)tileMode, IsDepth);
|
|
}
|
|
else
|
|
{
|
|
pos = computeSurfaceAddrFromCoordMacroTiled((uint)x, (uint)y, slice, sample, bitsPerPixel, pitch, height, numSamples, (AddrTileMode)tileMode, IsDepth, pipeSwizzle, bankSwizzle);
|
|
}
|
|
|
|
|
|
pos_ = (uint)(y * width + x) * bytesPerPixel;
|
|
|
|
if (pos_ + bytesPerPixel <= data.Length && pos + bytesPerPixel <= (ulong)data.Length)
|
|
{
|
|
if (swizzle == 0)
|
|
{
|
|
for (int n = 0; n < bytesPerPixel; n++)
|
|
result[pos_ + n] = data[(uint)pos + n];
|
|
}
|
|
else
|
|
{
|
|
for (int n = 0; n < bytesPerPixel; n++)
|
|
result[(uint)pos + n] = data[pos_ + n];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private static byte[] formatHwInfo = {
|
|
0x00, 0x00, 0x00, 0x01, 0x08, 0x03, 0x00, 0x01, 0x08, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
|
|
0x00, 0x00, 0x00, 0x01, 0x10, 0x07, 0x00, 0x00, 0x10, 0x03, 0x00, 0x01, 0x10, 0x03, 0x00, 0x01,
|
|
0x10, 0x0B, 0x00, 0x01, 0x10, 0x01, 0x00, 0x01, 0x10, 0x03, 0x00, 0x01, 0x10, 0x03, 0x00, 0x01,
|
|
0x10, 0x03, 0x00, 0x01, 0x20, 0x03, 0x00, 0x00, 0x20, 0x07, 0x00, 0x00, 0x20, 0x03, 0x00, 0x00,
|
|
0x20, 0x03, 0x00, 0x01, 0x20, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x03, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x20, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
|
|
0x00, 0x00, 0x00, 0x01, 0x20, 0x0B, 0x00, 0x01, 0x20, 0x0B, 0x00, 0x01, 0x20, 0x0B, 0x00, 0x01,
|
|
0x40, 0x05, 0x00, 0x00, 0x40, 0x03, 0x00, 0x00, 0x40, 0x03, 0x00, 0x00, 0x40, 0x03, 0x00, 0x00,
|
|
0x40, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x10, 0x01, 0x00, 0x00,
|
|
0x10, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00,
|
|
0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x60, 0x01, 0x00, 0x00,
|
|
0x60, 0x01, 0x00, 0x00, 0x40, 0x01, 0x00, 0x01, 0x80, 0x01, 0x00, 0x01, 0x80, 0x01, 0x00, 0x01,
|
|
0x40, 0x01, 0x00, 0x01, 0x80, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
};
|
|
|
|
private static byte[] formatExInfo = {
|
|
0x00, 0x01, 0x01, 0x03, 0x08, 0x01, 0x01, 0x03, 0x08, 0x01, 0x01, 0x03, 0x08, 0x01, 0x01, 0x03,
|
|
0x00, 0x01, 0x01, 0x03, 0x10, 0x01, 0x01, 0x03, 0x10, 0x01, 0x01, 0x03, 0x10, 0x01, 0x01, 0x03,
|
|
0x10, 0x01, 0x01, 0x03, 0x10, 0x01, 0x01, 0x03, 0x10, 0x01, 0x01, 0x03, 0x10, 0x01, 0x01, 0x03,
|
|
0x10, 0x01, 0x01, 0x03, 0x20, 0x01, 0x01, 0x03, 0x20, 0x01, 0x01, 0x03, 0x20, 0x01, 0x01, 0x03,
|
|
0x20, 0x01, 0x01, 0x03, 0x20, 0x01, 0x01, 0x03, 0x20, 0x01, 0x01, 0x03, 0x20, 0x01, 0x01, 0x03,
|
|
0x20, 0x01, 0x01, 0x03, 0x20, 0x01, 0x01, 0x03, 0x20, 0x01, 0x01, 0x03, 0x20, 0x01, 0x01, 0x03,
|
|
0x20, 0x01, 0x01, 0x03, 0x20, 0x01, 0x01, 0x03, 0x20, 0x01, 0x01, 0x03, 0x20, 0x01, 0x01, 0x03,
|
|
0x40, 0x01, 0x01, 0x03, 0x40, 0x01, 0x01, 0x03, 0x40, 0x01, 0x01, 0x03, 0x40, 0x01, 0x01, 0x03,
|
|
0x40, 0x01, 0x01, 0x03, 0x00, 0x01, 0x01, 0x03, 0x80, 0x01, 0x01, 0x03, 0x80, 0x01, 0x01, 0x03,
|
|
0x00, 0x01, 0x01, 0x03, 0x01, 0x08, 0x01, 0x05, 0x01, 0x08, 0x01, 0x06, 0x10, 0x01, 0x01, 0x07,
|
|
0x10, 0x01, 0x01, 0x08, 0x20, 0x01, 0x01, 0x03, 0x20, 0x01, 0x01, 0x03, 0x20, 0x01, 0x01, 0x03,
|
|
0x18, 0x03, 0x01, 0x04, 0x30, 0x03, 0x01, 0x04, 0x30, 0x03, 0x01, 0x04, 0x60, 0x03, 0x01, 0x04,
|
|
0x60, 0x03, 0x01, 0x04, 0x40, 0x04, 0x04, 0x09, 0x80, 0x04, 0x04, 0x0A, 0x80, 0x04, 0x04, 0x0B,
|
|
0x40, 0x04, 0x04, 0x0C, 0x40, 0x04, 0x04, 0x0D, 0x40, 0x04, 0x04, 0x0D, 0x40, 0x04, 0x04, 0x0D,
|
|
0x00, 0x01, 0x01, 0x03, 0x00, 0x01, 0x01, 0x03, 0x00, 0x01, 0x01, 0x03, 0x00, 0x01, 0x01, 0x03,
|
|
0x00, 0x01, 0x01, 0x03, 0x00, 0x01, 0x01, 0x03, 0x40, 0x01, 0x01, 0x03, 0x00, 0x01, 0x01, 0x03,
|
|
};
|
|
|
|
public static uint surfaceGetBitsPerPixel(uint surfaceFormat)
|
|
{
|
|
return formatHwInfo[(surfaceFormat & 0x3F) * 4];
|
|
}
|
|
|
|
public static uint nextPow2(uint dim)
|
|
{
|
|
uint newDim = 1;
|
|
if (dim < 0x7FFFFFFF)
|
|
{
|
|
while (newDim < dim)
|
|
newDim *= 2;
|
|
}
|
|
else
|
|
newDim = 0x80000000;
|
|
|
|
return newDim;
|
|
}
|
|
|
|
public static uint getDefaultGX2TileMode(uint dim, uint width, uint height, uint depth, uint format_, uint aa, uint use)
|
|
{
|
|
uint tileMode = 1;
|
|
bool IsDepthBuffer = (use & 4) != 0;
|
|
bool isColorBuffer = (use & 2) != 0;
|
|
|
|
if (dim != 0 || aa != 0 || IsDepthBuffer)
|
|
{
|
|
if (dim != 2 || isColorBuffer)
|
|
tileMode = 4;
|
|
else
|
|
tileMode = 7;
|
|
|
|
var surfOut = getSurfaceInfo((GX2SurfaceFormat)format_, width, height, depth, dim, tileMode, aa, 0);
|
|
if (width < surfOut.pitchAlign && height < surfOut.heightAlign)
|
|
{
|
|
if (tileMode == 7)
|
|
tileMode = 3;
|
|
else
|
|
tileMode = 2;
|
|
}
|
|
}
|
|
return tileMode;
|
|
}
|
|
|
|
private static uint GX2TileModeToAddrTileMode(uint tileMode)
|
|
{
|
|
if (tileMode == 0)
|
|
throw new Exception("Use tileMode from getDefaultGX2TileMode().");
|
|
|
|
if (tileMode == 16)
|
|
return 0;
|
|
|
|
return tileMode;
|
|
}
|
|
|
|
private static uint computeSurfaceThickness(AddrTileMode tileMode)
|
|
{
|
|
switch (tileMode)
|
|
{
|
|
case AddrTileMode.ADDR_TM_1D_TILED_THICK:
|
|
case AddrTileMode.ADDR_TM_2D_TILED_THICK:
|
|
case AddrTileMode.ADDR_TM_2B_TILED_THICK:
|
|
case AddrTileMode.ADDR_TM_3D_TILED_THICK:
|
|
case AddrTileMode.ADDR_TM_3B_TILED_THICK:
|
|
return 4;
|
|
|
|
case AddrTileMode.ADDR_TM_2D_TILED_XTHICK:
|
|
case AddrTileMode.ADDR_TM_3D_TILED_XTHICK:
|
|
return 8;
|
|
|
|
default:
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
private static uint computePixelIndexWithinMicroTile(uint x, uint y, uint z, uint bpp, AddrTileMode tileMode, bool IsDepth)
|
|
{
|
|
uint pixelBit0 = 0;
|
|
uint pixelBit1 = 0;
|
|
uint pixelBit2 = 0;
|
|
uint pixelBit3 = 0;
|
|
uint pixelBit4 = 0;
|
|
uint pixelBit5 = 0;
|
|
uint pixelBit6 = 0;
|
|
uint pixelBit7 = 0;
|
|
uint pixelBit8 = 0;
|
|
|
|
uint thickness = computeSurfaceThickness(tileMode);
|
|
|
|
if (IsDepth)
|
|
{
|
|
pixelBit0 = x & 1;
|
|
pixelBit1 = y & 1;
|
|
pixelBit2 = (x & 2) >> 1;
|
|
pixelBit3 = (y & 2) >> 1;
|
|
pixelBit4 = (x & 4) >> 2;
|
|
pixelBit5 = (y & 4) >> 2;
|
|
}
|
|
else
|
|
{
|
|
switch (bpp)
|
|
{
|
|
case 8:
|
|
pixelBit0 = x & 1;
|
|
pixelBit1 = (x & 2) >> 1;
|
|
pixelBit2 = (x & 4) >> 2;
|
|
pixelBit3 = (y & 2) >> 1;
|
|
pixelBit4 = y & 1;
|
|
pixelBit5 = (y & 4) >> 2;
|
|
break;
|
|
case 0x10:
|
|
pixelBit0 = x & 1;
|
|
pixelBit1 = (x & 2) >> 1;
|
|
pixelBit2 = (x & 4) >> 2;
|
|
pixelBit3 = y & 1;
|
|
pixelBit4 = (y & 2) >> 1;
|
|
pixelBit5 = (y & 4) >> 2;
|
|
break;
|
|
case 0x20:
|
|
case 0x60:
|
|
pixelBit0 = x & 1;
|
|
pixelBit1 = (x & 2) >> 1;
|
|
pixelBit2 = y & 1;
|
|
pixelBit3 = (x & 4) >> 2;
|
|
pixelBit4 = (y & 2) >> 1;
|
|
pixelBit5 = (y & 4) >> 2;
|
|
break;
|
|
case 0x40:
|
|
pixelBit0 = x & 1;
|
|
pixelBit1 = y & 1;
|
|
pixelBit2 = (x & 2) >> 1;
|
|
pixelBit3 = (x & 4) >> 2;
|
|
pixelBit4 = (y & 2) >> 1;
|
|
pixelBit5 = (y & 4) >> 2;
|
|
break;
|
|
case 0x80:
|
|
pixelBit0 = y & 1;
|
|
pixelBit1 = x & 1;
|
|
pixelBit2 = (x & 2) >> 1;
|
|
pixelBit3 = (x & 4) >> 2;
|
|
pixelBit4 = (y & 2) >> 1;
|
|
pixelBit5 = (y & 4) >> 2;
|
|
break;
|
|
default:
|
|
pixelBit0 = x & 1;
|
|
pixelBit1 = (x & 2) >> 1;
|
|
pixelBit2 = y & 1;
|
|
pixelBit3 = (x & 4) >> 2;
|
|
pixelBit4 = (y & 2) >> 1;
|
|
pixelBit5 = (y & 4) >> 2;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (thickness > 1)
|
|
{
|
|
pixelBit6 = z & 1;
|
|
pixelBit7 = (z & 2) >> 1;
|
|
}
|
|
|
|
if (thickness == 8)
|
|
pixelBit8 = (z & 4) >> 2;
|
|
|
|
return (pixelBit8 << 8) | (pixelBit7 << 7) | (pixelBit6 << 6) | 32 * pixelBit5 | 16 * pixelBit4 | 8 * pixelBit3 | 4 * pixelBit2 | pixelBit0 | 2 * pixelBit1;
|
|
}
|
|
|
|
private static uint computePipeFromCoordWoRotation(uint x, uint y)
|
|
{
|
|
return ((y >> 3) ^ (x >> 3)) & 1;
|
|
}
|
|
|
|
|
|
private static uint computeBankFromCoordWoRotation(uint x, uint y)
|
|
{
|
|
return ((y >> 5) ^ (x >> 3)) & 1 | 2 * (((y >> 4) ^ (x >> 4)) & 1);
|
|
}
|
|
|
|
private static uint computeSurfaceRotationFromTileMode(AddrTileMode tileMode)
|
|
{
|
|
switch (tileMode)
|
|
{
|
|
case AddrTileMode.ADDR_TM_2D_TILED_THIN1:
|
|
case AddrTileMode.ADDR_TM_2D_TILED_THIN2:
|
|
case AddrTileMode.ADDR_TM_2D_TILED_THIN4:
|
|
case AddrTileMode.ADDR_TM_2D_TILED_THICK:
|
|
case AddrTileMode.ADDR_TM_2B_TILED_THIN1:
|
|
case AddrTileMode.ADDR_TM_2B_TILED_THIN2:
|
|
case AddrTileMode.ADDR_TM_2B_TILED_THIN4:
|
|
case AddrTileMode.ADDR_TM_2B_TILED_THICK:
|
|
return 2;
|
|
case AddrTileMode.ADDR_TM_3D_TILED_THIN1:
|
|
case AddrTileMode.ADDR_TM_3D_TILED_THICK:
|
|
case AddrTileMode.ADDR_TM_3B_TILED_THIN1:
|
|
case AddrTileMode.ADDR_TM_3B_TILED_THICK:
|
|
return 1;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
private static uint isThickMacroTiled(AddrTileMode tileMode)
|
|
{
|
|
switch (tileMode)
|
|
{
|
|
case AddrTileMode.ADDR_TM_2D_TILED_THICK:
|
|
case AddrTileMode.ADDR_TM_2B_TILED_THICK:
|
|
case AddrTileMode.ADDR_TM_3D_TILED_THICK:
|
|
case AddrTileMode.ADDR_TM_3B_TILED_THICK:
|
|
return 1;
|
|
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
private static uint isBankSwappedTileMode(AddrTileMode tileMode)
|
|
{
|
|
switch (tileMode)
|
|
{
|
|
case AddrTileMode.ADDR_TM_2B_TILED_THIN1:
|
|
case AddrTileMode.ADDR_TM_2B_TILED_THIN2:
|
|
case AddrTileMode.ADDR_TM_2B_TILED_THIN4:
|
|
case AddrTileMode.ADDR_TM_2B_TILED_THICK:
|
|
case AddrTileMode.ADDR_TM_3B_TILED_THIN1:
|
|
case AddrTileMode.ADDR_TM_3B_TILED_THICK:
|
|
return 1;
|
|
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
private static uint computeMacroTileAspectRatio(AddrTileMode tileMode)
|
|
{
|
|
switch (tileMode)
|
|
{
|
|
case AddrTileMode.ADDR_TM_2D_TILED_THIN2:
|
|
case AddrTileMode.ADDR_TM_2B_TILED_THIN2:
|
|
return 2;
|
|
|
|
case AddrTileMode.ADDR_TM_2D_TILED_THIN4:
|
|
case AddrTileMode.ADDR_TM_2B_TILED_THIN4:
|
|
return 4;
|
|
|
|
default:
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
private static uint computeSurfaceBankSwappedWidth(AddrTileMode tileMode, uint bpp, uint numSamples, uint pitch)
|
|
{
|
|
if (isBankSwappedTileMode(tileMode) == 0)
|
|
return 0;
|
|
|
|
uint bytesPerSample = 8 * bpp;
|
|
uint samplesPerTile, slicesPerTile;
|
|
|
|
if (bytesPerSample != 0)
|
|
{
|
|
samplesPerTile = 2048 / bytesPerSample;
|
|
slicesPerTile = Math.Max(1, numSamples / samplesPerTile);
|
|
}
|
|
|
|
else
|
|
slicesPerTile = 1;
|
|
|
|
if (isThickMacroTiled(tileMode) != 0)
|
|
numSamples = 4;
|
|
|
|
uint bytesPerTileSlice = numSamples * bytesPerSample / slicesPerTile;
|
|
|
|
uint factor = computeMacroTileAspectRatio(tileMode);
|
|
uint swapTiles = Math.Max(1, 128 / bpp);
|
|
|
|
uint swapWidth = swapTiles * 32;
|
|
uint heightBytes = numSamples * factor * bpp * 2 / slicesPerTile;
|
|
uint swapMax = 0x4000 / heightBytes;
|
|
uint swapMin = 256 / bytesPerTileSlice;
|
|
|
|
uint bankSwapWidth = Math.Min(swapMax, Math.Max(swapMin, swapWidth));
|
|
|
|
while (bankSwapWidth >= 2 * pitch)
|
|
bankSwapWidth >>= 1;
|
|
|
|
return bankSwapWidth;
|
|
}
|
|
|
|
private static ulong computeSurfaceAddrFromCoordLinear(uint x, uint y, uint slice, uint sample, uint bpp, uint pitch, uint height, uint numSlices)
|
|
{
|
|
uint sliceOffset = pitch * height * (slice + sample * numSlices);
|
|
return (y * pitch + x + sliceOffset) * bpp;
|
|
}
|
|
|
|
private static ulong computeSurfaceAddrFromCoordMicroTiled(uint x, uint y, uint slice, uint bpp, uint pitch, uint height, AddrTileMode tileMode, bool IsDepth)
|
|
{
|
|
int microTileThickness = 1;
|
|
if (tileMode == AddrTileMode.ADDR_TM_1D_TILED_THICK)
|
|
microTileThickness = 4;
|
|
|
|
uint microTileBytes = (uint)(64 * microTileThickness * bpp + 7) / 8;
|
|
uint microTilesPerRow = pitch >> 3;
|
|
uint microTileIndexX = x >> 3;
|
|
uint microTileIndexY = y >> 3;
|
|
uint microTileIndexZ = slice / (uint)microTileThickness;
|
|
|
|
ulong microTileOffset = microTileBytes * (microTileIndexX + microTileIndexY * microTilesPerRow);
|
|
ulong sliceBytes = (ulong)(pitch * height * microTileThickness * bpp + 7) / 8;
|
|
ulong sliceOffset = microTileIndexZ * sliceBytes;
|
|
|
|
uint pixelIndex = computePixelIndexWithinMicroTile(x, y, slice, bpp, tileMode, IsDepth);
|
|
ulong pixelOffset = (bpp * pixelIndex) >> 3;
|
|
|
|
return pixelOffset + microTileOffset + sliceOffset;
|
|
}
|
|
|
|
private static byte[] bankSwapOrder = { 0, 1, 3, 2, 6, 7, 5, 4, 0, 0 };
|
|
|
|
private static ulong computeSurfaceAddrFromCoordMacroTiled(uint x, uint y, uint slice, uint sample, uint bpp, uint pitch, uint height,
|
|
uint numSamples, AddrTileMode tileMode, bool IsDepth, uint pipeSwizzle, uint bankSwizzle)
|
|
{
|
|
uint microTileThickness = computeSurfaceThickness(tileMode);
|
|
|
|
uint microTileBits = numSamples * bpp * (microTileThickness * 64);
|
|
uint microTileBytes = (microTileBits + 7) / 8;
|
|
|
|
uint pixelIndex = computePixelIndexWithinMicroTile(x, y, slice, bpp, tileMode, IsDepth);
|
|
uint bytesPerSample = microTileBytes / numSamples;
|
|
uint sampleOffset = 0;
|
|
uint pixelOffset = 0;
|
|
uint samplesPerSlice = 0;
|
|
uint numSampleSplits = 0;
|
|
uint sampleSlice = 0;
|
|
|
|
if (IsDepth)
|
|
{
|
|
sampleOffset = bpp * sample;
|
|
pixelOffset = numSamples * bpp * pixelIndex;
|
|
}
|
|
else
|
|
{
|
|
sampleOffset = sample * (microTileBits / numSamples);
|
|
pixelOffset = bpp * pixelIndex;
|
|
}
|
|
|
|
uint elemOffset = pixelOffset + sampleOffset;
|
|
|
|
if (numSamples <= 1 || microTileBytes <= 2048)
|
|
{
|
|
samplesPerSlice = numSamples;
|
|
numSampleSplits = 1;
|
|
sampleSlice = 0;
|
|
}
|
|
else
|
|
{
|
|
samplesPerSlice = 2048 / bytesPerSample;
|
|
numSampleSplits = numSamples / samplesPerSlice;
|
|
numSamples = samplesPerSlice;
|
|
|
|
uint tileSliceBits = microTileBits / numSampleSplits;
|
|
sampleSlice = elemOffset / tileSliceBits;
|
|
elemOffset %= tileSliceBits;
|
|
}
|
|
|
|
elemOffset = (elemOffset + 7) / 8;
|
|
|
|
uint pipe = computePipeFromCoordWoRotation(x, y);
|
|
uint bank = computeBankFromCoordWoRotation(x, y);
|
|
|
|
uint swizzle_ = pipeSwizzle + 2 * bankSwizzle;
|
|
uint bankPipe = pipe + 2 * bank;
|
|
uint rotation = computeSurfaceRotationFromTileMode(tileMode);
|
|
uint sliceIn = slice;
|
|
|
|
if (isThickMacroTiled(tileMode) != 0)
|
|
sliceIn >>= 2;
|
|
|
|
bankPipe ^= 2 * sampleSlice * 3 ^ (swizzle_ + sliceIn * rotation);
|
|
bankPipe %= 8;
|
|
|
|
pipe = bankPipe % 2;
|
|
bank = bankPipe / 2;
|
|
|
|
uint sliceBytes = (height * pitch * microTileThickness * bpp * numSamples + 7) / 8;
|
|
uint sliceOffset = sliceBytes * (sampleSlice + numSampleSplits * slice) / microTileThickness;
|
|
|
|
uint macroTilePitch = 32;
|
|
uint macroTileHeight = 16;
|
|
|
|
switch (tileMode)
|
|
{
|
|
case AddrTileMode.ADDR_TM_2D_TILED_THIN2:
|
|
case AddrTileMode.ADDR_TM_2B_TILED_THIN2:
|
|
{
|
|
macroTilePitch = 16;
|
|
macroTileHeight = 32;
|
|
break;
|
|
}
|
|
|
|
case AddrTileMode.ADDR_TM_2D_TILED_THIN4:
|
|
case AddrTileMode.ADDR_TM_2B_TILED_THIN4:
|
|
{
|
|
macroTilePitch = 8;
|
|
macroTileHeight = 64;
|
|
break;
|
|
}
|
|
}
|
|
|
|
uint macroTilesPerRow = pitch / macroTilePitch;
|
|
uint macroTileBytes = (numSamples * microTileThickness * bpp * macroTileHeight
|
|
* macroTilePitch + 7) / 8;
|
|
uint macroTileIndexX = x / macroTilePitch;
|
|
uint macroTileIndexY = y / macroTileHeight;
|
|
ulong macroTileOffset = (macroTileIndexX + macroTilesPerRow * macroTileIndexY) * macroTileBytes;
|
|
|
|
if (isBankSwappedTileMode(tileMode) != 0)
|
|
{
|
|
uint bankSwapWidth = computeSurfaceBankSwappedWidth(tileMode, bpp, 1, pitch);
|
|
uint swapIndex = macroTilePitch * macroTileIndexX / bankSwapWidth;
|
|
bank ^= bankSwapOrder[swapIndex & 3];
|
|
}
|
|
|
|
ulong totalOffset = elemOffset + ((macroTileOffset + sliceOffset) >> 3);
|
|
return bank << 9 | pipe << 8 | totalOffset & 255 | (ulong)((int)totalOffset & -256) << 3;
|
|
}
|
|
|
|
public static uint computeSurfaceMipLevelTileMode(uint baseTileMode, uint bpp, uint level, uint width, uint height,
|
|
uint numSlices, uint numSamples, uint isDepth, uint noRecursive)
|
|
{
|
|
uint widthAlignFactor = 1;
|
|
uint macroTileWidth = 32;
|
|
uint macroTileHeight = 16;
|
|
uint tileSlices = computeSurfaceTileSlices(baseTileMode, bpp, numSamples);
|
|
uint expTileMode = baseTileMode;
|
|
|
|
uint widtha, heighta, numSlicesa, thickness, microTileBytes;
|
|
|
|
if (DebugSurface)
|
|
Console.WriteLine("baseTileMode " + baseTileMode);
|
|
|
|
if (numSamples > 1 || tileSlices > 1 || isDepth != 0)
|
|
{
|
|
if (baseTileMode == 7)
|
|
expTileMode = 4;
|
|
else if (baseTileMode == 13)
|
|
expTileMode = 12;
|
|
else if (baseTileMode == 11)
|
|
expTileMode = 8;
|
|
else if (baseTileMode == 15)
|
|
expTileMode = 14;
|
|
}
|
|
|
|
if (baseTileMode == 2 && numSamples > 1)
|
|
{
|
|
expTileMode = 4;
|
|
}
|
|
else if (baseTileMode == 3)
|
|
{
|
|
if (numSamples > 1 || isDepth != 0)
|
|
expTileMode = 2;
|
|
|
|
if (numSamples == 2 || numSamples == 4)
|
|
expTileMode = 7;
|
|
}
|
|
else
|
|
{
|
|
expTileMode = baseTileMode;
|
|
}
|
|
if (DebugSurface)
|
|
Console.WriteLine("computeSurfaceMipLevelTileMode expTileMode " + expTileMode);
|
|
|
|
if (noRecursive != 0 || level == 0)
|
|
return expTileMode;
|
|
|
|
switch (bpp)
|
|
{
|
|
case 24:
|
|
case 48:
|
|
case 96:
|
|
bpp /= 3;
|
|
break;
|
|
}
|
|
|
|
widtha = nextPow2(width);
|
|
heighta = nextPow2(height);
|
|
numSlicesa = nextPow2(numSlices);
|
|
|
|
expTileMode = convertToNonBankSwappedMode((AddrTileMode)expTileMode);
|
|
thickness = computeSurfaceThickness((AddrTileMode)expTileMode);
|
|
microTileBytes = (numSamples * bpp * (thickness << 6) + 7) >> 3;
|
|
|
|
if (microTileBytes < 256)
|
|
{
|
|
widthAlignFactor = Math.Max(1, 256 / microTileBytes);
|
|
}
|
|
if (expTileMode == 4 || expTileMode == 12)
|
|
{
|
|
if ((widtha < widthAlignFactor * macroTileWidth) || heighta < macroTileHeight)
|
|
expTileMode = 2;
|
|
}
|
|
else if (expTileMode == 5)
|
|
{
|
|
macroTileWidth = 16;
|
|
macroTileHeight = 32;
|
|
|
|
if ((widtha < widthAlignFactor * macroTileWidth) || heighta < macroTileHeight)
|
|
expTileMode = 2;
|
|
}
|
|
else if (expTileMode == 6)
|
|
{
|
|
macroTileWidth = 8;
|
|
macroTileHeight = 64;
|
|
|
|
if ((widtha < widthAlignFactor * macroTileWidth) || heighta < macroTileHeight)
|
|
expTileMode = 2;
|
|
}
|
|
else if (expTileMode == 7 || expTileMode == 13)
|
|
{
|
|
if ((widtha < widthAlignFactor * macroTileWidth) || heighta < macroTileHeight)
|
|
expTileMode = 3;
|
|
}
|
|
|
|
if (numSlicesa < 4)
|
|
{
|
|
if (expTileMode == 3)
|
|
expTileMode = 2;
|
|
else if (expTileMode == 7)
|
|
expTileMode = 4;
|
|
else if (expTileMode == 13)
|
|
expTileMode = 12;
|
|
}
|
|
|
|
return computeSurfaceMipLevelTileMode(
|
|
expTileMode,
|
|
bpp,
|
|
level,
|
|
widtha,
|
|
heighta,
|
|
numSlicesa,
|
|
numSamples,
|
|
isDepth,
|
|
1);
|
|
}
|
|
|
|
private static uint computeSurfaceTileSlices(uint tileMode, uint bpp, uint numSamples)
|
|
{
|
|
uint bytePerSample = ((bpp << 6) + 7) >> 3;
|
|
uint tileSlices = 1;
|
|
uint samplePerTile;
|
|
|
|
if (computeSurfaceThickness((AddrTileMode)tileMode) > 1)
|
|
numSamples = 4;
|
|
|
|
if (bytePerSample != 0)
|
|
{
|
|
samplePerTile = 2048 / bytePerSample;
|
|
if (samplePerTile < numSamples)
|
|
tileSlices = Math.Max(1, numSamples / samplePerTile);
|
|
}
|
|
|
|
return tileSlices;
|
|
}
|
|
|
|
private static uint ComputeSurfaceInfoEx()
|
|
{
|
|
uint tileMode = pIn.tileMode;
|
|
uint bpp = pIn.bpp;
|
|
uint numSamples = Math.Max(1, pIn.numSamples);
|
|
uint pitch = pIn.width;
|
|
Console.WriteLine("ComputeSurfaceInfoEx pitch " + pitch);
|
|
uint height = pIn.height;
|
|
uint numSlices = pIn.numSlices;
|
|
uint mipLevel = pIn.mipLevel;
|
|
Flags flags = new Flags();
|
|
uint pPitchOut = pOut.pitch;
|
|
uint pHeightOut = pOut.height;
|
|
uint pNumSlicesOut = pOut.depth;
|
|
uint pTileModeOut = pOut.tileMode;
|
|
uint pSurfSize = (uint)pOut.surfSize;
|
|
uint pBaseAlign = pOut.baseAlign;
|
|
uint pPitchAlign = pOut.pitchAlign;
|
|
uint pHeightAlign = pOut.heightAlign;
|
|
uint pDepthAlign = pOut.depthAlign;
|
|
uint padDims = 0;
|
|
uint valid = 0;
|
|
uint baseTileMode = tileMode;
|
|
|
|
if (DebugSurface)
|
|
{
|
|
Console.WriteLine("---------------------------");
|
|
Console.WriteLine(tileMode);
|
|
Console.WriteLine(bpp);
|
|
Console.WriteLine(numSamples);
|
|
Console.WriteLine(pitch);
|
|
Console.WriteLine(height);
|
|
Console.WriteLine(numSlices);
|
|
Console.WriteLine(mipLevel);
|
|
Console.WriteLine(flags);
|
|
Console.WriteLine(pPitchOut);
|
|
Console.WriteLine(pHeightOut);
|
|
Console.WriteLine(pNumSlicesOut);
|
|
Console.WriteLine(pTileModeOut);
|
|
Console.WriteLine(pSurfSize);
|
|
Console.WriteLine(pBaseAlign);
|
|
Console.WriteLine(pPitchAlign);
|
|
Console.WriteLine(pHeightAlign);
|
|
Console.WriteLine(pDepthAlign);
|
|
Console.WriteLine(padDims);
|
|
Console.WriteLine(valid);
|
|
Console.WriteLine(baseTileMode);
|
|
Console.WriteLine("---------------------------");
|
|
}
|
|
|
|
|
|
flags.value = pIn.flags.value;
|
|
|
|
Console.WriteLine("padDims " + padDims);
|
|
|
|
if ((((flags.value >> 4) & 1) != 0) && (mipLevel == 0))
|
|
padDims = 2;
|
|
|
|
Console.WriteLine("padDims " + padDims);
|
|
|
|
if (((flags.value >> 6) & 1) != 0)
|
|
tileMode = convertToNonBankSwappedMode((AddrTileMode)tileMode);
|
|
else
|
|
{
|
|
if (DebugSurface)
|
|
Console.WriteLine(tileMode);
|
|
|
|
tileMode = computeSurfaceMipLevelTileMode(
|
|
tileMode,
|
|
bpp,
|
|
mipLevel,
|
|
pitch,
|
|
height,
|
|
numSlices,
|
|
numSamples,
|
|
(flags.value >> 1) & 1, 0);
|
|
|
|
if (DebugSurface)
|
|
{
|
|
Console.WriteLine("---------------------------");
|
|
Console.WriteLine(tileMode);
|
|
Console.WriteLine("---------------------------");
|
|
}
|
|
}
|
|
|
|
|
|
switch (tileMode)
|
|
{
|
|
case 0:
|
|
case 1:
|
|
var compSurfInfoLinear = computeSurfaceInfoLinear(
|
|
tileMode,
|
|
bpp,
|
|
numSamples,
|
|
pitch,
|
|
height,
|
|
numSlices,
|
|
mipLevel,
|
|
padDims,
|
|
flags);
|
|
|
|
valid = compSurfInfoLinear[0];
|
|
pPitchOut = compSurfInfoLinear[1];
|
|
pHeightOut = compSurfInfoLinear[2];
|
|
pNumSlicesOut = compSurfInfoLinear[3];
|
|
pSurfSize = compSurfInfoLinear[4];
|
|
pBaseAlign = compSurfInfoLinear[5];
|
|
pPitchAlign = compSurfInfoLinear[6];
|
|
pHeightAlign = compSurfInfoLinear[7];
|
|
pDepthAlign = compSurfInfoLinear[8];
|
|
|
|
pTileModeOut = tileMode;
|
|
break;
|
|
case 2:
|
|
case 3:
|
|
var compSurfInfoMicroTile = computeSurfaceInfoMicroTiled(
|
|
tileMode,
|
|
bpp,
|
|
numSamples,
|
|
pitch,
|
|
height,
|
|
numSlices,
|
|
mipLevel,
|
|
padDims,
|
|
flags);
|
|
|
|
valid = compSurfInfoMicroTile[0];
|
|
pPitchOut = compSurfInfoMicroTile[1];
|
|
pHeightOut = compSurfInfoMicroTile[2];
|
|
pNumSlicesOut = compSurfInfoMicroTile[3];
|
|
pSurfSize = compSurfInfoMicroTile[4];
|
|
pTileModeOut = compSurfInfoMicroTile[5];
|
|
pBaseAlign = compSurfInfoMicroTile[6];
|
|
pPitchAlign = compSurfInfoMicroTile[7];
|
|
pHeightAlign = compSurfInfoMicroTile[8];
|
|
pDepthAlign = compSurfInfoMicroTile[9];
|
|
|
|
break;
|
|
case 4:
|
|
case 5:
|
|
case 6:
|
|
case 7:
|
|
case 8:
|
|
case 9:
|
|
case 10:
|
|
case 11:
|
|
case 12:
|
|
case 13:
|
|
case 14:
|
|
case 15:
|
|
var compSurfInfoMacoTile = computeSurfaceInfoMacroTiled(
|
|
tileMode,
|
|
baseTileMode,
|
|
bpp,
|
|
numSamples,
|
|
pitch,
|
|
height,
|
|
numSlices,
|
|
mipLevel,
|
|
padDims,
|
|
flags);
|
|
|
|
valid = compSurfInfoMacoTile[0];
|
|
pPitchOut = compSurfInfoMacoTile[1];
|
|
pHeightOut = compSurfInfoMacoTile[2];
|
|
pNumSlicesOut = compSurfInfoMacoTile[3];
|
|
pSurfSize = compSurfInfoMacoTile[4];
|
|
pTileModeOut = compSurfInfoMacoTile[5];
|
|
pBaseAlign = compSurfInfoMacoTile[6];
|
|
pPitchAlign = compSurfInfoMacoTile[7];
|
|
pHeightAlign = compSurfInfoMacoTile[8];
|
|
pDepthAlign = compSurfInfoMacoTile[9];
|
|
break;
|
|
}
|
|
|
|
pOut.pitch = pPitchOut;
|
|
pOut.height = pHeightOut;
|
|
pOut.depth = pNumSlicesOut;
|
|
pOut.tileMode = pTileModeOut;
|
|
pOut.surfSize = pSurfSize;
|
|
pOut.baseAlign = pBaseAlign;
|
|
pOut.pitchAlign = pPitchAlign;
|
|
pOut.heightAlign = pHeightAlign;
|
|
pOut.depthAlign = pDepthAlign;
|
|
|
|
if (DebugSurface)
|
|
{
|
|
Console.WriteLine(pOut.pitch);
|
|
Console.WriteLine(pOut.height);
|
|
Console.WriteLine(pOut.depth);
|
|
Console.WriteLine(pOut.tileMode);
|
|
Console.WriteLine(pOut.surfSize);
|
|
Console.WriteLine(pOut.baseAlign);
|
|
Console.WriteLine(pOut.pitchAlign);
|
|
Console.WriteLine(pOut.heightAlign);
|
|
Console.WriteLine(pOut.depthAlign);
|
|
}
|
|
|
|
|
|
if (valid == 0)
|
|
return 3;
|
|
|
|
return 0;
|
|
}
|
|
private static uint[] computeSurfaceInfoLinear(uint tileMode, uint bpp, uint numSamples, uint pitch, uint height,
|
|
uint numSlices, uint mipLevel, uint padDims, Flags flags)
|
|
{
|
|
expPitch = pitch;
|
|
expHeight = height;
|
|
expNumSlices = numSlices;
|
|
|
|
uint valid = 1;
|
|
uint microTileThickness = computeSurfaceThickness((AddrTileMode)tileMode);
|
|
|
|
uint baseAlign, pitchAlign, heightAlign, slices;
|
|
uint pPitchOut, pHeightOut, pNumSlicesOut, pSurfSize, pBaseAlign, pPitchAlign, pHeightAlign, pDepthAlign;
|
|
|
|
var compAllignLinear = computeSurfaceAlignmentsLinear(tileMode, bpp, flags);
|
|
baseAlign = compAllignLinear.Item1;
|
|
pitchAlign = compAllignLinear.Item2;
|
|
heightAlign = compAllignLinear.Item3;
|
|
|
|
if ((((flags.value >> 9) & 1) != 0) && (mipLevel == 0))
|
|
{
|
|
expPitch /= 3;
|
|
expPitch = nextPow2(expPitch);
|
|
}
|
|
if (mipLevel != 0)
|
|
{
|
|
expPitch = nextPow2(expPitch);
|
|
expHeight = nextPow2(expHeight);
|
|
|
|
if (((flags.value >> 4) & 1) != 0)
|
|
{
|
|
expNumSlices = numSlices;
|
|
|
|
if (numSlices <= 1)
|
|
padDims = 2;
|
|
else
|
|
padDims = 0;
|
|
}
|
|
else
|
|
expNumSlices = nextPow2(numSlices);
|
|
}
|
|
|
|
var padimens = padDimensions(
|
|
tileMode,
|
|
padDims,
|
|
(flags.value >> 4) & 1,
|
|
pitchAlign,
|
|
heightAlign,
|
|
microTileThickness);
|
|
|
|
expPitch = padimens.Item1;
|
|
expHeight = padimens.Item2;
|
|
expNumSlices = padimens.Item3;
|
|
|
|
if ((((flags.value >> 9) & 1) != 0) && (mipLevel == 0))
|
|
expPitch *= 3;
|
|
|
|
slices = expNumSlices * numSamples / microTileThickness;
|
|
pPitchOut = expPitch;
|
|
pHeightOut = expHeight;
|
|
pNumSlicesOut = expNumSlices;
|
|
pSurfSize = (expHeight * expPitch * slices * bpp * numSamples + 7) / 8;
|
|
pBaseAlign = baseAlign;
|
|
pPitchAlign = pitchAlign;
|
|
pHeightAlign = heightAlign;
|
|
pDepthAlign = microTileThickness;
|
|
|
|
return new uint[] { valid, pPitchOut, pHeightOut, pNumSlicesOut, pSurfSize, pBaseAlign, pPitchAlign, pHeightAlign, pDepthAlign };
|
|
}
|
|
private static Tuple<uint, uint, uint> computeSurfaceAlignmentsLinear(uint tileMode, uint bpp, Flags flags)
|
|
{
|
|
uint pixelsPerPipeInterleave;
|
|
uint baseAlign, pitchAlign, heightAlign;
|
|
|
|
if (tileMode == 0)
|
|
{
|
|
baseAlign = 1;
|
|
pitchAlign = (bpp != 1 ? (uint)1 : 8);
|
|
heightAlign = 1;
|
|
}
|
|
else if (tileMode == 1)
|
|
{
|
|
pixelsPerPipeInterleave = 2048 / bpp;
|
|
baseAlign = 256;
|
|
pitchAlign = Math.Max(0x40, pixelsPerPipeInterleave);
|
|
heightAlign = 1;
|
|
}
|
|
else
|
|
{
|
|
baseAlign = 1;
|
|
pitchAlign = 1;
|
|
heightAlign = 1;
|
|
}
|
|
pitchAlign = adjustPitchAlignment(flags, pitchAlign);
|
|
|
|
return new Tuple<uint, uint, uint>(baseAlign, pitchAlign, heightAlign);
|
|
}
|
|
private static uint convertToNonBankSwappedMode(AddrTileMode tileMode)
|
|
{
|
|
switch ((uint)tileMode)
|
|
{
|
|
case 8:
|
|
return 4;
|
|
case 9:
|
|
return 5;
|
|
case 10:
|
|
return 6;
|
|
case 11:
|
|
return 7;
|
|
case 14:
|
|
return 12;
|
|
case 15:
|
|
return 13;
|
|
}
|
|
return (uint)tileMode;
|
|
}
|
|
|
|
private static void computeSurfaceInfo(surfaceIn aSurfIn, surfaceOut pSurfOut)
|
|
{
|
|
if (DebugSurface)
|
|
{
|
|
Console.WriteLine(" computeSurfaceInfo ------------------------------------ ");
|
|
|
|
}
|
|
|
|
pIn = aSurfIn;
|
|
pOut = pSurfOut;
|
|
|
|
uint returnCode = 0;
|
|
|
|
uint width, height, bpp, elemMode = 0;
|
|
uint expandY, expandX;
|
|
|
|
if (pIn.bpp > 0x80)
|
|
returnCode = 3;
|
|
|
|
if (DebugSurface)
|
|
Console.WriteLine("returnCode " + returnCode);
|
|
|
|
if (returnCode == 0)
|
|
{
|
|
if (DebugSurface)
|
|
{
|
|
Console.WriteLine("-------------------------------------------");
|
|
Console.WriteLine(" computeMipLevel");
|
|
Console.WriteLine("-------------------------------------------");
|
|
Console.WriteLine(" pIn.width " + pIn.width);
|
|
Console.WriteLine(" pIn.height " + pIn.height);
|
|
Console.WriteLine(" pIn.numSlices " + pIn.numSlices);
|
|
}
|
|
|
|
computeMipLevel();
|
|
|
|
width = pIn.width;
|
|
height = pIn.height;
|
|
bpp = pIn.bpp;
|
|
expandX = 1;
|
|
expandY = 1;
|
|
|
|
if (DebugSurface)
|
|
{
|
|
Console.WriteLine(pIn.width);
|
|
Console.WriteLine(pIn.height);
|
|
Console.WriteLine(pIn.numSlices);
|
|
Console.WriteLine("-------------------------------------------");
|
|
}
|
|
|
|
pOut.pixelBits = pIn.bpp;
|
|
|
|
if (pIn.format != 0)
|
|
{
|
|
bpp = formatExInfo[pIn.format * 4];
|
|
expandX = formatExInfo[pIn.format * 4 + 1];
|
|
expandY = formatExInfo[pIn.format * 4 + 2];
|
|
elemMode = formatExInfo[pIn.format * 4 + 3];
|
|
|
|
if (DebugSurface)
|
|
{
|
|
Console.WriteLine($"bpp {bpp}");
|
|
Console.WriteLine($"expandX {expandX}");
|
|
Console.WriteLine($"expandY {expandY}");
|
|
Console.WriteLine($"elemMode {elemMode}");
|
|
}
|
|
|
|
|
|
if (elemMode == 4 && expandX == 3 && pIn.tileMode == 1)
|
|
pIn.flags.value |= 0x200;
|
|
|
|
bpp = adjustSurfaceInfo(elemMode, expandX, expandY, bpp, width, height);
|
|
|
|
if (DebugSurface)
|
|
{
|
|
Console.WriteLine($"width {pIn.width}");
|
|
Console.WriteLine($"height {pIn.height}");
|
|
Console.WriteLine($"bpp {pIn.bpp}");
|
|
}
|
|
}
|
|
else if (pIn.bpp != 0)
|
|
{
|
|
pIn.width = Math.Max(1, pIn.width);
|
|
pIn.height = Math.Max(1, pIn.height);
|
|
}
|
|
else
|
|
returnCode = 3;
|
|
|
|
if (returnCode == 0)
|
|
returnCode = ComputeSurfaceInfoEx();
|
|
|
|
if (returnCode == 0)
|
|
{
|
|
pOut.bpp = pIn.bpp;
|
|
pOut.pixelPitch = pOut.pitch;
|
|
pOut.pixelHeight = pOut.height;
|
|
|
|
if (pIn.format != 0 && (((pIn.flags.value >> 9) & 1) == 0 || pIn.mipLevel == 0))
|
|
bpp = restoreSurfaceInfo(elemMode, expandX, expandY, bpp);
|
|
|
|
if (((pIn.flags.value >> 5) & 1) != 0)
|
|
pOut.sliceSize = (uint)pOut.surfSize;
|
|
|
|
else
|
|
{
|
|
pOut.sliceSize = (uint)(pOut.surfSize / pOut.depth);
|
|
|
|
if (pIn.slice == (pIn.numSlices - 1) && pIn.numSlices > 1)
|
|
pOut.sliceSize += pOut.sliceSize * (pOut.depth - pIn.numSlices);
|
|
}
|
|
|
|
pOut.pitchTileMax = (pOut.pitch >> 3) - 1;
|
|
pOut.heightTileMax = (pOut.height >> 3) - 1;
|
|
pOut.sliceTileMax = (pOut.height * pOut.pitch >> 6) - 1;
|
|
}
|
|
}
|
|
}
|
|
private static uint[] computeSurfaceInfoMicroTiled(uint tileMode, uint bpp, uint numSamples, uint pitch, uint height, uint numSlices, uint mipLevel, uint padDims, Flags flags)
|
|
{
|
|
expPitch = pitch;
|
|
expHeight = height;
|
|
expNumSlices = numSlices;
|
|
|
|
uint valid = 1;
|
|
uint expTileMode = tileMode;
|
|
uint microTileThickness = computeSurfaceThickness((AddrTileMode)tileMode);
|
|
uint pPitchOut, pHeightOut, pNumSlicesOut, pSurfSize, pTileModeOut, pBaseAlign, pPitchAlign, pHeightAlign, pDepthAlign;
|
|
|
|
if (mipLevel != 0)
|
|
{
|
|
expPitch = nextPow2(pitch);
|
|
expHeight = nextPow2(height);
|
|
if (((flags.value >> 4) & 1) != 0)
|
|
{
|
|
expNumSlices = numSlices;
|
|
|
|
if (numSlices <= 1)
|
|
padDims = 2;
|
|
|
|
else
|
|
padDims = 0;
|
|
}
|
|
|
|
else
|
|
expNumSlices = nextPow2(numSlices);
|
|
|
|
if (expTileMode == 3 && expNumSlices < 4)
|
|
{
|
|
expTileMode = 2;
|
|
microTileThickness = 1;
|
|
}
|
|
}
|
|
|
|
var surfMicroAlign = computeSurfaceAlignmentsMicroTiled(
|
|
expTileMode,
|
|
bpp,
|
|
flags,
|
|
numSamples);
|
|
|
|
uint baseAlign = surfMicroAlign.Item1;
|
|
uint pitchAlign = surfMicroAlign.Item2;
|
|
uint heightAlign = surfMicroAlign.Item3;
|
|
|
|
var padDimens = padDimensions(
|
|
expTileMode,
|
|
padDims,
|
|
(flags.value >> 4) & 1,
|
|
pitchAlign,
|
|
heightAlign,
|
|
microTileThickness);
|
|
|
|
expPitch = padDimens.Item1;
|
|
expHeight = padDimens.Item2;
|
|
expNumSlices = padDimens.Item3;
|
|
|
|
pPitchOut = expPitch;
|
|
pHeightOut = expHeight;
|
|
pNumSlicesOut = expNumSlices;
|
|
pSurfSize = (expHeight * expPitch * expNumSlices * bpp * numSamples + 7) / 8;
|
|
|
|
Console.WriteLine("pSurfSize " + pSurfSize);
|
|
Console.WriteLine("expHeight " + expHeight);
|
|
Console.WriteLine("expPitch " + expPitch);
|
|
Console.WriteLine("expNumSlices " + expNumSlices);
|
|
Console.WriteLine("numSamples " + numSamples);
|
|
|
|
pTileModeOut = expTileMode;
|
|
pBaseAlign = baseAlign;
|
|
pPitchAlign = pitchAlign;
|
|
pHeightAlign = heightAlign;
|
|
pDepthAlign = microTileThickness;
|
|
|
|
return new uint[] { valid, pPitchOut, pHeightOut, pNumSlicesOut, pSurfSize, pTileModeOut, pBaseAlign, pPitchAlign, pHeightAlign, pDepthAlign };
|
|
}
|
|
private static Tuple<uint, uint, uint> padDimensions(uint tileMode, uint padDims, uint isCube, uint pitchAlign, uint heightAlign, uint sliceAlign)
|
|
{
|
|
uint thickness = computeSurfaceThickness((AddrTileMode)tileMode);
|
|
if (padDims == 0)
|
|
padDims = 3;
|
|
|
|
if ((pitchAlign & (pitchAlign - 1)) == 0)
|
|
expPitch = powTwoAlign(expPitch, pitchAlign);
|
|
else
|
|
{
|
|
expPitch += pitchAlign - 1;
|
|
expPitch /= pitchAlign;
|
|
expPitch *= pitchAlign;
|
|
}
|
|
|
|
if (padDims > 1)
|
|
expHeight = powTwoAlign(expHeight, heightAlign);
|
|
|
|
if (padDims > 2 || thickness > 1)
|
|
{
|
|
if (isCube != 0)
|
|
expNumSlices = nextPow2(expNumSlices);
|
|
|
|
if (thickness > 1)
|
|
expNumSlices = powTwoAlign(expNumSlices, sliceAlign);
|
|
}
|
|
return new Tuple<uint, uint, uint>(expPitch, expHeight, expNumSlices);
|
|
}
|
|
|
|
|
|
private static uint[] computeSurfaceInfoMacroTiled(uint tileMode, uint baseTileMode, uint bpp, uint numSamples,
|
|
uint pitch, uint height, uint numSlices, uint mipLevel, uint padDims, Flags flags)
|
|
{
|
|
expPitch = pitch;
|
|
expHeight = height;
|
|
expNumSlices = numSlices;
|
|
|
|
uint valid = 1;
|
|
uint expTileMode = tileMode;
|
|
uint microTileThickness = computeSurfaceThickness((AddrTileMode)tileMode);
|
|
|
|
uint baseAlign, pitchAlign, heightAlign, macroWidth, macroHeight;
|
|
uint bankSwappedWidth, pitchAlignFactor;
|
|
uint result, pPitchOut, pHeightOut, pNumSlicesOut, pSurfSize, pTileModeOut, pBaseAlign, pPitchAlign, pHeightAlign, pDepthAlign;
|
|
|
|
if (mipLevel != 0)
|
|
{
|
|
expPitch = nextPow2(pitch);
|
|
expHeight = nextPow2(height);
|
|
|
|
if (((flags.value >> 4) & 1) != 0)
|
|
{
|
|
expNumSlices = numSlices;
|
|
|
|
if (numSlices <= 1)
|
|
padDims = 2;
|
|
else
|
|
padDims = 0;
|
|
}
|
|
else
|
|
expNumSlices = nextPow2(numSlices);
|
|
|
|
if (expTileMode == 7 && expNumSlices < 4)
|
|
{
|
|
expTileMode = 4;
|
|
microTileThickness = 1;
|
|
}
|
|
}
|
|
if (tileMode == baseTileMode
|
|
|| mipLevel == 0
|
|
|| isThickMacroTiled((AddrTileMode)baseTileMode) == 0
|
|
|| isThickMacroTiled((AddrTileMode)tileMode) != 0)
|
|
{
|
|
var tup = computeSurfaceAlignmentsMacroTiled(
|
|
tileMode,
|
|
bpp,
|
|
flags,
|
|
numSamples);
|
|
|
|
baseAlign = tup.Item1;
|
|
pitchAlign = tup.Item2;
|
|
heightAlign = tup.Item3;
|
|
macroWidth = tup.Item4;
|
|
macroHeight = tup.Item5;
|
|
|
|
bankSwappedWidth = computeSurfaceBankSwappedWidth((AddrTileMode)tileMode, bpp, numSamples, pitch);
|
|
|
|
if (bankSwappedWidth > pitchAlign)
|
|
pitchAlign = bankSwappedWidth;
|
|
|
|
var padDimens = padDimensions(
|
|
tileMode,
|
|
padDims,
|
|
(flags.value >> 4) & 1,
|
|
pitchAlign,
|
|
heightAlign,
|
|
microTileThickness);
|
|
|
|
expPitch = padDimens.Item1;
|
|
expHeight = padDimens.Item2;
|
|
expNumSlices = padDimens.Item3;
|
|
|
|
pPitchOut = expPitch;
|
|
pHeightOut = expHeight;
|
|
pNumSlicesOut = expNumSlices;
|
|
pSurfSize = (expHeight * expPitch * expNumSlices * bpp * numSamples + 7) / 8;
|
|
pTileModeOut = expTileMode;
|
|
pBaseAlign = baseAlign;
|
|
pPitchAlign = pitchAlign;
|
|
pHeightAlign = heightAlign;
|
|
pDepthAlign = microTileThickness;
|
|
result = valid;
|
|
}
|
|
|
|
else
|
|
{
|
|
var tup = computeSurfaceAlignmentsMacroTiled(
|
|
baseTileMode,
|
|
bpp,
|
|
flags,
|
|
numSamples);
|
|
|
|
baseAlign = tup.Item1;
|
|
pitchAlign = tup.Item2;
|
|
heightAlign = tup.Item3;
|
|
macroWidth = tup.Item4;
|
|
macroHeight = tup.Item5;
|
|
|
|
pitchAlignFactor = Math.Max(1, 32 / bpp);
|
|
|
|
if (expPitch < pitchAlign * pitchAlignFactor || expHeight < heightAlign)
|
|
{
|
|
expTileMode = 2;
|
|
|
|
var microTileInfo = computeSurfaceInfoMicroTiled(
|
|
2,
|
|
bpp,
|
|
numSamples,
|
|
pitch,
|
|
height,
|
|
numSlices,
|
|
mipLevel,
|
|
padDims,
|
|
flags);
|
|
|
|
result = microTileInfo[0];
|
|
pPitchOut = microTileInfo[1];
|
|
pHeightOut = microTileInfo[2];
|
|
pNumSlicesOut = microTileInfo[3];
|
|
pSurfSize = microTileInfo[4];
|
|
pTileModeOut = microTileInfo[5];
|
|
pBaseAlign = microTileInfo[6];
|
|
pPitchAlign = microTileInfo[7];
|
|
pHeightAlign = microTileInfo[8];
|
|
pDepthAlign = microTileInfo[9];
|
|
}
|
|
|
|
else
|
|
{
|
|
tup = computeSurfaceAlignmentsMacroTiled(
|
|
tileMode,
|
|
bpp,
|
|
flags,
|
|
numSamples);
|
|
|
|
baseAlign = tup.Item1;
|
|
pitchAlign = tup.Item2;
|
|
heightAlign = tup.Item3;
|
|
macroWidth = tup.Item4;
|
|
macroHeight = tup.Item5;
|
|
|
|
bankSwappedWidth = computeSurfaceBankSwappedWidth((AddrTileMode)tileMode, bpp, numSamples, pitch);
|
|
if (bankSwappedWidth > pitchAlign)
|
|
pitchAlign = bankSwappedWidth;
|
|
|
|
var padDimens = padDimensions(
|
|
tileMode,
|
|
padDims,
|
|
(flags.value >> 4) & 1,
|
|
pitchAlign,
|
|
heightAlign,
|
|
microTileThickness);
|
|
|
|
expPitch = padDimens.Item1;
|
|
expHeight = padDimens.Item2;
|
|
expNumSlices = padDimens.Item3;
|
|
|
|
pPitchOut = expPitch;
|
|
pHeightOut = expHeight;
|
|
pNumSlicesOut = expNumSlices;
|
|
pSurfSize = (expHeight * expPitch * expNumSlices * bpp * numSamples + 7) / 8;
|
|
|
|
pTileModeOut = expTileMode;
|
|
pBaseAlign = baseAlign;
|
|
pPitchAlign = pitchAlign;
|
|
pHeightAlign = heightAlign;
|
|
pDepthAlign = microTileThickness;
|
|
result = valid;
|
|
}
|
|
}
|
|
|
|
return new uint[] { result, pPitchOut, pHeightOut,
|
|
pNumSlicesOut, pSurfSize, pTileModeOut, pBaseAlign, pitchAlign, heightAlign, pDepthAlign};
|
|
}
|
|
private static Tuple<uint, uint, uint> computeSurfaceAlignmentsMicroTiled(uint tileMode, uint bpp, Flags flags, uint numSamples)
|
|
{
|
|
switch (bpp)
|
|
{
|
|
case 24:
|
|
case 48:
|
|
case 96:
|
|
bpp /= 3;
|
|
break;
|
|
}
|
|
uint thickness = computeSurfaceThickness((AddrTileMode)tileMode);
|
|
uint baseAlign = 256;
|
|
uint pitchAlign = Math.Max(8, 256 / bpp / numSamples / thickness);
|
|
uint heightAlign = 8;
|
|
|
|
pitchAlign = adjustPitchAlignment(flags, pitchAlign);
|
|
|
|
return new Tuple<uint, uint, uint>(baseAlign, pitchAlign, heightAlign);
|
|
|
|
}
|
|
private static Tuple<uint, uint, uint, uint, uint> computeSurfaceAlignmentsMacroTiled(uint tileMode, uint bpp, Flags flags, uint numSamples)
|
|
{
|
|
uint aspectRatio = computeMacroTileAspectRatio((AddrTileMode)tileMode);
|
|
uint thickness = computeSurfaceThickness((AddrTileMode)tileMode);
|
|
|
|
switch (bpp)
|
|
{
|
|
case 24:
|
|
case 48:
|
|
case 96:
|
|
bpp /= 3;
|
|
break;
|
|
case 3:
|
|
bpp = 1;
|
|
break;
|
|
}
|
|
uint macroTileWidth = 32 / aspectRatio;
|
|
uint macroTileHeight = aspectRatio * 16;
|
|
|
|
uint pitchAlign = Math.Max(macroTileWidth, macroTileWidth * (256 / bpp / (8 * thickness) / numSamples));
|
|
pitchAlign = adjustPitchAlignment(flags, pitchAlign);
|
|
|
|
uint heightAlign = macroTileHeight;
|
|
uint macroTileBytes = numSamples * ((bpp * macroTileHeight * macroTileWidth + 7) >> 3);
|
|
|
|
uint baseAlign;
|
|
|
|
if (thickness == 1)
|
|
baseAlign = Math.Max(macroTileBytes, (numSamples * heightAlign * bpp * pitchAlign + 7) >> 3);
|
|
else
|
|
baseAlign = Math.Max(256, (4 * heightAlign * bpp * pitchAlign + 7) >> 3);
|
|
|
|
uint microTileBytes = (thickness * numSamples * (bpp << 6) + 7) >> 3;
|
|
uint numSlicesPerMicroTile = (microTileBytes < 2048 ? (uint)1 : microTileBytes / 2048);
|
|
|
|
baseAlign /= numSlicesPerMicroTile;
|
|
|
|
return new Tuple<uint, uint, uint, uint, uint>(baseAlign, pitchAlign, heightAlign, macroTileWidth, macroTileHeight);
|
|
}
|
|
private static uint adjustPitchAlignment(Flags flags, uint pitchAlign)
|
|
{
|
|
if (((flags.value >> 13) & 1) != 0)
|
|
pitchAlign = powTwoAlign(pitchAlign, 0x20);
|
|
|
|
return pitchAlign;
|
|
}
|
|
private static uint adjustSurfaceInfo(uint elemMode, uint expandX, uint expandY, uint bpp, uint width, uint height)
|
|
{
|
|
uint bBCnFormat = 0;
|
|
uint widtha, heighta;
|
|
|
|
switch (elemMode)
|
|
{
|
|
case 9:
|
|
case 10:
|
|
case 11:
|
|
case 12:
|
|
case 13:
|
|
if (bpp != 0)
|
|
bBCnFormat = 1;
|
|
|
|
break;
|
|
}
|
|
|
|
if (width != 0 && height != 0)
|
|
{
|
|
if (expandX > 1 || expandY > 1)
|
|
{
|
|
if (elemMode == 4)
|
|
{
|
|
widtha = expandX * width;
|
|
heighta = expandY * height;
|
|
}
|
|
else if (bBCnFormat != 0)
|
|
{
|
|
widtha = width / expandX;
|
|
heighta = height / expandY;
|
|
}
|
|
else
|
|
{
|
|
widtha = (width + expandX - 1) / expandX;
|
|
heighta = (height + expandY - 1) / expandY;
|
|
}
|
|
|
|
pIn.width = Math.Max(1, widtha);
|
|
pIn.height = Math.Max(1, heighta);
|
|
}
|
|
}
|
|
|
|
if (bpp != 0)
|
|
{
|
|
switch (elemMode)
|
|
{
|
|
case 4:
|
|
pIn.bpp = bpp / expandX / expandY;
|
|
break;
|
|
|
|
case 5:
|
|
case 6:
|
|
pIn.bpp = expandY * expandX * bpp;
|
|
break;
|
|
|
|
case 9:
|
|
case 12:
|
|
pIn.bpp = 64;
|
|
break;
|
|
|
|
case 10:
|
|
case 11:
|
|
case 13:
|
|
pIn.bpp = 128;
|
|
break;
|
|
|
|
default:
|
|
pIn.bpp = bpp;
|
|
break;
|
|
}
|
|
|
|
return pIn.bpp;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
private static void computeMipLevel()
|
|
{
|
|
uint slices = 0;
|
|
uint height = 0;
|
|
uint width = 0;
|
|
uint hwlHandled = 0;
|
|
|
|
if (49 <= pIn.format && pIn.format <= 55 && (pIn.mipLevel == 0 || ((pIn.flags.value >> 12) & 1) != 0))
|
|
{
|
|
pIn.width = powTwoAlign(pIn.width, 4);
|
|
pIn.height = powTwoAlign(pIn.height, 4);
|
|
}
|
|
|
|
|
|
if (DebugSurface)
|
|
{
|
|
Console.WriteLine("-------------------------------------------");
|
|
Console.WriteLine(" hwlComputeMipLevel");
|
|
Console.WriteLine("-------------------------------------------");
|
|
Console.WriteLine(" pIn.width " + pIn.width);
|
|
Console.WriteLine(" pIn.height " + pIn.height);
|
|
Console.WriteLine(" pIn.numSlices " + pIn.numSlices);
|
|
}
|
|
|
|
hwlHandled = hwlComputeMipLevel();
|
|
if (DebugSurface)
|
|
{
|
|
Console.WriteLine(" Output:");
|
|
Console.WriteLine(" pIn.width " + pIn.width);
|
|
Console.WriteLine(" pIn.height " + pIn.height);
|
|
Console.WriteLine(" pIn.numSlices " + pIn.numSlices);
|
|
Console.WriteLine("-------------------------------------------");
|
|
}
|
|
|
|
if (hwlHandled == 0 && pIn.mipLevel != 0 && ((pIn.flags.value >> 12) & 1) != 0)
|
|
{
|
|
width = Math.Max(1, pIn.width >> (int)pIn.mipLevel);
|
|
height = Math.Max(1, pIn.height >> (int)pIn.mipLevel);
|
|
slices = Math.Max(1, pIn.numSlices);
|
|
|
|
if (((pIn.flags.value >> 4) & 1) == 0)
|
|
slices = Math.Max(1, slices >> (int)pIn.mipLevel);
|
|
|
|
if (pIn.format != 47 && pIn.format != 48)
|
|
{
|
|
width = nextPow2(width);
|
|
height = nextPow2(height);
|
|
slices = nextPow2(slices);
|
|
}
|
|
pIn.width = width;
|
|
pIn.height = height;
|
|
pIn.numSlices = slices;
|
|
}
|
|
}
|
|
|
|
private static uint restoreSurfaceInfo(uint elemMode, uint expandX, uint expandY, uint bpp)
|
|
{
|
|
uint width, height;
|
|
|
|
if (pOut.pixelPitch != 0 && pOut.pixelHeight != 0)
|
|
{
|
|
width = pOut.pixelPitch;
|
|
height = pOut.pixelHeight;
|
|
|
|
if (expandX > 1 || expandY > 1)
|
|
{
|
|
if (elemMode == 4)
|
|
{
|
|
width /= expandX;
|
|
height /= expandY;
|
|
}
|
|
|
|
else
|
|
{
|
|
width *= expandX;
|
|
height *= expandY;
|
|
}
|
|
}
|
|
|
|
pOut.pixelPitch = Math.Max(1, width);
|
|
pOut.pixelHeight = Math.Max(1, height);
|
|
}
|
|
if (bpp != 0)
|
|
{
|
|
switch (elemMode)
|
|
{
|
|
case 4:
|
|
return expandY * expandX * bpp;
|
|
|
|
case 5:
|
|
case 6:
|
|
return bpp / expandX / expandY;
|
|
|
|
case 9:
|
|
case 12:
|
|
return 64;
|
|
|
|
case 10:
|
|
case 11:
|
|
case 13:
|
|
return 128;
|
|
|
|
default:
|
|
return bpp;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
private static uint hwlComputeMipLevel()
|
|
{
|
|
uint handled = 0;
|
|
|
|
if (49 <= pIn.format && pIn.format <= 55)
|
|
{
|
|
if (pIn.mipLevel != 0)
|
|
{
|
|
uint width = pIn.width;
|
|
uint height = pIn.height;
|
|
uint slices = pIn.numSlices;
|
|
|
|
if (((pIn.flags.value >> 12) & 1) != 0)
|
|
{
|
|
uint widtha = width >> (int)pIn.mipLevel;
|
|
uint heighta = height >> (int)pIn.mipLevel;
|
|
|
|
if (((pIn.flags.value >> 4) & 1) == 0)
|
|
slices >>= (int)pIn.mipLevel;
|
|
|
|
width = Math.Max(1, widtha);
|
|
height = Math.Max(1, heighta);
|
|
slices = Math.Max(1, slices);
|
|
}
|
|
|
|
pIn.width = nextPow2(width);
|
|
pIn.height = nextPow2(height);
|
|
pIn.numSlices = slices;
|
|
}
|
|
|
|
handled = 1;
|
|
}
|
|
return handled;
|
|
}
|
|
private static uint powTwoAlign(uint x, uint align)
|
|
{
|
|
return ~(align - 1) & (x + align - 1);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the surface info of a GX2 texture
|
|
/// </summary>
|
|
/// <param name="surfaceFormat">The <see cref="GX2SurfaceFormat"/> of the surface.</param>
|
|
/// <param name="surfaceWidth">The width of the surface.</param>
|
|
/// <param name="surfaceHeight">The height of the surface.</param>
|
|
/// <param name="surfaceDepth">The depth of the surface.</param>
|
|
/// <param name="surfaceDim">The <see cref="GX2SurfaceDim"/ of the surface.</param>
|
|
/// <param name="surfaceTileMode">The <see cref="GX2TileMode"/ of the surface.</param>
|
|
/// <param name="surfaceAA">The <see cref="GX2AAMode"/ of the surface.</param>
|
|
/// <param name="level">The mip level of which the info will be calculated for (first mipmap corresponds to value 1</param>
|
|
public static surfaceOut getSurfaceInfo(GX2SurfaceFormat surfaceFormat, uint surfaceWidth, uint surfaceHeight, uint surfaceDepth, uint surfaceDim, uint surfaceTileMode, uint surfaceAA, int level)
|
|
{
|
|
uint dim = 0;
|
|
uint width = 0;
|
|
uint blockSize = 0;
|
|
uint numSamples = 0;
|
|
uint hwFormat = 0;
|
|
|
|
var aSurfIn = new surfaceIn();
|
|
var pSurfOut = new surfaceOut();
|
|
|
|
hwFormat = (uint)((int)surfaceFormat & 0x3F);
|
|
|
|
|
|
if (surfaceTileMode == 16)
|
|
{
|
|
numSamples = (uint)(1 << (int)surfaceAA);
|
|
|
|
if (hwFormat < 0x31 || hwFormat > 0x35)
|
|
blockSize = 1;
|
|
else
|
|
blockSize = 4;
|
|
|
|
width = (uint)(~(blockSize - 1) & (Math.Max(1, surfaceWidth >> level) + blockSize - 1));
|
|
|
|
pSurfOut.bpp = formatHwInfo[hwFormat * 4];
|
|
pSurfOut.size = 96;
|
|
pSurfOut.pitch = (uint)(width / blockSize);
|
|
pSurfOut.pixelBits = formatHwInfo[hwFormat * 4];
|
|
pSurfOut.baseAlign = 1;
|
|
pSurfOut.pitchAlign = 1;
|
|
pSurfOut.heightAlign = 1;
|
|
pSurfOut.depthAlign = 1;
|
|
dim = surfaceDim;
|
|
|
|
if (dim == 0)
|
|
{
|
|
pSurfOut.height = 1;
|
|
pSurfOut.depth = 1;
|
|
}
|
|
else if (dim == 1 || dim == 6)
|
|
{
|
|
pSurfOut.height = Math.Max(1, surfaceHeight >> level);
|
|
pSurfOut.depth = 1;
|
|
}
|
|
else if (dim == 2)
|
|
{
|
|
pSurfOut.height = Math.Max(1, surfaceHeight >> level);
|
|
pSurfOut.depth = Math.Max(1, surfaceDepth >> level);
|
|
}
|
|
else if (dim == 3)
|
|
{
|
|
pSurfOut.height = Math.Max(1, surfaceHeight >> level);
|
|
pSurfOut.depth = Math.Max(6, surfaceDepth);
|
|
}
|
|
else if (dim == 4)
|
|
{
|
|
pSurfOut.height = 1;
|
|
pSurfOut.depth = surfaceDepth;
|
|
}
|
|
else if (dim == 5 || dim == 7)
|
|
{
|
|
pSurfOut.height = Math.Max(1, surfaceHeight >> level);
|
|
pSurfOut.depth = surfaceDepth;
|
|
}
|
|
|
|
pSurfOut.pixelPitch = width;
|
|
pSurfOut.pixelHeight = (uint)(~(blockSize - 1) & (pSurfOut.height + blockSize - 1));
|
|
pSurfOut.height = (uint)(pSurfOut.pixelHeight / blockSize);
|
|
pSurfOut.surfSize = pSurfOut.bpp * numSamples * pSurfOut.depth * pSurfOut.height * pSurfOut.pitch >> 3;
|
|
|
|
if (surfaceDim == 2)
|
|
pSurfOut.sliceSize = (uint)pSurfOut.surfSize;
|
|
else
|
|
pSurfOut.sliceSize = (uint)(pSurfOut.surfSize / pSurfOut.depth);
|
|
|
|
pSurfOut.pitchTileMax = (pSurfOut.pitch >> 3) - 1;
|
|
pSurfOut.heightTileMax = (pSurfOut.height >> 3) - 1;
|
|
pSurfOut.sliceTileMax = (pSurfOut.height * pSurfOut.pitch >> 6) - 1;
|
|
}
|
|
else
|
|
{
|
|
aSurfIn.size = 60;
|
|
aSurfIn.tileMode = surfaceTileMode & 0x0F;
|
|
aSurfIn.format = hwFormat;
|
|
aSurfIn.bpp = formatHwInfo[hwFormat * 4];
|
|
aSurfIn.numSamples = (uint)(1 << (int)surfaceAA);
|
|
aSurfIn.numFrags = aSurfIn.numSamples;
|
|
aSurfIn.width = (uint)Math.Max(1, surfaceWidth >> level);
|
|
dim = surfaceDim;
|
|
|
|
if (dim == 0)
|
|
{
|
|
aSurfIn.height = 1;
|
|
aSurfIn.numSlices = 1;
|
|
}
|
|
else if (dim == 1 || dim == 6)
|
|
{
|
|
aSurfIn.height = (uint)Math.Max(1, surfaceHeight >> level);
|
|
aSurfIn.numSlices = 1;
|
|
}
|
|
else if (dim == 2)
|
|
{
|
|
aSurfIn.height = (uint)Math.Max(1, surfaceHeight >> level);
|
|
aSurfIn.numSlices = (uint)Math.Max(1, surfaceDepth >> level);
|
|
}
|
|
else if (dim == 3)
|
|
{
|
|
aSurfIn.height = (uint)Math.Max(1, surfaceHeight >> level);
|
|
aSurfIn.numSlices = (uint)Math.Max(6, surfaceDepth);
|
|
aSurfIn.flags.value |= 0x10;
|
|
}
|
|
else if (dim == 4)
|
|
{
|
|
aSurfIn.height = 1;
|
|
aSurfIn.numSlices = (uint)surfaceDepth;
|
|
}
|
|
else if (dim == 5 || dim == 7)
|
|
{
|
|
aSurfIn.height = (uint)Math.Max(1, surfaceHeight >> level);
|
|
aSurfIn.numSlices = (uint)surfaceDepth;
|
|
}
|
|
|
|
aSurfIn.slice = 0;
|
|
aSurfIn.mipLevel = (uint)level;
|
|
|
|
if (surfaceDim == 2)
|
|
aSurfIn.flags.value |= 0x20;
|
|
|
|
if (level == 0)
|
|
aSurfIn.flags.value = (1 << 12) | aSurfIn.flags.value & 0xFFFFEFFF;
|
|
else
|
|
aSurfIn.flags.value = aSurfIn.flags.value & 0xFFFFEFFF;
|
|
|
|
pSurfOut.size = 96;
|
|
computeSurfaceInfo(aSurfIn, pSurfOut);
|
|
|
|
pSurfOut = pOut;
|
|
}
|
|
if (pSurfOut.tileMode == 0)
|
|
pSurfOut.tileMode = 16;
|
|
|
|
return pSurfOut;
|
|
}
|
|
}
|
|
} |