jovian / venusian-glfw
The 'glfw' stager for Venusian Surface: staged windows on GLFW 3.4 through ext-glfw, presented through their OpenGL context, on macOS and Linux.
Requires
- php: ^8.4|^8.5|^8.6
- ext-glfw: ^0.10
- ext-opengl: ^0.10
- venusian-surface/bridge: ^0.10.0
- venusian-surface/contracts: ^0.10.0
- venusian-surface/drawing: ^0.10.0
- venusian-surface/windows: ^0.10.0
- venusian-voyager/nuts-and-bolts: ^0.10.1
Requires (Dev)
- jovian/venusian-vulkan: ^0.10.0
- pestphp/pest: ^4
- venusian-voyager/vessel: ^0.10.1
Suggests
- ext-appkit: On macOS: the CGL handle of a lent GL context, the Metal layer, the safe area.
- ext-metal: On macOS with ext-appkit: lending a CAMetalLayer.
- ext-vulkan: Lending a VkSurfaceKHR.
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-10-09 18:06:55 UTC
README
The glfw stager for Venusian Surface: staged windows on GLFW 3.4 through ext-glfw, on macOS and Linux (Wayland and X11). Each window has an OpenGL context and presents CPU frames through it.
Requirements
- macOS or Linux with GLFW 3.4, ext-glfw ^0.10 and ext-opengl ^0.10. PHP 8.4.
- On macOS, ext-appkit for a lent GL context's CGL handle, the Metal layer and the safe area; ext-metal for the Metal layer.
- ext-vulkan, and a Vulkan loader GLFW finds, for a lent Vulkan surface.
- On the Pi, the Wayland session (
WAYLAND_DISPLAY,XDG_RUNTIME_DIR), or X11 withbridge.stage.glfw.platformset tox11: GLFW finds Wayland's default socket even with onlyDISPLAYset.
Install
composer require jovian/venusian-glfw
The provider is discovered through extra.venusian.providers. With Surface's bridge bound, it registers the glfw stager on app('toolkit-bridge').
Usage
$window = app('staged-windows')->open('game', 640, 400, ['toolkit' => 'glfw', 'vsync' => VSync::Off]); $window->setScaling(ScaleFilter::Nearest, ScaleFit::Integer); $frame = $window->framebuffer('dirty', 320, 200); $frame->setPixel(10, 10, 0xFF0000FF); $window->present(); // only the damaged texels are uploaded $window->setMode(WindowMode::Exclusive, $window->displayModes()[0]);
config('bridge.stage.glfw.platform') picks GLFW's platform: cocoa, wayland or x11. Unset, GLFW chooses.
Behaviour
- Backend:
glfw/cocoa,glfw/waylandorglfw/x11. - Context: OpenGL 4.1 core on macOS; OpenGL ES 3.1 over EGL elsewhere, the dialects ext-opengl and the
openglengine speak. - Present: the damaged regions of the frame go into an RGBA8 texture, read in place through the unpack state (
GL_UNPACK_ROW_LENGTH, skip pixels and rows); a new size or no damage list uploads it all. The texture is blitted into the window atpresentRect()with the scaling filter, bars cleared, and the buffers swapped. Vsync is the swap interval:On1,Adaptive-1,OffandMailbox0. - Modes:
Fullscreenis GLFW's full screen on a monitor at its desktop mode;Exclusiveswitches the monitor to a video mode, and GLFW gives it back when the window leaves. Maximize, minimize and restore through GLFW; the iconify and maximize callbacks report modes the user chose. - Displays: GLFW monitors, the primary first. A display's id is its
GLFWmonitoraddress; sizes are screen coordinates; a mode's pixel density is the monitor's content scale. GLFW reports no HDR. - Capabilities, measured: macOS position, always-on-top, opacity, attention, exclusive fullscreen; X11 those and the window icon; Wayland attention only. No platform refuses focus, so
focusable: falseis refused at open. No keep-awake, frame clock or hit test. - Aspect: an exact ratio is GLFW's own; a range is kept by correcting the size after each resize.
- Close: the close callback closes the window, or with
confirm_closepostsWindowCloseRequestedand clears GLFW's should-close flag. - Lending: the window's own GL context (CGL on macOS, EGL elsewhere), whose present this window drives (current, framebuffer 0, the borrower's copy, swap); a
CAMetalLayeron a view pinned over GLFW's (macOS); aVkSurfaceKHR. GLFW makes a Vulkan surface only on a window without a context, so lending one remakes the native window without; the next CPU present or GL lend remakes it with. A remade window keeps its place, limits, aspect, opacity, icon, visibility and mode. - Session: GLFW never sleeps on a descriptor, so the loop polls it at its pace. No GLFW menu bar on macOS. No libdecor on Wayland: its GTK plugin collides with a GTK already in the process.
Presenting
EGL swaps name changed rects (EGL_KHR_swap_buffers_with_damage): compositor redraws only those. Wayland swaps at interval 0 (compositor paces, never tears; hidden window never blocks). Hidden window presents nothing, CPU or lent surface: a buffer committed to a hidden GLFW Wayland window makes showing it a protocol error. First present after show = whole frame. GL borrower asking 'native' gets the native window, remade without a context.
Testing
php84 -d memory_limit=128M vendor/bin/pest zhp -d memory_limit=128M vendor/bin/pest WAYLAND_DISPLAY=wayland-0 XDG_RUNTIME_DIR=/run/user/1000 GLFW_TEST_PLATFORM=wayland php -d memory_limit=128M vendor/bin/pest DISPLAY=:0 XDG_RUNTIME_DIR=/run/user/1000 GLFW_TEST_PLATFORM=x11 php -d memory_limit=128M vendor/bin/pest
Security
See SECURITY.md.
License
MIT. See LICENSE.