/** ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** * Copyright 2014 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ #ifndef XENIA_GPU_TEXTURE_INFO_H_ #define XENIA_GPU_TEXTURE_INFO_H_ #include #include #include "xenia/base/assert.h" #include "xenia/gpu/xenos.h" namespace xe { namespace gpu { // a2xx_sq_surfaceformat enum class TextureFormat : uint32_t { k_1_REVERSE = 0, k_1 = 1, k_8 = 2, k_1_5_5_5 = 3, k_5_6_5 = 4, k_6_5_5 = 5, k_8_8_8_8 = 6, k_2_10_10_10 = 7, k_8_A = 8, k_8_B = 9, k_8_8 = 10, k_Cr_Y1_Cb_Y0 = 11, k_Y1_Cr_Y0_Cb = 12, k_Shadow = 13, k_8_8_8_8_A = 14, k_4_4_4_4 = 15, k_10_11_11 = 16, k_11_11_10 = 17, k_DXT1 = 18, k_DXT2_3 = 19, k_DXT4_5 = 20, k_DXV = 21, k_24_8 = 22, k_24_8_FLOAT = 23, k_16 = 24, k_16_16 = 25, k_16_16_16_16 = 26, k_16_EXPAND = 27, k_16_16_EXPAND = 28, k_16_16_16_16_EXPAND = 29, k_16_FLOAT = 30, k_16_16_FLOAT = 31, k_16_16_16_16_FLOAT = 32, k_32 = 33, k_32_32 = 34, k_32_32_32_32 = 35, k_32_FLOAT = 36, k_32_32_FLOAT = 37, k_32_32_32_32_FLOAT = 38, k_32_AS_8 = 39, k_32_AS_8_8 = 40, k_16_MPEG = 41, k_16_16_MPEG = 42, k_8_INTERLACED = 43, k_32_AS_8_INTERLACED = 44, k_32_AS_8_8_INTERLACED = 45, k_16_INTERLACED = 46, k_16_MPEG_INTERLACED = 47, k_16_16_MPEG_INTERLACED = 48, k_DXN = 49, k_8_8_8_8_AS_16_16_16_16 = 50, k_DXT1_AS_16_16_16_16 = 51, k_DXT2_3_AS_16_16_16_16 = 52, k_DXT4_5_AS_16_16_16_16 = 53, k_2_10_10_10_AS_16_16_16_16 = 54, k_10_11_11_AS_16_16_16_16 = 55, k_11_11_10_AS_16_16_16_16 = 56, k_32_32_32_FLOAT = 57, k_DXT3A = 58, k_DXT5A = 59, k_CTX1 = 60, k_DXT3A_AS_1_1_1_1 = 61, k_2_10_10_10_FLOAT = 62, kUnknown = 0xFFFFFFFFu, }; inline TextureFormat GetBaseFormat(TextureFormat texture_format) { // These formats are used for resampling textures / gamma control. switch (texture_format) { case TextureFormat::k_16_EXPAND: return TextureFormat::k_16_FLOAT; case TextureFormat::k_16_16_EXPAND: return TextureFormat::k_16_16_FLOAT; case TextureFormat::k_16_16_16_16_EXPAND: return TextureFormat::k_16_16_16_16_FLOAT; case TextureFormat::k_8_8_8_8_AS_16_16_16_16: return TextureFormat::k_8_8_8_8; case TextureFormat::k_DXT1_AS_16_16_16_16: return TextureFormat::k_DXT1; case TextureFormat::k_DXT2_3_AS_16_16_16_16: return TextureFormat::k_DXT2_3; case TextureFormat::k_DXT4_5_AS_16_16_16_16: return TextureFormat::k_DXT4_5; case TextureFormat::k_2_10_10_10_AS_16_16_16_16: return TextureFormat::k_2_10_10_10; case TextureFormat::k_10_11_11_AS_16_16_16_16: return TextureFormat::k_10_11_11; case TextureFormat::k_11_11_10_AS_16_16_16_16: return TextureFormat::k_11_11_10; case TextureFormat::k_DXT3A_AS_1_1_1_1: return TextureFormat::k_DXT3A; default: break; } return texture_format; } inline size_t GetTexelSize(TextureFormat format) { switch (format) { case TextureFormat::k_1_5_5_5: return 2; case TextureFormat::k_2_10_10_10: return 4; case TextureFormat::k_4_4_4_4: return 2; case TextureFormat::k_5_6_5: return 2; case TextureFormat::k_8: return 1; case TextureFormat::k_8_8: return 2; case TextureFormat::k_8_8_8_8: return 4; case TextureFormat::k_16: return 4; case TextureFormat::k_16_FLOAT: return 4; case TextureFormat::k_16_16: return 4; case TextureFormat::k_16_16_FLOAT: return 4; case TextureFormat::k_16_16_16_16: return 8; case TextureFormat::k_16_16_16_16_FLOAT: return 8; case TextureFormat::k_32_FLOAT: return 4; case TextureFormat::k_32_32_FLOAT: return 8; case TextureFormat::k_32_32_32_32_FLOAT: return 16; case TextureFormat::k_10_11_11: case TextureFormat::k_11_11_10: return 4; default: assert_unhandled_case(format); return 0; } } inline bool IsSRGBCapable(TextureFormat format) { switch (format) { case TextureFormat::k_1_REVERSE: case TextureFormat::k_1: case TextureFormat::k_8: case TextureFormat::k_1_5_5_5: case TextureFormat::k_5_6_5: case TextureFormat::k_6_5_5: case TextureFormat::k_8_8_8_8: case TextureFormat::k_8_8: case TextureFormat::k_Cr_Y1_Cb_Y0: case TextureFormat::k_Y1_Cr_Y0_Cb: case TextureFormat::k_4_4_4_4: case TextureFormat::k_DXT1: case TextureFormat::k_DXT2_3: case TextureFormat::k_DXT4_5: case TextureFormat::k_24_8: case TextureFormat::k_16: case TextureFormat::k_16_16: case TextureFormat::k_16_16_16_16: case TextureFormat::k_16_EXPAND: case TextureFormat::k_16_16_EXPAND: case TextureFormat::k_16_16_16_16_EXPAND: case TextureFormat::k_32: case TextureFormat::k_32_32: case TextureFormat::k_32_32_32_32: case TextureFormat::k_32_FLOAT: case TextureFormat::k_32_32_FLOAT: case TextureFormat::k_32_32_32_32_FLOAT: case TextureFormat::k_32_AS_8: case TextureFormat::k_32_AS_8_8: case TextureFormat::k_16_MPEG: case TextureFormat::k_16_16_MPEG: case TextureFormat::k_8_INTERLACED: case TextureFormat::k_32_AS_8_INTERLACED: case TextureFormat::k_32_AS_8_8_INTERLACED: case TextureFormat::k_16_INTERLACED: case TextureFormat::k_16_MPEG_INTERLACED: case TextureFormat::k_16_16_MPEG_INTERLACED: case TextureFormat::k_DXN: case TextureFormat::k_8_8_8_8_AS_16_16_16_16: case TextureFormat::k_DXT1_AS_16_16_16_16: case TextureFormat::k_DXT2_3_AS_16_16_16_16: case TextureFormat::k_DXT4_5_AS_16_16_16_16: case TextureFormat::k_2_10_10_10_AS_16_16_16_16: case TextureFormat::k_10_11_11_AS_16_16_16_16: case TextureFormat::k_11_11_10_AS_16_16_16_16: return true; } return false; } inline TextureFormat ColorFormatToTextureFormat(ColorFormat color_format) { return static_cast(color_format); } inline TextureFormat ColorRenderTargetToTextureFormat( ColorRenderTargetFormat color_format) { switch (color_format) { case ColorRenderTargetFormat::k_8_8_8_8: return TextureFormat::k_8_8_8_8; case ColorRenderTargetFormat::k_8_8_8_8_GAMMA: return TextureFormat::k_8_8_8_8; case ColorRenderTargetFormat::k_2_10_10_10: return TextureFormat::k_2_10_10_10; case ColorRenderTargetFormat::k_2_10_10_10_FLOAT: return TextureFormat::k_2_10_10_10_FLOAT; case ColorRenderTargetFormat::k_16_16: return TextureFormat::k_16_16; case ColorRenderTargetFormat::k_16_16_16_16: return TextureFormat::k_16_16_16_16; case ColorRenderTargetFormat::k_16_16_FLOAT: return TextureFormat::k_16_16_FLOAT; case ColorRenderTargetFormat::k_16_16_16_16_FLOAT: return TextureFormat::k_16_16_16_16_FLOAT; case ColorRenderTargetFormat::k_2_10_10_10_AS_16_16_16_16: return TextureFormat::k_2_10_10_10_AS_16_16_16_16; case ColorRenderTargetFormat::k_2_10_10_10_FLOAT_AS_16_16_16_16: return TextureFormat::k_2_10_10_10_FLOAT; case ColorRenderTargetFormat::k_32_FLOAT: return TextureFormat::k_32_FLOAT; case ColorRenderTargetFormat::k_32_32_FLOAT: return TextureFormat::k_32_32_FLOAT; default: assert_unhandled_case(color_format); return TextureFormat::kUnknown; } } inline TextureFormat DepthRenderTargetToTextureFormat( DepthRenderTargetFormat depth_format) { switch (depth_format) { case DepthRenderTargetFormat::kD24S8: return TextureFormat::k_24_8; case DepthRenderTargetFormat::kD24FS8: return TextureFormat::k_24_8_FLOAT; default: assert_unhandled_case(depth_format); return TextureFormat::kUnknown; } } enum class FormatType { kUncompressed, kCompressed, }; struct FormatInfo { TextureFormat format; const char* name; FormatType type; uint32_t block_width; uint32_t block_height; uint32_t bits_per_pixel; static const FormatInfo* Get(uint32_t gpu_format); }; struct TextureInfo { uint32_t guest_address; TextureFormat texture_format; Dimension dimension; uint32_t pitch; // pitch in blocks uint32_t width; // width in pixels uint32_t height; // height in pixels uint32_t depth; // depth in layers Endian endianness; bool is_tiled; bool has_packed_mips; uint32_t mip_address; uint32_t mip_levels; uint32_t input_length; struct Size { uint32_t logical_width; uint32_t logical_height; uint32_t block_width; // # of horizontal blocks uint32_t block_height; // # of vertical blocks uint32_t input_width; // (full) texel pitch uint32_t input_height; // (full) texel height uint32_t input_face_length; // byte length of face } size; const FormatInfo* format_info() const { return FormatInfo::Get(static_cast(texture_format)); } bool is_compressed() const { return format_info()->type == FormatType::kCompressed; } static bool Prepare(const xenos::xe_gpu_texture_fetch_t& fetch, TextureInfo* out_info); static bool PrepareResolve(uint32_t physical_address, TextureFormat texture_format, Endian endian, uint32_t pitch, uint32_t width, uint32_t height, TextureInfo* out_info); static void ConvertTiled(uint8_t* dest, const uint8_t* src, Endian endian, const FormatInfo* format_info, uint32_t offset_x, uint32_t offset_y, uint32_t block_pitch, uint32_t width, uint32_t height, uint32_t output_width); static uint32_t GetMaxMipLevels(uint32_t width, uint32_t height, uint32_t depth); // Get the memory location of a mip. offset_x and offset_y are in blocks. static uint32_t GetMipLocation(const TextureInfo& src, uint32_t mip, uint32_t* offset_x, uint32_t* offset_y); static uint32_t GetMipByteSize(const TextureInfo& src, uint32_t mip); static uint32_t GetMipSizes(const TextureInfo& src, uint32_t mip); // Get the byte size of a MIP when stored linearly. static uint32_t GetMipLinearSize(const TextureInfo& src, uint32_t mip); static bool GetPackedTileOffset(uint32_t width, uint32_t height, const FormatInfo* format_info, int packed_tile, uint32_t* out_offset_x, uint32_t* out_offset_y); static bool GetPackedTileOffset(const TextureInfo& texture_info, int packed_tile, uint32_t* out_offset_x, uint32_t* out_offset_y); static uint32_t TiledOffset2DOuter(uint32_t y, uint32_t width, uint32_t log2_bpp); static uint32_t TiledOffset2DInner(uint32_t x, uint32_t y, uint32_t log2_bpp, uint32_t base_offset); uint64_t hash() const; bool operator==(const TextureInfo& other) const { return std::memcmp(this, &other, sizeof(TextureInfo)) == 0; } private: void CalculateTextureSizes1D(uint32_t width); void CalculateTextureSizes2D(uint32_t width, uint32_t height); void CalculateTextureSizes3D(uint32_t width, uint32_t height, uint32_t depth); void CalculateTextureSizesCube(uint32_t width, uint32_t height, uint32_t depth); }; } // namespace gpu } // namespace xe #endif // XENIA_GPU_TEXTURE_INFO_H_