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:
parent
0c1acb5107
commit
7b9b23e500
5 changed files with 351 additions and 115 deletions
|
@ -318,11 +318,14 @@ namespace Ryujinx.Graphics.Metal
|
||||||
0f,
|
0f,
|
||||||
1f);
|
1f);
|
||||||
|
|
||||||
|
Span<uint> componentMasks = stackalloc uint[index + 1];
|
||||||
|
componentMasks[index] = componentMask;
|
||||||
|
|
||||||
_pipeline.SetProgram(_programsColorClear[index]);
|
_pipeline.SetProgram(_programsColorClear[index]);
|
||||||
_pipeline.SetBlendState(index, new BlendDescriptor());
|
_pipeline.SetBlendState(index, new BlendDescriptor());
|
||||||
_pipeline.SetFaceCulling(false, Face.Front);
|
_pipeline.SetFaceCulling(false, Face.Front);
|
||||||
_pipeline.SetDepthTest(new DepthTestDescriptor(false, false, CompareOp.Always));
|
_pipeline.SetDepthTest(new DepthTestDescriptor(false, false, CompareOp.Always));
|
||||||
_pipeline.SetRenderTargetColorMasks([componentMask]);
|
_pipeline.SetRenderTargetColorMasks(componentMasks);
|
||||||
_pipeline.SetViewports(viewports);
|
_pipeline.SetViewports(viewports);
|
||||||
_pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip);
|
_pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip);
|
||||||
_pipeline.Draw(4, 1, 0, 0);
|
_pipeline.Draw(4, 1, 0, 0);
|
||||||
|
|
|
@ -149,7 +149,7 @@ namespace Ryujinx.Graphics.Metal
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool signaled = result.Signalled || result.Waitable.WaitForFences(false);
|
bool signaled = result.Signalled || result.Waitable.WaitForFences(true);
|
||||||
|
|
||||||
if (!signaled)
|
if (!signaled)
|
||||||
{
|
{
|
||||||
|
|
|
@ -57,7 +57,10 @@ namespace Ryujinx.Graphics.Metal
|
||||||
var swizzle = GetSwizzle(info, pixelFormat);
|
var swizzle = GetSwizzle(info, pixelFormat);
|
||||||
|
|
||||||
_mtlTexture = sourceTexture.NewTextureView(pixelFormat, textureType, levels, slices, swizzle);
|
_mtlTexture = sourceTexture.NewTextureView(pixelFormat, textureType, levels, slices, swizzle);
|
||||||
|
|
||||||
MtlFormat = pixelFormat;
|
MtlFormat = pixelFormat;
|
||||||
|
FirstLayer = firstLayer;
|
||||||
|
FirstLevel = firstLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
private MTLTextureSwizzleChannels GetSwizzle(TextureCreateInfo info, MTLPixelFormat pixelFormat)
|
private MTLTextureSwizzleChannels GetSwizzle(TextureCreateInfo info, MTLPixelFormat pixelFormat)
|
||||||
|
@ -94,6 +97,109 @@ namespace Ryujinx.Graphics.Metal
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CopyTo(ITexture destination, int firstLayer, int firstLevel)
|
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)
|
if (!_renderer.CommandBufferPool.OwnedByCurrentThread)
|
||||||
{
|
{
|
||||||
|
@ -102,107 +208,31 @@ namespace Ryujinx.Graphics.Metal
|
||||||
return;
|
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;
|
var dst = (Texture)destination;
|
||||||
bool isDepthOrStencil = dst.Info.Format.IsDepthOrStencil();
|
bool isDepthOrStencil = dst.Info.Format.IsDepthOrStencil();
|
||||||
|
|
||||||
|
if (dst.Info.IsCompressed) {
|
||||||
|
Console.WriteLine("shit");
|
||||||
|
}
|
||||||
|
|
||||||
_pipeline.Blit(this, destination, srcRegion, dstRegion, isDepthOrStencil, linearFilter);
|
_pipeline.Blit(this, destination, srcRegion, dstRegion, isDepthOrStencil, linearFilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CopyTo(BufferRange range, int layer, int level, int stride)
|
public void CopyTo(BufferRange range, int layer, int level, int stride)
|
||||||
{
|
{
|
||||||
var blitCommandEncoder = _pipeline.GetOrCreateBlitEncoder();
|
|
||||||
var cbs = _pipeline.Cbs;
|
var cbs = _pipeline.Cbs;
|
||||||
|
|
||||||
int outSize = Info.GetMipSize(level);
|
int outSize = Info.GetMipSize(level);
|
||||||
|
int hostSize = GetBufferDataLength(outSize);
|
||||||
|
|
||||||
ulong bytesPerRow = (ulong)Info.GetMipStride(level);
|
int offset = range.Offset;
|
||||||
ulong bytesPerImage = 0;
|
|
||||||
if (_mtlTexture.TextureType == MTLTextureType.Type3D)
|
|
||||||
{
|
|
||||||
bytesPerImage = bytesPerRow * (ulong)Info.Height;
|
|
||||||
}
|
|
||||||
|
|
||||||
var autoBuffer = _renderer.BufferManager.GetBuffer(range.Handle, true);
|
var autoBuffer = _renderer.BufferManager.GetBuffer(range.Handle, true);
|
||||||
var mtlBuffer = autoBuffer.Get(cbs, range.Offset, outSize).Value;
|
var mtlBuffer = autoBuffer.Get(cbs, range.Offset, outSize).Value;
|
||||||
|
|
||||||
blitCommandEncoder.CopyFromTexture(
|
// TODO: D32S8 conversion via temp copy holder
|
||||||
_mtlTexture,
|
|
||||||
(ulong)layer,
|
CopyFromOrToBuffer(cbs, mtlBuffer, _mtlTexture, hostSize, true, layer, level, 1, 1, singleSlice: true, offset: offset, stride: stride);
|
||||||
(ulong)level,
|
|
||||||
new MTLOrigin(),
|
|
||||||
new MTLSize { width = _mtlTexture.Width, height = _mtlTexture.Height, depth = _mtlTexture.Depth },
|
|
||||||
mtlBuffer,
|
|
||||||
(ulong)range.Offset,
|
|
||||||
bytesPerRow,
|
|
||||||
bytesPerImage);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ITexture CreateView(TextureCreateInfo info, int firstLayer, int firstLevel)
|
public ITexture CreateView(TextureCreateInfo info, int firstLayer, int firstLevel)
|
||||||
|
@ -217,6 +247,13 @@ namespace Ryujinx.Graphics.Metal
|
||||||
return size;
|
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)
|
private ReadOnlySpan<byte> GetDataFromBuffer(ReadOnlySpan<byte> storage, int size, Span<byte> output)
|
||||||
{
|
{
|
||||||
// TODO: D32S8 conversion
|
// TODO: D32S8 conversion
|
||||||
|
@ -422,37 +459,29 @@ namespace Ryujinx.Graphics.Metal
|
||||||
buffer.Dispose();
|
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)
|
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);
|
data.Dispose();
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetData(IMemoryOwner<byte> data, int layer, int level, Rectangle<int> region)
|
public void SetData(IMemoryOwner<byte> data, int layer, int level, Rectangle<int> region)
|
||||||
|
|
|
@ -21,7 +21,10 @@ namespace Ryujinx.Graphics.Metal
|
||||||
public int Width => Info.Width;
|
public int Width => Info.Width;
|
||||||
public int Height => Info.Height;
|
public int Height => Info.Height;
|
||||||
public int Depth => Info.Depth;
|
public int Depth => Info.Depth;
|
||||||
|
|
||||||
public MTLPixelFormat MtlFormat { get; protected set; }
|
public MTLPixelFormat MtlFormat { get; protected set; }
|
||||||
|
public int FirstLayer { get; protected set; }
|
||||||
|
public int FirstLevel { get; protected set; }
|
||||||
|
|
||||||
public TextureBase(MTLDevice device, MetalRenderer renderer, Pipeline pipeline, TextureCreateInfo info)
|
public TextureBase(MTLDevice device, MetalRenderer renderer, Pipeline pipeline, TextureCreateInfo info)
|
||||||
{
|
{
|
||||||
|
|
201
src/Ryujinx.Graphics.Metal/TextureCopy.cs
Normal file
201
src/Ryujinx.Graphics.Metal/TextureCopy.cs
Normal file
|
@ -0,0 +1,201 @@
|
||||||
|
using Ryujinx.Common;
|
||||||
|
using Ryujinx.Common.Logging;
|
||||||
|
using Ryujinx.Graphics.GAL;
|
||||||
|
using SharpMetal.Metal;
|
||||||
|
using System;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
|
namespace Ryujinx.Graphics.Metal
|
||||||
|
{
|
||||||
|
static class TextureCopy
|
||||||
|
{
|
||||||
|
public static void Copy(
|
||||||
|
CommandBufferScoped cbs,
|
||||||
|
MTLTexture srcImage,
|
||||||
|
MTLTexture dstImage,
|
||||||
|
TextureCreateInfo srcInfo,
|
||||||
|
TextureCreateInfo dstInfo,
|
||||||
|
int srcViewLayer,
|
||||||
|
int dstViewLayer,
|
||||||
|
int srcViewLevel,
|
||||||
|
int dstViewLevel,
|
||||||
|
int srcLayer,
|
||||||
|
int dstLayer,
|
||||||
|
int srcLevel,
|
||||||
|
int dstLevel)
|
||||||
|
{
|
||||||
|
int srcDepth = srcInfo.GetDepthOrLayers();
|
||||||
|
int srcLevels = srcInfo.Levels;
|
||||||
|
|
||||||
|
int dstDepth = dstInfo.GetDepthOrLayers();
|
||||||
|
int dstLevels = dstInfo.Levels;
|
||||||
|
|
||||||
|
if (dstInfo.Target == Target.Texture3D)
|
||||||
|
{
|
||||||
|
dstDepth = Math.Max(1, dstDepth >> dstLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
int depth = Math.Min(srcDepth, dstDepth);
|
||||||
|
int levels = Math.Min(srcLevels, dstLevels);
|
||||||
|
|
||||||
|
Copy(
|
||||||
|
cbs,
|
||||||
|
srcImage,
|
||||||
|
dstImage,
|
||||||
|
srcInfo,
|
||||||
|
dstInfo,
|
||||||
|
srcViewLayer,
|
||||||
|
dstViewLayer,
|
||||||
|
srcViewLevel,
|
||||||
|
dstViewLevel,
|
||||||
|
srcLayer,
|
||||||
|
dstLayer,
|
||||||
|
srcLevel,
|
||||||
|
dstLevel,
|
||||||
|
depth,
|
||||||
|
levels);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Copy(
|
||||||
|
CommandBufferScoped cbs,
|
||||||
|
MTLTexture srcImage,
|
||||||
|
MTLTexture dstImage,
|
||||||
|
TextureCreateInfo srcInfo,
|
||||||
|
TextureCreateInfo dstInfo,
|
||||||
|
int srcViewLayer,
|
||||||
|
int dstViewLayer,
|
||||||
|
int srcViewLevel,
|
||||||
|
int dstViewLevel,
|
||||||
|
int srcDepthOrLayer,
|
||||||
|
int dstDepthOrLayer,
|
||||||
|
int srcLevel,
|
||||||
|
int dstLevel,
|
||||||
|
int depthOrLayers,
|
||||||
|
int levels)
|
||||||
|
{
|
||||||
|
MTLBlitCommandEncoder blitCommandEncoder = cbs.Encoders.EnsureBlitEncoder();
|
||||||
|
|
||||||
|
int srcZ;
|
||||||
|
int srcLayer;
|
||||||
|
int srcDepth;
|
||||||
|
int srcLayers;
|
||||||
|
|
||||||
|
if (srcInfo.Target == Target.Texture3D)
|
||||||
|
{
|
||||||
|
srcZ = srcDepthOrLayer;
|
||||||
|
srcLayer = 0;
|
||||||
|
srcDepth = depthOrLayers;
|
||||||
|
srcLayers = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
srcZ = 0;
|
||||||
|
srcLayer = srcDepthOrLayer;
|
||||||
|
srcDepth = 1;
|
||||||
|
srcLayers = depthOrLayers;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dstZ;
|
||||||
|
int dstLayer;
|
||||||
|
int dstLayers;
|
||||||
|
|
||||||
|
if (dstInfo.Target == Target.Texture3D)
|
||||||
|
{
|
||||||
|
dstZ = dstDepthOrLayer;
|
||||||
|
dstLayer = 0;
|
||||||
|
dstLayers = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dstZ = 0;
|
||||||
|
dstLayer = dstDepthOrLayer;
|
||||||
|
dstLayers = depthOrLayers;
|
||||||
|
}
|
||||||
|
|
||||||
|
int srcWidth = srcInfo.Width;
|
||||||
|
int srcHeight = srcInfo.Height;
|
||||||
|
|
||||||
|
int dstWidth = dstInfo.Width;
|
||||||
|
int dstHeight = dstInfo.Height;
|
||||||
|
|
||||||
|
srcWidth = Math.Max(1, srcWidth >> srcLevel);
|
||||||
|
srcHeight = Math.Max(1, srcHeight >> srcLevel);
|
||||||
|
|
||||||
|
dstWidth = Math.Max(1, dstWidth >> dstLevel);
|
||||||
|
dstHeight = Math.Max(1, dstHeight >> dstLevel);
|
||||||
|
|
||||||
|
int blockWidth = 1;
|
||||||
|
int blockHeight = 1;
|
||||||
|
bool sizeInBlocks = false;
|
||||||
|
|
||||||
|
// When copying from a compressed to a non-compressed format,
|
||||||
|
// the non-compressed texture will have the size of the texture
|
||||||
|
// in blocks (not in texels), so we must adjust that size to
|
||||||
|
// match the size in texels of the compressed texture.
|
||||||
|
if (!srcInfo.IsCompressed && dstInfo.IsCompressed)
|
||||||
|
{
|
||||||
|
srcWidth *= dstInfo.BlockWidth;
|
||||||
|
srcHeight *= dstInfo.BlockHeight;
|
||||||
|
blockWidth = dstInfo.BlockWidth;
|
||||||
|
blockHeight = dstInfo.BlockHeight;
|
||||||
|
|
||||||
|
sizeInBlocks = true;
|
||||||
|
}
|
||||||
|
else if (srcInfo.IsCompressed && !dstInfo.IsCompressed)
|
||||||
|
{
|
||||||
|
dstWidth *= srcInfo.BlockWidth;
|
||||||
|
dstHeight *= srcInfo.BlockHeight;
|
||||||
|
blockWidth = srcInfo.BlockWidth;
|
||||||
|
blockHeight = srcInfo.BlockHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
int width = Math.Min(srcWidth, dstWidth);
|
||||||
|
int height = Math.Min(srcHeight, dstHeight);
|
||||||
|
|
||||||
|
for (int level = 0; level < levels; level++)
|
||||||
|
{
|
||||||
|
// Stop copy if we are already out of the levels range.
|
||||||
|
if (level >= srcInfo.Levels || dstLevel + level >= dstInfo.Levels)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
int copyWidth = sizeInBlocks ? BitUtils.DivRoundUp(width, blockWidth) : width;
|
||||||
|
int copyHeight = sizeInBlocks ? BitUtils.DivRoundUp(height, blockHeight) : height;
|
||||||
|
|
||||||
|
int layers = Math.Max(dstLayers - dstLayer, srcLayers);
|
||||||
|
|
||||||
|
for (int layer = 0; layer < layers; layer++)
|
||||||
|
{
|
||||||
|
if (srcInfo.Samples > 1 && srcInfo.Samples != dstInfo.Samples)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
Logger.Warning?.PrintMsg(LogClass.Gpu, "Unsupported mismatching sample count copy");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
blitCommandEncoder.CopyFromTexture(
|
||||||
|
srcImage,
|
||||||
|
(ulong)(srcViewLevel + srcLevel + level),
|
||||||
|
(ulong)(srcViewLayer + srcLayer + layer),
|
||||||
|
new MTLOrigin { z = (ulong)srcZ },
|
||||||
|
new MTLSize { width = (ulong)copyWidth, height = (ulong)copyHeight, depth = (ulong)srcDepth },
|
||||||
|
dstImage,
|
||||||
|
(ulong)(dstViewLevel + dstLevel + level),
|
||||||
|
(ulong)(dstViewLayer + dstLayer + layer),
|
||||||
|
new MTLOrigin { z = (ulong)dstZ });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
width = Math.Max(1, width >> 1);
|
||||||
|
height = Math.Max(1, height >> 1);
|
||||||
|
|
||||||
|
if (srcInfo.Target == Target.Texture3D)
|
||||||
|
{
|
||||||
|
srcDepth = Math.Max(1, srcDepth >> 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue