sharpemu/tests/SharpEmu.Libs.Tests/Gpu/Vulkan/NativeHalfConversionProbeDe...

65 lines
2.9 KiB
C#

// Copyright (C) 2026 SharpEmu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
using SharpEmu.Libs.Gpu.Vulkan;
using SharpEmu.Libs.Tests.Gpu.Images;
using Silk.NET.Vulkan;
using Xunit;
using Xunit.Abstractions;
namespace SharpEmu.Libs.Tests.Gpu.Vulkan;
public sealed class NativeHalfConversionProbeDeviceTests(HeadlessVulkanFixture fixture, ITestOutputHelper output)
: IClassFixture<HeadlessVulkanFixture>
{
// The probe is what decides whether the translator may use GLSL UnpackHalf2x16 /
// PackHalf2x16, so the gate is that it completes and reports a count - not that this
// device passes it. The verdict goes to the test output, where a port to another GPU
// can read it.
[Fact]
public void ProbeRunsAndReportsWhetherNativeHalfConversionIsExact()
{
var vulkan = fixture.Vulkan;
if (!GatePrerequisites.Ready(vulkan)) return;
using var harness = new ImageTestHarness(vulkan);
var result = default(NativeHalfConversionProbe.Result);
harness.Run(() => result = NativeHalfConversionProbe.Run(
harness.Device,
harness.Scheduler,
() => new CommandBuffer(harness.Scheduler.Current.Handle)));
output.WriteLine(
$"[VK][F16] native half conversion exact={result.Exact} mismatches={result.Mismatches} " +
$"tested={result.Tested} device={vulkan.DeviceName} first={result.Detail}");
Assert.Null(result.Note);
Assert.True(result.Tested >= 2 * 0x1_0000, $"tested={result.Tested}");
Assert.InRange(result.Mismatches, 0, result.Tested);
Assert.Equal(result.Mismatches == 0, result.Exact);
harness.AssertNoValidationMessages();
}
// Every test vector must agree with System.Half, which is what proves the integer
// sequences the probe compares against are the right reference in the first place.
[Fact]
public void ReferenceConversionsMatchSystemHalfForEveryTestVector()
{
foreach (var value in HalfConversionReference.BuildTestVectors())
{
var half = BitConverter.UInt16BitsToHalf((ushort)value);
var widened = BitConverter.SingleToUInt32Bits((float)half);
var wide = HalfConversionReference.HalfToFloatBits(value & 0xFFFFu);
Assert.True(
HalfConversionReference.Matches(widened, wide, asHalf: false),
$"half 0x{value & 0xFFFF:X4} widened to 0x{wide:X8}, System.Half says 0x{widened:X8}");
var single = BitConverter.UInt32BitsToSingle(value);
var narrowed = BitConverter.HalfToUInt16Bits((Half)single);
var narrow = HalfConversionReference.FloatToHalfBits(value);
Assert.True(
HalfConversionReference.Matches(narrowed, narrow, asHalf: true),
$"float 0x{value:X8} narrowed to 0x{narrow:X4}, System.Half says 0x{narrowed:X4}");
}
}
}