linux: hook up render event, basic renderer command buffer
This commit is contained in:
parent
7f8c64aa6c
commit
74fde5967b
3 changed files with 129 additions and 52 deletions
|
@ -1,11 +1,58 @@
|
|||
use crate::Scene;
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
const SURFACE_FRAME_COUNT: u32 = 3;
|
||||
const MAX_FRAME_TIME_MS: u32 = 1000;
|
||||
|
||||
pub struct BladeRenderer {
|
||||
gpu: Arc<blade::Context>,
|
||||
command_encoder: blade::CommandEncoder,
|
||||
last_sync_point: Option<blade::SyncPoint>,
|
||||
}
|
||||
|
||||
impl BladeRenderer {
|
||||
pub fn new(gpu: Arc<blade::Context>) -> Self {
|
||||
Self { gpu }
|
||||
pub fn new(gpu: Arc<blade::Context>, size: blade::Extent) -> Self {
|
||||
let _surface_format = gpu.resize(blade::SurfaceConfig {
|
||||
size,
|
||||
usage: blade::TextureUsage::TARGET,
|
||||
frame_count: SURFACE_FRAME_COUNT,
|
||||
});
|
||||
let command_encoder = gpu.create_command_encoder(blade::CommandEncoderDesc {
|
||||
name: "main",
|
||||
buffer_count: 2,
|
||||
});
|
||||
Self {
|
||||
gpu,
|
||||
command_encoder,
|
||||
last_sync_point: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn destroy(&mut self) {
|
||||
self.gpu.destroy_command_encoder(&mut self.command_encoder);
|
||||
}
|
||||
|
||||
pub fn resize(&mut self, size: blade::Extent) {
|
||||
self.gpu.resize(blade::SurfaceConfig {
|
||||
size,
|
||||
usage: blade::TextureUsage::TARGET,
|
||||
frame_count: SURFACE_FRAME_COUNT,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn draw(&mut self, scene: &Scene) {
|
||||
let frame = self.gpu.acquire_frame();
|
||||
self.command_encoder.start();
|
||||
|
||||
self.command_encoder.present(frame);
|
||||
|
||||
let sync_point = self.gpu.submit(&mut self.command_encoder);
|
||||
if let Some(ref last_sp) = self.last_sync_point {
|
||||
if !self.gpu.wait_for(last_sp, MAX_FRAME_TIME_MS) {
|
||||
panic!("GPU hung");
|
||||
}
|
||||
}
|
||||
self.last_sync_point = Some(sync_point);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -85,44 +85,46 @@ impl Platform for LinuxPlatform {
|
|||
fn run(&self, on_finish_launching: Box<dyn FnOnce()>) {
|
||||
on_finish_launching();
|
||||
|
||||
let mut need_repaint = HashSet::<x::Window>::default();
|
||||
|
||||
while !self.0.lock().windows.is_empty() {
|
||||
let event = self.0.lock().xcb_connection.wait_for_event().unwrap();
|
||||
let mut repaint_x_window = None;
|
||||
match event {
|
||||
xcb::Event::X(x::Event::ClientMessage(ev)) => {
|
||||
if let x::ClientMessageData::Data32([atom, ..]) = ev.data() {
|
||||
let mut lock = self.0.lock();
|
||||
if atom == lock.atoms.wm_del_window.resource_id() {
|
||||
let mut this = self.0.lock();
|
||||
if atom == this.atoms.wm_del_window.resource_id() {
|
||||
// window "x" button clicked by user, we gracefully exit
|
||||
{
|
||||
let mut window = lock.windows[&ev.window()].lock();
|
||||
let mut window = this.windows[&ev.window()].lock();
|
||||
window.destroy();
|
||||
}
|
||||
lock.windows.remove(&ev.window());
|
||||
this.xcb_connection.send_request(&x::UnmapWindow {
|
||||
window: ev.window(),
|
||||
});
|
||||
this.xcb_connection.send_request(&x::DestroyWindow {
|
||||
window: ev.window(),
|
||||
});
|
||||
this.windows.remove(&ev.window());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {} /*
|
||||
Event::Expose(event) => {
|
||||
if event.count == 0 {
|
||||
need_repaint.insert(event.window);
|
||||
}
|
||||
}
|
||||
Event::ConfigureNotify(event) => {
|
||||
let lock = self.0.lock();
|
||||
let mut window = lock.windows[&event.window].lock();
|
||||
window.resize(event.width, event.height);
|
||||
}
|
||||
_ => {}*/
|
||||
xcb::Event::X(x::Event::Expose(ev)) => {
|
||||
repaint_x_window = Some(ev.window());
|
||||
}
|
||||
xcb::Event::X(x::Event::ResizeRequest(ev)) => {
|
||||
let this = self.0.lock();
|
||||
let mut window = this.windows[&ev.window()].lock();
|
||||
window.resize(ev.width(), ev.height());
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
for x_window in need_repaint.drain() {
|
||||
let lock = self.0.lock();
|
||||
let mut window = lock.windows[&x_window].lock();
|
||||
window.paint();
|
||||
lock.xcb_connection.flush();
|
||||
if let Some(x_window) = repaint_x_window {
|
||||
let this = self.0.lock();
|
||||
let mut window = this.windows[&x_window].lock();
|
||||
window.request_frame();
|
||||
this.xcb_connection.flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -140,22 +142,22 @@ impl Platform for LinuxPlatform {
|
|||
fn unhide_other_apps(&self) {}
|
||||
|
||||
fn displays(&self) -> Vec<Rc<dyn PlatformDisplay>> {
|
||||
let lock = self.0.lock();
|
||||
let setup = lock.xcb_connection.get_setup();
|
||||
let this = self.0.lock();
|
||||
let setup = this.xcb_connection.get_setup();
|
||||
setup
|
||||
.roots()
|
||||
.enumerate()
|
||||
.map(|(root_id, _)| {
|
||||
Rc::new(LinuxDisplay::new(&lock.xcb_connection, root_id as i32))
|
||||
Rc::new(LinuxDisplay::new(&this.xcb_connection, root_id as i32))
|
||||
as Rc<dyn PlatformDisplay>
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn display(&self, id: DisplayId) -> Option<Rc<dyn PlatformDisplay>> {
|
||||
let lock = self.0.lock();
|
||||
let this = self.0.lock();
|
||||
Some(Rc::new(LinuxDisplay::new(
|
||||
&lock.xcb_connection,
|
||||
&this.xcb_connection,
|
||||
id.0 as i32,
|
||||
)))
|
||||
}
|
||||
|
@ -169,18 +171,18 @@ impl Platform for LinuxPlatform {
|
|||
handle: AnyWindowHandle,
|
||||
options: WindowOptions,
|
||||
) -> Box<dyn PlatformWindow> {
|
||||
let mut lock = self.0.lock();
|
||||
let x_window = lock.xcb_connection.generate_id();
|
||||
let mut this = self.0.lock();
|
||||
let x_window = this.xcb_connection.generate_id();
|
||||
|
||||
let window_ptr = LinuxWindowState::new_ptr(
|
||||
options,
|
||||
handle,
|
||||
&lock.xcb_connection,
|
||||
lock.x_root_index,
|
||||
&this.xcb_connection,
|
||||
this.x_root_index,
|
||||
x_window,
|
||||
&lock.atoms,
|
||||
&this.atoms,
|
||||
);
|
||||
lock.windows.insert(x_window, window_ptr.clone());
|
||||
this.windows.insert(x_window, window_ptr.clone());
|
||||
Box::new(LinuxWindow(window_ptr))
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,12 @@ use std::{
|
|||
};
|
||||
use xcb::{x, Xid as _};
|
||||
|
||||
#[derive(Default)]
|
||||
struct Callbacks {
|
||||
request_frame: Option<Box<dyn FnMut()>>,
|
||||
resize: Option<Box<dyn FnMut(Size<Pixels>, f32)>>,
|
||||
}
|
||||
|
||||
pub(crate) struct LinuxWindowState {
|
||||
display: Rc<dyn PlatformDisplay>,
|
||||
x_window: x::Window,
|
||||
|
@ -18,6 +24,7 @@ pub(crate) struct LinuxWindowState {
|
|||
content_size: Size<Pixels>,
|
||||
sprite_atlas: Arc<BladeAtlas>,
|
||||
renderer: BladeRenderer,
|
||||
callbacks: Callbacks,
|
||||
}
|
||||
|
||||
pub(crate) type LinuxWindowStatePtr = Arc<Mutex<LinuxWindowState>>;
|
||||
|
@ -65,7 +72,9 @@ impl LinuxWindowState {
|
|||
|
||||
let xcb_values = [
|
||||
x::Cw::BackPixel(screen.white_pixel()),
|
||||
x::Cw::EventMask(x::EventMask::EXPOSURE | x::EventMask::KEY_PRESS),
|
||||
x::Cw::EventMask(
|
||||
x::EventMask::EXPOSURE | x::EventMask::RESIZE_REDIRECT | x::EventMask::KEY_PRESS,
|
||||
),
|
||||
];
|
||||
|
||||
let (bound_x, bound_y, bound_width, bound_height) = match options.bounds {
|
||||
|
@ -137,6 +146,11 @@ impl LinuxWindowState {
|
|||
}
|
||||
.unwrap(),
|
||||
);
|
||||
let gpu_extent = blade::Extent {
|
||||
width: bound_width as u32,
|
||||
height: bound_height as u32,
|
||||
depth: 1,
|
||||
};
|
||||
|
||||
Arc::new(Mutex::new(Self {
|
||||
display: Rc::new(LinuxDisplay::new(xcb_connection, x_screen_index)),
|
||||
|
@ -147,7 +161,8 @@ impl LinuxWindowState {
|
|||
height: Pixels(bound_height as f32),
|
||||
},
|
||||
sprite_atlas: Arc::new(BladeAtlas::new(&gpu)),
|
||||
renderer: BladeRenderer::new(gpu),
|
||||
renderer: BladeRenderer::new(gpu, gpu_extent),
|
||||
callbacks: Callbacks::default(),
|
||||
}))
|
||||
}
|
||||
|
||||
|
@ -156,14 +171,25 @@ impl LinuxWindowState {
|
|||
width: Pixels(width as f32),
|
||||
height: Pixels(height as f32),
|
||||
};
|
||||
self.renderer.resize(blade::Extent {
|
||||
width: width as u32,
|
||||
height: height as u32,
|
||||
depth: 1,
|
||||
});
|
||||
if let Some(ref mut fun) = self.callbacks.resize {
|
||||
fun(self.content_size, 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn request_frame(&mut self) {
|
||||
if let Some(ref mut fun) = self.callbacks.request_frame {
|
||||
fun();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn destroy(&mut self) {
|
||||
self.sprite_atlas.destroy();
|
||||
}
|
||||
|
||||
pub fn paint(&mut self) {
|
||||
//TODO
|
||||
self.renderer.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -243,27 +269,27 @@ impl PlatformWindow for LinuxWindow {
|
|||
unimplemented!()
|
||||
}
|
||||
|
||||
fn on_request_frame(&self, _callback: Box<dyn FnMut()>) {}
|
||||
fn on_request_frame(&self, callback: Box<dyn FnMut()>) {
|
||||
self.0.lock().callbacks.request_frame = Some(callback);
|
||||
}
|
||||
|
||||
fn on_input(&self, callback: Box<dyn FnMut(crate::PlatformInput) -> bool>) {}
|
||||
|
||||
fn on_active_status_change(&self, callback: Box<dyn FnMut(bool)>) {}
|
||||
|
||||
fn on_resize(&self, callback: Box<dyn FnMut(Size<Pixels>, f32)>) {}
|
||||
fn on_resize(&self, callback: Box<dyn FnMut(Size<Pixels>, f32)>) {
|
||||
self.0.lock().callbacks.resize = Some(callback);
|
||||
}
|
||||
|
||||
fn on_fullscreen(&self, _callback: Box<dyn FnMut(bool)>) {}
|
||||
|
||||
fn on_moved(&self, callback: Box<dyn FnMut()>) {}
|
||||
|
||||
fn on_should_close(&self, callback: Box<dyn FnMut() -> bool>) {}
|
||||
fn on_should_close(&self, _callback: Box<dyn FnMut() -> bool>) {}
|
||||
|
||||
fn on_close(&self, _callback: Box<dyn FnOnce()>) {
|
||||
unimplemented!()
|
||||
}
|
||||
fn on_close(&self, _callback: Box<dyn FnOnce()>) {}
|
||||
|
||||
fn on_appearance_changed(&self, _callback: Box<dyn FnMut()>) {
|
||||
unimplemented!()
|
||||
}
|
||||
fn on_appearance_changed(&self, _callback: Box<dyn FnMut()>) {}
|
||||
|
||||
fn is_topmost_for_position(&self, _position: crate::Point<Pixels>) -> bool {
|
||||
unimplemented!()
|
||||
|
@ -271,7 +297,9 @@ impl PlatformWindow for LinuxWindow {
|
|||
|
||||
fn invalidate(&self) {}
|
||||
|
||||
fn draw(&self, _scene: &crate::Scene) {}
|
||||
fn draw(&self, scene: &crate::Scene) {
|
||||
self.0.lock().renderer.draw(scene);
|
||||
}
|
||||
|
||||
fn sprite_atlas(&self) -> sync::Arc<dyn crate::PlatformAtlas> {
|
||||
self.0.lock().sprite_atlas.clone()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue