From 0d14ae01bb6f7af57cb9eb4e01d4fbd9957bd05c Mon Sep 17 00:00:00 2001 From: Triang3l Date: Mon, 11 May 2020 22:40:52 +0300 Subject: [PATCH] [D3D12] Allow non-adaptive tessellation for patch primitive types, and all triangle and quad tessellation modes --- src/xenia/gpu/d3d12/pipeline_cache.cc | 78 +++--- .../gpu/d3d12/shaders/adaptive_quad.hs.hlsl | 6 +- .../d3d12/shaders/adaptive_triangle.hs.hlsl | 6 +- .../d3d12/shaders/dxbc/adaptive_quad_hs.cso | Bin 3596 -> 3664 bytes .../gpu/d3d12/shaders/dxbc/adaptive_quad_hs.h | 130 +++++----- .../d3d12/shaders/dxbc/adaptive_quad_hs.txt | 7 +- .../shaders/dxbc/adaptive_triangle_hs.cso | Bin 3432 -> 3500 bytes .../d3d12/shaders/dxbc/adaptive_triangle_hs.h | 110 ++++---- .../shaders/dxbc/adaptive_triangle_hs.txt | 7 +- src/xenia/gpu/d3d12/shaders/xenos_draw.hlsli | 2 - src/xenia/gpu/dxbc_shader_translator.cc | 236 ++++++++++-------- src/xenia/gpu/dxbc_shader_translator.h | 4 + src/xenia/gpu/shader.h | 12 +- src/xenia/gpu/shader_compiler_main.cc | 28 +-- src/xenia/gpu/xenos.h | 7 +- tools/shader-playground/Editor.Designer.cs | 12 +- tools/shader-playground/Editor.cs | 12 +- 17 files changed, 352 insertions(+), 305 deletions(-) diff --git a/src/xenia/gpu/d3d12/pipeline_cache.cc b/src/xenia/gpu/d3d12/pipeline_cache.cc index 2a694d59a..053407524 100644 --- a/src/xenia/gpu/d3d12/pipeline_cache.cc +++ b/src/xenia/gpu/d3d12/pipeline_cache.cc @@ -751,6 +751,7 @@ Shader::HostVertexShaderType PipelineCache::GetHostVertexShaderTypeIfValid() regs.Get().tess_mode; switch (vgt_draw_initiator.prim_type) { case PrimitiveType::kTriangleList: + case PrimitiveType::kTrianglePatch: // Also supported by triangle strips and fans according to: // https://www.khronos.org/registry/OpenGL/extensions/AMD/AMD_vertex_shader_tessellator.txt // Would need to convert those to triangle lists, but haven't seen any @@ -764,39 +765,44 @@ Shader::HostVertexShaderType PipelineCache::GetHostVertexShaderTypeIfValid() // - Viva Pinata - tree building with a beehive in the beginning // (visible on the start screen behind the logo), waterfall in the // beginning - kTriangleList. - return Shader::HostVertexShaderType::kTriangleDomainConstant; + return Shader::HostVertexShaderType::kTriangleDomainCPIndexed; + case xenos::TessellationMode::kAdaptive: + if (vgt_draw_initiator.prim_type == PrimitiveType::kTrianglePatch) { + // - Banjo-Kazooie: Nuts & Bolts - water. + // - Halo 3 - water. + return Shader::HostVertexShaderType::kTriangleDomainPatchIndexed; + } + break; default: break; } break; case PrimitiveType::kQuadList: + case PrimitiveType::kQuadPatch: switch (tessellation_mode) { // Also supported by quad strips according to: // https://www.khronos.org/registry/OpenGL/extensions/AMD/AMD_vertex_shader_tessellator.txt // Would need to convert those to quad lists, but haven't seen any games // using tessellated strips so far. + case xenos::TessellationMode::kDiscrete: + // Not seen in games so far. case xenos::TessellationMode::kContinuous: // - Defender - retro screen and beams in the main menu - kQuadList. - return Shader::HostVertexShaderType::kQuadDomainConstant; + // - Fable 2 - kQuadPatch. + return Shader::HostVertexShaderType::kQuadDomainCPIndexed; + case xenos::TessellationMode::kAdaptive: + if (vgt_draw_initiator.prim_type == PrimitiveType::kQuadPatch) { + // - Viva Pinata - garden ground. + return Shader::HostVertexShaderType::kQuadDomainPatchIndexed; + } + break; default: break; } break; - case PrimitiveType::kTrianglePatch: - if (tessellation_mode == xenos::TessellationMode::kAdaptive) { - // - Banjo-Kazooie: Nuts & Bolts - water. - // - Halo 3 - water. - return Shader::HostVertexShaderType::kTriangleDomainAdaptive; - } + default: + // TODO(Triang3l): Support line patches. break; - case PrimitiveType::kQuadPatch: - if (tessellation_mode == xenos::TessellationMode::kAdaptive) { - // - Viva Pinata - garden ground. - return Shader::HostVertexShaderType::kQuadDomainAdaptive; - } - break; - // TODO(Triang3l): Support line patches and non-adaptive quad - // tessellation. } XELOGE( "Unsupported tessellation mode {} for primitive type {}. Report the game " @@ -970,23 +976,23 @@ bool PipelineCache::TranslateShader( const char* host_shader_type; if (shader->type() == ShaderType::kVertex) { switch (shader->host_vertex_shader_type()) { - case Shader::HostVertexShaderType::kLineDomainConstant: - host_shader_type = "constant line domain"; + case Shader::HostVertexShaderType::kLineDomainCPIndexed: + host_shader_type = "control-point-indexed line domain"; break; - case Shader::HostVertexShaderType::kLineDomainAdaptive: - host_shader_type = "adaptive line domain"; + case Shader::HostVertexShaderType::kLineDomainPatchIndexed: + host_shader_type = "patch-indexed line domain"; break; - case Shader::HostVertexShaderType::kTriangleDomainConstant: - host_shader_type = "constant triangle domain"; + case Shader::HostVertexShaderType::kTriangleDomainCPIndexed: + host_shader_type = "control-point-indexed triangle domain"; break; - case Shader::HostVertexShaderType::kTriangleDomainAdaptive: - host_shader_type = "adaptive triangle domain"; + case Shader::HostVertexShaderType::kTriangleDomainPatchIndexed: + host_shader_type = "patch-indexed triangle domain"; break; - case Shader::HostVertexShaderType::kQuadDomainConstant: - host_shader_type = "constant quad domain"; + case Shader::HostVertexShaderType::kQuadDomainCPIndexed: + host_shader_type = "control-point-indexed quad domain"; break; - case Shader::HostVertexShaderType::kQuadDomainAdaptive: - host_shader_type = "adaptive quad domain"; + case Shader::HostVertexShaderType::kQuadDomainPatchIndexed: + host_shader_type = "patch-indexed quad domain"; break; default: host_shader_type = "vertex"; @@ -1481,11 +1487,13 @@ ID3D12PipelineState* PipelineCache::CreateD3D12PipelineState( switch (tessellation_mode) { case xenos::TessellationMode::kDiscrete: switch (host_vertex_shader_type) { - case Shader::HostVertexShaderType::kTriangleDomainConstant: + case Shader::HostVertexShaderType::kTriangleDomainCPIndexed: + case Shader::HostVertexShaderType::kTriangleDomainPatchIndexed: state_desc.HS.pShaderBytecode = discrete_triangle_hs; state_desc.HS.BytecodeLength = sizeof(discrete_triangle_hs); break; - case Shader::HostVertexShaderType::kQuadDomainConstant: + case Shader::HostVertexShaderType::kQuadDomainCPIndexed: + case Shader::HostVertexShaderType::kQuadDomainPatchIndexed: state_desc.HS.pShaderBytecode = discrete_quad_hs; state_desc.HS.BytecodeLength = sizeof(discrete_quad_hs); break; @@ -1496,11 +1504,13 @@ ID3D12PipelineState* PipelineCache::CreateD3D12PipelineState( break; case xenos::TessellationMode::kContinuous: switch (host_vertex_shader_type) { - case Shader::HostVertexShaderType::kTriangleDomainConstant: + case Shader::HostVertexShaderType::kTriangleDomainCPIndexed: + case Shader::HostVertexShaderType::kTriangleDomainPatchIndexed: state_desc.HS.pShaderBytecode = continuous_triangle_hs; state_desc.HS.BytecodeLength = sizeof(continuous_triangle_hs); break; - case Shader::HostVertexShaderType::kQuadDomainConstant: + case Shader::HostVertexShaderType::kQuadDomainCPIndexed: + case Shader::HostVertexShaderType::kQuadDomainPatchIndexed: state_desc.HS.pShaderBytecode = continuous_quad_hs; state_desc.HS.BytecodeLength = sizeof(continuous_quad_hs); break; @@ -1511,11 +1521,11 @@ ID3D12PipelineState* PipelineCache::CreateD3D12PipelineState( break; case xenos::TessellationMode::kAdaptive: switch (host_vertex_shader_type) { - case Shader::HostVertexShaderType::kTriangleDomainAdaptive: + case Shader::HostVertexShaderType::kTriangleDomainPatchIndexed: state_desc.HS.pShaderBytecode = adaptive_triangle_hs; state_desc.HS.BytecodeLength = sizeof(adaptive_triangle_hs); break; - case Shader::HostVertexShaderType::kQuadDomainAdaptive: + case Shader::HostVertexShaderType::kQuadDomainPatchIndexed: state_desc.HS.pShaderBytecode = adaptive_quad_hs; state_desc.HS.BytecodeLength = sizeof(adaptive_quad_hs); break; diff --git a/src/xenia/gpu/d3d12/shaders/adaptive_quad.hs.hlsl b/src/xenia/gpu/d3d12/shaders/adaptive_quad.hs.hlsl index af822ad04..3fa31b7e5 100644 --- a/src/xenia/gpu/d3d12/shaders/adaptive_quad.hs.hlsl +++ b/src/xenia/gpu/d3d12/shaders/adaptive_quad.hs.hlsl @@ -48,8 +48,10 @@ XeHSConstantDataOutput XePatchConstant( [outputtopology("triangle_cw")] [outputcontrolpoints(4)] [patchconstantfunc("XePatchConstant")] -XeHSAdaptiveControlPointOutput main( +XeHSControlPointOutput main( InputPatch xe_input_patch) { - XeHSAdaptiveControlPointOutput output; + XeHSControlPointOutput output; + // Not used with control point indices. + output.index = 0.0f; return output; } diff --git a/src/xenia/gpu/d3d12/shaders/adaptive_triangle.hs.hlsl b/src/xenia/gpu/d3d12/shaders/adaptive_triangle.hs.hlsl index b71dc55b6..c4199482f 100644 --- a/src/xenia/gpu/d3d12/shaders/adaptive_triangle.hs.hlsl +++ b/src/xenia/gpu/d3d12/shaders/adaptive_triangle.hs.hlsl @@ -54,8 +54,10 @@ XeHSConstantDataOutput XePatchConstant( [outputtopology("triangle_cw")] [outputcontrolpoints(3)] [patchconstantfunc("XePatchConstant")] -XeHSAdaptiveControlPointOutput main( +XeHSControlPointOutput main( InputPatch xe_input_patch) { - XeHSAdaptiveControlPointOutput output; + XeHSControlPointOutput output; + // Not used with control point indices. + output.index = 0.0f; return output; } diff --git a/src/xenia/gpu/d3d12/shaders/dxbc/adaptive_quad_hs.cso b/src/xenia/gpu/d3d12/shaders/dxbc/adaptive_quad_hs.cso index 1a660045bb794383872f5d211636357740394027..478fb2c1a78c8b0689573dc205db5143094af779 100644 GIT binary patch delta 159 zcmeB?xgcZe65-^0KB(&Sy(_9S6YnvJx%cn(U}Rum2;gI2U<1+?K>UW2fkA10N3 rdxca624*1z0kCp21_o9bo6!L*#IV_c+k%OaZ*nECHzVuhqrC0_W#}I< delta 110 zcmca0(<5W*65-^mefL!PGLA6KKQfmJR;NF%Vq{=o;NfFnU<1+?K>UW2fkA^CBn(s(K0Fe*M_pfe9h(24fb*kj0_A6Yj_zL*nqSJ5WnGMU{K&UW2fkAv&;ACK8U= 2); if (register_count() >= 1) { // Copy the domain location to r0.xyz. // ZYX swizzle according to Call of Duty 3 and Viva Pinata. + in_domain_location_used_ |= 0b0111; DxbcOpMov(uses_register_dynamic_addressing() ? DxbcDest::X(0, 0, 0b0111) : DxbcDest::R(0, 0b0111), DxbcSrc::VDomain(0b000110)); @@ -484,12 +487,13 @@ void DxbcShaderTranslator::StartVertexOrDomainShader() { } break; - case Shader::HostVertexShaderType::kTriangleDomainAdaptive: + case Shader::HostVertexShaderType::kTriangleDomainPatchIndexed: assert_true(register_count() >= 2); if (register_count() >= 1) { // Copy the domain location to r0.xyz. // ZYX swizzle with r1.y == 0, according to the water shader in // Banjo-Kazooie: Nuts & Bolts. + in_domain_location_used_ |= 0b0111; DxbcOpMov(uses_register_dynamic_addressing() ? DxbcDest::X(0, 0, 0b0111) : DxbcDest::R(0, 0b0111), DxbcSrc::VDomain(0b000110)); @@ -497,6 +501,7 @@ void DxbcShaderTranslator::StartVertexOrDomainShader() { // Copy the primitive index to r1.x as a float. uint32_t primitive_id_temp = uses_register_dynamic_addressing() ? PushSystemTemp() : 1; + in_primitive_id_used_ = true; DxbcOpUToF(DxbcDest::R(primitive_id_temp, 0b0001), DxbcSrc::VPrim()); if (uses_register_dynamic_addressing()) { DxbcOpMov(DxbcDest::X(0, 1, 0b0001), @@ -531,10 +536,11 @@ void DxbcShaderTranslator::StartVertexOrDomainShader() { } break; - case Shader::HostVertexShaderType::kQuadDomainConstant: + case Shader::HostVertexShaderType::kQuadDomainCPIndexed: assert_true(register_count() >= 2); if (register_count() >= 1) { // Copy the domain location to r0.xy. + in_domain_location_used_ |= 0b0011; DxbcOpMov(uses_register_dynamic_addressing() ? DxbcDest::X(0, 0, 0b0011) : DxbcDest::R(0, 0b0011), DxbcSrc::VDomain()); @@ -566,17 +572,19 @@ void DxbcShaderTranslator::StartVertexOrDomainShader() { } break; - case Shader::HostVertexShaderType::kQuadDomainAdaptive: + case Shader::HostVertexShaderType::kQuadDomainPatchIndexed: assert_true(register_count() >= 2); if (register_count() >= 1) { // Copy the domain location to r0.yz. // XY swizzle according to the ground shader in Viva Pinata. + in_domain_location_used_ |= 0b0011; DxbcOpMov(uses_register_dynamic_addressing() ? DxbcDest::X(0, 0, 0b0110) : DxbcDest::R(0, 0b0110), DxbcSrc::VDomain(0b010000)); // Copy the primitive index to r0.x as a float. uint32_t primitive_id_temp = uses_register_dynamic_addressing() ? PushSystemTemp() : 0; + in_primitive_id_used_ = true; DxbcOpUToF(DxbcDest::R(primitive_id_temp, 0b0001), DxbcSrc::VPrim()); if (uses_register_dynamic_addressing()) { DxbcOpMov(DxbcDest::X(0, 0, 0b0001), @@ -2931,42 +2939,38 @@ void DxbcShaderTranslator::WriteInputSignature() { } semantic_offset += AppendString(shader_object_, "SV_VertexID"); } else if (IsDxbcDomainShader()) { - 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 - // (XEVERTEXID). - size_t control_point_index_position = shader_object_.size(); - shader_object_.resize(shader_object_.size() + kParameterDwords); - ++parameter_count; - { - DxbcSignatureParameter& control_point_index = - *reinterpret_cast( - shader_object_.data() + control_point_index_position); - control_point_index.component_type = - DxbcSignatureRegisterComponentType::kFloat32; - control_point_index.register_index = - uint32_t(InOutRegister::kDSInControlPointIndex); - control_point_index.mask = 0b0001; - control_point_index.always_reads_mask = - in_control_point_index_used_ ? 0b0001 : 0b0000; - } - - // Semantic names. - uint32_t semantic_offset = - uint32_t((shader_object_.size() - chunk_position) * sizeof(uint32_t)); - { - DxbcSignatureParameter& control_point_index = - *reinterpret_cast( - shader_object_.data() + control_point_index_position); - control_point_index.semantic_name = semantic_offset; - } - semantic_offset += AppendString(shader_object_, "XEVERTEXID"); + // Control point indices, byte-swapped, biased according to the base index + // and converted to float by the host vertex and hull shaders + // (XEVERTEXID). Needed even for patch-indexed tessellation modes because + // hull and domain shaders have strict linkage requirements, all hull shader + // outputs must be declared in a domain shader, and the same hull shaders + // are used for control-point-indexed and patch-indexed tessellation modes. + size_t control_point_index_position = shader_object_.size(); + shader_object_.resize(shader_object_.size() + kParameterDwords); + ++parameter_count; + { + DxbcSignatureParameter& control_point_index = + *reinterpret_cast( + shader_object_.data() + control_point_index_position); + control_point_index.component_type = + DxbcSignatureRegisterComponentType::kFloat32; + control_point_index.register_index = + uint32_t(InOutRegister::kDSInControlPointIndex); + control_point_index.mask = 0b0001; + control_point_index.always_reads_mask = + in_control_point_index_used_ ? 0b0001 : 0b0000; } + + // Semantic names. + uint32_t semantic_offset = + uint32_t((shader_object_.size() - chunk_position) * sizeof(uint32_t)); + { + DxbcSignatureParameter& control_point_index = + *reinterpret_cast( + shader_object_.data() + control_point_index_position); + control_point_index.semantic_name = semantic_offset; + } + semantic_offset += AppendString(shader_object_, "XEVERTEXID"); } else if (IsDxbcPixelShader()) { // Written dynamically, so assume it's always used if it can be written to // any interpolator register. @@ -3133,15 +3137,15 @@ void DxbcShaderTranslator::WritePatchConstantSignature() { uint32_t tess_factor_inside_count = 0; DxbcName tess_factor_inside_system_value = DxbcName::kUndefined; switch (host_vertex_shader_type()) { - case Shader::HostVertexShaderType::kTriangleDomainConstant: - case Shader::HostVertexShaderType::kTriangleDomainAdaptive: + case Shader::HostVertexShaderType::kTriangleDomainCPIndexed: + case Shader::HostVertexShaderType::kTriangleDomainPatchIndexed: tess_factor_edge_count = 3; tess_factor_edge_system_value = DxbcName::kFinalTriEdgeTessFactor; tess_factor_inside_count = 1; tess_factor_inside_system_value = DxbcName::kFinalTriInsideTessFactor; break; - case Shader::HostVertexShaderType::kQuadDomainConstant: - case Shader::HostVertexShaderType::kQuadDomainAdaptive: + case Shader::HostVertexShaderType::kQuadDomainCPIndexed: + case Shader::HostVertexShaderType::kQuadDomainPatchIndexed: tess_factor_edge_count = 4; tess_factor_edge_system_value = DxbcName::kFinalQuadEdgeTessFactor; tess_factor_inside_count = 2; @@ -3501,24 +3505,21 @@ void DxbcShaderTranslator::WriteShaderCode() { // Inputs/outputs have 1D-indexed operands with a component mask and a // register index. - uint32_t domain_location_mask = 0b0111; if (IsDxbcDomainShader()) { // Not using control point data since Xenos only has a vertex shader acting // as both vertex shader and domain shader. stat_.c_control_points = 3; stat_.tessellator_domain = DxbcTessellatorDomain::kTriangle; switch (host_vertex_shader_type()) { - case Shader::HostVertexShaderType::kTriangleDomainConstant: - case Shader::HostVertexShaderType::kTriangleDomainAdaptive: + case Shader::HostVertexShaderType::kTriangleDomainCPIndexed: + case Shader::HostVertexShaderType::kTriangleDomainPatchIndexed: stat_.c_control_points = 3; stat_.tessellator_domain = DxbcTessellatorDomain::kTriangle; - domain_location_mask = 0b0111; break; - case Shader::HostVertexShaderType::kQuadDomainConstant: - case Shader::HostVertexShaderType::kQuadDomainAdaptive: + case Shader::HostVertexShaderType::kQuadDomainCPIndexed: + case Shader::HostVertexShaderType::kQuadDomainPatchIndexed: stat_.c_control_points = 4; stat_.tessellator_domain = DxbcTessellatorDomain::kQuad; - domain_location_mask = 0b0011; break; default: // TODO(Triang3l): Support line patches. @@ -3705,39 +3706,18 @@ void DxbcShaderTranslator::WriteShaderCode() { // Inputs and outputs. if (IsDxbcVertexOrDomainShader()) { if (IsDxbcDomainShader()) { - // Domain location input (barycentric for triangles, UV for quads). - 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(EncodeVectorMaskedOperand( - D3D11_SB_OPERAND_TYPE_INPUT_DOMAIN_POINT, domain_location_mask, 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) { + if (in_domain_location_used_) { + // Domain location input. 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); + ENCODE_D3D10_SB_TOKENIZED_INSTRUCTION_LENGTH(2)); shader_object_.push_back( - uint32_t(InOutRegister::kDSInControlPointIndex)); + EncodeVectorMaskedOperand(D3D11_SB_OPERAND_TYPE_INPUT_DOMAIN_POINT, + in_domain_location_used_, 0)); ++stat_.dcl_count; - } else { + } + if (in_primitive_id_used_) { + // Primitive (patch) index input. shader_object_.push_back( ENCODE_D3D10_SB_OPCODE_TYPE(D3D10_SB_OPCODE_DCL_INPUT) | ENCODE_D3D10_SB_TOKENIZED_INSTRUCTION_LENGTH(2)); @@ -3745,16 +3725,48 @@ void DxbcShaderTranslator::WriteShaderCode() { EncodeScalarOperand(D3D10_SB_OPERAND_TYPE_INPUT_PRIMITIVEID, 0)); ++stat_.dcl_count; } + if (in_control_point_index_used_) { + // Control point indices as float input. + uint32_t control_point_array_size; + switch (host_vertex_shader_type()) { + case Shader::HostVertexShaderType::kTriangleDomainCPIndexed: + control_point_array_size = 3; + break; + case Shader::HostVertexShaderType::kQuadDomainCPIndexed: + control_point_array_size = 4; + break; + default: + // TODO(Triang3l): Support line patches. + assert_unhandled_case(host_vertex_shader_type()); + EmitTranslationError( + "Unsupported host vertex shader type in " + "StartVertexOrDomainShader"); + 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 { - // Unswapped vertex index input (only X component). - shader_object_.push_back( - ENCODE_D3D10_SB_OPCODE_TYPE(D3D10_SB_OPCODE_DCL_INPUT_SGV) | - ENCODE_D3D10_SB_TOKENIZED_INSTRUCTION_LENGTH(4)); - shader_object_.push_back( - EncodeVectorMaskedOperand(D3D10_SB_OPERAND_TYPE_INPUT, 0b0001, 1)); - shader_object_.push_back(uint32_t(InOutRegister::kVSInVertexIndex)); - shader_object_.push_back(ENCODE_D3D10_SB_NAME(D3D10_SB_NAME_VERTEX_ID)); - ++stat_.dcl_count; + if (register_count()) { + // Unswapped vertex index input (only X component). + shader_object_.push_back( + ENCODE_D3D10_SB_OPCODE_TYPE(D3D10_SB_OPCODE_DCL_INPUT_SGV) | + ENCODE_D3D10_SB_TOKENIZED_INSTRUCTION_LENGTH(4)); + shader_object_.push_back( + EncodeVectorMaskedOperand(D3D10_SB_OPERAND_TYPE_INPUT, 0b0001, 1)); + shader_object_.push_back(uint32_t(InOutRegister::kVSInVertexIndex)); + shader_object_.push_back(ENCODE_D3D10_SB_NAME(D3D10_SB_NAME_VERTEX_ID)); + ++stat_.dcl_count; + } } // Interpolator output. for (uint32_t i = 0; i < kInterpolatorCount; ++i) { @@ -3832,16 +3844,18 @@ void DxbcShaderTranslator::WriteShaderCode() { i); ++stat_.dcl_count; } - // Point parameters input (only coordinates, not size, needed). - shader_object_.push_back( - ENCODE_D3D10_SB_OPCODE_TYPE(D3D10_SB_OPCODE_DCL_INPUT_PS) | - ENCODE_D3D10_SB_INPUT_INTERPOLATION_MODE( - D3D10_SB_INTERPOLATION_LINEAR) | - ENCODE_D3D10_SB_TOKENIZED_INSTRUCTION_LENGTH(3)); - shader_object_.push_back( - EncodeVectorMaskedOperand(D3D10_SB_OPERAND_TYPE_INPUT, 0b0011, 1)); - shader_object_.push_back(uint32_t(InOutRegister::kPSInPointParameters)); - ++stat_.dcl_count; + if (register_count()) { + // Point parameters input (only coordinates, not size, needed). + shader_object_.push_back( + ENCODE_D3D10_SB_OPCODE_TYPE(D3D10_SB_OPCODE_DCL_INPUT_PS) | + ENCODE_D3D10_SB_INPUT_INTERPOLATION_MODE( + D3D10_SB_INTERPOLATION_LINEAR) | + ENCODE_D3D10_SB_TOKENIZED_INSTRUCTION_LENGTH(3)); + shader_object_.push_back( + EncodeVectorMaskedOperand(D3D10_SB_OPERAND_TYPE_INPUT, 0b0011, 1)); + shader_object_.push_back(uint32_t(InOutRegister::kPSInPointParameters)); + ++stat_.dcl_count; + } } if (edram_rov_used_) { // Z and W in clip space, for per-sample depth. @@ -3855,19 +3869,19 @@ void DxbcShaderTranslator::WriteShaderCode() { shader_object_.push_back(uint32_t(InOutRegister::kPSInClipSpaceZW)); ++stat_.dcl_count; } - // Position input (only XY needed for ps_param_gen, and the ROV depth code - // calculates the depth from clip space Z and W). - shader_object_.push_back( - ENCODE_D3D10_SB_OPCODE_TYPE(D3D10_SB_OPCODE_DCL_INPUT_PS_SIV) | - ENCODE_D3D10_SB_INPUT_INTERPOLATION_MODE( - D3D10_SB_INTERPOLATION_LINEAR_NOPERSPECTIVE) | - ENCODE_D3D10_SB_TOKENIZED_INSTRUCTION_LENGTH(4)); - shader_object_.push_back( - EncodeVectorMaskedOperand(D3D10_SB_OPERAND_TYPE_INPUT, 0b0011, 1)); - shader_object_.push_back(uint32_t(InOutRegister::kPSInPosition)); - shader_object_.push_back(ENCODE_D3D10_SB_NAME(D3D10_SB_NAME_POSITION)); - ++stat_.dcl_count; - if (edram_rov_used_ || !is_depth_only_pixel_shader_) { + if (edram_rov_used_ || (!is_depth_only_pixel_shader_ && register_count())) { + // Position input (only XY needed for ps_param_gen, and the ROV depth code + // calculates the depth from clip space Z and W). + shader_object_.push_back( + ENCODE_D3D10_SB_OPCODE_TYPE(D3D10_SB_OPCODE_DCL_INPUT_PS_SIV) | + ENCODE_D3D10_SB_INPUT_INTERPOLATION_MODE( + D3D10_SB_INTERPOLATION_LINEAR_NOPERSPECTIVE) | + ENCODE_D3D10_SB_TOKENIZED_INSTRUCTION_LENGTH(4)); + shader_object_.push_back( + EncodeVectorMaskedOperand(D3D10_SB_OPERAND_TYPE_INPUT, 0b0011, 1)); + shader_object_.push_back(uint32_t(InOutRegister::kPSInPosition)); + shader_object_.push_back(ENCODE_D3D10_SB_NAME(D3D10_SB_NAME_POSITION)); + ++stat_.dcl_count; // Is front face. shader_object_.push_back( ENCODE_D3D10_SB_OPCODE_TYPE(D3D10_SB_OPCODE_DCL_INPUT_PS_SGV) | diff --git a/src/xenia/gpu/dxbc_shader_translator.h b/src/xenia/gpu/dxbc_shader_translator.h index 2a40b267a..42cbe5ac5 100644 --- a/src/xenia/gpu/dxbc_shader_translator.h +++ b/src/xenia/gpu/dxbc_shader_translator.h @@ -2357,6 +2357,10 @@ class DxbcShaderTranslator : public ShaderTranslator { // the remaining ones can be marked as unused in RDEF. uint64_t system_constants_used_; + // Mask of domain location actually used in the domain shader. + uint32_t in_domain_location_used_; + // Whether the primitive ID has been used in the domain shader. + bool in_primitive_id_used_; // Whether InOutRegister::kDSInControlPointIndex has been used in the shader. bool in_control_point_index_used_; diff --git a/src/xenia/gpu/shader.h b/src/xenia/gpu/shader.h index ac89bdc0a..11f92031c 100644 --- a/src/xenia/gpu/shader.h +++ b/src/xenia/gpu/shader.h @@ -646,12 +646,12 @@ class Shader { // packed. This is : uint32_t for simplicity of packing in bit fields. enum class HostVertexShaderType : uint32_t { kVertex, - kLineDomainConstant, - kLineDomainAdaptive, - kTriangleDomainConstant, - kTriangleDomainAdaptive, - kQuadDomainConstant, - kQuadDomainAdaptive, + kLineDomainCPIndexed, + kLineDomainPatchIndexed, + kTriangleDomainCPIndexed, + kTriangleDomainPatchIndexed, + kQuadDomainCPIndexed, + kQuadDomainPatchIndexed, }; struct Error { diff --git a/src/xenia/gpu/shader_compiler_main.cc b/src/xenia/gpu/shader_compiler_main.cc index 77bda5ab5..d5c8dd51e 100644 --- a/src/xenia/gpu/shader_compiler_main.cc +++ b/src/xenia/gpu/shader_compiler_main.cc @@ -38,8 +38,8 @@ DEFINE_string(shader_output_type, "ucode", DEFINE_string( vertex_shader_output_type, "", "Type of the host interface to produce the vertex or domain shader for: " - "[vertex or unspecified, linedomain, linedomainadaptive, triangledomain, " - "triangledomainadaptive, quaddomain, quaddomainadaptive].", + "[vertex or unspecified, linedomaincp, linedomainpatch, triangledomaincp, " + "triangledomainpatch, quaddomaincp, quaddomainpatch].", "GPU"); DEFINE_bool(shader_output_dxbc_rov, false, "Output ROV-based output-merger code in DXBC pixel shaders.", @@ -117,24 +117,24 @@ int shader_compiler_main(const std::vector& args) { Shader::HostVertexShaderType host_vertex_shader_type = Shader::HostVertexShaderType::kVertex; if (shader_type == ShaderType::kVertex) { - if (cvars::vertex_shader_output_type == "linedomain") { + if (cvars::vertex_shader_output_type == "linedomaincp") { host_vertex_shader_type = - Shader::HostVertexShaderType::kLineDomainConstant; - } else if (cvars::vertex_shader_output_type == "linedomainadaptive") { + Shader::HostVertexShaderType::kLineDomainCPIndexed; + } else if (cvars::vertex_shader_output_type == "linedomainpatch") { host_vertex_shader_type = - Shader::HostVertexShaderType::kLineDomainAdaptive; - } else if (cvars::vertex_shader_output_type == "triangledomain") { + Shader::HostVertexShaderType::kLineDomainPatchIndexed; + } else if (cvars::vertex_shader_output_type == "triangledomaincp") { host_vertex_shader_type = - Shader::HostVertexShaderType::kTriangleDomainConstant; - } else if (cvars::vertex_shader_output_type == "triangledomainadaptive") { + Shader::HostVertexShaderType::kTriangleDomainCPIndexed; + } else if (cvars::vertex_shader_output_type == "triangledomainpatch") { host_vertex_shader_type = - Shader::HostVertexShaderType::kTriangleDomainAdaptive; - } else if (cvars::vertex_shader_output_type == "quaddomain") { + Shader::HostVertexShaderType::kTriangleDomainPatchIndexed; + } else if (cvars::vertex_shader_output_type == "quaddomaincp") { host_vertex_shader_type = - Shader::HostVertexShaderType::kQuadDomainConstant; - } else if (cvars::vertex_shader_output_type == "quaddomainadaptive") { + Shader::HostVertexShaderType::kQuadDomainCPIndexed; + } else if (cvars::vertex_shader_output_type == "quaddomainpatch") { host_vertex_shader_type = - Shader::HostVertexShaderType::kQuadDomainAdaptive; + Shader::HostVertexShaderType::kQuadDomainPatchIndexed; } } diff --git a/src/xenia/gpu/xenos.h b/src/xenia/gpu/xenos.h index 11081663c..bdaa309a9 100644 --- a/src/xenia/gpu/xenos.h +++ b/src/xenia/gpu/xenos.h @@ -52,10 +52,9 @@ enum class PrimitiveType : uint32_t { k2DLineStrip = 0x15, k2DTriStrip = 0x16, - // Tessellation patches (D3DTPT) when VGT_OUTPUT_PATH_CNTL::path_select is - // xenos::VGTOutputPath::kTessellationEnable. Seen being used with adaptive - // tessellation in Banjo-Kazooie: Nuts & Bolts, Halo 3 and Viva Pinata; - // discrete/continuous uses kTriangleList in Call of Duty 3 and Viva Pinata. + // Tessellation patches when VGT_OUTPUT_PATH_CNTL::path_select is + // xenos::VGTOutputPath::kTessellationEnable. The vertex shader receives patch + // index rather than control point indices. kLinePatch = 0x10, kTrianglePatch = 0x11, kQuadPatch = 0x12, diff --git a/tools/shader-playground/Editor.Designer.cs b/tools/shader-playground/Editor.Designer.cs index 56a68bdd7..f57e550e4 100644 --- a/tools/shader-playground/Editor.Designer.cs +++ b/tools/shader-playground/Editor.Designer.cs @@ -87,12 +87,12 @@ this.vertexShaderComboBox.FormattingEnabled = true; this.vertexShaderComboBox.Items.AddRange(new object[] { "VS to VS", - "VS to isoline DS with constant factors", - "VS to isoline DS with adaptive factors", - "VS to triangle DS with constant factors", - "VS to triangle DS with adaptive factors", - "VS to quad DS with constant factors", - "VS to quad DS with adaptive factors"}); + "VS to line DS with control point indices", + "VS to line DS with patch index", + "VS to triangle DS with control point indices", + "VS to triangle DS with patch index", + "VS to quad DS with control point indices", + "VS to quad DS with patch index"}); this.vertexShaderComboBox.Location = new System.Drawing.Point(1224, 24); this.vertexShaderComboBox.Margin = new System.Windows.Forms.Padding(3, 3, 3, 0); this.vertexShaderComboBox.Name = "vertexShaderComboBox"; diff --git a/tools/shader-playground/Editor.cs b/tools/shader-playground/Editor.cs index 017773b39..52d1f6a6e 100644 --- a/tools/shader-playground/Editor.cs +++ b/tools/shader-playground/Editor.cs @@ -242,22 +242,22 @@ namespace shader_playground { string vertexShaderType = "vertex"; switch (vertexShaderComboBox.SelectedIndex) { case 1: - vertexShaderType = "linedomain"; + vertexShaderType = "linedomaincp"; break; case 2: - vertexShaderType = "linedomainadaptive"; + vertexShaderType = "linedomainpatch"; break; case 3: - vertexShaderType = "triangledomain"; + vertexShaderType = "triangledomaincp"; break; case 4: - vertexShaderType = "triangledomainadaptive"; + vertexShaderType = "triangledomainpatch"; break; case 5: - vertexShaderType = "quaddomain"; + vertexShaderType = "quaddomaincp"; break; case 6: - vertexShaderType = "quaddomainadaptive"; + vertexShaderType = "quaddomainpatch"; break; }