├── 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);
--------------------------------------------------------------------------------