diff --git a/src/dxbc/dxbc_compiler.cpp b/src/dxbc/dxbc_compiler.cpp index 8e89dabbd..79929a713 100644 --- a/src/dxbc/dxbc_compiler.cpp +++ b/src/dxbc/dxbc_compiler.cpp @@ -235,6 +235,9 @@ namespace dxvk { case DxbcProgramType::PixelShader: this->emitPsFinalize(); break; case DxbcProgramType::ComputeShader: this->emitCsFinalize(); break; } + + // Emit float control mode if the extension is supported + this->emitFloatControl(); // Declare the entry point, we now have all the // information we need, including the interfaces @@ -7467,7 +7470,32 @@ namespace dxvk { return varId; } - + + void DxbcCompiler::emitFloatControl() { + DxbcFloatControlFlags flags = m_moduleInfo.options.floatControl; + + if (flags.isClear()) + return; + + const uint32_t width32 = 32; + const uint32_t width64 = 64; + + m_module.enableExtension("SPV_KHR_float_controls"); + + if (flags.test(DxbcFloatControlFlag::DenormFlushToZero32)) + m_module.setExecutionMode(m_entryPointId, spv::ExecutionModeDenormFlushToZero, 1, &width32); + + if (flags.test(DxbcFloatControlFlag::DenormPreserve64)) + m_module.setExecutionMode(m_entryPointId, spv::ExecutionModeDenormPreserve, 1, &width64); + + if (flags.test(DxbcFloatControlFlag::PreserveNan32)) + m_module.setExecutionMode(m_entryPointId, spv::ExecutionModeSignedZeroInfNanPreserve, 1, &width32); + + if (flags.test(DxbcFloatControlFlag::PreserveNan64)) + m_module.setExecutionMode(m_entryPointId, spv::ExecutionModeSignedZeroInfNanPreserve, 1, &width64); + } + + uint32_t DxbcCompiler::emitNewVariable(const DxbcRegisterInfo& info) { const uint32_t ptrTypeId = this->getPointerTypeId(info); return m_module.newVar(ptrTypeId, info.sclass); diff --git a/src/dxbc/dxbc_compiler.h b/src/dxbc/dxbc_compiler.h index 90ed2a1e7..48ff03c76 100644 --- a/src/dxbc/dxbc_compiler.h +++ b/src/dxbc/dxbc_compiler.h @@ -1173,6 +1173,8 @@ namespace dxvk { uint32_t emitSamplePosArray(); + void emitFloatControl(); + /////////////////////////////// // Variable definition methods uint32_t emitNewVariable( diff --git a/src/dxbc/dxbc_options.cpp b/src/dxbc/dxbc_options.cpp index 090ddfa20..5b8cb8d6a 100644 --- a/src/dxbc/dxbc_options.cpp +++ b/src/dxbc/dxbc_options.cpp @@ -57,6 +57,19 @@ namespace dxvk { // Apply shader-related options applyTristate(useSubgroupOpsForEarlyDiscard, device->config().useEarlyDiscard); + + // Figure out float control flags to match D3D11 rules + if (devInfo.khrShaderFloatControls.shaderSignedZeroInfNanPreserveFloat32) + floatControl.set(DxbcFloatControlFlag::PreserveNan32); + if (devInfo.khrShaderFloatControls.shaderSignedZeroInfNanPreserveFloat64) + floatControl.set(DxbcFloatControlFlag::PreserveNan64); + + if (devInfo.khrShaderFloatControls.denormBehaviorIndependence != VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE) { + if (devInfo.khrShaderFloatControls.shaderDenormFlushToZeroFloat32) + floatControl.set(DxbcFloatControlFlag::DenormFlushToZero32); + if (devInfo.khrShaderFloatControls.shaderDenormPreserveFloat64) + floatControl.set(DxbcFloatControlFlag::DenormPreserve64); + } } } \ No newline at end of file diff --git a/src/dxbc/dxbc_options.h b/src/dxbc/dxbc_options.h index 9a4c3c15f..e163656f9 100644 --- a/src/dxbc/dxbc_options.h +++ b/src/dxbc/dxbc_options.h @@ -5,7 +5,16 @@ namespace dxvk { struct D3D11Options; - + + enum class DxbcFloatControlFlag : uint32_t { + DenormFlushToZero32, + DenormPreserve64, + PreserveNan32, + PreserveNan64, + }; + + using DxbcFloatControlFlags = Flags; + struct DxbcOptions { DxbcOptions(); DxbcOptions(const Rc& device, const D3D11Options& options); @@ -48,6 +57,9 @@ namespace dxvk { /// Insert memory barriers after TGSM stoes bool forceTgsmBarriers = false; + /// Float control flags + DxbcFloatControlFlags floatControl; + /// Minimum storage buffer alignment VkDeviceSize minSsboAlignment = 0; }; diff --git a/src/spirv/spirv_module.cpp b/src/spirv/spirv_module.cpp index c4f5e04b5..2ce7ce07c 100644 --- a/src/spirv/spirv_module.cpp +++ b/src/spirv/spirv_module.cpp @@ -93,6 +93,20 @@ namespace dxvk { } + void SpirvModule::setExecutionMode( + uint32_t entryPointId, + spv::ExecutionMode executionMode, + uint32_t argCount, + const uint32_t* args) { + m_execModeInfo.putIns (spv::OpExecutionMode, 3 + argCount); + m_execModeInfo.putWord(entryPointId); + m_execModeInfo.putWord(executionMode); + + for (uint32_t i = 0; i < argCount; i++) + m_execModeInfo.putWord(args[i]); + } + + void SpirvModule::setInvocations( uint32_t entryPointId, uint32_t invocations) { diff --git a/src/spirv/spirv_module.h b/src/spirv/spirv_module.h index 815926d3b..b0f270b24 100644 --- a/src/spirv/spirv_module.h +++ b/src/spirv/spirv_module.h @@ -86,6 +86,12 @@ namespace dxvk { uint32_t entryPointId, spv::ExecutionMode executionMode); + void setExecutionMode( + uint32_t entryPointId, + spv::ExecutionMode executionMode, + uint32_t argCount, + const uint32_t* args); + void setInvocations( uint32_t entryPointId, uint32_t invocations);