mirror of
https://github.com/Ryujinx/Ryujinx.git
synced 2025-01-08 19:45:13 +00:00
Improve performance when converting texture formats.
Still more work to do.
This commit is contained in:
parent
6416bc1938
commit
fc2d5086e7
|
@ -84,6 +84,8 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
|
|
||||||
private int _sequenceNumber;
|
private int _sequenceNumber;
|
||||||
|
|
||||||
|
private bool _noSync;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Constructs a new instance of the cached GPU texture.
|
/// Constructs a new instance of the cached GPU texture.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -301,7 +303,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
{
|
{
|
||||||
// Texture buffers are not handled here, instead they are invalidated (if modified)
|
// Texture buffers are not handled here, instead they are invalidated (if modified)
|
||||||
// when the texture is bound. This is handled by the buffer manager.
|
// when the texture is bound. This is handled by the buffer manager.
|
||||||
if ((_sequenceNumber == _context.SequenceNumber && _hasData) || Info.Target == Target.TextureBuffer)
|
if ((_sequenceNumber == _context.SequenceNumber && _hasData) || _noSync)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -999,6 +1001,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
|
|
||||||
_depth = info.GetDepth();
|
_depth = info.GetDepth();
|
||||||
_layers = info.GetLayers();
|
_layers = info.GetLayers();
|
||||||
|
_noSync = Info.Target == Target.TextureBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -33,6 +33,10 @@ namespace Ryujinx.Graphics.Texture
|
||||||
private int _robSize;
|
private int _robSize;
|
||||||
private int _sliceSize;
|
private int _sliceSize;
|
||||||
|
|
||||||
|
// Variables for built in iteration.
|
||||||
|
private int _yPart;
|
||||||
|
private int _zPart;
|
||||||
|
|
||||||
public BlockLinearLayout(
|
public BlockLinearLayout(
|
||||||
int width,
|
int width,
|
||||||
int height,
|
int height,
|
||||||
|
@ -97,5 +101,50 @@ namespace Ryujinx.Graphics.Texture
|
||||||
|
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Functions for built in iteration.
|
||||||
|
// Components of the offset can be updated separately, and combined to save some time.
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public void SetY(int y)
|
||||||
|
{
|
||||||
|
int yh = y / GobHeight;
|
||||||
|
int offset = (yh >> _bhShift) * _robSize;
|
||||||
|
|
||||||
|
offset += (yh & _bhMask) * GobSize;
|
||||||
|
|
||||||
|
offset += ((y & 0x07) >> 1) << 6;
|
||||||
|
offset += ((y & 0x01) >> 0) << 4;
|
||||||
|
|
||||||
|
_yPart = offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public void SetZ(int z)
|
||||||
|
{
|
||||||
|
int offset = (z >> _bdShift) * _sliceSize;
|
||||||
|
|
||||||
|
offset += ((z & _bdMask) * GobSize) << _bhShift;
|
||||||
|
|
||||||
|
_zPart = offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public int GetOffsetWithLineOffset(int x)
|
||||||
|
{
|
||||||
|
int offset = (x / GobStride) << _xShift;
|
||||||
|
|
||||||
|
offset += ((x & 0x3f) >> 5) << 8;
|
||||||
|
offset += ((x & 0x1f) >> 4) << 5;
|
||||||
|
offset += (x & 0x0f);
|
||||||
|
|
||||||
|
return offset + _yPart + _zPart;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public int GetOffset(int x)
|
||||||
|
{
|
||||||
|
return GetOffsetWithLineOffset(x << _bppShift);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,12 +1,20 @@
|
||||||
using Ryujinx.Common;
|
using Ryujinx.Common;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Runtime.Intrinsics;
|
||||||
using static Ryujinx.Graphics.Texture.BlockLinearConstants;
|
using static Ryujinx.Graphics.Texture.BlockLinearConstants;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Texture
|
namespace Ryujinx.Graphics.Texture
|
||||||
{
|
{
|
||||||
public static class LayoutConverter
|
public static class LayoutConverter
|
||||||
{
|
{
|
||||||
|
[StructLayout(LayoutKind.Sequential, Pack = 1, Size = 12)]
|
||||||
|
private struct Bpp12Pixel
|
||||||
|
{
|
||||||
|
private ulong _elem1;
|
||||||
|
private uint _elem2;
|
||||||
|
}
|
||||||
|
|
||||||
private const int HostStrideAlignment = 4;
|
private const int HostStrideAlignment = 4;
|
||||||
|
|
||||||
public static Span<byte> ConvertBlockLinearToLinear(
|
public static Span<byte> ConvertBlockLinearToLinear(
|
||||||
|
@ -86,36 +94,66 @@ namespace Ryujinx.Graphics.Texture
|
||||||
mipGobBlocksInZ,
|
mipGobBlocksInZ,
|
||||||
bytesPerPixel);
|
bytesPerPixel);
|
||||||
|
|
||||||
|
unsafe void Convert<T>(Span<byte> output, ReadOnlySpan<byte> data) where T : unmanaged
|
||||||
|
{
|
||||||
|
fixed (byte* outputBPtr = output, dataBPtr = data)
|
||||||
|
{
|
||||||
for (int layer = 0; layer < layers; layer++)
|
for (int layer = 0; layer < layers; layer++)
|
||||||
{
|
{
|
||||||
int inBaseOffset = layer * sizeInfo.LayerSize + sizeInfo.GetMipOffset(level);
|
int inBaseOffset = layer * sizeInfo.LayerSize + sizeInfo.GetMipOffset(level);
|
||||||
|
|
||||||
for (int z = 0; z < d; z++)
|
for (int z = 0; z < d; z++)
|
||||||
|
{
|
||||||
|
layoutConverter.SetZ(z);
|
||||||
for (int y = 0; y < h; y++)
|
for (int y = 0; y < h; y++)
|
||||||
{
|
{
|
||||||
|
layoutConverter.SetY(y);
|
||||||
for (int x = 0; x < strideTrunc; x += 16)
|
for (int x = 0; x < strideTrunc; x += 16)
|
||||||
{
|
{
|
||||||
int offset = inBaseOffset + layoutConverter.GetOffsetWithLineOffset(x, y, z);
|
int offset = inBaseOffset + layoutConverter.GetOffsetWithLineOffset(x);
|
||||||
|
|
||||||
Span<byte> dest = output.Slice(outOffs + x, 16);
|
*(Vector128<byte>*)(outputBPtr + outOffs + x) = *(Vector128<byte>*)(dataBPtr + offset);
|
||||||
|
|
||||||
data.Slice(offset, 16).CopyTo(dest);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int x = xStart; x < w; x++)
|
for (int x = xStart; x < w; x++)
|
||||||
{
|
{
|
||||||
int offset = inBaseOffset + layoutConverter.GetOffset(x, y, z);
|
int offset = inBaseOffset + layoutConverter.GetOffset(x);
|
||||||
|
|
||||||
Span<byte> dest = output.Slice(outOffs + x * bytesPerPixel, bytesPerPixel);
|
((T*)(outputBPtr + outOffs))[x] = *(T*)(dataBPtr + offset);
|
||||||
|
|
||||||
data.Slice(offset, bytesPerPixel).CopyTo(dest);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
outOffs += stride;
|
outOffs += stride;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (bytesPerPixel)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
Convert<byte>(output, data);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
Convert<ushort>(output, data);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
Convert<uint>(output, data);
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
Convert<ulong>(output, data);
|
||||||
|
break;
|
||||||
|
case 12:
|
||||||
|
Convert<Bpp12Pixel>(output, data);
|
||||||
|
break;
|
||||||
|
case 16:
|
||||||
|
Convert<Vector128<byte>>(output, data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new NotSupportedException($"Unable to convert ${bytesPerPixel} bpp pixel format.");
|
||||||
|
}
|
||||||
|
}
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,19 +175,48 @@ namespace Ryujinx.Graphics.Texture
|
||||||
|
|
||||||
int outOffs = 0;
|
int outOffs = 0;
|
||||||
|
|
||||||
|
unsafe void Convert<T>(Span<byte> output, ReadOnlySpan<byte> data) where T : unmanaged
|
||||||
|
{
|
||||||
|
fixed (byte* outputBPtr = output, dataBPtr = data)
|
||||||
|
{
|
||||||
for (int y = 0; y < h; y++)
|
for (int y = 0; y < h; y++)
|
||||||
{
|
{
|
||||||
for (int x = 0; x < w; x++)
|
for (int x = 0; x < w; x++)
|
||||||
{
|
{
|
||||||
int offset = y * stride + x * bytesPerPixel;
|
int offset = y * stride + x * bytesPerPixel;
|
||||||
|
|
||||||
Span<byte> dest = output.Slice(outOffs + x * bytesPerPixel, bytesPerPixel);
|
((T*)(outputBPtr + outOffs))[x] = *(T*)(dataBPtr + offset);
|
||||||
|
|
||||||
data.Slice(offset, bytesPerPixel).CopyTo(dest);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
outOffs += outStride;
|
outOffs += outStride;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (bytesPerPixel)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
Convert<byte>(output, data);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
Convert<ushort>(output, data);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
Convert<uint>(output, data);
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
Convert<ulong>(output, data);
|
||||||
|
break;
|
||||||
|
case 12:
|
||||||
|
Convert<Bpp12Pixel>(output, data);
|
||||||
|
break;
|
||||||
|
case 16:
|
||||||
|
Convert<Vector128<byte>>(output, data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new NotSupportedException($"Unable to convert ${bytesPerPixel} bpp pixel format.");
|
||||||
|
}
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
@ -217,26 +284,60 @@ namespace Ryujinx.Graphics.Texture
|
||||||
mipGobBlocksInZ,
|
mipGobBlocksInZ,
|
||||||
bytesPerPixel);
|
bytesPerPixel);
|
||||||
|
|
||||||
|
unsafe void Convert<T>(Span<byte> output, ReadOnlySpan<byte> data) where T : unmanaged
|
||||||
|
{
|
||||||
|
fixed (byte* outputBPtr = output, dataBPtr = data)
|
||||||
|
{
|
||||||
|
T* outputPtr = (T*)outputBPtr, dataPtr = (T*)dataBPtr;
|
||||||
for (int layer = 0; layer < layers; layer++)
|
for (int layer = 0; layer < layers; layer++)
|
||||||
{
|
{
|
||||||
int outBaseOffset = layer * sizeInfo.LayerSize + sizeInfo.GetMipOffset(level);
|
int outBaseOffset = layer * sizeInfo.LayerSize + sizeInfo.GetMipOffset(level);
|
||||||
|
|
||||||
for (int z = 0; z < d; z++)
|
for (int z = 0; z < d; z++)
|
||||||
|
{
|
||||||
|
layoutConverter.SetZ(z);
|
||||||
for (int y = 0; y < h; y++)
|
for (int y = 0; y < h; y++)
|
||||||
{
|
{
|
||||||
|
layoutConverter.SetY(y);
|
||||||
for (int x = 0; x < w; x++)
|
for (int x = 0; x < w; x++)
|
||||||
{
|
{
|
||||||
int offset = outBaseOffset + layoutConverter.GetOffset(x, y, z);
|
int offset = outBaseOffset + layoutConverter.GetOffset(x);
|
||||||
|
|
||||||
Span<byte> dest = output.Slice(offset, bytesPerPixel);
|
*(T*)(outputBPtr + offset) = ((T*)(dataBPtr + inOffs))[x];
|
||||||
|
|
||||||
data.Slice(inOffs + x * bytesPerPixel, bytesPerPixel).CopyTo(dest);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inOffs += stride;
|
inOffs += stride;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (bytesPerPixel)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
Convert<byte>(output, data);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
Convert<ushort>(output, data);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
Convert<uint>(output, data);
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
Convert<ulong>(output, data);
|
||||||
|
break;
|
||||||
|
case 12:
|
||||||
|
Convert<Bpp12Pixel>(output, data);
|
||||||
|
break;
|
||||||
|
case 16:
|
||||||
|
Convert<Vector128<byte>>(output, data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new NotSupportedException($"Unable to convert ${bytesPerPixel} bpp pixel format.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
@ -259,19 +360,48 @@ namespace Ryujinx.Graphics.Texture
|
||||||
|
|
||||||
int inOffs = 0;
|
int inOffs = 0;
|
||||||
|
|
||||||
|
unsafe void Convert<T>(Span<byte> output, ReadOnlySpan<byte> data) where T : unmanaged
|
||||||
|
{
|
||||||
|
fixed (byte* outputBPtr = output, dataBPtr = data)
|
||||||
|
{
|
||||||
for (int y = 0; y < h; y++)
|
for (int y = 0; y < h; y++)
|
||||||
{
|
{
|
||||||
for (int x = 0; x < w; x++)
|
for (int x = 0; x < w; x++)
|
||||||
{
|
{
|
||||||
int offset = y * stride + x * bytesPerPixel;
|
int offset = y * stride + x * bytesPerPixel;
|
||||||
|
|
||||||
Span<byte> dest = output.Slice(offset, bytesPerPixel);
|
*(T*)(outputBPtr + offset) = ((T*)(dataBPtr + inOffs))[x];
|
||||||
|
|
||||||
data.Slice(inOffs + x * bytesPerPixel, bytesPerPixel).CopyTo(dest);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inOffs += inStride;
|
inOffs += inStride;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (bytesPerPixel)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
Convert<byte>(output, data);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
Convert<ushort>(output, data);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
Convert<uint>(output, data);
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
Convert<ulong>(output, data);
|
||||||
|
break;
|
||||||
|
case 12:
|
||||||
|
Convert<Bpp12Pixel>(output, data);
|
||||||
|
break;
|
||||||
|
case 16:
|
||||||
|
Convert<Vector128<byte>>(output, data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new NotSupportedException($"Unable to convert ${bytesPerPixel} bpp pixel format.");
|
||||||
|
}
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue