Owned pixel buffer for no-copy presentation
This is based on the API that will be used for no-copy presentation. But wraps it in `set_buffer`. This also fixes the Wayland buffer code to set `self.width` and `self.height` on resize, and set the length of the shared memory file when the buffer is created. Co-authored-by: jtnunley <jtnunley01@gmail.com>
This commit is contained in:
parent
e5d546ff9e
commit
a09e4cf679
19 changed files with 1176 additions and 438 deletions
89
src/web.rs
89
src/web.rs
|
|
@ -1,3 +1,7 @@
|
|||
//! Implementation of software buffering for web targets.
|
||||
|
||||
#![allow(clippy::uninlined_format_args)]
|
||||
|
||||
use raw_window_handle::WebWindowHandle;
|
||||
use wasm_bindgen::Clamped;
|
||||
use wasm_bindgen::JsCast;
|
||||
|
|
@ -6,6 +10,8 @@ use web_sys::HtmlCanvasElement;
|
|||
use web_sys::ImageData;
|
||||
|
||||
use crate::SoftBufferError;
|
||||
use std::convert::TryInto;
|
||||
use std::num::NonZeroU32;
|
||||
|
||||
/// Display implementation for the web platform.
|
||||
///
|
||||
|
|
@ -36,8 +42,17 @@ impl WebDisplayImpl {
|
|||
}
|
||||
|
||||
pub struct WebImpl {
|
||||
/// The handle to the canvas that we're drawing to.
|
||||
canvas: HtmlCanvasElement,
|
||||
|
||||
/// The 2D rendering context for the canvas.
|
||||
ctx: CanvasRenderingContext2d,
|
||||
|
||||
/// The buffer that we're drawing to.
|
||||
buffer: Vec<u32>,
|
||||
|
||||
/// The current width of the canvas.
|
||||
width: u32,
|
||||
}
|
||||
|
||||
impl WebImpl {
|
||||
|
|
@ -73,24 +88,82 @@ impl WebImpl {
|
|||
.dyn_into()
|
||||
.expect("`getContext(\"2d\") didn't return a `CanvasRenderingContext2d`");
|
||||
|
||||
Ok(Self { canvas, ctx })
|
||||
Ok(Self {
|
||||
canvas,
|
||||
ctx,
|
||||
buffer: Vec::new(),
|
||||
width: 0,
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn set_buffer(&mut self, buffer: &[u32], width: u16, height: u16) {
|
||||
self.canvas.set_width(width.into());
|
||||
self.canvas.set_height(height.into());
|
||||
/// Resize the canvas to the given dimensions.
|
||||
pub(crate) fn resize(
|
||||
&mut self,
|
||||
width: NonZeroU32,
|
||||
height: NonZeroU32,
|
||||
) -> Result<(), SoftBufferError> {
|
||||
let width = width.get();
|
||||
let height = height.get();
|
||||
|
||||
let bitmap: Vec<_> = buffer
|
||||
self.buffer.resize(total_len(width, height), 0);
|
||||
self.canvas.set_width(width);
|
||||
self.canvas.set_height(height);
|
||||
self.width = width;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get a pointer to the mutable buffer.
|
||||
pub(crate) fn buffer_mut(&mut self) -> Result<BufferImpl, SoftBufferError> {
|
||||
Ok(BufferImpl { imp: self })
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BufferImpl<'a> {
|
||||
imp: &'a mut WebImpl,
|
||||
}
|
||||
|
||||
impl<'a> BufferImpl<'a> {
|
||||
pub fn pixels(&self) -> &[u32] {
|
||||
&self.imp.buffer
|
||||
}
|
||||
|
||||
pub fn pixels_mut(&mut self) -> &mut [u32] {
|
||||
&mut self.imp.buffer
|
||||
}
|
||||
|
||||
/// Push the buffer to the canvas.
|
||||
pub fn present(self) -> Result<(), SoftBufferError> {
|
||||
// Create a bitmap from the buffer.
|
||||
let bitmap: Vec<_> = self
|
||||
.imp
|
||||
.buffer
|
||||
.iter()
|
||||
.copied()
|
||||
.flat_map(|pixel| [(pixel >> 16) as u8, (pixel >> 8) as u8, pixel as u8, 255])
|
||||
.collect();
|
||||
|
||||
// This should only throw an error if the buffer we pass's size is incorrect, which is checked in the outer `set_buffer` call.
|
||||
// This should only throw an error if the buffer we pass's size is incorrect.
|
||||
let image_data =
|
||||
ImageData::new_with_u8_clamped_array(Clamped(&bitmap), width.into()).unwrap();
|
||||
ImageData::new_with_u8_clamped_array(Clamped(&bitmap), self.imp.width).unwrap();
|
||||
|
||||
// This can only throw an error if `data` is detached, which is impossible.
|
||||
self.ctx.put_image_data(&image_data, 0.0, 0.0).unwrap();
|
||||
self.imp.ctx.put_image_data(&image_data, 0.0, 0.0).unwrap();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn total_len(width: u32, height: u32) -> usize {
|
||||
// Convert width and height to `usize`, then multiply.
|
||||
width
|
||||
.try_into()
|
||||
.ok()
|
||||
.and_then(|w: usize| height.try_into().ok().and_then(|h| w.checked_mul(h)))
|
||||
.unwrap_or_else(|| {
|
||||
panic!(
|
||||
"Overflow when calculating total length of buffer: {}x{}",
|
||||
width, height
|
||||
);
|
||||
})
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue