[D3D12] Non-adaptive triangle tessellation

This commit is contained in:
Triang3l
2020-04-07 18:55:43 +03:00
parent b00baadf53
commit 9d36c257b0
21 changed files with 445 additions and 247 deletions

View File

@@ -448,7 +448,7 @@ void DxbcShaderTranslator::StartVertexShader_LoadVertexIndex() {
void DxbcShaderTranslator::StartVertexOrDomainShader() {
// Zero the interpolators.
for (uint32_t i = 0; i < kInterpolatorCount; ++i) {
DxbcOpMov(DxbcDest::O(uint32_t(InOutRegister::kVSOutInterpolators) + i),
DxbcOpMov(DxbcDest::O(uint32_t(InOutRegister::kVSDSOutInterpolators) + i),
DxbcSrc::LF(0.0f));
}
@@ -459,6 +459,30 @@ void DxbcShaderTranslator::StartVertexOrDomainShader() {
StartVertexShader_LoadVertexIndex();
break;
case Shader::HostVertexShaderType::kTriangleDomainConstant:
assert_true(register_count() >= 2);
if (register_count() >= 1) {
// Copy the domain location to r0.xyz.
// ZYX swizzle according to Call of Duty 3 and Viva Pinata.
DxbcOpMov(uses_register_dynamic_addressing() ? DxbcDest::X(0, 0, 0b0111)
: DxbcDest::R(0, 0b0111),
DxbcSrc::VDomain(0b000110));
if (register_count() >= 2) {
// Copy the control point indices (already swapped and converted to
// float by the host vertex and hull shaders) to r1.xyz.
DxbcDest control_point_index_dest(uses_register_dynamic_addressing()
? DxbcDest::X(0, 1)
: DxbcDest::R(1));
for (uint32_t i = 0; i < 3; ++i) {
DxbcOpMov(control_point_index_dest.Mask(1 << i),
DxbcSrc::VICP(
i, uint32_t(InOutRegister::kDSInControlPointIndex),
DxbcSrc::kXXXX));
}
}
}
break;
case Shader::HostVertexShaderType::kTriangleDomainAdaptive:
assert_true(register_count() >= 2);
if (register_count() >= 1) {
@@ -1162,7 +1186,8 @@ void DxbcShaderTranslator::CompleteVertexOrDomainShader() {
ENCODE_D3D10_SB_TOKENIZED_INSTRUCTION_LENGTH(12));
shader_code_.push_back(
EncodeVectorMaskedOperand(D3D10_SB_OPERAND_TYPE_OUTPUT, ucp_mask, 1));
shader_code_.push_back(uint32_t(InOutRegister::kVSOutClipDistance0123) + i);
shader_code_.push_back(uint32_t(InOutRegister::kVSDSOutClipDistance0123) +
i);
shader_code_.push_back(EncodeVectorSwizzledOperand(
D3D10_SB_OPERAND_TYPE_TEMP, kSwizzleXYZW, 1));
shader_code_.push_back(ucp_enabled_temp);
@@ -1276,7 +1301,7 @@ void DxbcShaderTranslator::CompleteVertexOrDomainShader() {
ENCODE_D3D10_SB_TOKENIZED_INSTRUCTION_LENGTH(5));
shader_code_.push_back(
EncodeVectorMaskedOperand(D3D10_SB_OPERAND_TYPE_OUTPUT, 0b0011, 1));
shader_code_.push_back(uint32_t(InOutRegister::kVSOutClipSpaceZW));
shader_code_.push_back(uint32_t(InOutRegister::kVSDSOutClipSpaceZW));
shader_code_.push_back(
EncodeVectorSwizzledOperand(D3D10_SB_OPERAND_TYPE_TEMP, 0b11111110, 1));
shader_code_.push_back(system_temp_position_);
@@ -1284,10 +1309,10 @@ void DxbcShaderTranslator::CompleteVertexOrDomainShader() {
++stat_.mov_instruction_count;
// Initialize SV_CullDistance.
DxbcOpMov(
DxbcDest::O(uint32_t(InOutRegister::kVSOutClipDistance45AndCullDistance),
0b0100),
DxbcSrc::LF(0.0f));
DxbcOpMov(DxbcDest::O(
uint32_t(InOutRegister::kVSDSOutClipDistance45AndCullDistance),
0b0100),
DxbcSrc::LF(0.0f));
// Kill the primitive if needed - check if the shader wants to kill.
// TODO(Triang3l): Find if the condition is actually the flag being non-zero.
uint32_t kill_temp = PushSystemTemp();
@@ -1319,7 +1344,7 @@ void DxbcShaderTranslator::CompleteVertexOrDomainShader() {
// negative.
DxbcOpMov(
DxbcDest::O(
uint32_t(InOutRegister::kVSOutClipDistance45AndCullDistance),
uint32_t(InOutRegister::kVSDSOutClipDistance45AndCullDistance),
0b0100),
DxbcSrc::LF(-1.0f));
}
@@ -1332,7 +1357,7 @@ void DxbcShaderTranslator::CompleteVertexOrDomainShader() {
ENCODE_D3D10_SB_TOKENIZED_INSTRUCTION_LENGTH(5));
shader_code_.push_back(
EncodeVectorMaskedOperand(D3D10_SB_OPERAND_TYPE_OUTPUT, 0b1111, 1));
shader_code_.push_back(uint32_t(InOutRegister::kVSOutPosition));
shader_code_.push_back(uint32_t(InOutRegister::kVSDSOutPosition));
shader_code_.push_back(
EncodeVectorSwizzledOperand(D3D10_SB_OPERAND_TYPE_TEMP, kSwizzleXYZW, 1));
shader_code_.push_back(system_temp_position_);
@@ -1341,11 +1366,13 @@ void DxbcShaderTranslator::CompleteVertexOrDomainShader() {
// Zero the point coordinate (will be set in the geometry shader if needed)
// and write the point size.
DxbcOpMov(DxbcDest::O(uint32_t(InOutRegister::kVSOutPointParameters), 0b0011),
DxbcSrc::LF(0.0f));
DxbcOpMov(DxbcDest::O(uint32_t(InOutRegister::kVSOutPointParameters), 0b0100),
DxbcSrc::R(system_temp_point_size_edge_flag_kill_vertex_,
DxbcSrc::kXXXX));
DxbcOpMov(
DxbcDest::O(uint32_t(InOutRegister::kVSDSOutPointParameters), 0b0011),
DxbcSrc::LF(0.0f));
DxbcOpMov(
DxbcDest::O(uint32_t(InOutRegister::kVSDSOutPointParameters), 0b0100),
DxbcSrc::R(system_temp_point_size_edge_flag_kill_vertex_,
DxbcSrc::kXXXX));
}
void DxbcShaderTranslator::CompleteShaderCode() {
@@ -2178,7 +2205,7 @@ void DxbcShaderTranslator::StoreResult(const InstructionResult& result,
saturate_bit);
shader_code_.push_back(
EncodeVectorMaskedOperand(D3D10_SB_OPERAND_TYPE_OUTPUT, mask, 1));
shader_code_.push_back(uint32_t(InOutRegister::kVSOutInterpolators) +
shader_code_.push_back(uint32_t(InOutRegister::kVSDSOutInterpolators) +
uint32_t(result.storage_index));
break;
@@ -3605,10 +3632,42 @@ void DxbcShaderTranslator::WriteInputSignature() {
// Vertex index semantic name.
AppendString(shader_object_, "SV_VertexID");
} else if (IsDxbcDomainShader()) {
// No inputs - tessellation factors specified in PCSG.
shader_object_.push_back(0);
// Unknown.
shader_object_.push_back(8);
// Tessellation factors are specified in PCSG, not ISGN.
if (host_vertex_shader_type() ==
Shader::HostVertexShaderType::kTriangleDomainConstant ||
host_vertex_shader_type() ==
Shader::HostVertexShaderType::kQuadDomainConstant) {
// TODO(Triang3l): Support line patches.
// Control point indices, byte-swapped, biased according to the base index
// and converted to float by the host vertex and hull shaders.
shader_object_.push_back(1);
// Unknown.
shader_object_.push_back(8);
// Control point indices.
// Semantic name XEVERTEXID (the only one in the signature).
shader_object_.push_back(
(signature_position_dwords + signature_size_dwords) *
sizeof(uint32_t));
// Semantic index.
shader_object_.push_back(0);
// D3D_NAME_UNDEFINED.
shader_object_.push_back(0);
// D3D_REGISTER_COMPONENT_FLOAT32.
shader_object_.push_back(3);
shader_object_.push_back(uint32_t(InOutRegister::kDSInControlPointIndex));
// x present, x used (always written to GPR 1).
shader_object_.push_back(0b0001 | (0b0001 << 8));
// Control point indices semantic name.
AppendString(shader_object_, "XEVERTEXID");
} else {
// No inputs.
shader_object_.push_back(0);
// Unknown.
shader_object_.push_back(8);
}
} else {
assert_true(IsDxbcPixelShader());
// Interpolators, point parameters (coordinates, size), clip space ZW,
@@ -3804,7 +3863,7 @@ void DxbcShaderTranslator::WriteOutputSignature() {
shader_object_.push_back(0);
// D3D_REGISTER_COMPONENT_FLOAT32.
shader_object_.push_back(3);
shader_object_.push_back(uint32_t(InOutRegister::kVSOutInterpolators) +
shader_object_.push_back(uint32_t(InOutRegister::kVSDSOutInterpolators) +
i);
// Unlike in ISGN, the second byte contains the unused components, not the
// used ones. All components are always used because they are reset to 0.
@@ -3817,7 +3876,7 @@ void DxbcShaderTranslator::WriteOutputSignature() {
shader_object_.push_back(kPointParametersTexCoord);
shader_object_.push_back(0);
shader_object_.push_back(3);
shader_object_.push_back(uint32_t(InOutRegister::kVSOutPointParameters));
shader_object_.push_back(uint32_t(InOutRegister::kVSDSOutPointParameters));
shader_object_.push_back(0b0111 | (0b1000 << 8));
// Z and W in clip space, for getting per-sample depth with ROV.
@@ -3825,7 +3884,7 @@ void DxbcShaderTranslator::WriteOutputSignature() {
shader_object_.push_back(kClipSpaceZWTexCoord);
shader_object_.push_back(0);
shader_object_.push_back(3);
shader_object_.push_back(uint32_t(InOutRegister::kVSOutClipSpaceZW));
shader_object_.push_back(uint32_t(InOutRegister::kVSDSOutClipSpaceZW));
shader_object_.push_back(0b0011 | (0b1100 << 8));
// Position.
@@ -3834,7 +3893,7 @@ void DxbcShaderTranslator::WriteOutputSignature() {
// D3D_NAME_POSITION.
shader_object_.push_back(1);
shader_object_.push_back(3);
shader_object_.push_back(uint32_t(InOutRegister::kVSOutPosition));
shader_object_.push_back(uint32_t(InOutRegister::kVSDSOutPosition));
shader_object_.push_back(0b1111);
// Clip and cull distances.
@@ -3844,8 +3903,8 @@ void DxbcShaderTranslator::WriteOutputSignature() {
// D3D_NAME_CLIP_DISTANCE.
shader_object_.push_back(2);
shader_object_.push_back(3);
shader_object_.push_back(uint32_t(InOutRegister::kVSOutClipDistance0123) +
i);
shader_object_.push_back(
uint32_t(InOutRegister::kDSVSOutClipDistance0123) + i);
shader_object_.push_back(i ? (0b0011 | (0b1100 << 8)) : 0b1111);
}
shader_object_.push_back(0);
@@ -3854,7 +3913,7 @@ void DxbcShaderTranslator::WriteOutputSignature() {
shader_object_.push_back(3);
shader_object_.push_back(3);
shader_object_.push_back(
uint32_t(InOutRegister::kVSOutClipDistance45AndCullDistance));
uint32_t(InOutRegister::kVSDSOutClipDistance45AndCullDistance));
shader_object_.push_back(0b0100 | (0b1011 << 8));
// Write the semantic names.
@@ -4186,13 +4245,39 @@ void DxbcShaderTranslator::WriteShaderCode() {
shader_object_.push_back(EncodeVectorMaskedOperand(
D3D11_SB_OPERAND_TYPE_INPUT_DOMAIN_POINT, domain_location_mask, 0));
++stat_.dcl_count;
// Primitive index input.
shader_object_.push_back(
ENCODE_D3D10_SB_OPCODE_TYPE(D3D10_SB_OPCODE_DCL_INPUT) |
ENCODE_D3D10_SB_TOKENIZED_INSTRUCTION_LENGTH(2));
shader_object_.push_back(
EncodeScalarOperand(D3D10_SB_OPERAND_TYPE_INPUT_PRIMITIVEID, 0));
++stat_.dcl_count;
// Control point indices as float for discrete/continuous tessellation, or
// primitive index for adaptive tessellation.
uint32_t control_point_array_size;
switch (host_vertex_shader_type()) {
case Shader::HostVertexShaderType::kTriangleDomainConstant:
control_point_array_size = 3;
break;
case Shader::HostVertexShaderType::kQuadDomainConstant:
control_point_array_size = 4;
break;
default:
// TODO(Triang3l): Support line patches.
// Adaptive.
control_point_array_size = 0;
}
if (control_point_array_size) {
shader_object_.push_back(
ENCODE_D3D10_SB_OPCODE_TYPE(D3D10_SB_OPCODE_DCL_INPUT) |
ENCODE_D3D10_SB_TOKENIZED_INSTRUCTION_LENGTH(4));
shader_object_.push_back(EncodeVectorMaskedOperand(
D3D11_SB_OPERAND_TYPE_INPUT_CONTROL_POINT, 0b0001, 2));
shader_object_.push_back(control_point_array_size);
shader_object_.push_back(
uint32_t(InOutRegister::kDSInControlPointIndex));
++stat_.dcl_count;
} else {
shader_object_.push_back(
ENCODE_D3D10_SB_OPCODE_TYPE(D3D10_SB_OPCODE_DCL_INPUT) |
ENCODE_D3D10_SB_TOKENIZED_INSTRUCTION_LENGTH(2));
shader_object_.push_back(
EncodeScalarOperand(D3D10_SB_OPERAND_TYPE_INPUT_PRIMITIVEID, 0));
++stat_.dcl_count;
}
} else {
// Unswapped vertex index input (only X component).
shader_object_.push_back(
@@ -4211,7 +4296,7 @@ void DxbcShaderTranslator::WriteShaderCode() {
ENCODE_D3D10_SB_TOKENIZED_INSTRUCTION_LENGTH(3));
shader_object_.push_back(
EncodeVectorMaskedOperand(D3D10_SB_OPERAND_TYPE_OUTPUT, 0b1111, 1));
shader_object_.push_back(uint32_t(InOutRegister::kVSOutInterpolators) +
shader_object_.push_back(uint32_t(InOutRegister::kVSDSOutInterpolators) +
i);
++stat_.dcl_count;
}
@@ -4221,7 +4306,7 @@ void DxbcShaderTranslator::WriteShaderCode() {
ENCODE_D3D10_SB_TOKENIZED_INSTRUCTION_LENGTH(3));
shader_object_.push_back(
EncodeVectorMaskedOperand(D3D10_SB_OPERAND_TYPE_OUTPUT, 0b0111, 1));
shader_object_.push_back(uint32_t(InOutRegister::kVSOutPointParameters));
shader_object_.push_back(uint32_t(InOutRegister::kVSDSOutPointParameters));
++stat_.dcl_count;
// Clip space Z and W output.
shader_object_.push_back(
@@ -4229,7 +4314,7 @@ void DxbcShaderTranslator::WriteShaderCode() {
ENCODE_D3D10_SB_TOKENIZED_INSTRUCTION_LENGTH(3));
shader_object_.push_back(
EncodeVectorMaskedOperand(D3D10_SB_OPERAND_TYPE_OUTPUT, 0b0011, 1));
shader_object_.push_back(uint32_t(InOutRegister::kVSOutClipSpaceZW));
shader_object_.push_back(uint32_t(InOutRegister::kVSDSOutClipSpaceZW));
++stat_.dcl_count;
// Position output.
shader_object_.push_back(
@@ -4237,7 +4322,7 @@ void DxbcShaderTranslator::WriteShaderCode() {
ENCODE_D3D10_SB_TOKENIZED_INSTRUCTION_LENGTH(4));
shader_object_.push_back(
EncodeVectorMaskedOperand(D3D10_SB_OPERAND_TYPE_OUTPUT, 0b1111, 1));
shader_object_.push_back(uint32_t(InOutRegister::kVSOutPosition));
shader_object_.push_back(uint32_t(InOutRegister::kVSDSOutPosition));
shader_object_.push_back(ENCODE_D3D10_SB_NAME(D3D10_SB_NAME_POSITION));
++stat_.dcl_count;
// Clip distance outputs.
@@ -4247,8 +4332,8 @@ void DxbcShaderTranslator::WriteShaderCode() {
ENCODE_D3D10_SB_TOKENIZED_INSTRUCTION_LENGTH(4));
shader_object_.push_back(EncodeVectorMaskedOperand(
D3D10_SB_OPERAND_TYPE_OUTPUT, i ? 0b0011 : 0b1111, 1));
shader_object_.push_back(uint32_t(InOutRegister::kVSOutClipDistance0123) +
i);
shader_object_.push_back(
uint32_t(InOutRegister::kVDSSOutClipDistance0123) + i);
shader_object_.push_back(
ENCODE_D3D10_SB_NAME(D3D10_SB_NAME_CLIP_DISTANCE));
++stat_.dcl_count;
@@ -4260,7 +4345,7 @@ void DxbcShaderTranslator::WriteShaderCode() {
shader_object_.push_back(
EncodeVectorMaskedOperand(D3D10_SB_OPERAND_TYPE_OUTPUT, 0b0100, 1));
shader_object_.push_back(
uint32_t(InOutRegister::kVSOutClipDistance45AndCullDistance));
uint32_t(InOutRegister::kVSDSOutClipDistance45AndCullDistance));
shader_object_.push_back(ENCODE_D3D10_SB_NAME(D3D10_SB_NAME_CULL_DISTANCE));
++stat_.dcl_count;
} else if (IsDxbcPixelShader()) {