From 10ec47e1fe3a529d3e394a8186fbd0e2b11530f0 Mon Sep 17 00:00:00 2001 From: Triang3l Date: Sun, 13 Feb 2022 21:18:02 +0300 Subject: [PATCH] [GPU] Move common-face polygon offset to draw_util --- src/xenia/gpu/d3d12/pipeline_cache.cc | 29 +++++++------------------- src/xenia/gpu/draw_util.cc | 30 +++++++++++++++++++++++++++ src/xenia/gpu/draw_util.h | 10 +++++++++ 3 files changed, 48 insertions(+), 21 deletions(-) diff --git a/src/xenia/gpu/d3d12/pipeline_cache.cc b/src/xenia/gpu/d3d12/pipeline_cache.cc index ff75f4151..494a53dac 100644 --- a/src/xenia/gpu/d3d12/pipeline_cache.cc +++ b/src/xenia/gpu/d3d12/pipeline_cache.cc @@ -1411,7 +1411,6 @@ bool PipelineCache::GetCurrentStateDescription( // rasterization will be disabled externally, or the draw call will be dropped // early if the vertex shader doesn't export to memory. bool cull_front, cull_back; - float poly_offset = 0.0f, poly_offset_scale = 0.0f; if (primitive_polygonal) { description_out.front_counter_clockwise = pa_su_sc_mode_cntl.face == 0; cull_front = pa_su_sc_mode_cntl.cull_front != 0; @@ -1435,10 +1434,6 @@ bool PipelineCache::GetCurrentStateDescription( xenos::PolygonType::kTriangles) { description_out.fill_mode_wireframe = 1; } - if (!edram_rov_used && pa_su_sc_mode_cntl.poly_offset_front_enable) { - poly_offset = regs[XE_GPU_REG_PA_SU_POLY_OFFSET_FRONT_OFFSET].f32; - poly_offset_scale = regs[XE_GPU_REG_PA_SU_POLY_OFFSET_FRONT_SCALE].f32; - } } if (!cull_back) { // Back faces aren't culled. @@ -1446,13 +1441,6 @@ bool PipelineCache::GetCurrentStateDescription( xenos::PolygonType::kTriangles) { description_out.fill_mode_wireframe = 1; } - // Prefer front depth bias because in general, front faces are the ones - // that are rendered (except for shadow volumes). - if (!edram_rov_used && pa_su_sc_mode_cntl.poly_offset_back_enable && - poly_offset == 0.0f && poly_offset_scale == 0.0f) { - poly_offset = regs[XE_GPU_REG_PA_SU_POLY_OFFSET_BACK_OFFSET].f32; - poly_offset_scale = regs[XE_GPU_REG_PA_SU_POLY_OFFSET_BACK_SCALE].f32; - } } if (pa_su_sc_mode_cntl.poly_mode != xenos::PolygonModeEnable::kDualMode) { description_out.fill_mode_wireframe = 0; @@ -1461,24 +1449,23 @@ bool PipelineCache::GetCurrentStateDescription( // Filled front faces only, without culling. cull_front = false; cull_back = false; - if (!edram_rov_used && pa_su_sc_mode_cntl.poly_offset_para_enable) { - poly_offset = regs[XE_GPU_REG_PA_SU_POLY_OFFSET_FRONT_OFFSET].f32; - poly_offset_scale = regs[XE_GPU_REG_PA_SU_POLY_OFFSET_FRONT_SCALE].f32; - } } if (!edram_rov_used) { - float poly_offset_host_scale = draw_util::GetD3D10PolygonOffsetFactor( + float polygon_offset, polygon_offset_scale; + draw_util::GetPreferredFacePolygonOffset( + regs, primitive_polygonal, polygon_offset_scale, polygon_offset); + float polygon_offset_host_scale = draw_util::GetD3D10PolygonOffsetFactor( regs.Get().depth_format, true); // Using ceil here just in case a game wants the offset but passes a value // that is too small - it's better to apply more offset than to make depth // fighting worse or to disable the offset completely (Direct3D 12 takes an // integer value). description_out.depth_bias = - int32_t(std::ceil(std::abs(poly_offset * poly_offset_host_scale))) * - (poly_offset < 0.0f ? -1 : 1); - // "slope computed in subpixels ([...] 1/16)" - R5xx Acceleration. + int32_t( + std::ceil(std::abs(polygon_offset * polygon_offset_host_scale))) * + (polygon_offset < 0.0f ? -1 : 1); description_out.depth_bias_slope_scaled = - poly_offset_scale * xenos::kPolygonOffsetScaleSubpixelUnit; + polygon_offset_scale * xenos::kPolygonOffsetScaleSubpixelUnit; } if (tessellated && cvars::d3d12_tessellation_wireframe) { description_out.fill_mode_wireframe = 1; diff --git a/src/xenia/gpu/draw_util.cc b/src/xenia/gpu/draw_util.cc index 370ffeb43..ba01e4b2f 100644 --- a/src/xenia/gpu/draw_util.cc +++ b/src/xenia/gpu/draw_util.cc @@ -68,6 +68,36 @@ const int8_t kD3D10StandardSamplePositions2x[2][2] = {{4, 4}, {-4, -4}}; const int8_t kD3D10StandardSamplePositions4x[4][2] = { {-2, -6}, {6, -2}, {-6, 2}, {2, 6}}; +void GetPreferredFacePolygonOffset(const RegisterFile& regs, + bool primitive_polygonal, float& scale_out, + float& offset_out) { + float scale = 0.0f, offset = 0.0f; + auto pa_su_sc_mode_cntl = regs.Get(); + if (primitive_polygonal) { + // Prefer the front polygon offset because in general, front faces are the + // ones that are rendered (except for shadow volumes). + if (pa_su_sc_mode_cntl.poly_offset_front_enable && + !pa_su_sc_mode_cntl.cull_front) { + scale = regs[XE_GPU_REG_PA_SU_POLY_OFFSET_FRONT_SCALE].f32; + offset = regs[XE_GPU_REG_PA_SU_POLY_OFFSET_FRONT_OFFSET].f32; + } + if (pa_su_sc_mode_cntl.poly_offset_back_enable && + !pa_su_sc_mode_cntl.cull_back && !scale && !offset) { + scale = regs[XE_GPU_REG_PA_SU_POLY_OFFSET_BACK_SCALE].f32; + offset = regs[XE_GPU_REG_PA_SU_POLY_OFFSET_BACK_OFFSET].f32; + } + } else { + // Non-triangle primitives use the front offset, but it's toggled via + // poly_offset_para_enable. + if (pa_su_sc_mode_cntl.poly_offset_para_enable) { + scale = regs[XE_GPU_REG_PA_SU_POLY_OFFSET_FRONT_SCALE].f32; + offset = regs[XE_GPU_REG_PA_SU_POLY_OFFSET_FRONT_OFFSET].f32; + } + } + scale_out = scale; + offset_out = offset; +} + bool IsPixelShaderNeededWithRasterization(const Shader& shader, const RegisterFile& regs) { assert_true(shader.type() == xenos::ShaderType::kPixel); diff --git a/src/xenia/gpu/draw_util.h b/src/xenia/gpu/draw_util.h index 1474461ec..d26ce8a6d 100644 --- a/src/xenia/gpu/draw_util.h +++ b/src/xenia/gpu/draw_util.h @@ -122,6 +122,16 @@ constexpr float GetD3D10PolygonOffsetFactor( return float24_as_0_to_0_5 ? kFloat24Scale * 0.5f : kFloat24Scale; } +// For hosts not supporting separate front and back polygon offsets, returns the +// polygon offset for the face which likely needs the offset the most (and that +// will not be culled). The values returned will have the units of the original +// registers (the scale is for 1/16 subpixels, multiply by +// xenos::kPolygonOffsetScaleSubpixelUnit outside if the value for pixels is +// needed). +void GetPreferredFacePolygonOffset(const RegisterFile& regs, + bool primitive_polygonal, float& scale_out, + float& offset_out); + inline bool DoesCoverageDependOnAlpha(reg::RB_COLORCONTROL rb_colorcontrol) { return (rb_colorcontrol.alpha_test_enable && rb_colorcontrol.alpha_func != xenos::CompareFunction::kAlways) ||