91 lines
3.4 KiB
C#
91 lines
3.4 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;
|
|
|
|
// Direct draws carry a modifier naming the shader stage and the user registers of the pipeline.
|
|
// Every modifier must still produce the draw: Unreal's volume passes use a geometry-stage modifier.
|
|
public sealed class AgcDirectDrawModifierTests
|
|
{
|
|
private const ulong BaseAddress = 0x2_1000_0000;
|
|
private const ulong CommandBufferAddress = BaseAddress + 0x80;
|
|
private const ulong CommandAddress = BaseAddress + 0x200;
|
|
|
|
public static TheoryData<ulong> Modifiers => new() { 0x4000_0000UL, 0x6000_0000UL, 0xA000_0000UL, 0x4008_0205UL, 0x1_6000_0000UL };
|
|
|
|
[Theory]
|
|
[MemberData(nameof(Modifiers))]
|
|
public void DrawIndexAutoEmitsTheDrawForEveryModifier(ulong modifier)
|
|
{
|
|
var memory = CreateCommandBuffer();
|
|
var context = new CpuContext(memory, Generation.Gen5);
|
|
context[CpuRegister.Rdi] = CommandBufferAddress;
|
|
context[CpuRegister.Rsi] = 6;
|
|
context[CpuRegister.Rdx] = modifier;
|
|
|
|
AgcExports.DcbDrawIndexAuto(context);
|
|
|
|
Assert.Equal(CommandAddress, context[CpuRegister.Rax]);
|
|
var runner = new StreamRunner();
|
|
Assert.Equal(SubmissionProgress.Complete, runner.Run(ReadDwords(memory, CommandAddress, 7)));
|
|
var draw = Assert.Single(runner.Host.AutoDraws);
|
|
Assert.Equal(6u, draw.VertexCount);
|
|
}
|
|
|
|
[Theory]
|
|
[MemberData(nameof(Modifiers))]
|
|
public void DrawIndexEmitsTheDrawForEveryModifier(ulong modifier)
|
|
{
|
|
var memory = CreateCommandBuffer();
|
|
var context = new CpuContext(memory, Generation.Gen5);
|
|
context[CpuRegister.Rdi] = CommandBufferAddress;
|
|
context[CpuRegister.Rsi] = 36;
|
|
context[CpuRegister.Rdx] = StreamRunner.DataAddress;
|
|
context[CpuRegister.Rcx] = modifier;
|
|
|
|
AgcExports.DcbDrawIndex(context);
|
|
|
|
Assert.NotEqual(0UL, context[CpuRegister.Rax]);
|
|
var runner = new StreamRunner();
|
|
Assert.Equal(SubmissionProgress.Complete, runner.Run(ReadDwords(memory, CommandAddress, 11)));
|
|
var draw = Assert.Single(runner.Host.IndexedDraws);
|
|
Assert.Equal(36u, draw.IndexCount);
|
|
Assert.Equal(StreamRunner.DataAddress, draw.IndexAddress);
|
|
}
|
|
|
|
private static FakeCpuMemory CreateCommandBuffer()
|
|
{
|
|
var memory = new FakeCpuMemory(BaseAddress, 0x1000);
|
|
WriteUInt64(memory, CommandBufferAddress + 0x10, CommandAddress);
|
|
WriteUInt64(memory, CommandBufferAddress + 0x18, CommandAddress + 0x100);
|
|
return memory;
|
|
}
|
|
|
|
private static uint[] ReadDwords(FakeCpuMemory memory, ulong address, int count)
|
|
{
|
|
var bytes = new byte[count * sizeof(uint)];
|
|
Assert.True(memory.TryRead(address, bytes));
|
|
var dwords = new uint[count];
|
|
for (var index = 0; index < count; index++)
|
|
{
|
|
dwords[index] = BinaryPrimitives.ReadUInt32LittleEndian(bytes.AsSpan(index * sizeof(uint)));
|
|
}
|
|
|
|
return dwords;
|
|
}
|
|
|
|
private static void WriteUInt64(FakeCpuMemory memory, ulong address, ulong value)
|
|
{
|
|
Span<byte> buffer = stackalloc byte[sizeof(ulong)];
|
|
BinaryPrimitives.WriteUInt64LittleEndian(buffer, value);
|
|
Assert.True(memory.TryWrite(address, buffer));
|
|
}
|
|
}
|