diff --git a/src/dxbc/dxbc_compiler.cpp b/src/dxbc/dxbc_compiler.cpp index 4e2c38e76..dda26782a 100644 --- a/src/dxbc/dxbc_compiler.cpp +++ b/src/dxbc/dxbc_compiler.cpp @@ -3892,6 +3892,26 @@ namespace dxvk { uint32_t killState = m_module.opLoad (typeId, m_ps.killState); killState = m_module.opLogicalOr(typeId, killState, zeroTest.id); m_module.opStore(m_ps.killState, killState); + + if (m_moduleInfo.options.useSubgroupOpsForEarlyDiscard) { + uint32_t killSubgroup = m_module.opGroupNonUniformLogicalAnd( + m_module.defBoolType(), + m_module.constu32(spv::ScopeSubgroup), + spv::GroupOperationReduce, killState, 0); + + DxbcConditional cond; + cond.labelIf = m_module.allocateId(); + cond.labelEnd = m_module.allocateId(); + + m_module.opSelectionMerge(cond.labelEnd, spv::SelectionControlMaskNone); + m_module.opBranchConditional(killSubgroup, cond.labelIf, cond.labelEnd); + + // OpKill terminates the block + m_module.opLabel(cond.labelIf); + m_module.opKill(); + + m_module.opLabel(cond.labelEnd); + } } } @@ -6166,6 +6186,11 @@ namespace dxvk { spv::StorageClassPrivate, m_module.constBool(false)); m_module.setDebugName(m_ps.killState, "ps_kill"); + + if (m_moduleInfo.options.useSubgroupOpsForEarlyDiscard) { + m_module.enableCapability(spv::CapabilityGroupNonUniform); + m_module.enableCapability(spv::CapabilityGroupNonUniformArithmetic); + } } // Main function of the pixel shader diff --git a/src/dxbc/dxbc_options.cpp b/src/dxbc/dxbc_options.cpp index 7829e9ec2..d016ae680 100644 --- a/src/dxbc/dxbc_options.cpp +++ b/src/dxbc/dxbc_options.cpp @@ -11,8 +11,14 @@ namespace dxvk { DxbcOptions::DxbcOptions(const Rc& device) { const DxvkDeviceFeatures& devFeatures = device->features(); - - useStorageImageReadWithoutFormat = devFeatures.core.features.shaderStorageImageReadWithoutFormat; + const DxvkDeviceInfo& devInfo = device->adapter()->devicePropertiesExt(); + + useStorageImageReadWithoutFormat + = devFeatures.core.features.shaderStorageImageReadWithoutFormat; + useSubgroupOpsForEarlyDiscard + = (devInfo.coreSubgroup.subgroupSize >= 4) + && (devInfo.coreSubgroup.supportedStages & VK_SHADER_STAGE_FRAGMENT_BIT) + && (devInfo.coreSubgroup.supportedOperations & VK_SUBGROUP_FEATURE_ARITHMETIC_BIT); } } \ No newline at end of file diff --git a/src/dxbc/dxbc_options.h b/src/dxbc/dxbc_options.h index bb72955c5..02ac012f9 100644 --- a/src/dxbc/dxbc_options.h +++ b/src/dxbc/dxbc_options.h @@ -10,6 +10,10 @@ namespace dxvk { /// Use the ShaderImageReadWithoutFormat capability. bool useStorageImageReadWithoutFormat = false; + + /// Use subgroup operations to discard fragment + /// shader invocations if derivatives remain valid. + bool useSubgroupOpsForEarlyDiscard = false; }; } \ No newline at end of file