├── LICENSE ├── README.md ├── app ├── CMakeLists.txt ├── SceLibKernel.yml ├── sce_sys │ ├── icon0.png │ ├── livearea │ │ └── contents │ │ │ ├── bg.png │ │ │ ├── startup.png │ │ │ └── template.xml │ └── pic0.png ├── src │ ├── main.c │ └── main.h └── tex │ ├── bg.jpg │ └── texture.gxt ├── main.c └── plugin ├── CMakeLists.txt ├── SceShellSvc.yml ├── ThreadOptimizer.yml ├── main.c └── main.h /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 GrapheneCt 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Thread Optimizer 2 | 3 | Plugin + config application for PS Vita that allows to adjust thread parameters to achieve maximum performance. 4 | 5 | More information here: https://forum.devchroma.nl/index.php/topic,210.0.html 6 | -------------------------------------------------------------------------------- /app/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | 3 | if(NOT DEFINED CMAKE_TOOLCHAIN_FILE) 4 | if(DEFINED ENV{DOLCESDK}) 5 | set(CMAKE_TOOLCHAIN_FILE "$ENV{DOLCESDK}/share/dolce.toolchain.cmake" CACHE PATH "toolchain file") 6 | else() 7 | message(FATAL_ERROR "Please define DOLCESDK to point to your SDK path!") 8 | endif() 9 | endif() 10 | 11 | project(ThreadOptimizer) 12 | 13 | include("${DOLCESDK}/share/dolce.cmake" REQUIRED) 14 | 15 | dolce_gen_libs(SceLibKernel_stubs 16 | SceLibKernel.yml 17 | LIB SceLibKernel_stub_weak) 18 | set(VITA_APP_NAME "Thread Optimizer") 19 | set(VITA_TITLEID "GRVA00004") 20 | set(VITA_VERSION "01.50") 21 | set(DOLCE_MKSFOEX_FLAGS "${DOLCE_MKSFOEX_FLAGS} -d PARENTAL_LEVEL=0") 22 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -O3 -Wno-unused-variable -Wno-unused-but-set-variable -Wno-format-truncation -fno-builtin") 23 | 24 | link_directories( 25 | ${CMAKE_CURRENT_BINARY_DIR} 26 | ) 27 | 28 | add_executable(${PROJECT_NAME} 29 | src/main.c 30 | ) 31 | 32 | target_link_libraries(${PROJECT_NAME} 33 | vita2d_sys 34 | SceGxm_stub 35 | SceLibKernel_stub 36 | SceSysmem_stub 37 | SceKernelThreadMgr_stub 38 | SceProcessMgr_stub 39 | SceAppMgr_stub 40 | ScePvf_stub 41 | SceDisplay_stub 42 | SceSysmodule_stub 43 | SceCtrl_stub 44 | SceIofilemgr_stub 45 | SceCommonDialog_stub 46 | SceVshBridge_stub 47 | SceJpeg_stub 48 | SceLibc_stub 49 | SceFios2_stub 50 | SceKernelDmacMgr_stub 51 | SceDbg_stub 52 | SceLibKernel_stub_weak 53 | ) 54 | 55 | set_target_properties(${PROJECT_NAME} 56 | PROPERTIES LINK_FLAGS "-nostdlib" 57 | ) 58 | 59 | dolce_create_self(eboot.bin ${PROJECT_NAME} UNSAFE) 60 | 61 | dolce_create_vpk(${PROJECT_NAME}.vpk ${VITA_TITLEID} eboot.bin 62 | VERSION ${VITA_VERSION} 63 | NAME ${VITA_APP_NAME} 64 | CONTENT_ID_LABEL THREADOPTIMIZER0 65 | FILE sce_sys/icon0.png sce_sys/icon0.png 66 | FILE sce_sys/pic0.png sce_sys/pic0.png 67 | FILE sce_sys/livearea/contents/bg.png sce_sys/livearea/contents/bg.png 68 | FILE sce_sys/livearea/contents/startup.png sce_sys/livearea/contents/startup.png 69 | FILE sce_sys/livearea/contents/template.xml sce_sys/livearea/contents/template.xml 70 | FILE tex/texture.gxt tex/texture.gxt 71 | FILE tex/bg.jpg tex/bg.jpg 72 | ) 73 | -------------------------------------------------------------------------------- /app/SceLibKernel.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | firmware: 3.60 3 | modules: 4 | SceLibKernel: 5 | nid: 0xF9C9C52F 6 | libraries: 7 | SceRtabi: 8 | kernel: false 9 | nid: 0xA941943F 10 | functions: 11 | SceRtabi_0D4F0635: 0x0D4F0635 12 | SceRtabi_141BC4CE: 0x141BC4CE 13 | SceRtabi_21FF67B9: 0x21FF67B9 # variation of SceRtabi_CBDA815C 14 | SceRtabi_317B3774: 0x317B3774 15 | __aeabi_idivmod: 0x38D62D60 # 32/32 -> 32 signed division 16 | SceRtabi_5024AB91: 0x5024AB91 17 | SceRtabi_609CA961: 0x609CA961 18 | SceRtabi_67104054: 0x67104054 # 32/32 -> 64 signed division 19 | SceRtabi_6BB838EF: 0x6BB838EF 20 | SceRtabi_6CBB0E84: 0x6CBB0E84 21 | SceRtabi_A5DB3A86: 0xA5DB3A86 # variation of SceRtabi_CBDA815C 22 | SceRtabi_AA1F1B50: 0xAA1F1B50 23 | __aeabi_uidivmod: 0xC33391D1 # ??? 32/32 -> 32 unsigned division 24 | SceRtabi_CBDA815C: 0xCBDA815C 25 | SceRtabi_CDF7708E: 0xCDF7708E 26 | __aeabi_uidiv: 0xFB311F87 # ??? 32/32 -> 32 unsigned division 27 | -------------------------------------------------------------------------------- /app/sce_sys/icon0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GrapheneCt/ThreadOptimizer/db8ec09beea03833630385d6425bee2a56beb1ff/app/sce_sys/icon0.png -------------------------------------------------------------------------------- /app/sce_sys/livearea/contents/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GrapheneCt/ThreadOptimizer/db8ec09beea03833630385d6425bee2a56beb1ff/app/sce_sys/livearea/contents/bg.png -------------------------------------------------------------------------------- /app/sce_sys/livearea/contents/startup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GrapheneCt/ThreadOptimizer/db8ec09beea03833630385d6425bee2a56beb1ff/app/sce_sys/livearea/contents/startup.png -------------------------------------------------------------------------------- /app/sce_sys/livearea/contents/template.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | bg.png 6 | 7 | 8 | 9 | startup.png 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/sce_sys/pic0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GrapheneCt/ThreadOptimizer/db8ec09beea03833630385d6425bee2a56beb1ff/app/sce_sys/pic0.png -------------------------------------------------------------------------------- /app/src/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Graphene 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "main.h" 19 | 20 | ScePVoid g_mspace; 21 | 22 | extern SceUID _vshKernelSearchModuleByName(const char *name, SceUInt64 *unk); 23 | extern int sceAppMgrDestroyAppByAppId(int appId); 24 | 25 | static char preset_dir[MAX_PRESET][10]; 26 | static vita2d_pvf *font, *icon_font; 27 | static vita2d_texture *tex_bg, *tex_separator, *tex_button; 28 | 29 | static SceCtrlData ctrl, ctrl_old; 30 | static ThreadOptimizerSnapshot snapshot; 31 | static SceBool cdlg_terminated = SCE_TRUE, cdlg_delete_request = SCE_FALSE, snapshot_loaded = SCE_FALSE, snapshot_changed = SCE_FALSE;; 32 | static unsigned int priority_type = PRIORITY_TYPE_SYSTEM, selection_temp = 0, selection_snapshot = 0, 33 | selection_thread = 0, selection_page = 0, selection_page_mod = 0, selection_m = 0, selection_page_m = 0, selection_page_mod_m = 0; 34 | 35 | #define ONPRESS(flag) ((ctrl.buttons & (flag)) && !(ctrl_old.buttons & (flag))) 36 | 37 | int controlsThread(SceSize args, void *argp) 38 | { 39 | while (1) { 40 | ctrl_old = ctrl; 41 | sceCtrlReadBufferPositive(0, &ctrl, 1); 42 | sceKernelDelayThread(10000); 43 | } 44 | 45 | return 0; 46 | } 47 | 48 | int controls2Thread(SceSize args, void *argp) 49 | { 50 | sceKernelDelayThread(500000); 51 | 52 | while (((ctrl.buttons & SCE_CTRL_RIGHT) == SCE_CTRL_RIGHT) || ((ctrl.buttons & SCE_CTRL_LEFT) == SCE_CTRL_LEFT)) { 53 | if ((ctrl.buttons & SCE_CTRL_RIGHT) == SCE_CTRL_RIGHT) { 54 | switch (priority_type) { 55 | case PRIORITY_TYPE_USER: 56 | if (snapshot.priority[selection_temp] != 0x100000E0) 57 | snapshot.priority[selection_temp]--; 58 | break; 59 | case PRIORITY_TYPE_SYSTEM: 60 | if (snapshot.priority[selection_temp] != 64) 61 | snapshot.priority[selection_temp]--; 62 | break; 63 | } 64 | sceKernelDelayThread(30000); 65 | } 66 | else if ((ctrl.buttons & SCE_CTRL_LEFT) == SCE_CTRL_LEFT) { 67 | switch (priority_type) { 68 | case PRIORITY_TYPE_USER: 69 | if (snapshot.priority[selection_temp] != 0x10000120) 70 | snapshot.priority[selection_temp]++; 71 | break; 72 | case PRIORITY_TYPE_SYSTEM: 73 | if (snapshot.priority[selection_temp] != 191) 74 | snapshot.priority[selection_temp]++; 75 | break; 76 | } 77 | sceKernelDelayThread(30000); 78 | } 79 | } 80 | 81 | sceKernelExitThread(0); 82 | return 0; 83 | } 84 | 85 | int showMessage(const char *str) 86 | { 87 | SceMsgDialogParam msgParam; 88 | SceMsgDialogUserMessageParam userMsgParam; 89 | 90 | sceMsgDialogParamInit(&msgParam); 91 | msgParam.mode = SCE_MSG_DIALOG_MODE_USER_MSG; 92 | 93 | sceClibMemset(&userMsgParam, 0, sizeof(SceMsgDialogUserMessageParam)); 94 | msgParam.userMsgParam = &userMsgParam; 95 | msgParam.userMsgParam->msg = (SceChar8 *)str; 96 | msgParam.userMsgParam->buttonType = SCE_MSG_DIALOG_BUTTON_TYPE_OK; 97 | 98 | msgParam.commonParam.infobarParam = NULL; 99 | msgParam.commonParam.bgColor = NULL; 100 | msgParam.commonParam.dimmerColor = NULL; 101 | 102 | return sceMsgDialogInit(&msgParam); 103 | } 104 | 105 | int showMessageYesNo(const char *str) 106 | { 107 | SceMsgDialogParam msgParam; 108 | SceMsgDialogUserMessageParam userMsgParam; 109 | 110 | sceMsgDialogParamInit(&msgParam); 111 | msgParam.mode = SCE_MSG_DIALOG_MODE_USER_MSG; 112 | 113 | sceClibMemset(&userMsgParam, 0, sizeof(SceMsgDialogUserMessageParam)); 114 | msgParam.userMsgParam = &userMsgParam; 115 | msgParam.userMsgParam->msg = (SceChar8 *)str; 116 | msgParam.userMsgParam->buttonType = SCE_MSG_DIALOG_BUTTON_TYPE_YESNO; 117 | 118 | msgParam.commonParam.infobarParam = NULL; 119 | msgParam.commonParam.bgColor = NULL; 120 | msgParam.commonParam.dimmerColor = NULL; 121 | 122 | return sceMsgDialogInit(&msgParam); 123 | } 124 | 125 | void cdlgDraw(void) { 126 | vita2d_start_drawing(); 127 | vita2d_clear_screen(); 128 | vita2d_draw_texture(tex_bg, 0, 0); 129 | vita2d_end_drawing(); 130 | vita2d_wait_rendering_done(); 131 | vita2d_common_dialog_update(); 132 | vita2d_end_shfb(); 133 | } 134 | 135 | float priorityToWidth(int priority_mode, int priority) 136 | { 137 | if (priority_mode == PRIORITY_TYPE_SYSTEM) { 138 | return (191 - priority) * 6.299f; 139 | } 140 | else 141 | return (0x10000120 - priority) * 12.5f; 142 | } 143 | 144 | void drawCores(int affinity) 145 | { 146 | vita2d_draw_rectangle(CORE_X, CORE_Y, CORE_SIZE, CORE_SIZE, RGBA8(255, 255, 255, 255)); 147 | vita2d_draw_rectangle(CORE_X + 10, CORE_Y + 10, CORE_SIZE - 20, CORE_SIZE - 20, RGBA8(105, 121, 125, 255)); 148 | if (affinity & SCE_KERNEL_CPU_MASK_USER_0) 149 | vita2d_draw_rectangle(CORE_X + 20, CORE_Y + 20, CORE_SIZE - 40, CORE_SIZE - 40, RGBA8(255, 255, 255, 255)); 150 | else 151 | vita2d_draw_rectangle(CORE_X + 20, CORE_Y + 20, CORE_SIZE - 40, CORE_SIZE - 40, RGBA8(105, 121, 125, 255)); 152 | 153 | vita2d_draw_rectangle(CORE_X + CORE_SIZE + CORE_DELTA, CORE_Y, CORE_SIZE, CORE_SIZE, RGBA8(255, 255, 255, 255)); 154 | vita2d_draw_rectangle(CORE_X + CORE_SIZE + CORE_DELTA + 10, CORE_Y + 10, CORE_SIZE - 20, CORE_SIZE - 20, RGBA8(105, 121, 125, 255)); 155 | if (affinity & SCE_KERNEL_CPU_MASK_USER_1) 156 | vita2d_draw_rectangle(CORE_X + CORE_SIZE + CORE_DELTA + 20, CORE_Y + 20, CORE_SIZE - 40, CORE_SIZE - 40, RGBA8(255, 255, 255, 255)); 157 | else 158 | vita2d_draw_rectangle(CORE_X + CORE_SIZE + CORE_DELTA + 20, CORE_Y + 20, CORE_SIZE - 40, CORE_SIZE - 40, RGBA8(105, 121, 125, 255)); 159 | 160 | vita2d_draw_rectangle(CORE_X + CORE_SIZE * 2 + CORE_DELTA * 2, CORE_Y, CORE_SIZE, CORE_SIZE, RGBA8(255, 255, 255, 255)); 161 | vita2d_draw_rectangle(CORE_X + CORE_SIZE * 2 + CORE_DELTA * 2 + 10, CORE_Y + 10, CORE_SIZE - 20, CORE_SIZE - 20, RGBA8(105, 121, 125, 255)); 162 | if (affinity & SCE_KERNEL_CPU_MASK_USER_2) 163 | vita2d_draw_rectangle(CORE_X + CORE_SIZE * 2 + CORE_DELTA * 2 + 20, CORE_Y + 20, CORE_SIZE - 40, CORE_SIZE - 40, RGBA8(255, 255, 255, 255)); 164 | else 165 | vita2d_draw_rectangle(CORE_X + CORE_SIZE * 2 + CORE_DELTA * 2 + 20, CORE_Y + 20, CORE_SIZE - 40, CORE_SIZE - 40, RGBA8(105, 121, 125, 255)); 166 | 167 | vita2d_draw_rectangle(CORE_X + CORE_SIZE * 3 + CORE_DELTA * 3, CORE_Y, CORE_SIZE, CORE_SIZE, RGBA8(255, 255, 255, 255)); 168 | vita2d_draw_rectangle(CORE_X + CORE_SIZE * 3 + CORE_DELTA * 3 + 10, CORE_Y + 10, CORE_SIZE - 20, CORE_SIZE - 20, RGBA8(105, 121, 125, 255)); 169 | if (affinity & SCE_KERNEL_CPU_MASK_USER_3) 170 | vita2d_draw_rectangle(CORE_X + CORE_SIZE * 3 + CORE_DELTA * 3 + 20, CORE_Y + 20, CORE_SIZE - 40, CORE_SIZE - 40, RGBA8(255, 255, 255, 255)); 171 | else 172 | vita2d_draw_rectangle(CORE_X + CORE_SIZE * 3 + CORE_DELTA * 3 + 20, CORE_Y + 20, CORE_SIZE - 40, CORE_SIZE - 40, RGBA8(105, 121, 125, 255)); 173 | } 174 | 175 | void drawSelector(unsigned int selection) 176 | { 177 | int x = CORE_X + (CORE_SIZE * selection + CORE_DELTA * selection); 178 | vita2d_draw_rectangle(x, CORE_Y - 40, CORE_SIZE, 5, RGBA8(255, 255, 255, 255)); 179 | vita2d_draw_rectangle(x, CORE_Y - 40, 5, 10, RGBA8(255, 255, 255, 255)); 180 | vita2d_draw_rectangle(x + CORE_SIZE - 5, CORE_Y - 40, 5, 10, RGBA8(255, 255, 255, 255)); 181 | 182 | vita2d_draw_rectangle(x, CORE_Y + CORE_SIZE + 40, CORE_SIZE, 5, RGBA8(255, 255, 255, 255)); 183 | vita2d_draw_rectangle(x, CORE_Y + CORE_SIZE + 35, 5, 10, RGBA8(255, 255, 255, 255)); 184 | vita2d_draw_rectangle(x + CORE_SIZE - 5, CORE_Y + CORE_SIZE + 35, 5, 10, RGBA8(255, 255, 255, 255)); 185 | } 186 | 187 | unsigned int drawThreadEdit(unsigned int selection_prev) 188 | { 189 | selection_temp = selection_prev; 190 | SceUID ctrl2_thrd = sceKernelCreateThread("Ctrl2Thread", controls2Thread, 0x10000100, 0x1000, 0, 0, NULL); 191 | 192 | char thread_text[MAX_NAME_LEN + 8]; 193 | sceClibSnprintf(thread_text, MAX_NAME_LEN + 8, "0x%04X %s", snapshot.crc16[selection_prev], snapshot.name[selection_prev]); 194 | 195 | int priority_backup, affinity_backup; 196 | priority_backup = snapshot.priority[selection_prev]; 197 | affinity_backup = snapshot.affinity[selection_prev]; 198 | 199 | unsigned int selection = 0, edit_mode = MODE_AFFINITY; 200 | 201 | while (1) { 202 | vita2d_start_drawing(); 203 | vita2d_clear_screen(); 204 | 205 | vita2d_draw_texture(tex_bg, 0, 0); 206 | vita2d_pvf_draw_text(font, 480 - (vita2d_pvf_text_width(font, 1, thread_text) / 2), TOPBAR_TEXT_Y, RGBA8(255, 255, 255, 255), 1, thread_text); 207 | vita2d_draw_texture(tex_separator, 0, TOPBAR_TEXT_Y + 20); 208 | 209 | vita2d_pvf_draw_text(icon_font, LEFT_MARGIN_MAIN, TOPBAR_TEXT_Y + 70, RGBA8(255, 255, 255, 255), 1, "'"); 210 | vita2d_pvf_draw_text(font, LEFT_MARGIN_MAIN + 40, TOPBAR_TEXT_Y + 70, RGBA8(255, 255, 255, 255), 1, "Edit Affinity"); 211 | vita2d_pvf_draw_text(icon_font, LEFT_MARGIN_MAIN + 180, TOPBAR_TEXT_Y + 70, RGBA8(255, 255, 255, 255), 1, "$"); 212 | vita2d_pvf_draw_text(font, LEFT_MARGIN_MAIN + 220, TOPBAR_TEXT_Y + 70, RGBA8(255, 255, 255, 255), 1, "Edit Priority"); 213 | vita2d_pvf_draw_text(icon_font, LEFT_MARGIN_MAIN + 360, TOPBAR_TEXT_Y + 70, RGBA8(255, 255, 255, 255), 1, "5"); 214 | vita2d_pvf_draw_text(font, LEFT_MARGIN_MAIN + 420, TOPBAR_TEXT_Y + 70, RGBA8(255, 255, 255, 255), 1, "Restore All"); 215 | 216 | switch (edit_mode) { 217 | case MODE_AFFINITY: 218 | 219 | drawCores(snapshot.affinity[selection_prev]); 220 | drawSelector(selection); 221 | 222 | vita2d_pvf_draw_text(font, LEFT_MARGIN + 10, TOPBAR_TEXT_Y + 460, RGBA8(255, 255, 255, 255), 1, "*If no cores set, CPU affinity mask will be automatically assigned by the system"); 223 | 224 | vita2d_end_drawing(); 225 | vita2d_wait_rendering_done(); 226 | vita2d_end_shfb(); 227 | 228 | if (ONPRESS(SCE_CTRL_RIGHT)) { 229 | if (selection != 3) 230 | selection++; 231 | } 232 | else if (ONPRESS(SCE_CTRL_LEFT)) { 233 | if (selection != 0) 234 | selection--; 235 | } 236 | else if (ONPRESS(SCE_CTRL_CROSS)) { 237 | switch (selection) { 238 | case 0: 239 | sceKernelAtomicXorAndGet32(&snapshot.affinity[selection_prev], SCE_KERNEL_CPU_MASK_USER_0); 240 | break; 241 | case 1: 242 | sceKernelAtomicXorAndGet32(&snapshot.affinity[selection_prev], SCE_KERNEL_CPU_MASK_USER_1); 243 | break; 244 | case 2: 245 | sceKernelAtomicXorAndGet32(&snapshot.affinity[selection_prev], SCE_KERNEL_CPU_MASK_USER_2); 246 | break; 247 | case 3: 248 | sceKernelAtomicXorAndGet32(&snapshot.affinity[selection_prev], SCE_KERNEL_CPU_MASK_USER_3); 249 | break; 250 | } 251 | } 252 | 253 | break; 254 | case MODE_PRIORITY: 255 | 256 | if (snapshot.priority[selection_prev] > SCE_KERNEL_COMMON_QUEUE_LOWEST_PRIORITY) 257 | priority_type = PRIORITY_TYPE_USER; 258 | else 259 | priority_type = PRIORITY_TYPE_SYSTEM; 260 | 261 | vita2d_draw_rectangle(80, TOPBAR_TEXT_Y + 220, 800, 10, RGBA8(54, 59, 61, 255)); 262 | vita2d_draw_rectangle(80, TOPBAR_TEXT_Y + 220, priorityToWidth(priority_type, snapshot.priority[selection_prev]), 10, RGBA8(255, 255, 255, 255)); 263 | 264 | if (priority_type == PRIORITY_TYPE_SYSTEM) { 265 | vita2d_pvf_draw_text(icon_font, LEFT_MARGIN + 10, TOPBAR_TEXT_Y + 120, RGBA8(255, 255, 255, 255), 1, "&"); 266 | vita2d_pvf_draw_text(font, LEFT_MARGIN + 50, TOPBAR_TEXT_Y + 120, RGBA8(255, 255, 255, 255), 1, "Priority mode: [System]"); 267 | vita2d_pvf_draw_textf(font, LEFT_MARGIN + 10, TOPBAR_TEXT_Y + 170, RGBA8(255, 255, 255, 255), 1, "Current priority: %d", snapshot.priority[selection_prev]); 268 | vita2d_draw_rectangle(80, TOPBAR_TEXT_Y + 230, 3, 10, RGBA8(0, 0, 255, 255)); 269 | vita2d_draw_rectangle(877, TOPBAR_TEXT_Y + 230, 3, 10, RGBA8(255, 0, 0, 255)); 270 | vita2d_draw_rectangle(480, TOPBAR_TEXT_Y + 230, 3, 10, RGBA8(0, 255, 0, 255)); 271 | vita2d_draw_rectangle(474, TOPBAR_TEXT_Y + 230, 3, 10, RGBA8(255, 255, 0, 255)); 272 | vita2d_draw_rectangle(LEFT_MARGIN + 10, TOPBAR_TEXT_Y + 288, 10, 10, RGBA8(0, 0, 255, 255)); 273 | vita2d_pvf_draw_text(font, LEFT_MARGIN + 30, TOPBAR_TEXT_Y + 300, RGBA8(255, 255, 255, 255), 1, "SCE_KERNEL_COMMON_QUEUE_LOWEST_PRIORITY (191)"); 274 | vita2d_draw_rectangle(LEFT_MARGIN + 10, TOPBAR_TEXT_Y + 328, 10, 10, RGBA8(255, 255, 0, 255)); 275 | vita2d_pvf_draw_text(font, LEFT_MARGIN + 30, TOPBAR_TEXT_Y + 340, RGBA8(255, 255, 255, 255), 1, "SCE_KERNEL_COMMON_QUEUE_HIGHEST_PRIORITY (128)"); 276 | vita2d_draw_rectangle(LEFT_MARGIN + 10, TOPBAR_TEXT_Y + 368, 10, 10, RGBA8(0, 255, 0, 255)); 277 | vita2d_pvf_draw_text(font, LEFT_MARGIN + 30, TOPBAR_TEXT_Y + 380, RGBA8(255, 255, 255, 255), 1, "SCE_KERNEL_INDIVIDUAL_QUEUE_LOWEST_PRIORITY (127)"); 278 | vita2d_draw_rectangle(LEFT_MARGIN + 10, TOPBAR_TEXT_Y + 408, 10, 10, RGBA8(255, 0, 0, 255)); 279 | vita2d_pvf_draw_text(font, LEFT_MARGIN + 30, TOPBAR_TEXT_Y + 420, RGBA8(255, 255, 255, 255), 1, "SCE_KERNEL_INDIVIDUAL_QUEUE_HIGHEST_PRIORITY (64)"); 280 | } 281 | else { 282 | vita2d_pvf_draw_text(icon_font, LEFT_MARGIN + 10, TOPBAR_TEXT_Y + 120, RGBA8(255, 255, 255, 255), 1, "&"); 283 | vita2d_pvf_draw_text(font, LEFT_MARGIN + 50, TOPBAR_TEXT_Y + 120, RGBA8(255, 255, 255, 255), 1, "Priority mode: [User]"); 284 | vita2d_pvf_draw_textf(font, LEFT_MARGIN + 10, TOPBAR_TEXT_Y + 170, RGBA8(255, 255, 255, 255), 1, "Current priority: %d", snapshot.priority[selection_prev] - 0x100000A0); 285 | vita2d_draw_rectangle(80, TOPBAR_TEXT_Y + 230, 3, 10, RGBA8(0, 0, 255, 255)); 286 | vita2d_draw_rectangle(877, TOPBAR_TEXT_Y + 230, 3, 10, RGBA8(255, 0, 0, 255)); 287 | vita2d_draw_rectangle(LEFT_MARGIN + 10, TOPBAR_TEXT_Y + 288, 10, 10, RGBA8(0, 0, 255, 255)); 288 | vita2d_pvf_draw_text(font, LEFT_MARGIN + 30, TOPBAR_TEXT_Y + 300, RGBA8(255, 255, 255, 255), 1, "SCE_KERNEL_INDIVIDUAL_QUEUE_LOWEST_PRIORITY (127)"); 289 | vita2d_draw_rectangle(LEFT_MARGIN + 10, TOPBAR_TEXT_Y + 328, 10, 10, RGBA8(255, 0, 0, 255)); 290 | vita2d_pvf_draw_text(font, LEFT_MARGIN + 30, TOPBAR_TEXT_Y + 340, RGBA8(255, 255, 255, 255), 1, "SCE_KERNEL_INDIVIDUAL_QUEUE_HIGHEST_PRIORITY (64)"); 291 | } 292 | 293 | vita2d_end_drawing(); 294 | vita2d_wait_rendering_done(); 295 | vita2d_end_shfb(); 296 | 297 | if (ONPRESS(SCE_CTRL_RIGHT)) { 298 | sceKernelStartThread(ctrl2_thrd, 0, NULL); 299 | switch (priority_type) { 300 | case PRIORITY_TYPE_USER: 301 | if (snapshot.priority[selection_prev] != 0x100000E0) 302 | snapshot.priority[selection_prev]--; 303 | break; 304 | case PRIORITY_TYPE_SYSTEM: 305 | if (snapshot.priority[selection_prev] != 64) 306 | snapshot.priority[selection_prev]--; 307 | break; 308 | } 309 | } 310 | else if (ONPRESS(SCE_CTRL_LEFT)) { 311 | sceKernelStartThread(ctrl2_thrd, 0, NULL); 312 | switch (priority_type) { 313 | case PRIORITY_TYPE_USER: 314 | if (snapshot.priority[selection_prev] != 0x10000120) 315 | snapshot.priority[selection_prev]++; 316 | break; 317 | case PRIORITY_TYPE_SYSTEM: 318 | if (snapshot.priority[selection_prev] != 191) 319 | snapshot.priority[selection_prev]++; 320 | break; 321 | } 322 | } 323 | else if (ONPRESS(SCE_CTRL_CROSS)) { 324 | if (snapshot.priority[selection_prev] > SCE_KERNEL_COMMON_QUEUE_LOWEST_PRIORITY) 325 | snapshot.priority[selection_prev] = 96; 326 | else 327 | snapshot.priority[selection_prev] = SCE_KERNEL_DEFAULT_PRIORITY; 328 | } 329 | 330 | break; 331 | } 332 | 333 | if (ONPRESS(SCE_CTRL_CIRCLE)) { 334 | break; 335 | } 336 | else if (ONPRESS(SCE_CTRL_SQUARE)) { 337 | edit_mode = MODE_AFFINITY; 338 | } 339 | else if (ONPRESS(SCE_CTRL_TRIANGLE)) { 340 | edit_mode = MODE_PRIORITY; 341 | } 342 | else if (ONPRESS(SCE_CTRL_START)) { 343 | snapshot.priority[selection_prev] = priority_backup; 344 | snapshot.affinity[selection_prev] = affinity_backup; 345 | } 346 | } 347 | 348 | if ((snapshot.priority[selection_prev] != priority_backup) || (snapshot.affinity[selection_prev] != affinity_backup)) 349 | snapshot_changed = SCE_TRUE; 350 | 351 | return selection_snapshot; 352 | } 353 | 354 | unsigned int drawThreadSelect(unsigned int selection_prev) 355 | { 356 | selection_snapshot = selection_prev; 357 | unsigned int total_pages = 0; 358 | char snapshot_path[46]; 359 | 360 | if (!snapshot_loaded) { 361 | sceClibMemset(&snapshot, 0, sizeof(ThreadOptimizerSnapshot)); 362 | 363 | sceClibMemset(&snapshot_path, 0, 46); 364 | sceClibSnprintf(snapshot_path, 46, "ux0:data/ThreadOptimizer/%s/config.dat", preset_dir[selection_prev]); 365 | 366 | SceUID fd = sceIoOpen(snapshot_path, SCE_O_RDONLY, 0777); 367 | sceIoRead(fd, &snapshot, sizeof(ThreadOptimizerSnapshot)); 368 | sceIoClose(fd); 369 | 370 | snapshot_loaded = SCE_TRUE; 371 | } 372 | 373 | float total_pages_temp = (float)snapshot.thread_count / (float)TOTAL_PER_PAGE; 374 | total_pages = ceilf(total_pages_temp); 375 | total_pages--; 376 | 377 | vita2d_sys_widget* widget[MAX_THREADS]; 378 | 379 | int coordinate_mltp = 0; 380 | char thread_text[MAX_THREADS][MAX_NAME_LEN + 8]; 381 | 382 | for (int i = 0; i < snapshot.thread_count; i++) { 383 | sceClibSnprintf(thread_text[i], MAX_NAME_LEN + 8, "0x%04X %s", snapshot.crc16[i], snapshot.name[i]); 384 | widget[i] = vita2d_sys_create_widget_button(tex_button, font, 0, (TOPBAR_TEXT_Y + 22) + WIDGET_BUTTON_HEIGHT * coordinate_mltp, WIDGET_BUTTON_TEXT_DX, WIDGET_BUTTON_TEXT_DY, thread_text[i]); 385 | coordinate_mltp++; 386 | if (coordinate_mltp == TOTAL_PER_PAGE) 387 | coordinate_mltp = 0; 388 | } 389 | 390 | unsigned int selection = selection_thread, page = selection_page, page_modifier = selection_page_mod; 391 | 392 | if (snapshot.thread_count == 0) { 393 | showMessageYesNo("Error: There are no threads in this snapshot.\n\nDo you want to delete it?"); 394 | while (sceMsgDialogGetStatus() != 2) 395 | cdlgDraw(); 396 | SceMsgDialogResult result; 397 | sceMsgDialogGetResult(&result); 398 | sceMsgDialogTerm(); 399 | if (result.buttonId == SCE_MSG_DIALOG_BUTTON_ID_YES) { 400 | char snapshot_dir_path[35]; 401 | sceClibMemset(&snapshot_dir_path, 0, 35); 402 | sceClibSnprintf(snapshot_dir_path, 35, "ux0:data/ThreadOptimizer/%s/config.dat", preset_dir[selection_prev]); 403 | sceIoRemove(snapshot_path); 404 | sceIoRmdir(snapshot_dir_path); 405 | } 406 | selection = BACK_MAGIC; 407 | goto threadSelect_ret; 408 | } 409 | 410 | while (1) { 411 | vita2d_start_drawing(); 412 | vita2d_clear_screen(); 413 | 414 | vita2d_draw_texture(tex_bg, 0, 0); 415 | vita2d_pvf_draw_text(font, 480 - (vita2d_pvf_text_width(font, 1, "Thread Selection") / 2), TOPBAR_TEXT_Y, RGBA8(255, 255, 255, 255), 1, "Thread Selection"); 416 | if (page != 0) 417 | vita2d_pvf_draw_text(icon_font, LEFT_MARGIN, TOPBAR_TEXT_Y, RGBA8(255, 255, 255, 255), 1, "0"); 418 | if (page != total_pages) 419 | vita2d_pvf_draw_text(icon_font, RIGHT_MARGIN, TOPBAR_TEXT_Y, RGBA8(255, 255, 255, 255), 1, "1"); 420 | vita2d_pvf_draw_text(icon_font, LEFT_MARGIN + 60, TOPBAR_TEXT_Y, RGBA8(255, 255, 255, 255), 1, "'"); 421 | vita2d_pvf_draw_text(font, LEFT_MARGIN + 60, TOPBAR_TEXT_Y, RGBA8(255, 255, 255, 255), 1, " Save"); 422 | vita2d_pvf_draw_text(icon_font, RIGHT_MARGIN - 40, TOPBAR_TEXT_Y, RGBA8(255, 255, 255, 255), 1, "$"); 423 | vita2d_pvf_draw_text(font, RIGHT_MARGIN - 150, TOPBAR_TEXT_Y, RGBA8(255, 255, 255, 255), 1, " Delete"); 424 | vita2d_draw_texture(tex_separator, 0, TOPBAR_TEXT_Y + 20); 425 | 426 | for (int i = 0; i < TOTAL_PER_PAGE && ((i + page_modifier) < snapshot.thread_count); i++) { 427 | if (i == selection) 428 | vita2d_sys_widget_set_highlight(widget[i + page_modifier], SCE_TRUE); 429 | else 430 | vita2d_sys_widget_set_highlight(widget[i + page_modifier], SCE_FALSE); 431 | vita2d_sys_draw_widget(widget[i + page_modifier]); 432 | } 433 | 434 | vita2d_end_drawing(); 435 | vita2d_wait_rendering_done(); 436 | if (sceMsgDialogGetStatus() != 2 && !cdlg_terminated) 437 | vita2d_common_dialog_update(); 438 | else if (!cdlg_terminated) { 439 | sceMsgDialogTerm(); 440 | cdlg_terminated = SCE_TRUE; 441 | } 442 | vita2d_end_shfb(); 443 | 444 | if (cdlg_delete_request) { 445 | SceMsgDialogResult result; 446 | sceMsgDialogGetResult(&result); 447 | if (result.buttonId == SCE_MSG_DIALOG_BUTTON_ID_YES) { 448 | sceMsgDialogTerm(); 449 | cdlg_terminated = SCE_TRUE; 450 | cdlg_delete_request = SCE_FALSE; 451 | char snapshot_dir_path[35]; 452 | sceClibMemset(&snapshot_dir_path, 0, 35); 453 | sceClibSnprintf(snapshot_dir_path, 35, "ux0:data/ThreadOptimizer/%s/config.dat", preset_dir[selection_prev]); 454 | sceIoRemove(snapshot_path); 455 | sceIoRmdir(snapshot_dir_path); 456 | selection = BACK_MAGIC; 457 | break; 458 | } 459 | else if (result.buttonId == SCE_MSG_DIALOG_BUTTON_ID_NO) { 460 | sceMsgDialogTerm(); 461 | cdlg_terminated = SCE_TRUE; 462 | cdlg_delete_request = SCE_FALSE; 463 | } 464 | } 465 | 466 | if (ONPRESS(SCE_CTRL_DOWN)) { 467 | if ((selection != (TOTAL_PER_PAGE - 1)) && ((selection + page_modifier) != (snapshot.thread_count - 1))) { 468 | vita2d_sys_widget_set_highlight_max(); 469 | selection++; 470 | } 471 | } 472 | else if (ONPRESS(SCE_CTRL_UP)) { 473 | if (selection != 0) { 474 | vita2d_sys_widget_set_highlight_max(); 475 | selection--; 476 | } 477 | } 478 | else if (ONPRESS(SCE_CTRL_R2)) { 479 | if (page != total_pages) { 480 | vita2d_sys_widget_set_highlight_max(); 481 | page_modifier += TOTAL_PER_PAGE; 482 | selection = 0; 483 | page++; 484 | } 485 | } 486 | else if (ONPRESS(SCE_CTRL_L2)) { 487 | if (page != 0) { 488 | vita2d_sys_widget_set_highlight_max(); 489 | page_modifier -= TOTAL_PER_PAGE; 490 | selection = 0; 491 | page--; 492 | } 493 | } 494 | else if (ONPRESS(SCE_CTRL_CROSS)) { 495 | for (int i = 0; i < snapshot.thread_count; i++) 496 | vita2d_sys_delete_widget(widget[i]); 497 | break; 498 | } 499 | else if (ONPRESS(SCE_CTRL_CIRCLE)) { 500 | for (int i = 0; i < snapshot.thread_count; i++) 501 | vita2d_sys_delete_widget(widget[i]); 502 | if (snapshot_changed) { 503 | showMessageYesNo("Do you want to save changes?"); 504 | while (sceMsgDialogGetStatus() != 2) 505 | cdlgDraw(); 506 | SceMsgDialogResult result; 507 | sceMsgDialogGetResult(&result); 508 | sceMsgDialogTerm(); 509 | if (result.buttonId == SCE_MSG_DIALOG_BUTTON_ID_YES) { 510 | SceUID fd = sceIoOpen(snapshot_path, SCE_O_WRONLY | SCE_O_CREAT, 0777); 511 | sceIoWrite(fd, &snapshot, sizeof(ThreadOptimizerSnapshot)); 512 | sceIoClose(fd); 513 | } 514 | snapshot_changed = SCE_FALSE; 515 | } 516 | selection = BACK_MAGIC; 517 | break; 518 | } 519 | else if (ONPRESS(SCE_CTRL_SQUARE)) { 520 | SceUID fd = sceIoOpen(snapshot_path, SCE_O_WRONLY | SCE_O_CREAT, 0777); 521 | sceIoWrite(fd, &snapshot, sizeof(ThreadOptimizerSnapshot)); 522 | sceIoClose(fd); 523 | snapshot_changed = SCE_FALSE; 524 | showMessage("Snapshot has been saved."); 525 | cdlg_terminated = SCE_FALSE; 526 | } 527 | else if (ONPRESS(SCE_CTRL_TRIANGLE)) { 528 | showMessageYesNo("Do you want to delete this snapshot?"); 529 | cdlg_delete_request = SCE_TRUE; 530 | cdlg_terminated = SCE_FALSE; 531 | } 532 | } 533 | 534 | threadSelect_ret: 535 | 536 | if (selection == BACK_MAGIC) 537 | return BACK_MAGIC; 538 | else { 539 | selection_page = page; 540 | selection_page_mod = page_modifier; 541 | selection_thread = selection; 542 | return selection + page_modifier; 543 | } 544 | } 545 | 546 | unsigned int drawMainSelect(void) 547 | { 548 | selection_page = 0; 549 | selection_page_mod = 0; 550 | selection_thread = 0; 551 | snapshot_loaded = SCE_FALSE; 552 | 553 | unsigned int preset_count = 0, total_pages = 0; 554 | 555 | SceUID dfd = sceIoDopen("ux0:data/ThreadOptimizer"); 556 | if (dfd < 0) { 557 | sceIoMkdir("ux0:data/ThreadOptimizer", 0777); 558 | dfd = sceIoDopen("ux0:data/ThreadOptimizer"); 559 | } 560 | 561 | SceIoDirent dirent; 562 | sceClibMemset(&preset_dir, 0, MAX_PRESET * 10); 563 | 564 | while (sceIoDread(dfd, &dirent) != 0) { 565 | sceClibStrncpy(preset_dir[preset_count], dirent.d_name, 10); 566 | preset_count++; 567 | } 568 | 569 | float total_pages_temp = (float)preset_count / (float)TOTAL_PER_PAGE; 570 | total_pages = ceilf(total_pages_temp); 571 | total_pages--; 572 | 573 | vita2d_sys_widget* widget[MAX_PRESET]; 574 | 575 | int coordinate_mltp = 0; 576 | 577 | for (int i = 0; i < preset_count; i++) { 578 | widget[i] = vita2d_sys_create_widget_button(tex_button, font, 0, (TOPBAR_TEXT_Y + 22) + WIDGET_BUTTON_HEIGHT * coordinate_mltp, WIDGET_BUTTON_TEXT_DX, WIDGET_BUTTON_TEXT_DY, preset_dir[i]); 579 | coordinate_mltp++; 580 | if (coordinate_mltp == TOTAL_PER_PAGE) 581 | coordinate_mltp = 0; 582 | } 583 | 584 | unsigned int selection = selection_m, total_count = 0, page = selection_page_m, page_modifier = selection_page_mod_m; 585 | 586 | if (preset_count == 0) { 587 | showMessage("Error: There are no saved snapshots."); 588 | while (sceMsgDialogGetStatus() != 2) 589 | cdlgDraw(); 590 | sceMsgDialogTerm(); 591 | sceAppMgrDestroyAppByAppId(-2); 592 | } 593 | 594 | while (1) { 595 | vita2d_start_drawing(); 596 | vita2d_clear_screen(); 597 | 598 | vita2d_draw_texture(tex_bg, 0, 0); 599 | vita2d_pvf_draw_text(font, 480 - (vita2d_pvf_text_width(font, 1, "Snapshot Selection") / 2), TOPBAR_TEXT_Y, RGBA8(255, 255, 255, 255), 1, "Snapshot Selection"); 600 | if (page != 0) 601 | vita2d_pvf_draw_text(icon_font, LEFT_MARGIN, TOPBAR_TEXT_Y, RGBA8(255, 255, 255, 255), 1, "0"); 602 | if (page != total_pages) 603 | vita2d_pvf_draw_text(icon_font, RIGHT_MARGIN, TOPBAR_TEXT_Y, RGBA8(255, 255, 255, 255), 1, "1"); 604 | vita2d_draw_texture(tex_separator, 0, TOPBAR_TEXT_Y + 20); 605 | 606 | for (int i = 0; i < TOTAL_PER_PAGE && ((i + page_modifier) < preset_count); i++) { 607 | if (i == selection) { 608 | vita2d_sys_widget_set_highlight(widget[i + page_modifier], SCE_TRUE); 609 | } 610 | else 611 | vita2d_sys_widget_set_highlight(widget[i + page_modifier], SCE_FALSE); 612 | vita2d_sys_draw_widget(widget[i + page_modifier]); 613 | } 614 | 615 | vita2d_end_drawing(); 616 | vita2d_wait_rendering_done(); 617 | vita2d_end_shfb(); 618 | 619 | if (ONPRESS(SCE_CTRL_DOWN)) { 620 | if ((selection != (TOTAL_PER_PAGE - 1)) && ((selection + page_modifier) != (preset_count - 1))) { 621 | vita2d_sys_widget_set_highlight_max(); 622 | selection++; 623 | } 624 | } 625 | else if (ONPRESS(SCE_CTRL_UP)) { 626 | if (selection != 0) { 627 | vita2d_sys_widget_set_highlight_max(); 628 | selection--; 629 | } 630 | } 631 | else if (ONPRESS(SCE_CTRL_R2)) { 632 | if (page != total_pages) { 633 | vita2d_sys_widget_set_highlight_max(); 634 | page_modifier += TOTAL_PER_PAGE; 635 | selection = 0; 636 | page++; 637 | } 638 | } 639 | else if (ONPRESS(SCE_CTRL_L2)) { 640 | if (page != 0) { 641 | vita2d_sys_widget_set_highlight_max(); 642 | page_modifier -= TOTAL_PER_PAGE; 643 | selection = 0; 644 | page--; 645 | } 646 | } 647 | else if (ONPRESS(SCE_CTRL_CROSS)) { 648 | for (int i = 0; i < preset_count; i++) 649 | vita2d_sys_delete_widget(widget[i]); 650 | break; 651 | } 652 | } 653 | 654 | selection_page_m = page; 655 | selection_page_mod_m = page_modifier; 656 | selection_m = selection; 657 | 658 | return selection + page_modifier; 659 | } 660 | 661 | void _start(unsigned int args, void *argp) 662 | { 663 | ScePVoid clibm_base; 664 | SceUID clib_heap = sceKernelAllocMemBlock("ClibHeap", SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE, CLIB_HEAP_SIZE, NULL); 665 | sceKernelGetMemBlockBase(clib_heap, &clibm_base); 666 | g_mspace = sceClibMspaceCreate(clibm_base, CLIB_HEAP_SIZE); 667 | 668 | vita2d_clib_pass_mspace(g_mspace); 669 | vita2d_init(); 670 | 671 | vita2d_set_vblank_wait(1); 672 | vita2d_set_clear_color(RGBA8(105, 121, 125, 255)); 673 | 674 | SceInt32 ret; 675 | SceUInt64 unk; 676 | 677 | vita2d_JPEG_decoder_initialize(); 678 | tex_bg = vita2d_load_JPEG_file("app0:tex/bg.jpg", 0, 0, 0, 0, 0); 679 | vita2d_JPEG_decoder_finish(); 680 | tex_separator = vita2d_load_GXT_file("app0:tex/texture.gxt", 0, 0); 681 | tex_button = vita2d_load_additional_GXT(tex_separator, 1); 682 | 683 | SceUID modid = _vshKernelSearchModuleByName("CoreUnlocker80000H", &unk); 684 | if (modid < 0) { 685 | showMessage("Error: CoreUnlocker80000H plugin not found.\n\nPlease install it and try again."); 686 | while (sceMsgDialogGetStatus() != 2) 687 | cdlgDraw(); 688 | sceMsgDialogTerm(); 689 | sceAppMgrDestroyAppByAppId(-2); 690 | } 691 | modid = _vshKernelSearchModuleByName("ioplus", &unk); 692 | if (modid < 0) { 693 | showMessage("Error: ioPlus plugin not found.\n\nPlease install it and try again."); 694 | while (sceMsgDialogGetStatus() != 2) 695 | cdlgDraw(); 696 | sceMsgDialogTerm(); 697 | sceAppMgrDestroyAppByAppId(-2); 698 | } 699 | 700 | vita2d_system_pvf_config configs[] = { 701 | {SCE_PVF_LANGUAGE_LATIN, SCE_PVF_FAMILY_SANSERIF, SCE_PVF_STYLE_REGULAR, NULL}, 702 | }; 703 | 704 | font = vita2d_load_system_pvf(1, configs, 14, 14); 705 | icon_font = vita2d_load_custom_pvf("sa0:data/font/pvf/psexchar.pvf", 14, 14); 706 | 707 | SceUID ctrl_thrd = sceKernelCreateThread("CtrlThread", controlsThread, 0x10000100, 0x1000, 0, 0, NULL); 708 | sceKernelStartThread(ctrl_thrd, 0, NULL); 709 | 710 | unsigned int selection; 711 | 712 | repeat_0: 713 | 714 | selection = 0; 715 | selection = drawMainSelect(); 716 | 717 | repeat_1: 718 | 719 | selection = drawThreadSelect(selection); 720 | 721 | if (selection == BACK_MAGIC) 722 | goto repeat_0; 723 | 724 | selection = drawThreadEdit(selection); 725 | goto repeat_1; 726 | 727 | sceKernelExitProcess(0); 728 | } 729 | 730 | -------------------------------------------------------------------------------- /app/src/main.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Graphene 3 | */ 4 | 5 | #pragma once 6 | 7 | //#define DEBUG_ON 8 | 9 | #ifdef DEBUG_ON 10 | # define DEBUG_PRINT(...) sceClibPrintf(__VA_ARGS__) 11 | #else 12 | # define DEBUG_PRINT(...) 13 | #endif 14 | 15 | #define MAX_PRESET 1024 16 | #define CLIB_HEAP_SIZE 1 * 1024 * 1024 17 | 18 | #define BACK_MAGIC 4294967295U 19 | 20 | #define LEFT_MARGIN 10 21 | #define LEFT_MARGIN_MAIN 210 22 | #define RIGHT_MARGIN 900 23 | #define TOP_MARGIN 110 24 | 25 | #define CORE_X 90 26 | #define CORE_Y 200 27 | #define CORE_SIZE 180 28 | #define CORE_DELTA 20 29 | 30 | #define WIDGET_BUTTON_TEXT_DX 30 31 | #define WIDGET_BUTTON_TEXT_DY 50 32 | #define WIDGET_BUTTON_HEIGHT 80 33 | 34 | #define TOPBAR_TEXT_Y 40 35 | 36 | #define MAX_THREADS 128 37 | #define MAX_NAME_LEN 37 38 | 39 | #define TOTAL_PER_PAGE 6 40 | 41 | typedef enum PriorityType { 42 | PRIORITY_TYPE_SYSTEM, 43 | PRIORITY_TYPE_USER 44 | } PriorityType; 45 | 46 | typedef enum EditMode { 47 | MODE_AFFINITY, 48 | MODE_PRIORITY 49 | } EditMode; 50 | 51 | typedef struct ThreadOptimizerSnapshot { 52 | char titleid[10]; 53 | unsigned int thread_count; 54 | unsigned short crc16[MAX_THREADS]; 55 | char name[MAX_THREADS][MAX_NAME_LEN]; 56 | SceKernelThreadEntry entry[MAX_THREADS]; 57 | int priority[MAX_THREADS]; 58 | int affinity[MAX_THREADS]; 59 | } ThreadOptimizerSnapshot; 60 | 61 | int32_t sceKernelAtomicXorAndGet32(int32_t* dst, int32_t val); -------------------------------------------------------------------------------- /app/tex/bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GrapheneCt/ThreadOptimizer/db8ec09beea03833630385d6425bee2a56beb1ff/app/tex/bg.jpg -------------------------------------------------------------------------------- /app/tex/texture.gxt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GrapheneCt/ThreadOptimizer/db8ec09beea03833630385d6425bee2a56beb1ff/app/tex/texture.gxt -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Graphene 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "main.h" 19 | 20 | ScePVoid g_mspace; 21 | 22 | extern SceUID _vshKernelSearchModuleByName(const char *name, SceUInt64 *unk); 23 | extern int sceAppMgrDestroyAppByAppId(int appId); 24 | 25 | static char preset_dir[MAX_PRESET][10]; 26 | static vita2d_pvf *font, *icon_font; 27 | static vita2d_texture *tex_bg, *tex_separator, *tex_button; 28 | 29 | static SceCtrlData ctrl, ctrl_old; 30 | static ThreadOptimizerSnapshot snapshot; 31 | static SceBool cdlg_terminated = SCE_TRUE, cdlg_delete_request = SCE_FALSE, snapshot_loaded = SCE_FALSE, snapshot_changed = SCE_FALSE;; 32 | static unsigned int priority_type = PRIORITY_TYPE_SYSTEM, selection_temp = 0, selection_snapshot = 0, 33 | selection_thread = 0, selection_page = 0, selection_page_mod = 0, selection_m = 0, selection_page_m = 0, selection_page_mod_m = 0; 34 | 35 | #define ONPRESS(flag) ((ctrl.buttons & (flag)) && !(ctrl_old.buttons & (flag))) 36 | 37 | int controlsThread(SceSize args, void *argp) 38 | { 39 | while (1) { 40 | ctrl_old = ctrl; 41 | sceCtrlReadBufferPositive(0, &ctrl, 1); 42 | sceKernelDelayThread(10000); 43 | } 44 | 45 | return 0; 46 | } 47 | 48 | int controls2Thread(SceSize args, void *argp) 49 | { 50 | sceKernelDelayThread(500000); 51 | 52 | while (((ctrl.buttons & SCE_CTRL_RIGHT) == SCE_CTRL_RIGHT) || ((ctrl.buttons & SCE_CTRL_LEFT) == SCE_CTRL_LEFT)) { 53 | if ((ctrl.buttons & SCE_CTRL_RIGHT) == SCE_CTRL_RIGHT) { 54 | switch (priority_type) { 55 | case PRIORITY_TYPE_USER: 56 | if (snapshot.priority[selection_temp] != 0x100000E0) 57 | snapshot.priority[selection_temp]--; 58 | break; 59 | case PRIORITY_TYPE_SYSTEM: 60 | if (snapshot.priority[selection_temp] != 64) 61 | snapshot.priority[selection_temp]--; 62 | break; 63 | } 64 | sceKernelDelayThread(30000); 65 | } 66 | else if ((ctrl.buttons & SCE_CTRL_LEFT) == SCE_CTRL_LEFT) { 67 | switch (priority_type) { 68 | case PRIORITY_TYPE_USER: 69 | if (snapshot.priority[selection_temp] != 0x10000120) 70 | snapshot.priority[selection_temp]++; 71 | break; 72 | case PRIORITY_TYPE_SYSTEM: 73 | if (snapshot.priority[selection_temp] != 191) 74 | snapshot.priority[selection_temp]++; 75 | break; 76 | } 77 | sceKernelDelayThread(30000); 78 | } 79 | } 80 | 81 | sceKernelExitThread(0); 82 | return 0; 83 | } 84 | 85 | int showMessage(const char *str) 86 | { 87 | SceMsgDialogParam msgParam; 88 | SceMsgDialogUserMessageParam userMsgParam; 89 | 90 | sceMsgDialogParamInit(&msgParam); 91 | msgParam.mode = SCE_MSG_DIALOG_MODE_USER_MSG; 92 | 93 | sceClibMemset(&userMsgParam, 0, sizeof(SceMsgDialogUserMessageParam)); 94 | msgParam.userMsgParam = &userMsgParam; 95 | msgParam.userMsgParam->msg = (SceChar8 *)str; 96 | msgParam.userMsgParam->buttonType = SCE_MSG_DIALOG_BUTTON_TYPE_OK; 97 | 98 | msgParam.commonParam.infobarParam = NULL; 99 | msgParam.commonParam.bgColor = NULL; 100 | msgParam.commonParam.dimmerColor = NULL; 101 | 102 | return sceMsgDialogInit(&msgParam); 103 | } 104 | 105 | int showMessageYesNo(const char *str) 106 | { 107 | SceMsgDialogParam msgParam; 108 | SceMsgDialogUserMessageParam userMsgParam; 109 | 110 | sceMsgDialogParamInit(&msgParam); 111 | msgParam.mode = SCE_MSG_DIALOG_MODE_USER_MSG; 112 | 113 | sceClibMemset(&userMsgParam, 0, sizeof(SceMsgDialogUserMessageParam)); 114 | msgParam.userMsgParam = &userMsgParam; 115 | msgParam.userMsgParam->msg = (SceChar8 *)str; 116 | msgParam.userMsgParam->buttonType = SCE_MSG_DIALOG_BUTTON_TYPE_YESNO; 117 | 118 | msgParam.commonParam.infobarParam = NULL; 119 | msgParam.commonParam.bgColor = NULL; 120 | msgParam.commonParam.dimmerColor = NULL; 121 | 122 | return sceMsgDialogInit(&msgParam); 123 | } 124 | 125 | void cdlgDraw(void) { 126 | vita2d_start_drawing(); 127 | vita2d_clear_screen(); 128 | vita2d_draw_texture(tex_bg, 0, 0); 129 | vita2d_end_drawing(); 130 | vita2d_wait_rendering_done(); 131 | vita2d_common_dialog_update(); 132 | vita2d_end_shfb(); 133 | } 134 | 135 | float priorityToWidth(int priority_mode, int priority) 136 | { 137 | if (priority_mode == PRIORITY_TYPE_SYSTEM) { 138 | return (191 - priority) * 6.299f; 139 | } 140 | else 141 | return (0x10000120 - priority) * 12.5f; 142 | } 143 | 144 | void drawCores(int affinity) 145 | { 146 | vita2d_draw_rectangle(CORE_X, CORE_Y, CORE_SIZE, CORE_SIZE, RGBA8(255, 255, 255, 255)); 147 | vita2d_draw_rectangle(CORE_X + 10, CORE_Y + 10, CORE_SIZE - 20, CORE_SIZE - 20, RGBA8(105, 121, 125, 255)); 148 | if (affinity & SCE_KERNEL_CPU_MASK_USER_0) 149 | vita2d_draw_rectangle(CORE_X + 20, CORE_Y + 20, CORE_SIZE - 40, CORE_SIZE - 40, RGBA8(255, 255, 255, 255)); 150 | else 151 | vita2d_draw_rectangle(CORE_X + 20, CORE_Y + 20, CORE_SIZE - 40, CORE_SIZE - 40, RGBA8(105, 121, 125, 255)); 152 | 153 | vita2d_draw_rectangle(CORE_X + CORE_SIZE + CORE_DELTA, CORE_Y, CORE_SIZE, CORE_SIZE, RGBA8(255, 255, 255, 255)); 154 | vita2d_draw_rectangle(CORE_X + CORE_SIZE + CORE_DELTA + 10, CORE_Y + 10, CORE_SIZE - 20, CORE_SIZE - 20, RGBA8(105, 121, 125, 255)); 155 | if (affinity & SCE_KERNEL_CPU_MASK_USER_1) 156 | vita2d_draw_rectangle(CORE_X + CORE_SIZE + CORE_DELTA + 20, CORE_Y + 20, CORE_SIZE - 40, CORE_SIZE - 40, RGBA8(255, 255, 255, 255)); 157 | else 158 | vita2d_draw_rectangle(CORE_X + CORE_SIZE + CORE_DELTA + 20, CORE_Y + 20, CORE_SIZE - 40, CORE_SIZE - 40, RGBA8(105, 121, 125, 255)); 159 | 160 | vita2d_draw_rectangle(CORE_X + CORE_SIZE * 2 + CORE_DELTA * 2, CORE_Y, CORE_SIZE, CORE_SIZE, RGBA8(255, 255, 255, 255)); 161 | vita2d_draw_rectangle(CORE_X + CORE_SIZE * 2 + CORE_DELTA * 2 + 10, CORE_Y + 10, CORE_SIZE - 20, CORE_SIZE - 20, RGBA8(105, 121, 125, 255)); 162 | if (affinity & SCE_KERNEL_CPU_MASK_USER_2) 163 | vita2d_draw_rectangle(CORE_X + CORE_SIZE * 2 + CORE_DELTA * 2 + 20, CORE_Y + 20, CORE_SIZE - 40, CORE_SIZE - 40, RGBA8(255, 255, 255, 255)); 164 | else 165 | vita2d_draw_rectangle(CORE_X + CORE_SIZE * 2 + CORE_DELTA * 2 + 20, CORE_Y + 20, CORE_SIZE - 40, CORE_SIZE - 40, RGBA8(105, 121, 125, 255)); 166 | 167 | vita2d_draw_rectangle(CORE_X + CORE_SIZE * 3 + CORE_DELTA * 3, CORE_Y, CORE_SIZE, CORE_SIZE, RGBA8(255, 255, 255, 255)); 168 | vita2d_draw_rectangle(CORE_X + CORE_SIZE * 3 + CORE_DELTA * 3 + 10, CORE_Y + 10, CORE_SIZE - 20, CORE_SIZE - 20, RGBA8(105, 121, 125, 255)); 169 | if (affinity & SCE_KERNEL_CPU_MASK_USER_3) 170 | vita2d_draw_rectangle(CORE_X + CORE_SIZE * 3 + CORE_DELTA * 3 + 20, CORE_Y + 20, CORE_SIZE - 40, CORE_SIZE - 40, RGBA8(255, 255, 255, 255)); 171 | else 172 | vita2d_draw_rectangle(CORE_X + CORE_SIZE * 3 + CORE_DELTA * 3 + 20, CORE_Y + 20, CORE_SIZE - 40, CORE_SIZE - 40, RGBA8(105, 121, 125, 255)); 173 | } 174 | 175 | void drawSelector(unsigned int selection) 176 | { 177 | int x = CORE_X + (CORE_SIZE * selection + CORE_DELTA * selection); 178 | vita2d_draw_rectangle(x, CORE_Y - 40, CORE_SIZE, 5, RGBA8(255, 255, 255, 255)); 179 | vita2d_draw_rectangle(x, CORE_Y - 40, 5, 10, RGBA8(255, 255, 255, 255)); 180 | vita2d_draw_rectangle(x + CORE_SIZE - 5, CORE_Y - 40, 5, 10, RGBA8(255, 255, 255, 255)); 181 | 182 | vita2d_draw_rectangle(x, CORE_Y + CORE_SIZE + 40, CORE_SIZE, 5, RGBA8(255, 255, 255, 255)); 183 | vita2d_draw_rectangle(x, CORE_Y + CORE_SIZE + 35, 5, 10, RGBA8(255, 255, 255, 255)); 184 | vita2d_draw_rectangle(x + CORE_SIZE - 5, CORE_Y + CORE_SIZE + 35, 5, 10, RGBA8(255, 255, 255, 255)); 185 | } 186 | 187 | unsigned int drawThreadEdit(unsigned int selection_prev) 188 | { 189 | selection_temp = selection_prev; 190 | SceUID ctrl2_thrd = sceKernelCreateThread("Ctrl2Thread", controls2Thread, 0x10000100, 0x1000, 0, 0, NULL); 191 | 192 | char thread_text[MAX_NAME_LEN + 8]; 193 | sceClibSnprintf(thread_text, MAX_NAME_LEN + 8, "0x%04X %s", snapshot.crc16[selection_prev], snapshot.name[selection_prev]); 194 | 195 | int priority_backup, affinity_backup; 196 | priority_backup = snapshot.priority[selection_prev]; 197 | affinity_backup = snapshot.affinity[selection_prev]; 198 | 199 | unsigned int selection = 0, edit_mode = MODE_AFFINITY; 200 | 201 | while (1) { 202 | vita2d_start_drawing(); 203 | vita2d_clear_screen(); 204 | 205 | vita2d_draw_texture(tex_bg, 0, 0); 206 | vita2d_pvf_draw_text(font, 480 - (vita2d_pvf_text_width(font, 1, thread_text) / 2), TOPBAR_TEXT_Y, RGBA8(255, 255, 255, 255), 1, thread_text); 207 | vita2d_draw_texture(tex_separator, 0, TOPBAR_TEXT_Y + 20); 208 | 209 | vita2d_pvf_draw_text(icon_font, LEFT_MARGIN_MAIN, TOPBAR_TEXT_Y + 70, RGBA8(255, 255, 255, 255), 1, "'"); 210 | vita2d_pvf_draw_text(font, LEFT_MARGIN_MAIN + 40, TOPBAR_TEXT_Y + 70, RGBA8(255, 255, 255, 255), 1, "Edit Affinity"); 211 | vita2d_pvf_draw_text(icon_font, LEFT_MARGIN_MAIN + 180, TOPBAR_TEXT_Y + 70, RGBA8(255, 255, 255, 255), 1, "$"); 212 | vita2d_pvf_draw_text(font, LEFT_MARGIN_MAIN + 220, TOPBAR_TEXT_Y + 70, RGBA8(255, 255, 255, 255), 1, "Edit Priority"); 213 | vita2d_pvf_draw_text(icon_font, LEFT_MARGIN_MAIN + 360, TOPBAR_TEXT_Y + 70, RGBA8(255, 255, 255, 255), 1, "5"); 214 | vita2d_pvf_draw_text(font, LEFT_MARGIN_MAIN + 420, TOPBAR_TEXT_Y + 70, RGBA8(255, 255, 255, 255), 1, "Restore All"); 215 | 216 | switch (edit_mode) { 217 | case MODE_AFFINITY: 218 | 219 | drawCores(snapshot.affinity[selection_prev]); 220 | drawSelector(selection); 221 | 222 | vita2d_pvf_draw_text(font, LEFT_MARGIN + 10, TOPBAR_TEXT_Y + 460, RGBA8(255, 255, 255, 255), 1, "*If no cores set, CPU affinity mask will be automatically assigned by the system"); 223 | 224 | vita2d_end_drawing(); 225 | vita2d_wait_rendering_done(); 226 | vita2d_end_shfb(); 227 | 228 | if (ONPRESS(SCE_CTRL_RIGHT)) { 229 | if (selection != 3) 230 | selection++; 231 | } 232 | else if (ONPRESS(SCE_CTRL_LEFT)) { 233 | if (selection != 0) 234 | selection--; 235 | } 236 | else if (ONPRESS(SCE_CTRL_CROSS)) { 237 | switch (selection) { 238 | case 0: 239 | sceKernelAtomicXorAndGet32(&snapshot.affinity[selection_prev], SCE_KERNEL_CPU_MASK_USER_0); 240 | break; 241 | case 1: 242 | sceKernelAtomicXorAndGet32(&snapshot.affinity[selection_prev], SCE_KERNEL_CPU_MASK_USER_1); 243 | break; 244 | case 2: 245 | sceKernelAtomicXorAndGet32(&snapshot.affinity[selection_prev], SCE_KERNEL_CPU_MASK_USER_2); 246 | break; 247 | case 3: 248 | sceKernelAtomicXorAndGet32(&snapshot.affinity[selection_prev], SCE_KERNEL_CPU_MASK_USER_3); 249 | break; 250 | } 251 | } 252 | 253 | break; 254 | case MODE_PRIORITY: 255 | 256 | if (snapshot.priority[selection_prev] > SCE_KERNEL_COMMON_QUEUE_LOWEST_PRIORITY) 257 | priority_type = PRIORITY_TYPE_USER; 258 | else 259 | priority_type = PRIORITY_TYPE_SYSTEM; 260 | 261 | vita2d_draw_rectangle(80, TOPBAR_TEXT_Y + 220, 800, 10, RGBA8(54, 59, 61, 255)); 262 | vita2d_draw_rectangle(80, TOPBAR_TEXT_Y + 220, priorityToWidth(priority_type, snapshot.priority[selection_prev]), 10, RGBA8(255, 255, 255, 255)); 263 | 264 | if (priority_type == PRIORITY_TYPE_SYSTEM) { 265 | vita2d_pvf_draw_text(icon_font, LEFT_MARGIN + 10, TOPBAR_TEXT_Y + 120, RGBA8(255, 255, 255, 255), 1, "&"); 266 | vita2d_pvf_draw_text(font, LEFT_MARGIN + 50, TOPBAR_TEXT_Y + 120, RGBA8(255, 255, 255, 255), 1, "Priority mode: [System]"); 267 | vita2d_pvf_draw_textf(font, LEFT_MARGIN + 10, TOPBAR_TEXT_Y + 170, RGBA8(255, 255, 255, 255), 1, "Current priority: %d", snapshot.priority[selection_prev]); 268 | vita2d_draw_rectangle(80, TOPBAR_TEXT_Y + 230, 3, 10, RGBA8(0, 0, 255, 255)); 269 | vita2d_draw_rectangle(877, TOPBAR_TEXT_Y + 230, 3, 10, RGBA8(255, 0, 0, 255)); 270 | vita2d_draw_rectangle(480, TOPBAR_TEXT_Y + 230, 3, 10, RGBA8(0, 255, 0, 255)); 271 | vita2d_draw_rectangle(474, TOPBAR_TEXT_Y + 230, 3, 10, RGBA8(255, 255, 0, 255)); 272 | vita2d_draw_rectangle(LEFT_MARGIN + 10, TOPBAR_TEXT_Y + 288, 10, 10, RGBA8(0, 0, 255, 255)); 273 | vita2d_pvf_draw_text(font, LEFT_MARGIN + 30, TOPBAR_TEXT_Y + 300, RGBA8(255, 255, 255, 255), 1, "SCE_KERNEL_COMMON_QUEUE_LOWEST_PRIORITY (191)"); 274 | vita2d_draw_rectangle(LEFT_MARGIN + 10, TOPBAR_TEXT_Y + 328, 10, 10, RGBA8(255, 255, 0, 255)); 275 | vita2d_pvf_draw_text(font, LEFT_MARGIN + 30, TOPBAR_TEXT_Y + 340, RGBA8(255, 255, 255, 255), 1, "SCE_KERNEL_COMMON_QUEUE_HIGHEST_PRIORITY (128)"); 276 | vita2d_draw_rectangle(LEFT_MARGIN + 10, TOPBAR_TEXT_Y + 368, 10, 10, RGBA8(0, 255, 0, 255)); 277 | vita2d_pvf_draw_text(font, LEFT_MARGIN + 30, TOPBAR_TEXT_Y + 380, RGBA8(255, 255, 255, 255), 1, "SCE_KERNEL_INDIVIDUAL_QUEUE_LOWEST_PRIORITY (127)"); 278 | vita2d_draw_rectangle(LEFT_MARGIN + 10, TOPBAR_TEXT_Y + 408, 10, 10, RGBA8(255, 0, 0, 255)); 279 | vita2d_pvf_draw_text(font, LEFT_MARGIN + 30, TOPBAR_TEXT_Y + 420, RGBA8(255, 255, 255, 255), 1, "SCE_KERNEL_INDIVIDUAL_QUEUE_HIGHEST_PRIORITY (64)"); 280 | } 281 | else { 282 | vita2d_pvf_draw_text(icon_font, LEFT_MARGIN + 10, TOPBAR_TEXT_Y + 120, RGBA8(255, 255, 255, 255), 1, "&"); 283 | vita2d_pvf_draw_text(font, LEFT_MARGIN + 50, TOPBAR_TEXT_Y + 120, RGBA8(255, 255, 255, 255), 1, "Priority mode: [User]"); 284 | vita2d_pvf_draw_textf(font, LEFT_MARGIN + 10, TOPBAR_TEXT_Y + 170, RGBA8(255, 255, 255, 255), 1, "Current priority: %d", snapshot.priority[selection_prev] - 0x100000A0); 285 | vita2d_draw_rectangle(80, TOPBAR_TEXT_Y + 230, 3, 10, RGBA8(0, 0, 255, 255)); 286 | vita2d_draw_rectangle(877, TOPBAR_TEXT_Y + 230, 3, 10, RGBA8(255, 0, 0, 255)); 287 | vita2d_draw_rectangle(LEFT_MARGIN + 10, TOPBAR_TEXT_Y + 288, 10, 10, RGBA8(0, 0, 255, 255)); 288 | vita2d_pvf_draw_text(font, LEFT_MARGIN + 30, TOPBAR_TEXT_Y + 300, RGBA8(255, 255, 255, 255), 1, "SCE_KERNEL_INDIVIDUAL_QUEUE_LOWEST_PRIORITY (127)"); 289 | vita2d_draw_rectangle(LEFT_MARGIN + 10, TOPBAR_TEXT_Y + 328, 10, 10, RGBA8(255, 0, 0, 255)); 290 | vita2d_pvf_draw_text(font, LEFT_MARGIN + 30, TOPBAR_TEXT_Y + 340, RGBA8(255, 255, 255, 255), 1, "SCE_KERNEL_INDIVIDUAL_QUEUE_HIGHEST_PRIORITY (64)"); 291 | } 292 | 293 | vita2d_end_drawing(); 294 | vita2d_wait_rendering_done(); 295 | vita2d_end_shfb(); 296 | 297 | if (ONPRESS(SCE_CTRL_RIGHT)) { 298 | sceKernelStartThread(ctrl2_thrd, 0, NULL); 299 | switch (priority_type) { 300 | case PRIORITY_TYPE_USER: 301 | if (snapshot.priority[selection_prev] != 0x100000E0) 302 | snapshot.priority[selection_prev]--; 303 | break; 304 | case PRIORITY_TYPE_SYSTEM: 305 | if (snapshot.priority[selection_prev] != 64) 306 | snapshot.priority[selection_prev]--; 307 | break; 308 | } 309 | } 310 | else if (ONPRESS(SCE_CTRL_LEFT)) { 311 | sceKernelStartThread(ctrl2_thrd, 0, NULL); 312 | switch (priority_type) { 313 | case PRIORITY_TYPE_USER: 314 | if (snapshot.priority[selection_prev] != 0x10000120) 315 | snapshot.priority[selection_prev]++; 316 | break; 317 | case PRIORITY_TYPE_SYSTEM: 318 | if (snapshot.priority[selection_prev] != 191) 319 | snapshot.priority[selection_prev]++; 320 | break; 321 | } 322 | } 323 | else if (ONPRESS(SCE_CTRL_CROSS)) { 324 | if (snapshot.priority[selection_prev] > SCE_KERNEL_COMMON_QUEUE_LOWEST_PRIORITY) 325 | snapshot.priority[selection_prev] = 96; 326 | else 327 | snapshot.priority[selection_prev] = SCE_KERNEL_DEFAULT_PRIORITY; 328 | } 329 | 330 | break; 331 | } 332 | 333 | if (ONPRESS(SCE_CTRL_CIRCLE)) { 334 | break; 335 | } 336 | else if (ONPRESS(SCE_CTRL_SQUARE)) { 337 | edit_mode = MODE_AFFINITY; 338 | } 339 | else if (ONPRESS(SCE_CTRL_TRIANGLE)) { 340 | edit_mode = MODE_PRIORITY; 341 | } 342 | else if (ONPRESS(SCE_CTRL_START)) { 343 | snapshot.priority[selection_prev] = priority_backup; 344 | snapshot.affinity[selection_prev] = affinity_backup; 345 | } 346 | } 347 | 348 | if ((snapshot.priority[selection_prev] != priority_backup) || (snapshot.affinity[selection_prev] != affinity_backup)) 349 | snapshot_changed = SCE_TRUE; 350 | 351 | return selection_snapshot; 352 | } 353 | 354 | unsigned int drawThreadSelect(unsigned int selection_prev) 355 | { 356 | selection_snapshot = selection_prev; 357 | unsigned int total_pages = 0; 358 | char snapshot_path[46]; 359 | 360 | if (!snapshot_loaded) { 361 | sceClibMemset(&snapshot, 0, sizeof(ThreadOptimizerSnapshot)); 362 | 363 | sceClibMemset(&snapshot_path, 0, 46); 364 | sceClibSnprintf(snapshot_path, 46, "ux0:data/ThreadOptimizer/%s/config.dat", preset_dir[selection_prev]); 365 | 366 | SceUID fd = sceIoOpen(snapshot_path, SCE_O_RDONLY, 0777); 367 | sceIoRead(fd, &snapshot, sizeof(ThreadOptimizerSnapshot)); 368 | sceIoClose(fd); 369 | 370 | snapshot_loaded = SCE_TRUE; 371 | } 372 | 373 | float total_pages_temp = (float)snapshot.thread_count / (float)TOTAL_PER_PAGE; 374 | total_pages = ceilf(total_pages_temp); 375 | total_pages--; 376 | 377 | vita2d_sys_widget* widget[MAX_THREADS]; 378 | 379 | int coordinate_mltp = 0; 380 | char thread_text[MAX_THREADS][MAX_NAME_LEN + 8]; 381 | 382 | for (int i = 0; i < snapshot.thread_count; i++) { 383 | sceClibSnprintf(thread_text[i], MAX_NAME_LEN + 8, "0x%04X %s", snapshot.crc16[i], snapshot.name[i]); 384 | widget[i] = vita2d_sys_create_widget_button(tex_button, font, 0, (TOPBAR_TEXT_Y + 22) + WIDGET_BUTTON_HEIGHT * coordinate_mltp, WIDGET_BUTTON_TEXT_DX, WIDGET_BUTTON_TEXT_DY, thread_text[i]); 385 | coordinate_mltp++; 386 | if (coordinate_mltp == TOTAL_PER_PAGE) 387 | coordinate_mltp = 0; 388 | } 389 | 390 | unsigned int selection = selection_thread, page = selection_page, page_modifier = selection_page_mod; 391 | 392 | if (snapshot.thread_count == 0) { 393 | showMessageYesNo("Error: There are no threads in this snapshot.\n\nDo you want to delete it?"); 394 | while (sceMsgDialogGetStatus() != 2) 395 | cdlgDraw(); 396 | SceMsgDialogResult result; 397 | sceMsgDialogGetResult(&result); 398 | sceMsgDialogTerm(); 399 | if (result.buttonId == SCE_MSG_DIALOG_BUTTON_ID_YES) { 400 | char snapshot_dir_path[35]; 401 | sceClibMemset(&snapshot_dir_path, 0, 35); 402 | sceClibSnprintf(snapshot_dir_path, 35, "ux0:data/ThreadOptimizer/%s/config.dat", preset_dir[selection_prev]); 403 | sceIoRemove(snapshot_path); 404 | sceIoRmdir(snapshot_dir_path); 405 | } 406 | selection = BACK_MAGIC; 407 | goto threadSelect_ret; 408 | } 409 | 410 | while (1) { 411 | vita2d_start_drawing(); 412 | vita2d_clear_screen(); 413 | 414 | vita2d_draw_texture(tex_bg, 0, 0); 415 | vita2d_pvf_draw_text(font, 480 - (vita2d_pvf_text_width(font, 1, "Thread Selection") / 2), TOPBAR_TEXT_Y, RGBA8(255, 255, 255, 255), 1, "Thread Selection"); 416 | if (page != 0) 417 | vita2d_pvf_draw_text(icon_font, LEFT_MARGIN, TOPBAR_TEXT_Y, RGBA8(255, 255, 255, 255), 1, "0"); 418 | if (page != total_pages) 419 | vita2d_pvf_draw_text(icon_font, RIGHT_MARGIN, TOPBAR_TEXT_Y, RGBA8(255, 255, 255, 255), 1, "1"); 420 | vita2d_pvf_draw_text(icon_font, LEFT_MARGIN + 60, TOPBAR_TEXT_Y, RGBA8(255, 255, 255, 255), 1, "'"); 421 | vita2d_pvf_draw_text(font, LEFT_MARGIN + 60, TOPBAR_TEXT_Y, RGBA8(255, 255, 255, 255), 1, " Save"); 422 | vita2d_pvf_draw_text(icon_font, RIGHT_MARGIN - 40, TOPBAR_TEXT_Y, RGBA8(255, 255, 255, 255), 1, "$"); 423 | vita2d_pvf_draw_text(font, RIGHT_MARGIN - 150, TOPBAR_TEXT_Y, RGBA8(255, 255, 255, 255), 1, " Delete"); 424 | vita2d_draw_texture(tex_separator, 0, TOPBAR_TEXT_Y + 20); 425 | 426 | for (int i = 0; i < TOTAL_PER_PAGE && ((i + page_modifier) < snapshot.thread_count); i++) { 427 | if (i == selection) 428 | vita2d_sys_widget_set_highlight(widget[i + page_modifier], SCE_TRUE); 429 | else 430 | vita2d_sys_widget_set_highlight(widget[i + page_modifier], SCE_FALSE); 431 | vita2d_sys_draw_widget(widget[i + page_modifier]); 432 | } 433 | 434 | vita2d_end_drawing(); 435 | vita2d_wait_rendering_done(); 436 | if (sceMsgDialogGetStatus() != 2 && !cdlg_terminated) 437 | vita2d_common_dialog_update(); 438 | else if (!cdlg_terminated) { 439 | sceMsgDialogTerm(); 440 | cdlg_terminated = SCE_TRUE; 441 | } 442 | vita2d_end_shfb(); 443 | 444 | if (cdlg_delete_request) { 445 | SceMsgDialogResult result; 446 | sceMsgDialogGetResult(&result); 447 | if (result.buttonId == SCE_MSG_DIALOG_BUTTON_ID_YES) { 448 | sceMsgDialogTerm(); 449 | cdlg_terminated = SCE_TRUE; 450 | cdlg_delete_request = SCE_FALSE; 451 | char snapshot_dir_path[35]; 452 | sceClibMemset(&snapshot_dir_path, 0, 35); 453 | sceClibSnprintf(snapshot_dir_path, 35, "ux0:data/ThreadOptimizer/%s/config.dat", preset_dir[selection_prev]); 454 | sceIoRemove(snapshot_path); 455 | sceIoRmdir(snapshot_dir_path); 456 | selection = BACK_MAGIC; 457 | break; 458 | } 459 | else if (result.buttonId == SCE_MSG_DIALOG_BUTTON_ID_NO) { 460 | sceMsgDialogTerm(); 461 | cdlg_terminated = SCE_TRUE; 462 | cdlg_delete_request = SCE_FALSE; 463 | } 464 | } 465 | 466 | if (ONPRESS(SCE_CTRL_DOWN)) { 467 | if ((selection != (TOTAL_PER_PAGE - 1)) && ((selection + page_modifier) != (snapshot.thread_count - 1))) { 468 | vita2d_sys_widget_set_highlight_max(); 469 | selection++; 470 | } 471 | } 472 | else if (ONPRESS(SCE_CTRL_UP)) { 473 | if (selection != 0) { 474 | vita2d_sys_widget_set_highlight_max(); 475 | selection--; 476 | } 477 | } 478 | else if (ONPRESS(SCE_CTRL_R2)) { 479 | if (page != total_pages) { 480 | vita2d_sys_widget_set_highlight_max(); 481 | page_modifier += TOTAL_PER_PAGE; 482 | selection = 0; 483 | page++; 484 | } 485 | } 486 | else if (ONPRESS(SCE_CTRL_L2)) { 487 | if (page != 0) { 488 | vita2d_sys_widget_set_highlight_max(); 489 | page_modifier -= TOTAL_PER_PAGE; 490 | selection = 0; 491 | page--; 492 | } 493 | } 494 | else if (ONPRESS(SCE_CTRL_CROSS)) { 495 | for (int i = 0; i < snapshot.thread_count; i++) 496 | vita2d_sys_delete_widget(widget[i]); 497 | break; 498 | } 499 | else if (ONPRESS(SCE_CTRL_CIRCLE)) { 500 | for (int i = 0; i < snapshot.thread_count; i++) 501 | vita2d_sys_delete_widget(widget[i]); 502 | if (snapshot_changed) { 503 | showMessageYesNo("Do you want to save changes?"); 504 | while (sceMsgDialogGetStatus() != 2) 505 | cdlgDraw(); 506 | SceMsgDialogResult result; 507 | sceMsgDialogGetResult(&result); 508 | sceMsgDialogTerm(); 509 | if (result.buttonId == SCE_MSG_DIALOG_BUTTON_ID_YES) { 510 | SceUID fd = sceIoOpen(snapshot_path, SCE_O_WRONLY | SCE_O_CREAT, 0777); 511 | sceIoWrite(fd, &snapshot, sizeof(ThreadOptimizerSnapshot)); 512 | sceIoClose(fd); 513 | } 514 | snapshot_changed = SCE_FALSE; 515 | } 516 | selection = BACK_MAGIC; 517 | break; 518 | } 519 | else if (ONPRESS(SCE_CTRL_SQUARE)) { 520 | SceUID fd = sceIoOpen(snapshot_path, SCE_O_WRONLY | SCE_O_CREAT, 0777); 521 | sceIoWrite(fd, &snapshot, sizeof(ThreadOptimizerSnapshot)); 522 | sceIoClose(fd); 523 | snapshot_changed = SCE_FALSE; 524 | showMessage("Snapshot has been saved."); 525 | cdlg_terminated = SCE_FALSE; 526 | } 527 | else if (ONPRESS(SCE_CTRL_TRIANGLE)) { 528 | showMessageYesNo("Do you want to delete this snapshot?"); 529 | cdlg_delete_request = SCE_TRUE; 530 | cdlg_terminated = SCE_FALSE; 531 | } 532 | } 533 | 534 | threadSelect_ret: 535 | 536 | if (selection == BACK_MAGIC) 537 | return BACK_MAGIC; 538 | else { 539 | selection_page = page; 540 | selection_page_mod = page_modifier; 541 | selection_thread = selection; 542 | return selection + page_modifier; 543 | } 544 | } 545 | 546 | unsigned int drawMainSelect(void) 547 | { 548 | selection_page = 0; 549 | selection_page_mod = 0; 550 | selection_thread = 0; 551 | snapshot_loaded = SCE_FALSE; 552 | 553 | unsigned int preset_count = 0, total_pages = 0; 554 | 555 | SceUID dfd = sceIoDopen("ux0:data/ThreadOptimizer"); 556 | if (dfd < 0) { 557 | sceIoMkdir("ux0:data/ThreadOptimizer", 0777); 558 | dfd = sceIoDopen("ux0:data/ThreadOptimizer"); 559 | } 560 | 561 | SceIoDirent dirent; 562 | sceClibMemset(&preset_dir, 0, MAX_PRESET * 10); 563 | 564 | while (sceIoDread(dfd, &dirent) != 0) { 565 | sceClibStrncpy(preset_dir[preset_count], dirent.d_name, 10); 566 | preset_count++; 567 | } 568 | 569 | float total_pages_temp = (float)preset_count / (float)TOTAL_PER_PAGE; 570 | total_pages = ceilf(total_pages_temp); 571 | total_pages--; 572 | 573 | vita2d_sys_widget* widget[MAX_PRESET]; 574 | 575 | int coordinate_mltp = 0; 576 | 577 | for (int i = 0; i < preset_count; i++) { 578 | widget[i] = vita2d_sys_create_widget_button(tex_button, font, 0, (TOPBAR_TEXT_Y + 22) + WIDGET_BUTTON_HEIGHT * coordinate_mltp, WIDGET_BUTTON_TEXT_DX, WIDGET_BUTTON_TEXT_DY, preset_dir[i]); 579 | coordinate_mltp++; 580 | if (coordinate_mltp == TOTAL_PER_PAGE) 581 | coordinate_mltp = 0; 582 | } 583 | 584 | unsigned int selection = selection_m, total_count = 0, page = selection_page_m, page_modifier = selection_page_mod_m; 585 | 586 | if (preset_count == 0) { 587 | showMessage("Error: There are no saved snapshots."); 588 | while (sceMsgDialogGetStatus() != 2) 589 | cdlgDraw(); 590 | sceMsgDialogTerm(); 591 | sceAppMgrDestroyAppByAppId(-2); 592 | } 593 | 594 | while (1) { 595 | vita2d_start_drawing(); 596 | vita2d_clear_screen(); 597 | 598 | vita2d_draw_texture(tex_bg, 0, 0); 599 | vita2d_pvf_draw_text(font, 480 - (vita2d_pvf_text_width(font, 1, "Snapshot Selection") / 2), TOPBAR_TEXT_Y, RGBA8(255, 255, 255, 255), 1, "Snapshot Selection"); 600 | if (page != 0) 601 | vita2d_pvf_draw_text(icon_font, LEFT_MARGIN, TOPBAR_TEXT_Y, RGBA8(255, 255, 255, 255), 1, "0"); 602 | if (page != total_pages) 603 | vita2d_pvf_draw_text(icon_font, RIGHT_MARGIN, TOPBAR_TEXT_Y, RGBA8(255, 255, 255, 255), 1, "1"); 604 | vita2d_draw_texture(tex_separator, 0, TOPBAR_TEXT_Y + 20); 605 | 606 | for (int i = 0; i < TOTAL_PER_PAGE && ((i + page_modifier) < preset_count); i++) { 607 | if (i == selection) { 608 | vita2d_sys_widget_set_highlight(widget[i + page_modifier], SCE_TRUE); 609 | } 610 | else 611 | vita2d_sys_widget_set_highlight(widget[i + page_modifier], SCE_FALSE); 612 | vita2d_sys_draw_widget(widget[i + page_modifier]); 613 | } 614 | 615 | vita2d_end_drawing(); 616 | vita2d_wait_rendering_done(); 617 | vita2d_end_shfb(); 618 | 619 | if (ONPRESS(SCE_CTRL_DOWN)) { 620 | if ((selection != (TOTAL_PER_PAGE - 1)) && ((selection + page_modifier) != (preset_count - 1))) { 621 | vita2d_sys_widget_set_highlight_max(); 622 | selection++; 623 | } 624 | } 625 | else if (ONPRESS(SCE_CTRL_UP)) { 626 | if (selection != 0) { 627 | vita2d_sys_widget_set_highlight_max(); 628 | selection--; 629 | } 630 | } 631 | else if (ONPRESS(SCE_CTRL_R2)) { 632 | if (page != total_pages) { 633 | vita2d_sys_widget_set_highlight_max(); 634 | page_modifier += TOTAL_PER_PAGE; 635 | selection = 0; 636 | page++; 637 | } 638 | } 639 | else if (ONPRESS(SCE_CTRL_L2)) { 640 | if (page != 0) { 641 | vita2d_sys_widget_set_highlight_max(); 642 | page_modifier -= TOTAL_PER_PAGE; 643 | selection = 0; 644 | page--; 645 | } 646 | } 647 | else if (ONPRESS(SCE_CTRL_CROSS)) { 648 | for (int i = 0; i < preset_count; i++) 649 | vita2d_sys_delete_widget(widget[i]); 650 | break; 651 | } 652 | } 653 | 654 | selection_page_m = page; 655 | selection_page_mod_m = page_modifier; 656 | selection_m = selection; 657 | 658 | return selection + page_modifier; 659 | } 660 | 661 | void _start(unsigned int args, void *argp) 662 | { 663 | ScePVoid clibm_base; 664 | SceUID clib_heap = sceKernelAllocMemBlock("ClibHeap", SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE, CLIB_HEAP_SIZE, NULL); 665 | sceKernelGetMemBlockBase(clib_heap, &clibm_base); 666 | g_mspace = sceClibMspaceCreate(clibm_base, CLIB_HEAP_SIZE); 667 | 668 | vita2d_clib_pass_mspace(g_mspace); 669 | vita2d_init(); 670 | 671 | vita2d_set_vblank_wait(1); 672 | vita2d_set_clear_color(RGBA8(105, 121, 125, 255)); 673 | 674 | SceInt32 ret; 675 | SceUInt64 unk; 676 | 677 | vita2d_JPEG_decoder_initialize(); 678 | tex_bg = vita2d_load_JPEG_file("app0:tex/bg.jpg", 0, 0, 0, 0, 0); 679 | vita2d_JPEG_decoder_finish(); 680 | tex_separator = vita2d_load_GXT_file("app0:tex/texture.gxt", 0, 0); 681 | tex_button = vita2d_load_additional_GXT(tex_separator, 1); 682 | 683 | SceUID modid = _vshKernelSearchModuleByName("CapUnlocker", &unk); 684 | if (modid < 0) { 685 | showMessage("Error: CapUnlocker plugin not found.\n\nPlease install it and try again."); 686 | while (sceMsgDialogGetStatus() != 2) 687 | cdlgDraw(); 688 | sceMsgDialogTerm(); 689 | sceAppMgrDestroyAppByAppId(-2); 690 | } 691 | modid = _vshKernelSearchModuleByName("ioplus", &unk); 692 | if (modid < 0) { 693 | showMessage("Error: ioPlus plugin not found.\n\nPlease install it and try again."); 694 | while (sceMsgDialogGetStatus() != 2) 695 | cdlgDraw(); 696 | sceMsgDialogTerm(); 697 | sceAppMgrDestroyAppByAppId(-2); 698 | } 699 | 700 | vita2d_system_pvf_config configs[] = { 701 | {SCE_PVF_LANGUAGE_LATIN, SCE_PVF_FAMILY_SANSERIF, SCE_PVF_STYLE_REGULAR, NULL}, 702 | }; 703 | 704 | font = vita2d_load_system_pvf(1, configs, 14, 14); 705 | icon_font = vita2d_load_custom_pvf("sa0:data/font/pvf/psexchar.pvf", 14, 14); 706 | 707 | SceUID ctrl_thrd = sceKernelCreateThread("CtrlThread", controlsThread, 0x10000100, 0x1000, 0, 0, NULL); 708 | sceKernelStartThread(ctrl_thrd, 0, NULL); 709 | 710 | unsigned int selection; 711 | 712 | repeat_0: 713 | 714 | selection = 0; 715 | selection = drawMainSelect(); 716 | 717 | repeat_1: 718 | 719 | selection = drawThreadSelect(selection); 720 | 721 | if (selection == BACK_MAGIC) 722 | goto repeat_0; 723 | 724 | selection = drawThreadEdit(selection); 725 | goto repeat_1; 726 | 727 | sceKernelExitProcess(0); 728 | } 729 | 730 | -------------------------------------------------------------------------------- /plugin/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | 3 | if(NOT DEFINED CMAKE_TOOLCHAIN_FILE) 4 | if(DEFINED ENV{DOLCESDK}) 5 | set(CMAKE_TOOLCHAIN_FILE "$ENV{DOLCESDK}/share/dolce.toolchain.cmake" CACHE PATH "toolchain file") 6 | else() 7 | message(FATAL_ERROR "Please define DOLCESDK to point to your SDK path!") 8 | endif() 9 | endif() 10 | 11 | project(ThreadOptimizer) 12 | include("${DOLCESDK}/share/dolce.cmake" REQUIRED) 13 | dolce_gen_libs(SceShellSvc_stubs 14 | SceShellSvc.yml 15 | LIB SceShellSvc_stub_weak) 16 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wl,-q -Wall -O3 -nostdlib") 17 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti -fno-exceptions") 18 | 19 | include_directories( 20 | ) 21 | 22 | link_directories( 23 | ${CMAKE_CURRENT_BINARY_DIR} 24 | ) 25 | 26 | add_executable(${PROJECT_NAME} 27 | main.c 28 | ) 29 | 30 | target_link_libraries(${PROJECT_NAME} 31 | taihen_stub 32 | SceLibKernel_stub 33 | SceIofilemgr_stub 34 | SceAppMgr_stub 35 | SceSysmodule_stub 36 | SceProcessmgr_stub 37 | SceKernelThreadMgr_stub 38 | SceNotificationutil_stub 39 | SceSysmem_stub 40 | SceCtrl_stub 41 | SceShellSvc_stub_weak 42 | ) 43 | 44 | set_target_properties(${PROJECT_NAME} 45 | PROPERTIES LINK_FLAGS "-nostdlib" 46 | ) 47 | 48 | dolce_create_self(${PROJECT_NAME}.suprx ${PROJECT_NAME} 49 | CONFIG ${CMAKE_SOURCE_DIR}/ThreadOptimizer.yml 50 | ) -------------------------------------------------------------------------------- /plugin/SceShellSvc.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | firmware: 3.60 3 | modules: 4 | SceShellSvc: 5 | nid: 0x36E557FA 6 | libraries: 7 | SceShellSvc: 8 | kernel: false 9 | nid: 0x773242C7 10 | functions: 11 | SceShellSvc_B31E7F1C: 0xB31E7F1C 12 | SceShellSvc_A0B067AC: 0xA0B067AC 13 | -------------------------------------------------------------------------------- /plugin/ThreadOptimizer.yml: -------------------------------------------------------------------------------- 1 | ThreadOptimizer: 2 | attributes: 0 3 | version: 4 | major: 0 5 | minor: 1 6 | main: 7 | start: module_start 8 | stop: module_stop 9 | -------------------------------------------------------------------------------- /plugin/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Graphene 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "main.h" 15 | 16 | static tai_hook_ref_t g_hook_ref[5]; 17 | static SceUID g_hook[5]; 18 | 19 | static char g_titleid[10]; 20 | static char g_snapshot_path[46]; 21 | static SceBool snapshot_present = SCE_FALSE; 22 | static unsigned int thread_count = 0, frames = 0; 23 | static SceCtrlData data; 24 | 25 | static ThreadOptimizerSnapshot snapshot; 26 | 27 | int sceCtrlPeekBufferPositive2(int port, SceCtrlData *pad_data, int count); 28 | 29 | /* Notification */ 30 | 31 | void notify(char* str1, const char* str2) 32 | { 33 | while (*str2) 34 | { 35 | *str1 = *str2; 36 | str1++; 37 | *str1 = '\0'; 38 | str1++; 39 | str2++; 40 | } 41 | } 42 | 43 | void sendNotification(char* buffer, int size) 44 | { 45 | SceShellSvcCustomParams params; 46 | sceClibMemset(¶ms, 0, sizeof(SceShellSvcCustomParams)); 47 | 48 | SceByte bg = 0; 49 | int unk = -1; 50 | 51 | int buf[2]; 52 | SceShellSvc_A0B067AC(&buf, 1); 53 | 54 | params.params1 = &bg; 55 | params.params1Size = 1; 56 | params.params2 = buffer; 57 | params.params2Size = size; 58 | 59 | void* tptr = SceShellSvc_B31E7F1C(); 60 | 61 | ((SceShellSvcTable *)(*(uint32_t *)tptr))->sceShellSvcAsyncMethod(tptr, 0x70007, ¶ms, 2, &unk, &buf); 62 | } 63 | 64 | /* CRC16 */ 65 | 66 | unsigned short crc16(const unsigned char* data_p, unsigned char length) { 67 | unsigned char x; 68 | unsigned short crc = 0xFFFF; 69 | 70 | while (length--) { 71 | x = crc >> 8 ^ *data_p++; 72 | x ^= x >> 4; 73 | crc = (crc << 8) ^ ((unsigned short)(x << 12)) ^ ((unsigned short)(x << 5)) ^ ((unsigned short)x); 74 | } 75 | return crc; 76 | } 77 | 78 | /* Threads */ 79 | 80 | SceUID sceKernelCreateThreadForUser_patched_read(const char* name, 81 | SceKernelThreadEntry entry, 82 | int initPriority, 83 | int stackSize, 84 | SceUInt attr, 85 | int cpuAffinityMask, 86 | const SceKernelThreadOptParam* option) 87 | { 88 | unsigned int entry_number = 0; 89 | int new_priority = initPriority; 90 | int new_affinity = cpuAffinityMask; 91 | 92 | /* Calculate crc16 */ 93 | 94 | unsigned short crc16_res = 0; 95 | unsigned char buffer[49]; 96 | sceClibMemset(&buffer, 0, 49); 97 | 98 | sceClibMemcpy(&buffer, name, sceClibStrnlen(name, MAX_NAME_LEN)); 99 | sceClibMemcpy(&buffer[37], &entry, 4); 100 | sceClibMemcpy(&buffer[41], &initPriority, 4); 101 | sceClibMemcpy(&buffer[45], &cpuAffinityMask, 4); 102 | crc16_res = crc16(buffer, 49); 103 | DEBUG_PRINT("CRC16: 0x%x\n", crc16_res); 104 | 105 | for (; entry_number < snapshot.thread_count; entry_number++) { 106 | if (crc16_res == snapshot.crc16[entry_number]) { 107 | DEBUG_PRINT("CRC16: SAVED DETECTED\n"); 108 | break; 109 | } 110 | } 111 | 112 | new_priority = snapshot.priority[entry_number]; 113 | new_affinity = snapshot.affinity[entry_number]; 114 | 115 | DEBUG_PRINT("----- NEW THREAD: CHANGED -----\n"); 116 | DEBUG_PRINT("ENTRY: 0x%x\n", entry); 117 | DEBUG_PRINT("NAME: %s\n", name); 118 | DEBUG_PRINT("PRIORITY: 0x%x\n", new_priority); 119 | DEBUG_PRINT("AFFINITY: 0x%x\n", new_affinity); 120 | 121 | thread_count++; 122 | 123 | return TAI_CONTINUE(SceUID, g_hook_ref[0], name, entry, new_priority, stackSize, attr, new_affinity, option); 124 | } 125 | 126 | SceUID sceKernelCreateThreadForUser_patched_write(const char* name, 127 | SceKernelThreadEntry entry, 128 | int initPriority, 129 | int stackSize, 130 | SceUInt attr, 131 | int cpuAffinityMask, 132 | const SceKernelThreadOptParam* option) 133 | { 134 | 135 | /* Calculate crc16 */ 136 | 137 | unsigned short crc16_res = 0; 138 | unsigned char buffer[49]; 139 | sceClibMemset(&buffer, 0, 49); 140 | 141 | sceClibMemcpy(&buffer, name, sceClibStrnlen(name, MAX_NAME_LEN)); 142 | sceClibMemcpy(&buffer[37], &entry, 4); 143 | sceClibMemcpy(&buffer[41], &initPriority, 4); 144 | sceClibMemcpy(&buffer[45], &cpuAffinityMask, 4); 145 | crc16_res = crc16(buffer, 49); 146 | DEBUG_PRINT("CRC16: 0x%x\n", crc16_res); 147 | 148 | for (int i = 0; i < thread_count; i++) { 149 | if (crc16_res == snapshot.crc16[i]) { 150 | DEBUG_PRINT("THREAD ALREADY SAVED\n"); 151 | return TAI_CONTINUE(SceUID, g_hook_ref[0], name, entry, initPriority, stackSize, attr, cpuAffinityMask, option); 152 | } 153 | } 154 | 155 | snapshot.crc16[thread_count] = crc16_res; 156 | snapshot.thread_count = thread_count; 157 | snapshot.entry[thread_count] = entry; 158 | sceClibStrncpy(snapshot.name[thread_count], name, MAX_NAME_LEN); 159 | snapshot.priority[thread_count] = initPriority; 160 | snapshot.affinity[thread_count] = cpuAffinityMask; 161 | 162 | DEBUG_PRINT("----- NEW THREAD: SAVED -----\n"); 163 | DEBUG_PRINT("ENTRY: 0x%x\n", snapshot.entry[thread_count]); 164 | DEBUG_PRINT("NAME: %s\n", snapshot.name[thread_count]); 165 | DEBUG_PRINT("PRIORITY: 0x%x\n", snapshot.priority[thread_count]); 166 | DEBUG_PRINT("AFFINITY: 0x%x\n", snapshot.affinity[thread_count]); 167 | 168 | thread_count++; 169 | 170 | return TAI_CONTINUE(SceUID, g_hook_ref[0], name, entry, initPriority, stackSize, attr, cpuAffinityMask, option); 171 | } 172 | 173 | /* Save to snapshot file */ 174 | 175 | int saveToFile(void) 176 | { 177 | char snapshot_dir[35]; 178 | sceClibMemset(&snapshot_dir, 0, 35); 179 | sceClibStrncpy(snapshot_dir, g_snapshot_path, 34); 180 | 181 | sceIoMkdir(snapshot_dir, 0777); 182 | SceUID fd = sceIoOpen(g_snapshot_path, SCE_O_WRONLY | SCE_O_CREAT, 0777); 183 | sceIoWrite(fd, &snapshot, sizeof(ThreadOptimizerSnapshot)); 184 | 185 | return sceIoClose(fd); 186 | } 187 | 188 | /* Delete snapshot file */ 189 | 190 | int deleteFile(void) 191 | { 192 | char snapshot_dir[35]; 193 | sceClibMemset(&snapshot_dir, 0, 35); 194 | sceClibStrncpy(snapshot_dir, g_snapshot_path, 34); 195 | 196 | sceIoRemove(g_snapshot_path); 197 | 198 | return sceIoRmdir(snapshot_dir); 199 | } 200 | 201 | /* Check input */ 202 | 203 | void checkInput(void) 204 | { 205 | sceClibMemset(&data, 0, sizeof(SceCtrlData)); 206 | sceCtrlPeekBufferPositive2(0, &data, 1); 207 | 208 | if (((data.buttons & (SCE_CTRL_R1 | SCE_CTRL_L1 | SCE_CTRL_SQUARE)) == (SCE_CTRL_R1 | SCE_CTRL_L1 | SCE_CTRL_SQUARE)) && !snapshot_present) { 209 | char buffer[60]; 210 | sceClibMemset(&buffer, 0, 60); 211 | notify(buffer, "TO: Snapshot has been saved!"); 212 | snapshot_present = SCE_TRUE; 213 | saveToFile(); 214 | sendNotification(buffer, 60); 215 | } 216 | else if (((data.buttons & (SCE_CTRL_R1 | SCE_CTRL_L1 | SCE_CTRL_TRIANGLE)) == (SCE_CTRL_R1 | SCE_CTRL_L1 | SCE_CTRL_TRIANGLE)) && snapshot_present) { 217 | char buffer[67]; 218 | sceClibMemset(&buffer, 0, 67); 219 | notify(buffer, "TO: Snapshot has been deleted!"); 220 | snapshot_present = SCE_FALSE; 221 | deleteFile(); 222 | sendNotification(buffer, 67); 223 | } 224 | } 225 | 226 | int sceDisplaySetFrameBuf_patched(const SceDisplayFrameBuf* pParam, SceDisplaySetBufSync sync) 227 | { 228 | if (frames == 60) { 229 | frames = 0; 230 | checkInput(); 231 | } 232 | 233 | frames++; 234 | 235 | return TAI_CONTINUE(int, g_hook_ref[1], pParam, sync); 236 | } 237 | 238 | SceUID sceKernelLoadStartModule_patched(const char *path, SceSize args, void *argp, int flags, SceKernelLMOption *option, int* status) 239 | { 240 | int ret = TAI_CONTINUE(SceUID, g_hook_ref[2], path, args, argp, flags, option, status); 241 | 242 | if (!sceClibStrncmp(path, "app0:/Media/Modules/pthread.suprx", 33)) { 243 | /* Thread hooks */ 244 | 245 | if (snapshot_present) { 246 | g_hook[3] = taiHookFunctionImport( 247 | &g_hook_ref[3], 248 | "PTHREAD_PRX", 249 | TAI_ANY_LIBRARY, 250 | 0xC5C11EE7, 251 | sceKernelCreateThreadForUser_patched_read); 252 | } 253 | else { 254 | g_hook[3] = taiHookFunctionImport( 255 | &g_hook_ref[3], 256 | "PTHREAD_PRX", 257 | TAI_ANY_LIBRARY, 258 | 0xC5C11EE7, 259 | sceKernelCreateThreadForUser_patched_write); 260 | } 261 | } 262 | return ret; 263 | } 264 | 265 | void _start() __attribute__((weak, alias("module_start"))); 266 | int module_start(SceSize argc, const void *args) 267 | { 268 | DEBUG_PRINT("ThreadOptimizer INIT\n"); 269 | 270 | sceClibMemset(&g_hook[0], -1, 40); 271 | 272 | SceUID dfd = sceIoDopen("ux0:data/ThreadOptimizer"); 273 | if (dfd < 0) 274 | sceIoMkdir("ux0:data/ThreadOptimizer", 0777); 275 | else 276 | sceIoDclose(dfd); 277 | 278 | sceClibMemset(&snapshot, 0, sizeof(ThreadOptimizerSnapshot)); 279 | 280 | /* Get titleid and set up path */ 281 | 282 | sceClibMemset(&g_titleid, 0, 10); 283 | sceAppMgrAppParamGetString(0, 12, g_titleid, 10); 284 | 285 | sceClibMemset(&g_snapshot_path, 0, 46); 286 | sceClibSnprintf(g_snapshot_path, 46, "ux0:data/ThreadOptimizer/%s/config.dat", g_titleid); 287 | 288 | /* Check for saved snapshot and load it */ 289 | 290 | SceUID fd = 0; 291 | fd = sceIoOpen(g_snapshot_path, SCE_O_RDONLY, 0777); 292 | if (fd >= 0) { 293 | snapshot_present = SCE_TRUE; 294 | sceIoRead(fd, &snapshot, sizeof(ThreadOptimizerSnapshot)); 295 | sceIoClose(fd); 296 | } 297 | else 298 | sceClibStrncpy(snapshot.titleid, g_titleid, 10); 299 | 300 | /* Thread hooks */ 301 | 302 | if (snapshot_present) { 303 | g_hook[0] = taiHookFunctionImport( 304 | &g_hook_ref[0], 305 | TAI_MAIN_MODULE, 306 | TAI_ANY_LIBRARY, 307 | 0xC5C11EE7, 308 | sceKernelCreateThreadForUser_patched_read); 309 | } 310 | else { 311 | g_hook[0] = taiHookFunctionImport( 312 | &g_hook_ref[0], 313 | TAI_MAIN_MODULE, 314 | TAI_ANY_LIBRARY, 315 | 0xC5C11EE7, 316 | sceKernelCreateThreadForUser_patched_write); 317 | } 318 | 319 | /* PTHREAD_PRX (unity games) */ 320 | 321 | g_hook[2] = taiHookFunctionImport( 322 | &g_hook_ref[2], 323 | TAI_MAIN_MODULE, 324 | TAI_ANY_LIBRARY, 325 | 0x2DCC4AFA, 326 | sceKernelLoadStartModule_patched); 327 | 328 | /* SceLibc (??? games) */ 329 | 330 | if (snapshot_present) { 331 | g_hook[4] = taiHookFunctionImport( 332 | &g_hook_ref[4], 333 | "SceLibc", 334 | TAI_ANY_LIBRARY, 335 | 0xC5C11EE7, 336 | sceKernelCreateThreadForUser_patched_read); 337 | } 338 | else { 339 | g_hook[4] = taiHookFunctionImport( 340 | &g_hook_ref[4], 341 | "SceLibc", 342 | TAI_ANY_LIBRARY, 343 | 0xC5C11EE7, 344 | sceKernelCreateThreadForUser_patched_write); 345 | } 346 | 347 | /*g_hook[1] = taiHookFunctionImport( 348 | &g_hook_ref[1], 349 | TAI_MAIN_MODULE, 350 | TAI_ANY_LIBRARY, 351 | 0x1BBDE3D9, 352 | sceKernelDeleteThread_patched); 353 | 354 | g_hook[2] = taiHookFunctionImport( 355 | &g_hook_ref[2], 356 | TAI_MAIN_MODULE, 357 | TAI_ANY_LIBRARY, 358 | 0x1D17DECF, 359 | sceKernelExitDeleteThread_patched);*/ 360 | 361 | /* Control hooks */ 362 | 363 | if (!snapshot_present) { 364 | g_hook[1] = taiHookFunctionImport( 365 | &g_hook_ref[1], 366 | TAI_MAIN_MODULE, 367 | TAI_ANY_LIBRARY, //SceDisplayUser 368 | 0x7A410B64, //sceDisplaySetFrameBuf 369 | sceDisplaySetFrameBuf_patched); 370 | } 371 | 372 | DEBUG_PRINT("ThreadOptimizer READY\n"); 373 | 374 | return SCE_KERNEL_START_SUCCESS; 375 | } 376 | 377 | int module_stop(SceSize argc, const void *args) 378 | { 379 | for (int i = 0; i < 5; i++) 380 | if (g_hook[i] >= 0) taiHookRelease(g_hook[i], g_hook_ref[i]); 381 | return SCE_KERNEL_STOP_SUCCESS; 382 | } -------------------------------------------------------------------------------- /plugin/main.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Graphene 3 | */ 4 | 5 | #pragma once 6 | 7 | //#define DEBUG_ON 8 | 9 | #ifdef DEBUG_ON 10 | # define DEBUG_PRINT(...) sceClibPrintf(__VA_ARGS__) 11 | #else 12 | # define DEBUG_PRINT(...) 13 | #endif 14 | 15 | #define MAX_THREADS 128 16 | #define MAX_NAME_LEN 37 17 | 18 | typedef struct ThreadOptimizerSnapshot { 19 | char titleid[10]; 20 | unsigned int thread_count; 21 | unsigned short crc16[MAX_THREADS]; 22 | char name[MAX_THREADS][MAX_NAME_LEN]; 23 | SceKernelThreadEntry entry[MAX_THREADS]; 24 | int priority[MAX_THREADS]; 25 | int affinity[MAX_THREADS]; 26 | } ThreadOptimizerSnapshot; 27 | 28 | typedef struct SceShellSvcCustomParams { 29 | void* params1; // optional params1 30 | SceSize params1Size; // size of optional params1 31 | void* params2; // optional params2, ex. path to audio file 32 | SceSize params2Size; // size of optional params2 33 | void* params3; // optional params3 34 | SceSize params3Size; // size of optional params3 35 | } SceShellSvcCustomParams; 36 | 37 | typedef struct SceShellSvcTable { 38 | void *pFunc_0x00; 39 | void *pFunc_0x04; 40 | void *pFunc_0x08; 41 | void *pFunc_0x0C; 42 | void *pFunc_0x10; 43 | void *pFunc_0x14; 44 | void *pFunc_0x18; 45 | int(*sceShellSvcAsyncMethod)(void *obj, int asyncMethodId, SceShellSvcCustomParams* params, int a4, int* a6, void* a7); 46 | 47 | // more ... 48 | } SceShellSvcTable; 49 | 50 | void* SceShellSvc_B31E7F1C(void); 51 | int SceShellSvc_A0B067AC(void* a1, int a2); --------------------------------------------------------------------------------