This guide covers using the SDL2 native frontend for PHPBoy emulation.
The SDL2 frontend provides a native desktop application experience with:
- Hardware-accelerated rendering - Direct GPU access for smooth 60fps
- Native window - True desktop application, no browser required
- Low latency input - Direct keyboard access
- VSync support - Tear-free rendering
- Cross-platform - Works on Linux, macOS, and Windows
Before using the SDL2 frontend, ensure you have:
- SDL2 PHP extension installed (see SDL2 Setup Guide)
- PHPBoy dependencies installed (
make install)
make check-sdlThis will verify the SDL2 extension is loaded and show the version.
make test-sdlA test window should appear briefly, confirming SDL2 is working.
make run-sdl-host ROM=path/to/your/rom.gbOr directly with PHP:
php bin/phpboy.php path/to/rom.gb --frontend=sdl# SDL2 native frontend (hardware accelerated)
php bin/phpboy.php rom.gb --frontend=sdl
# CLI terminal frontend (ANSI colors)
php bin/phpboy.php rom.gb --frontend=cli
# Headless mode (no display)
php bin/phpboy.php rom.gb --headless# Set window scale (1-8, default 4)
php bin/phpboy.php rom.gb --frontend=sdl --scale=3
# Disable VSync (for testing/benchmarking)
php bin/phpboy.php rom.gb --frontend=sdl --no-vsync
# Custom window title
php bin/phpboy.php rom.gb --frontend=sdl --title="My Game"| Game Boy Button | Keyboard Keys |
|---|---|
| D-Pad Up | Up Arrow |
| D-Pad Down | Down Arrow |
| D-Pad Left | Left Arrow |
| D-Pad Right | Right Arrow |
| A Button | Z or A |
| B Button | X or S |
| Start | Enter/Return |
| Select | Right Shift or Space |
The key mappings are displayed when the emulator starts, or you can check them programmatically:
$input = new \Gb\Frontend\Sdl\SdlInput();
$input->printKeyMappings();You can customize key mappings in your code:
use Gb\Frontend\Sdl\SdlInput;
use Gb\Input\Button;
$input = new SdlInput();
// Map different keys
$input->setKeyMapping(SDL_SCANCODE_W, Button::Up);
$input->setKeyMapping(SDL_SCANCODE_S, Button::Down);
$input->setKeyMapping(SDL_SCANCODE_A, Button::Left);
$input->setKeyMapping(SDL_SCANCODE_D, Button::Right);
// Action buttons on number keys
$input->setKeyMapping(SDL_SCANCODE_1, Button::A);
$input->setKeyMapping(SDL_SCANCODE_2, Button::B);The SDL2 frontend targets 60fps with VSync enabled by default. This matches the Game Boy's native refresh rate (59.73 Hz).
To check actual performance:
# Run with performance stats
php bin/phpboy.php rom.gb --frontend=sdl --statsFor performance testing without rendering overhead:
# Benchmark with headless mode
make benchmark ROM=rom.gb FRAMES=3600
# Compare SDL2 vs CLI frontend
php bin/phpboy.php rom.gb --frontend=sdl --frames=1000 --benchmark
php bin/phpboy.php rom.gb --frontend=cli --frames=1000 --benchmark-
Enable JIT - PHP 8.4 JIT can improve performance:
php -d opcache.jit_buffer_size=100M -d opcache.jit=tracing bin/phpboy.php rom.gb --frontend=sdl
-
Use VSync - Prevents wasted CPU cycles rendering faster than display refresh
-
Disable debugging - Remove
--debugand--traceflags in production
The SDL2 frontend implements the standard FramebufferInterface, making it a drop-in replacement:
use Gb\Frontend\Sdl\SdlRenderer;
use Gb\Frontend\Sdl\SdlInput;
use Gb\Emulator;
// Create SDL2 components
$renderer = new SdlRenderer(
scale: 4, // 640x576 window (160x4, 144x4)
vsync: true, // Smooth 60fps
windowTitle: 'PHPBoy - Tetris'
);
$input = new SdlInput();
// Create emulator with SDL2 frontend
$emulator = new Emulator($romPath, $renderer, $input);
// Main loop
while ($renderer->isRunning()) {
// Poll input and window events
if (!$renderer->pollEvents()) {
break;
}
// Run emulator frame
$emulator->stepFrame();
}Save the current framebuffer to PNG:
$renderer->saveToPng('screenshot.png');Or via command line (if implemented):
php bin/phpboy.php rom.gb --frontend=sdl --screenshot=output.pngHandle SDL events in your application:
while ($renderer->isRunning()) {
// Poll events
$event = new \SDL_Event();
while (SDL_PollEvent($event)) {
if ($event->type === SDL_QUIT) {
break 2;
}
if ($event->type === SDL_KEYDOWN) {
// Handle custom hotkeys
if ($event->key->keysym->scancode === SDL_SCANCODE_ESCAPE) {
break 2;
}
if ($event->key->keysym->scancode === SDL_SCANCODE_F11) {
// Toggle fullscreen
}
if ($event->key->keysym->scancode === SDL_SCANCODE_F12) {
// Take screenshot
$renderer->saveToPng("screenshot_" . time() . ".png");
}
}
}
$emulator->stepFrame();
}-
Check SDL2 is installed:
php -m | grep sdl -
Test SDL2 directly:
make test-sdl
-
Check display is available:
echo $DISPLAY # Should show :0 or similar on Linux
-
Check VSync - Disable to test raw performance:
php bin/phpboy.php rom.gb --frontend=sdl --no-vsync
-
Enable JIT - Significant performance boost:
php -d opcache.jit=tracing bin/phpboy.php rom.gb --frontend=sdl
-
Check GPU acceleration:
# Should show "accelerated" renderer php -r 'SDL_Init(SDL_INIT_VIDEO); $r = SDL_CreateRenderer(SDL_CreateWindow("t", 0, 0, 100, 100, 0), -1, SDL_RENDERER_ACCELERATED); var_dump($r);'
- Disable VSync temporarily to rule out timing issues
- Check polling rate - Ensure
pollEvents()is called every frame - Try different key mappings - Some keyboards have limitations
-
Check SDL2 library is installed:
sdl2-config --version
-
On Linux, ensure video subsystem is available:
SDL_VIDEODRIVER=x11 php bin/phpboy.php rom.gb --frontend=sdl
-
On macOS, may need to run from Terminal (not via SSH)
To create a distributable version with SDL2:
- Static PHP build with SDL2 extension compiled in
- Bundle SDL2 library with your application
- Create launcher script that sets library paths
Example launcher (phpboy.sh):
#!/bin/bash
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
export LD_LIBRARY_PATH="$SCRIPT_DIR/lib:$LD_LIBRARY_PATH"
"$SCRIPT_DIR/php" "$SCRIPT_DIR/phpboy.phar" "$@"| Feature | SDL2 | CLI (ANSI) | WASM (Browser) |
|---|---|---|---|
| Performance | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ |
| Visual Quality | ⭐⭐⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐⭐⭐ |
| Input Latency | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
| Setup Complexity | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐ |
| Distribution | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| Native Feel | ⭐⭐⭐⭐⭐ | ⭐ | ⭐⭐⭐ |
- Audio support: Implement SDL2 audio for APU output
- Joystick support: Add gamepad/controller input
- Fullscreen mode: Toggle fullscreen with F11
- Save states: Quick save/load with hotkeys
- Fast forward: Hold key to run at 2x-8x speed
- SDL2 Setup Guide - Installation instructions
- Frontend Architecture - How frontends work
- Official SDL2 Documentation