107 lines
4.8 KiB
C#
107 lines
4.8 KiB
C#
// Copyright (C) 2026 SharpEmu Emulator Project
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
using SharpEmu.Libs.Gpu.GpuCommands.Registers;
|
|
using SharpEmu.Libs.Gpu.Pipelines;
|
|
using SharpEmu.Libs.Gpu.Rendering;
|
|
using SharpEmu.Libs.Tests.Gpu.Scheduling;
|
|
using SharpEmu.ShaderCompiler.Resources;
|
|
using Xunit;
|
|
|
|
namespace SharpEmu.Libs.Tests.Gpu.Pipelines;
|
|
|
|
[Collection(SchedulingStateCollection.Name)]
|
|
public sealed class GraphicsRejectionPolicyTests
|
|
{
|
|
private const ulong VertexAddress = PipelineTestGuest.MemoryBase + 0x1000;
|
|
private const ulong PixelAddress = PipelineTestGuest.MemoryBase + 0x2000;
|
|
private const ulong TableAddress = PipelineTestGuest.MemoryBase + 0x40000;
|
|
|
|
[Theory]
|
|
[InlineData(null, false)]
|
|
[InlineData("0", false)]
|
|
[InlineData("1", false)]
|
|
[InlineData(null, true)]
|
|
[InlineData("0", true)]
|
|
[InlineData("1", true)]
|
|
[InlineData("invalid", false)]
|
|
[InlineData("invalid", true)]
|
|
public void GraphicsCompilationUsesTheSameStrictSwitch(string? setting, bool pixelActive)
|
|
{
|
|
var previous = Environment.GetEnvironmentVariable("SHARPEMU_STRICT_COMPUTE");
|
|
try
|
|
{
|
|
Environment.SetEnvironmentVariable("SHARPEMU_STRICT_COMPUTE", setting);
|
|
using var fatal = new FatalScope();
|
|
var guest = new PipelineTestGuest();
|
|
guest.RegisterProgram(VertexAddress, PipelineTestGuest.MemoryBase + 0x8000, PipelineTestGuest.EndProgram,
|
|
userDataAddress: PipelineTestGuest.MemoryBase + 0x9000);
|
|
guest.RegisterProgram(PixelAddress, PipelineTestGuest.MemoryBase + 0x8100, PipelineTestGuest.EndProgram,
|
|
userDataAddress: PipelineTestGuest.MemoryBase + 0xA000);
|
|
guest.Compiler.Rejection = "The test instruction is not supported.";
|
|
var cache = new ShaderPipelineCache(guest.Context, guest.Host, guest.Compiler, guest.Registry);
|
|
GraphicsPrograms Lookup() => cache.GetGraphicsPrograms(
|
|
new VertexStageRegisters { ExportAddress = VertexAddress }, new PixelStageRegisters { Address = PixelAddress },
|
|
new ShaderInterfaceRegisters(), new ContextRegisters(), [], pixelActive, depthBound: false);
|
|
if (setting != "0")
|
|
Assert.Contains("cannot be compiled", Assert.Throws<SchedulerFatalException>(() => Lookup()).Message);
|
|
else Assert.False(Lookup().Available);
|
|
Assert.Empty(guest.Host.Modules);
|
|
Assert.Empty(guest.Host.GraphicsPipelines);
|
|
if (setting == "0")
|
|
{
|
|
guest.Compiler.Rejection = null;
|
|
Assert.True(Lookup().Available);
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
Environment.SetEnvironmentVariable("SHARPEMU_STRICT_COMPUTE", previous);
|
|
}
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(false, false)]
|
|
[InlineData(true, false)]
|
|
[InlineData(false, true)]
|
|
[InlineData(true, true)]
|
|
public void PixelCandidateValidationHonorsCapacityAndStrictMode(bool strict, bool distinctCandidates)
|
|
{
|
|
using var fatal = new FatalScope();
|
|
var guest = new PipelineTestGuest();
|
|
guest.RegisterProgram(PixelAddress, PipelineTestGuest.MemoryBase + 0x8100,
|
|
[0x7E240500, 0xBE931312, 0x8F6A8513, 0xB7EA0158, 0xF40C0100, 0xD4000000,
|
|
0xF0000108, 0x00010400, 0xBF810000]);
|
|
for (var index = 0; index < 33; index++)
|
|
guest.WriteWords(TableAddress + 312 + (ulong)index * 32,
|
|
distinctCandidates ? 0x1000u + (uint)index : 0x1000u, 20u << 20, 0,
|
|
0xFACu | ((!distinctCandidates && index == 1 ? 10u : 9u) << 28), 0, 0, 0, 0);
|
|
var source = guest.Source(PixelAddress, ShaderStage.Pixel, [(uint)(TableAddress & uint.MaxValue), (uint)(TableAddress >> 32)]);
|
|
var options = new StageCompileOptions { PixelInfo = new PixelInputInfo() };
|
|
var cursor = 7u;
|
|
if (distinctCandidates)
|
|
{
|
|
Assert.True(guest.Programs.TryGetProgram(source, options, strict, ref cursor, out var program, out _, out var rejection), rejection);
|
|
Assert.True(program.IsValid);
|
|
Assert.Single(guest.Compiler.Requests);
|
|
Assert.Single(guest.Host.Modules);
|
|
return;
|
|
}
|
|
if (strict)
|
|
{
|
|
var failure = Assert.Throws<SchedulerFatalException>(() => guest.Programs.TryGetProgram(
|
|
source, options, true, ref cursor, out _, out _, out _));
|
|
Assert.Contains("could not be materialized", failure.Message);
|
|
}
|
|
else
|
|
{
|
|
Assert.False(guest.Programs.TryGetProgram(source, options, false, ref cursor, out var program, out _, out var rejection));
|
|
Assert.False(program.IsValid);
|
|
Assert.Contains("could not be materialized", rejection);
|
|
}
|
|
Assert.Equal(7u, cursor);
|
|
Assert.Empty(guest.Compiler.Requests);
|
|
Assert.Empty(guest.Host.Modules);
|
|
}
|
|
}
|