91 lines
3.8 KiB
C#
91 lines
3.8 KiB
C#
// Copyright (C) 2026 SharpEmu Emulator Project
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
using System.Buffers.Binary;
|
|
using SharpEmu.HLE;
|
|
using SharpEmu.Libs.Agc;
|
|
using SharpEmu.Libs.Gpu.GpuCommands;
|
|
using SharpEmu.Libs.Tests.Gpu.GpuCommands;
|
|
using Xunit;
|
|
|
|
namespace SharpEmu.Libs.Tests.Agc;
|
|
|
|
[Collection(AgcCommandBufferChainCollection.Name)]
|
|
public sealed class AgcContextStateTests
|
|
{
|
|
private const ulong MemoryBase = 0x210000000;
|
|
private const ulong CommandBuffer = MemoryBase + 0x40;
|
|
private const ulong Commands = MemoryBase + 0x200;
|
|
|
|
private static uint[] Emit(uint operation, uint capacity, out ulong result, out ulong cursor)
|
|
{
|
|
var memory = new FakeCpuMemory(MemoryBase, 0x1000);
|
|
var context = new CpuContext(memory, Generation.Gen5);
|
|
Assert.True(context.TryWriteUInt64(CommandBuffer + 0x10, Commands));
|
|
Assert.True(context.TryWriteUInt64(CommandBuffer + 0x18, Commands + capacity * 4));
|
|
context[CpuRegister.Rdi] = CommandBuffer;
|
|
context[CpuRegister.Rsi] = operation;
|
|
AgcExports.DcbContextStateOperation(context);
|
|
result = context[CpuRegister.Rax];
|
|
Span<byte> cursorBytes = stackalloc byte[8];
|
|
Assert.True(memory.TryRead(CommandBuffer + 0x10, cursorBytes));
|
|
cursor = BinaryPrimitives.ReadUInt64LittleEndian(cursorBytes);
|
|
var bytes = new byte[(int)(cursor - Commands)];
|
|
Assert.True(memory.TryRead(Commands, bytes));
|
|
return Enumerable.Range(0, bytes.Length / 4)
|
|
.Select(index => BinaryPrimitives.ReadUInt32LittleEndian(bytes.AsSpan(index * 4))).ToArray();
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(0u, 5u)]
|
|
[InlineData(1u, 27u)]
|
|
[InlineData(2u, 27u)]
|
|
[InlineData(3u, 32u)]
|
|
public void ExportPreservesPacketSizesAndOperation(uint operation, uint expectedDwords)
|
|
{
|
|
var words = Emit(operation, expectedDwords, out var result, out var cursor);
|
|
Assert.Equal(Commands, result);
|
|
Assert.Equal(Commands + expectedDwords * 4, cursor);
|
|
Assert.Equal(operation, words[1]);
|
|
for (var index = 0; index < words.Length;)
|
|
{
|
|
Assert.Equal(PacketOpcode.Nop, PacketHeader.Opcode(words[index]));
|
|
Assert.Equal(index == 0 ? PacketCustomCode.ContextState : 0u, PacketHeader.CustomCode(words[index]));
|
|
index += (int)PacketHeader.Length(words[index]);
|
|
Assert.InRange(index, 1, words.Length);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void ExportedPushClearAndPopRestoreViewportAndTargetMask()
|
|
{
|
|
var push = Emit(3, 32, out _, out _);
|
|
var pop = Emit(2, 27, out _, out _);
|
|
var runner = new StreamRunner();
|
|
runner.Run(
|
|
StreamRunner.Packet(PacketOpcode.SetContextRegister, 0x113, 0x3F800000u, 0u),
|
|
StreamRunner.Packet(PacketOpcode.SetContextRegister, 0x8E, 0xFu),
|
|
push,
|
|
StreamRunner.Packet(PacketOpcode.SetContextRegister, 0x113, 0x3F000000u, 0x3F000000u),
|
|
StreamRunner.Packet(PacketOpcode.SetContextRegister, 0x8E, 0u));
|
|
Assert.Equal(0.5f, runner.Interpreter.TypedRegisters.Context.ScreenViewport.Viewports[0].ZOffset);
|
|
runner.Run(pop);
|
|
var restored = runner.Interpreter.TypedRegisters.Context;
|
|
Assert.Equal(1f, restored.ScreenViewport.Viewports[0].ZScale);
|
|
Assert.Equal(0f, restored.ScreenViewport.Viewports[0].ZOffset);
|
|
Assert.Equal(0xFu, restored.RenderTargetMask);
|
|
Assert.False(runner.Interpreter.TypedRegisters.ContextPushed);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(4u, 32u)]
|
|
[InlineData(1u, 21u)]
|
|
[InlineData(0u, 4u)]
|
|
public void InvalidOperationOrInsufficientSpaceReturnsNull(uint operation, uint capacity)
|
|
{
|
|
Assert.Empty(Emit(operation, capacity, out var result, out var cursor));
|
|
Assert.Equal(0UL, result);
|
|
Assert.Equal(Commands, cursor);
|
|
}
|
|
}
|