From d1cfff4861319ec6d2e619f6c156f9fb2dd1ceea Mon Sep 17 00:00:00 2001 From: Maschell Date: Thu, 9 May 2024 16:34:28 +0200 Subject: [PATCH] Fix displaying the config menu when using 480i + 4:3 or 576i as output resolution --- source/main.cpp | 1 + source/utils/DrawUtils.cpp | 109 +++++++++++++++++++++++----- source/utils/DrawUtils.h | 2 + source/utils/config/ConfigUtils.cpp | 67 +++++++++++++---- 4 files changed, 146 insertions(+), 33 deletions(-) diff --git a/source/main.cpp b/source/main.cpp index 68fb6e1..4614d3b 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -76,6 +76,7 @@ WUMS_APPLICATION_STARTS() { } OSReport("Running WiiUPluginLoaderBackend " VERSION_FULL "\n"); + gStoredTVBuffer = {}; gUsedRPLs.clear(); diff --git a/source/utils/DrawUtils.cpp b/source/utils/DrawUtils.cpp index d1684ca..8e88c8c 100644 --- a/source/utils/DrawUtils.cpp +++ b/source/utils/DrawUtils.cpp @@ -2,32 +2,114 @@ #include "logger.h" #include "utils.h" +#include #include #include #include #include #include - // buffer width -#define TV_WIDTH 0x500 #define DRC_WIDTH 0x380 bool DrawUtils::isBackBuffer; -uint8_t *DrawUtils::tvBuffer = nullptr; -uint32_t DrawUtils::tvSize = 0; -uint8_t *DrawUtils::drcBuffer = nullptr; -uint32_t DrawUtils::drcSize = 0; -static SFT pFont = {}; +uint8_t *DrawUtils::tvBuffer = nullptr; +uint32_t DrawUtils::tvSize = 0; +uint8_t *DrawUtils::drcBuffer = nullptr; +uint32_t DrawUtils::drcSize = 0; +uint32_t DrawUtils::usedTVWidth = 1280; +float DrawUtils::usedTVScale = 1.5f; +static SFT pFont = {}; static Color font_col(0xFFFFFFFF); +#define __SetDCPitchReg ((void (*)(uint32_t, uint32_t))(0x101C400 + 0x1e714)) + +extern "C" uint32_t __OSPhysicalToEffectiveUncached(uint32_t); + +static uint32_t __ReadReg32(uint32_t index) { + if (OSIsECOMode()) { + return 0; + } + auto regs = (uint32_t *) __OSPhysicalToEffectiveUncached(0xc200000); + return regs[index]; +} + void DrawUtils::initBuffers(void *tvBuffer_, uint32_t tvSize_, void *drcBuffer_, uint32_t drcSize_) { DrawUtils::tvBuffer = (uint8_t *) tvBuffer_; DrawUtils::tvSize = tvSize_; DrawUtils::drcBuffer = (uint8_t *) drcBuffer_; DrawUtils::drcSize = drcSize_; + + bool bigScale = true; + switch (TVEGetCurrentPort()) { + case TVE_PORT_HDMI: + bigScale = true; + break; + case TVE_PORT_COMPONENT: + case TVE_PORT_COMPOSITE: + case TVE_PORT_SCART: + bigScale = false; + break; + } + + AVMTvResolution tvResolution = AVM_TV_RESOLUTION_720P; + if (AVMGetTVScanMode(&tvResolution)) { + switch (tvResolution) { + case AVM_TV_RESOLUTION_480P: + case AVM_TV_RESOLUTION_720P: + case AVM_TV_RESOLUTION_720P_3D: + case AVM_TV_RESOLUTION_1080I: + case AVM_TV_RESOLUTION_1080P: + case AVM_TV_RESOLUTION_576P: + case AVM_TV_RESOLUTION_720P_50HZ: + case AVM_TV_RESOLUTION_1080I_50HZ: + case AVM_TV_RESOLUTION_1080P_50HZ: + bigScale = true; + break; + case AVM_TV_RESOLUTION_576I: + case AVM_TV_RESOLUTION_480I: + case AVM_TV_RESOLUTION_480I_PAL60: + break; + } + } + + auto tvScanBufferWidth = __ReadReg32(0x184d + SCREEN_TV * 0x200); + + if (tvScanBufferWidth == 640) { // 480i/480p/576i 4:3 + DrawUtils::usedTVWidth = 640; + __SetDCPitchReg(SCREEN_TV, 640); + DrawUtils::usedTVScale = bigScale ? 0.75 : 0.75f; + } else if (tvScanBufferWidth == 854) { // 480i/480p/576i 16:9 + DrawUtils::usedTVWidth = 896; + __SetDCPitchReg(SCREEN_TV, 896); + DrawUtils::usedTVScale = bigScale ? 1.0 : 1.0f; + } else if (tvScanBufferWidth == 1280) { // 720p 16:9 + DrawUtils::usedTVWidth = 1280; + __SetDCPitchReg(SCREEN_TV, 1280); + if (bigScale) { + DrawUtils::usedTVScale = 1.5; + } else { + DrawUtils::usedTVScale = 0.75f; + if (tvResolution == AVM_TV_RESOLUTION_480I_PAL60 || tvResolution == AVM_TV_RESOLUTION_480I) { + AVMTvAspectRatio tvAspectRatio; + if (AVMGetTVAspectRatio(&tvAspectRatio) && tvAspectRatio == AVM_TV_ASPECT_RATIO_16_9) { + DEBUG_FUNCTION_LINE_WARN("force big scaling for 480i + 16:9"); + DrawUtils::usedTVScale = 1.5; + } + } + } + } else if (tvScanBufferWidth == 1920) { // 1080i/1080p 16:9 + DrawUtils::usedTVWidth = 1920; + __SetDCPitchReg(SCREEN_TV, 1920); + DrawUtils::usedTVScale = bigScale ? 2.25 : 1.125f; + } else { + DrawUtils::usedTVWidth = tvScanBufferWidth; + __SetDCPitchReg(SCREEN_TV, tvScanBufferWidth); + DrawUtils::usedTVScale = 1.0f; + DEBUG_FUNCTION_LINE_WARN("Unknown tv width detected, config menu might not show properly"); + } } void DrawUtils::beginDraw() { @@ -83,17 +165,10 @@ void DrawUtils::drawPixel(uint32_t x, uint32_t y, uint8_t r, uint8_t g, uint8_t } } - uint32_t USED_TV_WIDTH = TV_WIDTH; - float scale = 1.5f; - if (DrawUtils::tvSize == 0x00FD2000) { - USED_TV_WIDTH = 1920; - scale = 2.25f; - } - // scale and put pixel in the tv buffer - for (uint32_t yy = (y * scale); yy < ((y * scale) + (uint32_t) scale); yy++) { - for (uint32_t xx = (x * scale); xx < ((x * scale) + (uint32_t) scale); xx++) { - uint32_t i = (xx + yy * USED_TV_WIDTH) * 4; + for (uint32_t yy = (y * DrawUtils::usedTVScale); yy < ((y * DrawUtils::usedTVScale) + (uint32_t) DrawUtils::usedTVScale); yy++) { + for (uint32_t xx = (x * DrawUtils::usedTVScale); xx < ((x * DrawUtils::usedTVScale) + (uint32_t) DrawUtils::usedTVScale); xx++) { + uint32_t i = (xx + yy * DrawUtils::usedTVWidth) * 4; if (i + 3 < tvSize / 2) { if (isBackBuffer) { i += tvSize / 2; diff --git a/source/utils/DrawUtils.h b/source/utils/DrawUtils.h index 874fb4b..229c748 100644 --- a/source/utils/DrawUtils.h +++ b/source/utils/DrawUtils.h @@ -73,4 +73,6 @@ private: static uint32_t tvSize; static uint8_t *drcBuffer; static uint32_t drcSize; + static uint32_t usedTVWidth; + static float usedTVScale; }; diff --git a/source/utils/config/ConfigUtils.cpp b/source/utils/config/ConfigUtils.cpp index a929e11..f355023 100644 --- a/source/utils/config/ConfigUtils.cpp +++ b/source/utils/config/ConfigUtils.cpp @@ -9,6 +9,7 @@ #include "utils/input/VPADInput.h" #include "utils/input/WPADInput.h" +#include #include #include #include @@ -225,12 +226,42 @@ void ConfigUtils::displayMenu() { WUPSConfigAPIBackend::Intern::CleanAllHandles(); } -#define __SetDCPitchReg ((void (*)(uint32_t, uint32_t))(0x101C400 + 0x1e714)) +extern "C" uint32_t __OSPhysicalToEffectiveUncached(uint32_t); + +static uint32_t __ReadReg32(uint32_t index) { + if (OSIsECOMode()) { + return 0; + } + auto regs = (uint32_t *) __OSPhysicalToEffectiveUncached(0xc200000); + return regs[index]; +} + +static void __WriteReg32(uint32_t index, uint32_t val) { + if (OSIsECOMode()) { + return; + } + auto regs = (uint32_t *) __OSPhysicalToEffectiveUncached(0xc200000); + regs[index] = val; +} + + +extern "C" void (*real_GX2SetTVBuffer)(void *buffer, uint32_t buffer_size, int32_t tv_render_mode, GX2SurfaceFormat format, GX2BufferingMode buffering_mode); +extern "C" void (*real_GX2SetDRCBuffer)(void *buffer, uint32_t buffer_size, uint32_t drc_mode, GX2SurfaceFormat surface_format, GX2BufferingMode buffering_mode); void ConfigUtils::openConfigMenu() { gOnlyAcceptFromThread = OSGetCurrentThread(); bool wasHomeButtonMenuEnabled = OSIsHomeButtonMenuEnabled(); + // Save copy of DC reg values + auto tvRender1 = __ReadReg32(0x1841 + SCREEN_TV * 0x200); + auto tvRender2 = __ReadReg32(0x1840 + SCREEN_TV * 0x200); + auto tvPitch1 = __ReadReg32(0x1848 + SCREEN_TV * 0x200); + auto tvPitch2 = __ReadReg32(0x1866 + SCREEN_TV * 0x200); + auto drcRender1 = __ReadReg32(0x1841 + SCREEN_DRC * 0x200); + auto drcRender2 = __ReadReg32(0x1840 + SCREEN_DRC * 0x200); + auto drcPitch1 = __ReadReg32(0x1848 + SCREEN_DRC * 0x200); + auto drcPitch2 = __ReadReg32(0x1866 + SCREEN_DRC * 0x200); + OSScreenInit(); uint32_t screen_buf0_size = OSScreenGetBufferSizeEx(SCREEN_TV); @@ -238,11 +269,6 @@ void ConfigUtils::openConfigMenu() { void *screenbuffer0 = MEMAllocFromMappedMemoryForGX2Ex(screen_buf0_size, 0x100); void *screenbuffer1 = MEMAllocFromMappedMemoryForGX2Ex(screen_buf1_size, 0x100); - // Fix the TV buffer pitch if a 1080p buffer is used. - if (screen_buf0_size == 0x00FD2000) { - __SetDCPitchReg(SCREEN_TV, 1920); - } - bool skipScreen0Free = false; bool skipScreen1Free = false; bool doShutdownKPAD = false; @@ -271,8 +297,13 @@ void ConfigUtils::openConfigMenu() { OSScreenSetBufferEx(SCREEN_TV, screenbuffer0); OSScreenSetBufferEx(SCREEN_DRC, screenbuffer1); - OSScreenEnableEx(SCREEN_TV, 1); - OSScreenEnableEx(SCREEN_DRC, 1); + // Clear screens + OSScreenClearBufferEx(SCREEN_TV, 0); + OSScreenClearBufferEx(SCREEN_DRC, 0); + + // Flip buffers + OSScreenFlipBuffersEx(SCREEN_TV); + OSScreenFlipBuffersEx(SCREEN_DRC); // Clear screens OSScreenClearBufferEx(SCREEN_TV, 0); @@ -282,6 +313,9 @@ void ConfigUtils::openConfigMenu() { OSScreenFlipBuffersEx(SCREEN_TV); OSScreenFlipBuffersEx(SCREEN_DRC); + OSScreenEnableEx(SCREEN_TV, 1); + OSScreenEnableEx(SCREEN_DRC, 1); + DrawUtils::initBuffers(screenbuffer0, screen_buf0_size, screenbuffer1, screen_buf1_size); if (!DrawUtils::initFont()) { DEBUG_FUNCTION_LINE_ERR("Failed to init Font"); @@ -309,16 +343,17 @@ void ConfigUtils::openConfigMenu() { DrawUtils::deinitFont(); error_exit: + // Restore DC reg values + __WriteReg32(0x1841 + SCREEN_TV * 0x200, tvRender1); + __WriteReg32(0x1840 + SCREEN_TV * 0x200, tvRender2); + __WriteReg32(0x1848 + SCREEN_TV * 0x200, tvPitch1); + __WriteReg32(0x1866 + SCREEN_TV * 0x200, tvPitch2); - if (gStoredTVBuffer.buffer != nullptr) { - GX2SetTVBuffer(gStoredTVBuffer.buffer, gStoredTVBuffer.buffer_size, static_cast(gStoredTVBuffer.mode), - gStoredTVBuffer.surface_format, gStoredTVBuffer.buffering_mode); - } + __WriteReg32(0x1841 + SCREEN_DRC * 0x200, drcRender1); + __WriteReg32(0x1840 + SCREEN_DRC * 0x200, drcRender2); + __WriteReg32(0x1848 + SCREEN_DRC * 0x200, drcPitch1); + __WriteReg32(0x1866 + SCREEN_DRC * 0x200, drcPitch2); - if (gStoredDRCBuffer.buffer != nullptr) { - GX2SetDRCBuffer(gStoredDRCBuffer.buffer, gStoredDRCBuffer.buffer_size, static_cast(gStoredDRCBuffer.mode), - gStoredDRCBuffer.surface_format, gStoredDRCBuffer.buffering_mode); - } if (!skipScreen0Free && screenbuffer0) { MEMFreeToMappedMemory(screenbuffer0); }