⚠ This page is served via a proxy. Original site: https://github.com
This service does not collect credentials or authentication data.
Skip to content
Open
No due date
Last updated Jan 19, 2026
9% complete

The next version of Softbuffer. @madsmtm is envisioning the end result is something like:

pub struct Context<D> { ... }

impl<D: HasDisplayHandle> Context<D> {
    pub fn new(display: D) -> Result<Self, CreationError> { ... }

    pub fn supported_pixel_formats(&self) -> &[PixelFormat] { ... }
    pub fn supported_scale_modes(&self) -> &[ScaleMode] { ... }
    pub fn supported_filter_modes(&self) -> &[FilterMode] { ... }
}

pub struct Surface<D, W> { ... }

impl<D: HasDisplayHandle, W: HasWindowHandle> Surface<D, W> {
    pub fn new(context: &Context<D>, window: W) -> Result<Self, CreationError> { ... }

    pub fn window(&self) -> &W { ... }

    pub fn width(&self) -> u32 { ... }
    pub fn height(&self) -> u32 { ... }
    pub fn pixel_format(&self) -> PixelFormat { ... }
    pub fn configure(&mut self, width: u32, height: u32, pixel_format: PixelFormat) -> Result<(), ConfigureError> { ... }
    pub fn resize(&mut self, width: u32, height: u32) -> Result<(), ConfigureError> {
        self.configure(width, height, self.pixel_format())
    }

    pub fn alpha_mode(&self) -> AlphaMode { ... }
    pub fn set_alpha_mode(&mut self, alpha_mode: AlphaMode) { ... }

    // Only necessary when surface size != window size
    pub fn scale_mode(&self) -> ScaleMode { ... }
    pub fn set_scale_mode(&mut self, scale_mode: ScaleMode) { ... }
    pub fn filter_mode(&self) -> FilterMode { ... }
    pub fn set_scale_mode(&mut self, filter_mode: FilterMode) { ... }

    pub fn present_mode(&self) -> PresentMode { ... }
    pub fn set_present_mode(&mut self, present_mode: PresentMode) { ... }

    pub fn next_buffer(&mut self) -> Result<Buffer<'_>, NextBufferError> { ... }
}

pub enum PixelFormat {
    Rgba8,
    Bgra8,
    Bgra4,
    A2bgr10,
    Bgra16f,
    Bgra32f,
    // + a bunch more similar to https://docs.rs/wgpu/latest/wgpu/enum.TextureFormat.html
}

pub enum AlphaMode {
    #[default]
    Opaque,
    PreMultiplied,
    PostMultiplied,
}

pub enum PresentMode {
    #[default]
    Fifo,
    Immediate,
    Mailbox,
    // Unclear if this is the desired naming?
}

pub enum ScaleMode {
    #[default]
    Stretch,
    Letterbox,
    Crop,
}

/// Anti-aliasing.
pub enum FilterMode {
    Nearest,
    #[default]
    Linear,
    Trilinear,
}

struct Buffer<'a> {
    width: u32,
    height: u32,
    byte_stride: u32,
    pixel_format: PixelFormat,
    age: u8,
    data: &'a mut [u8],
    platform: PlatformSpecificData<'a>,
}

impl Buffer<'_> {
    pub fn width(&self) -> u32 { self.width }
    pub fn height(&self) -> u32 { self.height }
    pub fn byte_stride(&self) -> u32 { self.byte_stride }
    pub fn pixel_format(&self) -> PixelFormat { self.pixel_format }

    pub fn age(&self) -> u8 { self.age }

    pub fn data(&mut self) -> &mut [u8] { self.data }
    // Each row is `byte_stride` wide.
    pub fn rows(&mut self) -> impl Iterator<Item = &mut [u8]> { ... }

    // Probably .data_u16 / .data_u32 / .data_f16 / .data_f32 too.

    pub fn present(self) -> Result<(), PresentError> { ... }
    pub fn present_with_damage(self, damage: &[Rect]) -> Result<(), PresentError> { ... }
}

//
// Helpers for making people fall in the pit of success in terms of performance.
//

pub const DEFAULT_PIXEL_FORMAT: PixelFormat = if cfg!(android, wasm) { PixelFormat::Rgba8 } else { PixelFormat::Bgra8 };

struct Pixel {
    // Ordering depends on platform
    pub r: u8,
    pub g: u8,
    pub b: u8,
    pub a: u8,
}

impl Pixel {
    pub const BLACK: Self::new_rgba(0, 0, 0, 0);

    pub const fn new_rgb(r: u8, g: u8, b: u8) -> Self { ... }
    pub const fn new_rgba(r: u8, g: u8, b: u8, a: u8) -> Self { ... }
}

impl Buffer<'_> {
    // Each row is `byte_stride / 4` wide.
    pub fn pixel_rows(&mut self) -> impl Iterator<Item = &mut [Pixel]> { ... }
}

List view