[D3D12] Vertex kill and multipass vertex exports
This commit is contained in:
@@ -1313,10 +1313,14 @@ bool D3D12CommandProcessor::IssueDraw(PrimitiveType primitive_type,
|
||||
bool memexport_used = memexport_used_vertex || memexport_used_pixel;
|
||||
|
||||
bool primitive_two_faced = IsPrimitiveTwoFaced(tessellated, primitive_type);
|
||||
auto sq_program_cntl = regs.Get<reg::SQ_PROGRAM_CNTL>();
|
||||
auto pa_su_sc_mode_cntl = regs.Get<reg::PA_SU_SC_MODE_CNTL>();
|
||||
if (!memexport_used_vertex && primitive_two_faced &&
|
||||
pa_su_sc_mode_cntl.cull_front && pa_su_sc_mode_cntl.cull_back) {
|
||||
// Both sides are culled - can't be expressed in the pipeline state.
|
||||
if (!memexport_used_vertex &&
|
||||
(sq_program_cntl.vs_export_mode ==
|
||||
xenos::VertexShaderExportMode::kMultipass ||
|
||||
(primitive_two_faced && 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 state.
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2440,6 +2444,10 @@ void D3D12CommandProcessor::UpdateSystemConstantValues(
|
||||
if (viewport_scale_z < 0.0f) {
|
||||
flags |= DxbcShaderTranslator::kSysFlag_ReverseZ;
|
||||
}
|
||||
// Primitive killing condition.
|
||||
if (pa_cl_clip_cntl.vtx_kill_or) {
|
||||
flags |= DxbcShaderTranslator::kSysFlag_KillIfAnyVertexKilled;
|
||||
}
|
||||
// Alpha test.
|
||||
if (rb_colorcontrol.alpha_test_enable) {
|
||||
flags |= uint32_t(rb_colorcontrol.alpha_func)
|
||||
@@ -2534,6 +2542,18 @@ void D3D12CommandProcessor::UpdateSystemConstantValues(
|
||||
}
|
||||
}
|
||||
|
||||
// Half pixel offset.
|
||||
bool half_pixel_offset =
|
||||
cvars::d3d12_half_pixel_offset && !pa_su_vtx_cntl.pix_center;
|
||||
// Like in OpenGL - VPOS giving pixel centers, or like in Direct3D 9 - VPOS
|
||||
// giving the top-left corner.
|
||||
// TODO(Triang3l): Check if ps_param_gen should give center positions in
|
||||
// OpenGL mode on the Xbox 360.
|
||||
float param_gen_half_pixel_offset = half_pixel_offset ? 0.0f : 0.5f;
|
||||
dirty |=
|
||||
system_constants_.pixel_half_pixel_offset != param_gen_half_pixel_offset;
|
||||
system_constants_.pixel_half_pixel_offset = param_gen_half_pixel_offset;
|
||||
|
||||
// Conversion to Direct3D 12 normalized device coordinates.
|
||||
// See viewport configuration in UpdateFixedFunctionState for explanations.
|
||||
// X and Y scale/offset is to convert unnormalized coordinates generated by
|
||||
@@ -2545,72 +2565,72 @@ void D3D12CommandProcessor::UpdateSystemConstantValues(
|
||||
// different register (and if there's such register at all).
|
||||
float viewport_scale_x = regs[XE_GPU_REG_PA_CL_VPORT_XSCALE].f32;
|
||||
float viewport_scale_y = regs[XE_GPU_REG_PA_CL_VPORT_YSCALE].f32;
|
||||
// When VPORT_Z_SCALE_ENA is disabled, Z/W is directly what is expected to be
|
||||
// written to the depth buffer, and for some reason DX_CLIP_SPACE_DEF isn't
|
||||
// set in this case in draws in games.
|
||||
bool gl_clip_space_def =
|
||||
!pa_cl_clip_cntl.dx_clip_space_def && pa_cl_vte_cntl.vport_z_scale_ena;
|
||||
float ndc_scale_x, ndc_scale_y, ndc_scale_z;
|
||||
if (primitive_two_faced && pa_su_sc_mode_cntl.cull_front &&
|
||||
pa_su_sc_mode_cntl.cull_back) {
|
||||
// Kill all primitives if both faces are culled, but the vertex shader still
|
||||
// needs to do memexport (not NaN because of comparison for setting the
|
||||
// dirty flag).
|
||||
ndc_scale_x = ndc_scale_y = ndc_scale_z = 0;
|
||||
// Kill all primitives if multipass or both faces are culled, but still need
|
||||
// to do memexport.
|
||||
if (sq_program_cntl.vs_export_mode ==
|
||||
xenos::VertexShaderExportMode::kMultipass ||
|
||||
(primitive_two_faced && pa_su_sc_mode_cntl.cull_front &&
|
||||
pa_su_sc_mode_cntl.cull_back)) {
|
||||
dirty |= !std::isnan(system_constants_.ndc_scale[0]);
|
||||
dirty |= !std::isnan(system_constants_.ndc_scale[1]);
|
||||
dirty |= !std::isnan(system_constants_.ndc_scale[2]);
|
||||
dirty |= !std::isnan(system_constants_.ndc_offset[0]);
|
||||
dirty |= !std::isnan(system_constants_.ndc_offset[1]);
|
||||
dirty |= !std::isnan(system_constants_.ndc_offset[2]);
|
||||
float nan_value = std::nanf("");
|
||||
system_constants_.ndc_scale[0] = nan_value;
|
||||
system_constants_.ndc_scale[1] = nan_value;
|
||||
system_constants_.ndc_scale[2] = nan_value;
|
||||
system_constants_.ndc_offset[0] = nan_value;
|
||||
system_constants_.ndc_offset[1] = nan_value;
|
||||
system_constants_.ndc_offset[2] = nan_value;
|
||||
} else {
|
||||
if (pa_cl_vte_cntl.vport_x_scale_ena) {
|
||||
ndc_scale_x = viewport_scale_x >= 0.0f ? 1.0f : -1.0f;
|
||||
} else {
|
||||
ndc_scale_x = 1.0f / 1280.0f;
|
||||
}
|
||||
if (pa_cl_vte_cntl.vport_y_scale_ena) {
|
||||
ndc_scale_y = viewport_scale_y >= 0.0f ? -1.0f : 1.0f;
|
||||
} else {
|
||||
ndc_scale_y = -1.0f / 1280.0f;
|
||||
}
|
||||
ndc_scale_z = gl_clip_space_def ? 0.5f : 1.0f;
|
||||
}
|
||||
float ndc_offset_x = pa_cl_vte_cntl.vport_x_offset_ena ? 0.0f : -1.0f;
|
||||
float ndc_offset_y = pa_cl_vte_cntl.vport_y_offset_ena ? 0.0f : 1.0f;
|
||||
float ndc_offset_z = gl_clip_space_def ? 0.5f : 0.0f;
|
||||
// Like in OpenGL - VPOS giving pixel centers.
|
||||
// TODO(Triang3l): Check if ps_param_gen should give center positions in
|
||||
// OpenGL mode on the Xbox 360.
|
||||
float pixel_half_pixel_offset = 0.5f;
|
||||
if (cvars::d3d12_half_pixel_offset && !pa_su_vtx_cntl.pix_center) {
|
||||
// Signs are hopefully correct here, tested in GTA IV on both clearing
|
||||
// (without a viewport) and drawing things near the edges of the screen.
|
||||
if (pa_cl_vte_cntl.vport_x_scale_ena) {
|
||||
if (viewport_scale_x != 0.0f) {
|
||||
ndc_offset_x += 0.5f / viewport_scale_x;
|
||||
// When VPORT_Z_SCALE_ENA is disabled, Z/W is directly what is expected to
|
||||
// be written to the depth buffer, and for some reason DX_CLIP_SPACE_DEF
|
||||
// isn't set in this case in draws in games.
|
||||
bool gl_clip_space_def =
|
||||
!pa_cl_clip_cntl.dx_clip_space_def && pa_cl_vte_cntl.vport_z_scale_ena;
|
||||
float ndc_scale_x = pa_cl_vte_cntl.vport_x_scale_ena
|
||||
? (viewport_scale_x >= 0.0f ? 1.0f : -1.0f)
|
||||
: (1.0f / 1280.0f);
|
||||
float ndc_scale_y = pa_cl_vte_cntl.vport_y_scale_ena
|
||||
? (viewport_scale_y >= 0.0f ? -1.0f : 1.0f)
|
||||
: (-1.0f / 1280.0f);
|
||||
float ndc_scale_z = gl_clip_space_def ? 0.5f : 1.0f;
|
||||
float ndc_offset_x = pa_cl_vte_cntl.vport_x_offset_ena ? 0.0f : -1.0f;
|
||||
float ndc_offset_y = pa_cl_vte_cntl.vport_y_offset_ena ? 0.0f : 1.0f;
|
||||
float ndc_offset_z = gl_clip_space_def ? 0.5f : 0.0f;
|
||||
if (half_pixel_offset) {
|
||||
// Signs are hopefully correct here, tested in GTA IV on both clearing
|
||||
// (without a viewport) and drawing things near the edges of the screen.
|
||||
if (pa_cl_vte_cntl.vport_x_scale_ena) {
|
||||
if (viewport_scale_x != 0.0f) {
|
||||
ndc_offset_x += 0.5f / viewport_scale_x;
|
||||
}
|
||||
} else {
|
||||
ndc_offset_x += 1.0f / 2560.0f;
|
||||
}
|
||||
} else {
|
||||
ndc_offset_x += 1.0f / 2560.0f;
|
||||
}
|
||||
if (pa_cl_vte_cntl.vport_y_scale_ena) {
|
||||
if (viewport_scale_y != 0.0f) {
|
||||
ndc_offset_y += 0.5f / viewport_scale_y;
|
||||
if (pa_cl_vte_cntl.vport_y_scale_ena) {
|
||||
if (viewport_scale_y != 0.0f) {
|
||||
ndc_offset_y += 0.5f / viewport_scale_y;
|
||||
}
|
||||
} else {
|
||||
ndc_offset_y -= 1.0f / 2560.0f;
|
||||
}
|
||||
} else {
|
||||
ndc_offset_y -= 1.0f / 2560.0f;
|
||||
}
|
||||
// Like in Direct3D 9 - VPOS giving the top-left corner.
|
||||
pixel_half_pixel_offset = 0.0f;
|
||||
dirty |= system_constants_.ndc_scale[0] != ndc_scale_x;
|
||||
dirty |= system_constants_.ndc_scale[1] != ndc_scale_y;
|
||||
dirty |= system_constants_.ndc_scale[2] != ndc_scale_z;
|
||||
dirty |= system_constants_.ndc_offset[0] != ndc_offset_x;
|
||||
dirty |= system_constants_.ndc_offset[1] != ndc_offset_y;
|
||||
dirty |= system_constants_.ndc_offset[2] != ndc_offset_z;
|
||||
system_constants_.ndc_scale[0] = ndc_scale_x;
|
||||
system_constants_.ndc_scale[1] = ndc_scale_y;
|
||||
system_constants_.ndc_scale[2] = ndc_scale_z;
|
||||
system_constants_.ndc_offset[0] = ndc_offset_x;
|
||||
system_constants_.ndc_offset[1] = ndc_offset_y;
|
||||
system_constants_.ndc_offset[2] = ndc_offset_z;
|
||||
}
|
||||
dirty |= system_constants_.ndc_scale[0] != ndc_scale_x;
|
||||
dirty |= system_constants_.ndc_scale[1] != ndc_scale_y;
|
||||
dirty |= system_constants_.ndc_scale[2] != ndc_scale_z;
|
||||
dirty |= system_constants_.ndc_offset[0] != ndc_offset_x;
|
||||
dirty |= system_constants_.ndc_offset[1] != ndc_offset_y;
|
||||
dirty |= system_constants_.ndc_offset[2] != ndc_offset_z;
|
||||
dirty |= system_constants_.pixel_half_pixel_offset != pixel_half_pixel_offset;
|
||||
system_constants_.ndc_scale[0] = ndc_scale_x;
|
||||
system_constants_.ndc_scale[1] = ndc_scale_y;
|
||||
system_constants_.ndc_scale[2] = ndc_scale_z;
|
||||
system_constants_.ndc_offset[0] = ndc_offset_x;
|
||||
system_constants_.ndc_offset[1] = ndc_offset_y;
|
||||
system_constants_.ndc_offset[2] = ndc_offset_z;
|
||||
system_constants_.pixel_half_pixel_offset = pixel_half_pixel_offset;
|
||||
|
||||
// Point size.
|
||||
float point_size_x = float(pa_su_point_size.width) * 0.125f;
|
||||
|
||||
Reference in New Issue
Block a user