diff --git a/src/core/destroy_queue.rs b/src/core/destroy_queue.rs new file mode 100644 index 0000000..20038d5 --- /dev/null +++ b/src/core/destroy_queue.rs @@ -0,0 +1,12 @@ +use parking_lot::Mutex; +use std::any::Any; + +static MAIN_DESTROY_QUEUE: Mutex>> = Mutex::new(Vec::new()); + +pub fn add(thing: T) { + MAIN_DESTROY_QUEUE.lock().push(Box::new(thing)); +} + +pub fn clear() { + MAIN_DESTROY_QUEUE.lock().clear(); +} diff --git a/src/core/mod.rs b/src/core/mod.rs index 7330c06..9bfc371 100644 --- a/src/core/mod.rs +++ b/src/core/mod.rs @@ -1,3 +1,4 @@ +pub mod destroy_queue; pub mod resource; pub mod client; pub mod eventloop; diff --git a/src/main.rs b/src/main.rs index bcef0e2..2f0548d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,21 +2,18 @@ mod core; mod nodes; mod wayland; +use crate::core::destroy_queue; use crate::nodes::model::{MODELS_TO_DROP, MODEL_REGISTRY}; -use crate::wayland::WaylandState; +use crate::wayland::Wayland; use self::core::eventloop::EventLoop; use anyhow::Result; use clap::Parser; -use once_cell::sync::Lazy; -use parking_lot::Mutex; use slog::Drain; use std::sync::Arc; use stereokit::{lifecycle::DisplayMode, Settings}; use tokio::{runtime::Handle, sync::oneshot}; -static TOKIO_HANDLE: Lazy>> = Lazy::new(Default::default); - #[derive(Parser)] #[clap(author, version, about, long_about = None)] struct CliArgs { @@ -56,15 +53,18 @@ fn main() -> Result<()> { } let (event_stop_tx, event_stop_rx) = oneshot::channel::<()>(); + let (handle_sender, handle_receiver) = oneshot::channel::(); let event_thread = std::thread::Builder::new() .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!"); stereokit.run( |draw_ctx| { wayland.frame(&stereokit); + destroy_queue::clear(); nodes::root::Root::logic_step(stereokit.time_elapsed()); for model in MODEL_REGISTRY.get_valid_contents() { @@ -72,7 +72,7 @@ fn main() -> Result<()> { } MODELS_TO_DROP.lock().clear(); - unsafe { wayland.renderer.egl_context().make_current().unwrap() }; + wayland.make_context_current(); }, || { println!("Cleanly shut down StereoKit"); @@ -89,9 +89,14 @@ fn main() -> Result<()> { Ok(()) } -#[tokio::main] -async fn event_loop(stop_rx: oneshot::Receiver<()>) -> anyhow::Result<()> { - TOKIO_HANDLE.lock().replace(Handle::current()); +// #[tokio::main] +#[tokio::main(flavor = "current_thread")] +async fn event_loop( + handle_sender: oneshot::Sender, + stop_rx: oneshot::Receiver<()>, +) -> anyhow::Result<()> { + let _ = handle_sender.send(Handle::current()); + // console_subscriber::init(); let (event_loop, event_loop_join_handle) = EventLoop::new().expect("Couldn't create server socket"); diff --git a/src/nodes/core.rs b/src/nodes/core.rs index b7cf0a9..d6a3e2c 100644 --- a/src/nodes/core.rs +++ b/src/nodes/core.rs @@ -6,7 +6,6 @@ use super::model::Model; use super::spatial::Spatial; use crate::core::client::Client; use crate::core::registry::Registry; -use crate::TOKIO_HANDLE; use anyhow::{anyhow, Result}; use libstardustxr::scenegraph::ScenegraphError; use nanoid::nanoid; @@ -175,7 +174,7 @@ impl Node { let path = self.path.clone(); let method = method.to_string(); 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() { let _ = messenger .send_remote_signal(path.as_str(), method.as_str(), data.as_slice()) diff --git a/src/wayland/compositor.rs b/src/wayland/compositor.rs index 24ab1d0..a54d18a 100644 --- a/src/wayland/compositor.rs +++ b/src/wayland/compositor.rs @@ -1,20 +1,11 @@ -use std::sync::Arc; - +use super::state::WaylandState; use crate::nodes::{core::Node, item::ItemType}; - -use super::{panel_item::PanelItem, surface::CoreSurface, WaylandState}; -use send_wrapper::SendWrapper; use smithay::{ - backend::renderer::utils::{ - import_surface_tree, on_commit_buffer_handler, RendererSurfaceStateUserData, - }, delegate_compositor, reexports::wayland_server::protocol::wl_surface::WlSurface, - wayland::{ - compositor::{self, CompositorHandler, CompositorState}, - shell::xdg::XdgToplevelSurfaceData, - }, + wayland::compositor::{self, CompositorHandler, CompositorState}, }; +use std::sync::Arc; impl CompositorHandler for WaylandState { fn compositor_state(&mut self) -> &mut CompositorState { @@ -22,40 +13,12 @@ impl CompositorHandler for WaylandState { } 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| { - let mapped = data - .data_map - .get::() - .map(|surface_states| surface_states.borrow().wl_buffer().is_some()) - .unwrap_or(false); - - if !mapped || data.data_map.get::().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::().unwrap(); - let core_surface = data.data_map.get::().unwrap(); - *core_surface.wl_tex.lock() = surface_states - .borrow() - .texture(&self.renderer) - .cloned() - .map(SendWrapper::new); - - let panel_node = data.data_map.get::>().unwrap(); - let item = panel_node.item.get().unwrap(); - if let ItemType::Panel(panel_item) = &item.specialization { - panel_item.resize(&data.data_map); + if let Some(panel_node) = data.data_map.get::>() { + let item = panel_node.item.get().unwrap(); + if let ItemType::Panel(panel_item) = &item.specialization { + panel_item.resize(&data.data_map); + } } }); } diff --git a/src/wayland/mod.rs b/src/wayland/mod.rs index c42b439..0627f08 100644 --- a/src/wayland/mod.rs +++ b/src/wayland/mod.rs @@ -2,40 +2,44 @@ pub mod compositor; pub mod panel_item; pub mod seat; pub mod shaders; +pub mod state; pub mod surface; pub mod xdg_decoration; pub mod xdg_shell; -use self::{panel_item::PanelItem, seat::SeatDelegate}; -use crate::nodes::core::Node; +use self::{panel_item::PanelItem, state::WaylandState}; +use crate::{nodes::core::Node, wayland::state::ClientState}; use anyhow::{ensure, Result}; use once_cell::sync::OnceCell; use parking_lot::Mutex; -use send_wrapper::SendWrapper; use slog::Logger; use smithay::{ - backend::{egl::EGLContext, renderer::gles2::Gles2Renderer}, - delegate_output, delegate_shm, + backend::{ + egl::EGLContext, + renderer::{ + gles2::Gles2Renderer, + utils::{import_surface_tree, on_commit_buffer_handler, RendererSurfaceStateUserData}, + }, + }, desktop::utils::send_frames_surface_tree, - reexports::wayland_server::{ - backend::{ClientData, ClientId, DisconnectReason, GlobalId}, - protocol::wl_output::Subpixel, - Display, DisplayHandle, ListeningSocket, - }, - utils::Size, - wayland::{ - buffer::BufferHandler, - compositor::{with_states, CompositorState}, - output::{Output, OutputManagerState, Scale::Integer}, - shell::xdg::{decoration::XdgDecorationState, XdgShellState}, - shm::{ShmHandler, ShmState}, - }, + reexports::wayland_server::{backend::GlobalId, Display, ListeningSocket}, + wayland::{compositor::with_states, shell::xdg::XdgToplevelSurfaceData}, +}; +use std::os::unix::prelude::AsRawFd; +use std::{ + ffi::c_void, + os::unix::{ + net::UnixListener, + prelude::{FromRawFd, RawFd}, + }, + sync::Arc, }; -use std::sync::mpsc::{channel, Receiver, Sender}; -use std::{ffi::c_void, sync::Arc}; use stereokit as sk; use stereokit::StereoKit; use surface::CoreSurface; +use tokio::{ + io::unix::AsyncFd, net::UnixListener as AsyncUnixListener, sync::mpsc, task::JoinHandle, +}; struct EGLRawHandles { display: *const c_void, @@ -58,43 +62,17 @@ fn get_sk_egl() -> Result { }) } -pub struct ClientState; -impl ClientData for ClientState { - fn initialized(&self, client_id: ClientId) { - println!("Wayland client {:?} connected", client_id); - } +static GLOBAL_DESTROY_QUEUE: OnceCell> = OnceCell::new(); - fn disconnected(&self, client_id: ClientId, reason: DisconnectReason) { - println!( - "Wayland client {:?} disconnected because {:#?}", - client_id, reason - ); - } +pub struct Wayland { + log: slog::Logger, + + display: Arc>>, + join_handle: JoinHandle>, + renderer: Gles2Renderer, + state: Arc>, } - -lazy_static::lazy_static! { - static ref GLOBAL_DESTROY_QUEUE_IN: OnceCell>> = OnceCell::new(); -} - -pub struct WaylandState { - pub log: slog::Logger, - - global_destroy_queue: Receiver, - pub display: Arc>>, - 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 { +impl Wayland { pub fn new(log: Logger) -> Result { let egl_raw_handles = get_sk_egl()?; let renderer = unsafe { @@ -110,104 +88,124 @@ impl WaylandState { }; let display: Display = 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>>, + state: Arc>, + mut global_destroy_queue: mpsc::Receiver, + ) -> Result>> { let socket = ListeningSocket::bind_auto("wayland", 0..33)?; if let Some(socket_name) = socket.socket_name() { println!("Wayland compositor {:?} active", socket_name); } - let display_handle = display.handle(); - let compositor_state = CompositorState::new::(&display_handle, log.clone()); - let xdg_shell_state = XdgShellState::new::(&display_handle, log.clone()); - let xdg_decoration_state = XdgDecorationState::new::(&display_handle, log.clone()); - let shm_state = ShmState::new::(&display_handle, vec![], log.clone()); - let output_manager_state = OutputManagerState::new_with_xdg_output::(&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::(&display_handle); - output.change_current_state(None, None, Some(Integer(2)), None); - // let data_device_state = DataDeviceState::new(&dh, log.clone()); + let listen_async = + AsyncUnixListener::from_std(unsafe { UnixListener::from_raw_fd(socket.as_raw_fd()) })?; - let (global_destroy_queue_in, global_destroy_queue) = channel(); - GLOBAL_DESTROY_QUEUE_IN - .set(SendWrapper::new(global_destroy_queue_in)) - .unwrap(); + let dispatch_poll_fd: RawFd = display.lock().backend().poll_fd(); + let dispatch_poll_listener = AsyncFd::new(dispatch_poll_fd)?; - println!("Init Wayland compositor"); - Ok(WaylandState { - log, + let dh1 = display.lock().handle(); + let mut dh2 = dh1.clone(); - global_destroy_queue, - display: Arc::new(Mutex::new(display)), - display_handle, - socket, - renderer, - compositor_state, - xdg_shell_state, - xdg_decoration_state, - shm_state, - output_manager_state, - output, - seat_state: SeatDelegate, - // data_device_state, - }) + Ok(tokio::task::spawn(async move { + let _socket = socket; // Keep the socket alive + loop { + tokio::select! { + e = global_destroy_queue.recv() => { // New global to destroy + dh1.remove_global::(e.unwrap()); + } + acc = listen_async.accept() => { // New client connected + let (stream, _) = acc?; + dh2.insert_client(stream.into_std()?, Arc::new(ClientState))?; + } + e = dispatch_poll_listener.readable() => { // Dispatch + 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) { - let display_clone = self.display.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::(global_to_destroy); - } - + let log = self.log.clone(); let time_ms = (sk.time_getf() * 1000.) as u32; - self.xdg_shell_state.toplevel_surfaces(|surfs| { - for surf in surfs.iter() { - with_states(surf.wl_surface(), |data| { + let toplevel_surfaces = self + .state + .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::() + .map(|surface_states| surface_states.borrow().wl_buffer().is_some()) + .unwrap_or(false); + + if mapped && data.data_map.get::().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::() { - core_surface.update_tex(sk); + core_surface.update_tex(sk, data, &self.renderer); if let Some(panel_item) = data.data_map.get::>() { PanelItem::apply_surface_materials(panel_item, core_surface); } } - }); - send_frames_surface_tree(surf.wl_surface(), time_ms); - } - }); - display.flush_clients().unwrap(); + } + }); + send_frames_surface_tree(surf.wl_surface(), time_ms); + } + 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) { - 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); diff --git a/src/wayland/panel_item.rs b/src/wayland/panel_item.rs index 5c81f51..c7e99f9 100644 --- a/src/wayland/panel_item.rs +++ b/src/wayland/panel_item.rs @@ -1,3 +1,4 @@ +use super::{seat::SeatData, state::WaylandState, surface::CoreSurface, GLOBAL_DESTROY_QUEUE}; use crate::{ core::{ client::{Client, INTERNAL_CLIENT}, @@ -25,7 +26,7 @@ use smithay::{ wl_pointer::{Axis, ButtonState}, wl_surface::WlSurface, }, - DisplayHandle, Resource, + Display, DisplayHandle, Resource, }, utils::{user_data::UserDataMap, Logical, Size}, }; @@ -34,8 +35,6 @@ use std::{ sync::{Arc, Weak}, }; -use super::{seat::SeatData, surface::CoreSurface, GLOBAL_DESTROY_QUEUE_IN}; - lazy_static! { static ref ITEM_TYPE_INFO_PANEL: TypeInfo = TypeInfo { type_name: "panel", @@ -63,6 +62,7 @@ lazy_static! { pub struct PanelItem { node: Weak, pending_material_applications: Mutex, u32)>>, + display: Weak>>, dh: DisplayHandle, pub toplevel_surface_id: ObjectId, seat_data: SeatData, @@ -70,7 +70,8 @@ pub struct PanelItem { } impl PanelItem { pub fn create( - dh: &DisplayHandle, + display: &Arc>>, + dh: DisplayHandle, data: &UserDataMap, toplevel_surface: WlSurface, ) -> Arc { @@ -82,7 +83,7 @@ impl PanelItem { )); 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 .get::() @@ -95,7 +96,8 @@ impl PanelItem { let specialization = ItemType::Panel(PanelItem { node: Arc::downgrade(&node), pending_material_applications: Mutex::new(Vec::new()), - dh: dh.clone(), + display: Arc::downgrade(display), + dh, toplevel_surface_id: toplevel_surface.id(), seat_data, size, @@ -124,10 +126,18 @@ impl PanelItem { fn toplevel_surface(&self) -> WlSurface { 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) { if let Some(surface_states) = data.get::() { - if let Some(size) = surface_states.borrow().surface_size() { + if let Some(size) = surface_states.borrow().buffer_size() { *self.size.lock() = size; let _ = self.node.upgrade().unwrap().send_remote_signal( "resize", @@ -190,6 +200,8 @@ impl PanelItem { if let Some(pointer) = panel_item.seat_data.pointer() { pointer.leave(0, &panel_item.toplevel_surface()); *panel_item.seat_data.pointer_active.lock() = false; + pointer.frame(); + panel_item.flush_clients(); } } } @@ -211,6 +223,7 @@ impl PanelItem { *pointer_active = true; } pointer.frame(); + panel_item.flush_clients(); } } @@ -235,6 +248,7 @@ impl PanelItem { }, ); pointer.frame(); + panel_item.flush_clients(); } } } @@ -263,6 +277,7 @@ impl PanelItem { } } pointer.frame(); + panel_item.flush_clients(); } } } @@ -349,11 +364,8 @@ impl ItemSpecialization for PanelItem { } impl Drop for PanelItem { fn drop(&mut self) { - GLOBAL_DESTROY_QUEUE_IN - .get() - .unwrap() - .send(self.seat_data.global_id.get().cloned().unwrap()) - .unwrap(); + let id = self.seat_data.global_id.get().cloned().unwrap(); + tokio::spawn(async move { GLOBAL_DESTROY_QUEUE.get().unwrap().send(id).await }); } } diff --git a/src/wayland/seat.rs b/src/wayland/seat.rs index 679954a..73d7643 100644 --- a/src/wayland/seat.rs +++ b/src/wayland/seat.rs @@ -1,4 +1,3 @@ -use super::WaylandState; use nanoid::nanoid; use once_cell::sync::OnceCell; use parking_lot::Mutex; @@ -16,6 +15,8 @@ use smithay::reexports::wayland_server::{ use std::ops::Deref; use std::sync::Arc; +use super::state::WaylandState; + pub struct SeatDelegate; #[derive(Clone)] diff --git a/src/wayland/state.rs b/src/wayland/state.rs new file mode 100644 index 0000000..9b0df8f --- /dev/null +++ b/src/wayland/state.rs @@ -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::(&display_handle, log.clone()); + let xdg_shell_state = XdgShellState::new::(&display_handle, log.clone()); + let xdg_decoration_state = XdgDecorationState::new::(&display_handle, log.clone()); + let shm_state = ShmState::new::(&display_handle, vec![], log.clone()); + let output_manager_state = OutputManagerState::new_with_xdg_output::(&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::(&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); diff --git a/src/wayland/surface.rs b/src/wayland/surface.rs index 0ecca04..71a22fc 100644 --- a/src/wayland/surface.rs +++ b/src/wayland/surface.rs @@ -1,10 +1,17 @@ -use std::{fmt::Error, sync::Arc}; +use std::{fmt::Error, mem, sync::Arc}; use glam::vec2; use once_cell::sync::OnceCell; use parking_lot::Mutex; 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::{ material::Material, shader::Shader, @@ -12,6 +19,8 @@ use stereokit::{ StereoKit, }; +use crate::core::destroy_queue; + use super::shaders::SIMULA_SHADER_BYTES; 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 .sk_tex .get_or_try_init(|| { @@ -51,6 +60,14 @@ impl CoreSurface { .map(|mat| Arc::new(SendWrapper::new(mat))) }) .unwrap(); + + if let Some(surface_states) = data.data_map.get::() { + *self.wl_tex.lock() = surface_states + .borrow() + .texture(renderer) + .cloned() + .map(SendWrapper::new); + } if let Some(smithay_tex) = self.wl_tex.lock().as_ref() { unsafe { 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); + } +} diff --git a/src/wayland/xdg_decoration.rs b/src/wayland/xdg_decoration.rs index cfe594c..78c632b 100644 --- a/src/wayland/xdg_decoration.rs +++ b/src/wayland/xdg_decoration.rs @@ -1,11 +1,10 @@ +use super::state::WaylandState; use smithay::{ delegate_xdg_decoration, reexports::wayland_protocols::xdg::decoration::zv1::server::zxdg_toplevel_decoration_v1::Mode, wayland::shell::xdg::decoration::XdgDecorationHandler, }; -use super::WaylandState; - impl XdgDecorationHandler for WaylandState { fn new_decoration(&mut self, toplevel: smithay::wayland::shell::xdg::ToplevelSurface) { toplevel.with_pending_state(|state| { diff --git a/src/wayland/xdg_shell.rs b/src/wayland/xdg_shell.rs index 5b96ba3..63f3792 100644 --- a/src/wayland/xdg_shell.rs +++ b/src/wayland/xdg_shell.rs @@ -1,4 +1,4 @@ -use super::WaylandState; +use super::state::WaylandState; use smithay::{ delegate_xdg_shell, reexports::{