Improve performance when converting texture formats.

Still more work to do.
This commit is contained in:
riperiperi 2020-05-17 12:41:45 +01:00
parent 6416bc1938
commit fc2d5086e7
3 changed files with 231 additions and 49 deletions

View file

@ -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>

View file

@ -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);
}
} }
} }

View file

@ -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;
} }