diff --git a/src/utils/ConfigUtils.cpp b/src/utils/ConfigUtils.cpp index d04c935..fdbf2ca 100644 --- a/src/utils/ConfigUtils.cpp +++ b/src/utils/ConfigUtils.cpp @@ -190,9 +190,6 @@ void ConfigUtils::displayMenu() { int32_t curRegionIndex = region_map_to_index[curSelectedRegion]; int32_t curLangIndex = lang_map_to_index[curSelectedLanguage]; - KPADInit(); - WPADEnableURCC(true); - while (true) { buttonsTriggered = 0; buttonsReleased = 0; @@ -325,9 +322,6 @@ void ConfigUtils::displayMenu() { redraw = false; } } - KPADShutdown(); - // This disconnects any Pro Controllers... - //WPADEnableURCC(false); DrawUtils::beginDraw(); DrawUtils::clear(COLOR_BLACK); @@ -341,6 +335,7 @@ void ConfigUtils::openConfigMenu() { uint32_t screen_buf1_size = OSScreenGetBufferSizeEx(SCREEN_DRC); void *screenbuffer0 = MEMAllocFromMappedMemoryForGX2Ex(screen_buf0_size, 0x100); void *screenbuffer1 = MEMAllocFromMappedMemoryForGX2Ex(screen_buf1_size, 0x100); + bool doShutdownKPAD = false; if (!screenbuffer0 || !screenbuffer1) { DEBUG_FUNCTION_LINE_ERR("Failed to alloc buffers"); @@ -367,8 +362,23 @@ void ConfigUtils::openConfigMenu() { goto error_exit; } + + KPADStatus status; + KPADError err; + if (KPADReadEx(WPAD_CHAN_0, &status, 0, &err) == 0 && err == KPAD_ERROR_UNINITIALIZED) { + doShutdownKPAD = true; + KPADInit(); + WPADEnableURCC(true); + } + displayMenu(); + if (doShutdownKPAD) { + // This disconnects any Pro Controllers... + //WPADEnableURCC(false); + KPADShutdown(); + } + DrawUtils::deinitFont(); error_exit: diff --git a/src/utils/DrawUtils.cpp b/src/utils/DrawUtils.cpp index 6322524..5ea8f13 100644 --- a/src/utils/DrawUtils.cpp +++ b/src/utils/DrawUtils.cpp @@ -1,6 +1,8 @@ #include "DrawUtils.h" +#include "dc.h" #include "logger.h" #include "utils.h" +#include #include #include #include @@ -8,16 +10,17 @@ #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 = 0; +float DrawUtils::usedTVScale = 1.5f; +static SFT pFont = {}; static Color font_col(0xFFFFFFFF); @@ -26,6 +29,75 @@ void DrawUtils::initBuffers(void *tvBuffer_, uint32_t tvSize_, void *drcBuffer_, 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 = DCReadReg32(SCREEN_TV, D1GRPH_X_END_REG); + + 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() { @@ -77,17 +149,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/src/utils/DrawUtils.h b/src/utils/DrawUtils.h index 874fb4b..229c748 100644 --- a/src/utils/DrawUtils.h +++ b/src/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/src/utils/dc.h b/src/utils/dc.h new file mode 100644 index 0000000..55606ed --- /dev/null +++ b/src/utils/dc.h @@ -0,0 +1,35 @@ +#pragma once + +#include +#include + +extern "C" uint32_t __OSPhysicalToEffectiveUncached(uint32_t); + +static inline uint32_t DCReadReg32(OSScreenID screen, uint32_t index) { + if (OSIsECOMode()) { + return 0; + } + auto regs = (uint32_t *) __OSPhysicalToEffectiveUncached(0xc200000); + return regs[index + (screen * 0x200)]; +} + +static inline void DCWriteReg32(OSScreenID screen, uint32_t index, uint32_t val) { + if (OSIsECOMode()) { + return; + } + auto regs = (uint32_t *) __OSPhysicalToEffectiveUncached(0xc200000); + regs[index + (screen * 0x200)] = val; +} + +// https://www.x.org/docs/AMD/old/42589_rv630_rrg_1.01o.pdf (reg id in document / 4) +#define D1GRPH_ENABLE_REG 0x1840 +#define D1GRPH_CONTROL_REG 0x1841 +#define D1GRPH_PITCH_REG 0x1848 +#define D1OVL_PITCH_REG 0x1866 +#define D1GRPH_X_END_REG 0x184d +#define D1GRPH_Y_END_REG 0x184e + +static inline void SetDCPitchReg(OSScreenID screen, uint16_t pitch) { + DCWriteReg32(screen, D1GRPH_PITCH_REG, pitch); + DCWriteReg32(screen, D1OVL_PITCH_REG, pitch); +} \ No newline at end of file