diff --git a/src/dxbc/dxbc_compiler.cpp b/src/dxbc/dxbc_compiler.cpp index 1bd7f36d..9f6744d9 100644 --- a/src/dxbc/dxbc_compiler.cpp +++ b/src/dxbc/dxbc_compiler.cpp @@ -276,7 +276,7 @@ namespace dxvk { void DxbcCompiler::emitDclGlobalFlags(const DxbcShaderInstruction& ins) { - const DxbcGlobalFlags flags = ins.controls.globalFlags; + const DxbcGlobalFlags flags = ins.controls.globalFlags(); if (flags.test(DxbcGlobalFlag::EarlyFragmentTests)) m_module.setExecutionMode(m_entryPointId, spv::ExecutionModeEarlyFragmentTests); @@ -387,7 +387,7 @@ namespace dxvk { DxbcInterpolationMode im = DxbcInterpolationMode::Undefined; if (hasInterpolationMode) - im = ins.controls.interpolation; + im = ins.controls.interpolation(); // Declare the actual input/output variable switch (ins.op) { @@ -766,7 +766,7 @@ namespace dxvk { } // Defines the type of the resource (texture2D, ...) - const DxbcResourceDim resourceType = ins.controls.resourceDim; + const DxbcResourceDim resourceType = ins.controls.resourceDim(); // Defines the type of a read operation. DXBC has the ability // to define four different types whereas SPIR-V only allows @@ -871,7 +871,7 @@ namespace dxvk { m_module.decorateDescriptorSet(varId, 0); m_module.decorateBinding(varId, bindingId); - if (ins.controls.uavFlags.test(DxbcUavFlag::GloballyCoherent)) + if (ins.controls.uavFlags().test(DxbcUavFlag::GloballyCoherent)) m_module.decorate(varId, spv::DecorationCoherent); // Declare a specialization constant which will @@ -992,7 +992,7 @@ namespace dxvk { m_module.decorateDescriptorSet(varId, 0); m_module.decorateBinding(varId, bindingId); - if (ins.controls.uavFlags.test(DxbcUavFlag::GloballyCoherent)) + if (ins.controls.uavFlags().test(DxbcUavFlag::GloballyCoherent)) m_module.decorate(varId, spv::DecorationCoherent); // Declare a specialization constant which will @@ -1083,7 +1083,7 @@ namespace dxvk { // control bits of the opcode token. In SPIR-V, we // have to define an execution mode. const spv::ExecutionMode mode = [&] { - switch (ins.controls.primitive) { + switch (ins.controls.primitive()) { case DxbcPrimitive::Point: return spv::ExecutionModeInputPoints; case DxbcPrimitive::Line: return spv::ExecutionModeInputLines; case DxbcPrimitive::Triangle: return spv::ExecutionModeTriangles; @@ -1093,7 +1093,7 @@ namespace dxvk { } }(); - m_gs.inputPrimitive = ins.controls.primitive; + m_gs.inputPrimitive = ins.controls.primitive(); m_module.setExecutionMode(m_entryPointId, mode); const uint32_t vertexCount @@ -1109,7 +1109,7 @@ namespace dxvk { // control bits of the opcode token. In SPIR-V, we have // to define an execution mode. const spv::ExecutionMode mode = [&] { - switch (ins.controls.primitiveTopology) { + switch (ins.controls.primitiveTopology()) { case DxbcPrimitiveTopology::PointList: return spv::ExecutionModeOutputPoints; case DxbcPrimitiveTopology::LineStrip: return spv::ExecutionModeOutputLineStrip; case DxbcPrimitiveTopology::TriangleStrip: return spv::ExecutionModeOutputTriangleStrip; @@ -1134,11 +1134,11 @@ namespace dxvk { // dcl_input_control_points has the control point // count embedded within the opcode token. if (m_version.type() == DxbcProgramType::HullShader) { - m_hs.vertexCountIn = ins.controls.controlPointCount; + m_hs.vertexCountIn = ins.controls.controlPointCount(); emitDclInputArray(m_hs.vertexCountIn); } else { - m_ds.vertexCountIn = ins.controls.controlPointCount; + m_ds.vertexCountIn = ins.controls.controlPointCount(); m_ds.inputPerPatch = emitTessInterfacePerPatch (spv::StorageClassInput); m_ds.inputPerVertex = emitTessInterfacePerVertex(spv::StorageClassInput, m_ds.vertexCountIn); @@ -1149,12 +1149,12 @@ namespace dxvk { void DxbcCompiler::emitDclOutputControlPointCount(const DxbcShaderInstruction& ins) { // dcl_output_control_points has the control point // count embedded within the opcode token. - m_hs.vertexCountOut = ins.controls.controlPointCount; + m_hs.vertexCountOut = ins.controls.controlPointCount(); m_hs.outputPerPatch = emitTessInterfacePerPatch (spv::StorageClassOutput); m_hs.outputPerVertex = emitTessInterfacePerVertex(spv::StorageClassOutput, m_hs.vertexCountOut); - m_module.setOutputVertices(m_entryPointId, ins.controls.controlPointCount); + m_module.setOutputVertices(m_entryPointId, m_hs.vertexCountOut); } @@ -1165,7 +1165,7 @@ namespace dxvk { void DxbcCompiler::emitDclTessDomain(const DxbcShaderInstruction& ins) { const spv::ExecutionMode executionMode = [&] { - switch (ins.controls.tessDomain) { + switch (ins.controls.tessDomain()) { case DxbcTessDomain::Isolines: return spv::ExecutionModeIsolines; case DxbcTessDomain::Triangles: return spv::ExecutionModeTriangles; case DxbcTessDomain::Quads: return spv::ExecutionModeQuads; @@ -1179,7 +1179,7 @@ namespace dxvk { void DxbcCompiler::emitDclTessPartitioning(const DxbcShaderInstruction& ins) { const spv::ExecutionMode executionMode = [&] { - switch (ins.controls.tessPartitioning) { + switch (ins.controls.tessPartitioning()) { case DxbcTessPartitioning::Pow2: case DxbcTessPartitioning::Integer: return spv::ExecutionModeSpacingEqual; case DxbcTessPartitioning::FractOdd: return spv::ExecutionModeSpacingFractionalOdd; @@ -1193,7 +1193,7 @@ namespace dxvk { void DxbcCompiler::emitDclTessOutputPrimitive(const DxbcShaderInstruction& ins) { - switch (ins.controls.tessOutputPrimitive) { + switch (ins.controls.tessOutputPrimitive()) { case DxbcTessOutputPrimitive::Point: m_module.setExecutionMode(m_entryPointId, spv::ExecutionModePointMode); break; @@ -2184,7 +2184,7 @@ namespace dxvk { void DxbcCompiler::emitBarrier(const DxbcShaderInstruction& ins) { // sync takes no operands. Instead, the synchronization // scope is defined by the operand control bits. - const DxbcSyncFlags flags = ins.controls.syncFlags; + const DxbcSyncFlags flags = ins.controls.syncFlags(); uint32_t executionScope = spv::ScopeInvocation; uint32_t memoryScope = spv::ScopeInvocation; @@ -2572,7 +2572,7 @@ namespace dxvk { // (src1) Resource to query // TODO Check if resource is bound const DxbcBufferInfo resourceInfo = getBufferInfo(ins.src[1]); - const DxbcResinfoType resinfoType = ins.controls.resinfoType; + const DxbcResinfoType resinfoType = ins.controls.resinfoType(); // Read the exact LOD for the image query const DxbcRegisterValue mipLod = emitRegisterLoad( @@ -2709,7 +2709,7 @@ namespace dxvk { // TODO Check if resource is bound DxbcRegisterValue sampleCount = emitQueryTextureSamples(ins.src[0]); - if (ins.controls.returnType != DxbcInstructionReturnType::Uint) { + if (ins.controls.returnType() != DxbcInstructionReturnType::Uint) { sampleCount.type = { DxbcScalarType::Float32, 1 }; sampleCount.id = m_module.opConvertUtoF( getVectorTypeId(sampleCount.type), @@ -3250,7 +3250,7 @@ namespace dxvk { ins.src[0], DxbcRegMask(true, false, false, false)); const DxbcRegisterValue zeroTest = emitRegisterZeroTest( - condition, ins.controls.zeroTest); + condition, ins.controls.zeroTest()); // Declare the 'if' block. We do not know if there // will be an 'else' block or not, so we'll assume @@ -3508,7 +3508,7 @@ namespace dxvk { ins.src[0], DxbcRegMask(true, false, false, false)); const DxbcRegisterValue zeroTest = emitRegisterZeroTest( - condition, ins.controls.zeroTest); + condition, ins.controls.zeroTest()); // We basically have to wrap this into an 'if' block const uint32_t breakBlock = m_module.allocateId(); @@ -3551,7 +3551,7 @@ namespace dxvk { ins.src[0], DxbcRegMask(true, false, false, false)); const DxbcRegisterValue zeroTest = emitRegisterZeroTest( - condition, ins.controls.zeroTest); + condition, ins.controls.zeroTest()); // We basically have to wrap this into an 'if' block const uint32_t returnLabel = m_module.allocateId(); @@ -3578,7 +3578,7 @@ namespace dxvk { ins.src[0], DxbcRegMask(true, false, false, false)); const DxbcRegisterValue zeroTest = emitRegisterZeroTest( - condition, ins.controls.zeroTest); + condition, ins.controls.zeroTest()); // Insert a Pseudo-'If' block const uint32_t discardBlock = m_module.allocateId(); diff --git a/src/dxbc/dxbc_decoder.cpp b/src/dxbc/dxbc_decoder.cpp index e1fcf6a3..fae59c81 100644 --- a/src/dxbc/dxbc_decoder.cpp +++ b/src/dxbc/dxbc_decoder.cpp @@ -107,37 +107,7 @@ namespace dxvk { // Opcode controls. It will depend on the // opcode itself which ones are valid. - // TODO refactor this nonsense - m_instruction.controls.returnType = - static_cast(bit::extract(token, 11, 11)); - m_instruction.controls.globalFlags = - static_cast(bit::extract(token, 11, 14)); - m_instruction.controls.zeroTest = - static_cast(bit::extract(token, 18, 18)); - m_instruction.controls.syncFlags = - static_cast(bit::extract(token, 11, 14)); - m_instruction.controls.resourceDim = - static_cast(bit::extract(token, 11, 15)); - m_instruction.controls.resinfoType = - static_cast(bit::extract(token, 11, 12)); - m_instruction.controls.interpolation = - static_cast(bit::extract(token, 11, 14)); - m_instruction.controls.samplerMode = - static_cast(bit::extract(token, 11, 14)); - m_instruction.controls.primitiveTopology = - static_cast(bit::extract(token, 11, 17)); - m_instruction.controls.primitive = - static_cast(bit::extract(token, 11, 16)); - m_instruction.controls.tessDomain = - static_cast(bit::extract(token, 11, 12)); - m_instruction.controls.tessOutputPrimitive = - static_cast(bit::extract(token, 11, 13)); - m_instruction.controls.tessPartitioning = - static_cast(bit::extract(token, 11, 13)); - m_instruction.controls.uavFlags = - static_cast(bit::extract(token, 16, 16)); - m_instruction.controls.controlPointCount = - static_cast(bit::extract(token, 11, 16)); + m_instruction.controls = DxbcShaderOpcodeControls(token); // Process extended opcode tokens while (bit::extract(token, 31, 31)) { diff --git a/src/dxbc/dxbc_decoder.h b/src/dxbc/dxbc_decoder.h index dd9cc9dd..9ddf3586 100644 --- a/src/dxbc/dxbc_decoder.h +++ b/src/dxbc/dxbc_decoder.h @@ -239,22 +239,80 @@ namespace dxvk { * Instruction-specific controls. Usually, * only one of the members will be valid. */ - struct DxbcShaderOpcodeControls { - DxbcInstructionReturnType returnType; - DxbcGlobalFlags globalFlags; - DxbcZeroTest zeroTest; - DxbcSyncFlags syncFlags; - DxbcResourceDim resourceDim; - DxbcResinfoType resinfoType; - DxbcInterpolationMode interpolation; - DxbcSamplerMode samplerMode; - DxbcPrimitiveTopology primitiveTopology; - DxbcPrimitive primitive; - DxbcTessDomain tessDomain; - DxbcTessOutputPrimitive tessOutputPrimitive; - DxbcTessPartitioning tessPartitioning; - DxbcUavFlags uavFlags; - uint32_t controlPointCount; + class DxbcShaderOpcodeControls { + + public: + + DxbcShaderOpcodeControls() + : m_bits(0) { } + + DxbcShaderOpcodeControls(uint32_t bits) + : m_bits(bits) { } + + DxbcInstructionReturnType returnType() const { + return DxbcInstructionReturnType(bit::extract(m_bits, 11, 11)); + } + + DxbcGlobalFlags globalFlags() const { + return DxbcGlobalFlags(bit::extract(m_bits, 11, 14)); + } + + DxbcZeroTest zeroTest() const { + return DxbcZeroTest(bit::extract(m_bits, 18, 18)); + } + + DxbcSyncFlags syncFlags() const { + return DxbcSyncFlags(bit::extract(m_bits, 11, 14)); + } + + DxbcResourceDim resourceDim() const { + return DxbcResourceDim(bit::extract(m_bits, 11, 15)); + } + + DxbcResinfoType resinfoType() const { + return DxbcResinfoType(bit::extract(m_bits, 11, 12)); + } + + DxbcInterpolationMode interpolation() const { + return DxbcInterpolationMode(bit::extract(m_bits, 11, 14)); + } + + DxbcSamplerMode samplerMode() const { + return DxbcSamplerMode(bit::extract(m_bits, 11, 14)); + } + + DxbcPrimitiveTopology primitiveTopology() const { + return DxbcPrimitiveTopology(bit::extract(m_bits, 11, 17)); + } + + DxbcPrimitive primitive() const { + return DxbcPrimitive(bit::extract(m_bits, 11, 16)); + } + + DxbcTessDomain tessDomain() const { + return DxbcTessDomain(bit::extract(m_bits, 11, 12)); + } + + DxbcTessOutputPrimitive tessOutputPrimitive() const { + return DxbcTessOutputPrimitive(bit::extract(m_bits, 11, 13)); + } + + DxbcTessPartitioning tessPartitioning() const { + return DxbcTessPartitioning(bit::extract(m_bits, 11, 13)); + } + + DxbcUavFlags uavFlags() const { + return DxbcUavFlags(bit::extract(m_bits, 16, 16)); + } + + uint32_t controlPointCount() const { + return bit::extract(m_bits, 11, 16); + } + + private: + + uint32_t m_bits; + };