diff --git a/src/xenia/gpu/d3d12/d3d12_command_processor.cc b/src/xenia/gpu/d3d12/d3d12_command_processor.cc index 4e2ca3370..5b216b22b 100644 --- a/src/xenia/gpu/d3d12/d3d12_command_processor.cc +++ b/src/xenia/gpu/d3d12/d3d12_command_processor.cc @@ -1876,14 +1876,14 @@ bool D3D12CommandProcessor::IssueDraw(xenos::PrimitiveType primitive_type, !pixel_shader->memexport_stream_constants().empty(); bool memexport_used = memexport_used_vertex || memexport_used_pixel; - bool primitive_two_faced = - xenos::IsPrimitiveTwoFaced(tessellated, primitive_type); + bool primitive_polygonal = + xenos::IsPrimitivePolygonal(tessellated, primitive_type); auto sq_program_cntl = regs.Get(); auto pa_su_sc_mode_cntl = regs.Get(); if (!memexport_used_vertex && (sq_program_cntl.vs_export_mode == xenos::VertexShaderExportMode::kMultipass || - (primitive_two_faced && pa_su_sc_mode_cntl.cull_front && + (primitive_polygonal && pa_su_sc_mode_cntl.cull_front && pa_su_sc_mode_cntl.cull_back))) { // All faces are culled - can't be expressed in the pipeline. return true; @@ -2027,11 +2027,11 @@ bool D3D12CommandProcessor::IssueDraw(xenos::PrimitiveType primitive_type, scissor.height *= pixel_size_y; // Update viewport, scissor, blend factor and stencil reference. - UpdateFixedFunctionState(viewport_info, scissor, primitive_two_faced); + UpdateFixedFunctionState(viewport_info, scissor, primitive_polygonal); // Update system constants before uploading them. UpdateSystemConstantValues( - memexport_used, primitive_two_faced, line_loop_closing_index, + memexport_used, primitive_polygonal, line_loop_closing_index, indexed ? index_buffer_info->endianness : xenos::Endian::kNone, viewport_info, pixel_size_x, pixel_size_y, used_texture_mask, early_z, GetCurrentColorMask(pixel_shader), pipeline_render_targets); @@ -2785,7 +2785,7 @@ void D3D12CommandProcessor::ClearCommandAllocatorCache() { void D3D12CommandProcessor::UpdateFixedFunctionState( const draw_util::ViewportInfo& viewport_info, - const draw_util::Scissor& scissor, bool primitive_two_faced) { + const draw_util::Scissor& scissor, bool primitive_polygonal) { #if XE_UI_D3D12_FINE_GRAINED_DRAW_SCOPES SCOPE_profile_cpu_f("gpu"); #endif // XE_UI_D3D12_FINE_GRAINED_DRAW_SCOPES @@ -2851,7 +2851,7 @@ void D3D12CommandProcessor::UpdateFixedFunctionState( // choose the back face one only if drawing only back faces. Register stencil_ref_mask_reg; auto pa_su_sc_mode_cntl = regs.Get(); - if (primitive_two_faced && + if (primitive_polygonal && regs.Get().backface_enable && pa_su_sc_mode_cntl.cull_front && !pa_su_sc_mode_cntl.cull_back) { stencil_ref_mask_reg = XE_GPU_REG_RB_STENCILREFMASK_BF; @@ -2870,7 +2870,7 @@ void D3D12CommandProcessor::UpdateFixedFunctionState( } void D3D12CommandProcessor::UpdateSystemConstantValues( - bool shared_memory_is_uav, bool primitive_two_faced, + bool shared_memory_is_uav, bool primitive_polygonal, uint32_t line_loop_closing_index, xenos::Endian index_endian, const draw_util::ViewportInfo& viewport_info, uint32_t pixel_size_x, uint32_t pixel_size_y, uint32_t used_texture_mask, bool early_z, @@ -2983,9 +2983,9 @@ void D3D12CommandProcessor::UpdateSystemConstantValues( flags |= (pa_cl_clip_cntl.value & 0b111111) << DxbcShaderTranslator::kSysFlag_UserClipPlane0_Shift; } - // Whether SV_IsFrontFace matters. - if (primitive_two_faced) { - flags |= DxbcShaderTranslator::kSysFlag_PrimitiveTwoFaced; + // Whether the primitive is polygonal and SV_IsFrontFace matters. + if (primitive_polygonal) { + flags |= DxbcShaderTranslator::kSysFlag_PrimitivePolygonal; } // Primitive killing condition. if (pa_cl_clip_cntl.vtx_kill_or) { @@ -3082,7 +3082,7 @@ void D3D12CommandProcessor::UpdateSystemConstantValues( // to do memexport. if (sq_program_cntl.vs_export_mode == xenos::VertexShaderExportMode::kMultipass || - (primitive_two_faced && pa_su_sc_mode_cntl.cull_front && + (primitive_polygonal && pa_su_sc_mode_cntl.cull_front && pa_su_sc_mode_cntl.cull_back)) { float nan_value = std::nanf(""); for (uint32_t i = 0; i < 3; ++i) { @@ -3275,7 +3275,7 @@ void D3D12CommandProcessor::UpdateSystemConstantValues( // are used. float poly_offset_front_scale = 0.0f, poly_offset_front_offset = 0.0f; float poly_offset_back_scale = 0.0f, poly_offset_back_offset = 0.0f; - if (primitive_two_faced) { + if (primitive_polygonal) { if (pa_su_sc_mode_cntl.poly_offset_front_enable) { poly_offset_front_scale = regs[XE_GPU_REG_PA_SU_POLY_OFFSET_FRONT_SCALE].f32; @@ -3338,7 +3338,7 @@ void D3D12CommandProcessor::UpdateSystemConstantValues( system_constants_.edram_stencil_front_func_ops != stencil_func_ops; system_constants_.edram_stencil_front_func_ops = stencil_func_ops; - if (primitive_two_faced && rb_depthcontrol.backface_enable) { + if (primitive_polygonal && rb_depthcontrol.backface_enable) { dirty |= system_constants_.edram_stencil_back_reference != rb_stencilrefmask_bf.stencilref; system_constants_.edram_stencil_back_reference = diff --git a/src/xenia/gpu/d3d12/d3d12_command_processor.h b/src/xenia/gpu/d3d12/d3d12_command_processor.h index 982f9eac5..c75b5c203 100644 --- a/src/xenia/gpu/d3d12/d3d12_command_processor.h +++ b/src/xenia/gpu/d3d12/d3d12_command_processor.h @@ -348,9 +348,9 @@ class D3D12CommandProcessor : public CommandProcessor { void UpdateFixedFunctionState(const draw_util::ViewportInfo& viewport_info, const draw_util::Scissor& scissor, - bool primitive_two_faced); + bool primitive_polygonal); void UpdateSystemConstantValues( - bool shared_memory_is_uav, bool primitive_two_faced, + bool shared_memory_is_uav, bool primitive_polygonal, uint32_t line_loop_closing_index, xenos::Endian index_endian, const draw_util::ViewportInfo& viewport_info, uint32_t pixel_size_x, uint32_t pixel_size_y, uint32_t used_texture_mask, bool early_z, diff --git a/src/xenia/gpu/d3d12/pipeline_cache.cc b/src/xenia/gpu/d3d12/pipeline_cache.cc index b2db2654e..e69299f3d 100644 --- a/src/xenia/gpu/d3d12/pipeline_cache.cc +++ b/src/xenia/gpu/d3d12/pipeline_cache.cc @@ -1285,7 +1285,7 @@ bool PipelineCache::GetCurrentStateDescription( uint32_t(regs.Get().tess_mode); } - bool primitive_two_faced = xenos::IsPrimitiveTwoFaced( + bool primitive_polygonal = xenos::IsPrimitivePolygonal( host_vertex_shader_type != Shader::HostVertexShaderType::kVertex, primitive_type); @@ -1305,15 +1305,16 @@ bool PipelineCache::GetCurrentStateDescription( // Here we also assume that only one side is culled - if two sides are culled, // the D3D12 command processor will drop such draw early. bool cull_front, cull_back; - if (primitive_two_faced) { + if (primitive_polygonal) { cull_front = pa_su_sc_mode_cntl.cull_front != 0; cull_back = pa_su_sc_mode_cntl.cull_back != 0; } else { + // Non-polygonal primitives are never culled. cull_front = false; cull_back = false; } float poly_offset = 0.0f, poly_offset_scale = 0.0f; - if (primitive_two_faced) { + if (primitive_polygonal) { description_out.front_counter_clockwise = pa_su_sc_mode_cntl.face == 0; if (cull_front) { description_out.cull_mode = PipelineCullMode::kFront; @@ -1327,8 +1328,8 @@ bool PipelineCache::GetCurrentStateDescription( if (!cull_front) { // Front faces aren't culled. // Direct3D 12, unfortunately, doesn't support point fill mode. - if (pa_su_sc_mode_cntl.polymode_front_ptype != - xenos::PolygonType::kTriangles) { + if (primitive_polygonal && pa_su_sc_mode_cntl.polymode_front_ptype != + xenos::PolygonType::kTriangles) { description_out.fill_mode_wireframe = 1; } if (!edram_rov_used_ && pa_su_sc_mode_cntl.poly_offset_front_enable) { @@ -1338,8 +1339,8 @@ bool PipelineCache::GetCurrentStateDescription( } if (!cull_back) { // Back faces aren't culled. - if (pa_su_sc_mode_cntl.polymode_back_ptype != - xenos::PolygonType::kTriangles) { + if (primitive_polygonal && pa_su_sc_mode_cntl.polymode_back_ptype != + xenos::PolygonType::kTriangles) { description_out.fill_mode_wireframe = 1; } // Prefer front depth bias because in general, front faces are the ones @@ -1413,7 +1414,7 @@ bool PipelineCache::GetCurrentStateDescription( if (rb_depthcontrol.stencil_enable) { description_out.stencil_enable = 1; bool stencil_backface_enable = - primitive_two_faced && rb_depthcontrol.backface_enable; + primitive_polygonal && rb_depthcontrol.backface_enable; // Per-face masks not supported by Direct3D 12, choose the back face // ones only if drawing only back faces. Register stencil_ref_mask_reg; diff --git a/src/xenia/gpu/dxbc_shader_translator.cc b/src/xenia/gpu/dxbc_shader_translator.cc index 56278157d..a08cafd5e 100644 --- a/src/xenia/gpu/dxbc_shader_translator.cc +++ b/src/xenia/gpu/dxbc_shader_translator.cc @@ -770,7 +770,7 @@ void DxbcShaderTranslator::StartPixelShader() { uint32_t(CbufferRegister::kSystemConstants), kSysConst_Flags_Vec) .Select(kSysConst_Flags_Comp), - DxbcSrc::LU(kSysFlag_PrimitiveTwoFaced)); + DxbcSrc::LU(kSysFlag_PrimitivePolygonal)); DxbcOpIf(true, DxbcSrc::R(param_gen_temp, DxbcSrc::kZZZZ)); { // Negate modifier flips the sign bit even for 0 - set it to minus for diff --git a/src/xenia/gpu/dxbc_shader_translator.h b/src/xenia/gpu/dxbc_shader_translator.h index 997be5fe7..9edc40b56 100644 --- a/src/xenia/gpu/dxbc_shader_translator.h +++ b/src/xenia/gpu/dxbc_shader_translator.h @@ -124,7 +124,7 @@ class DxbcShaderTranslator : public ShaderTranslator { kSysFlag_UserClipPlane4_Shift, kSysFlag_UserClipPlane5_Shift, kSysFlag_KillIfAnyVertexKilled_Shift, - kSysFlag_PrimitiveTwoFaced_Shift, + kSysFlag_PrimitivePolygonal_Shift, kSysFlag_AlphaPassIfLess_Shift, kSysFlag_AlphaPassIfEqual_Shift, kSysFlag_AlphaPassIfGreater_Shift, @@ -165,7 +165,7 @@ class DxbcShaderTranslator : public ShaderTranslator { kSysFlag_UserClipPlane4 = 1u << kSysFlag_UserClipPlane4_Shift, kSysFlag_UserClipPlane5 = 1u << kSysFlag_UserClipPlane5_Shift, kSysFlag_KillIfAnyVertexKilled = 1u << kSysFlag_KillIfAnyVertexKilled_Shift, - kSysFlag_PrimitiveTwoFaced = 1u << kSysFlag_PrimitiveTwoFaced_Shift, + kSysFlag_PrimitivePolygonal = 1u << kSysFlag_PrimitivePolygonal_Shift, kSysFlag_AlphaPassIfLess = 1u << kSysFlag_AlphaPassIfLess_Shift, kSysFlag_AlphaPassIfEqual = 1u << kSysFlag_AlphaPassIfEqual_Shift, kSysFlag_AlphaPassIfGreater = 1u << kSysFlag_AlphaPassIfGreater_Shift, diff --git a/src/xenia/gpu/xenos.h b/src/xenia/gpu/xenos.h index 0fdcdffbe..d3a78a850 100644 --- a/src/xenia/gpu/xenos.h +++ b/src/xenia/gpu/xenos.h @@ -64,7 +64,15 @@ enum class PrimitiveType : uint32_t { kQuadPatch = 0x12, }; -inline bool IsPrimitiveTwoFaced(bool tessellated, PrimitiveType type) { +// Polygonal primitive types (not including points and lines) are rasterized as +// triangles, have front and back faces, and also support face culling and fill +// modes (polymode_front_ptype, polymode_back_ptype). Other primitive types are +// always "front" (but don't support front face and back face culling, according +// to OpenGL and Vulkan specifications - even if glCullFace is +// GL_FRONT_AND_BACK, points and lines are still drawn), and may in some cases +// use the "para" registers instead of "front" or "back" (for "parallelogram" - +// like poly_offset_para_enable). +constexpr bool IsPrimitivePolygonal(bool tessellated, PrimitiveType type) { if (tessellated && (type == PrimitiveType::kTrianglePatch || type == PrimitiveType::kQuadPatch)) { return true; @@ -74,6 +82,7 @@ inline bool IsPrimitiveTwoFaced(bool tessellated, PrimitiveType type) { case PrimitiveType::kTriangleFan: case PrimitiveType::kTriangleStrip: case PrimitiveType::kTriangleWithWFlags: + case PrimitiveType::kRectangleList: case PrimitiveType::kQuadList: case PrimitiveType::kQuadStrip: case PrimitiveType::kPolygon: