Pharo Smalltalk bindings for SDL (Simple DirectMedia Layer) version 3.0.
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://tinchodias/PharoSDL3:dev/src';
loadAlternatively, from your terminal:
curl https://get.pharo.org/140+vmLatest | bash
./pharo Pharo.image metacello install --save github://tinchodias/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'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.SDL3MultiWindowDemoApp: Management and update loops for multiple top-level windows simultaneously.SDL3TouchpadDemoApp: Multi-touch finger tracking on modern touchpads.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 system camera with orientation support.SDL3TrayMenuDemoApp: System tray integration, including icon management and contextual menus.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.SDL3GPURoundedRectDemoApp: Perfectly anti-aliased procedural shapes using Signed Distance Fields (SDF) and fragment shaders.SDL3GPUShimmerDemoApp: Mock UI with a loading effect utilizing time uniforms and procedural shader generation.SDL3GPUInstancedQuadDemoApp: High-performance rendering of thousands of objects using hardware instancing and instance buffers.SDL3GPUInstancingDemoApp: Massive amounts of geometric shapes rendered via GPU instancing and Shader Storage Buffer Objects (SSBO).SDL3TextScrollDemoApp: Smooth text scrolling of a large file utilizing a texture atlas and instanced quad rendering.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.SDL3GPUBoidsDemoApp: High-performance particle system using a compute-to-vertex-buffer architecture for a flocking simulation.SDL3GPUNodeForceDemoApp: Force-directed graph simulation utilizing N-body physics in a compute shader.SDL3GPUMandelbrotDemoApp: Background GPU fractal generation showcasing tiled rendering, level-of-detail (LOD), and asynchronous GPU resource loading.
The bindings follow a consistent naming convention to map C functions to Pharo methods.
The LibSDL3 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).
You can browse a mapping table in our wiki with a complete mapping from SDL functions to each Pharo method in LibSDL3.
Examples:
SDL_Init(flags)maps toLibSDL3 >> init: flagsSDL_CreateWindow(title, w, h, flags)maps toLibSDL3 >> newWindowTitle:w:h:flags:
Object-oriented classes like SDL3Window and SDL3Renderer provide more 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 low-level API, all arguments use
camelCase.
You can explore all available functions in the LibSDL3 class or by browsing the object classes. The tables in our wiki page can help, as well.
Independent root classes provide class-side methods for creating or opening resources.
- Explicit Ownership: These methods are prefixed with
unsafeNew(for creation) orunsafeOpen(for opening peripherals). This naming convention explicitly signals that the caller is responsible for manual memory management (e.g., callingdestroy,close, orrelease). - Internal Assertions: These methods internally perform success assertions (typically using
assertNotNullReturn).
Examples:
SDL3Window unsafeNewTitle: 'title' w: 800 h: 600 flags: 0SDL3Joystick unsafeOpen: 0SDL3PropertyGroup unsafeNew
The GPU stack provides specialized methods that use Block Closures to manage the lifecycle of transient resources (like passes, mapping addresses, or configuration structs). These methods use ensure: blocks internally to guarantee that resources are correctly closed, unmapped, or freed, even if an error occurs.
- Pass Management: Methods like
renderPassTargets:do:,computePassTextures:do:, andcopyPassDo:automatically call the underlyingEndGPU...Passfunctions when the block finishes. - Safe Resource Creation: Methods like
newGraphicsPipeline:,newSamplerDo:, andnewBufferDo:provide a temporaryCreateInfostruct to the block and automatically free it once the resource is created. - Memory Mapping:
mapTransferBuffer:cycle:do: [ :mappedAddress | ... ]automatically unmaps the transfer buffer when the block terminates.
Example:
commandBuffer renderPassTargets: targets do: [ :renderPass |
renderPass
pipeline: myPipeline;
drawPrimitives: 3 instances: 1 firstVertex: 0 firstInstance: 0
].
The block closure will be preceded by a FFI call to [SDL_BeginGPURenderPass](https://wiki.libsdl.org/SDL3/SDL_BeginGPURenderPass) and ended with a FFI call to [SDL_EndGPURenderPass](https://wiki.libsdl.org/SDL3/SDL_EndGPURenderPass)To provide a more idiomatic and safe experience, many wrapper methods in the High-level API handle error checking internally:
- Boolean Success: Methods that return a boolean success code in C (e.g.,
SDL_SetWindowBordered) useassertSuccess:internally. If the call fails, anSDL3Erroris raised with the message fromSDL_GetError(). These methods returnselfon success. - Pointer Results: Methods that create or return SDL3 objects (e.g.,
newRendererFor:) useassertNotNullReturninternally. If the returned pointer is NULL, anSDL3Erroris raised. - Void Returns: Methods returning
voidin C (e.g.,destroy) do not perform assertions and returnselfto allow for method chaining. - Query Methods: Methods that return a state or value (e.g.,
isTextInputActiveorflags) do not perform internal assertions and return the value directly.
You can explore all available functions in the LibSDL3 class or by browsing the object classes.
- Is this code generated? Yes, it was initially generated with CIG and post-processed manually.
- Wiki: Check the project wiki for post-processing details and technical documentation.
This project is licensed under the MIT license.