diff options
Diffstat (limited to 'Ryujinx.Graphics.Gpu')
| -rw-r--r-- | Ryujinx.Graphics.Gpu/Image/Texture.cs | 55 | ||||
| -rw-r--r-- | Ryujinx.Graphics.Gpu/Memory/Buffer.cs | 2 | ||||
| -rw-r--r-- | Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs | 5 |
3 files changed, 48 insertions, 14 deletions
diff --git a/Ryujinx.Graphics.Gpu/Image/Texture.cs b/Ryujinx.Graphics.Gpu/Image/Texture.cs index c9bff561..a3105cf2 100644 --- a/Ryujinx.Graphics.Gpu/Image/Texture.cs +++ b/Ryujinx.Graphics.Gpu/Image/Texture.cs @@ -4,6 +4,7 @@ using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.Gpu.Memory; using Ryujinx.Graphics.Texture; using Ryujinx.Graphics.Texture.Astc; +using Ryujinx.Memory; using Ryujinx.Memory.Range; using System; using System.Collections.Generic; @@ -821,14 +822,7 @@ namespace Ryujinx.Graphics.Gpu.Image return; // Flushing this format is not supported, as it may have been converted to another host format. } - if (tracked) - { - _physicalMemory.Write(Range, GetTextureDataFromGpu(tracked)); - } - else - { - _physicalMemory.WriteUntracked(Range, GetTextureDataFromGpu(tracked)); - } + FlushTextureDataToGuest(tracked); } /// <summary> @@ -864,19 +858,56 @@ namespace Ryujinx.Graphics.Gpu.Image texture = _flushHostTexture = GetScaledHostTexture(1f, _flushHostTexture); } - _physicalMemory.WriteUntracked(Range, GetTextureDataFromGpu(false, texture)); + FlushTextureDataToGuest(false, texture); }); } /// <summary> + /// Gets data from the host GPU, and flushes it to guest memory. + /// </summary> + /// <remarks> + /// This method should be used to retrieve data that was modified by the host GPU. + /// This is not cheap, avoid doing that unless strictly needed. + /// When possible, the data is written directly into guest memory, rather than copied. + /// </remarks> + /// <param name="tracked">True if writing the texture data is tracked, false otherwise</param> + /// <param name="texture">The specific host texture to flush. Defaults to this texture</param> + private void FlushTextureDataToGuest(bool tracked, ITexture texture = null) + { + if (Range.Count == 1) + { + MemoryRange subrange = Range.GetSubRange(0); + + using (WritableRegion region = _physicalMemory.GetWritableRegion(subrange.Address, (int)subrange.Size, tracked)) + { + GetTextureDataFromGpu(region.Memory.Span, tracked, texture); + } + } + else + { + if (tracked) + { + _physicalMemory.Write(Range, GetTextureDataFromGpu(Span<byte>.Empty, true, texture)); + } + else + { + _physicalMemory.WriteUntracked(Range, GetTextureDataFromGpu(Span<byte>.Empty, false, texture)); + } + } + } + + /// <summary> /// Gets data from the host GPU. /// </summary> /// <remarks> /// This method should be used to retrieve data that was modified by the host GPU. /// This is not cheap, avoid doing that unless strictly needed. /// </remarks> - /// <returns>Host texture data</returns> - private ReadOnlySpan<byte> GetTextureDataFromGpu(bool blacklist, ITexture texture = null) + /// <param name="output">An output span to place the texture data into. If empty, one is generated</param> + /// <param name="blacklist">True if the texture should be blacklisted, false otherwise</param> + /// <param name="texture">The specific host texture to flush. Defaults to this texture</param> + /// <returns>The span containing the texture data</returns> + private ReadOnlySpan<byte> GetTextureDataFromGpu(Span<byte> output, bool blacklist, ITexture texture = null) { ReadOnlySpan<byte> data; @@ -909,6 +940,7 @@ namespace Ryujinx.Graphics.Gpu.Image if (Info.IsLinear) { data = LayoutConverter.ConvertLinearToLinearStrided( + output, Info.Width, Info.Height, Info.FormatInfo.BlockWidth, @@ -920,6 +952,7 @@ namespace Ryujinx.Graphics.Gpu.Image else { data = LayoutConverter.ConvertLinearToBlockLinear( + output, Info.Width, Info.Height, _depth, diff --git a/Ryujinx.Graphics.Gpu/Memory/Buffer.cs b/Ryujinx.Graphics.Gpu/Memory/Buffer.cs index 96e10e77..3f869a50 100644 --- a/Ryujinx.Graphics.Gpu/Memory/Buffer.cs +++ b/Ryujinx.Graphics.Gpu/Memory/Buffer.cs @@ -412,7 +412,7 @@ namespace Ryujinx.Graphics.Gpu.Memory { int offset = (int)(address - Address); - byte[] data = _context.Renderer.GetBufferData(Handle, offset, (int)size); + ReadOnlySpan<byte> data = _context.Renderer.GetBufferData(Handle, offset, (int)size); // TODO: When write tracking shaders, they will need to be aware of changes in overlapping buffers. _physicalMemory.WriteUntracked(address, data); diff --git a/Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs b/Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs index 289e7c1b..8df3c8fb 100644 --- a/Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs +++ b/Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs @@ -128,10 +128,11 @@ namespace Ryujinx.Graphics.Gpu.Memory /// </summary> /// <param name="address">Start address of the range</param> /// <param name="size">Size in bytes to be range</param> + /// <param name="tracked">True if write tracking is triggered on the span</param> /// <returns>A writable region with the data at the specified memory location</returns> - public WritableRegion GetWritableRegion(ulong address, int size) + public WritableRegion GetWritableRegion(ulong address, int size, bool tracked = false) { - return _cpuMemory.GetWritableRegion(address, size); + return _cpuMemory.GetWritableRegion(address, size, tracked); } /// <summary> |
