It is useful to put a 2D buffer/image on a window in a platform-independent way

Related tags

Graphics softbuffer
Overview

Overview

As the popularity of the library minifb shows, it is useful to put 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 on some platforms and is missing key features such as the ability to set a window icon. While it would be possible to add these features to minifb, it makes more sense to instead use the standard window handling systems.

Softbuffer integrates with the raw-window-handle crate to allow writing 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.

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.

License & Credits

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.

Platform support:

Some, but not all, platforms supported in raw-window-handle are supported by Softbuffer. Pull requests are welcome to add new platforms! Nonetheless, all major desktop platforms that winit uses on desktop are supported.

For now, the priority for new platforms is:

  1. to have at least one platform on each OS working (e.g. one of Win32 or WinRT, or one of Xlib, Xcb, and Wayland) and
  2. for that one platform on each OS to be the one that winit uses.

(PRs will be accepted for any platform, even if it does not follow the above priority.)

: Present | : Absent

  • AndroidNdk
  • AppKit (Thanks to Seo Sanghyeon!)
  • Orbital
  • UiKit
  • Wayland (Wayland support in winit is immature at the moment, so it might be wise to force X11 if you're using winit)
  • Web
  • Win32
  • WinRt
  • Xcb
  • Xlib

Example

use softbuffer::GraphicsContext;
use winit::event::{Event, WindowEvent};
use winit::event_loop::{ControlFlow, EventLoop};
use winit::window::WindowBuilder;

fn main() {
    let event_loop = EventLoop::new();
    let window = WindowBuilder::new().build(&event_loop).unwrap();
    let mut graphics_context = unsafe { GraphicsContext::new(window) }.unwrap();

    event_loop.run(move |event, _, control_flow| {
        *control_flow = ControlFlow::Wait;

        match event {
            Event::RedrawRequested(window_id) if window_id == graphics_context.window().id() => {
                let (width, height) = {
                    let size = graphics_context.window().inner_size();
                    (size.width, size.height)
                };
                let buffer = (0..((width * height) as usize))
                    .map(|index| {
                        let y = index / (width as usize);
                        let x = index % (width as usize);
                        let red = x % 255;
                        let green = y % 255;
                        let blue = (x * y) % 255;

                        let color = blue | (green << 8) | (red << 16);

                        color as u32
                    })
                    .collect::
   
    <_>>();

                graphics_context.set_buffer(&buffer, width as u16, height as u16);
            }
            Event::WindowEvent {
                event: WindowEvent::CloseRequested,
                window_id,
            } if window_id == graphics_context.window().id() => {
                *control_flow = ControlFlow::Exit;
            }
            _ => {}
        }
    });
}

   
Comments
  • Add macOS support using Core Graphics

    Add macOS support using Core Graphics

    It draws something, but I am not confident it is correct. I am especially worried about coordinate system.

    What should I expect to see for winit example? I think it would help to include screenshots in README (plural, to show resizing), and for example to be recognizably different when horizontally or vertically flipped. I propose a 45-60-75 triangle.

    opened by sanxiyn 16
  • x11: Implement image transfer using the MIT-SHM extension

    x11: Implement image transfer using the MIT-SHM extension

    This PR implements image transfer using the MIT-SHM extension, allowing us to avoid image transfers over the wire.

    ~~At the moment I can't test this on my machine, as the x11-dl crate has a bug that prevents it from loading the MIT-SHM extension (https://github.com/AltF02/x11-rs/pull/164).~~ Circumvented this by moving to x11rb.

    Closes https://github.com/rust-windowing/softbuffer/issues/38

    (This is a port of rust-windowing/swbuf#23 to the new repository)

    enhancement Xcb Xlib 
    opened by notgull 12
  • x11: Add XCB support to the X11 backend

    x11: Add XCB support to the X11 backend

    This PR adds XCB support to the X11 backend. It uses the x11rb crate to handle interfacing with libxcb. In addition, the drawing logic is reimplemented using x11rb. Xlib support is now implemented by getting the inner libxcb connection from the Xlib Display and then just wrapping that.

    I chose x11rb because it's at arm's length, I trust it, it has minimal dependencies, and it provides easy libxcb support. I'm down to bikeshed if we should use another wrapper.

    Closes #45

    enhancement Xcb Xlib 
    opened by notgull 8
  • Wayland animation example fails on Gnome

    Wayland animation example fails on Gnome

    When running the animation example on Gnome/Mutter 43.2 it causes the entire desktop to freeze for about half a second, then the example terminates with the following error:

    request could not be marshaled: can't send file descriptor
    Error sending request: Resource temporarily unavailable
    

    I've known about this bug for some time, but when I tried diving into Wayland to fix it, I was unable to find a solution. Maybe you can shed some light @ids1024?

    Additionally, some other examples (notably winit_wrong_sized_buffer and fruit) are janky insofar as resizing causes temporary freezes of the softbuffer window.

    bug Wayland 
    opened by john01dav 8
  • Should Wayland allow double buffering or just wait until the buffer is released.

    Should Wayland allow double buffering or just wait until the buffer is released.

    On Wayland, we need to wait for the server to release a wl_buffer before we can reuse it. This generally means clients will double buffer and track buffer age when rendering. However it would be most ideal to avoid double buffering if at all possible.

    This probably means that softbuffer also needs a way to check if the buffer can be acquired to be rendered to if we run out of buffers to use.

    question Wayland Needs Design Work 
    opened by i509VCB 4
  • Use a shared memory buffer for the X11 backend

    Use a shared memory buffer for the X11 backend

    The current X11 backend sends the image over the wire, which is slow and inefficient. We should probably use the MIT-SHM strategy for this crate if it's available.

    (Also, we probably shouldn't create a new image every time we run the set_buffer command, but I think we can take care of that when we solve rust-windowing/softbuffer#37)

    enhancement Xlib 
    opened by notgull 4
  • Semantics of `set_buffer` are not documented

    Semantics of `set_buffer` are not documented

    It takes a slice. Is this slice immediately cloned, or does the window keep a reference to it? Should I double-buffer, or can I clobber the buffer after the call to set_buffer?

    Normally the fact that the slice doesn't stay borrowed would be a hint, but as this is a relatively new library using unsafe code, it's possible that it could be accidentally unsound, which is why documenting this would be helpful.

    opened by LoganDark 4
  • X11 can use XShm for faster rendering

    X11 can use XShm for faster rendering

    Here's an example usage of XShm (originally from Fabrice Bellard's TinyGL): https://github.com/lunixbochs/tinygles/blob/unstable/src/gles/glx.c#L107

    Basically, this allows you to blit pixels directly into X11's memory, saving both a memory copy and the general overhead of passing your image through an X11 socket.

    In the non-shm case, you also shouldn't need to create a new XImage every frame as you're doing now. You only really need to do it on startup and when the window is resized. You can just call XPutImage on an existing XImage repeatedly, as done here: https://github.com/lunixbochs/tinygles/blob/unstable/src/gles/glx.c#L368

    opened by lunixbochs 4
  • use CALayer for macOS backend

    use CALayer for macOS backend

    This should fix: https://github.com/rust-windowing/winit/pull/2189 and https://github.com/rust-windowing/winit/issues/1605

    As you're already constructing a CGImage, you can create an NSImage backed by it using NSCGImageRep

    You can set your view.layer to a new CALayer, and repeatedly set layer.contents to the new NSImage instead of trying to draw to the NSView directly.

    This approach works whether or not you're called from a draw callback, and does not require any changes to winit.

    opened by lunixbochs 4
  • Add web support

    Add web support

    Adds web support via. CanvasRenderingContext2D.putImageData,

    A limitation of this implementation is that it can't coexist with anything which creates a canvas context other than CanvasRenderingContext2D, since only one context can exist per canvas.

    opened by Liamolucko 4
  • Add support and CI tests for BSDs

    Add support and CI tests for BSDs

    This adds a fallback using shm_open/shm_unlink for platforms where memfd_create doesn't exist. This seems to be how this is normally handled, though it's a bit ugly.

    This also builds the wayland/x11 code for NetBSD/OpenBSD/DragonFlyBSD.

    Add CI builds for FreeBSD and NetBSD. We would need some kind of virtualisation though to actually run tests on such targets.

    I've tested the shm_open logic on Linux, but haven't run it on any BSDs.

    opened by ids1024 3
  • GBM/KMS platform

    GBM/KMS platform

    It may be useful to allow presenting CPU rendered buffers directly to the display on Linux.

    raw-window-handle already supports GBM and DRM so it should be possible to use GBM or dumb buffers.

    enhancement help wanted 
    opened by i509VCB 2
  • Make softbuffer window contexts own the pixel buffers.

    Make softbuffer window contexts own the pixel buffers.

    At the moment all backends need to perform a copy to present. Some backends such as Wayland (always) and X11 (with the SHM extensions) can simply share the pixel memory with the server. On Windows and Mac this saving wouldn't be possible, but it would help on other platforms.

    Not sure what redox does in this case.

    enhancement Needs Design Work 
    opened by i509VCB 16
  • Damage in presentation

    Damage in presentation

    In order to efficiently draw on the CPU, it may be desireable to reduce how many pixels are actually drawn.

    Often this involves telling the display server what pixels were changed so that the display server can reuse it's existing framebuffer or perform a partial upload of the texture data to the gpu to save pci bandwidth.

    enhancement Needs Design Work 
    opened by i509VCB 2
  • Split wrapper around

    Split wrapper around "display" and "window" into different types

    @i509vcb suggested this on Matrix. I don't know about other platforms, but for Wayland it could definitely be desirable to not create a new registry, etc. for every window. Doesn't make a difference for uses with a single window, but with a lot of wl_surfaces it definitely is a good idea to not duplicate everything like that.

    enhancement Needs Design Work 
    opened by ids1024 0
Owner
David Johnson
David Johnson
An online pipeline for image processing.

carbaseus An online pipeline for image processing. *carbaseus (feminine carbasea, neuter carbaseum)* : first/second-declension adjective 1. made of f

Maël 5 Sep 12, 2022
A little cross-platform graphics engine written in rust.

Bismuth This is a version of my C++ graphics engine named Bismuth re-written with Rust. My goal is to learn more about the Rust language and make my g

Admiral サイタマ 1 Nov 1, 2021
Rust bindings to bgfx, a cross-platform, graphics API agnostic

Rust bindings to bgfx, a cross-platform, graphics API agnostic, "Bring Your Own Engine/Framework" style rendering library.

Daniel Collin 65 Dec 24, 2022
Cross Platform Rust (crust)

This repository is the code to support my crust series of blog posts on my main Github page which is all about getting an OpenGL renderer up and running using cross platform Rust code.

Marcel Braghetto 4 Aug 21, 2022
Habitat is open source software that creates platform-independent build artifacts and provides built-in deployment and management capabilities.

Habitat is open source software that creates platform-independent build artifacts and provides built-in deployment and management capabilities. The go

Habitat 2.4k Dec 27, 2022
Platform independent data channels for WebRTC/Rust.

preach Platform independent data channels Preach provides an abstraction for WebRTC data channels that runs on both native and web platforms. Preach m

Douglas Dwyer 3 Apr 16, 2023
A small utility to wake computers up or put them to sleep over the local network

WKSL - a wake and sleep utility An experiment in writing a small CLI utility in Rust. The program lets you wake a machine on your local network up fro

Henrik Ravn 0 Nov 14, 2021
💤 Put your Minecraft server to rest when idle.

?? Put your Minecraft server to rest when idle.

Tim Visée 285 Jan 4, 2023
You _can_ put lipstick on a pig

lipstick ?? ?? You can put lipstick on a pig What lipstick compiles a subset of Rust's syntax into C. It's not a "Rust subset" though, since there's n

Roberto Vidal 87 Dec 5, 2022
put.io to sonarr/radarr proxy

putioarr Proxy that allows put.io to be used as a download client for sonarr/radarr/whisparr. The proxy uses the Transmission protocol. Installation T

Wouter de Bie 4 Oct 6, 2023
A lock-free thread-owned queue whereby tasks are taken by stealers in entirety via buffer swapping

Swap Queue A lock-free thread-owned queue whereby tasks are taken by stealers in entirety via buffer swapping. This is meant to be used [thread_local]

Thomas Sieverding 20 Sep 9, 2022
Stack buffer provides alternatives to Buf{Reader,Writer} allocated on the stack instead of the heap.

StackBuf{Reader,Writer} Stack buffer provides alternatives to BufReader and BufWriter allocated on the stack instead of the heap. Its implementation i

Alex Saveau 14 Nov 20, 2022
Simple async codec for rkyv. Reuses streaming buffer for maximum speed

rkyv_codec Simple async codec for rkyv. Reuses streaming buffer for maximum speed! This crate provides a makeshift adaptor for streaming &Archived<Obj

Zyansheep 19 Jun 14, 2022
Astro Format is a library for efficiently encoding and decoding a set of bytes into a single buffer format.

Astro Format is a library for efficiently transcoding arrays into a single buffer and native rust types into strings

Stelar Labs 1 Aug 13, 2022
Rust lib for fetching official protoc (Protocol Buffer compiler) releases

protoc-fetcher Rust library for fetching official Protocol Buffer compiler (protoc) releases, pegged to a specific version. protoc-fetcher downloads a

Arcanyx Technical Wizardry LLC 2 Sep 5, 2022
A high-performance SPSC bounded circular buffer of bytes

Cueue A high performance, single-producer, single-consumer, bounded circular buffer of contiguous elements, that supports lock-free atomic batch opera

Thaler Benedek 38 Dec 28, 2022
CLI tool for deterministically building and verifying executable against on-chain programs or buffer accounts

Solana Verify CLI A command line tool to build and verify solana programs. Users can ensure that the hash of the on-chain program matches the hash of

Ellipsis Labs 5 Jan 30, 2023
A crate to convert bytes to something more useable and the other way around in a way Compatible with the Confluent Schema Registry. Supporting Avro, Protobuf, Json schema, and both async and blocking.

#schema_registry_converter This library provides a way of using the Confluent Schema Registry in a way that is compliant with the Java client. The rel

Gerard Klijs 69 Dec 13, 2022
Learn-rust-the-hard-way - "Learn C The Hard Way" by Zed Shaw Converted to Rust

Learn Rust The Hard Way This is an implementation of Zed Shaw's Learn X The Hard Way for the Rust Programming Language. Installing Rust TODO: Instruct

Ryan Levick 309 Dec 8, 2022