From b3e0fe248d9983c5dbd5dcf656d099eeec4d9329 Mon Sep 17 00:00:00 2001 From: quarrel07 <178681861+quarrel07@users.noreply.github.com> Date: Mon, 20 Jul 2026 03:14:36 -0700 Subject: Fix widescreen letterbox/divider left-edge clipping on ARM64 (#709) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix widescreen letterbox/divider left-edge clipping on ARM64 The race-intro letterbox bars (draw_box_fill_wide) and the splitscreen divider lines fed the float OTRGetDimensionFromLeftEdge result into gDPFillWideRectangle, whose _SHIFTL packing casts float->unsigned. Converting a negative float to unsigned is UB: x86 wraps (and the wide-rect handler's sign extension recovers the value, so the bug is invisible there), but ARM64 fcvtzu saturates negatives to zero — so on Apple Silicon the fills started at the 4:3 left edge instead of the true left edge, leaving a strip of sky visible left of the intro bars in widescreen. Use the integer OTRGetRectDimensionFrom*Edge getters, matching the sibling draw_box_wide helpers. Co-Authored-By: Claude Fable 5 * Shorten the fix comment Co-Authored-By: Claude Fable 5 --------- Co-authored-by: Claude Fable 5 --- src/menu_items.c | 7 +++++-- src/racing/skybox_and_splitscreen.c | 9 +++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/menu_items.c b/src/menu_items.c index da6df9668..b6142ca37 100644 --- a/src/menu_items.c +++ b/src/menu_items.c @@ -3476,8 +3476,11 @@ Gfx* draw_box_fill_wide(Gfx* displayListHead, s32 ulx, s32 uly, s32 lrx, s32 lry gSPDisplayList(displayListHead++, D_02008030); gDPSetFillColor(displayListHead++, (GPACK_RGBA5551(red, green, (u32) blue, alpha) << 0x10 | GPACK_RGBA5551(red, green, (u32) blue, alpha))); - gDPFillWideRectangle(displayListHead++, OTRGetDimensionFromLeftEdge(ulx) - 1, uly, OTRGetDimensionFromRightEdge(lrx) + 1, - lry); + // Use the integer Rect getters: the float getters' negative left edge goes + // through a float->unsigned cast in _SHIFTL (UB) that ARM64 saturates to 0, + // pushing the fill's left edge to the 4:3 boundary in widescreen. + gDPFillWideRectangle(displayListHead++, OTRGetRectDimensionFromLeftEdge(ulx) - 1, uly, + OTRGetRectDimensionFromRightEdge(lrx) + 1, lry); gDPFillRectangle(displayListHead++, ulx, uly, lrx, lry); gSPDisplayList(displayListHead++, D_02008058); return displayListHead; diff --git a/src/racing/skybox_and_splitscreen.c b/src/racing/skybox_and_splitscreen.c index 825150f83..dff50e117 100644 --- a/src/racing/skybox_and_splitscreen.c +++ b/src/racing/skybox_and_splitscreen.c @@ -308,11 +308,16 @@ void func_802A4300(void) { gDPFillRectangle(gDisplayListHead++, 157, 0, 159, 239); break; case SCREEN_MODE_2P_SPLITSCREEN_HORIZONTAL: - gDPFillWideRectangle(gDisplayListHead++, OTRGetDimensionFromLeftEdge(0), 119, OTRGetGameRenderWidth(), 121); + // Integer Rect getter: the float getter's negative result through + // _SHIFTL is float->unsigned UB, which saturates to 0 on ARM64 and + // clips the divider's left extension (see draw_box_fill_wide). + gDPFillWideRectangle(gDisplayListHead++, OTRGetRectDimensionFromLeftEdge(0), 119, + OTRGetGameRenderWidth(), 121); break; case SCREEN_MODE_3P_4P_SPLITSCREEN: gDPFillRectangle(gDisplayListHead++, 157, 0, 159, 239); - gDPFillWideRectangle(gDisplayListHead++, OTRGetDimensionFromLeftEdge(0), 119, OTRGetGameRenderWidth(), 121); + gDPFillWideRectangle(gDisplayListHead++, OTRGetRectDimensionFromLeftEdge(0), 119, + OTRGetGameRenderWidth(), 121); break; } gDPPipeSync(gDisplayListHead++); -- cgit v1.2.3