From 7c50c319880e57a7fd7e1f4e852010f2c2bc660c Mon Sep 17 00:00:00 2001 From: kuba Date: Tue, 29 Sep 2026 23:19:26 +0200 Subject: [PATCH] [ShaderCompiler] Widen host-evaluable scalar operations for descriptors A resource descriptor the host materializes is built by replaying the shader's scalar operations on the host. The validator that decides whether a value can be replayed listed only part of what the scalar evaluator implements, so a descriptor computed through any of the others was rejected even though the host can compute it exactly. The list now covers every pure scalar function the evaluator supports: the remaining integer maximum, absolute value and high multiplies, the signed and unsigned comparisons, 64-bit equality, the bit-counting and bit-scanning operations, the quad mask, the integer/float conversions, and the float arithmetic and comparisons. Anything with side effects or a lane-varying result is still rejected. --- .../Resources/RuntimeValueValidator.cs | 9 +++++ .../RuntimeValueValidatorTests.cs | 35 +++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 tests/SharpEmu.ShaderCompiler.Tests/RuntimeValueValidatorTests.cs diff --git a/src/SharpEmu.ShaderCompiler/Resources/RuntimeValueValidator.cs b/src/SharpEmu.ShaderCompiler/Resources/RuntimeValueValidator.cs index 7df4bb3..1692f8f 100644 --- a/src/SharpEmu.ShaderCompiler/Resources/RuntimeValueValidator.cs +++ b/src/SharpEmu.ShaderCompiler/Resources/RuntimeValueValidator.cs @@ -49,6 +49,15 @@ public sealed class RuntimeValueValidator ScalarOperation.LogicalOr or ScalarOperation.LogicalAnd or ScalarOperation.LogicalXor or ScalarOperation.LogicalNot or ScalarOperation.FLessThanEqual or ScalarOperation.FGreaterThanEqual or ScalarOperation.FIsNan or ScalarOperation.FMul or ScalarOperation.FTrunc => true, + // Every other pure scalar function ScalarOperationSemantics evaluates is as uniform as the + // ones above; a descriptor built through them was rejected although the host can compute it. + ScalarOperation.UMax32 or ScalarOperation.IAbs32 or ScalarOperation.SMulHi32 or ScalarOperation.UMulHi32 or + ScalarOperation.SLessThan32 or ScalarOperation.SLessThanEqual32 or ScalarOperation.SGreaterThan32 or ScalarOperation.SGreaterThanEqual32 or + ScalarOperation.ULessThanEqual32 or ScalarOperation.UGreaterThanEqual32 or ScalarOperation.IEqual64 or ScalarOperation.INotEqual64 or + ScalarOperation.BitCount32 or ScalarOperation.BitReverse32 or ScalarOperation.FindLowestBit32 or ScalarOperation.FindHighestBit32 or + ScalarOperation.QuadMask32 or ScalarOperation.ConvertF32S32 or ScalarOperation.ConvertS32F32 or + ScalarOperation.FAdd or ScalarOperation.FSub or ScalarOperation.FMin or ScalarOperation.FMax or + ScalarOperation.FEqual or ScalarOperation.FNotEqual or ScalarOperation.FLessThan or ScalarOperation.FGreaterThan => true, _ => false, }; diff --git a/tests/SharpEmu.ShaderCompiler.Tests/RuntimeValueValidatorTests.cs b/tests/SharpEmu.ShaderCompiler.Tests/RuntimeValueValidatorTests.cs new file mode 100644 index 0000000..2b8e30c --- /dev/null +++ b/tests/SharpEmu.ShaderCompiler.Tests/RuntimeValueValidatorTests.cs @@ -0,0 +1,35 @@ +// Copyright (C) 2026 SharpEmu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +using SharpEmu.ShaderCompiler.Resources; +using Xunit; + +namespace SharpEmu.ShaderCompiler.Tests; + +public sealed class RuntimeValueValidatorTests +{ + // The host evaluates runtime descriptor values with ScalarOperationSemantics, so the validator must + // not reject an operation the evaluator can compute (Silent Hill's compute plans failed that way). + [Fact] + public void EveryEvaluableOperationIsAcceptedAsUniform() + { + ulong[] operands = [1, 2, 3, 4]; + foreach (var operation in Enum.GetValues()) + { + bool evaluable; + try + { + evaluable = ScalarOperationSemantics.TryEvaluate(operation, operands, out _); + } + catch (Exception) + { + evaluable = false; + } + + if (evaluable) + { + Assert.True(RuntimeValueValidator.IsUniformOperation(operation), $"{operation} is evaluable but not uniform."); + } + } + } +}