From b40d75aa3dc05d1b5b32af441d818cfe953f15ba Mon Sep 17 00:00:00 2001 From: "Dr. Chat" Date: Fri, 7 Apr 2017 15:10:35 -0500 Subject: [PATCH] TextureInfo: Store the texture format, not a pointer to texture format info. --- src/xenia/gpu/gl4/texture_cache.cc | 35 ++++++------ src/xenia/gpu/texture_info.cc | 79 ++++++++++++++------------- src/xenia/gpu/texture_info.h | 40 +++++++++++++- src/xenia/gpu/vulkan/texture_cache.cc | 48 ++++++++-------- 4 files changed, 122 insertions(+), 80 deletions(-) diff --git a/src/xenia/gpu/gl4/texture_cache.cc b/src/xenia/gpu/gl4/texture_cache.cc index c43c43a1d..ad12e016c 100644 --- a/src/xenia/gpu/gl4/texture_cache.cc +++ b/src/xenia/gpu/gl4/texture_cache.cc @@ -714,8 +714,7 @@ bool TextureCache::UploadTexture1D(GLuint texture, const auto host_address = memory_->TranslatePhysical(texture_info.guest_address); - const auto& config = - texture_configs[uint32_t(texture_info.format_info->format)]; + const auto& config = texture_configs[uint32_t(texture_info.texture_format)]; if (config.format == GL_INVALID_ENUM) { assert_always("Unhandled texture format"); return false; @@ -771,7 +770,7 @@ bool TextureCache::UploadTexture2D(GLuint texture, memory_->TranslatePhysical(texture_info.guest_address); const auto& config = - texture_configs[uint32_t(texture_info.format_info->format)]; + texture_configs[uint32_t(texture_info.format_info()->format)]; if (config.format == GL_INVALID_ENUM) { assert_always("Unhandled texture format"); return false; @@ -788,9 +787,9 @@ bool TextureCache::UploadTexture2D(GLuint texture, uint32_t offset_x, offset_y; if (texture_info.has_packed_mips && TextureInfo::GetPackedTileOffset(texture_info, &offset_x, &offset_y)) { - uint32_t bytes_per_block = texture_info.format_info->block_width * - texture_info.format_info->block_height * - texture_info.format_info->bits_per_pixel / 8; + uint32_t bytes_per_block = texture_info.format_info()->block_width * + texture_info.format_info()->block_height * + texture_info.format_info()->bits_per_pixel / 8; const uint8_t* src = host_address; // TODO(gibbed): this needs checking src += offset_y * texture_info.size_2d.input_pitch; @@ -833,9 +832,9 @@ bool TextureCache::UploadTexture2D(GLuint texture, // TODO(benvanik): optimize this inner loop (or work by tiles). const uint8_t* src = host_address; uint8_t* dest = reinterpret_cast(allocation.host_ptr); - uint32_t bytes_per_block = texture_info.format_info->block_width * - texture_info.format_info->block_height * - texture_info.format_info->bits_per_pixel / 8; + uint32_t bytes_per_block = texture_info.format_info()->block_width * + texture_info.format_info()->block_height * + texture_info.format_info()->bits_per_pixel / 8; // Tiled textures can be packed; get the offset into the packed texture. uint32_t offset_x; @@ -849,8 +848,9 @@ bool TextureCache::UploadTexture2D(GLuint texture, texture_info.size_2d.logical_height); y++, output_base_offset += texture_info.size_2d.output_pitch) { auto input_base_offset = TextureInfo::TiledOffset2DOuter( - offset_y + y, (texture_info.size_2d.input_width / - texture_info.format_info->block_width), + offset_y + y, + (texture_info.size_2d.input_width / + texture_info.format_info()->block_width), bpp); for (uint32_t x = 0, output_offset = output_base_offset; x < texture_info.size_2d.block_width; @@ -899,7 +899,7 @@ bool TextureCache::UploadTextureCube(GLuint texture, memory_->TranslatePhysical(texture_info.guest_address); const auto& config = - texture_configs[uint32_t(texture_info.format_info->format)]; + texture_configs[uint32_t(texture_info.format_info()->format)]; if (config.format == GL_INVALID_ENUM) { assert_always("Unhandled texture format"); return false; @@ -937,9 +937,9 @@ bool TextureCache::UploadTextureCube(GLuint texture, // TODO(benvanik): optimize this inner loop (or work by tiles). const uint8_t* src = host_address; uint8_t* dest = reinterpret_cast(allocation.host_ptr); - uint32_t bytes_per_block = texture_info.format_info->block_width * - texture_info.format_info->block_height * - texture_info.format_info->bits_per_pixel / 8; + uint32_t bytes_per_block = texture_info.format_info()->block_width * + texture_info.format_info()->block_height * + texture_info.format_info()->bits_per_pixel / 8; // Tiled textures can be packed; get the offset into the packed texture. uint32_t offset_x; uint32_t offset_y; @@ -951,8 +951,9 @@ bool TextureCache::UploadTextureCube(GLuint texture, y < texture_info.size_cube.block_height; y++, output_base_offset += texture_info.size_cube.output_pitch) { auto input_base_offset = TextureInfo::TiledOffset2DOuter( - offset_y + y, (texture_info.size_cube.input_width / - texture_info.format_info->block_width), + offset_y + y, + (texture_info.size_cube.input_width / + texture_info.format_info()->block_width), bpp); for (uint32_t x = 0, output_offset = output_base_offset; x < texture_info.size_cube.block_width; diff --git a/src/xenia/gpu/texture_info.cc b/src/xenia/gpu/texture_info.cc index 5394d3524..241339f51 100644 --- a/src/xenia/gpu/texture_info.cc +++ b/src/xenia/gpu/texture_info.cc @@ -132,14 +132,14 @@ bool TextureInfo::Prepare(const xe_gpu_texture_fetch_t& fetch, info.depth = fetch.size_stack.depth; break; } - info.format_info = FormatInfo::Get(fetch.format); + info.texture_format = static_cast(fetch.format); info.endianness = static_cast(fetch.endianness); info.is_tiled = fetch.tiled; info.has_packed_mips = fetch.packed_mips; info.input_length = 0; // Populated below. info.output_length = 0; - if (info.format_info->format == TextureFormat::kUnknown) { + if (info.format_info()->format == TextureFormat::kUnknown) { assert_true("Unsupported texture format"); return false; } @@ -154,13 +154,13 @@ bool TextureInfo::Prepare(const xe_gpu_texture_fetch_t& fetch, fetch.size_2d.height + 1); // DEBUG: Make sure our calculated pitch is equal to the fetch pitch. - uint32_t bytes_per_block = info.format_info->block_width * - info.format_info->block_height * - info.format_info->bits_per_pixel / 8; + uint32_t bytes_per_block = info.format_info()->block_width * + info.format_info()->block_height * + info.format_info()->bits_per_pixel / 8; assert_true(info.size_2d.input_pitch == (bytes_per_block * fetch.pitch << 5) / - info.format_info->block_width); + info.format_info()->block_width); } break; case Dimension::k3D: { // TODO(benvanik): calculate size. @@ -186,14 +186,14 @@ bool TextureInfo::PrepareResolve(uint32_t physical_address, info.dimension = Dimension::k2D; info.width = width - 1; info.height = height - 1; - info.format_info = FormatInfo::Get(static_cast(texture_format)); + info.texture_format = texture_format; info.endianness = endian; info.is_tiled = true; info.has_packed_mips = false; info.input_length = 0; info.output_length = 0; - if (info.format_info->format == TextureFormat::kUnknown) { + if (info.format_info()->format == TextureFormat::kUnknown) { assert_true("Unsupported texture format"); return false; } @@ -206,15 +206,16 @@ void TextureInfo::CalculateTextureSizes1D(uint32_t width) { // ? size_1d.logical_width = width; + auto format = format_info(); + uint32_t block_width = - xe::round_up(size_1d.logical_width, format_info->block_width) / - format_info->block_width; + xe::round_up(size_1d.logical_width, format->block_width) / + format->block_width; uint32_t tile_width = xe::round_up(block_width, 32) / 32; size_1d.block_width = tile_width * 32; - uint32_t bytes_per_block = - format_info->block_width * format_info->bits_per_pixel / 8; + uint32_t bytes_per_block = format->block_width * format->bits_per_pixel / 8; uint32_t byte_pitch = tile_width * 32 * bytes_per_block; if (!is_tiled) { @@ -222,12 +223,12 @@ void TextureInfo::CalculateTextureSizes1D(uint32_t width) { byte_pitch = xe::round_up(byte_pitch, 256); } - size_1d.input_width = tile_width * 32 * format_info->block_width; + size_1d.input_width = tile_width * 32 * format->block_width; size_1d.input_pitch = byte_pitch; input_length = size_1d.input_pitch; // TODO(DrChat): Remove this, leave it up to the backend. - size_1d.output_width = block_width * format_info->block_width; + size_1d.output_width = block_width * format->block_width; size_1d.output_pitch = block_width * bytes_per_block; output_length = size_1d.output_pitch; } @@ -240,13 +241,15 @@ void TextureInfo::CalculateTextureSizes2D(uint32_t width, uint32_t height) { // images and create GL textures. Changes here will impact that code. // TODO(benvanik): generic texture copying utility. + auto format = format_info(); + // w/h in blocks. uint32_t block_width = - xe::round_up(size_2d.logical_width, format_info->block_width) / - format_info->block_width; + xe::round_up(size_2d.logical_width, format->block_width) / + format->block_width; uint32_t block_height = - xe::round_up(size_2d.logical_height, format_info->block_height) / - format_info->block_height; + xe::round_up(size_2d.logical_height, format->block_height) / + format->block_height; // Tiles are 32x32 blocks. The pitch of all textures must a multiple of tile // dimensions. @@ -254,9 +257,8 @@ void TextureInfo::CalculateTextureSizes2D(uint32_t width, uint32_t height) { size_2d.block_width = tile_width * 32; size_2d.block_height = block_height; - uint32_t bytes_per_block = format_info->block_width * - format_info->block_height * - format_info->bits_per_pixel / 8; + uint32_t bytes_per_block = + format->block_width * format->block_height * format->bits_per_pixel / 8; uint32_t byte_pitch = size_2d.block_width * bytes_per_block; if (!is_tiled) { @@ -264,15 +266,15 @@ void TextureInfo::CalculateTextureSizes2D(uint32_t width, uint32_t height) { byte_pitch = xe::round_up(byte_pitch, 256); } - size_2d.input_width = size_2d.block_width * format_info->block_width; - size_2d.input_height = size_2d.block_height * format_info->block_height; + size_2d.input_width = size_2d.block_width * format->block_width; + size_2d.input_height = size_2d.block_height * format->block_height; size_2d.input_pitch = byte_pitch; input_length = size_2d.input_pitch * size_2d.block_height; // TODO(DrChat): Remove this, leave it up to the backend. - size_2d.output_width = block_width * format_info->block_width; - size_2d.output_height = block_height * format_info->block_height; + size_2d.output_width = block_width * format->block_width; + size_2d.output_height = block_height * format->block_height; size_2d.output_pitch = block_width * bytes_per_block; output_length = size_2d.output_pitch * block_height; @@ -284,13 +286,15 @@ void TextureInfo::CalculateTextureSizesCube(uint32_t width, uint32_t height, size_cube.logical_width = width; size_cube.logical_height = height; + auto format = format_info(); + // w/h in blocks must be a multiple of block size. uint32_t block_width = - xe::round_up(size_cube.logical_width, format_info->block_width) / - format_info->block_width; + xe::round_up(size_cube.logical_width, format->block_width) / + format->block_width; uint32_t block_height = - xe::round_up(size_cube.logical_height, format_info->block_height) / - format_info->block_height; + xe::round_up(size_cube.logical_height, format->block_height) / + format->block_height; // Tiles are 32x32 blocks. All textures must be multiples of tile dimensions. uint32_t tile_width = xe::round_up(block_width, 32) / 32; @@ -298,25 +302,24 @@ void TextureInfo::CalculateTextureSizesCube(uint32_t width, uint32_t height, size_cube.block_width = tile_width * 32; size_cube.block_height = tile_height * 32; - uint32_t bytes_per_block = format_info->block_width * - format_info->block_height * - format_info->bits_per_pixel / 8; + uint32_t bytes_per_block = + format->block_width * format->block_height * format->bits_per_pixel / 8; uint32_t byte_pitch = size_cube.block_width * bytes_per_block; if (!is_tiled) { // Each row must be a multiple of 256 in linear textures. byte_pitch = xe::round_up(byte_pitch, 256); } - size_cube.input_width = size_cube.block_width * format_info->block_width; - size_cube.input_height = size_cube.block_height * format_info->block_height; + size_cube.input_width = size_cube.block_width * format->block_width; + size_cube.input_height = size_cube.block_height * format->block_height; size_cube.input_pitch = byte_pitch; size_cube.input_face_length = size_cube.input_pitch * size_cube.block_height; input_length = size_cube.input_face_length * 6; // TODO(DrChat): Remove this, leave it up to the backend. - size_cube.output_width = block_width * format_info->block_width; - size_cube.output_height = block_height * format_info->block_height; + size_cube.output_width = block_width * format->block_width; + size_cube.output_height = block_height * format->block_height; size_cube.output_pitch = block_width * bytes_per_block; size_cube.output_face_length = size_cube.output_pitch * block_height; @@ -375,8 +378,8 @@ bool TextureInfo::GetPackedTileOffset(const TextureInfo& texture_info, *out_offset_x = 16; *out_offset_y = 0; } - *out_offset_x /= texture_info.format_info->block_width; - *out_offset_y /= texture_info.format_info->block_height; + *out_offset_x /= texture_info.format_info()->block_width; + *out_offset_y /= texture_info.format_info()->block_height; return true; } diff --git a/src/xenia/gpu/texture_info.h b/src/xenia/gpu/texture_info.h index 180b2f103..804496057 100644 --- a/src/xenia/gpu/texture_info.h +++ b/src/xenia/gpu/texture_info.h @@ -88,6 +88,38 @@ enum class TextureFormat : uint32_t { 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; + case TextureFormat::k_16_16_EXPAND: + return TextureFormat::k_16_16; + case TextureFormat::k_16_16_16_16_EXPAND: + return TextureFormat::k_16_16_16_16; + 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: @@ -215,19 +247,23 @@ struct FormatInfo { struct TextureInfo { uint32_t guest_address; + TextureFormat texture_format; Dimension dimension; uint32_t width; uint32_t height; uint32_t depth; - const FormatInfo* format_info; Endian endianness; bool is_tiled; bool has_packed_mips; uint32_t input_length; uint32_t output_length; + const FormatInfo* format_info() const { + return FormatInfo::Get(static_cast(texture_format)); + } + bool is_compressed() const { - return format_info->type == FormatType::kCompressed; + return format_info()->type == FormatType::kCompressed; } union { diff --git a/src/xenia/gpu/vulkan/texture_cache.cc b/src/xenia/gpu/vulkan/texture_cache.cc index 64df8fba0..8b7d03941 100644 --- a/src/xenia/gpu/vulkan/texture_cache.cc +++ b/src/xenia/gpu/vulkan/texture_cache.cc @@ -334,8 +334,8 @@ TextureCache::Texture* TextureCache::AllocateTexture( return nullptr; } - assert_not_null(texture_info.format_info); - auto& config = texture_configs[int(texture_info.format_info->format)]; + assert_not_null(texture_info.format_info()); + auto& config = texture_configs[int(texture_info.format_info()->format)]; VkFormat format = config.host_format != VK_FORMAT_UNDEFINED ? config.host_format : VK_FORMAT_R8G8B8A8_UNORM; @@ -517,6 +517,18 @@ TextureCache::Texture* TextureCache::Demand(const TextureInfo& texture_info, return nullptr; } + // Though we didn't find an exact match, that doesn't mean we're out of the + // woods yet. This texture could either be a portion of another texture or + // vice versa. Copy any overlapping textures into this texture. + // TODO: Byte count -> pixel count (on x and y axes) + VkOffset2D offset; + auto collide_tex = LookupAddress( + texture_info.guest_address, texture_info.width + 1, + texture_info.height + 1, texture_info.format_info()->format, &offset); + if (collide_tex != nullptr) { + // assert_always(); + } + trace_writer_->WriteMemoryRead(texture_info.guest_address, texture_info.input_length); @@ -555,16 +567,6 @@ TextureCache::Texture* TextureCache::Demand(const TextureInfo& texture_info, "0x%.8X - 0x%.8X", texture_info.guest_address, texture_info.guest_address + texture_info.output_length)); - // Though we didn't find an exact match, that doesn't mean we're out of the - // woods yet. This texture could either be a portion of another texture or - // vice versa. Copy any overlapping textures into this texture. - // TODO: Byte count -> pixel count (on x and y axes) - /* - for (auto it = textures_.begin(); it != textures_.end(); ++it) { - // TODO(DrChat) - } - */ - // Okay. Now that the texture is uploaded from system memory, put a writewatch // on it to tell us if it's been modified from the guest. texture->access_watch_handle = memory_->AddPhysicalAccessWatch( @@ -915,9 +917,9 @@ void TextureCache::ConvertTexture2D(uint8_t* dest, const TextureInfo& src) { uint32_t offset_x, offset_y; if (src.has_packed_mips && TextureInfo::GetPackedTileOffset(src, &offset_x, &offset_y)) { - uint32_t bytes_per_block = src.format_info->block_width * - src.format_info->block_height * - src.format_info->bits_per_pixel / 8; + uint32_t bytes_per_block = src.format_info()->block_width * + src.format_info()->block_height * + src.format_info()->bits_per_pixel / 8; const uint8_t* src_mem = reinterpret_cast(host_address); src_mem += offset_y * src.size_2d.input_pitch; @@ -955,9 +957,9 @@ void TextureCache::ConvertTexture2D(uint8_t* dest, const TextureInfo& src) { // TODO(benvanik): optimize this inner loop (or work by tiles). const uint8_t* src_mem = reinterpret_cast(host_address); - uint32_t bytes_per_block = src.format_info->block_width * - src.format_info->block_height * - src.format_info->bits_per_pixel / 8; + uint32_t bytes_per_block = src.format_info()->block_width * + src.format_info()->block_height * + src.format_info()->bits_per_pixel / 8; // Tiled textures can be packed; get the offset into the packed texture. uint32_t offset_x; @@ -970,7 +972,7 @@ void TextureCache::ConvertTexture2D(uint8_t* dest, const TextureInfo& src) { y++, output_base_offset += src.size_2d.output_pitch) { auto input_base_offset = TextureInfo::TiledOffset2DOuter( offset_y + y, - (src.size_2d.input_width / src.format_info->block_width), bpp); + (src.size_2d.input_width / src.format_info()->block_width), bpp); for (uint32_t x = 0, output_offset = output_base_offset; x < src.size_2d.block_width; x++, output_offset += bytes_per_block) { auto input_offset = @@ -1008,9 +1010,9 @@ void TextureCache::ConvertTextureCube(uint8_t* dest, const TextureInfo& src) { } else { // TODO(benvanik): optimize this inner loop (or work by tiles). const uint8_t* src_mem = reinterpret_cast(host_address); - uint32_t bytes_per_block = src.format_info->block_width * - src.format_info->block_height * - src.format_info->bits_per_pixel / 8; + uint32_t bytes_per_block = src.format_info()->block_width * + src.format_info()->block_height * + src.format_info()->bits_per_pixel / 8; // Tiled textures can be packed; get the offset into the packed texture. uint32_t offset_x; uint32_t offset_y; @@ -1023,7 +1025,7 @@ void TextureCache::ConvertTextureCube(uint8_t* dest, const TextureInfo& src) { y++, output_base_offset += src.size_cube.output_pitch) { auto input_base_offset = TextureInfo::TiledOffset2DOuter( offset_y + y, - (src.size_cube.input_width / src.format_info->block_width), bpp); + (src.size_cube.input_width / src.format_info()->block_width), bpp); for (uint32_t x = 0, output_offset = output_base_offset; x < src.size_cube.block_width; x++, output_offset += bytes_per_block) {