From 69b92c6c3179efcc8c443fccb1d0bf0290f1f2bb Mon Sep 17 00:00:00 2001 From: gibbed Date: Sun, 12 Mar 2017 01:11:32 -0600 Subject: [PATCH] Maybe fix texture uploads where mipmaps are packed in linear textures. --- src/xenia/gpu/gl4/texture_cache.cc | 24 +++++++++++++++++++++++- src/xenia/gpu/texture_info.cc | 1 + src/xenia/gpu/texture_info.h | 1 + src/xenia/gpu/vulkan/texture_cache.cc | 21 ++++++++++++++++++++- 4 files changed, 45 insertions(+), 2 deletions(-) diff --git a/src/xenia/gpu/gl4/texture_cache.cc b/src/xenia/gpu/gl4/texture_cache.cc index 7e9e68840..af4c292af 100644 --- a/src/xenia/gpu/gl4/texture_cache.cc +++ b/src/xenia/gpu/gl4/texture_cache.cc @@ -785,7 +785,29 @@ bool TextureCache::UploadTexture2D(GLuint texture, auto allocation = scratch_buffer_->Acquire(unpack_length); if (!texture_info.is_tiled) { - if (texture_info.size_2d.input_pitch == texture_info.size_2d.output_pitch) { + if (texture_info.has_packed_mips) { + 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 offset_x; + uint32_t offset_y; + TextureInfo::GetPackedTileOffset(texture_info, &offset_x, &offset_y); + const uint8_t* src = host_address; + // TODO(gibbed): this needs checking + src += offset_y * texture_info.size_2d.input_pitch; + src += offset_x * bytes_per_block; + uint8_t* dest = reinterpret_cast(allocation.host_ptr); + uint32_t pitch = std::min(texture_info.size_2d.input_pitch, + texture_info.size_2d.output_pitch); + for (uint32_t y = 0; y < std::min(texture_info.size_2d.block_height, + texture_info.size_2d.logical_height); + y++) { + TextureSwap(texture_info.endianness, dest, src, pitch); + src += texture_info.size_2d.input_pitch; + dest += texture_info.size_2d.output_pitch; + } + } else if (texture_info.size_2d.input_pitch == + texture_info.size_2d.output_pitch) { // Fast path copy entire image. TextureSwap(texture_info.endianness, allocation.host_ptr, host_address, unpack_length); diff --git a/src/xenia/gpu/texture_info.cc b/src/xenia/gpu/texture_info.cc index 16f7f4daa..1f8bcab70 100644 --- a/src/xenia/gpu/texture_info.cc +++ b/src/xenia/gpu/texture_info.cc @@ -135,6 +135,7 @@ bool TextureInfo::Prepare(const xe_gpu_texture_fetch_t& fetch, info.format_info = FormatInfo::Get(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; diff --git a/src/xenia/gpu/texture_info.h b/src/xenia/gpu/texture_info.h index 1881a6e4b..d2cf11235 100644 --- a/src/xenia/gpu/texture_info.h +++ b/src/xenia/gpu/texture_info.h @@ -222,6 +222,7 @@ struct TextureInfo { const FormatInfo* format_info; Endian endianness; bool is_tiled; + bool has_packed_mips; uint32_t input_length; uint32_t output_length; diff --git a/src/xenia/gpu/vulkan/texture_cache.cc b/src/xenia/gpu/vulkan/texture_cache.cc index 81f598b3e..48487c2e6 100644 --- a/src/xenia/gpu/vulkan/texture_cache.cc +++ b/src/xenia/gpu/vulkan/texture_cache.cc @@ -986,7 +986,26 @@ void TextureCache::ConvertTexture1D(uint8_t* dest, const TextureInfo& src) { void TextureCache::ConvertTexture2D(uint8_t* dest, const TextureInfo& src) { void* host_address = memory_->TranslatePhysical(src.guest_address); if (!src.is_tiled) { - if (src.size_2d.input_pitch == src.size_2d.output_pitch) { + if (src.has_packed_mips) { + uint32_t bytes_per_block = src.format_info->block_width * + src.format_info->block_height * + src.format_info->bits_per_pixel / 8; + uint32_t offset_x; + uint32_t offset_y; + TextureInfo::GetPackedTileOffset(src, &offset_x, &offset_y); + const uint8_t* src_mem = reinterpret_cast(host_address); + src_mem += offset_y * src.size_2d.input_pitch; + src_mem += offset_x * bytes_per_block; + uint32_t pitch = + std::min(src.size_2d.input_pitch, src.size_2d.output_pitch); + for (uint32_t y = 0; + y < std::min(src.size_2d.block_height, src.size_2d.logical_height); + y++) { + TextureSwap(src.endianness, dest, src_mem, pitch); + src_mem += src.size_2d.input_pitch; + dest += src.size_2d.output_pitch; + } + } else if (src.size_2d.input_pitch == src.size_2d.output_pitch) { // Fast path copy entire image. TextureSwap(src.endianness, dest, host_address, src.output_length); } else {