diff options
author | 浅倉麗子 | 2020-04-05 22:52:31 -0400 |
---|---|---|
committer | 浅倉麗子 | 2020-04-05 22:52:31 -0400 |
commit | 2cccc1d36c07e6dc624179e7173d41648f6a6b77 (patch) | |
tree | f35c39e6b3f45a92fc837000a112ec948c21f7fc | |
parent | Globally disable Iftu bilinear filtering (diff) | |
download | sharpscale-2cccc1d36c07e6dc624179e7173d41648f6a6b77.tar.gz |
Add support for more framebuffer sizes
-rw-r--r-- | CMakeLists.txt | 2 | ||||
-rw-r--r-- | main.c | 111 | ||||
-rw-r--r-- | scedisplay.h | 43 |
3 files changed, 144 insertions, 12 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index c282d86..f1e8a4a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,11 +30,13 @@ add_executable("${ELF}" ) target_link_libraries("${ELF}" + gcc SceDebugForDriver_stub SceDisplayForDriver_stub SceIofilemgrForDriver_stub SceSysclibForDriver_stub taihenForKernel_stub + taihenModuleUtils_stub ) dolce_create_self("${SELF}" @@ -30,6 +30,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. #include <psp2kern/kernel/sysmem.h> #include <psp2kern/lowio/iftu.h> #include <taihen.h> +#include "scedisplay.h" #define GLZ(x) do {\ if ((x) < 0) { goto fail; }\ @@ -60,7 +61,7 @@ static void LOG(const char *fmt, ...) { #endif } -#define N_HOOK 2 +#define N_HOOK 4 static SceUID hook_id[N_HOOK]; static tai_hook_ref_t hook_ref[N_HOOK]; @@ -72,18 +73,95 @@ static SceUID hook_export(int idx, char *mod, int libnid, int funcnid, void *fun #define HOOK_EXPORT(idx, mod, libnid, funcnid, func)\ hook_export(idx, mod, libnid, funcnid, func##_hook) +static SceUID hook_import(int idx, char *mod, int libnid, int funcnid, void *func) { + hook_id[idx] = taiHookFunctionImportForKernel(KERNEL_PID, hook_ref+idx, mod, libnid, funcnid, func); + LOG("Hooked %d UID %08X\n", idx, hook_id[idx]); + return hook_id[idx]; +} +#define HOOK_IMPORT(idx, mod, libnid, funcnid, func)\ + hook_import(idx, mod, libnid, funcnid, func##_hook) + +static SceUID hook_offset(int idx, int mod, int ofs, void *func) { + hook_id[idx] = taiHookFunctionOffsetForKernel(KERNEL_PID, hook_ref+idx, mod, 0, ofs, 1, func); + LOG("Hooked %d UID %08X\n", idx, hook_id[idx]); + return hook_id[idx]; +} +#define HOOK_OFFSET(idx, mod, ofs, func)\ + hook_offset(idx, mod, ofs, func##_hook) + +extern int module_get_offset(SceUID pid, SceUID modid, int segidx, size_t offset, uintptr_t *addr); +#define GET_OFFSET(modid, seg, ofs, addr)\ + module_get_offset(KERNEL_PID, modid, seg, ofs, (uintptr_t*)addr) + +// SceDisplay_8100B000 +static SceDisplayHead *head_data = 0; + +// SceDisplay_8100B1D4 +static int *primary_head_idx = 0; + +// protected by mutex at SceDisplay_8100B1E4 +static int cur_head_idx = -1; +static int cur_fb_w = 0; +static int cur_fb_h = 0; + +// mutex at SceDisplay_8100B1E4 is locked +static int prepare_set_fb_hook( + int head_idx, int fb_idx, int pitch, int width, int height, + int paddr, int pixelformat, int flags, int sync_mode) { + if ((head_idx & ~1) == 0 && (fb_idx & ~1) == 0 && (sync_mode & ~1) == 0) { + if (head_idx == *primary_head_idx) { + cur_head_idx = head_idx; + cur_fb_w = width; + cur_fb_h = height; + } else { + cur_head_idx = -1; + } + } + return TAI_CONTINUE(int, hook_ref[0], head_idx, fb_idx, pitch, width, height, + paddr, pixelformat, flags, sync_mode); +} + +// mutex at SceDisplay_8100B1E4 is locked +static int prepare_fb_compat_hook( + SceIftuPlaneState *plane, int pitch, int width, int height, + int unk5, int unk6, int unk7, int unk8, int paddr, int flags) { + cur_head_idx = *primary_head_idx; + cur_fb_w = width; + cur_fb_h = height; + return TAI_CONTINUE(int, hook_ref[1], plane, pitch, width, height, + unk5, unk6, unk7, unk8, paddr, flags); +} + +// if mutex at SceDisplay_8100B1E4 is not locked, then state points to a zero struct static int sceIftuSetInputFrameBuffer_hook(int plane, SceIftuPlaneState *state, int bilinear, int sync_mode) { - if (state->src_w == 0xC000 && state->src_h == 0xC16D) { - state->src_w = state->src_h = 0x10000; - state->dst_x = (1280 - 960) / 2; - state->dst_y = (720 - 544) / 2; - } else if (state->src_w == 0x8000 && state->src_h == 0x80F3) { - state->src_h = state->src_w; + if ((cur_head_idx & ~1) != 0 || !state || !state->fb.width || !state->fb.height) { + goto done; } - bilinear = (bilinear == 1) ? 0 : bilinear; + int fb_w = cur_fb_w; + int fb_h = cur_fb_h; + int head_w = head_data[cur_head_idx].head_w; + int head_h = head_data[cur_head_idx].head_h; - return TAI_CONTINUE(int, hook_ref[0], plane, state, bilinear, sync_mode); + int scale_w = head_w / fb_w; + int scale_h = head_h / (fb_h - 16); + int scale = (scale_w < scale_h) ? scale_w : scale_h; + + if (scale > 0) { + state->src_w = 0x10000 / scale; + state->src_h = 0x10000 / scale; + + state->dst_x = (head_w - fb_w * scale) / 2; + state->dst_y = (fb_h * scale <= head_h) + ? (head_h - fb_h * scale) / 2 + : 0; + } + + cur_head_idx = -1; + +done: + bilinear = (bilinear == 1) ? 0 : bilinear; + return TAI_CONTINUE(int, hook_ref[2], plane, state, bilinear, sync_mode); } static int sceDisplaySetScaleConf_hook(float scale, int head, int index, int mode) { @@ -91,7 +169,7 @@ static int sceDisplaySetScaleConf_hook(float scale, int head, int index, int mod scale = 1.0f; mode = 0; } - return TAI_CONTINUE(int, hook_ref[1], scale, head, index, mode); + return TAI_CONTINUE(int, hook_ref[3], scale, head, index, mode); } static void startup(void) { @@ -112,9 +190,18 @@ int _start() __attribute__ ((weak, alias("module_start"))); int module_start(SceSize argc, const void *argv) { (void)argc; (void)argv; startup(); - GLZ(HOOK_EXPORT(0, "SceLowio", 0xCAFCFE50, 0x7CE0C4DA, sceIftuSetInputFrameBuffer)); - GLZ(HOOK_EXPORT(1, "SceDisplay", 0x9FED47AC, 0xEB390A76, sceDisplaySetScaleConf)); + tai_module_info_t minfo; + minfo.size = sizeof(minfo); + GLZ(taiGetModuleInfoForKernel(KERNEL_PID, "SceDisplay", &minfo)); + + GLZ(GET_OFFSET(minfo.modid, 1, 0x000, &head_data)); + GLZ(GET_OFFSET(minfo.modid, 1, 0x1D4, &primary_head_idx)); + + GLZ(HOOK_OFFSET(0, minfo.modid, 0x2CC, prepare_set_fb)); + GLZ(HOOK_OFFSET(1, minfo.modid, 0x004, prepare_fb_compat)); + GLZ(HOOK_IMPORT(2, "SceDisplay", 0xCAFCFE50, 0x7CE0C4DA, sceIftuSetInputFrameBuffer)); + GLZ(HOOK_EXPORT(3, "SceDisplay", 0x9FED47AC, 0xEB390A76, sceDisplaySetScaleConf)); LOG("Disable scaling head 1 fb 0 ret %08X\n", ksceDisplaySetScaleConf(1.0f, 1, 0, 0)); LOG("Disable scaling head 1 fb 1 ret %08X\n", ksceDisplaySetScaleConf(1.0f, 1, 1, 0)); diff --git a/scedisplay.h b/scedisplay.h new file mode 100644 index 0000000..cc9696a --- /dev/null +++ b/scedisplay.h @@ -0,0 +1,43 @@ +#ifndef SCEDISPLAY_H +#define SCEDISPLAY_H + +// From https://github.com/vita-nuova/bounties/issues/7#issuecomment-520154064 + +typedef struct { + SceUID pid; + int paddr; + int scale_mode; + float scale_ratio; + int vp_x; + int vp_y; + int vp_w; + int vp_h; +} SceDisplayHeadFrameBuf; + +typedef struct { + int lock; + int enabled; + int initialized; + int vblankcount; + int cb_event_uid; + int unk14; + int pulse_event_value; + int dsi_bus; + int plane_idx0; + int plane_idx1; + int vic; + int head_w; + int head_h; + int conv_flags; + int head_pixelformat; + int pixel_size; + float refresh_rate; + int interlaced; + int brightness; + int invert_colors; + SceDisplayHeadFrameBuf fb[2]; + int cb_uid; + int brightness_control_value; +} SceDisplayHead; + +#endif |