Enables software rendering via drawing an image straight to a window.
Softbuffer integrates with the raw-window-handle crate
to allow writing pixels to a window in a cross-platform way while using the very high quality dedicated window management
libraries that are available in the Rust ecosystem.
minifb also allows putting a 2D buffer/image on a window in a platform-independent way. Minifb's approach to doing window management itself, however, is problematic code duplication. We already have very high quality libraries for this in the Rust ecosystem (such as winit), and minifb's implementation of window management is not ideal. For example, it occasionally segfaults and is missing key features such as setting a window icon on some platforms. While adding these features to minifb would be possible, it makes more sense to use the standard window handling systems instead.
What about pixels? Pixels accomplishes a very similar goal to Softbuffer, however there are two key differences. Pixels provides some capacity for GPU-accelerated post-processing of what is displayed, while Softbuffer does not. Due to not having this post-processing, Softbuffer does not rely on the GPU or hardware accelerated graphics stack in any way, and is thus more portable to installations that do not have access to hardware acceleration (e.g. VMs, older computers, computers with misconfigured drivers). Softbuffer should be used over pixels when its GPU-accelerated post-processing effects are not needed.
This library is dual-licensed under MIT or Apache-2.0, just like minifb and rust. Significant portions of code were taken from the minifb library to do platform-specific work.
Softbuffer supports many platforms, some to a higher degree than others. This is codified with a "tier" system. Tier 1 platforms can be thought of as "tested and guaranteed to work", tier 2 as "will likely work", and tier 3 as "builds in CI".
The current status is as follows (based on the list of platforms exposed by raw-window-handle):
| Platform | Tier | Available |
|---|---|---|
| AppKit (macOS) | 1 | ✅ |
| Wayland | 1 | ✅ |
| Win32 | 1 | ✅ |
| XCB / Xlib (X11) | 1 | ✅ |
| Android NDK | 2 | ✅ |
| UIKit (iOS) | 2 | ✅ |
| WebAssembly | 2 | ✅ |
| DRM/KMS | 3 | ✅ |
| Orbital | 3 | ✅ |
| GBM/KMS | N/A | ❌ |
| Haiku | N/A | ❌ |
| OpenHarmony OS NDK | N/A | ❌ (#261) |
| WinRT | N/A | ❌ |
| UEFI | N/A | ❌ (#282) |
Beware that big endian targets are much less tested, and may behave incorrectly.
Pull requests to add support for new platforms are welcome!
To run an example with the web backend: cargo run-wasm --example winit
To run the Android-specific example on an Android phone: cargo apk r --example winit_android or cargo apk r --example winit_multithread_android.
use std::num::NonZeroU32;
use std::rc::Rc;
use softbuffer::{Context, Pixel, Surface};
use winit::event::{Event, WindowEvent};
use winit::event_loop::{ControlFlow, EventLoop};
use winit::window::Window;
#[path = "../examples/util/mod.rs"]
mod util;
fn main() {
let event_loop = EventLoop::new().unwrap();
let context = Context::new(event_loop.owned_display_handle()).unwrap();
let mut app = util::WinitAppBuilder::with_init(
|elwt| {
let window = elwt.create_window(Window::default_attributes());
Rc::new(window.unwrap())
},
|_elwt, window| Surface::new(&context, window.clone()).unwrap(),
)
.with_event_handler(|window, surface, window_id, event, elwt| {
elwt.set_control_flow(ControlFlow::Wait);
if window_id != window.id() {
return;
}
match event {
WindowEvent::RedrawRequested => {
let Some(surface) = surface else {
tracing::error!("RedrawRequested fired before Resumed or after Suspended");
return;
};
let size = window.inner_size();
surface
.resize(
NonZeroU32::new(size.width).unwrap(),
NonZeroU32::new(size.height).unwrap(),
)
.unwrap();
let mut buffer = surface.buffer_mut().unwrap();
for (x, y, pixel) in buffer.pixels_iter() {
let red = (x % 255) as u8;
let green = (y % 255) as u8;
let blue = ((x * y) % 255) as u8;
*pixel = Pixel::new_rgb(red, green, blue);
}
buffer.present().unwrap();
}
WindowEvent::CloseRequested => {
elwt.exit();
}
_ => {}
}
});
event_loop.run_app(&mut app).unwrap();
}This crate's Minimum Supported Rust Version (MSRV) is 1.71. Changes to the MSRV will be accompanied by a minor version bump.
As a tentative policy, the upper bound of the MSRV is given by the following formula:
min(sid, stable - 3)
Where sid is the current version of rustc provided by Debian Sid, and
stable is the latest stable version of Rust. This bound may be broken in case of a major ecosystem shift or a security vulnerability.
Orbital is not covered by this MSRV policy, as it requires a Rust nightly toolchain to compile.
All crates in the rust-windowing organizations have the
same MSRV policy.
See the changelog for a list of this package's versions and the changes made in each version.