Fix displaying the config menu when using 480i + 4:3 or 576i as output resolution

This commit is contained in:
Maschell 2024-05-09 16:34:28 +02:00
parent 43a18b56d7
commit d1cfff4861
4 changed files with 146 additions and 33 deletions

View File

@ -76,6 +76,7 @@ WUMS_APPLICATION_STARTS() {
} }
OSReport("Running WiiUPluginLoaderBackend " VERSION_FULL "\n"); OSReport("Running WiiUPluginLoaderBackend " VERSION_FULL "\n");
gStoredTVBuffer = {};
gUsedRPLs.clear(); gUsedRPLs.clear();

View File

@ -2,32 +2,114 @@
#include "logger.h" #include "logger.h"
#include "utils.h" #include "utils.h"
#include <avm/tv.h>
#include <coreinit/cache.h> #include <coreinit/cache.h>
#include <coreinit/memory.h> #include <coreinit/memory.h>
#include <coreinit/screen.h> #include <coreinit/screen.h>
#include <cstdlib> #include <cstdlib>
#include <png.h> #include <png.h>
// buffer width // buffer width
#define TV_WIDTH 0x500
#define DRC_WIDTH 0x380 #define DRC_WIDTH 0x380
bool DrawUtils::isBackBuffer; bool DrawUtils::isBackBuffer;
uint8_t *DrawUtils::tvBuffer = nullptr; uint8_t *DrawUtils::tvBuffer = nullptr;
uint32_t DrawUtils::tvSize = 0; uint32_t DrawUtils::tvSize = 0;
uint8_t *DrawUtils::drcBuffer = nullptr; uint8_t *DrawUtils::drcBuffer = nullptr;
uint32_t DrawUtils::drcSize = 0; uint32_t DrawUtils::drcSize = 0;
static SFT pFont = {}; uint32_t DrawUtils::usedTVWidth = 1280;
float DrawUtils::usedTVScale = 1.5f;
static SFT pFont = {};
static Color font_col(0xFFFFFFFF); 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_) { void DrawUtils::initBuffers(void *tvBuffer_, uint32_t tvSize_, void *drcBuffer_, uint32_t drcSize_) {
DrawUtils::tvBuffer = (uint8_t *) tvBuffer_; DrawUtils::tvBuffer = (uint8_t *) tvBuffer_;
DrawUtils::tvSize = tvSize_; DrawUtils::tvSize = tvSize_;
DrawUtils::drcBuffer = (uint8_t *) drcBuffer_; DrawUtils::drcBuffer = (uint8_t *) drcBuffer_;
DrawUtils::drcSize = drcSize_; 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() { 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 // scale and put pixel in the tv buffer
for (uint32_t yy = (y * scale); yy < ((y * scale) + (uint32_t) scale); yy++) { for (uint32_t yy = (y * DrawUtils::usedTVScale); yy < ((y * DrawUtils::usedTVScale) + (uint32_t) DrawUtils::usedTVScale); yy++) {
for (uint32_t xx = (x * scale); xx < ((x * scale) + (uint32_t) scale); xx++) { for (uint32_t xx = (x * DrawUtils::usedTVScale); xx < ((x * DrawUtils::usedTVScale) + (uint32_t) DrawUtils::usedTVScale); xx++) {
uint32_t i = (xx + yy * USED_TV_WIDTH) * 4; uint32_t i = (xx + yy * DrawUtils::usedTVWidth) * 4;
if (i + 3 < tvSize / 2) { if (i + 3 < tvSize / 2) {
if (isBackBuffer) { if (isBackBuffer) {
i += tvSize / 2; i += tvSize / 2;

View File

@ -73,4 +73,6 @@ private:
static uint32_t tvSize; static uint32_t tvSize;
static uint8_t *drcBuffer; static uint8_t *drcBuffer;
static uint32_t drcSize; static uint32_t drcSize;
static uint32_t usedTVWidth;
static float usedTVScale;
}; };

View File

@ -9,6 +9,7 @@
#include "utils/input/VPADInput.h" #include "utils/input/VPADInput.h"
#include "utils/input/WPADInput.h" #include "utils/input/WPADInput.h"
#include <avm/tv.h>
#include <coreinit/screen.h> #include <coreinit/screen.h>
#include <gx2/display.h> #include <gx2/display.h>
#include <memory/mappedmemory.h> #include <memory/mappedmemory.h>
@ -225,12 +226,42 @@ void ConfigUtils::displayMenu() {
WUPSConfigAPIBackend::Intern::CleanAllHandles(); 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() { void ConfigUtils::openConfigMenu() {
gOnlyAcceptFromThread = OSGetCurrentThread(); gOnlyAcceptFromThread = OSGetCurrentThread();
bool wasHomeButtonMenuEnabled = OSIsHomeButtonMenuEnabled(); 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(); OSScreenInit();
uint32_t screen_buf0_size = OSScreenGetBufferSizeEx(SCREEN_TV); uint32_t screen_buf0_size = OSScreenGetBufferSizeEx(SCREEN_TV);
@ -238,11 +269,6 @@ void ConfigUtils::openConfigMenu() {
void *screenbuffer0 = MEMAllocFromMappedMemoryForGX2Ex(screen_buf0_size, 0x100); void *screenbuffer0 = MEMAllocFromMappedMemoryForGX2Ex(screen_buf0_size, 0x100);
void *screenbuffer1 = MEMAllocFromMappedMemoryForGX2Ex(screen_buf1_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 skipScreen0Free = false;
bool skipScreen1Free = false; bool skipScreen1Free = false;
bool doShutdownKPAD = false; bool doShutdownKPAD = false;
@ -271,8 +297,13 @@ void ConfigUtils::openConfigMenu() {
OSScreenSetBufferEx(SCREEN_TV, screenbuffer0); OSScreenSetBufferEx(SCREEN_TV, screenbuffer0);
OSScreenSetBufferEx(SCREEN_DRC, screenbuffer1); OSScreenSetBufferEx(SCREEN_DRC, screenbuffer1);
OSScreenEnableEx(SCREEN_TV, 1); // Clear screens
OSScreenEnableEx(SCREEN_DRC, 1); OSScreenClearBufferEx(SCREEN_TV, 0);
OSScreenClearBufferEx(SCREEN_DRC, 0);
// Flip buffers
OSScreenFlipBuffersEx(SCREEN_TV);
OSScreenFlipBuffersEx(SCREEN_DRC);
// Clear screens // Clear screens
OSScreenClearBufferEx(SCREEN_TV, 0); OSScreenClearBufferEx(SCREEN_TV, 0);
@ -282,6 +313,9 @@ void ConfigUtils::openConfigMenu() {
OSScreenFlipBuffersEx(SCREEN_TV); OSScreenFlipBuffersEx(SCREEN_TV);
OSScreenFlipBuffersEx(SCREEN_DRC); OSScreenFlipBuffersEx(SCREEN_DRC);
OSScreenEnableEx(SCREEN_TV, 1);
OSScreenEnableEx(SCREEN_DRC, 1);
DrawUtils::initBuffers(screenbuffer0, screen_buf0_size, screenbuffer1, screen_buf1_size); DrawUtils::initBuffers(screenbuffer0, screen_buf0_size, screenbuffer1, screen_buf1_size);
if (!DrawUtils::initFont()) { if (!DrawUtils::initFont()) {
DEBUG_FUNCTION_LINE_ERR("Failed to init Font"); DEBUG_FUNCTION_LINE_ERR("Failed to init Font");
@ -309,16 +343,17 @@ void ConfigUtils::openConfigMenu() {
DrawUtils::deinitFont(); DrawUtils::deinitFont();
error_exit: 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) { __WriteReg32(0x1841 + SCREEN_DRC * 0x200, drcRender1);
GX2SetTVBuffer(gStoredTVBuffer.buffer, gStoredTVBuffer.buffer_size, static_cast<GX2TVRenderMode>(gStoredTVBuffer.mode), __WriteReg32(0x1840 + SCREEN_DRC * 0x200, drcRender2);
gStoredTVBuffer.surface_format, gStoredTVBuffer.buffering_mode); __WriteReg32(0x1848 + SCREEN_DRC * 0x200, drcPitch1);
} __WriteReg32(0x1866 + SCREEN_DRC * 0x200, drcPitch2);
if (gStoredDRCBuffer.buffer != nullptr) {
GX2SetDRCBuffer(gStoredDRCBuffer.buffer, gStoredDRCBuffer.buffer_size, static_cast<GX2DrcRenderMode>(gStoredDRCBuffer.mode),
gStoredDRCBuffer.surface_format, gStoredDRCBuffer.buffering_mode);
}
if (!skipScreen0Free && screenbuffer0) { if (!skipScreen0Free && screenbuffer0) {
MEMFreeToMappedMemory(screenbuffer0); MEMFreeToMappedMemory(screenbuffer0);
} }