aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2024-09-15 18:12:05 -0300
committerGitHub <noreply@github.com>2024-09-15 18:12:05 -0300
commitcd74ae1bbd491987d983bfff36545451e2e6764c (patch)
treee4a3156c29f49497d39d2048a66d71ee91e01430
parent62216782ca9ca12ea01c88b2a43733e8949c5692 (diff)
Implement fast DMA texture to texture copy (#7299)1.1.1388
* Implement fast DMA texture to texture copy * PR feedback
-rw-r--r--src/Ryujinx.Graphics.Gpu/Engine/Dma/DmaClass.cs48
-rw-r--r--src/Ryujinx.Graphics.Gpu/Image/TextureCache.cs47
2 files changed, 93 insertions, 2 deletions
diff --git a/src/Ryujinx.Graphics.Gpu/Engine/Dma/DmaClass.cs b/src/Ryujinx.Graphics.Gpu/Engine/Dma/DmaClass.cs
index 218db15c..f2bfd8ea 100644
--- a/src/Ryujinx.Graphics.Gpu/Engine/Dma/DmaClass.cs
+++ b/src/Ryujinx.Graphics.Gpu/Engine/Dma/DmaClass.cs
@@ -276,8 +276,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma
dstBaseOffset += dstStride * (yCount - 1);
}
- ReadOnlySpan<byte> srcSpan = memoryManager.GetSpan(srcGpuVa + (ulong)srcBaseOffset, srcSize, true);
-
// If remapping is disabled, we always copy the components directly, in order.
// If it's enabled, but the mapping is just XYZW, we also copy them in order.
bool isIdentityRemap = !remap ||
@@ -289,6 +287,52 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma
bool completeSource = IsTextureCopyComplete(src, srcLinear, srcBpp, srcStride, xCount, yCount);
bool completeDest = IsTextureCopyComplete(dst, dstLinear, dstBpp, dstStride, xCount, yCount);
+ // Check if the source texture exists on the GPU, if it does, do a GPU side copy.
+ // Otherwise, we would need to flush the source texture which is costly.
+ // We don't expect the source to be linear in such cases, as linear source usually indicates buffer or CPU written data.
+
+ if (completeSource && completeDest && !srcLinear && isIdentityRemap)
+ {
+ var source = memoryManager.Physical.TextureCache.FindTexture(
+ memoryManager,
+ srcGpuVa,
+ srcBpp,
+ srcStride,
+ src.Height,
+ xCount,
+ yCount,
+ srcLinear,
+ src.MemoryLayout.UnpackGobBlocksInY(),
+ src.MemoryLayout.UnpackGobBlocksInZ());
+
+ if (source != null && source.Height == yCount)
+ {
+ source.SynchronizeMemory();
+
+ var target = memoryManager.Physical.TextureCache.FindOrCreateTexture(
+ memoryManager,
+ source.Info.FormatInfo,
+ dstGpuVa,
+ xCount,
+ yCount,
+ dstStride,
+ dstLinear,
+ dst.MemoryLayout.UnpackGobBlocksInY(),
+ dst.MemoryLayout.UnpackGobBlocksInZ());
+
+ if (source.ScaleFactor != target.ScaleFactor)
+ {
+ target.PropagateScale(source);
+ }
+
+ source.HostTexture.CopyTo(target.HostTexture, 0, 0);
+ target.SignalModified();
+ return;
+ }
+ }
+
+ ReadOnlySpan<byte> srcSpan = memoryManager.GetSpan(srcGpuVa + (ulong)srcBaseOffset, srcSize, true);
+
// Try to set the texture data directly,
// but only if we are doing a complete copy,
// and not for block linear to linear copies, since those are typically accessed from the CPU.
diff --git a/src/Ryujinx.Graphics.Gpu/Image/TextureCache.cs b/src/Ryujinx.Graphics.Gpu/Image/TextureCache.cs
index b6fa842e..5a3319b0 100644
--- a/src/Ryujinx.Graphics.Gpu/Image/TextureCache.cs
+++ b/src/Ryujinx.Graphics.Gpu/Image/TextureCache.cs
@@ -351,6 +351,53 @@ namespace Ryujinx.Graphics.Gpu.Image
/// Tries to find an existing texture, or create a new one if not found.
/// </summary>
/// <param name="memoryManager">GPU memory manager where the texture is mapped</param>
+ /// <param name="formatInfo">Format of the texture</param>
+ /// <param name="gpuAddress">GPU virtual address of the texture</param>
+ /// <param name="xCount">Texture width in bytes</param>
+ /// <param name="yCount">Texture height</param>
+ /// <param name="stride">Texture stride if linear, otherwise ignored</param>
+ /// <param name="isLinear">Indicates if the texture is linear or block linear</param>
+ /// <param name="gobBlocksInY">GOB blocks in Y for block linear textures</param>
+ /// <param name="gobBlocksInZ">GOB blocks in Z for 3D block linear textures</param>
+ /// <returns>The texture</returns>
+ public Texture FindOrCreateTexture(
+ MemoryManager memoryManager,
+ FormatInfo formatInfo,
+ ulong gpuAddress,
+ int xCount,
+ int yCount,
+ int stride,
+ bool isLinear,
+ int gobBlocksInY,
+ int gobBlocksInZ)
+ {
+ TextureInfo info = new(
+ gpuAddress,
+ xCount / formatInfo.BytesPerPixel,
+ yCount,
+ 1,
+ 1,
+ 1,
+ 1,
+ stride,
+ isLinear,
+ gobBlocksInY,
+ gobBlocksInZ,
+ 1,
+ Target.Texture2D,
+ formatInfo);
+
+ Texture texture = FindOrCreateTexture(memoryManager, TextureSearchFlags.ForCopy, info, 0, sizeHint: new Size(xCount, yCount, 1));
+
+ texture?.SynchronizeMemory();
+
+ return texture;
+ }
+
+ /// <summary>
+ /// Tries to find an existing texture, or create a new one if not found.
+ /// </summary>
+ /// <param name="memoryManager">GPU memory manager where the texture is mapped</param>
/// <param name="colorState">Color buffer texture to find or create</param>
/// <param name="layered">Indicates if the texture might be accessed with a non-zero layer index</param>
/// <param name="discard">Indicates that the sizeHint region's data will be overwritten</param>