diff --git a/src/video_core/amdgpu/liverpool.h b/src/video_core/amdgpu/liverpool.h index 9160f53ff..b1036c019 100644 --- a/src/video_core/amdgpu/liverpool.h +++ b/src/video_core/amdgpu/liverpool.h @@ -566,17 +566,22 @@ struct Liverpool { s16 top_left_x; s16 top_left_y; }; - union { - BitField<0, 15, u32> bottom_right_x; - BitField<16, 15, u32> bottom_right_y; + struct { + s16 bottom_right_x; + s16 bottom_right_y; }; + // From AMD spec: 'Negative numbers clamped to 0' + static s16 Clamp(s16 value) { + return std::max(s16(0), value); + } + u32 GetWidth() const { - return static_cast(bottom_right_x - top_left_x); + return static_cast(Clamp(bottom_right_x) - Clamp(top_left_x)); } u32 GetHeight() const { - return static_cast(bottom_right_y - top_left_y); + return static_cast(Clamp(bottom_right_y) - Clamp(top_left_y)); } }; @@ -588,12 +593,12 @@ struct Liverpool { struct ViewportScissor { union { BitField<0, 15, s32> top_left_x; - BitField<15, 15, s32> top_left_y; - BitField<30, 1, s32> window_offset_disable; + BitField<16, 15, s32> top_left_y; + BitField<31, 1, s32> window_offset_disable; }; - union { - BitField<0, 15, s32> bottom_right_x; - BitField<15, 15, s32> bottom_right_y; + struct { + s16 bottom_right_x; + s16 bottom_right_y; }; u32 GetWidth() const { diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 41f74a28d..cbfc9c654 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -342,6 +342,14 @@ void Rasterizer::UpdateDynamicState(const GraphicsPipeline& pipeline) { } } +static s16 CombinedScissorValueTL(s16 scr, s16 win, s16 gen, s16 win_offset) { + return std::max({scr, s16(win + win_offset), s16(gen + win_offset)}); +} + +static s16 CombinedScissorValueBR(s16 scr, s16 win, s16 gen, s16 win_offset) { + return std::min({scr, s16(win + win_offset), s16(gen + win_offset)}); +} + void Rasterizer::UpdateViewportScissorState() { auto& regs = liverpool->regs; @@ -369,20 +377,44 @@ void Rasterizer::UpdateViewportScissorState() { }); } - if (!regs.mode_control.vport_scissor_enable) { - const auto& sc = regs.screen_scissor; - scissors.push_back({ - .offset = {sc.top_left_x, sc.top_left_y}, - .extent = {sc.GetWidth(), sc.GetHeight()}, - }); - } else { - for (u32 i = 0; i < Liverpool::NumViewports; i++) { - const auto& scsrs = regs.viewport_scissors[i]; - scissors.push_back({ - .offset = {scsrs.top_left_x, scsrs.top_left_y}, - .extent = {scsrs.GetWidth(), scsrs.GetHeight()}, - }); + const bool enable_offset = !regs.window_scissor.window_offset_disable.Value(); + Liverpool::Scissor scsr; + scsr.top_left_x = CombinedScissorValueTL( + regs.screen_scissor.top_left_x, s16(regs.window_scissor.top_left_x.Value()), + s16(regs.generic_scissor.top_left_x.Value()), + enable_offset ? regs.window_offset.window_x_offset : 0); + + scsr.top_left_y = CombinedScissorValueTL( + regs.screen_scissor.top_left_y, s16(regs.window_scissor.top_left_y.Value()), + s16(regs.generic_scissor.top_left_y.Value()), + enable_offset ? regs.window_offset.window_y_offset : 0); + + scsr.bottom_right_x = CombinedScissorValueBR( + regs.screen_scissor.bottom_right_x, regs.window_scissor.bottom_right_x, + regs.generic_scissor.bottom_right_x, + enable_offset ? regs.window_offset.window_x_offset : 0); + + scsr.bottom_right_y = CombinedScissorValueBR( + regs.screen_scissor.bottom_right_y, regs.window_scissor.bottom_right_y, + regs.generic_scissor.bottom_right_y, + enable_offset ? regs.window_offset.window_y_offset : 0); + + for (u32 i = 0; i < Liverpool::NumViewports; i++) { + auto vp_scsr = scsr; + if (regs.mode_control.vport_scissor_enable) { + vp_scsr.top_left_x = + std::max(vp_scsr.top_left_x, s16(regs.viewport_scissors[i].top_left_x.Value())); + vp_scsr.top_left_y = + std::max(vp_scsr.top_left_y, s16(regs.viewport_scissors[i].top_left_y.Value())); + vp_scsr.bottom_right_x = + std::min(vp_scsr.bottom_right_x, regs.viewport_scissors[i].bottom_right_x); + vp_scsr.bottom_right_y = + std::min(vp_scsr.bottom_right_y, regs.viewport_scissors[i].bottom_right_y); } + scissors.push_back({ + .offset = {vp_scsr.top_left_x, vp_scsr.top_left_y}, + .extent = {vp_scsr.GetWidth(), vp_scsr.GetHeight()}, + }); } const auto cmdbuf = scheduler.CommandBuffer();