From b015cf0bb23c669496379a265dc40170dfb793aa Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Tue, 22 Mar 2022 17:32:43 +0100 Subject: [PATCH] [dxbc] Support switch-case fallthrough Apparently this is a thing in Shader Model 4, although FXC cannot emit it. --- src/dxbc/dxbc_compiler.cpp | 37 ++++++++++++++++++++++++++++++------- src/dxbc/dxbc_compiler.h | 7 ++++++- 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/src/dxbc/dxbc_compiler.cpp b/src/dxbc/dxbc_compiler.cpp index 27afccaa..78d5284f 100644 --- a/src/dxbc/dxbc_compiler.cpp +++ b/src/dxbc/dxbc_compiler.cpp @@ -70,6 +70,9 @@ namespace dxvk { void DxbcCompiler::processInstruction(const DxbcShaderInstruction& ins) { + m_lastOp = m_currOp; + m_currOp = ins.op; + switch (ins.opClass) { case DxbcInstClass::Declaration: return this->emitDcl(ins); @@ -3877,12 +3880,17 @@ namespace dxvk { // The source operand must be a 32-bit immediate. if (ins.src[0].type != DxbcOperandType::Imm32) throw DxvkError("DxbcCompiler: Invalid operand type for 'Case'"); - - // Use the last label allocated for 'case'. The block starting - // with that label is guaranteed to be empty unless a previous - // 'case' block was not properly closed in the DXBC shader. + + // Use the last label allocated for 'case'. DxbcCfgBlockSwitch* block = &m_controlFlowBlocks.back().b_switch; - + + if (caseBlockIsFallthrough()) { + block->labelCase = m_module.allocateId(); + + m_module.opBranch(block->labelCase); + m_module.opLabel (block->labelCase); + } + DxbcSwitchLabel label; label.desc.literal = ins.src[0].imm.u32_1; label.desc.labelId = block->labelCase; @@ -3896,9 +3904,17 @@ namespace dxvk { || m_controlFlowBlocks.back().type != DxbcCfgBlockType::Switch) throw DxvkError("DxbcCompiler: 'Default' without 'Switch' found"); + DxbcCfgBlockSwitch* block = &m_controlFlowBlocks.back().b_switch; + + if (caseBlockIsFallthrough()) { + block->labelCase = m_module.allocateId(); + + m_module.opBranch(block->labelCase); + m_module.opLabel (block->labelCase); + } + // Set the last label allocated for 'case' as the default label. - m_controlFlowBlocks.back().b_switch.labelDefault - = m_controlFlowBlocks.back().b_switch.labelCase; + block->labelDefault = block->labelCase; } @@ -7802,6 +7818,13 @@ namespace dxvk { return result; } + bool DxbcCompiler::caseBlockIsFallthrough() const { + return m_lastOp != DxbcOpcode::Case + && m_lastOp != DxbcOpcode::Break + && m_lastOp != DxbcOpcode::Ret; + } + + uint32_t DxbcCompiler::getScalarTypeId(DxbcScalarType type) { if (type == DxbcScalarType::Float64) m_module.enableCapability(spv::CapabilityFloat64); diff --git a/src/dxbc/dxbc_compiler.h b/src/dxbc/dxbc_compiler.h index 2404642e..464b2a2a 100644 --- a/src/dxbc/dxbc_compiler.h +++ b/src/dxbc/dxbc_compiler.h @@ -543,6 +543,9 @@ namespace dxvk { // Global state stuff bool m_precise = true; + DxbcOpcode m_lastOp = DxbcOpcode::Nop; + DxbcOpcode m_currOp = DxbcOpcode::Nop; + ///////////////////////////////////////////////////// // Shader interface and metadata declaration methods void emitDcl( @@ -1238,7 +1241,9 @@ namespace dxvk { DxbcRegisterPointer getIndexableTempPtr( const DxbcRegister& operand, DxbcRegisterValue vectorId); - + + bool caseBlockIsFallthrough() const; + /////////////////////////// // Type definition methods uint32_t getScalarTypeId(