[GPU] Move common-face polygon offset to draw_util

This commit is contained in:
Triang3l 2022-02-13 21:18:02 +03:00
parent 8d07c79897
commit 10ec47e1fe
3 changed files with 48 additions and 21 deletions

View File

@ -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<reg::RB_DEPTH_INFO>().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;

View File

@ -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<reg::PA_SU_SC_MODE_CNTL>();
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);

View File

@ -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) ||