diff --git a/src/xenia/gpu/d3d12/d3d12_command_processor.cc b/src/xenia/gpu/d3d12/d3d12_command_processor.cc index 8e28702f0..ea5b3b567 100644 --- a/src/xenia/gpu/d3d12/d3d12_command_processor.cc +++ b/src/xenia/gpu/d3d12/d3d12_command_processor.cc @@ -948,6 +948,9 @@ bool D3D12CommandProcessor::IssueDraw(PrimitiveType primitive_type, case PrimitiveType::kTriangleStrip: primitive_topology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP; break; + case PrimitiveType::kQuadList: + primitive_topology = D3D_PRIMITIVE_TOPOLOGY_LINELIST_ADJ; + break; default: return false; } diff --git a/src/xenia/gpu/d3d12/pipeline_cache.cc b/src/xenia/gpu/d3d12/pipeline_cache.cc index b9c388706..00f95f0f2 100644 --- a/src/xenia/gpu/d3d12/pipeline_cache.cc +++ b/src/xenia/gpu/d3d12/pipeline_cache.cc @@ -27,6 +27,7 @@ namespace gpu { namespace d3d12 { // Generated with `xb buildhlsl`. +#include "xenia/gpu/d3d12/shaders/bin/primitive_quad_list_gs.h" #include "xenia/gpu/d3d12/shaders/bin/primitive_rectangle_list_gs.h" PipelineCache::PipelineCache(D3D12CommandProcessor* command_processor, @@ -275,15 +276,26 @@ PipelineCache::UpdateStatus PipelineCache::UpdateShaderStages( dirty |= regs.pixel_shader != pixel_shader; regs.vertex_shader = vertex_shader; regs.pixel_shader = pixel_shader; - // Points are emulated via a geometry shader because Direct3D 10+ doesn't - // support point sizes other than 1. - bool primitive_topology_is_line = - primitive_type == PrimitiveType::kLineList || - primitive_type == PrimitiveType::kLineStrip || - primitive_type == PrimitiveType::kLineLoop || - primitive_type == PrimitiveType::k2DLineStrip; - dirty |= regs.primitive_topology_is_line != primitive_topology_is_line; - if (primitive_type == PrimitiveType::kRectangleList) { + // This topology type is before the geometry shader stage. + D3D12_PRIMITIVE_TOPOLOGY_TYPE primitive_topology_type; + switch (primitive_type) { + case PrimitiveType::kPointList: + primitive_topology_type = D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT; + break; + case PrimitiveType::kLineList: + case PrimitiveType::kLineStrip: + case PrimitiveType::kLineLoop: + // Quads are emulated as line lists with adjacency. + case PrimitiveType::kQuadList: + case PrimitiveType::k2DLineStrip: + primitive_topology_type = D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE; + break; + default: + primitive_topology_type = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; + }; + dirty |= regs.primitive_topology_type != primitive_topology_type; + if (primitive_type == PrimitiveType::kRectangleList || + primitive_type == PrimitiveType::kQuadList) { dirty |= regs.geometry_shader_primitive_type != primitive_type; regs.geometry_shader_primitive_type = primitive_type; } else { @@ -318,14 +330,16 @@ PipelineCache::UpdateStatus PipelineCache::UpdateShaderStages( update_desc_.GS.pShaderBytecode = primitive_rectangle_list_gs; update_desc_.GS.BytecodeLength = sizeof(primitive_rectangle_list_gs); break; + case PrimitiveType::kQuadList: + update_desc_.GS.pShaderBytecode = primitive_quad_list_gs; + update_desc_.GS.BytecodeLength = sizeof(primitive_quad_list_gs); + break; default: // TODO(Triang3l): More geometry shaders for various primitive types. update_desc_.GS.pShaderBytecode = nullptr; update_desc_.GS.BytecodeLength = 0; } - update_desc_.PrimitiveTopologyType = - primitive_topology_is_line ? D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE - : D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; + update_desc_.PrimitiveTopologyType = primitive_topology_type; return UpdateStatus::kMismatch; } diff --git a/src/xenia/gpu/d3d12/pipeline_cache.h b/src/xenia/gpu/d3d12/pipeline_cache.h index 1bdfaf3d9..138e274de 100644 --- a/src/xenia/gpu/d3d12/pipeline_cache.h +++ b/src/xenia/gpu/d3d12/pipeline_cache.h @@ -115,7 +115,7 @@ class PipelineCache { struct UpdateShaderStagesRegisters { D3D12Shader* vertex_shader; D3D12Shader* pixel_shader; - bool primitive_topology_is_line; + D3D12_PRIMITIVE_TOPOLOGY_TYPE primitive_topology_type; // Primitive type if it needs a geometry shader, or kNone. PrimitiveType geometry_shader_primitive_type; diff --git a/src/xenia/gpu/d3d12/shaders/primitive_quad_list.gs.hlsl b/src/xenia/gpu/d3d12/shaders/primitive_quad_list.gs.hlsl new file mode 100644 index 000000000..0b4c5b524 --- /dev/null +++ b/src/xenia/gpu/d3d12/shaders/primitive_quad_list.gs.hlsl @@ -0,0 +1,15 @@ +struct XeVertex { + float4 interpolators[16] : TEXCOORD; + float4 position : SV_Position; + float point_size : PSIZE; +}; + +[maxvertexcount(4)] +void main(lineadj XeVertex xe_in[4], + inout TriangleStream xe_stream) { + xe_stream.Append(xe_in[0]); + xe_stream.Append(xe_in[1]); + xe_stream.Append(xe_in[3]); + xe_stream.Append(xe_in[2]); + xe_stream.RestartStrip(); +} diff --git a/src/xenia/gpu/d3d12/shaders/primitive_rectangle_list.gs.hlsl b/src/xenia/gpu/d3d12/shaders/primitive_rectangle_list.gs.hlsl index 1deb33c9d..26d82c6c7 100644 --- a/src/xenia/gpu/d3d12/shaders/primitive_rectangle_list.gs.hlsl +++ b/src/xenia/gpu/d3d12/shaders/primitive_rectangle_list.gs.hlsl @@ -5,21 +5,13 @@ struct XeVertex { }; [maxvertexcount(6)] -void main(triangle XeVertex xe_in[3], inout TriangleStream xe_stream) { +void main(triangle XeVertex xe_in[3], + inout TriangleStream xe_stream) { XeVertex xe_out; - xe_out.interpolators = xe_in[0].interpolators; - xe_out.position = xe_in[0].position; - xe_out.point_size = xe_in[0].point_size; - xe_stream.Append(xe_out); - xe_out.interpolators = xe_in[1].interpolators; - xe_out.position = xe_in[1].position; - xe_out.point_size = xe_in[1].point_size; - xe_stream.Append(xe_out); - xe_out.interpolators = xe_in[2].interpolators; - xe_out.position = xe_in[2].position; - xe_out.point_size = xe_in[2].point_size; - xe_stream.Append(xe_out); + xe_stream.Append(xe_in[0]); + xe_stream.Append(xe_in[1]); + xe_stream.Append(xe_in[2]); xe_stream.RestartStrip(); // Most games use a left-aligned form. @@ -38,14 +30,8 @@ void main(triangle XeVertex xe_in[3], inout TriangleStream xe_stream) // | // | 2: 1,-1 // | - | 3: [ 1, 1 ] // 1 ------[3] - xe_out.interpolators = xe_in[2].interpolators; - xe_out.position = xe_in[2].position; - xe_out.point_size = xe_in[2].point_size; - xe_stream.Append(xe_out); - xe_out.interpolators = xe_in[1].interpolators; - xe_out.position = xe_in[1].position; - xe_out.point_size = xe_in[1].point_size; - xe_stream.Append(xe_out); + xe_stream.Append(xe_in[2]); + xe_stream.Append(xe_in[1]); [unroll] for (int i = 0; i < 16; ++i) { xe_out.interpolators[i] = xe_in[1].interpolators[i] - xe_in[0].interpolators[i] + @@ -61,14 +47,8 @@ void main(triangle XeVertex xe_in[3], inout TriangleStream xe_stream) // | \\ | 2: 1, 1 // | - | 3: [-1, 1 ] // [3] ----- 2 - xe_out.interpolators = xe_in[0].interpolators; - xe_out.position = xe_in[0].position; - xe_out.point_size = xe_in[0].point_size; - xe_stream.Append(xe_out); - xe_out.interpolators = xe_in[2].interpolators; - xe_out.position = xe_in[2].position; - xe_out.point_size = xe_in[2].point_size; - xe_stream.Append(xe_out); + xe_stream.Append(xe_in[0]); + xe_stream.Append(xe_in[2]); [unroll] for (int i = 0; i < 16; ++i) { xe_out.interpolators[i] = xe_in[0].interpolators[i] - xe_in[1].interpolators[i] +