Files
sharpemu/tests/SharpEmu.Libs.Tests/Audio/AcmExportsTests.cs
T
Berk 2b6bd5a532 Sdl backend (#670)
* [audio] added sdl audio backend and in-tree atrac9 decoder

* [input] replaced per-platform pad readers with sdl gamepad input

* [video] added sdl window and host display plumbing

* [gui] added host display options and per-game render settings

* [bink] synced host movie playback to the guest audio clock

* [cpu] hooked windows write faults into guest image tracking

* [perf] added guest and render profiling, reserved host cpu lanes

* [kernel] fixed stale pthread mutex handle alias

* [host] wired the sdl session, save-data paths and project references

* [audio] hoisted ajm trace stackalloc out of its loop

* [video] Add guest image sync setting

* [build] Strip native symbols

* reuse
2026-07-28 03:33:26 +03:00

131 lines
4.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.Acm;
using Xunit;
namespace SharpEmu.Libs.Tests.Audio;
[CollectionDefinition("AcmState", DisableParallelization = true)]
public sealed class AcmStateCollection
{
public const string Name = "AcmState";
}
[Collection(AcmStateCollection.Name)]
public sealed class AcmExportsTests : IDisposable
{
private const ulong MemoryBase = 0x1_1000_0000;
private const ulong ContextAddress = MemoryBase + 0x100;
private const ulong InfoArrayAddress = MemoryBase + 0x200;
private const ulong ErrorAddress = MemoryBase + 0x300;
private const ulong BatchAddress = MemoryBase + 0x400;
private readonly FakeCpuMemory _memory = new(MemoryBase, 0x1000);
private readonly CpuContext _ctx;
public AcmExportsTests()
{
AcmExports.ResetForTests();
_ctx = new CpuContext(_memory, Generation.Gen5);
}
[Fact]
public void ContextAndBatchLifecycle_UsesFourByteHandlesAndClearsErrors()
{
Span<byte> contextSentinel = stackalloc byte[8];
contextSentinel.Fill(0xCC);
Assert.True(_memory.TryWrite(ContextAddress, contextSentinel));
_ctx[CpuRegister.Rdi] = ContextAddress;
Assert.Equal(0, AcmExports.AcmContextCreate(_ctx));
var context = ReadUInt32(ContextAddress);
Assert.Equal(1u, context);
Assert.Equal(0xCCCCCCCCu, ReadUInt32(ContextAddress + 4));
Span<byte> errorSentinel = stackalloc byte[32];
errorSentinel.Fill(0xCC);
Assert.True(_memory.TryWrite(ErrorAddress, errorSentinel));
WriteUInt64(InfoArrayAddress, MemoryBase + 0x500);
_ctx[CpuRegister.Rdi] = context;
_ctx[CpuRegister.Rsi] = 1;
_ctx[CpuRegister.Rdx] = InfoArrayAddress;
_ctx[CpuRegister.Rcx] = ErrorAddress;
_ctx[CpuRegister.R8] = BatchAddress;
Assert.Equal(0, AcmExports.AcmBatchStartBuffers(_ctx));
Assert.Equal(1u, ReadUInt32(BatchAddress));
Assert.All(ReadBytes(ErrorAddress, 32), value => Assert.Equal(0, value));
_ctx[CpuRegister.Rdi] = context;
_ctx[CpuRegister.Rsi] = 1;
_ctx[CpuRegister.Rdx] = 0;
Assert.Equal(0, AcmExports.AcmBatchWait(_ctx));
}
[Fact]
public void BatchStartBuffers_RejectsUnknownContextAndMissingOutputs()
{
_ctx[CpuRegister.Rdi] = 99;
_ctx[CpuRegister.Rsi] = 1;
_ctx[CpuRegister.Rdx] = InfoArrayAddress;
_ctx[CpuRegister.R8] = BatchAddress;
Assert.Equal(
(int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT,
AcmExports.AcmBatchStartBuffers(_ctx));
_ctx[CpuRegister.Rdi] = ContextAddress;
Assert.Equal(0, AcmExports.AcmContextCreate(_ctx));
_ctx[CpuRegister.Rdi] = ReadUInt32(ContextAddress);
_ctx[CpuRegister.Rsi] = 1;
_ctx[CpuRegister.Rdx] = 0;
_ctx[CpuRegister.R8] = BatchAddress;
Assert.Equal(
(int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT,
AcmExports.AcmBatchStartBuffers(_ctx));
}
[Fact]
public void AcmBatchExports_RegisterForBothGenerations()
{
foreach (var generation in new[] { Generation.Gen4, Generation.Gen5 })
{
var manager = new ModuleManager();
manager.RegisterExports(SharpEmu.Generated.SysAbiExportRegistry.CreateExports(generation));
Assert.True(manager.TryGetExport("8fe55ktlNVo", out var start));
Assert.Equal("sceAcmBatchStartBuffers", start.Name);
Assert.True(manager.TryGetExport("RLN3gRlXJLE", out var wait));
Assert.Equal("sceAcmBatchWait", wait.Name);
}
}
public void Dispose()
{
AcmExports.ResetForTests();
}
private uint ReadUInt32(ulong address)
{
Span<byte> value = stackalloc byte[sizeof(uint)];
Assert.True(_memory.TryRead(address, value));
return BinaryPrimitives.ReadUInt32LittleEndian(value);
}
private byte[] ReadBytes(ulong address, int length)
{
var value = new byte[length];
Assert.True(_memory.TryRead(address, value));
return value;
}
private void WriteUInt64(ulong address, ulong value)
{
Span<byte> bytes = stackalloc byte[sizeof(ulong)];
BinaryPrimitives.WriteUInt64LittleEndian(bytes, value);
Assert.True(_memory.TryWrite(address, bytes));
}
}