[GPU] Clamp scissor to surface_pitch

This commit is contained in:
Triang3l 2020-12-29 11:15:05 +03:00
parent 56d802c323
commit e7cd2ffffa
2 changed files with 21 additions and 4 deletions

View File

@ -121,9 +121,9 @@ bool IsRasterizationPotentiallyDone(const RegisterFile& regs,
edram_mode != xenos::ModeControl::kDepth) {
return false;
}
auto sq_program_cntl = regs.Get<reg::SQ_PROGRAM_CNTL>();
if (sq_program_cntl.vs_export_mode ==
xenos::VertexShaderExportMode::kMultipass) {
if (regs.Get<reg::SQ_PROGRAM_CNTL>().vs_export_mode ==
xenos::VertexShaderExportMode::kMultipass ||
!regs.Get<reg::RB_SURFACE_INFO>().surface_pitch) {
return false;
}
if (primitive_polygonal) {
@ -390,6 +390,20 @@ void GetScissor(const RegisterFile& regs, Scissor& scissor_out) {
br_y = uint32_t(std::max(
int32_t(br_y) + pa_sc_window_offset.window_y_offset, int32_t(0)));
}
// Clamp the horizontal scissor to surface_pitch for safety, in case that's
// not done by the guest for some reason (it's not when doing draws completely
// without a viewport, for instance), to prevent overflow - this is important
// for host implementations, both based on target-indepedent rasterization
// without render target width at all (pixel shader interlocks-based custom RB
// implementations) and using conventional render targets, but padded to EDRAM
// tiles.
uint32_t surface_pitch = regs.Get<reg::RB_SURFACE_INFO>().surface_pitch;
tl_x = std::min(tl_x, surface_pitch);
br_x = std::min(br_x, surface_pitch);
// Ensure the rectangle is non-negative, by collapsing it into a 0-sized one
// (not by reordering the bounds preserving the width / height, which would
// reveal samples not meant to be covered, unless TL > BR does that on a real
// console, but no evidence of such has ever been seen).
br_x = std::max(br_x, tl_x);
br_y = std::max(br_y, tl_y);
scissor_out.left = tl_x;

View File

@ -37,7 +37,10 @@ int32_t FloatToD3D11Fixed16p8(float f32);
// Whether with the current state, any samples to rasterize (for any reason, not
// only to write something to a render target, but also to do sample counting or
// pixel shader memexport) can be generated. Finally dropping draw calls can
// only be done if the vertex shader doesn't memexport.
// only be done if the vertex shader doesn't memexport. Checks mostly special
// cases (for both the guest and usual host implementations), not everything
// like whether viewport / scissor are empty (until this truly matters in any
// game, of course).
bool IsRasterizationPotentiallyDone(const RegisterFile& regs,
bool primitive_polygonal);