PortableGL-rs
"Because of the nature of Moore's law, anything that an extremely clever graphics programmer can do at one point can be replicated by a merely competent programmer some number of years later." -John Carmack
PortableGL-rs is a Rust port of PortableGL, an implementation of OpenGL 3.x core (mostly; see GL Version) as a pure software renderer. No GPU required.
The original is a ~13,000 line single-header C99 library. This port rewrites it in idiomatic Rust while maintaining functional equivalence, and can also serve as a drop-in C library replacement via an optional FFI layer.
It can be used with anything that takes a 32 or 16 bit framebuffer/texture as input in any format (including just writing images to disk or blitting raw pixels to the screen via SDL2, win32, X11, etc.).
It supports arbitrary 32- and 16-bit color buffer formats (selected at compile time via Cargo features) with several common ones ready to use out of the box.
Goals (inherited from the original project, roughly in order of priority):
- Portability
- Matching the OpenGL API within reason
- Ease of Use
- Straightforward code
- Speed
Like the original, shaders are native function pointers (Rust fn / C function pointers) rather than GLSL strings.
Uniforms are passed as a raw *mut c_void pointer to a user-defined struct.
Features
- Pure software OpenGL 3.x core profile renderer (no GPU, no platform dependencies)
- Vertex processing with configurable attributes and instancing
- Triangle rasterization with barycentric coordinates
- Sutherland-Hodgman triangle clipping against 6 frustum planes
- Cohen-Sutherland parametric line clipping
- Perspective-correct, noperspective, and flat interpolation
- Depth testing, stencil testing, scissor testing
- Alpha blending with separate RGB/Alpha equations
- Face culling, polygon modes (fill/line/point)
- 1D/2D/3D textures, cubemaps, texture arrays, rectangle textures
- Nearest and linear (bilinear/trilinear) texture filtering
- Texture wrap modes: repeat, clamp to edge, clamp to border, mirrored repeat
- Bresenham and Wu's anti-aliased line drawing
- Point sprites with gl_PointCoord
- Polygon offset (depth bias)
- Logic operations
no_stdsupport (withalloc)- C FFI layer for drop-in replacement of the original C library
Differences from the C Version
| Aspect | C (PortableGL) | Rust (PortableGL-rs) |
|---|---|---|
| Language | C99, single-header library | Rust 2021 edition, multi-module crate |
| API style | Free functions with global glContext* |
Methods on GlContext struct |
| Shaders | C function pointers | unsafe extern "C" fn pointers (compatible with both Rust and C callers) |
| Memory | Manual (malloc/free, cvector) |
Vec<T>, RAII, ownership |
| Pixel format | Preprocessor macros | Cargo feature flags |
| Build system | Makefile / single header include | cargo build |
no_std |
N/A (requires libc) | Supported via no_std feature + alloc |
| C FFI | Native | Optional via ffi feature flag |
| Thread safety | Global mutable state | Owned GlContext per thread (FFI uses global for C compat) |
Getting Started
As a Rust Library
Add to your Cargo.toml:
[]
= { = "path/to/portablegl-rs" }
Basic usage:
use GlContext;
use *;
use *;
use c_void;
// Define a vertex shader
unsafe extern "C"
// Define a fragment shader
unsafe extern "C"
As a C Drop-in Replacement
Build with the ffi feature to produce a shared/static library:
This produces:
portablegl.dll/libportablegl.so(shared library)libportablegl.a(static library)
Link against it from C/C++ and use the same API as the original PortableGL:
// Use the same function names as PortableGL
extern GLboolean ;
extern void ;
extern void ;
extern void ;
// ... etc.
For no_std Environments
[]
= { = "path/to/portablegl-rs", = ["no_std"] }
Requires an allocator (alloc crate). Uses libm for float math. Works on embedded targets,
custom OS kernels, WASM without std, etc.
Running Examples
Three interactive examples are included (using minifb for windowing):
Cargo Features
| Feature | Description | Default |
|---|---|---|
abgr32 |
ABGR 32-bit pixel format | Yes |
rgba32 |
RGBA 32-bit pixel format | |
argb32 |
ARGB 32-bit pixel format | |
bgra32 |
BGRA 32-bit pixel format | |
rgb565 |
RGB 16-bit pixel format | |
bgr565 |
BGR 16-bit pixel format | |
d24s8 |
24-bit depth + 8-bit stencil | Yes |
d16 |
16-bit depth, no stencil | |
no_depth |
No depth buffer | |
no_std |
no_std + alloc support (uses libm) |
|
no_stencil |
Disable stencil buffer | |
ffi |
Enable C FFI wrappers | |
unsafe_mode |
Allow additional unsafe optimizations | |
hermite_smoothing |
Use Hermite smoothing for interpolation | |
better_thick_lines |
Improved thick line rendering | |
examples |
Build interactive examples (uses minifb) |
Project Structure
src/
lib.rs - Crate root, module declarations
math.rs - Vec2/3/4, Mat3/4, Color, Line types and operations
gl_types.rs - GL type aliases, 313 constants, core structs
gl_context.rs - GlContext state machine struct
gl_impl.rs - GL API implementation (buffers, textures, VAOs, draw calls, state)
gl_internal.rs - Core pipeline (clipping, rasterization, fragment processing)
gl_glsl.rs - Texture sampling functions (1D/2D/3D, cubemap, array, fetch)
pgl_ext.rs - PGL extensions (clear screen, draw frame, format conversion)
float_math.rs - Float math compatibility layer for no_std
ffi.rs - C FFI wrappers (behind "ffi" feature)
GL Version
Same as the original PortableGL: mostly OpenGL 3.x core profile, with some 4.x DSA functions and compatibility profile features (like a default VAO) included where they come for free in a software renderer. See the original README for details.
Documentation
The best way to learn is to look at the original PortableGL examples and demos, as well as the LearnPortableGL tutorials.
The official OpenGL reference pages cover 90-95% of the API usage.
Similar/Related Projects
- PortableGL - The original C99 implementation this is ported from.
- pgl - A Go port of PortableGL.
- TinyGL - Fabrice Bellard's OpenGL 1.x subset implementation.
- Mesa3D - Full open source OpenGL/Vulkan implementation with software renderers.
- SoftGLRender - OpenGL software renderer in modern C++.
Acknowledgments
This project was ported from C to Rust with the assistance of Claude Opus 4.6 (Anthropic).
Claude helped translate the ~13,000-line C99 codebase into idiomatic Rust, implement the no_std
support layer, C FFI bindings, and port the regression test suite — achieving full functional
equivalence with the original PortableGL.
LICENSE
PortableGL-rs is licensed under the MIT License (MIT).
The code used for clipping is copyright (c) Fabrice Bellard from TinyGL, also under the MIT License. See LICENSE.