Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP Format API #186

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion examples/winit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ fn main() {
}

let context = softbuffer::Context::new(window.clone()).unwrap();
let mut surface = softbuffer::Surface::new(&context, window.clone()).unwrap();
let mut surface =
softbuffer::Surface::new(&context, window.clone(), softbuffer::Format::BGRX).unwrap();

event_loop
.run(move |event, elwt| {
Expand Down
4 changes: 4 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@ pub enum SoftBufferError {
rect: crate::Rect,
},

/// The requested format is not supported by the display.
UnsupportedFormat { format: crate::Format },

/// A platform-specific backend error occurred.
///
/// The first field provides a human-readable description of the error. The second field
Expand Down Expand Up @@ -138,6 +141,7 @@ impl fmt::Display for SoftBufferError {
"Damage rect {}x{} at ({}, {}) out of range for backend.",
rect.width, rect.height, rect.x, rect.y
),
Self::UnsupportedFormat { format } => write!(f, "Format {:?} unsupported on display.", format),
Self::Unimplemented => write!(f, "This function is unimplemented on this platform."),
}
}
Expand Down
91 changes: 91 additions & 0 deletions src/format.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
use crate::{Format, Rect, SoftBufferError};
use std::num::NonZeroU32;

pub struct ConvertFormat {
buffer: Vec<u32>,
buffer_presented: bool,
size: Option<(NonZeroU32, NonZeroU32)>,
in_fmt: Format,
out_fmt: Format,
}

impl ConvertFormat {
pub fn new(in_fmt: Format, out_fmt: Format) -> Result<Self, SoftBufferError> {
// TODO select out_fmt from native_formats?
Ok(Self {
buffer: Vec::new(),
buffer_presented: false,
size: None,
in_fmt,
out_fmt,
})
}

pub fn pixels(&self) -> &[u32] {
&self.buffer
}

pub fn pixels_mut(&mut self) -> &mut [u32] {
&mut self.buffer
}

pub fn resize(&mut self, width: NonZeroU32, height: NonZeroU32) {
if self.size == Some((width, height)) {
return;
}
self.size = Some((width, height));
self.buffer_presented = false;
self.buffer
.resize((u32::from(width) * u32::from(height)) as usize, 0);
}

pub fn age(&self) -> u8 {
if self.buffer_presented {
1
} else {
0
}
}

// Can only damage be copied? Need to track damage for multiple buffers? if backend uses
pub fn present(&self, outputs: &mut [u32], damage: &[Rect]) {
assert_eq!(outputs.len(), self.buffer.len());
convert_format(self.in_fmt, &self.buffer, self.out_fmt, outputs);
self.buffer_presented;
}
}

fn convert_pixels<F: FnMut([u8; 4]) -> [u8; 4]>(inputs: &[u32], outputs: &mut [u32], mut cb: F) {
for (input, output) in inputs.iter().zip(outputs.iter_mut()) {
*output = u32::from_ne_bytes(cb(input.to_ne_bytes()));
}
}

// Convert between BGR* and RGB*
#[inline(always)]
fn swap_rb(mut bytes: [u8; 4]) -> [u8; 4] {
bytes.swap(0, 2);
bytes
}

// Convert ***X to ***A format by setting alpha to 255
#[inline(always)]
fn set_opaque(mut bytes: [u8; 4]) -> [u8; 4] {
bytes[3] = 255;
bytes
}

fn convert_format(in_fmt: Format, inputs: &[u32], out_fmt: Format, outputs: &mut [u32]) {
use Format::*;
match (in_fmt, out_fmt) {
(RGBA, RGBA) | (RGBX, RGBX) | (BGRA, BGRA) | (BGRX, BGRX) => {
outputs.copy_from_slice(inputs)
}
(RGBX, RGBA) | (BGRX, BGRA) => convert_pixels(inputs, outputs, set_opaque),
(RGBX, BGRX) | (RGBA, BGRA) | (BGRX, RGBX) | (BGRA, RGBA) => {
convert_pixels(inputs, outputs, swap_rb)
}
(RGBX, BGRA) | (BGRX, RGBA) => convert_pixels(inputs, outputs, |x| set_opaque(swap_rb(x))),
(RGBA | BGRA, RGBX | BGRX) => unimplemented!("can't convert alpha to non-alpha format"),
}
}
5 changes: 5 additions & 0 deletions src/kms.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use std::os::unix::io::{AsFd, BorrowedFd};
use std::rc::Rc;

use crate::error::{InitError, SoftBufferError, SwResultExt};
use crate::Format;

#[derive(Debug)]
pub(crate) struct KmsDisplayImpl<D: ?Sized> {
Expand Down Expand Up @@ -55,6 +56,10 @@ impl<D: HasDisplayHandle> KmsDisplayImpl<D> {
_display: display,
})
}

pub(crate) fn formats(&self) -> Vec<Format> {
vec![Format::BGRX]
}
}

/// All the necessary types for the Drm/Kms backend.
Expand Down
25 changes: 23 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ mod win32;
mod x11;

mod error;
mod format;
mod util;

use std::marker::PhantomData;
Expand Down Expand Up @@ -75,6 +76,15 @@ macro_rules! make_dispatch {
)*
}
}

pub fn formats(&mut self) -> Vec<Format> {
match self {
$(
$(#[$attr])*
Self::$name(inner) => inner.formats(),
)*
}
}
}

#[allow(clippy::large_enum_variant)] // it's boxed anyways
Expand Down Expand Up @@ -256,7 +266,7 @@ pub struct Surface<D, W> {

impl<D: HasDisplayHandle, W: HasWindowHandle> Surface<D, W> {
/// Creates a new surface for the context for the provided window.
pub fn new(context: &Context<D>, window: W) -> Result<Self, SoftBufferError> {
pub fn new(context: &Context<D>, window: W, format: Format) -> Result<Self, SoftBufferError> {
macro_rules! leap {
($e:expr) => {{
match ($e) {
Expand All @@ -283,7 +293,7 @@ impl<D: HasDisplayHandle, W: HasWindowHandle> Surface<D, W> {
}
#[cfg(wayland_platform)]
ContextDispatch::Wayland(wayland_display_impl) => SurfaceDispatch::Wayland(leap!(
wayland::WaylandImpl::new(window, wayland_display_impl.clone())
wayland::WaylandImpl::new(window, wayland_display_impl.clone(), format)
)),
#[cfg(kms_platform)]
ContextDispatch::Kms(kms_display_impl) => {
Expand Down Expand Up @@ -511,3 +521,14 @@ fn display_handle_type_name(handle: &RawDisplayHandle) -> &'static str {
_ => "Unknown Name", //don't completely fail to compile if there is a new raw window handle type that's added at some point
}
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Format {
RGBA,
RGBX,
BGRA,
BGRX,
}

// XXX format conversion: swap components? seperate buffer?
// damage, age
18 changes: 8 additions & 10 deletions src/wayland/buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,13 @@ pub(super) struct WaylandBuffer {
}

impl WaylandBuffer {
pub fn new(shm: &wl_shm::WlShm, width: i32, height: i32, qh: &QueueHandle<State>) -> Self {
pub fn new(
shm: &wl_shm::WlShm,
format: wl_shm::Format,
width: i32,
height: i32,
qh: &QueueHandle<State>,
) -> Self {
// Calculate size to use for shm pool
let pool_size = get_pool_size(width, height);

Expand All @@ -93,15 +99,7 @@ impl WaylandBuffer {
// Create wayland shm pool and buffer
let pool = shm.create_pool(tempfile.as_fd(), pool_size, qh, ());
let released = Arc::new(AtomicBool::new(true));
let buffer = pool.create_buffer(
0,
width,
height,
width * 4,
wl_shm::Format::Xrgb8888,
qh,
released.clone(),
);
let buffer = pool.create_buffer(0, width, height, width * 4, format, qh, released.clone());

Self {
qh: qh.clone(),
Expand Down
Loading