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;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
const SURFACE_FRAME_COUNT: u32 = 3;
|
||||||
|
const MAX_FRAME_TIME_MS: u32 = 1000;
|
||||||
|
|
||||||
pub struct BladeRenderer {
|
pub struct BladeRenderer {
|
||||||
gpu: Arc<blade::Context>,
|
gpu: Arc<blade::Context>,
|
||||||
|
command_encoder: blade::CommandEncoder,
|
||||||
|
last_sync_point: Option<blade::SyncPoint>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BladeRenderer {
|
impl BladeRenderer {
|
||||||
pub fn new(gpu: Arc<blade::Context>) -> Self {
|
pub fn new(gpu: Arc<blade::Context>, size: blade::Extent) -> Self {
|
||||||
Self { gpu }
|
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()>) {
|
fn run(&self, on_finish_launching: Box<dyn FnOnce()>) {
|
||||||
on_finish_launching();
|
on_finish_launching();
|
||||||
|
|
||||||
let mut need_repaint = HashSet::<x::Window>::default();
|
|
||||||
|
|
||||||
while !self.0.lock().windows.is_empty() {
|
while !self.0.lock().windows.is_empty() {
|
||||||
let event = self.0.lock().xcb_connection.wait_for_event().unwrap();
|
let event = self.0.lock().xcb_connection.wait_for_event().unwrap();
|
||||||
|
let mut repaint_x_window = None;
|
||||||
match event {
|
match event {
|
||||||
xcb::Event::X(x::Event::ClientMessage(ev)) => {
|
xcb::Event::X(x::Event::ClientMessage(ev)) => {
|
||||||
if let x::ClientMessageData::Data32([atom, ..]) = ev.data() {
|
if let x::ClientMessageData::Data32([atom, ..]) = ev.data() {
|
||||||
let mut lock = self.0.lock();
|
let mut this = self.0.lock();
|
||||||
if atom == lock.atoms.wm_del_window.resource_id() {
|
if atom == this.atoms.wm_del_window.resource_id() {
|
||||||
// window "x" button clicked by user, we gracefully exit
|
// 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();
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {} /*
|
xcb::Event::X(x::Event::Expose(ev)) => {
|
||||||
Event::Expose(event) => {
|
repaint_x_window = Some(ev.window());
|
||||||
if event.count == 0 {
|
}
|
||||||
need_repaint.insert(event.window);
|
xcb::Event::X(x::Event::ResizeRequest(ev)) => {
|
||||||
}
|
let this = self.0.lock();
|
||||||
}
|
let mut window = this.windows[&ev.window()].lock();
|
||||||
Event::ConfigureNotify(event) => {
|
window.resize(ev.width(), ev.height());
|
||||||
let lock = self.0.lock();
|
}
|
||||||
let mut window = lock.windows[&event.window].lock();
|
_ => {}
|
||||||
window.resize(event.width, event.height);
|
|
||||||
}
|
|
||||||
_ => {}*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for x_window in need_repaint.drain() {
|
if let Some(x_window) = repaint_x_window {
|
||||||
let lock = self.0.lock();
|
let this = self.0.lock();
|
||||||
let mut window = lock.windows[&x_window].lock();
|
let mut window = this.windows[&x_window].lock();
|
||||||
window.paint();
|
window.request_frame();
|
||||||
lock.xcb_connection.flush();
|
this.xcb_connection.flush();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -140,22 +142,22 @@ impl Platform for LinuxPlatform {
|
||||||
fn unhide_other_apps(&self) {}
|
fn unhide_other_apps(&self) {}
|
||||||
|
|
||||||
fn displays(&self) -> Vec<Rc<dyn PlatformDisplay>> {
|
fn displays(&self) -> Vec<Rc<dyn PlatformDisplay>> {
|
||||||
let lock = self.0.lock();
|
let this = self.0.lock();
|
||||||
let setup = lock.xcb_connection.get_setup();
|
let setup = this.xcb_connection.get_setup();
|
||||||
setup
|
setup
|
||||||
.roots()
|
.roots()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(root_id, _)| {
|
.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>
|
as Rc<dyn PlatformDisplay>
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn display(&self, id: DisplayId) -> Option<Rc<dyn PlatformDisplay>> {
|
fn display(&self, id: DisplayId) -> Option<Rc<dyn PlatformDisplay>> {
|
||||||
let lock = self.0.lock();
|
let this = self.0.lock();
|
||||||
Some(Rc::new(LinuxDisplay::new(
|
Some(Rc::new(LinuxDisplay::new(
|
||||||
&lock.xcb_connection,
|
&this.xcb_connection,
|
||||||
id.0 as i32,
|
id.0 as i32,
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
@ -169,18 +171,18 @@ impl Platform for LinuxPlatform {
|
||||||
handle: AnyWindowHandle,
|
handle: AnyWindowHandle,
|
||||||
options: WindowOptions,
|
options: WindowOptions,
|
||||||
) -> Box<dyn PlatformWindow> {
|
) -> Box<dyn PlatformWindow> {
|
||||||
let mut lock = self.0.lock();
|
let mut this = self.0.lock();
|
||||||
let x_window = lock.xcb_connection.generate_id();
|
let x_window = this.xcb_connection.generate_id();
|
||||||
|
|
||||||
let window_ptr = LinuxWindowState::new_ptr(
|
let window_ptr = LinuxWindowState::new_ptr(
|
||||||
options,
|
options,
|
||||||
handle,
|
handle,
|
||||||
&lock.xcb_connection,
|
&this.xcb_connection,
|
||||||
lock.x_root_index,
|
this.x_root_index,
|
||||||
x_window,
|
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))
|
Box::new(LinuxWindow(window_ptr))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,12 @@ use std::{
|
||||||
};
|
};
|
||||||
use xcb::{x, Xid as _};
|
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 {
|
pub(crate) struct LinuxWindowState {
|
||||||
display: Rc<dyn PlatformDisplay>,
|
display: Rc<dyn PlatformDisplay>,
|
||||||
x_window: x::Window,
|
x_window: x::Window,
|
||||||
|
@ -18,6 +24,7 @@ pub(crate) struct LinuxWindowState {
|
||||||
content_size: Size<Pixels>,
|
content_size: Size<Pixels>,
|
||||||
sprite_atlas: Arc<BladeAtlas>,
|
sprite_atlas: Arc<BladeAtlas>,
|
||||||
renderer: BladeRenderer,
|
renderer: BladeRenderer,
|
||||||
|
callbacks: Callbacks,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) type LinuxWindowStatePtr = Arc<Mutex<LinuxWindowState>>;
|
pub(crate) type LinuxWindowStatePtr = Arc<Mutex<LinuxWindowState>>;
|
||||||
|
@ -65,7 +72,9 @@ impl LinuxWindowState {
|
||||||
|
|
||||||
let xcb_values = [
|
let xcb_values = [
|
||||||
x::Cw::BackPixel(screen.white_pixel()),
|
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 {
|
let (bound_x, bound_y, bound_width, bound_height) = match options.bounds {
|
||||||
|
@ -137,6 +146,11 @@ impl LinuxWindowState {
|
||||||
}
|
}
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
);
|
);
|
||||||
|
let gpu_extent = blade::Extent {
|
||||||
|
width: bound_width as u32,
|
||||||
|
height: bound_height as u32,
|
||||||
|
depth: 1,
|
||||||
|
};
|
||||||
|
|
||||||
Arc::new(Mutex::new(Self {
|
Arc::new(Mutex::new(Self {
|
||||||
display: Rc::new(LinuxDisplay::new(xcb_connection, x_screen_index)),
|
display: Rc::new(LinuxDisplay::new(xcb_connection, x_screen_index)),
|
||||||
|
@ -147,7 +161,8 @@ impl LinuxWindowState {
|
||||||
height: Pixels(bound_height as f32),
|
height: Pixels(bound_height as f32),
|
||||||
},
|
},
|
||||||
sprite_atlas: Arc::new(BladeAtlas::new(&gpu)),
|
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),
|
width: Pixels(width as f32),
|
||||||
height: Pixels(height 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) {
|
pub fn destroy(&mut self) {
|
||||||
self.sprite_atlas.destroy();
|
self.sprite_atlas.destroy();
|
||||||
}
|
self.renderer.destroy();
|
||||||
|
|
||||||
pub fn paint(&mut self) {
|
|
||||||
//TODO
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -243,27 +269,27 @@ impl PlatformWindow for LinuxWindow {
|
||||||
unimplemented!()
|
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_input(&self, callback: Box<dyn FnMut(crate::PlatformInput) -> bool>) {}
|
||||||
|
|
||||||
fn on_active_status_change(&self, callback: Box<dyn FnMut(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_fullscreen(&self, _callback: Box<dyn FnMut(bool)>) {}
|
||||||
|
|
||||||
fn on_moved(&self, callback: Box<dyn FnMut()>) {}
|
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()>) {
|
fn on_close(&self, _callback: Box<dyn FnOnce()>) {}
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn on_appearance_changed(&self, _callback: Box<dyn FnMut()>) {
|
fn on_appearance_changed(&self, _callback: Box<dyn FnMut()>) {}
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_topmost_for_position(&self, _position: crate::Point<Pixels>) -> bool {
|
fn is_topmost_for_position(&self, _position: crate::Point<Pixels>) -> bool {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
|
@ -271,7 +297,9 @@ impl PlatformWindow for LinuxWindow {
|
||||||
|
|
||||||
fn invalidate(&self) {}
|
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> {
|
fn sprite_atlas(&self) -> sync::Arc<dyn crate::PlatformAtlas> {
|
||||||
self.0.lock().sprite_atlas.clone()
|
self.0.lock().sprite_atlas.clone()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue