├── .gitignore ├── CMakeLists.txt ├── README.md ├── VGi.yml ├── appinfo.c ├── device.c ├── graphics.c ├── main.c ├── main.h ├── memory.c ├── misc.c ├── osd.c ├── osd.h ├── osd_font.h └── threads.c /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | VGi.project 3 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | 3 | if(NOT DEFINED CMAKE_TOOLCHAIN_FILE) 4 | if(DEFINED ENV{VITASDK}) 5 | set(CMAKE_TOOLCHAIN_FILE "$ENV{VITASDK}/share/vita.toolchain.cmake" CACHE PATH "toolchain file") 6 | else() 7 | message(FATAL_ERROR "Please define VITASDK to point to your SDK path!") 8 | endif() 9 | endif() 10 | 11 | project(VGi) 12 | include("$ENV{VITASDK}/share/vita.cmake" REQUIRED) 13 | 14 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wl,-q -Wall -O3 -std=gnu99") 15 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fno-rtti -fno-exceptions") 16 | 17 | add_executable(${PROJECT_NAME} 18 | main.c 19 | osd.c 20 | appinfo.c 21 | graphics.c 22 | memory.c 23 | threads.c 24 | misc.c 25 | device.c 26 | ) 27 | 28 | target_link_libraries(${PROJECT_NAME} 29 | gcc 30 | taihen_stub 31 | taihenModuleUtils_stub 32 | SceAppMgr_stub 33 | SceDisplay_stub 34 | SceCtrl_stub 35 | SceKernelModulemgr_stub 36 | SceSysmem_stub 37 | SceLibc_stub 38 | ScePower_stub 39 | SceLibKernel_stub 40 | ) 41 | 42 | set_target_properties(${PROJECT_NAME} 43 | PROPERTIES LINK_FLAGS "-nostdlib" 44 | ) 45 | 46 | vita_create_self(${PROJECT_NAME}.suprx ${PROJECT_NAME} 47 | CONFIG ${CMAKE_SOURCE_DIR}/${PROJECT_NAME}.yml 48 | ) 49 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # VGi 2 | A simple taihen plugin that prints useful information about PS Vita games 3 | 4 | This can be particularly useful for figuring out back-buffer resolutions, memory usage, etc... 5 | 6 | ## How to use 7 | * Add VGi.suprx to taihen config.txt (either *ALL or title id of your game), reload 8 | * Open your game 9 | * Press SELECT + LT to open VGi menu 10 | 11 | ## Controls 12 | * SELECT + LT - Open/Close VGi 13 | * LT/RT - Move between sections 14 | * D-PAD UP/DOWN - Scroll 15 | 16 | ## Screenshots 17 | ![App Info](https://user-images.githubusercontent.com/12598379/52503983-5bda8c80-2be7-11e9-80c1-c96fd6800c43.png) 18 | ![Graphics](https://user-images.githubusercontent.com/12598379/52503994-672db800-2be7-11e9-9794-5e52e74c11a3.png) 19 | ![Render Targets](https://user-images.githubusercontent.com/12598379/52504010-757bd400-2be7-11e9-9f25-b4730b39f1f6.png) 20 | ![Color Surfaces](https://user-images.githubusercontent.com/12598379/52504017-7f9dd280-2be7-11e9-8035-bf3be8998709.png) 21 | ![Depth/Stencil Surfaces](https://user-images.githubusercontent.com/12598379/52504022-87f60d80-2be7-11e9-90f3-741ead66ae12.png) 22 | ![Textures](https://user-images.githubusercontent.com/12598379/52504036-917f7580-2be7-11e9-8ffc-27b79fc04403.png) 23 | ![Memory](https://user-images.githubusercontent.com/12598379/52504063-9cd2a100-2be7-11e9-9e46-6761a933a669.png) 24 | ![Threads](https://user-images.githubusercontent.com/12598379/52504070-a3f9af00-2be7-11e9-9399-5e788c45e831.png) 25 | ![Misc](https://user-images.githubusercontent.com/12598379/52504098-afe57100-2be7-11e9-8766-11225d9804b8.png) 26 | ![Device](https://user-images.githubusercontent.com/12598379/52504104-b673e880-2be7-11e9-85b8-615af35228d5.png) 27 | -------------------------------------------------------------------------------- /VGi.yml: -------------------------------------------------------------------------------- 1 | VGi: 2 | attributes: 0 3 | version: 4 | major: 0 5 | minor: 1 6 | main: 7 | start: module_start 8 | stop: module_stop -------------------------------------------------------------------------------- /appinfo.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "osd.h" 5 | #include "main.h" 6 | 7 | // app info 8 | static tai_module_info_t g_appModuleInfo = {0}; 9 | static SceKernelModuleInfo g_appSceModuleInfo = {0}; 10 | static char g_appContent[256] = {0}; 11 | static char g_appTitle[256] = {0}; 12 | static char g_appSTitle[64] = {0}; 13 | static char g_appTitleID[12] = {0}; 14 | static char g_appRegion[10] = {0}; 15 | 16 | void drawAppInfoMenu(const SceDisplayFrameBuf *pParam) { 17 | osdSetTextScale(2); 18 | osdDrawStringF((pParam->width / 2) - osdGetTextWidth(MENU_TITLE_APP_INFO) / 2, 5, MENU_TITLE_APP_INFO); 19 | 20 | osdSetTextScale(1); 21 | int x = 10, y = 38; 22 | osdDrawStringF(x, y += 22, "Title: %s", g_appTitle); 23 | osdDrawStringF(x, y += 20, "STitle: %s", g_appSTitle); 24 | osdDrawStringF(x, y += 20, "ContentID: %s", g_appContent); 25 | osdDrawStringF(x, y += 20, "TitleID: %s [ %s ]", g_appTitleID, g_appRegion); 26 | osdDrawStringF(x, y += 20, "Module: %s", g_appModuleInfo.name); 27 | osdDrawStringF(x, y += 20, "Module path: %s", g_appSceModuleInfo.path); 28 | osdDrawStringF(x, y += 20, "Module NID: 0x%08X", g_appModuleInfo.module_nid); 29 | } 30 | 31 | void setupAppInfoMenu() { 32 | g_appModuleInfo.size = sizeof(tai_module_info_t); 33 | taiGetModuleInfo(TAI_MAIN_MODULE, &g_appModuleInfo); 34 | 35 | g_appSceModuleInfo.size = sizeof(SceKernelModuleInfo); 36 | sceKernelGetModuleInfo(g_appModuleInfo.modid, &g_appSceModuleInfo); 37 | 38 | sceAppMgrAppParamGetString(0, 6, g_appContent, 256); 39 | sceAppMgrAppParamGetString(0, 9, g_appTitle, 256); 40 | sceAppMgrAppParamGetString(0, 10, g_appSTitle, 64); 41 | sceAppMgrAppParamGetString(0, 12, g_appTitleID, 12); 42 | 43 | if (!strncmp(g_appTitleID, "PCSA", 4)) { 44 | snprintf(g_appRegion, 10, "US 1st"); 45 | } else if (!strncmp(g_appTitleID, "PCSE", 4)) { 46 | snprintf(g_appRegion, 10, "US 3rd"); 47 | } else if (!strncmp(g_appTitleID, "PCSB", 4)) { 48 | snprintf(g_appRegion, 10, "EU 1st"); 49 | } else if (!strncmp(g_appTitleID, "PCSF", 4)) { 50 | snprintf(g_appRegion, 10, "EU 3rd"); 51 | } else if (!strncmp(g_appTitleID, "PCSC", 4)) { 52 | snprintf(g_appRegion, 10, "JP 1st"); 53 | } else if (!strncmp(g_appTitleID, "PCSG", 4)) { 54 | snprintf(g_appRegion, 10, "JP 3rd"); 55 | } else if (!strncmp(g_appTitleID, "PCSD", 4)) { 56 | snprintf(g_appRegion, 10, "ASIA 1st"); 57 | } else if (!strncmp(g_appTitleID, "PCSH", 4)) { 58 | snprintf(g_appRegion, 10, "ASIA 3rd"); 59 | } else { 60 | snprintf(g_appRegion, 10, "?"); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /device.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "osd.h" 5 | #include "main.h" 6 | 7 | static uint8_t scePowerSetConfigurationMode_mode = 0; 8 | 9 | 10 | static int scePowerSetConfigurationMode_patched(int mode) { 11 | scePowerSetConfigurationMode_mode = mode; 12 | return TAI_CONTINUE(int, g_hookrefs[26], mode); 13 | } 14 | 15 | void drawDeviceMenu(const SceDisplayFrameBuf *pParam) { 16 | osdSetTextScale(2); 17 | osdDrawStringF((pParam->width / 2) - osdGetTextWidth(MENU_TITLE_DEVICE) / 2, 5, MENU_TITLE_DEVICE); 18 | 19 | osdSetTextScale(1); 20 | int x = 10, y = 60; 21 | 22 | osdDrawStringF(x, y += 22, "Using Wireless Features: %s", scePowerGetUsingWireless() == SCE_TRUE ? "YES" : "NO"); 23 | osdDrawStringF(x, y += 22, "PowerConfiguration: %s", 24 | scePowerSetConfigurationMode_mode == 0 ? "Unknown" : 25 | (scePowerSetConfigurationMode_mode == SCE_POWER_CONFIGURATION_MODE_A ? "MODE_A" : 26 | (scePowerSetConfigurationMode_mode == SCE_POWER_CONFIGURATION_MODE_B ? "MODE_B" : 27 | (scePowerSetConfigurationMode_mode == SCE_POWER_CONFIGURATION_MODE_C ? "MODE_C" : "???")))); 28 | if (scePowerSetConfigurationMode_mode != 0) { 29 | osdDrawStringF(x + 20, y += 22, "GPU clock: %s", scePowerSetConfigurationMode_mode == SCE_POWER_CONFIGURATION_MODE_A ? "normal" : "high"); 30 | osdDrawStringF(x + 20, y += 22, "WLAN enabled: %s", scePowerSetConfigurationMode_mode == SCE_POWER_CONFIGURATION_MODE_B ? "NO" : "YES"); 31 | osdDrawStringF(x + 20, y += 22, "Camera disabled: %s, Max Brightness limited: %s", 32 | scePowerSetConfigurationMode_mode == SCE_POWER_CONFIGURATION_MODE_C ? "YES" : "NO", 33 | scePowerSetConfigurationMode_mode == SCE_POWER_CONFIGURATION_MODE_C ? "YES" : "NO"); 34 | } 35 | 36 | osdDrawStringF(x, y += 44, "Current Clocks:"); 37 | osdDrawStringF(x + 20, y += 22, "CPU: %d MHz", scePowerGetArmClockFrequency()); 38 | osdDrawStringF(x + 20, y += 22, "GPU: %d MHz", scePowerGetGpuClockFrequency()); 39 | osdDrawStringF(x + 20, y += 22, "BUS: %d MHz", scePowerGetBusClockFrequency()); 40 | osdDrawStringF(x + 20, y += 22, "XBAR: %d MHz", scePowerGetGpuXbarClockFrequency()); 41 | } 42 | 43 | void setupDeviceMenu() { 44 | 45 | g_hooks[26] = taiHookFunctionImport( 46 | &g_hookrefs[26], 47 | TAI_MAIN_MODULE, 48 | TAI_ANY_LIBRARY, 49 | 0x3CE187B6, 50 | scePowerSetConfigurationMode_patched); 51 | } 52 | -------------------------------------------------------------------------------- /graphics.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "osd.h" 5 | #include "main.h" 6 | 7 | #define MAX_RENDER_TARGETS 64 8 | #define MAX_COLOR_SURFACES 64 9 | #define MAX_DEPTH_STENCIL_SURFACES 64 10 | #define MAX_TEXTURES 64 11 | 12 | typedef struct { 13 | uint8_t active; 14 | SceGxmRenderTarget *ptr; 15 | SceGxmRenderTargetParams params; 16 | SceUID driverMemBlockBeforeCreate; 17 | } VGi_RenderTarget; 18 | 19 | typedef struct { 20 | SceGxmColorSurface *surface; 21 | SceGxmColorFormat colorFormat; 22 | SceGxmColorSurfaceType surfaceType; 23 | SceGxmColorSurfaceScaleMode scaleMode; 24 | SceGxmOutputRegisterSize outputRegisterSize; 25 | unsigned int width; 26 | unsigned int height; 27 | unsigned int strideInPixels; 28 | void *data; 29 | } VGi_ColorSurface; 30 | 31 | typedef struct { 32 | SceGxmDepthStencilSurface *surface; 33 | SceGxmDepthStencilFormat depthStencilFormat; 34 | SceGxmDepthStencilSurfaceType surfaceType; 35 | unsigned int strideInSamples; 36 | void *depthData; 37 | void *stencilData; 38 | } VGi_DepthStencilSurface; 39 | 40 | typedef enum { 41 | TEXTURE_LINEAR, 42 | TEXTURE_LINEAR_STRIDED, 43 | TEXTURE_SWIZZLED, 44 | TEXTURE_TILED, 45 | TEXTURE_CUBE 46 | } VGi_TextureType; 47 | 48 | typedef struct { 49 | SceGxmTexture *texture; 50 | VGi_TextureType type; 51 | const void *data; 52 | SceGxmTextureFormat texFormat; 53 | unsigned int width; 54 | unsigned int height; 55 | unsigned int mipCount; 56 | unsigned int byteStride; 57 | } VGi_Texture; 58 | 59 | static uint8_t sceDisplayGetRefreshRate_used = 0; 60 | static uint8_t sceDisplayGetVcount_used = 0; 61 | static uint8_t sceDisplayWaitVblankStart_used = 0; 62 | static uint8_t sceDisplayWaitVblankStartCB_used = 0; 63 | static uint8_t sceDisplayWaitVblankStartMulti_used = 0; 64 | static uint8_t sceDisplayWaitVblankStartMultiCB_used = 0; 65 | static uint8_t sceDisplayWaitSetFrameBuf_used = 0; 66 | static uint8_t sceDisplayWaitSetFrameBufCB_used = 0; 67 | static uint8_t sceDisplayWaitSetFrameBufMulti_used = 0; 68 | static uint8_t sceDisplayWaitSetFrameBufMultiCB_used = 0; 69 | 70 | static uint8_t sceDisplayWaitVblankStartMulti_vcount = 0; 71 | static uint8_t sceDisplayWaitVblankStartMultiCB_vcount = 0; 72 | static uint8_t sceDisplayWaitSetFrameBufMulti_vcount = 0; 73 | static uint8_t sceDisplayWaitSetFrameBufMultiCB_vcount = 0; 74 | 75 | static VGi_RenderTarget g_renderTargets[MAX_RENDER_TARGETS] = {0}; 76 | static uint32_t g_renderTargetsCount = 0; 77 | 78 | static VGi_ColorSurface g_colorSurfaces[MAX_COLOR_SURFACES] = {0}; 79 | static uint32_t g_colorSurfacesCount = 0; 80 | 81 | static VGi_DepthStencilSurface g_depthStencilSurfaces[MAX_DEPTH_STENCIL_SURFACES] = {0}; 82 | static uint32_t g_depthStencilSurfacesCount = 0; 83 | 84 | static VGi_Texture g_textures[MAX_TEXTURES] = {0}; 85 | static uint32_t g_texturesCount = 0; 86 | 87 | static SceGxmInitializeParams g_gxmInitializeParams = {0}; 88 | 89 | static int sceGxmCreateRenderTarget_patched(const SceGxmRenderTargetParams *params, SceGxmRenderTarget *renderTarget) { 90 | SceUID dmb = params->driverMemBlock; 91 | int ret = TAI_CONTINUE(int, g_hookrefs[11], params, renderTarget); 92 | 93 | for (int i = 0; i < MAX_RENDER_TARGETS; i++) { 94 | if (!g_renderTargets[i].active) { 95 | g_renderTargets[i].active = 1; 96 | g_renderTargets[i].ptr = renderTarget; 97 | g_renderTargets[i].driverMemBlockBeforeCreate = dmb; 98 | memcpy(&(g_renderTargets[i].params), params, sizeof(SceGxmRenderTargetParams)); 99 | goto RET; 100 | } 101 | } 102 | 103 | RET: 104 | g_renderTargetsCount++; 105 | return ret; 106 | } 107 | 108 | static int sceGxmDestroyRenderTarget_patched(SceGxmRenderTarget *renderTarget) { 109 | for (int i = 0; i < MAX_RENDER_TARGETS; i++) { 110 | if (g_renderTargets[i].ptr == renderTarget && g_renderTargets[i].active) { 111 | g_renderTargets[i].active = 0; 112 | goto RET; 113 | } 114 | } 115 | 116 | RET: 117 | g_renderTargetsCount--; 118 | return TAI_CONTINUE(int, g_hookrefs[12], renderTarget); 119 | } 120 | 121 | static int sceDisplayGetRefreshRate_patched(float *pFps) { 122 | sceDisplayGetRefreshRate_used = 1; 123 | return TAI_CONTINUE(int, g_hookrefs[1], pFps); 124 | } 125 | static int sceDisplayGetVcount_patched() { 126 | sceDisplayGetVcount_used = 1; 127 | return TAI_CONTINUE(int, g_hookrefs[2]); 128 | } 129 | static int sceDisplayWaitVblankStart_patched() { 130 | sceDisplayWaitVblankStart_used = 1; 131 | if (g_vsyncKillswitch == 2) 132 | return 0; 133 | return TAI_CONTINUE(int, g_hookrefs[3]); 134 | } 135 | static int sceDisplayWaitVblankStartCB_patched() { 136 | sceDisplayWaitVblankStartCB_used = 1; 137 | if (g_vsyncKillswitch == 2) 138 | return 0; 139 | return TAI_CONTINUE(int, g_hookrefs[4]); 140 | } 141 | static int sceDisplayWaitVblankStartMulti_patched(unsigned int vcount) { 142 | sceDisplayWaitVblankStartMulti_used = 1; 143 | sceDisplayWaitVblankStartMulti_vcount = vcount; 144 | if (g_vsyncKillswitch == 2) 145 | return 0; 146 | if (g_vsyncKillswitch == 1) 147 | vcount = 1; 148 | return TAI_CONTINUE(int, g_hookrefs[5], vcount); 149 | } 150 | static int sceDisplayWaitVblankStartMultiCB_patched(unsigned int vcount) { 151 | sceDisplayWaitVblankStartMultiCB_used = 1; 152 | sceDisplayWaitVblankStartMultiCB_vcount = vcount; 153 | if (g_vsyncKillswitch == 2) 154 | return 0; 155 | if (g_vsyncKillswitch == 1) 156 | vcount = 1; 157 | return TAI_CONTINUE(int, g_hookrefs[6], vcount); 158 | } 159 | static int sceDisplayWaitSetFrameBuf_patched() { 160 | sceDisplayWaitSetFrameBuf_used = 1; 161 | if (g_vsyncKillswitch == 2) 162 | return 0; 163 | return TAI_CONTINUE(int, g_hookrefs[7]); 164 | } 165 | static int sceDisplayWaitSetFrameBufCB_patched() { 166 | sceDisplayWaitSetFrameBufCB_used = 1; 167 | if (g_vsyncKillswitch == 2) 168 | return 0; 169 | return TAI_CONTINUE(int, g_hookrefs[8]); 170 | } 171 | static int sceDisplayWaitSetFrameBufMulti_patched(unsigned int vcount) { 172 | sceDisplayWaitSetFrameBufMulti_used = 1; 173 | sceDisplayWaitSetFrameBufMulti_vcount = vcount; 174 | if (g_vsyncKillswitch == 2) 175 | return 0; 176 | if (g_vsyncKillswitch == 1) 177 | vcount = 1; 178 | return TAI_CONTINUE(int, g_hookrefs[9], vcount); 179 | } 180 | static int sceDisplayWaitSetFrameBufMultiCB_patched(unsigned int vcount) { 181 | sceDisplayWaitSetFrameBufMultiCB_used = 1; 182 | sceDisplayWaitSetFrameBufMultiCB_vcount = vcount; 183 | if (g_vsyncKillswitch == 2) 184 | return 0; 185 | if (g_vsyncKillswitch == 1) 186 | vcount = 1; 187 | return TAI_CONTINUE(int, g_hookrefs[10], vcount); 188 | } 189 | 190 | static int sceGxmColorSurfaceInit_patched( 191 | SceGxmColorSurface *surface, 192 | SceGxmColorFormat colorFormat, 193 | SceGxmColorSurfaceType surfaceType, 194 | SceGxmColorSurfaceScaleMode scaleMode, 195 | SceGxmOutputRegisterSize outputRegisterSize, 196 | unsigned int width, 197 | unsigned int height, 198 | unsigned int strideInPixels, 199 | void *data) { 200 | int ret = TAI_CONTINUE(int, g_hookrefs[22], surface, colorFormat, surfaceType, 201 | scaleMode, outputRegisterSize, width, height, strideInPixels, data); 202 | 203 | int i = 0; 204 | for (i = 0; i < MAX_COLOR_SURFACES; i++) { 205 | if (g_colorSurfaces[i].surface == surface) { 206 | goto RET_EXISTING; 207 | } 208 | } 209 | for (i = 0; i < MAX_COLOR_SURFACES; i++) { 210 | if (!g_colorSurfaces[i].surface) { 211 | goto RET_NEW; 212 | } 213 | } 214 | 215 | return ret; 216 | 217 | RET_NEW: 218 | g_colorSurfacesCount++; 219 | RET_EXISTING: 220 | g_colorSurfaces[i].surface = surface; 221 | g_colorSurfaces[i].colorFormat = colorFormat; 222 | g_colorSurfaces[i].surfaceType = surfaceType; 223 | g_colorSurfaces[i].scaleMode = scaleMode; 224 | g_colorSurfaces[i].outputRegisterSize = outputRegisterSize; 225 | g_colorSurfaces[i].width = width; 226 | g_colorSurfaces[i].height = height; 227 | g_colorSurfaces[i].strideInPixels = strideInPixels; 228 | g_colorSurfaces[i].data = data; 229 | return ret; 230 | } 231 | 232 | static int sceGxmInitialize_patched(const SceGxmInitializeParams *params) { 233 | memcpy(&g_gxmInitializeParams, params, sizeof(SceGxmInitializeParams)); 234 | return TAI_CONTINUE(int, g_hookrefs[25], params); 235 | } 236 | 237 | static int sceGxmDepthStencilSurfaceInit_patched( 238 | SceGxmDepthStencilSurface *surface, 239 | SceGxmDepthStencilFormat depthStencilFormat, 240 | SceGxmDepthStencilSurfaceType surfaceType, 241 | unsigned int strideInSamples, 242 | void *depthData, 243 | void *stencilData) { 244 | int ret = TAI_CONTINUE(int, g_hookrefs[27], surface, depthStencilFormat, surfaceType, 245 | strideInSamples, depthData, stencilData); 246 | 247 | int i = 0; 248 | for (i = 0; i < MAX_DEPTH_STENCIL_SURFACES; i++) { 249 | if (g_depthStencilSurfaces[i].surface == surface) { 250 | goto RET_EXISTING; 251 | } 252 | } 253 | for (i = 0; i < MAX_DEPTH_STENCIL_SURFACES; i++) { 254 | if (!g_depthStencilSurfaces[i].surface) { 255 | goto RET_NEW; 256 | } 257 | } 258 | 259 | return ret; 260 | 261 | RET_NEW: 262 | g_depthStencilSurfacesCount++; 263 | RET_EXISTING: 264 | g_depthStencilSurfaces[i].surface = surface; 265 | g_depthStencilSurfaces[i].depthStencilFormat = depthStencilFormat; 266 | g_depthStencilSurfaces[i].surfaceType = surfaceType; 267 | g_depthStencilSurfaces[i].strideInSamples = strideInSamples; 268 | g_depthStencilSurfaces[i].depthData = depthData; 269 | g_depthStencilSurfaces[i].stencilData = stencilData; 270 | return ret; 271 | } 272 | 273 | static void addTexture( 274 | VGi_TextureType type, 275 | SceGxmTexture *texture, 276 | const void *data, 277 | SceGxmTextureFormat texFormat, 278 | unsigned int width, 279 | unsigned int height, 280 | unsigned int mipCount, 281 | unsigned int byteStride) { 282 | int i = 0; 283 | for (i = 0; i < MAX_TEXTURES; i++) { 284 | if (g_textures[i].texture == texture) { 285 | goto RET_EXISTING; 286 | } 287 | if (g_textures[i].texture && 288 | g_textures[i].width == width && 289 | g_textures[i].height == height) { 290 | goto RET_SKIP; 291 | } 292 | } 293 | for (i = 0; i < MAX_TEXTURES; i++) { 294 | if (!g_textures[i].texture) { 295 | goto RET_NEW; 296 | } 297 | } 298 | 299 | RET_NEW: 300 | g_texturesCount++; 301 | RET_EXISTING: 302 | g_textures[i].texture = texture; 303 | g_textures[i].type = type; 304 | g_textures[i].data = data; 305 | g_textures[i].texFormat = texFormat; 306 | g_textures[i].width = width; 307 | g_textures[i].height = height; 308 | g_textures[i].mipCount = mipCount; 309 | g_textures[i].byteStride = byteStride; 310 | return; 311 | RET_SKIP: 312 | g_texturesCount++; 313 | return; 314 | } 315 | 316 | static int sceGxmTextureInitSwizzled_patched( 317 | SceGxmTexture *texture, 318 | const void *data, 319 | SceGxmTextureFormat texFormat, 320 | unsigned int width, 321 | unsigned int height, 322 | unsigned int mipCount) { 323 | int ret = TAI_CONTINUE(int, g_hookrefs[28], texture, data, texFormat, 324 | width, height, mipCount); 325 | addTexture(TEXTURE_SWIZZLED, texture, data, texFormat, width, height, mipCount, 0); 326 | return ret; 327 | } 328 | static int sceGxmTextureInitLinear_patched( 329 | SceGxmTexture *texture, 330 | const void *data, 331 | SceGxmTextureFormat texFormat, 332 | unsigned int width, 333 | unsigned int height, 334 | unsigned int mipCount) { 335 | int ret = TAI_CONTINUE(int, g_hookrefs[29], texture, data, texFormat, 336 | width, height, mipCount); 337 | addTexture(TEXTURE_LINEAR, texture, data, texFormat, width, height, mipCount, 0); 338 | return ret; 339 | } 340 | static int sceGxmTextureInitLinearStrided_patched( 341 | SceGxmTexture *texture, 342 | const void *data, 343 | SceGxmTextureFormat texFormat, 344 | unsigned int width, 345 | unsigned int height, 346 | unsigned int byteStride) { 347 | int ret = TAI_CONTINUE(int, g_hookrefs[30], texture, data, texFormat, 348 | width, height, byteStride); 349 | addTexture(TEXTURE_LINEAR_STRIDED, texture, data, texFormat, width, height, 0, byteStride); 350 | return ret; 351 | } 352 | static int sceGxmTextureInitTiled_patched( 353 | SceGxmTexture *texture, 354 | const void *data, 355 | SceGxmTextureFormat texFormat, 356 | unsigned int width, 357 | unsigned int height, 358 | unsigned int mipCount) { 359 | int ret = TAI_CONTINUE(int, g_hookrefs[31], texture, data, texFormat, 360 | width, height, mipCount); 361 | addTexture(TEXTURE_TILED, texture, data, texFormat, width, height, mipCount, 0); 362 | return ret; 363 | } 364 | static int sceGxmTextureInitCube_patched( 365 | SceGxmTexture *texture, 366 | const void *data, 367 | SceGxmTextureFormat texFormat, 368 | unsigned int width, 369 | unsigned int height, 370 | unsigned int mipCount) { 371 | int ret = TAI_CONTINUE(int, g_hookrefs[32], texture, data, texFormat, 372 | width, height, mipCount); 373 | addTexture(TEXTURE_CUBE, texture, data, texFormat, width, height, mipCount, 0); 374 | return ret; 375 | } 376 | 377 | static const char *getTextureTypeString(VGi_TextureType type) { 378 | switch (type) { 379 | case TEXTURE_LINEAR: 380 | return "LINEAR"; 381 | case TEXTURE_LINEAR_STRIDED: 382 | return "LINEAR_S"; 383 | case TEXTURE_SWIZZLED: 384 | return "SWIZZLED"; 385 | case TEXTURE_TILED: 386 | return "TILED"; 387 | case TEXTURE_CUBE: 388 | return "CUBE"; 389 | default: 390 | return "?"; 391 | } 392 | } 393 | 394 | void drawGraphicsMenu(const SceDisplayFrameBuf *pParam) { 395 | osdSetTextScale(2); 396 | osdDrawStringF((pParam->width / 2) - osdGetTextWidth(MENU_TITLE_GRAPHICS) / 2, 5, MENU_TITLE_GRAPHICS); 397 | 398 | osdSetTextScale(1); 399 | osdDrawStringF(10, 60, "Framebuffer: %dx%d, stride = %d", pParam->width, pParam->height, pParam->pitch); 400 | osdDrawStringF(10, 82, "Max Pending Swaps: %d", g_gxmInitializeParams.displayQueueMaxPendingCount); 401 | osdDrawStringF(10, 104, "DQ Callback: 0x%X", g_gxmInitializeParams.displayQueueCallback); 402 | osdDrawStringF(10, 126, "Param. buf. size: %d B", g_gxmInitializeParams.parameterBufferSize); 403 | 404 | osdDrawStringF(10, 170, "VSync mechanisms:"); 405 | if (!g_vsyncKillswitch) { 406 | osdSetTextColor(150, 255, 150, 255); 407 | osdDrawStringF(pParam->width - osdGetTextWidth("DEFAULT (O)") - 10, 170, "DEFAULT (O)"); 408 | } else if (g_vsyncKillswitch == 1) { 409 | osdSetTextColor(255, 255, 150, 255); 410 | osdDrawStringF(pParam->width - osdGetTextWidth("ALLOW 1 (O)") - 10, 170, "ALLOW 1 (O)"); 411 | } else if (g_vsyncKillswitch == 2) { 412 | osdSetTextColor(255, 150, 150, 255); 413 | osdDrawStringF(pParam->width - osdGetTextWidth("DROP ALL (O)") - 10, 170, "DROP ALL (O)"); 414 | } 415 | osdSetTextColor(255, 255, 255, 255); 416 | 417 | int x = 30, y = 192; 418 | if (sceDisplayGetRefreshRate_used) 419 | osdDrawStringF(x, y += 22, "sceDisplayGetRefreshRate()"); 420 | if (sceDisplayGetVcount_used) 421 | osdDrawStringF(x, y += 22, "sceDisplayGetVcount()"); 422 | if (sceDisplayWaitVblankStart_used) 423 | osdDrawStringF(x, y += 22, "sceDisplayWaitVblankStart()"); 424 | if (sceDisplayWaitVblankStartCB_used) 425 | osdDrawStringF(x, y += 22, "sceDisplayWaitVblankStartCB()"); 426 | if (sceDisplayWaitVblankStartMulti_used) 427 | osdDrawStringF(x, y += 22, "sceDisplayWaitVblankStartMulti( %d )", sceDisplayWaitVblankStartMulti_vcount); 428 | if (sceDisplayWaitVblankStartMultiCB_used) 429 | osdDrawStringF(x, y += 22, "sceDisplayWaitVblankStartMultiCB( %d )", sceDisplayWaitVblankStartMultiCB_vcount); 430 | if (sceDisplayWaitSetFrameBuf_used) 431 | osdDrawStringF(x, y += 22, "sceDisplayWaitSetFrameBuf()"); 432 | if (sceDisplayWaitSetFrameBufCB_used) 433 | osdDrawStringF(x, y += 22, "sceDisplayWaitSetFrameBufCB()"); 434 | if (sceDisplayWaitSetFrameBufMulti_used) 435 | osdDrawStringF(x, y += 22, "sceDisplayWaitSetFrameBufMulti( %d )", sceDisplayWaitSetFrameBufMulti_vcount); 436 | if (sceDisplayWaitSetFrameBufMultiCB_used) 437 | osdDrawStringF(x, y += 22, "sceDisplayWaitSetFrameBufMultiCB( %d )", sceDisplayWaitSetFrameBufMultiCB_vcount); 438 | } 439 | 440 | void drawGraphics2Menu(const SceDisplayFrameBuf *pParam) { 441 | osdSetTextScale(2); 442 | osdDrawStringF((pParam->width / 2) - osdGetTextWidth(MENU_TITLE_GRAPHICS_2) / 2, 5, MENU_TITLE_GRAPHICS_2); 443 | 444 | // Header 445 | osdSetTextScale(1); 446 | osdDrawStringF(10, 60, "Active Render Targets (%d):", g_renderTargetsCount); 447 | if (g_renderTargetsCount > MAX_RENDER_TARGETS) { 448 | char buf[32]; 449 | snprintf(buf, 32, "!! > %d", MAX_RENDER_TARGETS); 450 | osdDrawStringF(pParam->width - osdGetTextWidth(buf), 60, buf); 451 | } 452 | osdDrawStringF(30, 93, " WxH MSAA scenesPF memBlockUID"); 453 | 454 | // Scrollable section 455 | int x = 30, y = 104; 456 | 457 | if (g_menuScroll > 0) { 458 | // Draw scroll indicator 459 | osdDrawStringF(pParam->width - 24 - 5, y + 22, "/\\"); 460 | osdDrawStringF(pParam->width - 24 - 5, y + 44, "%2d", g_menuScroll); 461 | } 462 | 463 | for (int i = g_menuScroll; i < MAX_RENDER_TARGETS; i++) { 464 | if (g_renderTargets[i].active) { 465 | osdDrawStringF(x, y += 22, "%4dx%-10d %-8s %-8d 0x%08X %s", 466 | g_renderTargets[i].params.width, 467 | g_renderTargets[i].params.height, 468 | g_renderTargets[i].params.multisampleMode == SCE_GXM_MULTISAMPLE_4X ? "4x" : 469 | (g_renderTargets[i].params.multisampleMode == SCE_GXM_MULTISAMPLE_2X ? "2x" : ""), 470 | g_renderTargets[i].params.scenesPerFrame, 471 | g_renderTargets[i].params.driverMemBlock, 472 | g_renderTargets[i].driverMemBlockBeforeCreate == 0xFFFFFFFF ? "(A)" : ""); 473 | } 474 | 475 | // Do not draw out of screen 476 | if (y > pParam->height - 72) { 477 | // Draw scroll indicator 478 | osdDrawStringF(pParam->width - 24 - 5, pParam->height - 72, "%2d", MIN(g_renderTargetsCount, MAX_RENDER_TARGETS) - i); 479 | osdDrawStringF(pParam->width - 24 - 5, pParam->height - 50, "\\/"); 480 | break; 481 | } 482 | } 483 | } 484 | 485 | void drawGraphics3Menu(const SceDisplayFrameBuf *pParam) { 486 | osdSetTextScale(2); 487 | osdDrawStringF((pParam->width / 2) - osdGetTextWidth(MENU_TITLE_GRAPHICS_3) / 2, 5, MENU_TITLE_GRAPHICS_3); 488 | 489 | // Header 490 | osdSetTextScale(1); 491 | osdDrawStringF(10, 60, "Color Surfaces (%d):", g_colorSurfacesCount); 492 | if (g_colorSurfacesCount > MAX_COLOR_SURFACES) { 493 | char buf[32]; 494 | snprintf(buf, 32, "!! > %d", MAX_COLOR_SURFACES); 495 | osdDrawStringF(pParam->width - osdGetTextWidth(buf), 60, buf); 496 | } 497 | osdDrawStringF(30, 93, " WxH stride MSAA colorFormat surfaceType"); 498 | 499 | // Scrollable section 500 | int x = 30, y = 104; 501 | 502 | if (g_menuScroll > 0) { 503 | // Draw scroll indicator 504 | osdDrawStringF(pParam->width - 24 - 5, y + 22, "/\\"); 505 | osdDrawStringF(pParam->width - 24 - 5, y + 44, "%2d", g_menuScroll); 506 | } 507 | 508 | for (int i = g_menuScroll; i < MAX_COLOR_SURFACES; i++) { 509 | if (g_colorSurfaces[i].surface) { 510 | osdDrawStringF(x, y += 22, "%4dx%-7d %-8d %-6s 0x%-10X 0x%X", 511 | g_colorSurfaces[i].width, 512 | g_colorSurfaces[i].height, 513 | g_colorSurfaces[i].strideInPixels, 514 | g_colorSurfaces[i].scaleMode == SCE_GXM_COLOR_SURFACE_SCALE_MSAA_DOWNSCALE ? "DS" : "", 515 | g_colorSurfaces[i].colorFormat, 516 | g_colorSurfaces[i].surfaceType); 517 | } 518 | 519 | // Do not draw out of screen 520 | if (y > pParam->height - 72) { 521 | // Draw scroll indicator 522 | osdDrawStringF(pParam->width - 24 - 5, pParam->height - 72, "%2d", MIN(g_colorSurfacesCount, MAX_COLOR_SURFACES) - i); 523 | osdDrawStringF(pParam->width - 24 - 5, pParam->height - 50, "\\/"); 524 | break; 525 | } 526 | } 527 | } 528 | 529 | void drawGraphics4Menu(const SceDisplayFrameBuf *pParam) { 530 | osdSetTextScale(2); 531 | osdDrawStringF((pParam->width / 2) - osdGetTextWidth(MENU_TITLE_GRAPHICS_4) / 2, 5, MENU_TITLE_GRAPHICS_4); 532 | 533 | // Header 534 | osdSetTextScale(1); 535 | osdDrawStringF(10, 60, "Depth/Stencil Surfaces (%d):", g_depthStencilSurfacesCount); 536 | if (g_depthStencilSurfacesCount > MAX_DEPTH_STENCIL_SURFACES) { 537 | char buf[32]; 538 | snprintf(buf, 32, "!! > %d", MAX_DEPTH_STENCIL_SURFACES); 539 | osdDrawStringF(pParam->width - osdGetTextWidth(buf), 60, buf); 540 | } 541 | osdDrawStringF(30, 93, "strideSamples surface depth stencil format type"); 542 | 543 | // Scrollable section 544 | int x = 30, y = 104; 545 | 546 | if (g_menuScroll > 0) { 547 | // Draw scroll indicator 548 | osdDrawStringF(pParam->width - 24 - 5, y + 22, "/\\"); 549 | osdDrawStringF(pParam->width - 24 - 5, y + 44, "%2d", g_menuScroll); 550 | } 551 | 552 | for (int i = g_menuScroll; i < MAX_DEPTH_STENCIL_SURFACES; i++) { 553 | if (g_depthStencilSurfaces[i].surface) { 554 | osdDrawStringF(x, y += 22, " %-9d 0x%-9X 0x%-9X 0x%-9X 0x%-9X 0x%-9X", 555 | g_depthStencilSurfaces[i].strideInSamples, 556 | g_depthStencilSurfaces[i].surface, 557 | g_depthStencilSurfaces[i].depthData, 558 | g_depthStencilSurfaces[i].stencilData, 559 | g_depthStencilSurfaces[i].depthStencilFormat, 560 | g_depthStencilSurfaces[i].surfaceType); 561 | } 562 | 563 | // Do not draw out of screen 564 | if (y > pParam->height - 72) { 565 | // Draw scroll indicator 566 | osdDrawStringF(pParam->width - 24 - 5, pParam->height - 72, "%2d", MIN(g_depthStencilSurfacesCount, MAX_DEPTH_STENCIL_SURFACES) - i); 567 | osdDrawStringF(pParam->width - 24 - 5, pParam->height - 50, "\\/"); 568 | break; 569 | } 570 | } 571 | } 572 | 573 | void drawGraphics5Menu(const SceDisplayFrameBuf *pParam) { 574 | osdSetTextScale(2); 575 | osdDrawStringF((pParam->width / 2) - osdGetTextWidth(MENU_TITLE_GRAPHICS_5) / 2, 5, MENU_TITLE_GRAPHICS_5); 576 | 577 | // Header 578 | osdSetTextScale(1); 579 | osdDrawStringF(10, 60, "Textures (showing only 1 per size):"); 580 | if (g_texturesCount > MAX_TEXTURES) { 581 | char buf[32]; 582 | snprintf(buf, 32, "!! > %d", MAX_TEXTURES); 583 | osdDrawStringF(pParam->width - osdGetTextWidth(buf), 60, buf); 584 | } 585 | osdDrawStringF(30, 93, " size type ptr data format mipCount byteStride"); 586 | 587 | // Scrollable section 588 | int x = 30, y = 104; 589 | 590 | if (g_menuScroll > 0) { 591 | // Draw scroll indicator 592 | osdDrawStringF(pParam->width - 24 - 5, y + 22, "/\\"); 593 | osdDrawStringF(pParam->width - 24 - 5, y + 44, "%2d", g_menuScroll); 594 | } 595 | 596 | for (int i = g_menuScroll; i < MAX_TEXTURES; i++) { 597 | if (g_textures[i].texture) { 598 | osdDrawStringF(x, y += 22, "%4dx%-5d %-9s 0x%-9X 0x%-9X 0x%-9X %-6d %d", 599 | g_textures[i].width, 600 | g_textures[i].height, 601 | getTextureTypeString(g_textures[i].type), 602 | g_textures[i].texture, 603 | g_textures[i].data, 604 | g_textures[i].texFormat, 605 | g_textures[i].mipCount, 606 | g_textures[i].byteStride); 607 | } 608 | 609 | // Do not draw out of screen 610 | if (y > pParam->height - 72) { 611 | // Draw scroll indicator 612 | osdDrawStringF(pParam->width - 24 - 5, pParam->height - 72, "%2d", MIN(g_texturesCount, MAX_TEXTURES) - i); 613 | osdDrawStringF(pParam->width - 24 - 5, pParam->height - 50, "\\/"); 614 | break; 615 | } 616 | } 617 | } 618 | 619 | void setupGraphicsMenu() { 620 | 621 | g_hooks[1] = taiHookFunctionImport( 622 | &g_hookrefs[1], 623 | TAI_MAIN_MODULE, 624 | TAI_ANY_LIBRARY, 625 | 0xA08CA60D, 626 | sceDisplayGetRefreshRate_patched); 627 | 628 | g_hooks[2] = taiHookFunctionImport( 629 | &g_hookrefs[2], 630 | TAI_MAIN_MODULE, 631 | TAI_ANY_LIBRARY, 632 | 0xB6FDE0BA, 633 | sceDisplayGetVcount_patched); 634 | 635 | g_hooks[3] = taiHookFunctionImport( 636 | &g_hookrefs[3], 637 | TAI_MAIN_MODULE, 638 | TAI_ANY_LIBRARY, 639 | 0x5795E898, 640 | sceDisplayWaitVblankStart_patched); 641 | 642 | g_hooks[4] = taiHookFunctionImport( 643 | &g_hookrefs[4], 644 | TAI_MAIN_MODULE, 645 | TAI_ANY_LIBRARY, 646 | 0x78B41B92, 647 | sceDisplayWaitVblankStartCB_patched); 648 | 649 | g_hooks[5] = taiHookFunctionImport( 650 | &g_hookrefs[5], 651 | TAI_MAIN_MODULE, 652 | TAI_ANY_LIBRARY, 653 | 0xDD0A13B8, 654 | sceDisplayWaitVblankStartMulti_patched); 655 | 656 | g_hooks[6] = taiHookFunctionImport( 657 | &g_hookrefs[6], 658 | TAI_MAIN_MODULE, 659 | TAI_ANY_LIBRARY, 660 | 0x05F27764, 661 | sceDisplayWaitVblankStartMultiCB_patched); 662 | 663 | g_hooks[7] = taiHookFunctionImport( 664 | &g_hookrefs[7], 665 | TAI_MAIN_MODULE, 666 | TAI_ANY_LIBRARY, 667 | 0x9423560C, 668 | sceDisplayWaitSetFrameBuf_patched); 669 | 670 | g_hooks[8] = taiHookFunctionImport( 671 | &g_hookrefs[8], 672 | TAI_MAIN_MODULE, 673 | TAI_ANY_LIBRARY, 674 | 0x814C90AF, 675 | sceDisplayWaitSetFrameBufCB_patched); 676 | 677 | g_hooks[9] = taiHookFunctionImport( 678 | &g_hookrefs[9], 679 | TAI_MAIN_MODULE, 680 | TAI_ANY_LIBRARY, 681 | 0x7D9864A8, 682 | sceDisplayWaitSetFrameBufMulti_patched); 683 | 684 | g_hooks[10] = taiHookFunctionImport( 685 | &g_hookrefs[10], 686 | TAI_MAIN_MODULE, 687 | TAI_ANY_LIBRARY, 688 | 0x3E796EF5, 689 | sceDisplayWaitSetFrameBufMultiCB_patched); 690 | 691 | g_hooks[11] = taiHookFunctionImport( 692 | &g_hookrefs[11], 693 | TAI_MAIN_MODULE, 694 | TAI_ANY_LIBRARY, 695 | 0x207AF96B, 696 | sceGxmCreateRenderTarget_patched); 697 | g_hooks[12] = taiHookFunctionImport( 698 | &g_hookrefs[12], 699 | TAI_MAIN_MODULE, 700 | TAI_ANY_LIBRARY, 701 | 0x0B94C50A, 702 | sceGxmDestroyRenderTarget_patched); 703 | 704 | g_hooks[22] = taiHookFunctionImport( 705 | &g_hookrefs[22], 706 | TAI_MAIN_MODULE, 707 | TAI_ANY_LIBRARY, 708 | 0xED0F6E25, 709 | sceGxmColorSurfaceInit_patched); 710 | 711 | g_hooks[25] = taiHookFunctionImport( 712 | &g_hookrefs[25], 713 | TAI_MAIN_MODULE, 714 | TAI_ANY_LIBRARY, 715 | 0xB0F1E4EC, 716 | sceGxmInitialize_patched); 717 | 718 | g_hooks[27] = taiHookFunctionImport( 719 | &g_hookrefs[27], 720 | TAI_MAIN_MODULE, 721 | TAI_ANY_LIBRARY, 722 | 0xCA9D41D1, 723 | sceGxmDepthStencilSurfaceInit_patched); 724 | 725 | g_hooks[28] = taiHookFunctionImport( 726 | &g_hookrefs[28], 727 | TAI_MAIN_MODULE, 728 | TAI_ANY_LIBRARY, 729 | 0xD572D547, 730 | sceGxmTextureInitSwizzled_patched); 731 | g_hooks[29] = taiHookFunctionImport( 732 | &g_hookrefs[29], 733 | TAI_MAIN_MODULE, 734 | TAI_ANY_LIBRARY, 735 | 0x4811AECB, 736 | sceGxmTextureInitLinear_patched); 737 | g_hooks[30] = taiHookFunctionImport( 738 | &g_hookrefs[30], 739 | TAI_MAIN_MODULE, 740 | TAI_ANY_LIBRARY, 741 | 0x6679BEF0, 742 | sceGxmTextureInitLinearStrided_patched); 743 | g_hooks[31] = taiHookFunctionImport( 744 | &g_hookrefs[31], 745 | TAI_MAIN_MODULE, 746 | TAI_ANY_LIBRARY, 747 | 0xE6F0DB27, 748 | sceGxmTextureInitTiled_patched); 749 | g_hooks[32] = taiHookFunctionImport( 750 | &g_hookrefs[32], 751 | TAI_MAIN_MODULE, 752 | TAI_ANY_LIBRARY, 753 | 0x11DC8DC9, 754 | sceGxmTextureInitCube_patched); 755 | } 756 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "osd.h" 5 | #include "main.h" 6 | 7 | #define VGi_VERSION "v0.7" 8 | 9 | #define HOOKS_NUM 35 10 | SceUID g_hooks[HOOKS_NUM] = {0}; 11 | tai_hook_ref_t g_hookrefs[HOOKS_NUM] = {0}; 12 | 13 | #define BUTTONS_FAST_MOVE_DELAY 500000 14 | uint8_t g_menuScroll = 0; 15 | uint8_t g_menuVisible = 0; 16 | uint8_t g_vsyncKillswitch = 0; 17 | static VGi_MenuSection g_menuSection = MENU_APP_INFO; 18 | static unsigned int g_buttonsPressed = 0; 19 | static SceUInt32 g_buttonsLastChange = 0; 20 | 21 | static void checkButtons() { 22 | SceCtrlData ctrl; 23 | sceCtrlPeekBufferPositive(0, &ctrl, 1); 24 | unsigned int buttons = ctrl.buttons & ~g_buttonsPressed; 25 | SceUInt32 time_now = sceKernelGetProcessTimeLow(); 26 | 27 | if (ctrl.buttons & SCE_CTRL_SELECT) { 28 | // Toggle menu 29 | if (buttons & SCE_CTRL_LTRIGGER) { 30 | g_menuVisible = !g_menuVisible; 31 | } 32 | } else if (g_menuVisible) { 33 | // Move between sections 34 | if (buttons & SCE_CTRL_LTRIGGER) { 35 | if (g_menuSection > MENU_APP_INFO) { 36 | g_menuSection--; 37 | g_menuScroll = 0; 38 | } 39 | } else if (buttons & SCE_CTRL_RTRIGGER) { 40 | if (g_menuSection < MENU_MAX - 1) { 41 | g_menuSection++; 42 | g_menuScroll = 0; 43 | } 44 | } else if (buttons & SCE_CTRL_UP) { 45 | if (g_menuScroll > 0) 46 | g_menuScroll--; 47 | g_buttonsLastChange = time_now; 48 | } else if (buttons & SCE_CTRL_DOWN) { 49 | if (g_menuScroll < 255) 50 | g_menuScroll++; 51 | g_buttonsLastChange = time_now; 52 | } 53 | // Fast scroll UP 54 | else if (ctrl.buttons & SCE_CTRL_UP && 55 | time_now - g_buttonsLastChange > BUTTONS_FAST_MOVE_DELAY) { 56 | if (g_menuScroll > 0) 57 | g_menuScroll--; 58 | } 59 | // Fast scroll DOWN 60 | else if (ctrl.buttons & SCE_CTRL_DOWN && 61 | time_now - g_buttonsLastChange > BUTTONS_FAST_MOVE_DELAY) { 62 | if (g_menuScroll < 255) 63 | g_menuScroll++; 64 | } 65 | } 66 | 67 | // Vsync Killswitch 68 | if (g_menuVisible && g_menuSection == MENU_GRAPHICS) { 69 | if (buttons & SCE_CTRL_CIRCLE) { 70 | if (g_vsyncKillswitch < 2) 71 | g_vsyncKillswitch++; 72 | else 73 | g_vsyncKillswitch = 0; 74 | } 75 | } 76 | 77 | g_buttonsPressed = ctrl.buttons; 78 | } 79 | 80 | static void drawNextSectionIndicator(const SceDisplayFrameBuf *pParam, const char *L, const char *R) { 81 | char buf[64]; 82 | 83 | snprintf(buf, 64, "%s%s", strlen(L) > 0 ? "< " : "", L); 84 | osdDrawStringF(5, pParam->height - 22 - 5, "%s", buf); 85 | 86 | snprintf(buf, 64, "%s%s", R, strlen(R) > 0 ? " >" : ""); 87 | osdDrawStringF(pParam->width - osdGetTextWidth(buf) - 5, pParam->height - 22 - 5, "%s", buf); 88 | } 89 | 90 | static int sceDisplaySetFrameBuf_patched(const SceDisplayFrameBuf *pParam, int sync) { 91 | 92 | // Check for pressed buttons 93 | checkButtons(); 94 | 95 | if (!g_menuVisible) 96 | goto CONT; 97 | 98 | osdUpdateFrameBuf(pParam); 99 | 100 | // BG 101 | osdSetBgColor(0, 0, 0, 225); 102 | osdFastDrawRectangle(0, 0, pParam->width, pParam->height); 103 | 104 | // Watermark 105 | osdSetBgColor(0, 0, 0, 0); 106 | osdSetTextColor(10, 20, 50, 255); 107 | osdSetTextScale(pParam->width == 640 ? 3 : 5); 108 | osdDrawStringF(0, pParam->height - 115, "VGi %s", VGi_VERSION); 109 | osdSetTextScale(2); 110 | osdDrawStringF(pParam->width - osdGetTextWidth("by Electry"), pParam->height - 71, "by Electry"); 111 | 112 | // Section content 113 | osdSetTextColor(255, 255, 255, 255); 114 | 115 | switch (g_menuSection) { 116 | case MENU_APP_INFO: 117 | drawAppInfoMenu(pParam); 118 | drawNextSectionIndicator(pParam, "", MENU_TITLE_GRAPHICS); 119 | break; 120 | case MENU_GRAPHICS: 121 | drawGraphicsMenu(pParam); 122 | drawNextSectionIndicator(pParam, MENU_TITLE_APP_INFO, MENU_TITLE_GRAPHICS_2); 123 | break; 124 | case MENU_GRAPHICS_2: 125 | drawGraphics2Menu(pParam); 126 | drawNextSectionIndicator(pParam, MENU_TITLE_GRAPHICS, MENU_TITLE_GRAPHICS_3); 127 | break; 128 | case MENU_GRAPHICS_3: 129 | drawGraphics3Menu(pParam); 130 | drawNextSectionIndicator(pParam, MENU_TITLE_GRAPHICS_2, MENU_TITLE_GRAPHICS_4); 131 | break; 132 | case MENU_GRAPHICS_4: 133 | drawGraphics4Menu(pParam); 134 | drawNextSectionIndicator(pParam, MENU_TITLE_GRAPHICS_3, MENU_TITLE_GRAPHICS_5); 135 | break; 136 | case MENU_GRAPHICS_5: 137 | drawGraphics5Menu(pParam); 138 | drawNextSectionIndicator(pParam, MENU_TITLE_GRAPHICS_4, MENU_TITLE_MEMORY); 139 | break; 140 | case MENU_MEMORY: 141 | drawMemoryMenu(pParam); 142 | drawNextSectionIndicator(pParam, MENU_TITLE_GRAPHICS_5, MENU_TITLE_THREADS); 143 | break; 144 | case MENU_THREADS: 145 | drawThreadsMenu(pParam); 146 | drawNextSectionIndicator(pParam, MENU_TITLE_MEMORY, MENU_TITLE_MISC); 147 | break; 148 | case MENU_MISC: 149 | drawMiscMenu(pParam); 150 | drawNextSectionIndicator(pParam, MENU_TITLE_THREADS, MENU_TITLE_DEVICE); 151 | break; 152 | case MENU_DEVICE: 153 | drawDeviceMenu(pParam); 154 | drawNextSectionIndicator(pParam, MENU_TITLE_MISC, ""); 155 | break; 156 | case MENU_MAX: 157 | break; 158 | } 159 | 160 | sceDisplayWaitSetFrameBufMulti(4); 161 | CONT: 162 | return TAI_CONTINUE(int, g_hookrefs[0], pParam, sync); 163 | } 164 | 165 | void _start() __attribute__ ((weak, alias ("module_start"))); 166 | int module_start(SceSize argc, const void *args) { 167 | 168 | g_hooks[0] = taiHookFunctionImport( 169 | &g_hookrefs[0], 170 | TAI_MAIN_MODULE, 171 | TAI_ANY_LIBRARY, 172 | 0x7A410B64, 173 | sceDisplaySetFrameBuf_patched); 174 | 175 | // Setup hooks, etc... 176 | setupAppInfoMenu(); 177 | setupGraphicsMenu(); 178 | setupMemoryMenu(); 179 | setupThreadsMenu(); 180 | setupMiscMenu(); 181 | setupDeviceMenu(); 182 | 183 | return SCE_KERNEL_START_SUCCESS; 184 | } 185 | 186 | int module_stop(SceSize argc, const void *args) { 187 | 188 | // Release all hooks 189 | for (int i = 0; i < HOOKS_NUM; i++) { 190 | if (g_hooks[i] >= 0) 191 | taiHookRelease(g_hooks[i], g_hookrefs[i]); 192 | } 193 | 194 | return SCE_KERNEL_STOP_SUCCESS; 195 | } 196 | -------------------------------------------------------------------------------- /main.h: -------------------------------------------------------------------------------- 1 | #ifndef _MAIN_H_ 2 | #define _MAIN_H_ 3 | 4 | #define MENU_TITLE_APP_INFO "App Info" 5 | #define MENU_TITLE_GRAPHICS "Graphics" 6 | #define MENU_TITLE_GRAPHICS_2 "Render Targets" 7 | #define MENU_TITLE_GRAPHICS_3 "Color Surfaces" 8 | #define MENU_TITLE_GRAPHICS_4 "Depth/Stencil Surfaces" 9 | #define MENU_TITLE_GRAPHICS_5 "Textures" 10 | #define MENU_TITLE_MEMORY "Memory" 11 | #define MENU_TITLE_THREADS "Threads" 12 | #define MENU_TITLE_MISC "Misc" 13 | #define MENU_TITLE_DEVICE "Device" 14 | 15 | typedef enum { 16 | MENU_APP_INFO, 17 | MENU_GRAPHICS, 18 | MENU_GRAPHICS_2, 19 | MENU_GRAPHICS_3, 20 | MENU_GRAPHICS_4, 21 | MENU_GRAPHICS_5, 22 | MENU_MEMORY, 23 | MENU_THREADS, 24 | MENU_MISC, 25 | MENU_DEVICE, 26 | MENU_MAX 27 | } VGi_MenuSection; 28 | 29 | extern uint8_t g_menuScroll; 30 | extern uint8_t g_menuVisible; 31 | extern uint8_t g_vsyncKillswitch; 32 | 33 | extern SceUID g_hooks[]; 34 | extern tai_hook_ref_t g_hookrefs[]; 35 | 36 | void setupAppInfoMenu(); 37 | void drawAppInfoMenu(const SceDisplayFrameBuf *pParam); 38 | 39 | void setupGraphicsMenu(); 40 | void drawGraphicsMenu(const SceDisplayFrameBuf *pParam); 41 | void drawGraphics2Menu(const SceDisplayFrameBuf *pParam); 42 | void drawGraphics3Menu(const SceDisplayFrameBuf *pParam); 43 | void drawGraphics4Menu(const SceDisplayFrameBuf *pParam); 44 | void drawGraphics5Menu(const SceDisplayFrameBuf *pParam); 45 | 46 | void setupMemoryMenu(); 47 | void drawMemoryMenu(const SceDisplayFrameBuf *pParam); 48 | 49 | void setupThreadsMenu(); 50 | void drawThreadsMenu(const SceDisplayFrameBuf *pParam); 51 | 52 | void setupMiscMenu(); 53 | void drawMiscMenu(const SceDisplayFrameBuf *pParam); 54 | 55 | void setupDeviceMenu(); 56 | void drawDeviceMenu(const SceDisplayFrameBuf *pParam); 57 | 58 | #define MIN(a,b) (((a)<(b))?(a):(b)) 59 | #define MAX(a,b) (((a)>(b))?(a):(b)) 60 | 61 | #define SCE_POWER_CONFIGURATION_MODE_A 0x00000080U 62 | #define SCE_POWER_CONFIGURATION_MODE_B 0x00000800U 63 | #define SCE_POWER_CONFIGURATION_MODE_C 0x00010880U 64 | 65 | int snprintf(char *s, size_t n, const char *format, ...); 66 | 67 | #endif -------------------------------------------------------------------------------- /memory.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "osd.h" 5 | #include "main.h" 6 | 7 | #define MAX_MEM_BLOCKS 64 8 | 9 | typedef struct { 10 | uint8_t active; 11 | char name[128]; 12 | SceKernelMemBlockType type; 13 | int size; 14 | void *optp; 15 | SceUID ret; 16 | void *base; 17 | } VGi_MemBlock; 18 | 19 | static VGi_MemBlock g_memBlocks[MAX_MEM_BLOCKS] = {0}; 20 | static uint32_t g_memBlocksCount = 0; 21 | 22 | static SceUID sceKernelAllocMemBlock_patched(const char *name, SceKernelMemBlockType type, int size, void *optp) { 23 | int ret = TAI_CONTINUE(SceUID, g_hookrefs[23], name, type, size, optp); 24 | 25 | for (int i = 0; i < MAX_MEM_BLOCKS; i++) { 26 | if (!g_memBlocks[i].active) { 27 | g_memBlocks[i].active = 1; 28 | strncpy(g_memBlocks[i].name, name, 128); 29 | g_memBlocks[i].type = type; 30 | g_memBlocks[i].size = size; 31 | g_memBlocks[i].ret = ret; 32 | sceKernelGetMemBlockBase(ret, &(g_memBlocks[i].base)); 33 | goto RET; 34 | } 35 | } 36 | 37 | RET: 38 | g_memBlocksCount++; 39 | return ret; 40 | } 41 | 42 | static int sceKernelFreeMemBlock_patched(SceUID uid) { 43 | 44 | for (int i = 0; i < MAX_MEM_BLOCKS; i++) { 45 | if (g_memBlocks[i].active && g_memBlocks[i].ret == uid) { 46 | g_memBlocks[i].active = 0; 47 | goto RET; 48 | } 49 | } 50 | 51 | RET: 52 | g_memBlocksCount--; 53 | return TAI_CONTINUE(int, g_hookrefs[24], uid); 54 | } 55 | 56 | 57 | const char *getMemBlockTypeString(SceKernelMemBlockType type) { 58 | switch (type) { 59 | case SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE: 60 | return "UNCACHE"; 61 | case SCE_KERNEL_MEMBLOCK_TYPE_USER_RW: 62 | return "RW"; 63 | case SCE_KERNEL_MEMBLOCK_TYPE_USER_MAIN_PHYCONT_RW: 64 | return "PHYCONT"; 65 | case SCE_KERNEL_MEMBLOCK_TYPE_USER_MAIN_PHYCONT_NC_RW: 66 | return "PHY_NC"; 67 | case SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW: 68 | return "CDRAM"; 69 | default: 70 | return "?"; 71 | } 72 | } 73 | 74 | void formatReadableSize(int bytes, char *out, size_t out_size) { 75 | if (bytes > 1024*1024) { 76 | snprintf(out, out_size, "%3d %s", bytes / 1024 / 1024, "MB"); 77 | } else if (bytes > 1024) { 78 | snprintf(out, out_size, "%3d %s", bytes / 1024, "kB"); 79 | } else { 80 | snprintf(out, out_size, "%3d %s", bytes, "B"); 81 | } 82 | } 83 | 84 | void drawMemoryMenu(const SceDisplayFrameBuf *pParam) { 85 | osdSetTextScale(2); 86 | osdDrawStringF((pParam->width / 2) - osdGetTextWidth(MENU_TITLE_MEMORY) / 2, 5, MENU_TITLE_MEMORY); 87 | 88 | osdSetTextScale(1); 89 | 90 | SceKernelFreeMemorySizeInfo info; 91 | info.size = sizeof(SceKernelFreeMemorySizeInfo); 92 | sceKernelGetFreeMemorySize(&info); 93 | 94 | char buf[32]; 95 | formatReadableSize(info.size_user, buf, 32); 96 | osdDrawStringF(10, 60, "Free RAM: %s", buf); 97 | formatReadableSize(info.size_cdram, buf, 32); 98 | osdDrawStringF(10, 82, "Free VRAM: %s", buf); 99 | formatReadableSize(info.size_phycont, buf, 32); 100 | osdDrawStringF(10, 104, "Free phycont: %s", buf); 101 | 102 | // Header 103 | osdDrawStringF(pParam->width - 398, 104, "Allocated MemBlocks (%d):", g_memBlocksCount); 104 | if (g_memBlocksCount > MAX_MEM_BLOCKS) { 105 | char buf[32]; 106 | snprintf(buf, 32, "!! > %d", MAX_MEM_BLOCKS); 107 | osdDrawStringF(pParam->width - osdGetTextWidth(buf), 104, buf); 108 | } 109 | osdDrawStringF(30, 148, " type UID base size"); 110 | 111 | // Scrollable section 112 | int x = 30, y = 165; 113 | 114 | if (g_menuScroll > 0) { 115 | // Draw scroll indicator 116 | osdDrawStringF(pParam->width - 24 - 5, y + 22, "/\\"); 117 | osdDrawStringF(pParam->width - 24 - 5, y + 44, "%2d", g_menuScroll); 118 | } 119 | 120 | for (int i = g_menuScroll; i < MAX_MEM_BLOCKS; i++) { 121 | // Draw only active blocks 122 | if (g_memBlocks[i].active) { 123 | formatReadableSize(g_memBlocks[i].size, buf, 32); 124 | osdDrawStringF(x, y += 27, "'%s'", g_memBlocks[i].name); 125 | osdDrawStringF(pParam->width - osdGetTextWidth(buf) - 40, y, "%s", buf); 126 | osdDrawStringF(x + 24, y += 22, "%-9s 0x%-10X 0x%-10X %d B", 127 | getMemBlockTypeString(g_memBlocks[i].type), 128 | g_memBlocks[i].ret, 129 | g_memBlocks[i].base, 130 | g_memBlocks[i].size); 131 | } 132 | 133 | // Do not draw out of screen 134 | if (y > pParam->height - 94) { 135 | // Draw scroll indicator 136 | osdDrawStringF(pParam->width - 24 - 5, pParam->height - 72, "%2d", MIN(g_memBlocksCount, MAX_MEM_BLOCKS) - i); 137 | osdDrawStringF(pParam->width - 24 - 5, pParam->height - 50, "\\/"); 138 | break; 139 | } 140 | } 141 | } 142 | 143 | void setupMemoryMenu() { 144 | 145 | g_hooks[23] = taiHookFunctionImport( 146 | &g_hookrefs[23], 147 | TAI_MAIN_MODULE, 148 | TAI_ANY_LIBRARY, 149 | 0xB9D5EBDE, 150 | sceKernelAllocMemBlock_patched); 151 | 152 | g_hooks[24] = taiHookFunctionImport( 153 | &g_hookrefs[24], 154 | TAI_MAIN_MODULE, 155 | TAI_ANY_LIBRARY, 156 | 0xA91E15EE, 157 | sceKernelFreeMemBlock_patched); 158 | } 159 | -------------------------------------------------------------------------------- /misc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "osd.h" 5 | #include "main.h" 6 | 7 | static uint8_t sceCtrlPeekBufferPositive_used = 0; 8 | static uint8_t sceCtrlPeekBufferNegative_used = 0; 9 | static uint8_t sceCtrlReadBufferPositive_used = 0; 10 | static uint8_t sceCtrlReadBufferNegative_used = 0; 11 | 12 | static uint8_t sceMotionGetState_used = 0; 13 | static uint8_t sceMotionGetSensorState_used = 0; 14 | static uint8_t sceMotionGetBasicOrientation_used = 0; 15 | 16 | static uint8_t sceTouchPeek_front = 0; 17 | static uint8_t sceTouchPeek_back = 0; 18 | static uint8_t sceTouchRead_front = 0; 19 | static uint8_t sceTouchRead_back = 0; 20 | 21 | static int sceCtrlPeekBufferPositive_patched(int port, SceCtrlData *pad_data, int count) { 22 | int ret = TAI_CONTINUE(int, g_hookrefs[13], port, pad_data, count); 23 | sceCtrlPeekBufferPositive_used = 1; 24 | 25 | if (g_menuVisible && pad_data) 26 | pad_data->buttons = 0; 27 | 28 | return ret; 29 | } 30 | static int sceCtrlPeekBufferNegative_patched(int port, SceCtrlData *pad_data, int count) { 31 | int ret = TAI_CONTINUE(int, g_hookrefs[14], port, pad_data, count); 32 | sceCtrlPeekBufferNegative_used = 1; 33 | 34 | if (g_menuVisible && pad_data) 35 | pad_data->buttons = 0; 36 | 37 | return ret; 38 | } 39 | static int sceCtrlReadBufferPositive_patched(int port, SceCtrlData *pad_data, int count) { 40 | int ret = TAI_CONTINUE(int, g_hookrefs[15], port, pad_data, count); 41 | sceCtrlReadBufferPositive_used = 1; 42 | 43 | if (g_menuVisible && pad_data) 44 | pad_data->buttons = 0; 45 | 46 | return ret; 47 | } 48 | static int sceCtrlReadBufferNegative_patched(int port, SceCtrlData *pad_data, int count) { 49 | int ret = TAI_CONTINUE(int, g_hookrefs[16], port, pad_data, count); 50 | sceCtrlReadBufferNegative_used = 1; 51 | 52 | if (g_menuVisible && pad_data) 53 | pad_data->buttons = 0; 54 | 55 | return ret; 56 | } 57 | 58 | static int sceMotionGetState_patched(SceMotionState *motionState) { 59 | sceMotionGetState_used = 1; 60 | return TAI_CONTINUE(int, g_hookrefs[17], motionState); 61 | } 62 | static int sceMotionGetSensorState_patched(SceMotionSensorState *sensorState, int numRecords) { 63 | sceMotionGetSensorState_used = 1; 64 | return TAI_CONTINUE(int, g_hookrefs[18], sensorState, numRecords); 65 | } 66 | static int sceMotionGetBasicOrientation_patched(SceFVector3 *basicOrientation) { 67 | sceMotionGetBasicOrientation_used = 1; 68 | return TAI_CONTINUE(int, g_hookrefs[19], basicOrientation); 69 | } 70 | 71 | static int sceTouchPeek_patched(SceUInt32 port, SceTouchData *pData, SceUInt32 nBufs) { 72 | int ret = TAI_CONTINUE(int, g_hookrefs[20], port, pData, nBufs); 73 | if (port == SCE_TOUCH_PORT_FRONT) { 74 | sceTouchPeek_front = 1; 75 | } else if (port == SCE_TOUCH_PORT_BACK) { 76 | sceTouchPeek_back = 1; 77 | } 78 | 79 | if (g_menuVisible && pData) { 80 | pData->reportNum = 0; 81 | memset(pData->report, 0, sizeof(SceTouchReport) * SCE_TOUCH_MAX_REPORT); 82 | } 83 | 84 | return ret; 85 | } 86 | static int sceTouchRead_patched(SceUInt32 port, SceTouchData *pData, SceUInt32 nBufs) { 87 | int ret = TAI_CONTINUE(int, g_hookrefs[21], port, pData, nBufs); 88 | if (port == SCE_TOUCH_PORT_FRONT) { 89 | sceTouchRead_front = 1; 90 | } else if (port == SCE_TOUCH_PORT_BACK) { 91 | sceTouchRead_back = 1; 92 | } 93 | 94 | if (g_menuVisible && pData) { 95 | pData->reportNum = 0; 96 | memset(pData->report, 0, sizeof(SceTouchReport) * SCE_TOUCH_MAX_REPORT); 97 | } 98 | 99 | return ret; 100 | } 101 | 102 | void drawMiscMenu(const SceDisplayFrameBuf *pParam) { 103 | osdSetTextScale(2); 104 | osdDrawStringF((pParam->width / 2) - osdGetTextWidth(MENU_TITLE_MISC) / 2, 5, MENU_TITLE_MISC); 105 | 106 | osdSetTextScale(1); 107 | osdDrawStringF(10, 60, "Input handlers:"); 108 | int x = 30, y = 82; 109 | if (sceCtrlPeekBufferPositive_used) 110 | osdDrawStringF(x, y += 22, "sceCtrlPeekBufferPositive()"); 111 | if (sceCtrlPeekBufferNegative_used) 112 | osdDrawStringF(x, y += 22, "sceCtrlPeekBufferNegative()"); 113 | if (sceCtrlReadBufferPositive_used) 114 | osdDrawStringF(x, y += 22, "sceCtrlReadBufferPositive()"); 115 | if (sceCtrlReadBufferNegative_used) 116 | osdDrawStringF(x, y += 22, "sceCtrlReadBufferNegative()"); 117 | if (sceMotionGetState_used) 118 | osdDrawStringF(x, y += 22, "sceMotionGetState()"); 119 | if (sceMotionGetSensorState_used) 120 | osdDrawStringF(x, y += 22, "sceMotionGetSensorState()"); 121 | if (sceMotionGetBasicOrientation_used) 122 | osdDrawStringF(x, y += 22, "sceMotionGetBasicOrientation()"); 123 | if (sceTouchPeek_front) 124 | osdDrawStringF(x, y += 22, "sceTouchPeek( FRONT )"); 125 | if (sceTouchPeek_back) 126 | osdDrawStringF(x, y += 22, "sceTouchPeek( BACK )"); 127 | if (sceTouchRead_front) 128 | osdDrawStringF(x, y += 22, "sceTouchRead( FRONT )"); 129 | if (sceTouchRead_back) 130 | osdDrawStringF(x, y += 22, "sceTouchRead( BACK )"); 131 | } 132 | 133 | void setupMiscMenu() { 134 | 135 | g_hooks[13] = taiHookFunctionImport( 136 | &g_hookrefs[13], 137 | TAI_MAIN_MODULE, 138 | TAI_ANY_LIBRARY, 139 | 0xA9C3CED6, 140 | sceCtrlPeekBufferPositive_patched); 141 | g_hooks[14] = taiHookFunctionImport( 142 | &g_hookrefs[14], 143 | TAI_MAIN_MODULE, 144 | TAI_ANY_LIBRARY, 145 | 0x104ED1A7, 146 | sceCtrlPeekBufferNegative_patched); 147 | g_hooks[15] = taiHookFunctionImport( 148 | &g_hookrefs[15], 149 | TAI_MAIN_MODULE, 150 | TAI_ANY_LIBRARY, 151 | 0x67E7AB83, 152 | sceCtrlReadBufferPositive_patched); 153 | g_hooks[16] = taiHookFunctionImport( 154 | &g_hookrefs[16], 155 | TAI_MAIN_MODULE, 156 | TAI_ANY_LIBRARY, 157 | 0x15F96FB0, 158 | sceCtrlReadBufferNegative_patched); 159 | 160 | g_hooks[17] = taiHookFunctionImport( 161 | &g_hookrefs[17], 162 | TAI_MAIN_MODULE, 163 | TAI_ANY_LIBRARY, 164 | 0xBDB32767, 165 | sceMotionGetState_patched); 166 | g_hooks[18] = taiHookFunctionImport( 167 | &g_hookrefs[18], 168 | TAI_MAIN_MODULE, 169 | TAI_ANY_LIBRARY, 170 | 0x47D679EA, 171 | sceMotionGetSensorState_patched); 172 | g_hooks[19] = taiHookFunctionImport( 173 | &g_hookrefs[19], 174 | TAI_MAIN_MODULE, 175 | TAI_ANY_LIBRARY, 176 | 0x4F28BFE0, 177 | sceMotionGetBasicOrientation_patched); 178 | 179 | g_hooks[20] = taiHookFunctionImport( 180 | &g_hookrefs[20], 181 | TAI_MAIN_MODULE, 182 | TAI_ANY_LIBRARY, 183 | 0xFF082DF0, 184 | sceTouchPeek_patched); 185 | g_hooks[21] = taiHookFunctionImport( 186 | &g_hookrefs[21], 187 | TAI_MAIN_MODULE, 188 | TAI_ANY_LIBRARY, 189 | 0x169A1D58, 190 | sceTouchRead_patched); 191 | } 192 | -------------------------------------------------------------------------------- /osd.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "osd.h" 4 | #include "osd_font.h" 5 | 6 | #define OSD_MAX_STRING_LENGTH 512 7 | 8 | static SceDisplayFrameBuf g_framebuf; 9 | static uint8_t g_font_scale = 1; 10 | 11 | static RGBA g_color_text = {.rgba = {255, 255, 255, 255}}; 12 | static RGBA g_color_bg = {.rgba = { 0, 0, 0, 255}}; 13 | 14 | RGBA osdBlendColor(RGBA fg, RGBA bg) { 15 | uint8_t inv_alpha = 255 - fg.rgba.a; 16 | 17 | RGBA result; 18 | result.rgba.b = ((fg.rgba.a * fg.rgba.b + inv_alpha * bg.rgba.b) >> 8); // B 19 | result.rgba.g = ((fg.rgba.a * fg.rgba.g + inv_alpha * bg.rgba.g) >> 8); // G 20 | result.rgba.r = ((fg.rgba.a * fg.rgba.r + inv_alpha * bg.rgba.r) >> 8); // R 21 | result.rgba.a = 0xFF; // A 22 | return result; 23 | } 24 | 25 | void osdUpdateFrameBuf(const SceDisplayFrameBuf *pParam) { 26 | memcpy(&g_framebuf, pParam, sizeof(SceDisplayFrameBuf)); 27 | } 28 | 29 | void osdSetTextColor(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { 30 | g_color_text.rgba.r = r; 31 | g_color_text.rgba.g = g; 32 | g_color_text.rgba.b = b; 33 | g_color_text.rgba.a = a; 34 | } 35 | void osdSetBgColor(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { 36 | g_color_bg.rgba.r = r; 37 | g_color_bg.rgba.g = g; 38 | g_color_bg.rgba.b = b; 39 | g_color_bg.rgba.a = a; 40 | } 41 | 42 | void osdSetTextScale(uint8_t scale) { 43 | g_font_scale = scale; 44 | } 45 | 46 | uint32_t osdGetTextWidth(const char *str) { 47 | return strlen(str) * FONT_WIDTH * g_font_scale; 48 | } 49 | 50 | /** 51 | * Draws alpha-blended rectangle over the whole screen 52 | */ 53 | void osdClearScreen() { 54 | if (g_color_bg.rgba.a == 255) { 55 | // Faster 56 | memset(g_framebuf.base, g_color_bg.uint32, 57 | sizeof(uint32_t) * (g_framebuf.pitch * g_framebuf.height)); 58 | return; 59 | } 60 | 61 | osdDrawRectangle(0, 0, g_framebuf.width, g_framebuf.height); 62 | } 63 | 64 | /** 65 | * Draws alpha-blended rectangle at 1/4 res. 66 | */ 67 | void osdFastDrawRectangle(int x, int y, int width, int height) { 68 | if (g_color_bg.rgba.a == 0 || g_color_bg.rgba.a == 255) { 69 | osdDrawRectangle(x, y, width, height); 70 | } 71 | 72 | for (int yy = y; yy < y + height; yy += 2) { 73 | for (int xx = x; xx < x + width; xx += 2) { 74 | RGBA *pixelRGB = (RGBA *)g_framebuf.base + yy * g_framebuf.pitch + xx; 75 | RGBA newColor = osdBlendColor(g_color_bg, *pixelRGB); 76 | *pixelRGB = newColor; 77 | *(pixelRGB + 1) = newColor; 78 | *(pixelRGB + g_framebuf.pitch) = newColor; 79 | *(pixelRGB + g_framebuf.pitch + 1) = newColor; 80 | } 81 | } 82 | } 83 | 84 | /** 85 | * Draws alpha-blended rectangle 86 | */ 87 | void osdDrawRectangle(int x, int y, int width, int height) { 88 | if (g_color_bg.rgba.a == 0) 89 | return; 90 | 91 | if (g_color_bg.rgba.a == 255) { 92 | for (int yy = y; yy < y + height; yy++) { 93 | memset((uint32_t *)g_framebuf.base + (yy + y) * g_framebuf.pitch + x, 94 | g_color_bg.uint32, 95 | sizeof(uint32_t) * width); 96 | } 97 | return; 98 | } 99 | 100 | for (int yy = y; yy < y + height; yy++) { 101 | for (int xx = x; xx < x + width; xx++) { 102 | RGBA *pixelRGB = (RGBA *)g_framebuf.base + yy * g_framebuf.pitch + xx; 103 | *pixelRGB = osdBlendColor(g_color_bg, *pixelRGB); 104 | } 105 | } 106 | } 107 | 108 | /** 109 | * Draws single character 110 | */ 111 | void osdDrawCharacter(const char character, int x, int y) { 112 | for (int yy = 0; yy < FONT_HEIGHT * g_font_scale; yy++) { 113 | int yy_font = yy / g_font_scale; 114 | uint32_t displacement = x + (y + yy) * g_framebuf.pitch; 115 | RGBA *screenRGB = (RGBA *)g_framebuf.base + displacement; 116 | 117 | if (displacement >= g_framebuf.pitch * g_framebuf.height) 118 | return; // out of bounds 119 | 120 | for (int xx = 0; xx < FONT_WIDTH * g_font_scale; xx++) { 121 | if (x + xx >= g_framebuf.width) 122 | return; // out of bounds 123 | 124 | // Get px 0/1 from osd_font.h 125 | int xx_font = xx / g_font_scale; 126 | uint32_t charPos = character * (FONT_HEIGHT * ((FONT_WIDTH / 8) + 1)); 127 | uint32_t charPosH = charPos + (yy_font * ((FONT_WIDTH / 8) + 1)); 128 | uint8_t charByte = g_font[charPosH + (xx_font / 8)]; 129 | RGBA clr = ((charByte >> (7 - (xx_font % 8))) & 1) ? g_color_text : g_color_bg; 130 | 131 | if (clr.rgba.a) { // alpha != 0 132 | if (clr.rgba.a != 0xFF) { // alpha < 255 133 | *(screenRGB + xx) = osdBlendColor(clr, *(screenRGB + xx)); // blend FG/BG color 134 | } else { 135 | *(screenRGB + xx) = clr; 136 | } 137 | } 138 | } 139 | } 140 | } 141 | 142 | /** 143 | * Draws string 144 | */ 145 | void osdDrawString(int x, int y, const char *str) { 146 | for (size_t i = 0; i < strlen(str); i++) 147 | osdDrawCharacter(str[i], x + i * FONT_WIDTH * g_font_scale, y); 148 | } 149 | 150 | /** 151 | * Draws formatted string 152 | */ 153 | void osdDrawStringF(int x, int y, const char *format, ...) { 154 | char buffer[OSD_MAX_STRING_LENGTH] = ""; 155 | va_list va; 156 | 157 | va_start(va, format); 158 | vsnprintf(buffer, OSD_MAX_STRING_LENGTH, format, va); 159 | va_end(va); 160 | 161 | osdDrawString(x, y, buffer); 162 | } 163 | -------------------------------------------------------------------------------- /osd.h: -------------------------------------------------------------------------------- 1 | #ifndef _OSD_H_ 2 | #define _OSD_H_ 3 | 4 | typedef union { 5 | struct { 6 | uint8_t r; 7 | uint8_t g; 8 | uint8_t b; 9 | uint8_t a; 10 | } rgba; 11 | uint32_t uint32; 12 | } RGBA; 13 | 14 | int vsnprintf(char *s, size_t n, const char *format, va_list arg); 15 | 16 | 17 | void osdUpdateFrameBuf(const SceDisplayFrameBuf *param); 18 | void osdSetBgColor(uint8_t r, uint8_t g, uint8_t b, uint8_t a); 19 | void osdSetTextColor(uint8_t r, uint8_t g, uint8_t b, uint8_t a); 20 | void osdSetTextScale(uint8_t scale); 21 | 22 | uint32_t osdGetTextWidth(const char *str); 23 | 24 | void osdClearScreen(); 25 | void osdDrawLogo(int x, int y); 26 | void osdDrawRectangle(int x, int y, int width, int height); 27 | void osdFastDrawRectangle(int x, int y, int width, int height); 28 | 29 | void osdDrawCharacter(const char character, int x, int y); 30 | void osdDrawString(int x, int y, const char *str); 31 | void osdDrawStringF(int x, int y, const char *format, ...); 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /threads.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "osd.h" 5 | #include "main.h" 6 | 7 | #define MAX_THREADS 64 8 | 9 | typedef struct { 10 | SceUID id; 11 | } VGi_Thread; 12 | 13 | static VGi_Thread g_threads[MAX_THREADS] = {0}; 14 | static uint32_t g_threadsCount = 0; 15 | 16 | static SceUID sceKernelCreateThread_patched( 17 | const char *name, SceKernelThreadEntry entry, int initPriority, 18 | int stackSize, SceUInt attr, int cpuAffinityMask, 19 | const SceKernelThreadOptParam *option) { 20 | int ret = TAI_CONTINUE(SceUID, g_hookrefs[33], name, entry, 21 | initPriority, stackSize, attr, cpuAffinityMask, option); 22 | 23 | for (int i = 0; i < MAX_THREADS; i++) { 24 | if (!g_threads[i].id) { 25 | g_threads[i].id = ret; 26 | goto RET; 27 | } 28 | } 29 | 30 | RET: 31 | g_threadsCount++; 32 | return ret; 33 | } 34 | 35 | static int sceKernelDeleteThread_patched(SceUID thid) { 36 | 37 | for (int i = 0; i < MAX_THREADS; i++) { 38 | if (g_threads[i].id == thid) { 39 | g_threads[i].id = 0; 40 | goto RET; 41 | } 42 | } 43 | 44 | RET: 45 | g_threadsCount--; 46 | return TAI_CONTINUE(int, g_hookrefs[34], thid); 47 | } 48 | 49 | void drawThreadsMenu(const SceDisplayFrameBuf *pParam) { 50 | osdSetTextScale(2); 51 | osdDrawStringF((pParam->width / 2) - osdGetTextWidth(MENU_TITLE_THREADS) / 2, 5, MENU_TITLE_THREADS); 52 | 53 | osdSetTextScale(1); 54 | 55 | // Header 56 | osdDrawStringF(10, 60, "Threads (%d):", g_threadsCount); 57 | if (g_threadsCount > MAX_THREADS) { 58 | char buf[32]; 59 | snprintf(buf, 32, "!! > %d", MAX_THREADS); 60 | osdDrawStringF(pParam->width - osdGetTextWidth(buf), 60, buf); 61 | } 62 | osdDrawStringF(30, 90, " thid entry stack priority affinity"); 63 | 64 | // Scrollable section 65 | int x = 30, y = 107; 66 | 67 | if (g_menuScroll > 0) { 68 | // Draw scroll indicator 69 | osdDrawStringF(pParam->width - 24 - 5, y + 22, "/\\"); 70 | osdDrawStringF(pParam->width - 24 - 5, y + 44, "%2d", g_menuScroll); 71 | } 72 | 73 | SceKernelThreadInfo info; 74 | info.size = sizeof(SceKernelThreadInfo); 75 | 76 | for (int i = g_menuScroll; i < MAX_THREADS; i++) { 77 | if (g_threads[i].id && !sceKernelGetThreadInfo(g_threads[i].id, &info)) { 78 | osdDrawStringF(x, y += 27, "'%s' (%d)", info.name, info.status); 79 | osdDrawStringF(x + 24, y += 22, "0x%-10X 0x%-10X 0x%08X [0x%06X] 0x%-6X 0x%-10X", 80 | g_threads[i].id, 81 | info.entry, 82 | info.stack, 83 | info.stackSize, 84 | info.currentPriority, 85 | info.currentCpuAffinityMask); 86 | } 87 | 88 | // Do not draw out of screen 89 | if (y > pParam->height - 94) { 90 | // Draw scroll indicator 91 | osdDrawStringF(pParam->width - 24 - 5, pParam->height - 72, "%2d", MIN(g_threadsCount, MAX_THREADS) - i); 92 | osdDrawStringF(pParam->width - 24 - 5, pParam->height - 50, "\\/"); 93 | break; 94 | } 95 | } 96 | } 97 | 98 | void setupThreadsMenu() { 99 | 100 | g_hooks[33] = taiHookFunctionImport( 101 | &g_hookrefs[33], 102 | TAI_MAIN_MODULE, 103 | TAI_ANY_LIBRARY, 104 | 0xC5C11EE7, 105 | sceKernelCreateThread_patched); 106 | 107 | g_hooks[34] = taiHookFunctionImport( 108 | &g_hookrefs[34], 109 | TAI_MAIN_MODULE, 110 | TAI_ANY_LIBRARY, 111 | 0x1BBDE3D9, 112 | sceKernelDeleteThread_patched); 113 | } 114 | --------------------------------------------------------------------------------