feat(wayland): fully async!!!

This commit is contained in:
Nova
2022-09-04 00:35:44 -04:00
parent a42834063e
commit 50161ed87d
12 changed files with 328 additions and 211 deletions

12
src/core/destroy_queue.rs Normal file
View File

@@ -0,0 +1,12 @@
use parking_lot::Mutex;
use std::any::Any;
static MAIN_DESTROY_QUEUE: Mutex<Vec<Box<dyn Any + Send + Sync>>> = Mutex::new(Vec::new());
pub fn add<T: Any + Sync + Send>(thing: T) {
MAIN_DESTROY_QUEUE.lock().push(Box::new(thing));
}
pub fn clear() {
MAIN_DESTROY_QUEUE.lock().clear();
}

View File

@@ -1,3 +1,4 @@
pub mod destroy_queue;
pub mod resource; pub mod resource;
pub mod client; pub mod client;
pub mod eventloop; pub mod eventloop;

View File

@@ -2,21 +2,18 @@ mod core;
mod nodes; mod nodes;
mod wayland; mod wayland;
use crate::core::destroy_queue;
use crate::nodes::model::{MODELS_TO_DROP, MODEL_REGISTRY}; use crate::nodes::model::{MODELS_TO_DROP, MODEL_REGISTRY};
use crate::wayland::WaylandState; use crate::wayland::Wayland;
use self::core::eventloop::EventLoop; use self::core::eventloop::EventLoop;
use anyhow::Result; use anyhow::Result;
use clap::Parser; use clap::Parser;
use once_cell::sync::Lazy;
use parking_lot::Mutex;
use slog::Drain; use slog::Drain;
use std::sync::Arc; use std::sync::Arc;
use stereokit::{lifecycle::DisplayMode, Settings}; use stereokit::{lifecycle::DisplayMode, Settings};
use tokio::{runtime::Handle, sync::oneshot}; use tokio::{runtime::Handle, sync::oneshot};
static TOKIO_HANDLE: Lazy<Mutex<Option<Handle>>> = Lazy::new(Default::default);
#[derive(Parser)] #[derive(Parser)]
#[clap(author, version, about, long_about = None)] #[clap(author, version, about, long_about = None)]
struct CliArgs { struct CliArgs {
@@ -56,15 +53,18 @@ fn main() -> Result<()> {
} }
let (event_stop_tx, event_stop_rx) = oneshot::channel::<()>(); let (event_stop_tx, event_stop_rx) = oneshot::channel::<()>();
let (handle_sender, handle_receiver) = oneshot::channel::<Handle>();
let event_thread = std::thread::Builder::new() let event_thread = std::thread::Builder::new()
.name("event_loop".to_owned()) .name("event_loop".to_owned())
.spawn(move || event_loop(event_stop_rx))?; .spawn(move || event_loop(handle_sender, event_stop_rx))?;
let _tokio_handle = handle_receiver.blocking_recv()?.enter();
let mut wayland = WaylandState::new(log)?; let mut wayland = Wayland::new(log)?;
println!("Stardust ready!"); println!("Stardust ready!");
stereokit.run( stereokit.run(
|draw_ctx| { |draw_ctx| {
wayland.frame(&stereokit); wayland.frame(&stereokit);
destroy_queue::clear();
nodes::root::Root::logic_step(stereokit.time_elapsed()); nodes::root::Root::logic_step(stereokit.time_elapsed());
for model in MODEL_REGISTRY.get_valid_contents() { for model in MODEL_REGISTRY.get_valid_contents() {
@@ -72,7 +72,7 @@ fn main() -> Result<()> {
} }
MODELS_TO_DROP.lock().clear(); MODELS_TO_DROP.lock().clear();
unsafe { wayland.renderer.egl_context().make_current().unwrap() }; wayland.make_context_current();
}, },
|| { || {
println!("Cleanly shut down StereoKit"); println!("Cleanly shut down StereoKit");
@@ -89,9 +89,14 @@ fn main() -> Result<()> {
Ok(()) Ok(())
} }
#[tokio::main] // #[tokio::main]
async fn event_loop(stop_rx: oneshot::Receiver<()>) -> anyhow::Result<()> { #[tokio::main(flavor = "current_thread")]
TOKIO_HANDLE.lock().replace(Handle::current()); async fn event_loop(
handle_sender: oneshot::Sender<Handle>,
stop_rx: oneshot::Receiver<()>,
) -> anyhow::Result<()> {
let _ = handle_sender.send(Handle::current());
// console_subscriber::init();
let (event_loop, event_loop_join_handle) = let (event_loop, event_loop_join_handle) =
EventLoop::new().expect("Couldn't create server socket"); EventLoop::new().expect("Couldn't create server socket");

View File

@@ -6,7 +6,6 @@ use super::model::Model;
use super::spatial::Spatial; use super::spatial::Spatial;
use crate::core::client::Client; use crate::core::client::Client;
use crate::core::registry::Registry; use crate::core::registry::Registry;
use crate::TOKIO_HANDLE;
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use libstardustxr::scenegraph::ScenegraphError; use libstardustxr::scenegraph::ScenegraphError;
use nanoid::nanoid; use nanoid::nanoid;
@@ -175,7 +174,7 @@ impl Node {
let path = self.path.clone(); let path = self.path.clone();
let method = method.to_string(); let method = method.to_string();
let data = data.to_vec(); let data = data.to_vec();
TOKIO_HANDLE.lock().as_ref().unwrap().spawn(async move { tokio::spawn(async move {
if let Some(messenger) = client.messenger.as_ref() { if let Some(messenger) = client.messenger.as_ref() {
let _ = messenger let _ = messenger
.send_remote_signal(path.as_str(), method.as_str(), data.as_slice()) .send_remote_signal(path.as_str(), method.as_str(), data.as_slice())

View File

@@ -1,20 +1,11 @@
use std::sync::Arc; use super::state::WaylandState;
use crate::nodes::{core::Node, item::ItemType}; use crate::nodes::{core::Node, item::ItemType};
use super::{panel_item::PanelItem, surface::CoreSurface, WaylandState};
use send_wrapper::SendWrapper;
use smithay::{ use smithay::{
backend::renderer::utils::{
import_surface_tree, on_commit_buffer_handler, RendererSurfaceStateUserData,
},
delegate_compositor, delegate_compositor,
reexports::wayland_server::protocol::wl_surface::WlSurface, reexports::wayland_server::protocol::wl_surface::WlSurface,
wayland::{ wayland::compositor::{self, CompositorHandler, CompositorState},
compositor::{self, CompositorHandler, CompositorState},
shell::xdg::XdgToplevelSurfaceData,
},
}; };
use std::sync::Arc;
impl CompositorHandler for WaylandState { impl CompositorHandler for WaylandState {
fn compositor_state(&mut self) -> &mut CompositorState { fn compositor_state(&mut self) -> &mut CompositorState {
@@ -22,40 +13,12 @@ impl CompositorHandler for WaylandState {
} }
fn commit(&mut self, surface: &WlSurface) { fn commit(&mut self, surface: &WlSurface) {
// Let Smithay handle all the buffer maintenance
on_commit_buffer_handler(surface);
// Create/update textures from all buffers
import_surface_tree(&mut self.renderer, surface, &self.log).unwrap();
compositor::with_states(surface, |data| { compositor::with_states(surface, |data| {
let mapped = data if let Some(panel_node) = data.data_map.get::<Arc<Node>>() {
.data_map let item = panel_node.item.get().unwrap();
.get::<RendererSurfaceStateUserData>() if let ItemType::Panel(panel_item) = &item.specialization {
.map(|surface_states| surface_states.borrow().wl_buffer().is_some()) panel_item.resize(&data.data_map);
.unwrap_or(false); }
if !mapped || data.data_map.get::<XdgToplevelSurfaceData>().is_none() {
return;
}
data.data_map.insert_if_missing_threadsafe(CoreSurface::new);
data.data_map.insert_if_missing_threadsafe(|| {
PanelItem::create(&self.display_handle, &data.data_map, surface.clone())
});
let surface_states = data.data_map.get::<RendererSurfaceStateUserData>().unwrap();
let core_surface = data.data_map.get::<CoreSurface>().unwrap();
*core_surface.wl_tex.lock() = surface_states
.borrow()
.texture(&self.renderer)
.cloned()
.map(SendWrapper::new);
let panel_node = data.data_map.get::<Arc<Node>>().unwrap();
let item = panel_node.item.get().unwrap();
if let ItemType::Panel(panel_item) = &item.specialization {
panel_item.resize(&data.data_map);
} }
}); });
} }

View File

@@ -2,40 +2,44 @@ pub mod compositor;
pub mod panel_item; pub mod panel_item;
pub mod seat; pub mod seat;
pub mod shaders; pub mod shaders;
pub mod state;
pub mod surface; pub mod surface;
pub mod xdg_decoration; pub mod xdg_decoration;
pub mod xdg_shell; pub mod xdg_shell;
use self::{panel_item::PanelItem, seat::SeatDelegate}; use self::{panel_item::PanelItem, state::WaylandState};
use crate::nodes::core::Node; use crate::{nodes::core::Node, wayland::state::ClientState};
use anyhow::{ensure, Result}; use anyhow::{ensure, Result};
use once_cell::sync::OnceCell; use once_cell::sync::OnceCell;
use parking_lot::Mutex; use parking_lot::Mutex;
use send_wrapper::SendWrapper;
use slog::Logger; use slog::Logger;
use smithay::{ use smithay::{
backend::{egl::EGLContext, renderer::gles2::Gles2Renderer}, backend::{
delegate_output, delegate_shm, egl::EGLContext,
renderer::{
gles2::Gles2Renderer,
utils::{import_surface_tree, on_commit_buffer_handler, RendererSurfaceStateUserData},
},
},
desktop::utils::send_frames_surface_tree, desktop::utils::send_frames_surface_tree,
reexports::wayland_server::{ reexports::wayland_server::{backend::GlobalId, Display, ListeningSocket},
backend::{ClientData, ClientId, DisconnectReason, GlobalId}, wayland::{compositor::with_states, shell::xdg::XdgToplevelSurfaceData},
protocol::wl_output::Subpixel, };
Display, DisplayHandle, ListeningSocket, use std::os::unix::prelude::AsRawFd;
}, use std::{
utils::Size, ffi::c_void,
wayland::{ os::unix::{
buffer::BufferHandler, net::UnixListener,
compositor::{with_states, CompositorState}, prelude::{FromRawFd, RawFd},
output::{Output, OutputManagerState, Scale::Integer}, },
shell::xdg::{decoration::XdgDecorationState, XdgShellState}, sync::Arc,
shm::{ShmHandler, ShmState},
},
}; };
use std::sync::mpsc::{channel, Receiver, Sender};
use std::{ffi::c_void, sync::Arc};
use stereokit as sk; use stereokit as sk;
use stereokit::StereoKit; use stereokit::StereoKit;
use surface::CoreSurface; use surface::CoreSurface;
use tokio::{
io::unix::AsyncFd, net::UnixListener as AsyncUnixListener, sync::mpsc, task::JoinHandle,
};
struct EGLRawHandles { struct EGLRawHandles {
display: *const c_void, display: *const c_void,
@@ -58,43 +62,17 @@ fn get_sk_egl() -> Result<EGLRawHandles> {
}) })
} }
pub struct ClientState; static GLOBAL_DESTROY_QUEUE: OnceCell<mpsc::Sender<GlobalId>> = OnceCell::new();
impl ClientData for ClientState {
fn initialized(&self, client_id: ClientId) {
println!("Wayland client {:?} connected", client_id);
}
fn disconnected(&self, client_id: ClientId, reason: DisconnectReason) { pub struct Wayland {
println!( log: slog::Logger,
"Wayland client {:?} disconnected because {:#?}",
client_id, reason display: Arc<Mutex<Display<WaylandState>>>,
); join_handle: JoinHandle<Result<()>>,
} renderer: Gles2Renderer,
state: Arc<Mutex<WaylandState>>,
} }
impl Wayland {
lazy_static::lazy_static! {
static ref GLOBAL_DESTROY_QUEUE_IN: OnceCell<SendWrapper<Sender<GlobalId>>> = OnceCell::new();
}
pub struct WaylandState {
pub log: slog::Logger,
global_destroy_queue: Receiver<GlobalId>,
pub display: Arc<Mutex<Display<WaylandState>>>,
pub display_handle: DisplayHandle,
pub socket: ListeningSocket,
pub renderer: Gles2Renderer,
pub compositor_state: CompositorState,
pub xdg_shell_state: XdgShellState,
pub xdg_decoration_state: XdgDecorationState,
pub shm_state: ShmState,
pub output_manager_state: OutputManagerState,
pub output: Output,
pub seat_state: SeatDelegate,
// pub data_device_state: DataDeviceState,
}
impl WaylandState {
pub fn new(log: Logger) -> Result<Self> { pub fn new(log: Logger) -> Result<Self> {
let egl_raw_handles = get_sk_egl()?; let egl_raw_handles = get_sk_egl()?;
let renderer = unsafe { let renderer = unsafe {
@@ -110,104 +88,124 @@ impl WaylandState {
}; };
let display: Display<WaylandState> = Display::new()?; let display: Display<WaylandState> = Display::new()?;
let display_handle = display.handle();
let display = Arc::new(Mutex::new(display));
let state = Arc::new(Mutex::new(WaylandState::new(
log.clone(),
display_handle.clone(),
)));
let (global_destroy_queue_in, global_destroy_queue) = mpsc::channel(8);
GLOBAL_DESTROY_QUEUE.set(global_destroy_queue_in).unwrap();
let join_handle =
Wayland::start_loop(display.clone(), state.clone(), global_destroy_queue)?;
Ok(Wayland {
log,
display,
join_handle,
renderer,
state,
})
}
fn start_loop(
display: Arc<Mutex<Display<WaylandState>>>,
state: Arc<Mutex<WaylandState>>,
mut global_destroy_queue: mpsc::Receiver<GlobalId>,
) -> Result<JoinHandle<Result<()>>> {
let socket = ListeningSocket::bind_auto("wayland", 0..33)?; let socket = ListeningSocket::bind_auto("wayland", 0..33)?;
if let Some(socket_name) = socket.socket_name() { if let Some(socket_name) = socket.socket_name() {
println!("Wayland compositor {:?} active", socket_name); println!("Wayland compositor {:?} active", socket_name);
} }
let display_handle = display.handle();
let compositor_state = CompositorState::new::<Self, _>(&display_handle, log.clone()); let listen_async =
let xdg_shell_state = XdgShellState::new::<Self, _>(&display_handle, log.clone()); AsyncUnixListener::from_std(unsafe { UnixListener::from_raw_fd(socket.as_raw_fd()) })?;
let xdg_decoration_state = XdgDecorationState::new::<Self, _>(&display_handle, log.clone());
let shm_state = ShmState::new::<Self, _>(&display_handle, vec![], log.clone());
let output_manager_state = OutputManagerState::new_with_xdg_output::<Self>(&display_handle);
let output = Output::new(
"1x".to_owned(),
smithay::wayland::output::PhysicalProperties {
size: Size::default(),
subpixel: Subpixel::None,
make: "Virtual XR Display".to_owned(),
model: "Your Headset Name Here".to_owned(),
},
log.clone(),
);
let _global = output.create_global::<Self>(&display_handle);
output.change_current_state(None, None, Some(Integer(2)), None);
// let data_device_state = DataDeviceState::new(&dh, log.clone());
let (global_destroy_queue_in, global_destroy_queue) = channel(); let dispatch_poll_fd: RawFd = display.lock().backend().poll_fd();
GLOBAL_DESTROY_QUEUE_IN let dispatch_poll_listener = AsyncFd::new(dispatch_poll_fd)?;
.set(SendWrapper::new(global_destroy_queue_in))
.unwrap();
println!("Init Wayland compositor"); let dh1 = display.lock().handle();
Ok(WaylandState { let mut dh2 = dh1.clone();
log,
global_destroy_queue, Ok(tokio::task::spawn(async move {
display: Arc::new(Mutex::new(display)), let _socket = socket; // Keep the socket alive
display_handle, loop {
socket, tokio::select! {
renderer, e = global_destroy_queue.recv() => { // New global to destroy
compositor_state, dh1.remove_global::<WaylandState>(e.unwrap());
xdg_shell_state, }
xdg_decoration_state, acc = listen_async.accept() => { // New client connected
shm_state, let (stream, _) = acc?;
output_manager_state, dh2.insert_client(stream.into_std()?, Arc::new(ClientState))?;
output, }
seat_state: SeatDelegate, e = dispatch_poll_listener.readable() => { // Dispatch
// data_device_state, let mut guard = e?;
}) let mut display = display.lock();
display.dispatch_clients(&mut *state.lock())?;
display.flush_clients()?;
guard.clear_ready();
}
}
}
}))
} }
pub fn frame(&mut self, sk: &StereoKit) { pub fn frame(&mut self, sk: &StereoKit) {
let display_clone = self.display.clone(); let log = self.log.clone();
let mut display = display_clone.lock();
if let Ok(Some(client)) = self.socket.accept() {
let _ = display
.handle()
.insert_client(client, Arc::new(ClientState));
}
display.dispatch_clients(self).unwrap();
while let Ok(global_to_destroy) = self.global_destroy_queue.try_recv() {
self.display_handle
.remove_global::<WaylandState>(global_to_destroy);
}
let time_ms = (sk.time_getf() * 1000.) as u32; let time_ms = (sk.time_getf() * 1000.) as u32;
self.xdg_shell_state.toplevel_surfaces(|surfs| { let toplevel_surfaces = self
for surf in surfs.iter() { .state
with_states(surf.wl_surface(), |data| { .lock()
.xdg_shell_state
.toplevel_surfaces(|surfs| surfs.to_vec());
for surf in toplevel_surfaces {
// Let Smithay handle all the buffer maintenance
on_commit_buffer_handler(surf.wl_surface());
// Import all surface buffers into textures
import_surface_tree(&mut self.renderer, surf.wl_surface(), &log).unwrap();
with_states(surf.wl_surface(), |data| {
let mapped = data
.data_map
.get::<RendererSurfaceStateUserData>()
.map(|surface_states| surface_states.borrow().wl_buffer().is_some())
.unwrap_or(false);
if mapped && data.data_map.get::<XdgToplevelSurfaceData>().is_some() {
data.data_map.insert_if_missing_threadsafe(CoreSurface::new);
data.data_map.insert_if_missing_threadsafe(|| {
PanelItem::create(
&self.display,
self.display.lock().handle(),
&data.data_map,
surf.wl_surface().clone(),
)
});
if let Some(core_surface) = data.data_map.get::<CoreSurface>() { if let Some(core_surface) = data.data_map.get::<CoreSurface>() {
core_surface.update_tex(sk); core_surface.update_tex(sk, data, &self.renderer);
if let Some(panel_item) = data.data_map.get::<Arc<Node>>() { if let Some(panel_item) = data.data_map.get::<Arc<Node>>() {
PanelItem::apply_surface_materials(panel_item, core_surface); PanelItem::apply_surface_materials(panel_item, core_surface);
} }
} }
}); }
send_frames_surface_tree(surf.wl_surface(), time_ms); });
} send_frames_surface_tree(surf.wl_surface(), time_ms);
}); }
display.flush_clients().unwrap(); self.display.lock().flush_clients().unwrap();
}
pub fn make_context_current(&self) {
unsafe {
self.renderer.egl_context().make_current().unwrap();
}
} }
} }
impl Drop for WaylandState { impl Drop for Wayland {
fn drop(&mut self) { fn drop(&mut self) {
println!("Cleanly shut down the Wayland compositor"); self.join_handle.abort();
} }
} }
impl BufferHandler for WaylandState {
fn buffer_destroyed(
&mut self,
_buffer: &smithay::reexports::wayland_server::protocol::wl_buffer::WlBuffer,
) {
}
}
impl ShmHandler for WaylandState {
fn shm_state(&self) -> &smithay::wayland::shm::ShmState {
&self.shm_state
}
}
delegate_shm!(WaylandState);
delegate_output!(WaylandState);

View File

@@ -1,3 +1,4 @@
use super::{seat::SeatData, state::WaylandState, surface::CoreSurface, GLOBAL_DESTROY_QUEUE};
use crate::{ use crate::{
core::{ core::{
client::{Client, INTERNAL_CLIENT}, client::{Client, INTERNAL_CLIENT},
@@ -25,7 +26,7 @@ use smithay::{
wl_pointer::{Axis, ButtonState}, wl_pointer::{Axis, ButtonState},
wl_surface::WlSurface, wl_surface::WlSurface,
}, },
DisplayHandle, Resource, Display, DisplayHandle, Resource,
}, },
utils::{user_data::UserDataMap, Logical, Size}, utils::{user_data::UserDataMap, Logical, Size},
}; };
@@ -34,8 +35,6 @@ use std::{
sync::{Arc, Weak}, sync::{Arc, Weak},
}; };
use super::{seat::SeatData, surface::CoreSurface, GLOBAL_DESTROY_QUEUE_IN};
lazy_static! { lazy_static! {
static ref ITEM_TYPE_INFO_PANEL: TypeInfo = TypeInfo { static ref ITEM_TYPE_INFO_PANEL: TypeInfo = TypeInfo {
type_name: "panel", type_name: "panel",
@@ -63,6 +62,7 @@ lazy_static! {
pub struct PanelItem { pub struct PanelItem {
node: Weak<Node>, node: Weak<Node>,
pending_material_applications: Mutex<Vec<(Arc<Model>, u32)>>, pending_material_applications: Mutex<Vec<(Arc<Model>, u32)>>,
display: Weak<Mutex<Display<WaylandState>>>,
dh: DisplayHandle, dh: DisplayHandle,
pub toplevel_surface_id: ObjectId, pub toplevel_surface_id: ObjectId,
seat_data: SeatData, seat_data: SeatData,
@@ -70,7 +70,8 @@ pub struct PanelItem {
} }
impl PanelItem { impl PanelItem {
pub fn create( pub fn create(
dh: &DisplayHandle, display: &Arc<Mutex<Display<WaylandState>>>,
dh: DisplayHandle,
data: &UserDataMap, data: &UserDataMap,
toplevel_surface: WlSurface, toplevel_surface: WlSurface,
) -> Arc<Node> { ) -> Arc<Node> {
@@ -82,7 +83,7 @@ impl PanelItem {
)); ));
Spatial::add_to(&node, None, Mat4::IDENTITY).unwrap(); Spatial::add_to(&node, None, Mat4::IDENTITY).unwrap();
let seat_data = SeatData::new(dh, toplevel_surface.client_id().unwrap()); let seat_data = SeatData::new(&dh, toplevel_surface.client_id().unwrap());
let size = data let size = data
.get::<RendererSurfaceStateUserData>() .get::<RendererSurfaceStateUserData>()
@@ -95,7 +96,8 @@ impl PanelItem {
let specialization = ItemType::Panel(PanelItem { let specialization = ItemType::Panel(PanelItem {
node: Arc::downgrade(&node), node: Arc::downgrade(&node),
pending_material_applications: Mutex::new(Vec::new()), pending_material_applications: Mutex::new(Vec::new()),
dh: dh.clone(), display: Arc::downgrade(display),
dh,
toplevel_surface_id: toplevel_surface.id(), toplevel_surface_id: toplevel_surface.id(),
seat_data, seat_data,
size, size,
@@ -124,10 +126,18 @@ impl PanelItem {
fn toplevel_surface(&self) -> WlSurface { fn toplevel_surface(&self) -> WlSurface {
WlSurface::from_id(&self.dh, self.toplevel_surface_id.clone()).unwrap() WlSurface::from_id(&self.dh, self.toplevel_surface_id.clone()).unwrap()
} }
fn flush_clients(&self) {
self.display
.upgrade()
.unwrap()
.lock()
.flush_clients()
.unwrap();
}
pub fn resize(&self, data: &UserDataMap) { pub fn resize(&self, data: &UserDataMap) {
if let Some(surface_states) = data.get::<RendererSurfaceStateUserData>() { if let Some(surface_states) = data.get::<RendererSurfaceStateUserData>() {
if let Some(size) = surface_states.borrow().surface_size() { if let Some(size) = surface_states.borrow().buffer_size() {
*self.size.lock() = size; *self.size.lock() = size;
let _ = self.node.upgrade().unwrap().send_remote_signal( let _ = self.node.upgrade().unwrap().send_remote_signal(
"resize", "resize",
@@ -190,6 +200,8 @@ impl PanelItem {
if let Some(pointer) = panel_item.seat_data.pointer() { if let Some(pointer) = panel_item.seat_data.pointer() {
pointer.leave(0, &panel_item.toplevel_surface()); pointer.leave(0, &panel_item.toplevel_surface());
*panel_item.seat_data.pointer_active.lock() = false; *panel_item.seat_data.pointer_active.lock() = false;
pointer.frame();
panel_item.flush_clients();
} }
} }
} }
@@ -211,6 +223,7 @@ impl PanelItem {
*pointer_active = true; *pointer_active = true;
} }
pointer.frame(); pointer.frame();
panel_item.flush_clients();
} }
} }
@@ -235,6 +248,7 @@ impl PanelItem {
}, },
); );
pointer.frame(); pointer.frame();
panel_item.flush_clients();
} }
} }
} }
@@ -263,6 +277,7 @@ impl PanelItem {
} }
} }
pointer.frame(); pointer.frame();
panel_item.flush_clients();
} }
} }
} }
@@ -349,11 +364,8 @@ impl ItemSpecialization for PanelItem {
} }
impl Drop for PanelItem { impl Drop for PanelItem {
fn drop(&mut self) { fn drop(&mut self) {
GLOBAL_DESTROY_QUEUE_IN let id = self.seat_data.global_id.get().cloned().unwrap();
.get() tokio::spawn(async move { GLOBAL_DESTROY_QUEUE.get().unwrap().send(id).await });
.unwrap()
.send(self.seat_data.global_id.get().cloned().unwrap())
.unwrap();
} }
} }

View File

@@ -1,4 +1,3 @@
use super::WaylandState;
use nanoid::nanoid; use nanoid::nanoid;
use once_cell::sync::OnceCell; use once_cell::sync::OnceCell;
use parking_lot::Mutex; use parking_lot::Mutex;
@@ -16,6 +15,8 @@ use smithay::reexports::wayland_server::{
use std::ops::Deref; use std::ops::Deref;
use std::sync::Arc; use std::sync::Arc;
use super::state::WaylandState;
pub struct SeatDelegate; pub struct SeatDelegate;
#[derive(Clone)] #[derive(Clone)]

103
src/wayland/state.rs Normal file
View File

@@ -0,0 +1,103 @@
use slog::Logger;
use smithay::{
delegate_output, delegate_shm,
reexports::wayland_server::{
backend::{ClientData, ClientId, DisconnectReason},
protocol::wl_output::Subpixel,
DisplayHandle,
},
utils::Size,
wayland::{
buffer::BufferHandler,
compositor::CompositorState,
output::{Output, OutputManagerState, Scale},
shell::xdg::{decoration::XdgDecorationState, XdgShellState},
shm::{ShmHandler, ShmState},
},
};
use super::seat::SeatDelegate;
pub struct ClientState;
impl ClientData for ClientState {
fn initialized(&self, client_id: ClientId) {
println!("Wayland client {:?} connected", client_id);
}
fn disconnected(&self, client_id: ClientId, reason: DisconnectReason) {
println!(
"Wayland client {:?} disconnected because {:#?}",
client_id, reason
);
}
}
pub struct WaylandState {
pub display_handle: DisplayHandle,
pub compositor_state: CompositorState,
pub xdg_shell_state: XdgShellState,
pub xdg_decoration_state: XdgDecorationState,
pub shm_state: ShmState,
pub output_manager_state: OutputManagerState,
pub output: Output,
pub seat_state: SeatDelegate,
// pub data_device_state: DataDeviceState,
}
impl WaylandState {
pub fn new(log: Logger, display_handle: DisplayHandle) -> Self {
let compositor_state = CompositorState::new::<Self, _>(&display_handle, log.clone());
let xdg_shell_state = XdgShellState::new::<Self, _>(&display_handle, log.clone());
let xdg_decoration_state = XdgDecorationState::new::<Self, _>(&display_handle, log.clone());
let shm_state = ShmState::new::<Self, _>(&display_handle, vec![], log.clone());
let output_manager_state = OutputManagerState::new_with_xdg_output::<Self>(&display_handle);
let output = Output::new(
"1x".to_owned(),
smithay::wayland::output::PhysicalProperties {
size: Size::default(),
subpixel: Subpixel::None,
make: "Virtual XR Display".to_owned(),
model: "Your Headset Name Here".to_owned(),
},
log.clone(),
);
let _global = output.create_global::<Self>(&display_handle);
output.change_current_state(None, None, Some(Scale::Integer(2)), None);
// let data_device_state = DataDeviceState::new(&dh, log.clone());
println!("Init Wayland compositor");
WaylandState {
display_handle,
compositor_state,
xdg_shell_state,
xdg_decoration_state,
shm_state,
output_manager_state,
output,
seat_state: SeatDelegate,
// data_device_state,
}
}
}
impl Drop for WaylandState {
fn drop(&mut self) {
println!("Cleanly shut down the Wayland compositor");
}
}
impl BufferHandler for WaylandState {
fn buffer_destroyed(
&mut self,
_buffer: &smithay::reexports::wayland_server::protocol::wl_buffer::WlBuffer,
) {
}
}
impl ShmHandler for WaylandState {
fn shm_state(&self) -> &smithay::wayland::shm::ShmState {
&self.shm_state
}
}
delegate_shm!(WaylandState);
delegate_output!(WaylandState);

View File

@@ -1,10 +1,17 @@
use std::{fmt::Error, sync::Arc}; use std::{fmt::Error, mem, sync::Arc};
use glam::vec2; use glam::vec2;
use once_cell::sync::OnceCell; use once_cell::sync::OnceCell;
use parking_lot::Mutex; use parking_lot::Mutex;
use send_wrapper::SendWrapper; use send_wrapper::SendWrapper;
use smithay::backend::renderer::{gles2::Gles2Texture, Texture}; use smithay::{
backend::renderer::{
gles2::{Gles2Renderer, Gles2Texture},
utils::RendererSurfaceStateUserData,
Texture,
},
wayland::compositor::SurfaceData,
};
use stereokit::{ use stereokit::{
material::Material, material::Material,
shader::Shader, shader::Shader,
@@ -12,6 +19,8 @@ use stereokit::{
StereoKit, StereoKit,
}; };
use crate::core::destroy_queue;
use super::shaders::SIMULA_SHADER_BYTES; use super::shaders::SIMULA_SHADER_BYTES;
pub struct CoreSurface { pub struct CoreSurface {
@@ -29,7 +38,7 @@ impl CoreSurface {
} }
} }
pub fn update_tex(&self, sk: &StereoKit) { pub fn update_tex(&self, sk: &StereoKit, data: &SurfaceData, renderer: &Gles2Renderer) {
let sk_tex = self let sk_tex = self
.sk_tex .sk_tex
.get_or_try_init(|| { .get_or_try_init(|| {
@@ -51,6 +60,14 @@ impl CoreSurface {
.map(|mat| Arc::new(SendWrapper::new(mat))) .map(|mat| Arc::new(SendWrapper::new(mat)))
}) })
.unwrap(); .unwrap();
if let Some(surface_states) = data.data_map.get::<RendererSurfaceStateUserData>() {
*self.wl_tex.lock() = surface_states
.borrow()
.texture(renderer)
.cloned()
.map(SendWrapper::new);
}
if let Some(smithay_tex) = self.wl_tex.lock().as_ref() { if let Some(smithay_tex) = self.wl_tex.lock().as_ref() {
unsafe { unsafe {
sk_tex.set_native( sk_tex.set_native(
@@ -70,3 +87,10 @@ impl CoreSurface {
} }
} }
} }
impl Drop for CoreSurface {
fn drop(&mut self) {
destroy_queue::add(mem::replace(self.wl_tex.get_mut(), None));
self.sk_tex.take().map(destroy_queue::add);
self.sk_mat.take().map(destroy_queue::add);
}
}

View File

@@ -1,11 +1,10 @@
use super::state::WaylandState;
use smithay::{ use smithay::{
delegate_xdg_decoration, delegate_xdg_decoration,
reexports::wayland_protocols::xdg::decoration::zv1::server::zxdg_toplevel_decoration_v1::Mode, reexports::wayland_protocols::xdg::decoration::zv1::server::zxdg_toplevel_decoration_v1::Mode,
wayland::shell::xdg::decoration::XdgDecorationHandler, wayland::shell::xdg::decoration::XdgDecorationHandler,
}; };
use super::WaylandState;
impl XdgDecorationHandler for WaylandState { impl XdgDecorationHandler for WaylandState {
fn new_decoration(&mut self, toplevel: smithay::wayland::shell::xdg::ToplevelSurface) { fn new_decoration(&mut self, toplevel: smithay::wayland::shell::xdg::ToplevelSurface) {
toplevel.with_pending_state(|state| { toplevel.with_pending_state(|state| {

View File

@@ -1,4 +1,4 @@
use super::WaylandState; use super::state::WaylandState;
use smithay::{ use smithay::{
delegate_xdg_shell, delegate_xdg_shell,
reexports::{ reexports::{