diff --git a/Ryujinx.Graphics.Gpu/Image/TextureCache.cs b/Ryujinx.Graphics.Gpu/Image/TextureCache.cs index 27bec786..f18de607 100644 --- a/Ryujinx.Graphics.Gpu/Image/TextureCache.cs +++ b/Ryujinx.Graphics.Gpu/Image/TextureCache.cs @@ -474,6 +474,13 @@ namespace Ryujinx.Graphics.Gpu.Image { address = memoryManager.Translate(info.GpuAddress); + // If the start address is unmapped, let's try to find a page of memory that is mapped. + if (address == MemoryManager.PteUnmapped) + { + address = memoryManager.TranslateFirstMapped(info.GpuAddress, (ulong)info.CalculateSizeInfo(layerSize).TotalSize); + } + + // If address is still invalid, the texture is fully unmapped, so it has no data, just return null. if (address == MemoryManager.PteUnmapped) { return null; diff --git a/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs b/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs index 0ac6160d..b0f7e799 100644 --- a/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs +++ b/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs @@ -583,6 +583,38 @@ namespace Ryujinx.Graphics.Gpu.Memory return UnpackPaFromPte(pte) + (va & PageMask); } + /// + /// Translates a GPU virtual address to a CPU virtual address on the first mapped page of memory + /// on the specified region. + /// If no page is mapped on the specified region, is returned. + /// + /// GPU virtual address to be translated + /// Size of the range to be translated + /// CPU virtual address, or if unmapped + public ulong TranslateFirstMapped(ulong va, ulong size) + { + if (!ValidateAddress(va)) + { + return PteUnmapped; + } + + ulong endVa = va + size; + + ulong pte = GetPte(va); + + for (; va < endVa && pte == PteUnmapped; va += PageSize - (va & PageMask)) + { + pte = GetPte(va); + } + + if (pte == PteUnmapped) + { + return PteUnmapped; + } + + return UnpackPaFromPte(pte) + (va & PageMask); + } + /// /// Gets the kind of a given memory page. /// This might indicate the type of resource that can be allocated on the page, and also texture tiling.