[shader] add scalar memory fallback

This commit is contained in:
ParantezTech
2026-07-18 23:02:12 +03:00
parent ce243b3622
commit 2064c1eda6
3 changed files with 102 additions and 2 deletions
@@ -0,0 +1,99 @@
// Copyright (C) 2026 SharpEmu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
using System.Buffers.Binary;
using SharpEmu.HLE;
using SharpEmu.ShaderCompiler;
using Xunit;
namespace SharpEmu.Libs.Tests.Agc;
public sealed class Gen5ScalarMemoryFallbackTests
{
private const ulong ScalarTableAddress = 0x4_4665_4FD0;
private static readonly object FallbackReaderGate = new();
[Fact]
public void ScalarLoadReadsTrackedFallbackMemory()
{
var expected = new uint[]
{
0x4665_4F70,
0x0000_0004,
0x4EA7_FCE0,
0x0000_0004,
};
var table = new byte[expected.Length * sizeof(uint)];
for (var index = 0; index < expected.Length; index++)
{
BinaryPrimitives.WriteUInt32LittleEndian(
table.AsSpan(index * sizeof(uint), sizeof(uint)),
expected[index]);
}
var load = new Gen5ShaderInstruction(
0,
Gen5ShaderEncoding.Smem,
"SLoadDwordx4",
[],
[Gen5Operand.Scalar(0)],
[
Gen5Operand.Scalar(16),
Gen5Operand.Scalar(17),
Gen5Operand.Scalar(18),
Gen5Operand.Scalar(19),
],
new Gen5ScalarMemoryControl(4, 0, null));
var end = new Gen5ShaderInstruction(
8,
Gen5ShaderEncoding.Sopp,
"SEndpgm",
[],
[],
[],
null);
var state = new Gen5ShaderState(
new Gen5ShaderProgram(0, [load, end]),
[unchecked((uint)ScalarTableAddress), (uint)(ScalarTableAddress >> 32)],
null);
var ctx = new CpuContext(new FakeCpuMemory(0x1000, 0x100), Generation.Gen5);
lock (FallbackReaderGate)
{
var previousReader = Gen5ShaderScalarEvaluator.FallbackMemoryReader;
try
{
Gen5ShaderScalarEvaluator.FallbackMemoryReader = ReadFallback;
Assert.True(
Gen5ShaderScalarEvaluator.TryEvaluate(
ctx,
state,
out var evaluation,
out var error),
error);
Assert.Equal(expected, evaluation.ScalarRegisters.Skip(16).Take(4));
}
finally
{
Gen5ShaderScalarEvaluator.FallbackMemoryReader = previousReader;
}
}
bool ReadFallback(ulong address, Span<byte> destination)
{
if (address < ScalarTableAddress)
{
return false;
}
var offset = address - ScalarTableAddress;
if (offset + (ulong)destination.Length > (ulong)table.Length)
{
return false;
}
table.AsSpan((int)offset, destination.Length).CopyTo(destination);
return true;
}
}
}