[GPU] Use Gen5 render-target tile equations on the CPU and GPU
Co-authored-by: Sekai <140012992+SekaixX@users.noreply.github.com>
This commit is contained in:
parent
7b30868b03
commit
1984901a31
|
|
@ -63,7 +63,7 @@ public struct TileTransferArguments
|
|||
// Runs the tiling, detiling, depth conversion and channel swap compute passes.
|
||||
public sealed unsafe class GpuTiler : IDisposable
|
||||
{
|
||||
private const uint KindCount = 9;
|
||||
private const uint KindCount = 10;
|
||||
private const uint ElementSizeCount = 5;
|
||||
private const uint DirectionCount = 2;
|
||||
private const uint PipelineCount = KindCount * ElementSizeCount * DirectionCount;
|
||||
|
|
|
|||
|
|
@ -452,7 +452,9 @@ public sealed class TextureTransferLayout
|
|||
transfer.Width = Math.Max((region.ImageExtent.Width + texture.TexelWidth - 1) / texture.TexelWidth, 1);
|
||||
transfer.Height = Math.Max((logicalHeight + texture.TexelHeight - 1) / texture.TexelHeight, 1);
|
||||
transfer.Depth = 1;
|
||||
transfer.SurfaceZ = block.Kind is TileBlockKind.RenderTarget64KB or TileBlockKind.Depth64KB ? region.ImageSubresource.BaseArrayLayer : 0;
|
||||
transfer.SurfaceZ = block.Kind is TileBlockKind.RenderTarget64KB or TileBlockKind.RenderTarget64KBGen5 or TileBlockKind.Depth64KB
|
||||
? region.ImageSubresource.BaseArrayLayer
|
||||
: 0;
|
||||
transfer.Pitch = Math.Max((pitch + texture.TexelWidth - 1) / texture.TexelWidth, 1);
|
||||
transfer.Tail = tail;
|
||||
transfer.TailX = tail ? mip.TailX : 0;
|
||||
|
|
|
|||
|
|
@ -230,6 +230,75 @@ public static partial class TileGeometry
|
|||
}
|
||||
}
|
||||
|
||||
private static uint Gen5RenderTargetOffset(uint x, uint y, uint bytesPerElement)
|
||||
{
|
||||
uint offset = 0;
|
||||
switch (bytesPerElement)
|
||||
{
|
||||
case 1:
|
||||
offset ^= (y << 2) & 0x0008;
|
||||
offset ^= (y << 4) & 0x0010;
|
||||
offset ^= (y << 3) & 0x00a0;
|
||||
offset ^= (y << 5) & 0x0f00;
|
||||
offset ^= (y << 6) & 0x1000;
|
||||
offset ^= (y << 7) & 0x4000;
|
||||
offset ^= x & 0x0007;
|
||||
offset ^= (x << 3) & 0x0040;
|
||||
offset ^= (x << 5) & 0x0300;
|
||||
offset ^= (x << 4) & 0x0400;
|
||||
offset ^= (x << 6) & 0x0800;
|
||||
offset ^= (x << 7) & 0x2000;
|
||||
offset ^= (x << 8) & 0x8000;
|
||||
return offset;
|
||||
case 2:
|
||||
offset ^= (y << 4) & 0x0070;
|
||||
offset ^= (y << 5) & 0x0f00;
|
||||
offset ^= (y << 8) & 0x5000;
|
||||
offset ^= (x << 1) & 0x000e;
|
||||
offset ^= (x << 4) & 0x0480;
|
||||
offset ^= (x << 5) & 0x0300;
|
||||
offset ^= (x << 6) & 0x0800;
|
||||
offset ^= (x << 7) & 0x2000;
|
||||
offset ^= (x << 8) & 0x8000;
|
||||
return offset;
|
||||
case 4:
|
||||
offset ^= (y << 4) & 0x0070;
|
||||
offset ^= (y << 5) & 0x0f00;
|
||||
offset ^= (y << 9) & 0x1000;
|
||||
offset ^= (y << 8) & 0x4000;
|
||||
offset ^= (x << 2) & 0x000c;
|
||||
offset ^= (x << 5) & 0x0380;
|
||||
offset ^= (x << 4) & 0x0400;
|
||||
offset ^= (x << 6) & 0x0800;
|
||||
offset ^= (x << 9) & 0xa000;
|
||||
return offset;
|
||||
case 8:
|
||||
offset ^= (y << 4) & 0x0010;
|
||||
offset ^= (y << 6) & 0x0080;
|
||||
offset ^= (y << 5) & 0x0f00;
|
||||
offset ^= (y << 10) & 0x5000;
|
||||
offset ^= (x << 3) & 0x0008;
|
||||
offset ^= (x << 4) & 0x0460;
|
||||
offset ^= (x << 5) & 0x0300;
|
||||
offset ^= (x << 6) & 0x0800;
|
||||
offset ^= (x << 10) & 0x2000;
|
||||
offset ^= (x << 9) & 0x8000;
|
||||
return offset;
|
||||
case 16:
|
||||
offset ^= (x << 4) & 0x0410;
|
||||
offset ^= (x << 5) & 0x0340;
|
||||
offset ^= (x << 6) & 0x0800;
|
||||
offset ^= (x << 11) & 0xa000;
|
||||
offset ^= (y << 5) & 0x0f20;
|
||||
offset ^= (y << 6) & 0x0080;
|
||||
offset ^= (y << 10) & 0x1000;
|
||||
offset ^= (y << 11) & 0x4000;
|
||||
return offset;
|
||||
default:
|
||||
throw SubmissionScheduler.Fatal($"The Gen5 render-target tile block does not support this element size: bytes={bytesPerElement}.");
|
||||
}
|
||||
}
|
||||
|
||||
private static uint Depth64KB8X(uint x) =>
|
||||
(x & 0x0001) ^ ((x << 1) & 0x0004) ^ ((x << 2) & 0x0010) ^ ((x << 3) & 0x0040) ^ ((x << 5) & 0x0300) ^
|
||||
((x << 4) & 0x0400) ^ ((x << 6) & 0x0800) ^ ((x << 7) & 0x2000) ^ ((x << 8) & 0x8000);
|
||||
|
|
@ -319,6 +388,14 @@ public static partial class TileGeometry
|
|||
|
||||
offset = RenderTargetOffset(x, y, bytes);
|
||||
break;
|
||||
case TileBlockKind.RenderTarget64KBGen5:
|
||||
if (bytes > 16)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
offset = Gen5RenderTargetOffset(x, y, bytes);
|
||||
break;
|
||||
case TileBlockKind.Depth64KB:
|
||||
switch (bytes)
|
||||
{
|
||||
|
|
@ -364,17 +441,19 @@ public static partial class TileGeometry
|
|||
|
||||
byteOffset = Depth64KB64X(blockX * layout.BlockWidth) ^ Depth64KB64Y(blockY * layout.BlockHeight);
|
||||
}
|
||||
else if (layout.Kind == TileBlockKind.RenderTarget64KB)
|
||||
else if (layout.Kind is TileBlockKind.RenderTarget64KB or TileBlockKind.RenderTarget64KBGen5)
|
||||
{
|
||||
if (blockX > uint.MaxValue / layout.BlockWidth || blockY > uint.MaxValue / layout.BlockHeight || layout.BytesPerElement > 16)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
byteOffset = RenderTargetOffset(blockX * layout.BlockWidth, blockY * layout.BlockHeight, layout.BytesPerElement);
|
||||
byteOffset = layout.Kind == TileBlockKind.RenderTarget64KBGen5
|
||||
? Gen5RenderTargetOffset(blockX * layout.BlockWidth, blockY * layout.BlockHeight, layout.BytesPerElement)
|
||||
: RenderTargetOffset(blockX * layout.BlockWidth, blockY * layout.BlockHeight, layout.BytesPerElement);
|
||||
}
|
||||
|
||||
if (layout.Kind is TileBlockKind.RenderTarget64KB or TileBlockKind.Depth64KB)
|
||||
if (layout.Kind is TileBlockKind.RenderTarget64KB or TileBlockKind.RenderTarget64KBGen5 or TileBlockKind.Depth64KB)
|
||||
{
|
||||
byteOffset ^= ((blockZ & 8) << 5) ^ ((blockZ & 4) << 7) ^ ((blockZ & 2) << 9) ^ ((blockZ & 1) << 11);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ public enum TileBlockKind : uint
|
|||
Prt64KB3D,
|
||||
RenderTarget64KB,
|
||||
Depth64KB,
|
||||
RenderTarget64KBGen5,
|
||||
}
|
||||
|
||||
public readonly record struct TileBlockLayout(TileBlockKind Kind, uint BytesPerElement, uint BlockSize, uint BlockWidth, uint BlockHeight, uint BlockDepth)
|
||||
|
|
@ -109,6 +110,7 @@ public static partial class TileGeometry
|
|||
new(65536, Thick64KB, 16),
|
||||
new(65536, Thin64KB, 16),
|
||||
new(65536, Thin64KB, 8),
|
||||
new(65536, Thin64KB, 16),
|
||||
];
|
||||
|
||||
private static readonly Log2BlockDimensions[][] MsaaBlocks =
|
||||
|
|
@ -247,6 +249,7 @@ public static partial class TileGeometry
|
|||
case TileBlockKind.Standard64KB:
|
||||
case TileBlockKind.Prt64KB:
|
||||
case TileBlockKind.RenderTarget64KB:
|
||||
case TileBlockKind.RenderTarget64KBGen5:
|
||||
rule = new MipTailRule(TailThin64KB[index], block.BlockWidth >> 1, block.BlockHeight);
|
||||
return true;
|
||||
default:
|
||||
|
|
@ -297,7 +300,7 @@ public static partial class TileGeometry
|
|||
kind = TileBlockKind.Depth64KB;
|
||||
break;
|
||||
case GuestTileMode.RenderTarget:
|
||||
kind = TileBlockKind.RenderTarget64KB;
|
||||
kind = TileBlockKind.RenderTarget64KBGen5;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
|
|
@ -308,7 +311,7 @@ public static partial class TileGeometry
|
|||
return false;
|
||||
}
|
||||
|
||||
if (kind is TileBlockKind.Depth64KB or TileBlockKind.RenderTarget64KB &&
|
||||
if (kind is TileBlockKind.Depth64KB or TileBlockKind.RenderTarget64KB or TileBlockKind.RenderTarget64KBGen5 &&
|
||||
GuestPixelFormats.RenderTargetBytesPerElement(format) != element.Bytes)
|
||||
{
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ public enum TilerBlockShape
|
|||
Prt64KB3D,
|
||||
RenderTarget64KB,
|
||||
Depth64KB,
|
||||
RenderTarget64KBGen5,
|
||||
}
|
||||
|
||||
// Assembles the tiler compute shaders: block copies per shape and element size,
|
||||
|
|
@ -251,6 +252,15 @@ public static class TilerShaders
|
|||
return offset;
|
||||
}
|
||||
|
||||
private static Term[] Gen5RenderTargetTerms(uint bytes) => bytes switch
|
||||
{
|
||||
1 => [Y(2, 0x008), Y(4, 0x010), Y(3, 0x0a0), Y(5, 0xf00), Y(6, 0x1000), Y(7, 0x4000), X(0, 0x007), X(3, 0x040), X(5, 0x300), X(4, 0x400), X(6, 0x800), X(7, 0x2000), X(8, 0x8000)],
|
||||
2 => [Y(4, 0x070), Y(5, 0xf00), Y(8, 0x5000), X(1, 0x00e), X(4, 0x480), X(5, 0x300), X(6, 0x800), X(7, 0x2000), X(8, 0x8000)],
|
||||
4 => [Y(4, 0x070), Y(5, 0xf00), Y(9, 0x1000), Y(8, 0x4000), X(2, 0x00c), X(5, 0x380), X(4, 0x400), X(6, 0x800), X(9, 0xa000)],
|
||||
8 => [Y(4, 0x010), Y(6, 0x080), Y(5, 0xf00), Y(10, 0x5000), X(3, 0x008), X(4, 0x460), X(5, 0x300), X(6, 0x800), X(10, 0x2000), X(9, 0x8000)],
|
||||
_ => [X(4, 0x410), X(5, 0x340), X(6, 0x800), X(11, 0xa000), Y(5, 0xf20), Y(6, 0x080), Y(10, 0x1000), Y(11, 0x4000)],
|
||||
};
|
||||
|
||||
private static Term[] DepthTerms(uint bytes) => bytes switch
|
||||
{
|
||||
1 => [X(0, 1), X(1, 0x004), X(2, 0x010), X(3, 0x040), X(5, 0x300), X(4, 0x400), X(6, 0x800), X(7, 0x2000), X(8, 0x8000), Y(1, 0x002), Y(2, 0x008), Y(3, 0x0a0), Y(5, 0xf00), Y(6, 0x1000), Y(7, 0x4000)],
|
||||
|
|
@ -314,7 +324,7 @@ public static class TilerShaders
|
|||
TilerBlockShape.Standard256B => (ThinExtent(256, bytes, 16, 8, 4), 256),
|
||||
TilerBlockShape.Standard4KB => (ThinExtent(4096, bytes, 64, 32, 16), 4096),
|
||||
TilerBlockShape.Standard4KB3D => (Thick4KBExtent(bytes), 4096),
|
||||
TilerBlockShape.Standard64KB or TilerBlockShape.Prt64KB or TilerBlockShape.RenderTarget64KB => (ThinExtent(65536, bytes, 256, 128, 64), 65536),
|
||||
TilerBlockShape.Standard64KB or TilerBlockShape.Prt64KB or TilerBlockShape.RenderTarget64KB or TilerBlockShape.RenderTarget64KBGen5 => (ThinExtent(65536, bytes, 256, 128, 64), 65536),
|
||||
TilerBlockShape.Standard64KB3D or TilerBlockShape.Prt64KB3D => (Thick64KBExtent(bytes), 65536),
|
||||
TilerBlockShape.Depth64KB => (ThinExtent(65536, bytes, 256, 128, 128), 65536),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(shape)),
|
||||
|
|
@ -348,6 +358,8 @@ public static class TilerShaders
|
|||
}
|
||||
case TilerBlockShape.RenderTarget64KB:
|
||||
return shaderModule.Xor(RenderTargetOffset(shaderModule, x, y, bytes), ZSpread(shaderModule, z));
|
||||
case TilerBlockShape.RenderTarget64KBGen5:
|
||||
return shaderModule.Xor(XorTerms(shaderModule, x, y, z, Gen5RenderTargetTerms(bytes)), ZSpread(shaderModule, z));
|
||||
case TilerBlockShape.Depth64KB:
|
||||
return shaderModule.Xor(ZSpread(shaderModule, z), XorTerms(shaderModule, x, y, z, DepthTerms(bytes)));
|
||||
default:
|
||||
|
|
|
|||
Loading…
Reference in New Issue