feat(graphics): implement double-buffered graphics surface with lock and post engine
This commit is contained in:
parent
6ae2bcb091
commit
94584bed1e
3 changed files with 118 additions and 0 deletions
|
|
@ -1,2 +1,3 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
pub mod surface;
|
||||
pub mod types;
|
||||
|
|
|
|||
95
crates/molotov-core/src/graphics/surface.rs
Normal file
95
crates/molotov-core/src/graphics/surface.rs
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
use super::types::{ANativeWindow_Buffer, ARect, WindowFormat};
|
||||
use std::ffi::c_void;
|
||||
use std::sync::atomic::{AtomicU32, Ordering};
|
||||
|
||||
pub struct GraphicsSurface {
|
||||
width: i32,
|
||||
height: i32,
|
||||
format: WindowFormat,
|
||||
back_buffer: Vec<u8>,
|
||||
front_buffer: Vec<u8>,
|
||||
is_locked: bool,
|
||||
ref_count: AtomicU32,
|
||||
}
|
||||
|
||||
impl GraphicsSurface {
|
||||
pub fn new(width: i32, height: i32, format: WindowFormat) -> Self {
|
||||
let size = (width as usize) * (height as usize) * format.bytes_per_pixel();
|
||||
Self {
|
||||
width,
|
||||
height,
|
||||
format,
|
||||
back_buffer: vec![0u8; size],
|
||||
front_buffer: vec![0u8; size],
|
||||
is_locked: false,
|
||||
ref_count: AtomicU32::new(1),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn width(&self) -> i32 {
|
||||
self.width
|
||||
}
|
||||
|
||||
pub fn height(&self) -> i32 {
|
||||
self.height
|
||||
}
|
||||
|
||||
pub fn format(&self) -> WindowFormat {
|
||||
self.format
|
||||
}
|
||||
|
||||
pub fn acquire(&self) -> u32 {
|
||||
self.ref_count.fetch_add(1, Ordering::Relaxed) + 1
|
||||
}
|
||||
|
||||
pub fn release(&self) -> u32 {
|
||||
self.ref_count.fetch_sub(1, Ordering::Release) - 1
|
||||
}
|
||||
|
||||
pub fn set_geometry(&mut self, width: i32, height: i32, format: WindowFormat) {
|
||||
if width > 0 && height > 0 {
|
||||
self.width = width;
|
||||
self.height = height;
|
||||
self.format = format;
|
||||
let size = (width as usize) * (height as usize) * format.bytes_per_pixel();
|
||||
self.back_buffer.resize(size, 0);
|
||||
self.front_buffer.resize(size, 0);
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn lock(
|
||||
&mut self,
|
||||
out_buffer: *mut ANativeWindow_Buffer,
|
||||
_in_out_dirty: *mut ARect,
|
||||
) -> i32 {
|
||||
if out_buffer.is_null() {
|
||||
return -libc::EINVAL;
|
||||
}
|
||||
if self.is_locked {
|
||||
return -libc::EBUSY;
|
||||
}
|
||||
|
||||
self.is_locked = true;
|
||||
|
||||
(*out_buffer).width = self.width;
|
||||
(*out_buffer).height = self.height;
|
||||
(*out_buffer).stride = self.width;
|
||||
(*out_buffer).format = self.format as i32;
|
||||
(*out_buffer).bits = self.back_buffer.as_mut_ptr() as *mut c_void;
|
||||
(*out_buffer).reserved = [0; 6];
|
||||
|
||||
0
|
||||
}
|
||||
|
||||
pub fn unlock_and_post(&mut self) -> i32 {
|
||||
if !self.is_locked {
|
||||
return -libc::EINVAL;
|
||||
}
|
||||
|
||||
// Swap front and back buffer for presentation
|
||||
std::mem::swap(&mut self.front_buffer, &mut self.back_buffer);
|
||||
self.is_locked = false;
|
||||
0
|
||||
}
|
||||
}
|
||||
22
crates/molotov-core/tests/surface_buffer_test.rs
Normal file
22
crates/molotov-core/tests/surface_buffer_test.rs
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
use molotov_core::graphics::surface::GraphicsSurface;
|
||||
use molotov_core::graphics::types::WindowFormat;
|
||||
|
||||
#[test]
|
||||
fn test_surface_lock_and_unlock_post() {
|
||||
let mut surface = GraphicsSurface::new(800, 600, WindowFormat::Rgba8888);
|
||||
assert_eq!(surface.width(), 800);
|
||||
assert_eq!(surface.height(), 600);
|
||||
|
||||
let mut buffer = std::mem::MaybeUninit::uninit();
|
||||
let lock_res = unsafe { surface.lock(buffer.as_mut_ptr(), std::ptr::null_mut()) };
|
||||
assert_eq!(lock_res, 0);
|
||||
|
||||
let buf = unsafe { buffer.assume_init() };
|
||||
assert_eq!(buf.width, 800);
|
||||
assert_eq!(buf.height, 600);
|
||||
assert!(!buf.bits.is_null());
|
||||
|
||||
let post_res = surface.unlock_and_post();
|
||||
assert_eq!(post_res, 0);
|
||||
}
|
||||
Reference in a new issue