diff --git a/src/dxbc/dxbc_compiler.cpp b/src/dxbc/dxbc_compiler.cpp index f8ca4e07..fef2fe29 100644 --- a/src/dxbc/dxbc_compiler.cpp +++ b/src/dxbc/dxbc_compiler.cpp @@ -260,6 +260,15 @@ namespace dxvk { case DxbcOpcode::DclOutputControlPointCount: return this->emitDclOutputControlPointCount(ins); + case DxbcOpcode::DclTessDomain: + return this->emitDclTessDomain(ins); + + case DxbcOpcode::DclTessPartitioning: + return this->emitDclTessPartitioning(ins); + + case DxbcOpcode::DclTessOutputPrimitive: + return this->emitDclTessOutputPrimitive(ins); + case DxbcOpcode::DclThreadGroup: return this->emitDclThreadGroup(ins); @@ -1057,18 +1066,76 @@ namespace dxvk { // dcl_max_output_vertex_count has one operand: // (imm0) The maximum number of vertices m_gs.outputVertexCount = ins.imm[0].u32; + m_module.setOutputVertices(m_entryPointId, m_gs.outputVertexCount); } void DxbcCompiler::emitDclInputControlPointCount(const DxbcShaderInstruction& ins) { + // dcl_input_control_points has the control point + // count embedded within the opcode token. m_hs.vertexCountIn = ins.controls.controlPointCount; } void DxbcCompiler::emitDclOutputControlPointCount(const DxbcShaderInstruction& ins) { - m_module.setOutputVertices(m_entryPointId, ins.controls.controlPointCount); + // dcl_output_control_points has the control point + // count embedded within the opcode token. m_hs.vertexCountOut = ins.controls.controlPointCount; + + m_module.setOutputVertices(m_entryPointId, ins.controls.controlPointCount); + } + + + void DxbcCompiler::emitDclTessDomain(const DxbcShaderInstruction& ins) { + const spv::ExecutionMode executionMode = [&] { + switch (ins.controls.tessDomain) { + case DxbcTessDomain::Isolines: return spv::ExecutionModeIsolines; + case DxbcTessDomain::Triangles: return spv::ExecutionModeTriangles; + case DxbcTessDomain::Quads: return spv::ExecutionModeQuads; + default: throw DxvkError("Dxbc: Invalid tess domain"); + } + }(); + + m_module.setExecutionMode(m_entryPointId, executionMode); + } + + + void DxbcCompiler::emitDclTessPartitioning(const DxbcShaderInstruction& ins) { + const spv::ExecutionMode executionMode = [&] { + switch (ins.controls.tessPartitioning) { + case DxbcTessPartitioning::Pow2: + case DxbcTessPartitioning::Integer: return spv::ExecutionModeSpacingEqual; + case DxbcTessPartitioning::FractOdd: return spv::ExecutionModeSpacingFractionalOdd; + case DxbcTessPartitioning::FractEven: return spv::ExecutionModeSpacingFractionalEven; + default: throw DxvkError("Dxbc: Invalid tess partitioning"); + } + }(); + + m_module.setExecutionMode(m_entryPointId, executionMode); + } + + + void DxbcCompiler::emitDclTessOutputPrimitive(const DxbcShaderInstruction& ins) { + switch (ins.controls.tessOutputPrimitive) { + case DxbcTessOutputPrimitive::Point: + m_module.setExecutionMode(m_entryPointId, spv::ExecutionModePointMode); + break; + + case DxbcTessOutputPrimitive::Line: + break; + + case DxbcTessOutputPrimitive::TriangleCw: + m_module.setExecutionMode(m_entryPointId, spv::ExecutionModeVertexOrderCw); + break; + + case DxbcTessOutputPrimitive::TriangleCcw: + m_module.setExecutionMode(m_entryPointId, spv::ExecutionModeVertexOrderCcw); + break; + + default: + throw DxvkError("Dxbc: Invalid tess output primitive"); + } } diff --git a/src/dxbc/dxbc_compiler.h b/src/dxbc/dxbc_compiler.h index 784ccc2d..01cf214c 100644 --- a/src/dxbc/dxbc_compiler.h +++ b/src/dxbc/dxbc_compiler.h @@ -464,6 +464,15 @@ namespace dxvk { void emitDclOutputControlPointCount( const DxbcShaderInstruction& ins); + void emitDclTessDomain( + const DxbcShaderInstruction& ins); + + void emitDclTessPartitioning( + const DxbcShaderInstruction& ins); + + void emitDclTessOutputPrimitive( + const DxbcShaderInstruction& ins); + void emitDclThreadGroup( const DxbcShaderInstruction& ins); diff --git a/src/dxbc/dxbc_decoder.cpp b/src/dxbc/dxbc_decoder.cpp index 2447a05b..fda43ac0 100644 --- a/src/dxbc/dxbc_decoder.cpp +++ b/src/dxbc/dxbc_decoder.cpp @@ -105,7 +105,9 @@ namespace dxvk { m_instruction.modifiers.saturate = !!bit::extract(token, 13, 13); m_instruction.modifiers.precise = !!bit::extract(token, 19, 22); - // Opcode controls. It will depend on the opcode itself which ones are valid. + // Opcode controls. It will depend on the + // opcode itself which ones are valid. + // TODO refactor this nonsense m_instruction.controls.globalFlags = static_cast(bit::extract(token, 11, 14)); m_instruction.controls.zeroTest = @@ -124,6 +126,12 @@ namespace dxvk { 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.controlPointCount = static_cast(bit::extract(token, 11, 16)); diff --git a/src/dxbc/dxbc_decoder.h b/src/dxbc/dxbc_decoder.h index ac763bed..00d4d125 100644 --- a/src/dxbc/dxbc_decoder.h +++ b/src/dxbc/dxbc_decoder.h @@ -251,6 +251,9 @@ namespace dxvk { DxbcSamplerMode samplerMode; DxbcPrimitiveTopology primitiveTopology; DxbcPrimitive primitive; + DxbcTessDomain tessDomain; + DxbcTessOutputPrimitive tessOutputPrimitive; + DxbcTessPartitioning tessPartitioning; uint32_t controlPointCount; }; diff --git a/src/dxbc/dxbc_defs.cpp b/src/dxbc/dxbc_defs.cpp index e46e0f85..5d93c4f5 100644 --- a/src/dxbc/dxbc_defs.cpp +++ b/src/dxbc/dxbc_defs.cpp @@ -720,11 +720,11 @@ namespace dxvk { /* DclOutputControlPointCount */ { 0, DxbcInstClass::Declaration }, /* DclTessDomain */ - { }, + { 0, DxbcInstClass::Declaration }, /* DclTessPartitioning */ - { }, + { 0, DxbcInstClass::Declaration }, /* DclTessOutputPrimitive */ - { }, + { 0, DxbcInstClass::Declaration }, /* DclHsMaxTessFactor */ { }, /* DclHsForkPhaseInstanceCount */ diff --git a/src/dxbc/dxbc_enums.h b/src/dxbc/dxbc_enums.h index fc9f3648..1369eb14 100644 --- a/src/dxbc/dxbc_enums.h +++ b/src/dxbc/dxbc_enums.h @@ -547,6 +547,38 @@ namespace dxvk { }; + /** + * \brief Tessellator domain + */ + enum class DxbcTessDomain : uint32_t { + Undefined = 0, + Isolines = 1, + Triangles = 2, + Quads = 3, + }; + + /** + * \brief Tessellator partitioning + */ + enum class DxbcTessPartitioning : uint32_t { + Undefined = 0, + Integer = 1, + Pow2 = 2, + FractOdd = 3, + FractEven = 4, + }; + + /** + * \brief Tessellator output primitive + */ + enum class DxbcTessOutputPrimitive : uint32_t { + Undefined = 0, + Point = 1, + Line = 2, + TriangleCw = 3, + TriangleCcw = 4, + }; + /** * \brief Custom data class *