CfgUSBLoader/source/deflicker.c

184 lines
6.4 KiB
C
Raw Normal View History

/*
* Deflicker filter patching by wiidev (blackb0x @ GBAtemp)
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gccore.h>
#include <sys/unistd.h>
#ifdef DEBUG_PATCH
#define debug_printf(fmt, args...) \
printf(fmt, ##args)
#else
#define debug_printf(fmt, args...)
#endif
static u8 PATTERN[12][2] = {
{6, 6}, {6, 6}, {6, 6},
{6, 6}, {6, 6}, {6, 6},
{6, 6}, {6, 6}, {6, 6},
{6, 6}, {6, 6}, {6, 6}
};
static u8 PATTERN_AA[12][2] = {
{3, 2}, {9, 6}, {3, 10},
{3, 2}, {9, 6}, {3, 10},
{9, 2}, {3, 6}, {9, 10},
{9, 2}, {3, 6}, {9, 10}
};
// Patch known and unknown vfilters within GXRModeObj structures
void patch_vfilters(u8 *addr, u32 len, u8 *vfilter)
{
u8 *addr_start = addr;
while (len >= sizeof(GXRModeObj))
{
GXRModeObj *vidmode = (GXRModeObj *)addr_start;
if ((memcmp(vidmode->sample_pattern, PATTERN, 24) == 0 || memcmp(vidmode->sample_pattern, PATTERN_AA, 24) == 0) &&
(vidmode->fbWidth == 640 || vidmode->fbWidth == 608 || vidmode->fbWidth == 512) &&
(vidmode->field_rendering == 0 || vidmode->field_rendering == 1) &&
(vidmode->aa == 0 || vidmode->aa == 1))
{
debug_printf("Replaced vfilter %02x%02x%02x%02x%02x%02x%02x @ %p (GXRModeObj)\n",
vidmode->vfilter[0], vidmode->vfilter[1], vidmode->vfilter[2], vidmode->vfilter[3],
vidmode->vfilter[4], vidmode->vfilter[5], vidmode->vfilter[6], addr_start);
memcpy(vidmode->vfilter, vfilter, 7);
addr_start += (sizeof(GXRModeObj) - 4);
len -= (sizeof(GXRModeObj) - 4);
}
addr_start += 4;
len -= 4;
}
}
// Patch rogue vfilters found in some games
void patch_vfilters_rogue(u8 *addr, u32 len, u8 *vfilter)
{
u8 known_vfilters[7][7] = {
{8, 8, 10, 12, 10, 8, 8}, // Ntsc480ProgSoft
{4, 8, 12, 16, 12, 8, 4}, // Ntsc480ProgAa
{7, 7, 12, 12, 12, 7, 7}, // Mario Kart Wii
{5, 5, 15, 14, 15, 5, 5}, // Mario Kart Wii
{4, 4, 15, 18, 15, 4, 4}, // Sonic Colors
{4, 4, 16, 16, 16, 4, 4}, // DKC Returns
{2, 2, 17, 22, 17, 2, 2}
};
u8 *addr_start = addr;
u8 *addr_end = addr + len - 8;
while (addr_start <= addr_end)
{
u8 known_vfilter[7];
int i;
for (i = 0; i < 7; i++)
{
int x;
for (x = 0; x < 7; x++)
known_vfilter[x] = known_vfilters[i][x];
if (!addr_start[7] && memcmp(addr_start, known_vfilter, 7) == 0)
{
debug_printf("Replaced vfilter %02x%02x%02x%02x%02x%02x%02x @ %p\n", addr_start[0], addr_start[1],
addr_start[2], addr_start[3], addr_start[4], addr_start[5], addr_start[6], addr_start);
memcpy(addr_start, vfilter, 7);
addr_start += 7;
break;
}
}
addr_start += 1;
}
}
// Patch GXSetCopyFilter to disable the deflicker filter
void deflicker_patch(u8 *addr, u32 len)
{
u32 SearchPattern[18] = {
0x3D20CC01, 0x39400061, 0x99498000,
0x2C050000, 0x38800053, 0x39600000,
0x90098000, 0x38000054, 0x39800000,
0x508BC00E, 0x99498000, 0x500CC00E,
0x90698000, 0x99498000, 0x90E98000,
0x99498000, 0x91098000, 0x41820040};
u8 *addr_start = addr;
u8 *addr_end = addr + len - sizeof(SearchPattern);
while (addr_start <= addr_end)
{
if (memcmp(addr_start, SearchPattern, sizeof(SearchPattern)) == 0)
{
*((u32 *)addr_start + 17) = 0x48000040; // Change beq to b
debug_printf("Patched GXSetCopyFilter @ %p\n", addr_start);
return;
}
addr_start += 4;
}
}
// Patch Dithering
void dithering_patch(u8 *addr, u32 len)
{
u32 SearchPattern[10] = {
0x3C80CC01, 0x38A00061, 0x38000000,
0x80C70220, 0x5066177A, 0x98A48000,
0x90C48000, 0x90C70220, 0xB0070002,
0x4E800020};
u8 *addr_start = addr;
u8 *addr_end = addr + len - sizeof(SearchPattern);
while (addr_start <= addr_end)
{
if (memcmp(addr_start, SearchPattern, sizeof(SearchPattern)) == 0)
{
*((u32 *)addr_start - 1) = 0x48000028;
debug_printf("Patched Dithering @ %p\n", addr_start - 1);
return;
}
addr_start += 4;
}
}
// Patch Framebuffer Width
void framebuffer_patch(void *addr, u32 len)
{
u8 SearchPattern[32] = {
0x40, 0x82, 0x00, 0x08, 0x48, 0x00, 0x00, 0x1C,
0x28, 0x09, 0x00, 0x03, 0x40, 0x82, 0x00, 0x08,
0x48, 0x00, 0x00, 0x10, 0x2C, 0x03, 0x00, 0x00,
0x40, 0x82, 0x00, 0x08, 0x54, 0xA5, 0x0C, 0x3C};
u8 *addr_start = (u8 *)addr;
u8 *addr_end = addr_start + len - sizeof(SearchPattern);
while (addr_start <= addr_end)
{
if (memcmp(addr_start, SearchPattern, sizeof(SearchPattern)) == 0)
{
if (addr_start[-0x70] == 0xA0 && addr_start[-0x6E] == 0x00 && addr_start[-0x6D] == 0x0A)
{
if (addr_start[-0x44] == 0xA0 && addr_start[-0x42] == 0x00 && addr_start[-0x41] == 0x0E)
{
u8 reg_a = (addr_start[-0x6F] >> 5);
u8 reg_b = (addr_start[-0x43] >> 5);
// Patch to the framebuffer resolution
addr_start[-0x41] = 0x04;
// Center the image
void *offset = addr_start - 0x70;
u32 old_heap_ptr = *(u32 *)0x80003110;
*(u32 *)0x80003110 = old_heap_ptr - 0x40;
u32 heap_space = old_heap_ptr - 0x40;
u32 org_address = (addr_start[-0x70] << 24) | (addr_start[-0x6F] << 16);
*(u32 *)(heap_space + 0x00) = org_address | 4;
*(u32 *)(heap_space + 0x04) = 0x200002D0 | (reg_b << 21) | (reg_a << 16);
*(u32 *)(heap_space + 0x08) = 0x38000002 | (reg_a << 21);
*(u32 *)(heap_space + 0x0C) = 0x7C000396 | (reg_a << 21) | (reg_b << 16) | (reg_a << 11);
*(u32 *)offset = 0x48000000 + ((heap_space - (u32)offset) & 0x3ffffff);
*(u32 *)(heap_space + 0x10) = 0x48000000 + ((((u32)offset + 0x04) - (heap_space + 0x10)) & 0x3ffffff);
debug_printf("Patched resolution. Branched from 0x%x to 0x%x\n", (u32) offset, (u32) heap_space);
return;
}
}
}
addr_start += 4;
}
}