Files
dusk/.claude/platform-psp.md
T
2026-06-16 10:15:59 -05:00

201 lines
5.4 KiB
Markdown

# Platform -- Sony PSP
`DUSK_TARGET_SYSTEM`: `psp`
Source layer: `src/duskpsp/`
Renderer: OpenGL ES (legacy, via PSPGL/SDL2)
---
## Overview
The PSP is a 32 MB MIPS-based handheld console running at up to 333 MHz.
It uses SDL2 (ported to PSP) for windowing and OpenGL in legacy/fixed-
function mode. The game binary and all assets are packaged together inside
a `.pbp` file -- the PSP's native executable format.
---
## Hardware
| Attribute | Value |
|-----------|-------|
| CPU | MIPS R4000 (Allegrex), up to 333 MHz |
| RAM | 32 MB (4 MB reserved for OS) |
| Display | 480x272, 16/32-bit colour |
| Storage | Memory Stick (UMD for retail; MS for homebrew) |
| Endian | Little-endian |
---
## Compile-time macros
| Macro | Set |
|-------|-----|
| `DUSK_PSP` | yes |
| `DUSK_SDL2` | yes |
| `DUSK_OPENGL` | yes |
| `DUSK_OPENGL_LEGACY` | yes |
| `DUSK_INPUT_GAMEPAD` | yes |
| `DUSK_PLATFORM_ENDIAN_LITTLE` | yes |
| `DUSK_DISPLAY_WIDTH` | 480 |
| `DUSK_DISPLAY_HEIGHT` | 272 |
| `DUSK_THREAD_PTHREAD` | yes |
No `DUSK_DISPLAY_SIZE_DYNAMIC` -- the resolution is fixed.
No `DUSK_INPUT_KEYBOARD`, no `DUSK_INPUT_POINTER`.
---
## Display
- Fixed 480x272 resolution.
- OpenGL legacy (fixed-function pipeline, `DUSK_OPENGL_LEGACY`).
- Texture dimensions **must** be powers of two (use `mathNextPowTwo`).
- VFPU (4-wide float SIMD) is available -- use it for matrix/vector hot
paths under `#ifdef DUSK_PSP`.
---
## Asset loading
Assets are packed into the **PSAR** section of the `.pbp` file by the
post-build `create_pbp_file()` CMake command. At runtime,
`assetInitPBP()` locates and opens the PSAR from the running executable's
path.
The PBP format header:
```c
typedef struct {
char_t signature[4]; // "\0PBP"
uint32_t version;
uint32_t sfoOffset;
uint32_t icon0Offset;
uint32_t icon1Offset;
uint32_t pic0Offset;
uint32_t pic1Offset;
uint32_t snd0Offset;
uint32_t pspOffset;
uint32_t psarOffset; // dusk.dsk starts here
} assetpbpheader_t;
```
`assetpbp_t` holds the open file handle and parsed header. Asset paths
inside the PSAR are ZIP paths within `dusk.dsk`.
---
## Input
Layered on SDL2. `inputInitPSP()` maps PSP physical buttons to SDL2
`SDL_CONTROLLER_BUTTON_*` constants:
| PSP button | Action |
|------------|--------|
| Cross | Accept |
| Circle | Cancel |
| Triangle | - |
| Square | - |
| L / R | Shoulder buttons |
| D-pad | Directional |
| L-Stick | Analog axes |
No keyboard or pointer input available. Attempting to use
`INPUT_BUTTON_TYPE_KEYBOARD` on PSP is undefined behaviour.
The PSP system setting `PSP_UTILITY_ACCEPT_CROSS` / `ACCEPT_CIRCLE`
swaps the Cross and Circle button roles in OS dialogs -- read this via
`systemPSPGetCrossButtonSetting()` if you need to match the system
convention.
---
## Save system
- Path: `ms0:/PSP/SAVEDATA/<TITLE_ID><slot>/save.dat`
(default title ID `DUSK00001`, configurable via `SAVE_PSP_TITLE_ID`).
- Uses `sceIo` for file I/O -- no extra dialog required for raw reads.
- PSP OS-level save/load dialogs (via `sceUtility`) are separate and
block the main loop when open (`systemGetActiveDialogType()` returns
`SYSTEM_DIALOG_TYPE_TICK_BLOCKING`).
- Do not call save functions directly from game code during a dialog.
---
## Network
Connection requires an explicit user Wi-Fi selection step via the PSP
system network dialog (`sceUtilityNetconfInitStart`).
```
networkRequestConnection(onConnected, onFailed, onDisconnect, user);
// -> shows PSP Wi-Fi selection dialog (blocking dialog type)
// -> calls onConnected or onFailed when the dialog closes
```
HTTP and SSL modules (`psphttp`, `pspssl`, `pspnet_resolver`) are
linked in `psp.cmake` but the HTTP implementation code is commented out.
The infrastructure exists for future use.
---
## Time
- Tick source: `SDL_GetTicks64()`.
- Real time: `sceRtcGetCurrentTick()` (returns microseconds).
- Dynamic timestep is **not** enabled (`DUSK_TIME_DYNAMIC` not set).
Every tick is a fixed 16 ms step.
---
## System dialogs
PSP shows OS-level dialogs for:
- Wi-Fi configuration (`networkRequestConnection`)
- Save management (if using `sceUtility` save dialogs)
Check `systemGetActiveDialogTypePSP()` to know whether the main loop
should skip rendering or ticking.
---
## Build and toolchain
Requires the [PSPDEV toolchain](https://github.com/pspdev/pspdev).
Set `PSPDEV` in your environment before configuring.
```sh
cmake -B build \
-DDUSK_TARGET_SYSTEM=psp \
-DCMAKE_TOOLCHAIN_FILE=${PSPDEV}/lib/cmake/psp.cmake \
-DCMAKE_BUILD_TYPE=Release
cmake --build build
```
Post-build output: `Dusk.pbp` (executable + assets combined).
Dependencies: SDL2-PSP, OpenGL-PSP, pspgu, pspctrl, pspdisplay,
pspaudio, pspaudiolib, psputility, pspvfpu, pspvram, pspnet,
pspnet_inet, pspnet_apctl, psphttp, pspssl, pspdebug, psphprm,
mbedtls, mbedcrypto, lzma, zip, bz2, z.
---
## Endianness
Little-endian. `DUSK_PLATFORM_ENDIAN_LITTLE` is set at compile time.
No runtime endian check is needed.
---
## Gotchas
- The PSP has only 28 MB of usable RAM after the OS. Keep asset budgets
tight -- see `.claude/optimization.md`.
- VFPU instructions are not valid on threads other than the main thread
on some firmware versions. Use `assertIsMainThread` on any code that
calls VFPU intrinsics.
- OpenGL legacy mode means no vertex/fragment shaders; rendering uses
the fixed-function pipeline via `pspgl`.
- `DUSK_TIME_DYNAMIC` is absent -- physics always runs at exactly the
fixed step rate.