Pharo FFI bindings for SDL (Simple DirectMedia Layer) version 3.0, initially generated with PharoCIG.
SDL is a cross-platform development library designed to provide low-level access to audio, keyboard, mouse, joystick, and graphics hardware. It is used by video playback software, emulators, and games.
In a Pharo 14 image, evaluate the following Metacello script:
Metacello new
baseline: 'SDL3';
repository: 'github://pharo-graphics/PharoSDL3:dev/src';
loadGet Pharo:
curl https://get.pharo.org/140+vmLatest | bashand load this project:
./pharo Pharo.image metacello install github://pharo-graphics/PharoSDL3:dev/src SDL3Since end of June/2026, the Pharo 14 "latest" VM ships SDL3 for Mac and Windows (not Linux yet). Find below other options to ensure the SDL3 library is available on your system so Pharo's FFI can find it.
- MacOS:
brew install sdl3 - Linux: Build from source or use your package manager.
- Windows: Download the DLL from SDL releases and place it in the same folder as your Pharo image.
The System Settings provide an option to establish the OSWindow driver. Search for "OSWindow":

You can force the driver from an environment variable, from terminal:
- Download Pharo 14 via zeroconf script as described above
- Load this project's baseline
- Save and Close
- Run in terminal:
PHARO_WINDOW_DRIVER=OSSDL3Driver ./pharo-ui Pharo.image - Verify that
OSWindowDriver currentanswers aOSSDL3Driver
Other options define the strategy for refreshing the window & VSYNC. The OSBenchmarkMorph can show metrics and visuals related to such options.
The project includes automated tests as well as interactive demos. These demos complement automated testing by allowing for human verification of visual rendering and event handling.
Important: Pharo's UI and SDL2 (used by default in Pharo 14) conflict with SDL3's subsystems. It is recommended to run SDL3 tests and demos in headless mode or ensure proper work.
Run tests from the terminal:
./pharo Pharo.image test 'SDL3-Tests' 'SDL3-GPU-Tests'(This video) shows how to run SDL3WindowTest>>#test12ShapedWindow.
You can run any of the following demos by evaluating ./pharo Pharo.image eval '<ClassName> new run' from terminal. They are listed below from simplest to most advanced:
SDL3ClearDemoApp: The basic "Hello World" of window management and rendering clear operations.SDL3LogEventsDemoApp: Real-time logging of the SDL3 event stream (mouse, keyboard, window) to a console.SDL3SystemQueryDemoApp: Queries system and device properties like display modes, audio drivers, and video drivers.SDL3DisplayDemoApp: Visualizes logical display layouts, hardware specs, and multiple display boundary frontiers.SDL3MouseDemoApp: Mouse-related functions including grabbing, relative mode, window confinement, warping, and system cursors.SDL3KeyboardDemoApp: Low-level keyboard state monitoring (scancodes, keycodes, modifiers) and Unicode text input.SDL3WindowChildrenDemoApp: Parent/child window relationships including utility, tooltip, popup menu, and modal behaviors.SDL3AnimatedCursorDemoApp: Creation and usage of custom animated cursors from image frames (Video).SDL3MultiWindowDemoApp: Management and update loops for multiple top-level windows simultaneously.SDL3TouchpadDemoApp: Multi-touch finger tracking (Video).SDL3TouchpadZoomDemoApp: Smooth zooming gestures utilizing complex touchpad pinch events.SDL3AudioRecorderDemoApp: Audio capture from the system's default microphone and playback.SDL3CameraDemoApp: Live frame acquisition from a camera with horizontal mirror support.SDL3TrayMenuDemoApp: System tray integration, including icon management and contextual menus (Video).SDL3ImageClipboardDemoApp: System clipboard integration for copying and pasting image data.SDL3FolderDialogDemoApp: Native system file/folder selection dialogs.
SDL3GPUClearDemoApp: The simplest entry point to the hardware-accelerated GPU API, showing basic render pass and clear color setup.SDL3GPURenderStateDemoApp: Simplified use of the graphics pipeline via theSDL_RendererAPI. (Video)SDL3GPUQuadDemoApp: Foundations of geometry: rendering a textured quad using vertex buffers, index buffers, and UV mapping (Video).SDL3GPURoundedRectDemoApp: Perfectly anti-aliased procedural shapes using Signed Distance Fields (SDF) and fragment shaders (Video).SDL3GPUShimmerDemoApp: Mock UI with a loading effect utilizing time uniforms and procedural shader generation (Video).SDL3GPUInstancedQuadDemoApp: High-performance rendering of thousands of objects using hardware instancing and instance buffers.SDL3TextScrollDemoApp: Smooth text scrolling of a large file utilizing a texture atlas and instanced quad rendering.SDL3GPUMandelbrotDemoApp: Interactive fractal exploration using compute shaders, storage textures, and dynamic zoom/pan navigation uniforms.SDL3GPUBlurComputeDemoApp: Real-time image processing utilizing compute shaders, storage textures, and a Gaussian blur algorithm.SDL3GPUKawaseBlurDemoApp: Multi-pass post-processing effect demonstrating ping-pong buffers, downsampling/upsampling, and a Dual Kawase Blur (Video).SDL3GPUBoidsDemoApp: High-performance particle system using a compute-to-vertex-buffer architecture for a flocking simulation (Video).SDL3GPUNodeForceDemoApp: Force-directed graph simulation utilizing N-body physics in a compute shader (Video).
The project includes shell scripts in scripts/:
-
scripts/smokeTestDemos.sh: Runs each demo sequentially for few seconds to verify startup, execution, and clean shutdown without throwing errors or crashing. Collects all results and reports a summary.# Run all demos (defaults to ./pharo Pharo.image) ./pharo-local/iceberg/pharo-graphics/PharoSDL3/scripts/smokeTestDemos.sh # Filter demos by substring (e.g. GPU demos) ./pharo-local/iceberg/pharo-graphics/PharoSDL3/scripts/smokeTestDemos.sh GPU # Custom Pharo VM/Image path ./pharo-local/iceberg/pharo-graphics/PharoSDL3/scripts/smokeTestDemos.sh GPU "./pharo PharoCustom.image"
-
scripts/benchOSWindow.sh: RunsOSBenchmarkMorphagainst multiple OSWindow drivers to collect windowing benchmarks.# Run benchmarks with default ./pharo-ui Pharo.image ./pharo-local/iceberg/pharo-graphics/PharoSDL3/scripts/benchOSWindow.sh # Run and record results to a file for comparison ./pharo-local/iceberg/pharo-graphics/PharoSDL3/scripts/benchOSWindow.sh | tee -a results.txt # Custom Pharo VM/Image path ./pharo-local/iceberg/pharo-graphics/PharoSDL3/scripts/benchOSWindow.sh "./pharo-ui PharoCustom.image" | tee -a results.txt
While the core FFI layer provides direct bindings to C functions, PharoSDL3 adds object-oriented abstractions that eliminate manual C bookkeeping:
- Standalone Desktop Applications (
SDL3App): Build and run standalone desktop applications directly from a headless Pharo image, completely independent of Morphic and OSWindow. - GPU Pipeline Builder (
SDL3GPUGraphicsPipelineBuilder): Declarative pipeline configuration with vertex struct reflection (addVertexBufferFor:) and pre-flight validation preventing native driver crashes. - Polymorphic Event Visitor (
TSDL3HierarchicalEventVisitor): Reifies the raw CSDL_Eventunion into 130+ event classes with hierarchical bubbling delegation. - Deterministic Scope Disposal (
DiScope): RAII-style ambient LIFO scopes that guarantee clean resource teardown without nestedensure:blocks. - Reified Domain Entities: First-class objects for C integer IDs (
SDL3Display,SDL3AudioDevice,SDL3PropertyGroup) and typed macro flags (SDL3MacroDefinedFlag,SDL3WindowFlags). - Pharo Interoperability: Zero-copy surface sharing (
Form >> unownedAsSDL3Surface) and geometry/color conversions.
SDL3SingleWindowApp << #MyGameApp
slots: { #renderer };
package: 'MyGame'.
MyGameApp >> setUp [
super setUp.
renderer := DiScope own: window unownedNewRenderer.
]
MyGameApp >> step [
renderer
drawColor: (SDL3FColor r: 0.1 g: 0.2 b: 0.3 a: 1.0);
renderClear;
renderPresent.
]
MyGameApp >> visitKeyboardDownEvent: anEvent [
anEvent key = SDLK_SPACE asInteger ifTrue: [ "handle spacebar" ].
^ super visitKeyboardDownEvent: anEvent
]Run it from the terminal using a headless Pharo VM:
./pharo Pharo.image eval 'MyGameApp new run'For detailed architectural explanations and guides, see:
doc/Standalone-Applications.md: Complete guide toSDL3App, lifecycle hooks, frame pacing withSDL3CappedLoop, and GPU apps.doc/Architecture-And-OOP-Design.md: In-depth comparison of the raw C FFI baseline against the OOP abstractions (events, builder, domain entities).doc/GPU-Resource-Mapping.md: Ground-truth reference for HLSL descriptor spaces, registers, and transpiler rules.
The bindings follow a consistent naming convention to map C functions to Pharo methods.
GENERAL TIP: Given a SDL3 C name (e.g. SDL_ function, struct or constant), in Pharo you can select the string -> open context menu -> "Code search" -> "Method source with it", and you should find where in the project it is used or defined.
The SDL3Library class provides direct access to the C API.
- Prefix Removal: The
SDL_prefix is removed. - CamelCase: The first letter of the function name is lowercased.
- Keywords: Function parameters are converted into Pharo keywords.
- Argument Naming: Arguments are named using
camelCase(e.g.,numThreadsinstead ofnum_threads).
Examples:
SDL_Init(flags)maps toSDL3Library >> init: flagsSDL_CreateWindow(title, w, h, flags)maps toSDL3Library >> createWindowTitle:w:h:flags:
Key classes like SDL3Window, SDL3Renderer, SDL3Surface, and SDL3GPUDevice provide idiomatic Smalltalk methods.
- Accessors: Getter and setter functions are converted to Smalltalk-style accessors by omitting the
GetandSetprefixes.SDL_GetWindowFlags(window)maps toSDL3Window >> flagsSDL_SetWindowBordered(window, bordered)maps toSDL3Window >> bordered: bordered
- Output Parameters (Into): When a function returns values via pointers (output parameters), the Pharo method typically uses the
Intokeyword in the selector.SDL_GetWindowSize(window, &w, &h)maps toSDL3Window >> getSizeIntoW: w h: hSDL_GetRenderClipRect(renderer, &rect)maps toSDL3Renderer >> getRenderClipRectInto: rect
- Argument Naming: Just like in the raw API, all arguments use
camelCase. - Internal Assertions: These methods internally perform success assertions, and signal
SDL3Errorif something was wrong in a SDL3 C function call.
You can explore all available functions in the SDL3Library class or by browsing the object classes.
These key classes also provide class-side and factory methods for creating or opening SDL resources.
- Explicit Ownership: Methods prefixed with
unownedNew,unownedOpen,unownedAs..., orunownedCopy...signal that the sender is responsible for disposing the object (e.g., sendingdispose,destroy,close,end, orrelease). - Internal Assertions: These methods verify return values and signal
SDL3Erroron failure.
Examples:
SDL3Window unownedNewTitle: 'title' width: 800 height: 600 flags: 0SDL3Joystick unownedOpen: 0SDL3PropertyGroup unownedNew
This project is licensed under the MIT license.