sharpemu/tests/SharpEmu.ShaderCompiler.Tests/Gen5ScalarArithmeticShift64...

68 lines
2.7 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.ShaderCompiler.Metal;
using SharpEmu.ShaderCompiler.Tests.Resources;
using SharpEmu.ShaderCompiler.Vulkan;
using Xunit;
using static SharpEmu.ShaderCompiler.Tests.Resources.ResourceTestProgram;
namespace SharpEmu.ShaderCompiler.Tests;
public sealed class Gen5ScalarArithmeticShift64Tests
{
[Fact]
public void DecodeGfx10Encoding()
{
var instruction = Decode(0x91880604);
Assert.Equal("SAshrI64", instruction.Opcode);
Assert.Equal(Gen5ShaderEncoding.Sop2, instruction.Encoding);
Assert.Equal(Gen5Operand.Scalar(4), instruction.Sources[0]);
Assert.Equal(Gen5Operand.Scalar(6), instruction.Sources[1]);
Assert.Equal(Gen5Operand.Scalar(8), Assert.Single(instruction.Destinations));
}
[Fact]
public void CompilesOnBothBackends()
{
var program = Program(
Sop2(0, "SAshrI64", 8, Gen5Operand.Scalar(4), Gen5Operand.Scalar(6)),
EndProgram(4));
var (plan, resources, layout) = Prepare(program);
var request = new ShaderCompileRequest(plan, resources, layout) { LocalSizeX = 1, ThreadCountX = 1 };
Assert.True(Gen5SpirvTranslator.TryCompileProgram(request, out var spirv, out var spirvError), spirvError);
var inspector = new SpirvModuleInspector(spirv.Spirv);
Assert.Contains((ushort)SpirvOp.ShiftRightArithmetic, inspector.Opcodes);
Assert.True(Gen5MslTranslator.TryCompileProgram(request, out var metal, out var metalError), metalError);
Assert.Contains("as_type<long>", metal.Source);
Assert.Contains("& 63u", metal.Source);
}
private static Gen5ShaderInstruction Decode(uint word)
{
var bytes = new byte[8];
BinaryPrimitives.WriteUInt32LittleEndian(bytes, word);
BinaryPrimitives.WriteUInt32LittleEndian(bytes.AsSpan(4), 0xBF810000);
var context = new CpuContext(new InstructionMemory(bytes), Generation.Gen5);
Assert.True(Gen5ShaderTranslator.TryDecodeProgram(context, 0x1000, out var program, out var error), error);
return program.Instructions[0];
}
private sealed class InstructionMemory(byte[] bytes) : ICpuMemory
{
public bool TryRead(ulong address, Span<byte> destination)
{
if (address < 0x1000 || destination.Length > bytes.Length ||
address - 0x1000 > (ulong)(bytes.Length - destination.Length)) return false;
bytes.AsSpan((int)(address - 0x1000), destination.Length).CopyTo(destination);
return true;
}
public bool TryWrite(ulong address, ReadOnlySpan<byte> source) => false;
}
}