[Tests] Cover Gen5 tiling, DCC clears and offline authentication

Co-authored-by: Sekai <140012992+SekaixX@users.noreply.github.com>
This commit is contained in:
ParantezTech 2026-10-08 17:32:02 +03:00
parent c0028d304b
commit dd6a936a12
9 changed files with 342 additions and 33 deletions

View File

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

View File

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

View File

@ -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()
{

View File

@ -74,21 +74,40 @@ public sealed class ImageRequestBuildersTests : IClassFixture<HeadlessVulkanFixt
}
[Theory]
[InlineData(GuestImageType.Color2D, 1u, false)]
[InlineData(GuestImageType.Color2D, 1u, true)]
[InlineData(GuestImageType.Color3D, 32u, false)]
[InlineData(GuestImageType.Color3D, 32u, true)]
[InlineData(GuestImageType.Color2DArray, 4u, false)]
public void CompressedTexture_CarriesDccMetadataOnlyForSingleLayer2D(GuestImageType type, uint layers, bool expected)
[InlineData(GuestImageType.Color2DArray, 4u, true)]
public void CompressedTexture_CarriesDccMetadataForEverySlice(GuestImageType type, uint layers, bool storage)
{
const ulong metadata = 0x1_2000_0000;
var words = RegisterWords.Texture(Base, GuestPixelFormat.Bits8_8_8_8UNorm, 32, 32, type, GuestTileMode.RenderTarget, layers: layers);
words[6] |= (1u << 21) | (uint)(((metadata >> 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;

View File

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

View File

@ -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<TileBlockKind>();
var shaderKinds = Enum.GetValues<TilerBlockShape>();
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()
{

View File

@ -59,6 +59,11 @@ public sealed class TilerParityTests : IClassFixture<HeadlessVulkanFixture>
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 })
{

View File

@ -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<FakeCompiledShader>(compiled).Spirv);

View File

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