From ceb2b664e01eb564e25c76d6277297c8f1f95748 Mon Sep 17 00:00:00 2001 From: nmzik Date: Sun, 6 Sep 2026 21:25:12 +0400 Subject: [PATCH] render: reset rasterization defaults on CLEAR_STATE --- src/graphics/guest_gpu/hardwareContext.h | 30 +++++------ src/graphics/host_gpu/renderer/debug.cpp | 68 ++++++------------------ tests/ShaderRecompilerComputeTests.cpp | 41 ++++++++++++++ 3 files changed, 73 insertions(+), 66 deletions(-) diff --git a/src/graphics/guest_gpu/hardwareContext.h b/src/graphics/guest_gpu/hardwareContext.h index 23b43c58a..c52693ec1 100644 --- a/src/graphics/guest_gpu/hardwareContext.h +++ b/src/graphics/guest_gpu/hardwareContext.h @@ -362,16 +362,16 @@ struct AaConfig { struct Viewport { float zmin = 0.0f; float zmax = 0.0f; - float xscale = 0.0f; + float xscale = 1.0f; float xoffset = 0.0f; - float yscale = 0.0f; + float yscale = 1.0f; float yoffset = 0.0f; - float zscale = 0.0f; + float zscale = 1.0f; float zoffset = 0.0f; int viewport_scissor_left = 0; int viewport_scissor_top = 0; - int viewport_scissor_right = 0; - int viewport_scissor_bottom = 0; + int viewport_scissor_right = 16384; + int viewport_scissor_bottom = 16384; bool viewport_scissor_window_offset_enable = false; }; @@ -380,26 +380,26 @@ struct ScreenViewport { uint32_t transform_control = 1087; int screen_scissor_left = 0; int screen_scissor_top = 0; - int screen_scissor_right = 0; - int screen_scissor_bottom = 0; + int screen_scissor_right = 16384; + int screen_scissor_bottom = 16384; int window_scissor_left = 0; int window_scissor_top = 0; - int window_scissor_right = 0; - int window_scissor_bottom = 0; + int window_scissor_right = 16384; + int window_scissor_bottom = 16384; bool window_scissor_window_offset_enable = false; int generic_scissor_left = 0; int generic_scissor_top = 0; - int generic_scissor_right = 0; - int generic_scissor_bottom = 0; + int generic_scissor_right = 16384; + int generic_scissor_bottom = 16384; bool generic_scissor_window_offset_enable = false; int window_offset_x = 0; int window_offset_y = 0; uint32_t hw_offset_x = 0; uint32_t hw_offset_y = 0; - float guard_band_horz_clip = 0.0f; - float guard_band_vert_clip = 0.0f; - float guard_band_horz_discard = 0.0f; - float guard_band_vert_discard = 0.0f; + float guard_band_horz_clip = 1.0f; + float guard_band_vert_clip = 1.0f; + float guard_band_horz_discard = 1.0f; + float guard_band_vert_discard = 1.0f; uint16_t clip_rect_rule = 0xffffu; int clip_rect_left[4] = {}; int clip_rect_top[4] = {}; diff --git a/src/graphics/host_gpu/renderer/debug.cpp b/src/graphics/host_gpu/renderer/debug.cpp index 070a43662..ecc211dfc 100644 --- a/src/graphics/host_gpu/renderer/debug.cpp +++ b/src/graphics/host_gpu/renderer/debug.cpp @@ -17,8 +17,6 @@ namespace Libs::Graphics { -static std::atomic g_scissor_default_log_count = 0; - uint32_t render_target_mask_slot(uint32_t mask, uint32_t slot) { return (mask >> (slot * 4u)) & 0x0fu; } @@ -868,10 +866,6 @@ static bool ScissorRectValid(const ScissorRect& r) { return r.right > r.left && r.bottom > r.top; } -static bool ScissorRectSet(const ScissorRect& r) { - return r.left != 0 || r.top != 0 || r.right != 0 || r.bottom != 0; -} - static ScissorRect ScissorRectOffset(ScissorRect r, int x, int y) { r.left += x; r.right += x; @@ -931,48 +925,24 @@ static bool ScissorClipRuleToIntersectionMask(uint16_t rule, uint8_t* mask) { ScissorRect calc_final_scissor(const HW::ScreenViewport& vp, const HW::ScanModeControl& smc, vk::Extent2D extent, uint32_t viewport_index) { EXIT_IF(viewport_index >= std::size(vp.viewports)); - ScissorRect screen {vp.screen_scissor_left, vp.screen_scissor_top, vp.screen_scissor_right, - vp.screen_scissor_bottom}; - ScissorRect final = screen; - - if (!ScissorRectSet(screen)) { - final = {0, 0, static_cast(extent.width), static_cast(extent.height)}; - - auto log_id = g_scissor_default_log_count.fetch_add(1); - if (log_id < 32) { - LOGF("temporary: default unset screen scissor to framebuffer extent %ux%u\n", - extent.width, extent.height); + ScissorRect final {vp.screen_scissor_left, vp.screen_scissor_top, vp.screen_scissor_right, + vp.screen_scissor_bottom}; + const auto intersect = [&](ScissorRect rect, bool window_offset) { + if (window_offset) { + rect = ScissorRectOffset(rect, vp.window_offset_x, vp.window_offset_y); } - } - - ScissorRect window {vp.window_scissor_left, vp.window_scissor_top, vp.window_scissor_right, - vp.window_scissor_bottom}; - if (ScissorRectSet(window)) { - if (vp.window_scissor_window_offset_enable) { - window = ScissorRectOffset(window, vp.window_offset_x, vp.window_offset_y); - } - final = ScissorRectIntersect(final, window); - } - - ScissorRect generic {vp.generic_scissor_left, vp.generic_scissor_top, vp.generic_scissor_right, - vp.generic_scissor_bottom}; - if (ScissorRectSet(generic)) { - if (vp.generic_scissor_window_offset_enable) { - generic = ScissorRectOffset(generic, vp.window_offset_x, vp.window_offset_y); - } - final = ScissorRectIntersect(final, generic); - } + final = ScissorRectIntersect(final, rect); + }; + intersect({vp.window_scissor_left, vp.window_scissor_top, vp.window_scissor_right, + vp.window_scissor_bottom}, vp.window_scissor_window_offset_enable); + intersect({vp.generic_scissor_left, vp.generic_scissor_top, vp.generic_scissor_right, + vp.generic_scissor_bottom}, vp.generic_scissor_window_offset_enable); const auto& viewport = vp.viewports[viewport_index]; - ScissorRect viewport_scissor {viewport.viewport_scissor_left, viewport.viewport_scissor_top, - viewport.viewport_scissor_right, - viewport.viewport_scissor_bottom}; - if (smc.vport_scissor_enable && ScissorRectSet(viewport_scissor)) { - if (viewport.viewport_scissor_window_offset_enable) { - viewport_scissor = - ScissorRectOffset(viewport_scissor, vp.window_offset_x, vp.window_offset_y); - } - final = ScissorRectIntersect(final, viewport_scissor); + if (smc.vport_scissor_enable) { + intersect({viewport.viewport_scissor_left, viewport.viewport_scissor_top, + viewport.viewport_scissor_right, viewport.viewport_scissor_bottom}, + viewport.viewport_scissor_window_offset_enable); } if (vp.clip_rect_rule == 0) { @@ -985,12 +955,8 @@ ScissorRect calc_final_scissor(const HW::ScreenViewport& vp, const HW::ScanModeC continue; } - ScissorRect clip {vp.clip_rect_left[i], vp.clip_rect_top[i], vp.clip_rect_right[i], - vp.clip_rect_bottom[i]}; - if (vp.clip_rect_window_offset_enable[i]) { - clip = ScissorRectOffset(clip, vp.window_offset_x, vp.window_offset_y); - } - final = ScissorRectIntersect(final, clip); + intersect({vp.clip_rect_left[i], vp.clip_rect_top[i], vp.clip_rect_right[i], + vp.clip_rect_bottom[i]}, vp.clip_rect_window_offset_enable[i]); } } else { static std::atomic log_count {0}; diff --git a/tests/ShaderRecompilerComputeTests.cpp b/tests/ShaderRecompilerComputeTests.cpp index b3ae8a259..7bf2573bf 100644 --- a/tests/ShaderRecompilerComputeTests.cpp +++ b/tests/ShaderRecompilerComputeTests.cpp @@ -28,6 +28,7 @@ #include "graphics/host_gpu/renderer/image/tiler.h" #include "graphics/host_gpu/renderer/pipeline/descriptors.h" #include "graphics/host_gpu/renderer/pipeline/pipelineCache.h" +#include "graphics/host_gpu/renderer/debug.h" #include "graphics/host_gpu/renderer/render.h" #include "graphics/host_gpu/renderer/renderContext.h" #include "graphics/host_gpu/renderer/renderDraw.h" @@ -27638,6 +27639,46 @@ void CheckPm4ContextStateOperations(RenderContext &renderer) { processor.GetCtx().GetRenderTargetMask() == 0x0badc0de, "CLEAR_STATE discarded the pushed Cx state"); + // AGC CLEAR_STATE restores the viewport, scissor, and guard-band register defaults. + processor.GetCtx().SetScreenScissor(1, 2, 3, 4); + processor.GetCtx().SetGuardBands(2.0f, 3.0f, 4.0f, 5.0f); + Pm4Execution scissor_reset; + Require("Pm4ContextState", "scissor reset packet", + processor.Process(scissor_reset, clear_state_packet) == Pm4ProcessResult::Complete, + "CLEAR_STATE could not reset the rasterization state"); + const auto &viewport = processor.GetCtx().GetScreenViewport(); + const auto defaults = calc_final_scissor(viewport, {}, {20000, 20000}, 0); + Require("Pm4ContextState", "Rasterization defaults", + defaults.left == 0 && defaults.top == 0 && defaults.right == 16384 && + defaults.bottom == 16384 && viewport.guard_band_horz_clip == 1.0f && + viewport.guard_band_vert_clip == 1.0f && + viewport.guard_band_horz_discard == 1.0f && + viewport.guard_band_vert_discard == 1.0f && + std::ranges::all_of(viewport.viewports, [](const auto &slot) { + return slot.xscale == 1.0f && slot.yscale == 1.0f && slot.zscale == 1.0f && + slot.viewport_scissor_right == 16384 && + slot.viewport_scissor_bottom == 16384 && + !slot.viewport_scissor_window_offset_enable; + }), + "CLEAR_STATE did not restore scissor and guard-band defaults"); + const std::array scissor_registers{ + std::pair{Pm4::PA_SC_SCREEN_SCISSOR_TL, Pm4::PA_SC_SCREEN_SCISSOR_BR}, + std::pair{Pm4::PA_SC_WINDOW_SCISSOR_TL, Pm4::PA_SC_WINDOW_SCISSOR_BR}, + std::pair{Pm4::PA_SC_GENERIC_SCISSOR_TL, Pm4::PA_SC_GENERIC_SCISSOR_BR}, + std::pair{Pm4::PA_SC_VPORT_SCISSOR_0_TL, Pm4::PA_SC_VPORT_SCISSOR_0_BR}}; + for (const auto &[tl, br] : scissor_registers) { + processor.GetCtx().Reset(); + g_hw_ctx_indirect_func[tl](processor, tl, 0); + g_hw_ctx_indirect_func[br](processor, br, 0); + HW::ScanModeControl scan{}; + scan.vport_scissor_enable = tl == Pm4::PA_SC_VPORT_SCISSOR_0_TL; + const auto empty = calc_final_scissor(processor.GetCtx().GetScreenViewport(), + scan, {3840, 2160}, 0); + Require("Pm4ContextState", "explicit empty scissor", + empty.right == empty.left && empty.bottom == empty.top, + "an explicitly empty scissor was expanded or ignored"); + } + processor.GetCtx().SetRenderTargetMask(0xabcdef01); Require("Pm4ContextState", "push before processor reset", invoke(ContextStateOperation::Push) == Pm4ProcessResult::Complete,