forked from Mirror/Ryujinx
Implement fast DMA texture to texture copy (#7299)
* Implement fast DMA texture to texture copy * PR feedback
This commit is contained in:
parent
62216782ca
commit
cd74ae1bbd
2 changed files with 93 additions and 2 deletions
|
@ -276,8 +276,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma
|
||||||
dstBaseOffset += dstStride * (yCount - 1);
|
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 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.
|
// If it's enabled, but the mapping is just XYZW, we also copy them in order.
|
||||||
bool isIdentityRemap = !remap ||
|
bool isIdentityRemap = !remap ||
|
||||||
|
@ -289,6 +287,52 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma
|
||||||
bool completeSource = IsTextureCopyComplete(src, srcLinear, srcBpp, srcStride, xCount, yCount);
|
bool completeSource = IsTextureCopyComplete(src, srcLinear, srcBpp, srcStride, xCount, yCount);
|
||||||
bool completeDest = IsTextureCopyComplete(dst, dstLinear, dstBpp, dstStride, 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,
|
// Try to set the texture data directly,
|
||||||
// but only if we are doing a complete copy,
|
// 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.
|
// and not for block linear to linear copies, since those are typically accessed from the CPU.
|
||||||
|
|
|
@ -347,6 +347,53 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
return texture;
|
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="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>
|
/// <summary>
|
||||||
/// Tries to find an existing texture, or create a new one if not found.
|
/// Tries to find an existing texture, or create a new one if not found.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
Reference in a new issue