diff --git a/src/video_core/amdgpu/liverpool.h b/src/video_core/amdgpu/liverpool.h index 411b25ed..b1036c01 100644 --- a/src/video_core/amdgpu/liverpool.h +++ b/src/video_core/amdgpu/liverpool.h @@ -253,6 +253,13 @@ struct Liverpool { } }; + struct ModeControl { + s32 msaa_enable : 1; + s32 vport_scissor_enable : 1; + s32 line_stripple_enable : 1; + s32 send_unlit_stiles_to_pkr : 1; + }; + enum class ZOrder : u32 { LateZ = 0, EarlyZLateZ = 1, @@ -559,29 +566,39 @@ 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)); } }; + struct WindowOffset { + s32 window_x_offset : 16; + s32 window_y_offset : 16; + }; + 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 { @@ -953,10 +970,14 @@ struct Liverpool { Scissor screen_scissor; INSERT_PADDING_WORDS(0xA010 - 0xA00C - 2); DepthBuffer depth_buffer; - INSERT_PADDING_WORDS(0xA08E - 0xA018); + INSERT_PADDING_WORDS(0xA080 - 0xA018); + WindowOffset window_offset; + ViewportScissor window_scissor; + INSERT_PADDING_WORDS(0xA08E - 0xA081 - 2); ColorBufferMask color_target_mask; ColorBufferMask color_shader_mask; - INSERT_PADDING_WORDS(0xA094 - 0xA08E - 2); + ViewportScissor generic_scissor; + INSERT_PADDING_WORDS(2); std::array viewport_scissors; std::array viewport_depths; INSERT_PADDING_WORDS(0xA103 - 0xA0D4); @@ -994,7 +1015,9 @@ struct Liverpool { PolygonControl polygon_control; ViewportControl viewport_control; VsOutputControl vs_output_control; - INSERT_PADDING_WORDS(0xA29E - 0xA207 - 2); + INSERT_PADDING_WORDS(0xA292 - 0xA207 - 1); + ModeControl mode_control; + INSERT_PADDING_WORDS(0xA29D - 0xA292 - 1); u32 index_size; u32 max_index_size; IndexBufferType index_buffer_type; @@ -1206,8 +1229,11 @@ static_assert(GFX6_3D_REG_INDEX(depth_htile_data_base) == 0xA005); static_assert(GFX6_3D_REG_INDEX(screen_scissor) == 0xA00C); static_assert(GFX6_3D_REG_INDEX(depth_buffer.z_info) == 0xA010); static_assert(GFX6_3D_REG_INDEX(depth_buffer.depth_slice) == 0xA017); +static_assert(GFX6_3D_REG_INDEX(window_offset) == 0xA080); +static_assert(GFX6_3D_REG_INDEX(window_scissor) == 0xA081); static_assert(GFX6_3D_REG_INDEX(color_target_mask) == 0xA08E); static_assert(GFX6_3D_REG_INDEX(color_shader_mask) == 0xA08F); +static_assert(GFX6_3D_REG_INDEX(generic_scissor) == 0xA090); static_assert(GFX6_3D_REG_INDEX(viewport_scissors) == 0xA094); static_assert(GFX6_3D_REG_INDEX(primitive_restart_index) == 0xA103); static_assert(GFX6_3D_REG_INDEX(stencil_control) == 0xA10B); @@ -1227,6 +1253,7 @@ static_assert(GFX6_3D_REG_INDEX(color_control) == 0xA202); static_assert(GFX6_3D_REG_INDEX(clipper_control) == 0xA204); static_assert(GFX6_3D_REG_INDEX(viewport_control) == 0xA206); static_assert(GFX6_3D_REG_INDEX(vs_output_control) == 0xA207); +static_assert(GFX6_3D_REG_INDEX(mode_control) == 0xA292); static_assert(GFX6_3D_REG_INDEX(index_size) == 0xA29D); static_assert(GFX6_3D_REG_INDEX(index_buffer_type) == 0xA29F); static_assert(GFX6_3D_REG_INDEX(enable_primitive_id) == 0xA2A1); diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index e511c161..159b489d 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -368,11 +368,55 @@ void Rasterizer::UpdateViewportScissorState() { .maxDepth = vp.zscale + vp.zoffset, }); } - const auto& sc = regs.screen_scissor; - scissors.push_back({ - .offset = {sc.top_left_x, sc.top_left_y}, - .extent = {sc.GetWidth(), sc.GetHeight()}, - }); + + const bool enable_offset = !regs.window_scissor.window_offset_disable.Value(); + Liverpool::Scissor scsr{}; + const auto combined_scissor_value_tl = [](s16 scr, s16 win, s16 gen, s16 win_offset) { + return std::max({scr, s16(win + win_offset), s16(gen + win_offset)}); + }; + + scsr.top_left_x = combined_scissor_value_tl( + 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 = combined_scissor_value_tl( + 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); + + const auto combined_scissor_value_br = [](s16 scr, s16 win, s16 gen, s16 win_offset) { + return std::min({scr, s16(win + win_offset), s16(gen + win_offset)}); + }; + + scsr.bottom_right_x = combined_scissor_value_br( + 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 = combined_scissor_value_br( + 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 idx = 0; idx < Liverpool::NumViewports; idx++) { + 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[idx].top_left_x.Value())); + vp_scsr.top_left_y = + std::max(vp_scsr.top_left_y, s16(regs.viewport_scissors[idx].top_left_y.Value())); + vp_scsr.bottom_right_x = + std::min(vp_scsr.bottom_right_x, regs.viewport_scissors[idx].bottom_right_x); + vp_scsr.bottom_right_y = + std::min(vp_scsr.bottom_right_y, regs.viewport_scissors[idx].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(); cmdbuf.setViewport(0, viewports); cmdbuf.setScissor(0, scissors);