From a8bbfbafdf64d1119b34c599ae3211b087219f71 Mon Sep 17 00:00:00 2001 From: Nova Date: Mon, 22 Aug 2022 10:15:20 -0400 Subject: [PATCH] feat(wayland): core surface --- src/main.rs | 68 ++-------------- src/wayland/compositor.rs | 23 +++++- src/wayland/mod.rs | 106 ++++++++++++++++++++++--- src/wayland/shader_unlit_gamma.hlsl | 39 ++++++++++ src/wayland/shader_unlit_gamma.sks | Bin 0 -> 13927 bytes src/wayland/shader_unlit_simula.hlsl | 111 +++++++++++++++++++++++++++ src/wayland/shader_unlit_simula.sks | Bin 0 -> 28411 bytes src/wayland/surface.rs | 67 ++++++++++++++++ src/wayland/xdg_shell.rs | 12 ++- 9 files changed, 352 insertions(+), 74 deletions(-) create mode 100644 src/wayland/shader_unlit_gamma.hlsl create mode 100644 src/wayland/shader_unlit_gamma.sks create mode 100644 src/wayland/shader_unlit_simula.hlsl create mode 100644 src/wayland/shader_unlit_simula.sks create mode 100644 src/wayland/surface.rs diff --git a/src/main.rs b/src/main.rs index 52d4d35..a248d6f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,20 +3,15 @@ mod nodes; mod wayland; use crate::nodes::model::{MODELS_TO_DROP, MODEL_REGISTRY}; -use crate::wayland::{ClientState, WaylandState}; +use crate::wayland::WaylandState; use self::core::eventloop::EventLoop; -use anyhow::{ensure, Result}; +use anyhow::Result; use clap::Parser; use once_cell::sync::Lazy; use parking_lot::Mutex; use slog::Drain; -use smithay::backend::egl::EGLContext; -use smithay::backend::renderer::gles2::Gles2Renderer; -use smithay::reexports::wayland_server::{Display, ListeningSocket}; -use std::ffi::c_void; use std::sync::Arc; -use stereokit as sk; use stereokit::{lifecycle::DisplayMode, Settings}; use tokio::{runtime::Handle, sync::oneshot}; @@ -34,27 +29,6 @@ struct CliArgs { overlay: bool, } -struct EGLRawHandles { - display: *const c_void, - config: *const c_void, - context: *const c_void, -} -fn get_sk_egl() -> Result { - ensure!( - unsafe { sk::sys::backend_graphics_get() } - == sk::sys::backend_graphics__backend_graphics_opengles_egl, - "StereoKit is not running using EGL!" - ); - - Ok(unsafe { - EGLRawHandles { - display: sk::sys::backend_opengl_egl_get_display() as *const c_void, - config: sk::sys::backend_opengl_egl_get_config() as *const c_void, - context: sk::sys::backend_opengl_egl_get_context() as *const c_void, - } - }) -} - fn main() -> Result<()> { let cli_args = Arc::new(CliArgs::parse()); let log = ::slog::Logger::root(::slog_stdlog::StdLog.fuse(), slog::o!()); @@ -72,41 +46,18 @@ fn main() -> Result<()> { }) .init() .expect("StereoKit failed to initialize"); + println!("Init StereoKit"); let (event_stop_tx, event_stop_rx) = oneshot::channel::<()>(); let event_thread = std::thread::Builder::new() .name("event_loop".to_owned()) .spawn(move || event_loop(event_stop_rx))?; - let egl_raw_handles = get_sk_egl()?; - let renderer = unsafe { - Gles2Renderer::new( - EGLContext::from_raw( - egl_raw_handles.display, - egl_raw_handles.config, - egl_raw_handles.context, - log.clone(), - )?, - log.clone(), - )? - }; - - let mut display: Display = Display::new()?; - let socket = ListeningSocket::bind_auto("wayland", 0..33)?; - if let Some(socket_name) = socket.socket_name() { - println!("Wayland compositor {:?} active", socket_name); - } - let mut wayland_state = WaylandState::new(&display, renderer, log)?; - + let mut wayland = WaylandState::new(log)?; + println!("Stardust ready!"); stereokit.run( |draw_ctx| { - if let Ok(Some(client)) = socket.accept() { - let _ = display - .handle() - .insert_client(client, Arc::new(ClientState)); - } - display.dispatch_clients(&mut wayland_state).unwrap(); - display.flush_clients().unwrap(); + wayland.frame(&stereokit); nodes::root::Root::logic_step(stereokit.time_elapsed()); for model in MODEL_REGISTRY.get_valid_contents() { @@ -114,17 +65,14 @@ fn main() -> Result<()> { } MODELS_TO_DROP.lock().clear(); - unsafe { wayland_state.renderer.egl_context().make_current().unwrap() }; + unsafe { wayland.renderer.egl_context().make_current().unwrap() }; }, || { println!("Cleanly shut down StereoKit"); }, ); - drop(wayland_state); - drop(socket); - drop(display); - println!("Cleanly shut down the Wayland compositor"); + drop(wayland); let _ = event_stop_tx.send(()); event_thread diff --git a/src/wayland/compositor.rs b/src/wayland/compositor.rs index ed5b39c..1170827 100644 --- a/src/wayland/compositor.rs +++ b/src/wayland/compositor.rs @@ -1,8 +1,11 @@ -use super::WaylandState; +use super::{surface::CoreSurface, WaylandState}; +use send_wrapper::SendWrapper; use smithay::{ - backend::renderer::utils::{import_surface_tree, on_commit_buffer_handler}, + backend::renderer::utils::{ + import_surface_tree, on_commit_buffer_handler, RendererSurfaceStateUserData, + }, delegate_compositor, - wayland::compositor::CompositorHandler, + wayland::compositor::{self, CompositorHandler}, }; impl CompositorHandler for WaylandState { @@ -17,6 +20,20 @@ impl CompositorHandler for WaylandState { ) { on_commit_buffer_handler(surface); import_surface_tree(&mut self.renderer, surface, &self.log).unwrap(); + + compositor::with_states(surface, |data| { + if let Some(surface_states) = data.data_map.get::() { + if let Some(core_surface) = data.data_map.get::() { + core_surface.wl_tex.replace( + surface_states + .borrow() + .texture(&self.renderer) + .cloned() + .map(|renderer| SendWrapper::new(renderer)), + ); + } + } + }); } } diff --git a/src/wayland/mod.rs b/src/wayland/mod.rs index 0fa0292..99cb571 100644 --- a/src/wayland/mod.rs +++ b/src/wayland/mod.rs @@ -1,26 +1,55 @@ pub mod compositor; +pub mod surface; pub mod xdg_decoration; mod xdg_shell; -use anyhow::Result; +use std::{ffi::c_void, sync::Arc}; + +use anyhow::{ensure, Result}; +use parking_lot::Mutex; use slog::Logger; use smithay::{ - backend::renderer::gles2::Gles2Renderer, + backend::{egl::EGLContext, renderer::gles2::Gles2Renderer}, delegate_output, delegate_shm, + desktop::utils::send_frames_surface_tree, reexports::wayland_server::{ backend::{ClientData, ClientId, DisconnectReason}, protocol::wl_output::Subpixel, - Display, DisplayHandle, + Display, DisplayHandle, ListeningSocket, }, utils::Size, wayland::{ buffer::BufferHandler, - compositor::CompositorState, + compositor::{with_states, CompositorState}, output::{Output, OutputManagerState, Scale::Integer}, seat::SeatState, shell::xdg::{decoration::XdgDecorationState, XdgShellState}, shm::{ShmHandler, ShmState}, }, }; +use stereokit as sk; +use stereokit::StereoKit; +use surface::CoreSurface; + +struct EGLRawHandles { + display: *const c_void, + config: *const c_void, + context: *const c_void, +} +fn get_sk_egl() -> Result { + ensure!( + unsafe { sk::sys::backend_graphics_get() } + == sk::sys::backend_graphics__backend_graphics_opengles_egl, + "StereoKit is not running using EGL!" + ); + + Ok(unsafe { + EGLRawHandles { + display: sk::sys::backend_opengl_egl_get_display() as *const c_void, + config: sk::sys::backend_opengl_egl_get_config() as *const c_void, + context: sk::sys::backend_opengl_egl_get_context() as *const c_void, + } + }) +} pub struct ClientState; impl ClientData for ClientState { @@ -39,7 +68,9 @@ impl ClientData for ClientState { pub struct WaylandState { pub log: slog::Logger, + pub display: Arc>>, pub display_handle: DisplayHandle, + pub socket: ListeningSocket, pub renderer: Gles2Renderer, pub compositor_state: CompositorState, pub xdg_shell_state: XdgShellState, @@ -52,11 +83,25 @@ pub struct WaylandState { } impl WaylandState { - pub fn new( - display: &Display, - renderer: Gles2Renderer, - log: Logger, - ) -> Result { + pub fn new(log: Logger) -> Result { + let egl_raw_handles = get_sk_egl()?; + let renderer = unsafe { + Gles2Renderer::new( + EGLContext::from_raw( + egl_raw_handles.display, + egl_raw_handles.config, + egl_raw_handles.context, + log.clone(), + )?, + log.clone(), + )? + }; + + let display: Display = Display::new()?; + 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()); @@ -79,9 +124,12 @@ impl WaylandState { let seat_state = SeatState::new(); // let data_device_state = DataDeviceState::new(&dh, log.clone()); + println!("Init Wayland compositor"); Ok(WaylandState { log, + display: Arc::new(Mutex::new(display)), display_handle, + socket, renderer, compositor_state, xdg_shell_state, @@ -93,6 +141,46 @@ impl WaylandState { // data_device_state, }) } + + 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(); + display.flush_clients().unwrap(); + + drop(display); + drop(display_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 core_surface = data.data_map.get::().unwrap(); + core_surface.update_tex(sk); + }); + send_frames_surface_tree(surf.wl_surface(), time_ms); + } + }); + self.xdg_shell_state.popup_surfaces(|surfs| { + for surf in surfs.iter() { + with_states(surf.wl_surface(), |data| { + let core_surface = data.data_map.get::().unwrap(); + core_surface.update_tex(sk); + }); + send_frames_surface_tree(surf.wl_surface(), time_ms); + } + }); + } +} +impl Drop for WaylandState { + fn drop(&mut self) { + println!("Cleanly shut down the Wayland compositor"); + } } impl BufferHandler for WaylandState { fn buffer_destroyed( diff --git a/src/wayland/shader_unlit_gamma.hlsl b/src/wayland/shader_unlit_gamma.hlsl new file mode 100644 index 0000000..13459b7 --- /dev/null +++ b/src/wayland/shader_unlit_gamma.hlsl @@ -0,0 +1,39 @@ +#include "stereokit.hlsli" + +//--name = sk/unlit +//--diffuse = white +//--uv_offset = 0.0, 0.0 +//--uv_scale = 1.0, 1.0 +Texture2D diffuse : register(t0); +SamplerState diffuse_s : register(s0); +float2 uv_scale; +float2 uv_offset; + +struct vsIn { + float4 pos : SV_Position; + float3 norm : NORMAL0; + float2 uv : TEXCOORD0; +}; +struct psIn { + float4 pos : SV_POSITION; + float2 uv : TEXCOORD0; + uint view_id : SV_RenderTargetArrayIndex; +}; + +psIn vs(vsIn input, uint id : SV_InstanceID) { + psIn o; + o.view_id = id % sk_view_count; + id = id / sk_view_count; + + float3 world = mul(float4(input.pos.xyz, 1), sk_inst[id].world).xyz; + o.pos = mul(float4(world, 1), sk_viewproj[o.view_id]); + + o.uv = (input.uv) + uv_offset * uv_scale; + return o; +} +float4 ps(psIn input) : SV_TARGET { + float4 col = diffuse.Sample(diffuse_s, input.uv); + col.rgb = pow(col.rgb, float3(2.2)); + + return col; +} diff --git a/src/wayland/shader_unlit_gamma.sks b/src/wayland/shader_unlit_gamma.sks new file mode 100644 index 0000000000000000000000000000000000000000..194b0676de1b898d12e4a1c323779874d26e6e38 GIT binary patch literal 13927 zcmeI3{f}H#8OLwCyL}l@P_W30_4WmrvCDK{OUtI%Ep5t5Vax7Pilwh&ts$wnB5 zwR@t*-sa3q7T&H+NK2MaiMqzrwch<1_(%p0GVn|b?(t>?pR+Y% zD~PIdqIQ-iMCw-Uk;N~YC$@XMr&{zb?`wkTZ;vFut|u{GqrYeMB-rQlu(pWdvVD8m z$f2jpdqr@nbDj5d!E04}ymj8MTkv}Cb;0XY4@mp(^gOrNRwX)dvJq8J1j$J;+sYq= z<0ozZl!5+$}HusVB~*G1$s@O_yfFxD?cD3B0zlL4LWmH@09! zL@+*}b8Cy<;}tS+QSei;F#Ua4 z@Jowr%_x3h+=%LG+EEh8(=YU&7VPvtW_4ogaSPMO^Hv`Ci-O-+Y-_rCJe)1ngQ&xh z2+wA8K9_;Noq=D-z(2^qFA08Awyu_*Zv82Sjc7Jp%8a4CYTI5X*>Olj>bmBZNNaJ?2clrZJ+bWkas(VlsQ)_B?-I5>H*m^8}8q2WGMvIkP& zu?JF^4|7@^ncVC_p8;2WT=l%_1y%OQ9zDr-_5jz0y=SZF?Rz%+5Oj*2XOc{5*cQ#~ zHS9&mkz1B#_B%(%Tif2suQl@67k$w_vPL@*y6{uHMeDxfu{SU9(skPL*vG_Mw5~cH zIYGPZI_UbdKINHp%gN_b+M@M^xZNT;h5dL?&oMj6(FIPKuf>(Jo{mPmrfZcNdkXR1 zp=bMgf-H23{4{F^_I9QuWA7osZmttwa7uRmIyyG9a}8ZbjWj;=m|Tgf^=6}(?yJzq zos?G9LYK;sODU~MN=d5AWz9b?t3hLQyb2EV3xnJ4fie1+Q+`RsSV%UhHuH>?A_!frCZg!PZ-SekfUU2 z>Q@o`hXHXzlH~+S-8|dzp677TTqA8e7OQk)3|# zAvE5R9E~_b<6Xwl&;^Zm4o73YLF3)P(U@n@ltL{U^9&k$E$=#81*?e}C+6B_RSM$< zzDbpM5nngoT$~(kY#5n^IhpM*a_B&Ak1D!{^`viyRPoo%MW+kjpgG@|ms#Jy@eMxh z-Q0BT9nIM#KIlZw>12Lpb%LXlf{(24x<>4>)ak$I}*R+UjBO4Hn0L z-u1566P@VeeGhr}y~jHo>i{y)z*z^fIO{+br*95-`aUiie$n376MN9WH(A{2-`s{X zmdL~B9g$qcC;Y%R_Iy?J(ALQlgS7A6-pzuE2W>}W6Z{rS!$)Frt19!t7oN8~+HVw2 z?$RgxaD5sQJgA`42l5yhXd5*W|$_Nsb% zcXaY&!WeId>lM~prHZc)=}D}q==-#u=!1@ZaB>_P{D&><D-{d+4oo|W4n!8(6Y(A<=f5EZA`vd-iqmvU8{2f&*^5kh%a_Lr8C-V(U|B_^A z^NcF(pg(D8&t+(%vdp-DOO@Q%rTUzGqVsye&#S_}U+u|>@2KJ{#nE0642@Vj+IKCD zejkz@`uIIn+9MBtuj*H&7vA?(v4za2EaBISs`PP8mA*KiUJ?w?+4`Yi+EX0uM}nbc zefqJbWqo>CG}7U$Gc)HPy!-0L!7u4S2$KiIdKN2M-_)zK zZ(n-Tb`zmK2IHwxd?IX&#&PM)7$1kmX3kifOY){u=H3h<00W&~1Oi?kTAUgw3=g4=vP9&PpDm~w#*nNg7=)_ilW;BO-@(gg57 zk;#$uai~PB`ijKaG>?=BN!~=qIA2JkH#ItOVEm^%^PaKzgy*8h>Sg&tlG?*VK4it>z))nzbe0gKG0+yv$wVrO73*$s7=?@L|<+emK z<#5J7a4;C1*y~OV%5iBvsFz~RTg{&&w?$JdteQ3#6;%JiYUy|-REw%Qkkx+gzCd;x zI)Jdp66PGDUG>sZS-q8L#+S!YH7w`l%zcL!&NoWr@j#(XXQ#v>b%~r!_4y|%!9fm3 z6!3;0l$*1&X9CfTqrqG$cD-`5l4+28EJrfUmKsC8$*mEC&xO-NzM@}?(gO){P}H1Bv!L+8Q126+0vu6xRBbiGwbNUvDD!5VkWOI zO^lP3OVHSwEl#WHtvt${wjAAM9do>e)0UQnHkJ-sI#{il>_K|EYSk+y zYz66oX)Biu$?Z8(zN>#hd8Ia8Vuw*uDVd_GZ^CNU4DK{WTwgPC{Z4K$U0VY7q@@H0 zoZx^JY|f2jC-p^^3_GVL4~r|z zz}Ruj^i46)Od|*b{!9|!aL&xmq(1jxEk0F>b(&wEsLkKYY|5t-H!jt+lj)7YEa3A( zNBpz7++0l?)@&)N<_mUsOil&;!^4U;a6YeoxIT^T)84S0%Y}mWLnU9aEhAYyq{F=@ zNbk~)W}2EAjT6TT+JG4De14fm!#l7Su}QvTcei)C>$X{Ewv}aePcHTq%oc3k%(M~F zIWq|ARw}Fgbeo@70&8bo*hDREUhix(#pIw_jA_}((_L{iDCSd!z3iL%mTB!}g9Ckj zsGVwIJ6n1yY1HB<=e_{iHUH1O^uL$y)NPB~W$@bE z=F#Q4+_Kbi(5y4!ML!lf1x+RUV-e&o?MEQ%P-kjA@w`64T>fy-e5dNwdLM_+f%;NE z0-+5*X1G>-d!{A4M;CG}JdlW?p*ub7(ub?1VJoG%OZ_#*c1pA7jYf8@@u%amUpy`+ zvAKs zxPT>I*wr0?xu65SS@reTuH4fr4*Xjz4LTJY+x5gZat2?(i7zzxgBErdZ{Wn+@poF7 zIM5!P_&fe?!T99#gEI!u-tJ-yo5QNu<06H=KB7vjz==yqm6#k>))J57s*k8be^4~+ zhN{rfHLj~`VsSzhI+cRIt5vU53-~834V}mmyK#*#`nc?(9Wu=Y?>% zv+6Tt==L2u2XF5m-Z{`W*gr7LMHc6W9o|TdIrBti@pP|IT|8r-x*0V3=QD?e#PykM zTi;3sIe=UU?2-eK%Dt1}NL#2QZ$Bt4(Muhg vY=cV}pqBXiH%#nk3{$*ln9_rSh0(aAVRH8eX|I+V5*=B!y1Wv7ov8l{t?GKZ literal 0 HcmV?d00001 diff --git a/src/wayland/shader_unlit_simula.hlsl b/src/wayland/shader_unlit_simula.hlsl new file mode 100644 index 0000000..a246965 --- /dev/null +++ b/src/wayland/shader_unlit_simula.hlsl @@ -0,0 +1,111 @@ +#include "stereokit.hlsli" + +// Port of https://github.com/SimulaVR/Simula/blob/master/addons/godot-haskell-plugin/TextShader.tres to StereoKit and HLSL. + +//--name = stardust/text_shader +//--diffuse = white +//--fcFactor = 1.0 +//--ripple = 4.0 +//--size = 256, 256 +//--uv_offset = 0.0, 0.0 +//--uv_scale = 1.0, 1.0 +Texture2D diffuse : register(t0); +SamplerState diffuse_s : register(s0); +int2 size; +float fcFactor; +float ripple; +float2 uv_scale; +float2 uv_offset; + +struct vsIn { + float4 pos : SV_Position; + float3 norm : NORMAL0; + float2 uv : TEXCOORD0; +}; +struct psIn { + float4 pos : SV_POSITION; + float2 uv : TEXCOORD0; + uint view_id : SV_RenderTargetArrayIndex; +}; + +psIn vs(vsIn input, uint id : SV_InstanceID) { + psIn o; + o.view_id = id % sk_view_count; + id = id / sk_view_count; + + float3 world = mul(float4(input.pos.xyz, 1), sk_inst[id].world).xyz; + o.pos = mul(float4(world, 1), sk_viewproj[o.view_id]); + + o.uv = (input.uv) + uv_offset * uv_scale; + return o; +} + +// float gaussian(float x, float t) { +// float PI = 3.14159265358; +// return exp(-x*x/(2.0 * t*t))/(sqrt(2.0*PI)*t); +// } + +float besselI0(float x) { + return 1.0 + pow(x, 2.0) * (0.25 + pow(x, 2.0) * (0.015625 + pow(x, 2.0) * (0.000434028 + pow(x, 2.0) * (6.78168e-6 + pow(x, 2.0) * (6.78168e-8 + pow(x, 2.0) * (4.7095e-10 + pow(x, 2.0) * (2.40281e-12 + pow(x, 2.0) * (9.38597e-15 + pow(x, 2.0) * (2.8969e-17 + 7.24226e-20 * pow(x, 2.0)))))))))); +} + +float kaiser(float x, float alpha) { + if (x > 1.0) { + return 0.0; + } + return besselI0(alpha * sqrt(1.0-x*x)); +} + +float4 lowpassFilter(Texture2D tex, sampler2D texSampler, float2 uv, float alpha) { + float PI = 3.14159265358; + + float4 q = float4(0.0); + + float2 dx_uv = ddx(uv); + float2 dy_uv = ddy(uv); + //float width = sqrt(max(dot(dx_uv, dx_uv), dot(dy_uv, dy_uv))); + float2 width = abs(float2(dx_uv.x, dy_uv.y)); + + float2 pixelWidth = floor(width * float2(size)); + float2 aspectRatio = normalize(pixelWidth); + + float2 xyf = uv * float2(size); + int2 xy = int2(xyf); + + pixelWidth = clamp(pixelWidth, float2(1.0), float2(2.0)); + + int2 start = xy - int2(pixelWidth); + int2 end = xy + int2(pixelWidth); + + float4 outColor = float4(0.0); + + float qSum = 0.0; + + for (int v = start.y; v <= end.y; v++) { + for (int u = start.x; u <= end.x; u++) { + float kx = fcFactor * (xyf.x - float(u))/pixelWidth.x; + float ky = fcFactor * (xyf.y - float(v))/pixelWidth.y; + + //float lanczosValue = gaussian(kx, fcx); + float lanczosValue = kaiser(sqrt(kx*kx + ky*ky), alpha); + + q += tex.Sample(texSampler, (float2(u, v)+float2(0.5))/float2(size)) * lanczosValue; + // q += tex.Load(int3(u, v, 0)) * lanczosValue; + qSum += lanczosValue; + } + } + + return q/qSum; +} + +float4 ps(psIn input) : SV_TARGET { + float gamma = 2.2; + // float4 col = diffuse.Sample(diffuse_s, input.uv); + + // float4 col = lowpassFilter(diffuse, diffuse_s, diffuse_i.xy, float2(1.0 - input.uv.x, input.uv.y), ripple); + float4 col = lowpassFilter(diffuse, diffuse_s, input.uv, ripple); + // float4 col = diffuse.Sample(diffuse_s, input.uv); + col.rgb = pow(col.rgb, float3(gamma)); + + return col; +} diff --git a/src/wayland/shader_unlit_simula.sks b/src/wayland/shader_unlit_simula.sks new file mode 100644 index 0000000000000000000000000000000000000000..1e0a7c851b0843844dd5f9635afb832d51df7175 GIT binary patch literal 28411 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 J_`>>, + sk_tex: OnceCell, + sk_mat: OnceCell, +} + +impl CoreSurface { + pub fn new() -> Self { + CoreSurface { + wl_tex: RefCell::new(None), + sk_tex: OnceCell::new(), + sk_mat: OnceCell::new(), + } + } + + pub fn update_tex(&self, sk: &StereoKit) { + let sk_tex = self + .sk_tex + .get_or_try_init(|| { + SKTexture::create(sk, TextureType::ImageNoMips, TextureFormat::RGBA32).ok_or(Error) + }) + .unwrap(); + let sk_mat = self + .sk_mat + .get_or_try_init(|| { + let shader = Shader::from_mem(sk, SIMULA_SHADER_BYTES).unwrap(); + Material::create(sk, &shader).ok_or(Error).map(|mat| { + mat.set_parameter("diffuse", self.sk_tex.get().unwrap()); + mat + }) + }) + .unwrap(); + if let Some(smithay_tex) = self.wl_tex.borrow().as_ref() { + unsafe { + sk_tex.set_native( + smithay_tex.tex_id() as usize, + smithay::backend::renderer::gles2::ffi::RGBA8.into(), + TextureType::Image, + smithay_tex.width(), + smithay_tex.height(), + false, + ); + let size: mint::Vector2 = + vec2(smithay_tex.width() as f32, smithay_tex.height() as f32).into(); + sk_mat.set_parameter("size", &size); + sk_tex.set_sample(TextureSample::Point); + sk_tex.set_address_mode(TextureAddress::Clamp); + } + } + } +} diff --git a/src/wayland/xdg_shell.rs b/src/wayland/xdg_shell.rs index 0dccd91..a97fd01 100644 --- a/src/wayland/xdg_shell.rs +++ b/src/wayland/xdg_shell.rs @@ -4,10 +4,10 @@ use smithay::{ decoration::zv1::server::zxdg_toplevel_decoration_v1::Mode, shell::server::xdg_toplevel::State, }, - wayland::shell::xdg::XdgShellHandler, + wayland::{compositor, shell::xdg::XdgShellHandler}, }; -use super::WaylandState; +use super::{surface::CoreSurface, WaylandState}; impl XdgShellHandler for WaylandState { fn xdg_shell_state(&mut self) -> &mut smithay::wayland::shell::xdg::XdgShellState { @@ -26,6 +26,10 @@ impl XdgShellHandler for WaylandState { state.decoration_mode = Some(Mode::ServerSide); }); surface.send_configure(); + + compositor::with_states(surface.wl_surface(), |data| { + data.data_map.insert_if_missing(|| CoreSurface::new()); + }); } fn new_popup( @@ -37,6 +41,10 @@ impl XdgShellHandler for WaylandState { self.output .enter(&self.display_handle, surface.wl_surface()); let _ = surface.send_configure(); + + compositor::with_states(surface.wl_surface(), |data| { + data.data_map.insert_if_missing(|| CoreSurface::new()); + }); } fn grab(