diff --git a/src/xenia/gpu/texture_info.cc b/src/xenia/gpu/texture_info.cc index f890cedef..4f8926f50 100644 --- a/src/xenia/gpu/texture_info.cc +++ b/src/xenia/gpu/texture_info.cc @@ -365,6 +365,16 @@ uint32_t TextureInfo::GetMipLocation(const TextureInfo& src, uint32_t mip, return address_base + address_offset; } +uint32_t TextureInfo::GetMipLinearSize(const TextureInfo& src, uint32_t mip) { + uint32_t bytes_per_block = src.format_info()->block_width * + src.format_info()->block_height * + src.format_info()->bits_per_pixel / 8; + uint32_t size = src.input_length >> (mip * 2); + + // The size is at least one block large. + return std::max(size, bytes_per_block); +} + bool TextureInfo::GetPackedTileOffset(uint32_t width, uint32_t height, const FormatInfo* format_info, uint32_t* out_offset_x, diff --git a/src/xenia/gpu/texture_info.h b/src/xenia/gpu/texture_info.h index 667210c55..930eff292 100644 --- a/src/xenia/gpu/texture_info.h +++ b/src/xenia/gpu/texture_info.h @@ -318,6 +318,9 @@ struct TextureInfo { // 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); + // 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, uint32_t* out_offset_x, diff --git a/src/xenia/gpu/vulkan/texture_cache.cc b/src/xenia/gpu/vulkan/texture_cache.cc index 3ea4afead..eac942b2e 100644 --- a/src/xenia/gpu/vulkan/texture_cache.cc +++ b/src/xenia/gpu/vulkan/texture_cache.cc @@ -62,7 +62,7 @@ static const TextureConfig texture_configs[64] = { // TODO: D24 unsupported on AMD. /* k_24_8 */ {VK_FORMAT_D24_UNORM_S8_UINT}, - /* k_24_8_FLOAT */ {VK_FORMAT_D24_UNORM_S8_UINT}, + /* k_24_8_FLOAT */ {VK_FORMAT_D32_SFLOAT_S8_UINT}, /* k_16 */ {VK_FORMAT_R16_UNORM}, /* k_16_16 */ {VK_FORMAT_R16G16_UNORM}, /* k_16_16_16_16 */ {VK_FORMAT_R16G16B16A16_UNORM}, @@ -555,7 +555,8 @@ TextureCache::TextureView* TextureCache::DemandView(Texture* texture, swiz_component_map[(swizzle >> 6) & 0x7], swiz_component_map[(swizzle >> 9) & 0x7], }; - view_info.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}; + view_info.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, + texture->texture_info.mip_levels, 0, 1}; if (texture->format == VK_FORMAT_D16_UNORM_S8_UINT || texture->format == VK_FORMAT_D24_UNORM_S8_UINT || texture->format == VK_FORMAT_D32_SFLOAT_S8_UINT) { @@ -887,6 +888,13 @@ bool TextureCache::ConvertTexture2D(uint8_t* dest, uint32_t input_width = src.size_2d.input_width >> mip; uint32_t input_height = src.size_2d.input_height >> mip; + // All dimensions must be at least one block w/h + logical_width = std::max(logical_width, src.format_info()->block_width); + logical_height = std::max(logical_height, src.format_info()->block_height); + block_width = std::max(block_width, src.format_info()->block_width); + input_width = std::max(input_width, src.format_info()->block_width); + input_height = std::max(input_height, src.format_info()->block_height); + if (!src.is_tiled) { uint32_t offset_x, offset_y; if (src.has_packed_mips && @@ -1018,7 +1026,7 @@ bool TextureCache::UploadTexture(VkCommandBuffer command_buffer, size_t total_unpack_length = unpack_length; for (uint32_t i = 1; i < src.mip_levels; i++) { // Add in more space for mips. - total_unpack_length += unpack_length >> (2 * i); + total_unpack_length += TextureInfo::GetMipLinearSize(src, i); } if (!staging_buffer_.CanAcquire(total_unpack_length)) { @@ -1087,7 +1095,7 @@ bool TextureCache::UploadTexture(VkCommandBuffer command_buffer, copy_regions[mip].imageOffset = {0, 0, 0}; // With each mip, the length is divided by 4. - buffer_offset += unpack_length >> (2 * mip); + buffer_offset += TextureInfo::GetMipLinearSize(src, mip); } // Transition the texture into a transfer destination layout.