mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-29 06:16:55 +01:00
shader: evaluate saturating float-to-signed conversions in runtime descriptor values
This commit is contained in:
@@ -82,6 +82,7 @@ bool IsRuntimeUniformOp(ValueOpcode op) {
|
|||||||
case ValueOpcode::BitCastU32F32:
|
case ValueOpcode::BitCastU32F32:
|
||||||
case ValueOpcode::BitCastF32U32:
|
case ValueOpcode::BitCastF32U32:
|
||||||
case ValueOpcode::ConvertU32F32:
|
case ValueOpcode::ConvertU32F32:
|
||||||
|
case ValueOpcode::ConvertS32F32:
|
||||||
case ValueOpcode::ConvertF32U32:
|
case ValueOpcode::ConvertF32U32:
|
||||||
case ValueOpcode::CompositeConstructU64:
|
case ValueOpcode::CompositeConstructU64:
|
||||||
case ValueOpcode::CompositeExtractU64:
|
case ValueOpcode::CompositeExtractU64:
|
||||||
@@ -1038,6 +1039,23 @@ void WalkerCompiler::EmitStrict(const Node& node) {
|
|||||||
c.L(done);
|
c.L(done);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case ValueOpcode::ConvertS32F32: {
|
||||||
|
// The conversion saturates and maps NaN to zero. cvttss2si's out-of-range result,
|
||||||
|
// INT32_MIN, is already right for negative overflow.
|
||||||
|
Xbyak::Label done;
|
||||||
|
c.movd(c.xmm0, c.eax);
|
||||||
|
c.xor_(c.eax, c.eax);
|
||||||
|
c.ucomiss(c.xmm0, c.xmm0);
|
||||||
|
c.jp(done, Near);
|
||||||
|
c.mov(c.ecx, 0x4f000000u);
|
||||||
|
c.movd(c.xmm1, c.ecx);
|
||||||
|
c.mov(c.eax, INT32_MAX);
|
||||||
|
c.ucomiss(c.xmm0, c.xmm1);
|
||||||
|
c.jae(done, Near);
|
||||||
|
c.cvttss2si(c.eax, c.xmm0);
|
||||||
|
c.L(done);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case ValueOpcode::FPMul32:
|
case ValueOpcode::FPMul32:
|
||||||
c.movd(c.xmm0, c.eax);
|
c.movd(c.xmm0, c.eax);
|
||||||
c.movd(c.xmm1, c.ecx);
|
c.movd(c.xmm1, c.ecx);
|
||||||
|
|||||||
@@ -515,6 +515,34 @@ void TestFloatComparisonDescriptorInputs() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestSignedConversionDescriptorInputs() {
|
||||||
|
// 3.75 and -3.75 truncate, the largest float below 2^31 converts exactly, 2^31 and +inf
|
||||||
|
// saturate up, -2^31 and -1e10 saturate down, and -0.0, a denormal and both NaNs read zero.
|
||||||
|
constexpr std::array<std::pair<uint32_t, uint32_t>, 11> inputs = {{
|
||||||
|
{0x40700000u, 3u}, {0xc0700000u, 0xfffffffdu}, {0x4effffffu, 0x7fffff80u},
|
||||||
|
{0x4f000000u, 0x7fffffffu}, {0x7f800000u, 0x7fffffffu}, {0xcf000000u, 0x80000000u},
|
||||||
|
{0xd01502f9u, 0x80000000u}, {0x80000000u, 0u}, {0x00000001u, 0u},
|
||||||
|
{0x7fc00000u, 0u}, {0xffc00000u, 0u}}};
|
||||||
|
Fixture fixture;
|
||||||
|
const auto user = fixture.Emit(
|
||||||
|
ValueOpcode::GetUserData, {Value(static_cast<ScalarReg>(2))});
|
||||||
|
const auto converted = fixture.Emit(
|
||||||
|
ValueOpcode::ConvertS32F32, {fixture.Emit(ValueOpcode::BitCastF32U32, {user})});
|
||||||
|
Check(ValidateRuntimeValue(fixture.program, converted),
|
||||||
|
"signed float conversion was rejected as a runtime value");
|
||||||
|
fixture.program.descriptor_sources.push_back(
|
||||||
|
{.dwords = {converted}, .dword_count = 1});
|
||||||
|
|
||||||
|
auto plan = ExtractResourcePlan(fixture.program);
|
||||||
|
for (const auto [bits, expected] : inputs) {
|
||||||
|
const std::array user_data{bits};
|
||||||
|
DescriptorValue result;
|
||||||
|
Check(EvaluateSource(plan, {.user_data = user_data}, 0, result) &&
|
||||||
|
result.dwords[0] == expected,
|
||||||
|
"descriptor signed conversion disagrees with the native conversion");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void TestSharedIntegerRuntimeDependencies() {
|
void TestSharedIntegerRuntimeDependencies() {
|
||||||
Fixture fixture;
|
Fixture fixture;
|
||||||
const auto lane = fixture.Emit(ValueOpcode::LaneId);
|
const auto lane = fixture.Emit(ValueOpcode::LaneId);
|
||||||
@@ -888,6 +916,7 @@ int main() {
|
|||||||
TestRuntime64BitDescriptorOps();
|
TestRuntime64BitDescriptorOps();
|
||||||
TestUniformFirstLaneSamplerLod();
|
TestUniformFirstLaneSamplerLod();
|
||||||
TestFloatComparisonDescriptorInputs();
|
TestFloatComparisonDescriptorInputs();
|
||||||
|
TestSignedConversionDescriptorInputs();
|
||||||
TestSharedIntegerRuntimeDependencies();
|
TestSharedIntegerRuntimeDependencies();
|
||||||
TestConstantBufferBounds();
|
TestConstantBufferBounds();
|
||||||
TestReadLaneElimination();
|
TestReadLaneElimination();
|
||||||
|
|||||||
Reference in New Issue
Block a user