From c0b325b4835f22aa821fb8f99d9b3284389a25c9 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Tue, 5 Feb 2019 19:58:46 +0100 Subject: [PATCH] [dxbc] Add option to enable strict sm4-compliat division SM4 is defined to return the first source operand if the divisor is zero. Windows drivers don't do this by default, so we shouldn't do it either. --- src/d3d11/d3d11_options.cpp | 1 + src/d3d11/d3d11_options.h | 5 +++++ src/dxbc/dxbc_compiler.cpp | 15 +++++++++++++++ src/dxbc/dxbc_options.cpp | 1 + src/dxbc/dxbc_options.h | 3 +++ 5 files changed, 25 insertions(+) diff --git a/src/d3d11/d3d11_options.cpp b/src/d3d11/d3d11_options.cpp index 5ffdedc16..aa827ca41 100644 --- a/src/d3d11/d3d11_options.cpp +++ b/src/d3d11/d3d11_options.cpp @@ -7,6 +7,7 @@ namespace dxvk { D3D11Options::D3D11Options(const Config& config) { this->allowMapFlagNoWait = config.getOption("d3d11.allowMapFlagNoWait", false); this->dcSingleUseMode = config.getOption("d3d11.dcSingleUseMode", true); + this->strictDivision = config.getOption("d3d11.strictDivision", false); this->zeroInitWorkgroupMemory = config.getOption("d3d11.zeroInitWorkgroupMemory", false); this->maxTessFactor = config.getOption("d3d11.maxTessFactor", 0); this->samplerAnisotropy = config.getOption("d3d11.samplerAnisotropy", -1); diff --git a/src/d3d11/d3d11_options.h b/src/d3d11/d3d11_options.h index 6558cd6d6..58d32341f 100644 --- a/src/d3d11/d3d11_options.h +++ b/src/d3d11/d3d11_options.h @@ -25,6 +25,11 @@ namespace dxvk { /// than once. bool dcSingleUseMode; + /// Enables sm4-compliant division-by-zero behaviour + /// Windows drivers don't normally do this, but some + /// games may expect correct behaviour. + bool strictDivision; + /// Zero-initialize workgroup memory /// /// Workargound for games that don't initialize diff --git a/src/dxbc/dxbc_compiler.cpp b/src/dxbc/dxbc_compiler.cpp index e3f1a5b85..1225b45c0 100644 --- a/src/dxbc/dxbc_compiler.cpp +++ b/src/dxbc/dxbc_compiler.cpp @@ -1519,6 +1519,21 @@ namespace dxvk { break; case DxbcOpcode::Div: + dst.id = m_module.opFDiv(typeId, + src.at(0).id, src.at(1).id); + + if (m_moduleInfo.options.strictDivision) { + uint32_t boolType = dst.type.ccount > 1 + ? m_module.defVectorType(m_module.defBoolType(), dst.type.ccount) + : m_module.defBoolType(); + + dst.id = m_module.opSelect(typeId, + m_module.opFOrdNotEqual(boolType, src.at(1).id, + emitBuildConstVecf32(0.0f, 0.0f, 0.0f, 0.0f, ins.dst[0].mask).id), + dst.id, src.at(0).id); + } + break; + case DxbcOpcode::DDiv: dst.id = m_module.opFDiv(typeId, src.at(0).id, src.at(1).id); diff --git a/src/dxbc/dxbc_options.cpp b/src/dxbc/dxbc_options.cpp index 12f1c39f4..940119d4b 100644 --- a/src/dxbc/dxbc_options.cpp +++ b/src/dxbc/dxbc_options.cpp @@ -24,6 +24,7 @@ namespace dxvk { useRawSsbo = (devInfo.core.properties.limits.minStorageBufferOffsetAlignment <= sizeof(uint32_t)); + strictDivision = options.strictDivision; zeroInitWorkgroupMemory = options.zeroInitWorkgroupMemory; // Disable early discard on RADV due to GPU hangs diff --git a/src/dxbc/dxbc_options.h b/src/dxbc/dxbc_options.h index 85cbf327b..b569398fd 100644 --- a/src/dxbc/dxbc_options.h +++ b/src/dxbc/dxbc_options.h @@ -21,6 +21,9 @@ namespace dxvk { /// for raw and structured buffers. bool useRawSsbo = false; + /// Enables sm4-compliant division-by-zero behaviour + bool strictDivision = false; + /// Clear thread-group shared memory to zero bool zeroInitWorkgroupMemory = false; };