mirror of
https://github.com/par274/sharpemu.git
synced 2026-07-31 06:59:45 +08:00
2b6bd5a532
* [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
131 lines
4.4 KiB
C#
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));
|
|
}
|
|
}
|