diff --git a/tests/SharpEmu.Libs.Tests/Gpu/Images/GpuTilerTests.cs b/tests/SharpEmu.Libs.Tests/Gpu/Images/GpuTilerTests.cs index 4be8149..56e1b96 100644 --- a/tests/SharpEmu.Libs.Tests/Gpu/Images/GpuTilerTests.cs +++ b/tests/SharpEmu.Libs.Tests/Gpu/Images/GpuTilerTests.cs @@ -78,7 +78,7 @@ internal static class TilerCases transfer.Tail = true; break; case Shape.Layered: - if (kind is not (TileBlockKind.RenderTarget64KB or TileBlockKind.Depth64KB)) + if (kind is not (TileBlockKind.RenderTarget64KB or TileBlockKind.Depth64KB or TileBlockKind.RenderTarget64KBGen5)) { return null; } @@ -203,7 +203,7 @@ public sealed class GpuTilerTests : IClassFixture public void CpuTwinCases_CoverEveryKindAndElementSize() { var cases = TilerCases.All().ToList(); - Assert.Equal(44 + 39 + 9, cases.Count); + Assert.Equal((44 + 39 + 9) + 15, cases.Count); Assert.All(cases, tilerCase => Assert.True(tilerCase.Transfer.SurfaceZ != 0 || tilerCase.Tiled.Length == (int)tilerCase.Transfer.TiledSize)); } diff --git a/tests/SharpEmu.Libs.Tests/Gpu/Images/GuestImageCacheTests.Metadata.cs b/tests/SharpEmu.Libs.Tests/Gpu/Images/GuestImageCacheTests.Metadata.cs index b0438dc..2eb5a41 100644 --- a/tests/SharpEmu.Libs.Tests/Gpu/Images/GuestImageCacheTests.Metadata.cs +++ b/tests/SharpEmu.Libs.Tests/Gpu/Images/GuestImageCacheTests.Metadata.cs @@ -100,31 +100,31 @@ public sealed partial class GuestImageCacheTests } [Fact] - public void DccFills_AreAbsorbedOnlyByRegisteredDcc() + public void DccFills_RemainGuestProducersUntilDescriptorDiscovery() { if (!GatePrerequisites.Ready(_vulkan)) return; - using var fatal = new FatalScope(); using var harness = new CacheHarness(_vulkan); var address = harness.MapBacked(0x20000, ReadWrite); var metadata = address + 0x10000; - Assert.False(harness.Images.TryAbsorbDccFill(metadata, 0x100, 0x20202020u)); + harness.Write(metadata, Bytes(0x11223344u)); + Assert.False(harness.Images.TryAbsorbDccFill(metadata, 0x1000, 0x20202020u)); Assert.False(harness.Images.IsMetadata(metadata)); - Assert.False(harness.Images.TryAbsorbDccFill(metadata, 0x100, 0x40404040u)); + Assert.False(harness.Images.TryAbsorbDccFill(metadata, 0x1000, 0x40404040u)); harness.Write(address + 0xc000, Bytes(0x55667788u)); var target = LinearRequest(address + 0xc000, 4, Format.R8G8B8A8Srgb, GuestPixelFormat.Bits8_8_8_8Srgb, GuestImageType.Color2D, new Extent3D(1, 1, 1), 1, 4, 1); target = AsColorTarget(target); target.Description.Metadata.Kind = MetadataKind.Dcc; - target.Description.Metadata.Range = new GuestSpan(metadata, 0x100); + target.Description.Metadata.Range = new GuestSpan(metadata, 0x1000); target.Description.Metadata.Compression = DisplayCompression.Dcc256_256_0; var targetId = harness.Acquire(ref target); - Assert.True(harness.Images.IsMetadata(metadata)); - Assert.True(harness.Images.IsMetadataCleared(metadata, 0, out var fill)); - Assert.Equal(0x40404040u, fill); - Assert.True(harness.Images.TryAbsorbDccFill(metadata, 0x100, 0x01010101u)); + Assert.False(harness.Images.IsMetadata(metadata)); Assert.False(harness.Images.IsMetadataCleared(metadata, 0)); - Assert.True(harness.Images.TryAbsorbDccFill(metadata, 0x100, 0xc0c0c0c0u)); - Assert.True(harness.Images.IsMetadataCleared(metadata, 5)); + Assert.Equal(0x11223344u, harness.ReadUInt32(metadata)); + Assert.False(harness.Images.TryAbsorbDccFill(metadata, 0x1000, 0x01010101u)); + Assert.False(harness.Images.TryAbsorbDccFill(metadata, 0x1000, 0xc0c0c0c0u)); + Assert.False(harness.Images.IsMetadataCleared(metadata, 5)); + Assert.Equal(0x11223344u, harness.ReadUInt32(metadata)); Assert.False(harness.Images.ClearMetadata(metadata)); // A compressed target rejects readback and read claims but keeps GPU ownership. @@ -144,15 +144,169 @@ public sealed partial class GuestImageCacheTests Assert.False(videoImage.Binding.NeedsRebind); Assert.False(videoImage.Uses.VideoOut); - // A depth target must not reuse DCC metadata. var depth = LinearRequest(address + 0xe000, 4, Format.D32Sfloat, GuestPixelFormat.Bits32Float, GuestImageType.Color2D, new Extent3D(1, 1, 1), 1, 4, 1); depth = AsDepthTarget(depth, Format.D32Sfloat); depth.Description.Metadata.Kind = MetadataKind.Htile; depth.Description.Metadata.Range = new GuestSpan(metadata, 0x100); var depthId = harness.Find(ref depth); var depthLocal = depth; - harness.Worker.Run(() => Assert.Throws(() => harness.Images.AcquireDepthTargetView(depthId, depthLocal))); - Assert.Contains(fatal.Messages, message => message.Contains("depth target reuses metadata that is not HTile")); + harness.Worker.Run(() => Assert.NotEqual( + 0UL, + harness.Images.AcquireDepthTargetView(depthId, depthLocal).Handle)); + Assert.True(harness.Images.IsMetadata(metadata)); + harness.Shutdown(); + } + + [Fact] + public void DccVolumeOverThirtyTwoSlices_MaterializesAndConsumesEveryUniformSlice() + { + if (!GatePrerequisites.Ready(_vulkan)) return; + using var harness = new CacheHarness(_vulkan); + var address = harness.MapBacked(0x80000, ReadWrite); + var imageAddress = address + 0x1000; + var metadataAddress = address + 0x10000; + const uint depth = 64; + const ulong metadataSliceSize = 0x1000; + var metadataBytes = new byte[checked((int)(depth * metadataSliceSize))]; + Array.Fill(metadataBytes, (byte)0xc0); + harness.Write(metadataAddress, metadataBytes); + + const uint width = 4; + const uint height = 4; + var imageSize = (ulong)width * height * depth * 4; + var target = LinearRequest( + imageAddress, + imageSize, + Format.R8G8B8A8Unorm, + GuestPixelFormat.Bits8_8_8_8UNorm, + GuestImageType.Color3D, + new Extent3D(width, height, depth), + 1, + 4, + 1); + target = AsColorTarget(target); + target.View = target.View with + { + Type = ImageViewType.Type2DArray, + BaseLayer = 0, + LayerCount = depth, + }; + target.Description.Metadata.Kind = MetadataKind.Dcc; + target.Description.Metadata.Range = new GuestSpan(metadataAddress, depth * metadataSliceSize); + target.Description.Metadata.DccAlphaMsb = true; + + Assert.False(harness.Images.TryAbsorbDccFill( + metadataAddress, + depth * metadataSliceSize, + 0xc0c0c0c0u)); + var targetId = harness.Find(ref target); + harness.Finish(); + + Assert.True(targetId.IsValid); + Assert.Equal(uint.MaxValue, harness.ReadUInt32(metadataAddress)); + Assert.Equal(uint.MaxValue, harness.ReadUInt32(metadataAddress + 31 * metadataSliceSize)); + Assert.Equal(uint.MaxValue, harness.ReadUInt32(metadataAddress + 32 * metadataSliceSize)); + Assert.Equal(uint.MaxValue, harness.ReadUInt32(metadataAddress + (depth - 1) * metadataSliceSize)); + Assert.False(harness.Images.IsMetadataCleared(metadataAddress, 0)); + Assert.False(harness.Images.IsMetadataCleared(metadataAddress, 31)); + Assert.False(harness.Images.IsMetadataCleared(metadataAddress, 32)); + harness.Shutdown(); + } + + [Fact] + public void SelflossShapeDccVolume_HandlesOneHundredTwentyEightSlicesIndependently() + { + if (!GatePrerequisites.Ready(_vulkan)) return; + using var harness = new CacheHarness(_vulkan); + var address = harness.MapBacked(0x140000, ReadWrite); + var imageAddress = address + 0x1000; + var metadataAddress = address + 0x20000; + const uint depth = 128; + const ulong metadataSliceSize = 0x2000; + var metadataBytes = new byte[checked((int)(depth * metadataSliceSize))]; + Array.Fill(metadataBytes, (byte)0xc0); + const uint mixedSlice = 73; + Array.Fill( + metadataBytes, + (byte)0x55, + checked((int)(mixedSlice * metadataSliceSize + 1)), + checked((int)metadataSliceSize - 1)); + harness.Write(metadataAddress, metadataBytes); + + const uint width = 4; + const uint height = 4; + var imageSize = (ulong)width * height * depth * 8; + var texture = LinearRequest( + imageAddress, + imageSize, + Format.R16G16B16A16Sfloat, + GuestPixelFormat.Bits16_16_16_16Float, + GuestImageType.Color3D, + new Extent3D(width, height, depth), + 1, + 8, + 1); + texture.Description.Metadata.Kind = MetadataKind.Dcc; + texture.Description.Metadata.Range = new GuestSpan( + metadataAddress, + depth * metadataSliceSize); + texture.Description.Metadata.DccAlphaMsb = true; + + var textureId = harness.Find(ref texture); + harness.Finish(); + + Assert.True(textureId.IsValid); + Assert.Equal(uint.MaxValue, harness.ReadUInt32(metadataAddress)); + Assert.Equal( + 0x555555c0u, + harness.ReadUInt32(metadataAddress + mixedSlice * metadataSliceSize)); + Assert.Equal( + uint.MaxValue, + harness.ReadUInt32(metadataAddress + (depth - 1) * metadataSliceSize)); + Assert.False(harness.Images.IsMetadata(metadataAddress)); + harness.Shutdown(); + } + + [Fact] + public void DccMetadataScan_RejectsAMismatchBeyondTheFirstPooledChunk() + { + if (!GatePrerequisites.Ready(_vulkan)) return; + using var harness = new CacheHarness(_vulkan); + var address = harness.MapBacked(0x50000, ReadWrite); + var imageAddress = address + 0x1000; + var metadataAddress = address + 0x10000; + const uint layers = 2; + const ulong metadataSliceSize = 0x11000; + var metadataBytes = new byte[checked((int)(layers * metadataSliceSize))]; + Array.Fill(metadataBytes, (byte)0xc0); + metadataBytes[^1] = 0x55; + harness.Write(metadataAddress, metadataBytes); + + const uint width = 4; + const uint height = 4; + var texture = LinearRequest( + imageAddress, + (ulong)width * height * layers * 4, + Format.R8G8B8A8Unorm, + GuestPixelFormat.Bits8_8_8_8UNorm, + GuestImageType.Color2D, + new Extent3D(width, height, 1), + layers, + 4, + 1); + texture.Description.Metadata.Kind = MetadataKind.Dcc; + texture.Description.Metadata.Range = new GuestSpan( + metadataAddress, + layers * metadataSliceSize); + texture.Description.Metadata.DccAlphaMsb = true; + + var textureId = harness.Find(ref texture); + harness.Finish(); + + Assert.True(textureId.IsValid); + Assert.Equal(uint.MaxValue, harness.ReadUInt32(metadataAddress)); + Assert.Equal(0xc0c0c0c0u, harness.ReadUInt32(metadataAddress + metadataSliceSize)); + Assert.Equal(0x55, harness.Read(metadataAddress + 2 * metadataSliceSize - 1, 1)[0]); harness.Shutdown(); } @@ -196,8 +350,10 @@ public sealed partial class GuestImageCacheTests harness.Shutdown(); } - [Fact] - public void ATextureRequestWithDcc_GivesAnImageFoundWithoutMetadataItsDccMetadata() + [Theory] + [InlineData(false)] + [InlineData(true)] + public void DccDescriptor_SynchronizesMetadataOnAnImageFoundWithoutIt(bool native) { if (!GatePrerequisites.Ready(_vulkan)) return; using var harness = new CacheHarness(_vulkan); @@ -220,14 +376,15 @@ public sealed partial class GuestImageCacheTests var compressed = plain; compressed.Description.TileMode = GuestTileMode.RenderTarget; compressed.Description.Metadata.Kind = MetadataKind.Dcc; - compressed.Description.Metadata.Range = new GuestSpan(metadata, 0); + compressed.Description.Metadata.Range = new GuestSpan(metadata, native ? SliceSize : 0); Assert.Equal(imageId, harness.Find(ref compressed)); Assert.Equal(MetadataKind.Dcc, image.Description.Metadata.Kind); Assert.Equal(metadata, image.Description.Metadata.Range.Address); Assert.Equal(SliceSize, image.Description.DccSliceSize); Assert.False(harness.Cache.HasGpuDirtyBytes(metadata, SliceSize)); - Assert.True(harness.Images.TryReadGuestDccClear(metadata, SliceSize, 0, out _, out var code)); - Assert.Equal(0x00, code); + harness.Finish(); + Assert.Equal(native ? uint.MaxValue : 0u, harness.ReadUInt32(metadata)); + Assert.Equal(!native, harness.Images.TryReadGuestDccClear(metadata, SliceSize, 0, out _, out _)); harness.Shutdown(); } diff --git a/tests/SharpEmu.Libs.Tests/Gpu/Images/ImageDescriptionTests.cs b/tests/SharpEmu.Libs.Tests/Gpu/Images/ImageDescriptionTests.cs index 141c722..192a2e4 100644 --- a/tests/SharpEmu.Libs.Tests/Gpu/Images/ImageDescriptionTests.cs +++ b/tests/SharpEmu.Libs.Tests/Gpu/Images/ImageDescriptionTests.cs @@ -154,6 +154,21 @@ public sealed class ImageDescriptionTests Assert.False(ImageDescription.CanUseDisplayNativeWithoutUpload(DisplayCompression.Unsupported, renderTarget: true, gpuModified: true, guestModified: false)); } + [Theory] + [InlineData(true, 0.0f, 1.0f)] + [InlineData(false, 1.0f, 0.0f)] + public void DccFixedClear_RespectsTheAlphaPosition(bool alphaMsb, float red, float alpha) + { + var metadata = new MetadataDescription { DccAlphaMsb = alphaMsb }; + Assert.True(PackedClearValue.TryDecodeDccColor( + Format.A2B10G10R10UnormPack32, 0x40404040, metadata, false, out var clear)); + Assert.Equal((red, 0.0f, 0.0f, alpha), (clear.Float32_0, clear.Float32_1, clear.Float32_2, clear.Float32_3)); + Assert.False(PackedClearValue.TryDecodeDccColor( + Format.A2B10G10R10UnormPack32, 0x40400040, metadata, false, out _)); + Assert.False(PackedClearValue.TryDecodeDccColor( + Format.A2B10G10R10UnormPack32, 0xffffffff, metadata, false, out _)); + } + [Fact] public void PackedClears_DecodePerFormat() { diff --git a/tests/SharpEmu.Libs.Tests/Gpu/Images/ImageRequestBuildersTests.cs b/tests/SharpEmu.Libs.Tests/Gpu/Images/ImageRequestBuildersTests.cs index cfd8351..64414f2 100644 --- a/tests/SharpEmu.Libs.Tests/Gpu/Images/ImageRequestBuildersTests.cs +++ b/tests/SharpEmu.Libs.Tests/Gpu/Images/ImageRequestBuildersTests.cs @@ -74,21 +74,40 @@ public sealed class ImageRequestBuildersTests : IClassFixture> 8) & 0xFF) << 24); words[7] = (uint)(metadata >> 16); - var shape = Sampled2D with { Volume = type == GuestImageType.Color3D, Arrayed = type == GuestImageType.Color2DArray }; + var shape = Sampled2D with { Volume = type == GuestImageType.Color3D, Arrayed = type == GuestImageType.Color2DArray, Storage = storage }; var description = ImageRequestBuilders.Texture(words, shape).Request.Description; - Assert.Equal(expected ? MetadataKind.Dcc : MetadataKind.None, description.Metadata.Kind); - Assert.Equal(expected ? metadata : 0UL, description.Metadata.Range.Address); + Assert.Equal(MetadataKind.Dcc, description.Metadata.Kind); + Assert.Equal(metadata, description.Metadata.Range.Address); + Assert.Equal((ulong)layers * 0x1000, description.Metadata.Range.Size); + } + + [Fact] + public void DemonSlayerColorLut_CarriesItsVolumeDccFootprintAndAlphaPosition() + { + uint[] words = [0x606D4E00, 0xC3200000, 0x0007C007, 0xA1B00FAC, 0x0000001F, 0x00700000, 0x006B0000, 0x00606D6E]; + var description = ImageRequestBuilders.Texture(words, Sampled2D with { Volume = true }).Request.Description; + + Assert.Equal(GuestImageType.Color3D, description.Type); + Assert.Equal(new Extent3D(32, 32, 32), description.Extent); + Assert.Equal(Format.A2B10G10R10UnormPack32, description.PixelFormat); + Assert.Equal(MetadataKind.Dcc, description.Metadata.Kind); + Assert.Equal(0x606D6E0000UL, description.Metadata.Range.Address); + Assert.Equal(0x20000UL, description.Metadata.Range.Size); + Assert.True(description.Metadata.DccAlphaMsb); } private readonly HeadlessVulkan? _vulkan; diff --git a/tests/SharpEmu.Libs.Tests/Gpu/Images/TextureTransferLayoutTests.cs b/tests/SharpEmu.Libs.Tests/Gpu/Images/TextureTransferLayoutTests.cs index 173d666..516bf59 100644 --- a/tests/SharpEmu.Libs.Tests/Gpu/Images/TextureTransferLayoutTests.cs +++ b/tests/SharpEmu.Libs.Tests/Gpu/Images/TextureTransferLayoutTests.cs @@ -97,7 +97,7 @@ public sealed class TextureTransferLayoutTests var target = TextureTransferLayout.Compute(GuestPixelFormat.Bits8_8_8_8UNorm, 128, 128, 1, 2, GuestTileMode.RenderTarget, 0, false, false, "test"); Assert.True(target.TryBuildTileTransfers(2 * 65536, target.BuildCopies(), 1, out var targetTransfers)); Assert.Equal(1u, targetTransfers[1].SurfaceZ); - Assert.Equal(TileBlockKind.RenderTarget64KB, targetTransfers[1].Kind); + Assert.Equal(TileBlockKind.RenderTarget64KBGen5, targetTransfers[1].Kind); } [Fact] diff --git a/tests/SharpEmu.Libs.Tests/Gpu/Images/TileGeometryTests.cs b/tests/SharpEmu.Libs.Tests/Gpu/Images/TileGeometryTests.cs index 79213b2..6cb54a9 100644 --- a/tests/SharpEmu.Libs.Tests/Gpu/Images/TileGeometryTests.cs +++ b/tests/SharpEmu.Libs.Tests/Gpu/Images/TileGeometryTests.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later using SharpEmu.Libs.Gpu.Images; +using SharpEmu.ShaderCompiler.Vulkan; using Xunit; namespace SharpEmu.Libs.Tests.Gpu.Images; @@ -39,6 +40,7 @@ public sealed class TileGeometryTests [InlineData(TileBlockKind.Prt64KB3D, 65536u, 16u)] [InlineData(TileBlockKind.RenderTarget64KB, 65536u, 16u)] [InlineData(TileBlockKind.Depth64KB, 65536u, 8u)] + [InlineData(TileBlockKind.RenderTarget64KBGen5, 65536u, 16u)] public void BlockLayouts_CoverEveryElementSize(TileBlockKind kind, uint blockSize, uint maxBytes) { for (uint bytes = 1; bytes <= 16; bytes *= 2) @@ -107,6 +109,83 @@ public sealed class TileGeometryTests } } + [Theory] + [InlineData(1u, 0x0B75u, 0x8000u, 0x4000u)] + [InlineData(2u, 0x0B7Au, 0x8000u, 0x4100u)] + [InlineData(4u, 0x0BF4u, 0x8100u, 0x4100u)] + [InlineData(8u, 0x1BD8u, 0x4100u, 0x8800u)] + [InlineData(16u, 0x3BB0u, 0x4400u, 0x8800u)] + public void RenderTargetBlockOffsets_MatchRbPlusReferenceSpotValues( + uint bytes, + uint elementOffset, + uint xBlockXor, + uint yBlockXor) + { + Assert.True(TileGeometry.TryGetBlockLayout(TileBlockKind.RenderTarget64KB, bytes, out var layout)); + Assert.True(TileGeometry.TryGetBlockOffset(layout, 37, 23, 0, out var offset)); + Assert.Equal(elementOffset, offset); + + Assert.True(TileGeometry.TryGetBlockXor(layout, 1, 0, out var blockX)); + Assert.Equal(xBlockXor, blockX); + Assert.True(TileGeometry.TryGetBlockXor(layout, 0, 1, out var blockY)); + Assert.Equal(yBlockXor, blockY); + } + + [Theory] + [InlineData(1u, 0x0b75u, 0x0abdu)] + [InlineData(2u, 0x0b7au, 0x1a7au)] + [InlineData(4u, 0x0bf4u, 0x0af4u)] + [InlineData(8u, 0x1bd8u, 0x5ad8u)] + [InlineData(16u, 0x3bb0u, 0x3ab0u)] + public void Gen5RenderTargetBlockOffsets_MatchReferenceAndDifferFromRbPlus( + uint bytes, + uint expectedRbPlus, + uint expectedGen5) + { + Assert.True(TileGeometry.TryGetBlockLayout(TileBlockKind.RenderTarget64KB, bytes, out var rbPlus)); + Assert.True(TileGeometry.TryGetBlockLayout(TileBlockKind.RenderTarget64KBGen5, bytes, out var gen5)); + + Assert.True(TileGeometry.TryGetBlockOffset(rbPlus, 37, 23, 0, out var rbPlusOffset)); + Assert.True(TileGeometry.TryGetBlockOffset(gen5, 37, 23, 0, out var gen5Offset)); + Assert.Equal(expectedRbPlus, rbPlusOffset); + Assert.Equal(expectedGen5, gen5Offset); + Assert.NotEqual(rbPlusOffset, gen5Offset); + } + + [Fact] + public void Gen5RenderTargetGeometry_MatchesTheReferenceVolumeAllocation() + { + const uint width = 480; + const uint height = 270; + const uint depth = 128; + Assert.True(TileGeometry.TryGetBlockLayout(TileBlockKind.RenderTarget64KBGen5, 8, out var block)); + Assert.Equal((128u, 64u, 1u), (block.BlockWidth, block.BlockHeight, block.BlockDepth)); + + var paddedWidth = (width + block.BlockWidth - 1) / block.BlockWidth * block.BlockWidth; + var paddedHeight = (height + block.BlockHeight - 1) / block.BlockHeight * block.BlockHeight; + var blocksPerSlice = (ulong)(paddedWidth / block.BlockWidth) * (paddedHeight / block.BlockHeight); + var sliceSize = blocksPerSlice * block.BlockSize; + var totalSize = sliceSize * depth; + + Assert.Equal((512u, 320u), (paddedWidth, paddedHeight)); + Assert.Equal(0x140000UL, sliceSize); + Assert.Equal(0xA000000UL, totalSize); + } + + [Fact] + public void CpuAndShaderBlockKindOrdinals_StayAligned() + { + var cpuKinds = Enum.GetValues(); + var shaderKinds = Enum.GetValues(); + Assert.Equal(cpuKinds.Length, shaderKinds.Length); + + for (var index = 0; index < cpuKinds.Length; index++) + { + Assert.Equal(cpuKinds[index].ToString(), shaderKinds[index].ToString()); + Assert.Equal((uint)cpuKinds[index], (uint)shaderKinds[index]); + } + } + [Fact] public void MipTail_StartsWhereTheLevelFitsAndOffsetsRunBackwards() { diff --git a/tests/SharpEmu.Libs.Tests/Gpu/Images/TilerParityTests.cs b/tests/SharpEmu.Libs.Tests/Gpu/Images/TilerParityTests.cs index 0a7d2d6..ef70828 100644 --- a/tests/SharpEmu.Libs.Tests/Gpu/Images/TilerParityTests.cs +++ b/tests/SharpEmu.Libs.Tests/Gpu/Images/TilerParityTests.cs @@ -59,6 +59,11 @@ public sealed class TilerParityTests : IClassFixture foreach (var tilerCase in TilerCases.All()) { var transfer = tilerCase.Transfer; + if (transfer.Kind == TileBlockKind.RenderTarget64KBGen5) + { + continue; + } + var reference = blobs[(int)transfer.Kind]!; foreach (var toTiled in new[] { false, true }) { diff --git a/tests/SharpEmu.Libs.Tests/Gpu/Pipelines/ShaderPrewarmListTests.cs b/tests/SharpEmu.Libs.Tests/Gpu/Pipelines/ShaderPrewarmListTests.cs index cacde02..7629dce 100644 --- a/tests/SharpEmu.Libs.Tests/Gpu/Pipelines/ShaderPrewarmListTests.cs +++ b/tests/SharpEmu.Libs.Tests/Gpu/Pipelines/ShaderPrewarmListTests.cs @@ -61,7 +61,7 @@ public sealed class ShaderPrewarmListTests : IDisposable Assert.True( ShaderProgramCache.TryCompilePrewarm( record, code, new FakeShaderCompiler(Compile), host.SharedInt64AtomicsEnabled, host.ExecGuardElisionEnabled, - out var compiled, out var layout, out var error), + host.ShaderSignedZeroInfNanPreserveFloat32Supported, out var compiled, out var layout, out var error), error); Assert.NotNull(layout); Assert.Equal(runtime, Assert.IsType(compiled).Spirv); diff --git a/tests/SharpEmu.Libs.Tests/Np/NpAuthExportsTests.cs b/tests/SharpEmu.Libs.Tests/Np/NpAuthExportsTests.cs index e3b679b..c1a1705 100644 --- a/tests/SharpEmu.Libs.Tests/Np/NpAuthExportsTests.cs +++ b/tests/SharpEmu.Libs.Tests/Np/NpAuthExportsTests.cs @@ -46,14 +46,48 @@ public sealed class NpAuthExportsTests Assert.Equal(unchecked((int)0x80550304), BinaryPrimitives.ReadInt32LittleEndian(resultBytes)); } - [Fact] - public void OnlineOperation_ReturnsServiceDownWithoutProducingCredentials() + [Theory] + [InlineData(false, false)] + [InlineData(false, true)] + [InlineData(true, false)] + [InlineData(true, true)] + public void OnlineOperation_CompletesSignedOutWithoutProducingCredentials(bool async, bool idToken) { NpAuthExports.ResetRuntimeState(); - var ctx = new CpuContext(new FakeCpuMemory(MemoryBase, 0x1000), Generation.Gen5); - var requestId = NpAuthExports.NpAuthCreateRequest(ctx); - ctx[CpuRegister.Rdi] = unchecked((uint)requestId); + var memory = new FakeCpuMemory(MemoryBase, 0x2000); + var ctx = new CpuContext(memory, Generation.Gen5); + ctx[CpuRegister.Rdi] = MemoryBase; + Assert.True(ctx.TryWriteUInt64(MemoryBase, 24)); + var requestId = async + ? NpAuthExports.NpAuthCreateAsyncRequest(ctx) + : NpAuthExports.NpAuthCreateRequest(ctx); + Assert.True(requestId > 0); - Assert.Equal(unchecked((int)0x80550401), NpAuthExports.NpAuthGetAuthorizationCodeV3(ctx)); + var outputAddress = MemoryBase + 0x100; + var issuerAddress = MemoryBase + 0x1800; + var credentials = new byte[idToken ? 4104 : 136]; + Array.Fill(credentials, (byte)0xAA); + Assert.True(memory.TryWrite(outputAddress, credentials)); + Assert.True(ctx.TryWriteUInt32(issuerAddress, uint.MaxValue)); + ctx[CpuRegister.Rdi] = unchecked((uint)requestId); + ctx[CpuRegister.Rdx] = outputAddress; + ctx[CpuRegister.Rcx] = issuerAddress; + + var result = idToken + ? NpAuthExports.NpAuthGetIdTokenV3(ctx) + : NpAuthExports.NpAuthGetAuthorizationCodeV3(ctx); + Assert.Equal(async ? 0 : unchecked((int)0x80550006), result); + Assert.True(memory.TryRead(outputAddress, credentials)); + Assert.All(credentials, value => Assert.Equal((byte)0, value)); + Assert.True(ctx.TryReadUInt32(issuerAddress, out var issuer)); + Assert.Equal(idToken ? uint.MaxValue : 0u, issuer); + + var resultAddress = MemoryBase + 0x1880; + ctx[CpuRegister.Rsi] = resultAddress; + Assert.Equal(0, NpAuthExports.NpAuthPollAsync(ctx)); + Assert.True(ctx.TryReadUInt32(resultAddress, out var completionResult)); + Assert.Equal(0x80550006u, completionResult); + + Assert.Equal(unchecked((int)0x80550301), NpAuthExports.NpAuthGetAuthorizationCodeV3(ctx)); } }