Fix a bunch of issues with texture copy and flush (#32)

* Fix a bunch of issues with texture copy and flush

* TextureCopy helper class, fix clear bug
This commit is contained in:
riperiperi 2024-07-03 10:27:03 +01:00 committed by Isaac Marovitz
parent 0c1acb5107
commit 7b9b23e500
5 changed files with 351 additions and 115 deletions

View file

@ -57,7 +57,10 @@ namespace Ryujinx.Graphics.Metal
var swizzle = GetSwizzle(info, pixelFormat);
_mtlTexture = sourceTexture.NewTextureView(pixelFormat, textureType, levels, slices, swizzle);
MtlFormat = pixelFormat;
FirstLayer = firstLayer;
FirstLevel = firstLevel;
}
private MTLTextureSwizzleChannels GetSwizzle(TextureCreateInfo info, MTLPixelFormat pixelFormat)
@ -94,6 +97,109 @@ namespace Ryujinx.Graphics.Metal
}
public void CopyTo(ITexture destination, int firstLayer, int firstLevel)
{
CommandBufferScoped cbs = _pipeline.Cbs;
TextureBase src = this;
TextureBase dst = (TextureBase)destination;
var srcImage = GetHandle();
var dstImage = dst.GetHandle();
if (!dst.Info.Target.IsMultisample() && Info.Target.IsMultisample())
{
//int layers = Math.Min(Info.GetLayers(), dst.Info.GetLayers() - firstLayer);
//_gd.HelperShader.CopyMSToNonMS(_gd, cbs, src, dst, 0, firstLayer, layers);
}
else if (dst.Info.Target.IsMultisample() && !Info.Target.IsMultisample())
{
//int layers = Math.Min(Info.GetLayers(), dst.Info.GetLayers() - firstLayer);
//_gd.HelperShader.CopyNonMSToMS(_gd, cbs, src, dst, 0, firstLayer, layers);
}
else if (dst.Info.BytesPerPixel != Info.BytesPerPixel)
{
//int layers = Math.Min(Info.GetLayers(), dst.Info.GetLayers() - firstLayer);
//int levels = Math.Min(Info.Levels, dst.Info.Levels - firstLevel);
//_gd.HelperShader.CopyIncompatibleFormats(_gd, cbs, src, dst, 0, firstLayer, 0, firstLevel, layers, levels);
}
else if (src.Info.Format.IsDepthOrStencil() != dst.Info.Format.IsDepthOrStencil())
{
int layers = Math.Min(Info.GetLayers(), dst.Info.GetLayers() - firstLayer);
int levels = Math.Min(Info.Levels, dst.Info.Levels - firstLevel);
// TODO: depth copy?
//_gd.HelperShader.CopyColor(_gd, cbs, src, dst, 0, firstLayer, 0, FirstLevel, layers, levels);
}
else
{
TextureCopy.Copy(
cbs,
srcImage,
dstImage,
src.Info,
dst.Info,
0,//src.FirstLayer,
0,//dst.FirstLayer,
0,//src.FirstLevel,
0,//dst.FirstLevel,
0,
firstLayer,
0,
firstLevel);
}
}
public void CopyTo(ITexture destination, int srcLayer, int dstLayer, int srcLevel, int dstLevel)
{
CommandBufferScoped cbs = _pipeline.Cbs;
TextureBase src = this;
TextureBase dst = (TextureBase)destination;
var srcImage = GetHandle();
var dstImage = dst.GetHandle();
if (!dst.Info.Target.IsMultisample() && Info.Target.IsMultisample())
{
//_gd.HelperShader.CopyMSToNonMS(_gd, cbs, src, dst, srcLayer, dstLayer, 1);
}
else if (dst.Info.Target.IsMultisample() && !Info.Target.IsMultisample())
{
//_gd.HelperShader.CopyNonMSToMS(_gd, cbs, src, dst, srcLayer, dstLayer, 1);
}
else if (dst.Info.BytesPerPixel != Info.BytesPerPixel)
{
//_gd.HelperShader.CopyIncompatibleFormats(_gd, cbs, src, dst, srcLayer, dstLayer, srcLevel, dstLevel, 1, 1);
}
else if (src.Info.Format.IsDepthOrStencil() != dst.Info.Format.IsDepthOrStencil())
{
//_gd.HelperShader.CopyColor(_gd, cbs, src, dst, srcLayer, dstLayer, srcLevel, dstLevel, 1, 1);
}
else
{
TextureCopy.Copy(
cbs,
srcImage,
dstImage,
src.Info,
dst.Info,
0, //src.FirstLayer,
0, //dst.FirstLayer,
0, //src.FirstLevel,
0, //dst.FirstLevel,
srcLayer,
dstLayer,
srcLevel,
dstLevel,
1,
1);
}
}
public void CopyTo(ITexture destination, Extents2D srcRegion, Extents2D dstRegion, bool linearFilter)
{
if (!_renderer.CommandBufferPool.OwnedByCurrentThread)
{
@ -102,107 +208,31 @@ namespace Ryujinx.Graphics.Metal
return;
}
var blitCommandEncoder = _pipeline.GetOrCreateBlitEncoder();
if (destination is Texture destinationTexture)
{
if (destinationTexture.Info.Target == Target.Texture3D)
{
blitCommandEncoder.CopyFromTexture(
_mtlTexture,
0,
(ulong)firstLevel,
new MTLOrigin { x = 0, y = 0, z = (ulong)firstLayer },
new MTLSize { width = (ulong)Math.Min(Info.Width, destinationTexture.Info.Width), height = (ulong)Math.Min(Info.Height, destinationTexture.Info.Height), depth = 1 },
destinationTexture._mtlTexture,
0,
(ulong)firstLevel,
new MTLOrigin { x = 0, y = 0, z = (ulong)firstLayer });
}
else
{
blitCommandEncoder.CopyFromTexture(
_mtlTexture,
(ulong)firstLayer,
(ulong)firstLevel,
destinationTexture._mtlTexture,
(ulong)firstLayer,
(ulong)firstLevel,
_mtlTexture.ArrayLength,
_mtlTexture.MipmapLevelCount);
}
}
}
public void CopyTo(ITexture destination, int srcLayer, int dstLayer, int srcLevel, int dstLevel)
{
var blitCommandEncoder = _pipeline.GetOrCreateBlitEncoder();
if (destination is Texture destinationTexture)
{
if (destinationTexture.Info.Target == Target.Texture3D)
{
blitCommandEncoder.CopyFromTexture(
_mtlTexture,
0,
(ulong)srcLevel,
new MTLOrigin { x = 0, y = 0, z = (ulong)srcLayer },
new MTLSize { width = (ulong)Math.Min(Info.Width, destinationTexture.Info.Width), height = (ulong)Math.Min(Info.Height, destinationTexture.Info.Height), depth = 1 },
destinationTexture._mtlTexture,
0,
(ulong)dstLevel,
new MTLOrigin { x = 0, y = 0, z = (ulong)dstLayer });
}
else
{
blitCommandEncoder.CopyFromTexture(
_mtlTexture,
(ulong)srcLayer,
(ulong)srcLevel,
destinationTexture._mtlTexture,
(ulong)dstLayer,
(ulong)dstLevel,
_mtlTexture.ArrayLength,
_mtlTexture.MipmapLevelCount);
}
}
}
public void CopyTo(ITexture destination, Extents2D srcRegion, Extents2D dstRegion, bool linearFilter)
{
var dst = (Texture)destination;
bool isDepthOrStencil = dst.Info.Format.IsDepthOrStencil();
if (dst.Info.IsCompressed) {
Console.WriteLine("shit");
}
_pipeline.Blit(this, destination, srcRegion, dstRegion, isDepthOrStencil, linearFilter);
}
public void CopyTo(BufferRange range, int layer, int level, int stride)
{
var blitCommandEncoder = _pipeline.GetOrCreateBlitEncoder();
var cbs = _pipeline.Cbs;
int outSize = Info.GetMipSize(level);
int hostSize = GetBufferDataLength(outSize);
ulong bytesPerRow = (ulong)Info.GetMipStride(level);
ulong bytesPerImage = 0;
if (_mtlTexture.TextureType == MTLTextureType.Type3D)
{
bytesPerImage = bytesPerRow * (ulong)Info.Height;
}
int offset = range.Offset;
var autoBuffer = _renderer.BufferManager.GetBuffer(range.Handle, true);
var mtlBuffer = autoBuffer.Get(cbs, range.Offset, outSize).Value;
blitCommandEncoder.CopyFromTexture(
_mtlTexture,
(ulong)layer,
(ulong)level,
new MTLOrigin(),
new MTLSize { width = _mtlTexture.Width, height = _mtlTexture.Height, depth = _mtlTexture.Depth },
mtlBuffer,
(ulong)range.Offset,
bytesPerRow,
bytesPerImage);
// TODO: D32S8 conversion via temp copy holder
CopyFromOrToBuffer(cbs, mtlBuffer, _mtlTexture, hostSize, true, layer, level, 1, 1, singleSlice: true, offset: offset, stride: stride);
}
public ITexture CreateView(TextureCreateInfo info, int firstLayer, int firstLevel)
@ -217,6 +247,13 @@ namespace Ryujinx.Graphics.Metal
return size;
}
private void CopyDataToBuffer(Span<byte> storage, ReadOnlySpan<byte> input)
{
// TODO: D32S8 conversion
input.CopyTo(storage);
}
private ReadOnlySpan<byte> GetDataFromBuffer(ReadOnlySpan<byte> storage, int size, Span<byte> output)
{
// TODO: D32S8 conversion
@ -422,37 +459,29 @@ namespace Ryujinx.Graphics.Metal
buffer.Dispose();
}
private void SetData(ReadOnlySpan<byte> data, int layer, int level, int layers, int levels, bool singleSlice)
{
int bufferDataLength = GetBufferDataLength(data.Length);
using var bufferHolder = _renderer.BufferManager.Create(bufferDataLength);
// TODO: loadInline logic
var cbs = _pipeline.Cbs;
CopyDataToBuffer(bufferHolder.GetDataStorage(0, bufferDataLength), data);
var buffer = bufferHolder.GetBuffer().Get(cbs).Value;
var image = GetHandle();
CopyFromOrToBuffer(cbs, buffer, image, bufferDataLength, false, layer, level, layers, levels, singleSlice);
}
public void SetData(IMemoryOwner<byte> data, int layer, int level)
{
var blitCommandEncoder = _pipeline.GetOrCreateBlitEncoder();
SetData(data.Memory.Span, layer, level, 1, 1, singleSlice: true);
ulong bytesPerRow = (ulong)Info.GetMipStride(level);
ulong bytesPerImage = 0;
if (_mtlTexture.TextureType == MTLTextureType.Type3D)
{
bytesPerImage = bytesPerRow * (ulong)Info.Height;
}
var dataSpan = data.Memory.Span;
var buffer = _renderer.BufferManager.Create(dataSpan.Length);
buffer.SetDataUnchecked(0, dataSpan);
var mtlBuffer = buffer.GetBuffer(false).Get(_pipeline.Cbs).Value;
blitCommandEncoder.CopyFromBuffer(
mtlBuffer,
0,
bytesPerRow,
bytesPerImage,
new MTLSize { width = _mtlTexture.Width, height = _mtlTexture.Height, depth = _mtlTexture.Depth },
_mtlTexture,
(ulong)layer,
(ulong)level,
new MTLOrigin()
);
// Cleanup
buffer.Dispose();
data.Dispose();
}
public void SetData(IMemoryOwner<byte> data, int layer, int level, Rectangle<int> region)