From 12b6830546e28e6a697c5dbcbc3aa24882ec7fb3 Mon Sep 17 00:00:00 2001 From: Exzap <13877693+Exzap@users.noreply.github.com> Date: Sat, 17 Sep 2022 16:32:46 +0200 Subject: [PATCH] GX2: Add crash workaround for FFL uninitialized texture (#264) When a game tries to generate Miis without the FFL files being dumped (/sys/title/0005001b/10056000/content/) it will cause it to create and use a texture with invalid parameters. This workaround catches and replaces bad texture parameters to avoid crashing further down the line. Resolves crashes in Sonic Lost World, Super Mario 3D World and probably a few others. We had this workaround in pre-2.0 Cemu already but it was dropped during refactoring. --- src/Cafe/OS/libs/gx2/GX2_Surface.cpp | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/Cafe/OS/libs/gx2/GX2_Surface.cpp b/src/Cafe/OS/libs/gx2/GX2_Surface.cpp index 5ce8a453..1d858e18 100644 --- a/src/Cafe/OS/libs/gx2/GX2_Surface.cpp +++ b/src/Cafe/OS/libs/gx2/GX2_Surface.cpp @@ -112,8 +112,34 @@ namespace GX2 return levels; } + void _GX2CalcSurfaceSizeAndAlignmentWorkaround(GX2Surface* surface) + { + // this workaround catches an issue where the FFL (Mii) library embedded into games tries to use an uninitialized texture + // and subsequently crashes. It only happens when FFL files are not present in mlc. + // seen in Sonic Lost World and in Super Mario 3D World + if ((uint32)surface->dim.value() >= 50 || surface->aa.value() >= 0x100 || (uint32)surface->width.value() >= 0x01000000 || + (uint32)surface->height.value() >= 0x01000000 || (uint32)surface->depth.value() >= 0x01000000 || (uint32)surface->format.value() >= 0x10000) + { + cemuLog_log(LogType::Force, "GX2CalcSurfaceSizeAndAlignment(): Uninitialized surface encountered\n"); + // overwrite surface parameters with placeholder values to avoid crashing later down the line + surface->dim = Latte::E_DIM::DIM_2D; + surface->width = 8; + surface->height = 8; + surface->depth = 1; + surface->tileMode = Latte::E_GX2TILEMODE::TM_2D_TILED_THIN1; + surface->pitch = 8; + surface->numLevels = 0; + surface->imagePtr = MEMORY_TILINGAPERTURE_AREA_ADDR; + surface->swizzle = 0; + surface->aa = 0; + surface->format = Latte::E_GX2SURFFMT::R8_G8_B8_A8_UNORM; + surface->alignment = 0x400; + } + } + void GX2CalcSurfaceSizeAndAlignment(GX2Surface* surface) { + _GX2CalcSurfaceSizeAndAlignmentWorkaround(surface); LatteAddrLib::AddrSurfaceInfo_OUT surfOut = { 0 }; uint32 firstMipOffset = 0; bool changeTilemode = false;