mirror of
https://github.com/par274/sharpemu.git
synced 2026-09-01 22:31:17 +08:00
[shader] add scalar memory fallback
This commit is contained in:
@@ -27,7 +27,7 @@ internal static class AgcShaderCompilerHooks
|
|||||||
internal static void Install()
|
internal static void Install()
|
||||||
{
|
{
|
||||||
Gen5ShaderScalarEvaluator.FallbackMemoryReader =
|
Gen5ShaderScalarEvaluator.FallbackMemoryReader =
|
||||||
KernelMemoryCompatExports.TryReadTrackedLibcHeap;
|
KernelMemoryCompatExports.TryReadShaderGuestMemory;
|
||||||
Gen5ShaderScalarEvaluator.GlobalMemoryPool =
|
Gen5ShaderScalarEvaluator.GlobalMemoryPool =
|
||||||
GuestDataPool.Shared;
|
GuestDataPool.Shared;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2350,7 +2350,8 @@ public static class Gen5ShaderScalarEvaluator
|
|||||||
private static bool TryReadUInt32(CpuContext ctx, ulong address, out uint value)
|
private static bool TryReadUInt32(CpuContext ctx, ulong address, out uint value)
|
||||||
{
|
{
|
||||||
Span<byte> bytes = stackalloc byte[sizeof(uint)];
|
Span<byte> bytes = stackalloc byte[sizeof(uint)];
|
||||||
if (!ctx.Memory.TryRead(address, bytes))
|
if (!ctx.Memory.TryRead(address, bytes) &&
|
||||||
|
FallbackMemoryReader?.Invoke(address, bytes) != true)
|
||||||
{
|
{
|
||||||
value = 0;
|
value = 0;
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user