feat(wayland): fully async!!!
This commit is contained in:
12
src/core/destroy_queue.rs
Normal file
12
src/core/destroy_queue.rs
Normal 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();
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
pub mod destroy_queue;
|
||||
pub mod resource;
|
||||
pub mod client;
|
||||
pub mod eventloop;
|
||||
|
||||
27
src/main.rs
27
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<Mutex<Option<Handle>>> = 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::<Handle>();
|
||||
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<Handle>,
|
||||
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");
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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::<RendererSurfaceStateUserData>()
|
||||
.map(|surface_states| surface_states.borrow().wl_buffer().is_some())
|
||||
.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);
|
||||
if let Some(panel_node) = data.data_map.get::<Arc<Node>>() {
|
||||
let item = panel_node.item.get().unwrap();
|
||||
if let ItemType::Panel(panel_item) = &item.specialization {
|
||||
panel_item.resize(&data.data_map);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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<EGLRawHandles> {
|
||||
})
|
||||
}
|
||||
|
||||
pub struct ClientState;
|
||||
impl ClientData for ClientState {
|
||||
fn initialized(&self, client_id: ClientId) {
|
||||
println!("Wayland client {:?} connected", client_id);
|
||||
}
|
||||
static GLOBAL_DESTROY_QUEUE: OnceCell<mpsc::Sender<GlobalId>> = 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<Mutex<Display<WaylandState>>>,
|
||||
join_handle: JoinHandle<Result<()>>,
|
||||
renderer: Gles2Renderer,
|
||||
state: Arc<Mutex<WaylandState>>,
|
||||
}
|
||||
|
||||
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 {
|
||||
impl Wayland {
|
||||
pub fn new(log: Logger) -> Result<Self> {
|
||||
let egl_raw_handles = get_sk_egl()?;
|
||||
let renderer = unsafe {
|
||||
@@ -110,104 +88,124 @@ impl WaylandState {
|
||||
};
|
||||
|
||||
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)?;
|
||||
if let Some(socket_name) = socket.socket_name() {
|
||||
println!("Wayland compositor {:?} active", socket_name);
|
||||
}
|
||||
let display_handle = display.handle();
|
||||
|
||||
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(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::<WaylandState>(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::<WaylandState>(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::<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>() {
|
||||
core_surface.update_tex(sk);
|
||||
core_surface.update_tex(sk, data, &self.renderer);
|
||||
if let Some(panel_item) = data.data_map.get::<Arc<Node>>() {
|
||||
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);
|
||||
|
||||
@@ -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<Node>,
|
||||
pending_material_applications: Mutex<Vec<(Arc<Model>, u32)>>,
|
||||
display: Weak<Mutex<Display<WaylandState>>>,
|
||||
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<Mutex<Display<WaylandState>>>,
|
||||
dh: DisplayHandle,
|
||||
data: &UserDataMap,
|
||||
toplevel_surface: WlSurface,
|
||||
) -> Arc<Node> {
|
||||
@@ -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::<RendererSurfaceStateUserData>()
|
||||
@@ -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::<RendererSurfaceStateUserData>() {
|
||||
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 });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)]
|
||||
|
||||
103
src/wayland/state.rs
Normal file
103
src/wayland/state.rs
Normal 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);
|
||||
@@ -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::<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() {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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| {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use super::WaylandState;
|
||||
use super::state::WaylandState;
|
||||
use smithay::{
|
||||
delegate_xdg_shell,
|
||||
reexports::{
|
||||
|
||||
Reference in New Issue
Block a user