diff --git a/src/video_core/buffer_cache/buffer_cache.cpp b/src/video_core/buffer_cache/buffer_cache.cpp index 4fa7c6bdb..7815abab4 100644 --- a/src/video_core/buffer_cache/buffer_cache.cpp +++ b/src/video_core/buffer_cache/buffer_cache.cpp @@ -581,15 +581,22 @@ bool BufferCache::SynchronizeBufferFromImage(Buffer& buffer, VAddr device_addr, return false; } Image& image = texture_cache.GetImage(image_id); + ASSERT_MSG(buffer.CpuAddr() == image.info.guest_address, + "Texel buffer aliases image subresources {} : {}", buffer.CpuAddr(), + image.info.guest_address); boost::container::small_vector copies; u32 offset = buffer.Offset(image.cpu_addr); const u32 num_layers = image.info.resources.layers; + u32 total_size = 0; for (u32 m = 0; m < image.info.resources.levels; m++) { const u32 width = std::max(image.info.size.width >> m, 1u); const u32 height = std::max(image.info.size.height >> m, 1u); const u32 depth = image.info.props.is_volume ? std::max(image.info.size.depth >> m, 1u) : 1u; const auto& [mip_size, mip_pitch, mip_height, mip_ofs] = image.info.mips_layout[m]; + if (total_size + mip_size > buffer.SizeBytes()) { + break; + } copies.push_back({ .bufferOffset = offset, .bufferRowLength = static_cast(mip_pitch), @@ -604,14 +611,14 @@ bool BufferCache::SynchronizeBufferFromImage(Buffer& buffer, VAddr device_addr, .imageExtent = {width, height, depth}, }); offset += mip_ofs * num_layers; + total_size += mip_size; } - if (!copies.empty()) { - scheduler.EndRendering(); - image.Transit(vk::ImageLayout::eTransferSrcOptimal, vk::AccessFlagBits2::eTransferRead, {}); - const auto cmdbuf = scheduler.CommandBuffer(); - cmdbuf.copyImageToBuffer(image.image, vk::ImageLayout::eTransferSrcOptimal, buffer.buffer, - copies); - } + ASSERT(!copies.empty()); // If triggered, need to find which layers fit + scheduler.EndRendering(); + image.Transit(vk::ImageLayout::eTransferSrcOptimal, vk::AccessFlagBits2::eTransferRead, {}); + const auto cmdbuf = scheduler.CommandBuffer(); + cmdbuf.copyImageToBuffer(image.image, vk::ImageLayout::eTransferSrcOptimal, buffer.buffer, + copies); return true; }