diff --git a/src/SharpEmu.Libs/Gpu/Images/GuestImageCache.Transfers.cs b/src/SharpEmu.Libs/Gpu/Images/GuestImageCache.Transfers.cs index 000513d..d4b8cc9 100644 --- a/src/SharpEmu.Libs/Gpu/Images/GuestImageCache.Transfers.cs +++ b/src/SharpEmu.Libs/Gpu/Images/GuestImageCache.Transfers.cs @@ -703,11 +703,39 @@ public sealed unsafe partial class GuestImageCache } } + // The mip layout can end before the tile plan does (Silent Hill: a 128x128 slice planned at + // the exact end of the mip chain aborted the process). Cover the whole plan when the buffer + // holds it; otherwise keep the guest bytes instead of copying a partial image. + if (!plan.Depth && plan.Color.Tiled) + { + var tiledEnd = TiledEndOf(plan.Color.Tiles); + if (tiledEnd > copySize) + { + if (tiledEnd > available) + { + return false; + } + + copySize = tiledEnd; + } + } + DownloadToBuffer(image, buffer, bufferOffset, copySize, plan); image.MarkBufferHoldsGpuContents(); return true; } + private static ulong TiledEndOf(List tiles) + { + var end = 0UL; + foreach (var tile in tiles) + { + end = Math.Max(end, tile.TiledOffset + tile.TiledSize); + } + + return end; + } + // Publishes a GPU-owned image to guest memory after its tick completes; false when it cannot. private bool TryDownloadToGuest(ResourceSlotIdentifier imageIdentifier) {