From b35fe935f95d4f31ae793880987deef14b6232f7 Mon Sep 17 00:00:00 2001 From: gibbed Date: Fri, 1 Jun 2018 22:04:13 -0500 Subject: [PATCH] [GPU] Ignore mipmap level count when mip data address is invalid. --- src/xenia/gpu/texture_info.cc | 33 +++++++++++++++++++-------- src/xenia/gpu/vulkan/texture_cache.cc | 24 +++++++++++-------- 2 files changed, 39 insertions(+), 18 deletions(-) diff --git a/src/xenia/gpu/texture_info.cc b/src/xenia/gpu/texture_info.cc index fe971ce58..c154beecd 100644 --- a/src/xenia/gpu/texture_info.cc +++ b/src/xenia/gpu/texture_info.cc @@ -62,7 +62,8 @@ bool TextureInfo::Prepare(const xe_gpu_texture_fetch_t& fetch, break; } info.pitch = fetch.pitch << 5; - info.mip_levels = fetch.packed_mips ? fetch.mip_max_level + 1 : 1; + assert_true(fetch.mip_min_level == 0); + info.mip_levels = 1 + fetch.mip_max_level; info.is_tiled = fetch.tiled; info.has_packed_mips = fetch.packed_mips; @@ -77,6 +78,12 @@ bool TextureInfo::Prepare(const xe_gpu_texture_fetch_t& fetch, info.extent = TextureExtent::Calculate(out_info, true); info.SetupMemoryInfo(fetch.base_address << 12, fetch.mip_address << 12); + + if (!info.memory.mip_address) { + // No mip data? One mip level, period. + info.mip_levels = 1; + } + return true; } @@ -149,7 +156,7 @@ void TextureInfo::GetMipSize(uint32_t mip, uint32_t* out_width, uint32_t TextureInfo::GetMipLocation(uint32_t mip, uint32_t* offset_x, uint32_t* offset_y, bool is_guest) const { if (mip == 0) { - // Short-circuit. Mip 0 is always stored in guest_address. + // Short-circuit. Mip 0 is always stored in base_address. if (!has_packed_mips) { *offset_x = 0; *offset_y = 0; @@ -159,6 +166,13 @@ uint32_t TextureInfo::GetMipLocation(uint32_t mip, uint32_t* offset_x, return memory.base_address; } + if (!memory.mip_address) { + // Short-circuit. There is no mip data. + *offset_x = 0; + *offset_y = 0; + return 0; + } + uint32_t address_base, address_offset; address_base = memory.mip_address; address_offset = 0; @@ -296,20 +310,21 @@ void TextureInfo::SetupMemoryInfo(uint32_t base_address, uint32_t mip_address) { memory.mip_address = 0; memory.mip_size = 0; - if (mip_levels <= 1) { + if (mip_levels <= 1 || !mip_address) { // Sort circuit. Only one mip. return; } - if (!mip_address || base_address == mip_address) { - memory.mip_address = base_address; - memory.mip_address += GetMipExtent(0, true).all_blocks() * bytes_per_block; - } else { - memory.mip_address = mip_address; + if (base_address == mip_address) { + // TODO(gibbed): This doesn't actually make any sense. Force only one mip. + // Offending title issues: #26, #45 + return; } + memory.mip_address = mip_address; + if (!has_packed_mips) { - for (uint32_t mip = 0; mip < mip_levels - 1; mip++) { + for (uint32_t mip = 1; mip < mip_levels - 1; mip++) { memory.mip_size += GetMipExtent(mip, true).all_blocks() * bytes_per_block; } memory.mip_size += diff --git a/src/xenia/gpu/vulkan/texture_cache.cc b/src/xenia/gpu/vulkan/texture_cache.cc index f61ddb893..e6d284681 100644 --- a/src/xenia/gpu/vulkan/texture_cache.cc +++ b/src/xenia/gpu/vulkan/texture_cache.cc @@ -898,6 +898,10 @@ bool TextureCache::ConvertTexture(uint8_t* dest, VkBufferImageCopy* copy_region, uint32_t offset_x = 0; uint32_t offset_y = 0; uint32_t address = src.GetMipLocation(mip, &offset_x, &offset_y, true); + if (!address) { + return false; + } + void* host_address = memory_->TranslatePhysical(address); auto is_cube = src.dimension == Dimension::kCube; @@ -1025,17 +1029,16 @@ bool TextureCache::UploadTexture(VkCommandBuffer command_buffer, // on the CPU. std::vector copy_regions(src.mip_levels); - auto dest_data = reinterpret_cast(alloc->host_ptr); - - // Upload all the mips - VkDeviceSize buffer_offset = 0; + // Upload all mips. + auto unpack_buffer = reinterpret_cast(alloc->host_ptr); + VkDeviceSize unpack_offset = 0; for (uint32_t mip = 0; mip < src.mip_levels; mip++) { - if (!ConvertTexture(&dest_data[buffer_offset], ©_regions[mip], mip, + if (!ConvertTexture(&unpack_buffer[unpack_offset], ©_regions[mip], mip, src)) { XELOGW("Failed to convert texture mip %u!", mip); return false; } - copy_regions[mip].bufferOffset = alloc->offset + buffer_offset; + copy_regions[mip].bufferOffset = alloc->offset + unpack_offset; copy_regions[mip].imageOffset = {0, 0, 0}; /* @@ -1044,7 +1047,7 @@ bool TextureCache::UploadTexture(VkCommandBuffer command_buffer, copy_regions[mip].imageExtent.depth, buffer_offset); */ - buffer_offset += ComputeMipStorage(src, mip); + unpack_offset += ComputeMipStorage(src, mip); } // Transition the texture into a transfer destination layout. @@ -1177,8 +1180,11 @@ uint32_t TextureCache::ComputeTextureStorage(const TextureInfo& src) { uint32_t height = src.height + 1; uint32_t depth = src.depth + 1; uint32_t length = 0; - for (uint32_t mip = 0; mip < src.mip_levels; mip++) { - length += ComputeMipStorage(format_info, width, height, depth, mip); + length += ComputeMipStorage(format_info, width, height, depth, 0); + if (src.memory.mip_address) { + for (uint32_t mip = 1; mip < src.mip_levels; mip++) { + length += ComputeMipStorage(format_info, width, height, depth, mip); + } } return length; }