aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author浅倉麗子2020-04-05 22:52:31 -0400
committer浅倉麗子2020-04-05 22:52:31 -0400
commit2cccc1d36c07e6dc624179e7173d41648f6a6b77 (patch)
treef35c39e6b3f45a92fc837000a112ec948c21f7fc
parentGlobally disable Iftu bilinear filtering (diff)
downloadsharpscale-2cccc1d36c07e6dc624179e7173d41648f6a6b77.tar.gz
Add support for more framebuffer sizes
-rw-r--r--CMakeLists.txt2
-rw-r--r--main.c111
-rw-r--r--scedisplay.h43
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}"
diff --git a/main.c b/main.c
index c16e116..6b71a2d 100644
--- a/main.c
+++ b/main.c
@@ -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