fix(model): no panic on material change

This commit is contained in:
Nova
2024-06-06 09:02:32 -04:00
parent 9425d30cb3
commit 3cbc10d91e
5 changed files with 48 additions and 30 deletions

View File

@@ -9,7 +9,6 @@ use color_eyre::eyre::{eyre, Result};
use glam::{vec3, Vec4Swizzles}; use glam::{vec3, Vec4Swizzles};
use once_cell::sync::OnceCell; use once_cell::sync::OnceCell;
use parking_lot::Mutex; use parking_lot::Mutex;
use send_wrapper::SendWrapper;
use stardust_xr::values::ResourceID; use stardust_xr::values::ResourceID;
use std::ops::DerefMut; use std::ops::DerefMut;
@@ -25,7 +24,7 @@ pub struct Sound {
volume: f32, volume: f32,
pending_audio_path: PathBuf, pending_audio_path: PathBuf,
sk_sound: OnceCell<SendWrapper<SkSound>>, sk_sound: OnceCell<SkSound>,
instance: Mutex<Option<SoundInst>>, instance: Mutex<Option<SoundInst>>,
stop: Mutex<Option<()>>, stop: Mutex<Option<()>>,
play: Mutex<Option<()>>, play: Mutex<Option<()>>,
@@ -54,9 +53,9 @@ impl Sound {
} }
fn update(&self) { fn update(&self) {
let sound = self.sk_sound.get_or_init(|| { let sound = self
SendWrapper::new(SkSound::from_file(self.pending_audio_path.clone()).unwrap()) .sk_sound
}); .get_or_init(|| SkSound::from_file(self.pending_audio_path.clone()).unwrap());
if self.stop.lock().take().is_some() { if self.stop.lock().take().is_some() {
if let Some(instance) = self.instance.lock().take() { if let Some(instance) = self.instance.lock().take() {
instance.stop(); instance.stop();

View File

@@ -9,7 +9,7 @@ use glam::{Mat4, Vec2, Vec3};
use once_cell::sync::OnceCell; use once_cell::sync::OnceCell;
use parking_lot::Mutex; use parking_lot::Mutex;
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use send_wrapper::SendWrapper;
use stardust_xr::values::ResourceID; use stardust_xr::values::ResourceID;
use stereokit_rust::material::Transparency; use stereokit_rust::material::Transparency;
use stereokit_rust::maths::Bounds; use stereokit_rust::maths::Bounds;
@@ -21,8 +21,12 @@ use std::sync::{Arc, Weak};
use super::{MaterialParameter, ModelAspect, ModelPartAspect, MODEL_PART_ASPECT_ALIAS_INFO}; use super::{MaterialParameter, ModelAspect, ModelPartAspect, MODEL_PART_ASPECT_ALIAS_INFO};
pub struct MaterialWrapper(pub Material);
unsafe impl Send for MaterialWrapper {}
unsafe impl Sync for MaterialWrapper {}
static MODEL_REGISTRY: Registry<Model> = Registry::new(); static MODEL_REGISTRY: Registry<Model> = Registry::new();
static HOLDOUT_MATERIAL: OnceCell<Arc<SendWrapper<Material>>> = OnceCell::new(); static HOLDOUT_MATERIAL: OnceCell<Arc<MaterialWrapper>> = OnceCell::new();
impl MaterialParameter { impl MaterialParameter {
fn apply_to_material(&self, client: &Client, material: &Material, parameter_name: &str) { fn apply_to_material(&self, client: &Client, material: &Material, parameter_name: &str) {
@@ -72,7 +76,7 @@ pub struct ModelPart {
space: Arc<Spatial>, space: Arc<Spatial>,
model: Weak<Model>, model: Weak<Model>,
pending_material_parameters: Mutex<FxHashMap<String, MaterialParameter>>, pending_material_parameters: Mutex<FxHashMap<String, MaterialParameter>>,
pending_material_replacement: Mutex<Option<Arc<SendWrapper<Material>>>>, pending_material_replacement: Mutex<Option<Arc<MaterialWrapper>>>,
aliases: AliasList, aliases: AliasList,
} }
impl ModelPart { impl ModelPart {
@@ -81,7 +85,7 @@ impl ModelPart {
let mut mat = Material::copy(Material::unlit()); let mut mat = Material::copy(Material::unlit());
mat.transparency(Transparency::None); mat.transparency(Transparency::None);
mat.color_tint(Color128::BLACK_TRANSPARENT); mat.color_tint(Color128::BLACK_TRANSPARENT);
Arc::new(SendWrapper::new(mat)) Arc::new(MaterialWrapper(mat))
}); });
let nodes = sk_model.get_nodes(); let nodes = sk_model.get_nodes();
@@ -151,7 +155,7 @@ impl ModelPart {
Some(model_part) Some(model_part)
} }
pub fn replace_material(&self, replacement: Arc<SendWrapper<Material>>) { pub fn replace_material(&self, replacement: Arc<MaterialWrapper>) {
self.pending_material_replacement self.pending_material_replacement
.lock() .lock()
.replace(replacement); .replace(replacement);
@@ -195,7 +199,7 @@ impl ModelPart {
}; };
if let Some(material_replacement) = self.pending_material_replacement.lock().take() { if let Some(material_replacement) = self.pending_material_replacement.lock().take() {
part.material(&**material_replacement); part.material(&material_replacement.0);
} }
// todo: find all materials with identical parameters and batch them into 1 material again // todo: find all materials with identical parameters and batch them into 1 material again

View File

@@ -45,12 +45,12 @@ impl InputMethod {
handler_field_aliases: AliasList::default(), handler_field_aliases: AliasList::default(),
handler_order: Mutex::new(Vec::new()), handler_order: Mutex::new(Vec::new()),
}; };
<InputMethod as InputMethodRefAspect>::add_node_members(node);
<InputMethod as InputMethodAspect>::add_node_members(node);
for handler in INPUT_HANDLER_REGISTRY.get_valid_contents() { for handler in INPUT_HANDLER_REGISTRY.get_valid_contents() {
method.handle_new_handler(&handler); method.handle_new_handler(&handler);
} }
let method = INPUT_METHOD_REGISTRY.add(method); let method = INPUT_METHOD_REGISTRY.add(method);
<InputMethod as InputMethodRefAspect>::add_node_members(node);
<InputMethod as InputMethodAspect>::add_node_members(node);
node.add_aspect_raw(method.clone()); node.add_aspect_raw(method.clone());
Ok(method) Ok(method)
} }

View File

@@ -5,7 +5,10 @@ use crate::{
core::{client::Client, registry::Registry, scenegraph::MethodResponseSender}, core::{client::Client, registry::Registry, scenegraph::MethodResponseSender},
create_interface, create_interface,
nodes::{ nodes::{
drawable::{model::ModelPart, shaders::UNLIT_SHADER_BYTES}, drawable::{
model::{MaterialWrapper, ModelPart},
shaders::UNLIT_SHADER_BYTES,
},
items::TypeInfo, items::TypeInfo,
spatial::{Spatial, Transform}, spatial::{Spatial, Transform},
Message, Node, Message, Node,
@@ -17,7 +20,7 @@ use lazy_static::lazy_static;
use mint::{ColumnMatrix4, Vector2}; use mint::{ColumnMatrix4, Vector2};
use once_cell::sync::OnceCell; use once_cell::sync::OnceCell;
use parking_lot::Mutex; use parking_lot::Mutex;
use send_wrapper::SendWrapper;
use stardust_xr::schemas::flex::{deserialize, serialize}; use stardust_xr::schemas::flex::{deserialize, serialize};
use std::sync::Arc; use std::sync::Arc;
use stereokit_rust::{ use stereokit_rust::{
@@ -30,6 +33,10 @@ use stereokit_rust::{
}; };
use tracing::error; use tracing::error;
pub struct TexWrapper(pub Tex);
unsafe impl Send for TexWrapper {}
unsafe impl Sync for TexWrapper {}
stardust_xr_server_codegen::codegen_item_camera_protocol!(); stardust_xr_server_codegen::codegen_item_camera_protocol!();
lazy_static! { lazy_static! {
pub(super) static ref ITEM_TYPE_INFO_CAMERA: TypeInfo = TypeInfo { pub(super) static ref ITEM_TYPE_INFO_CAMERA: TypeInfo = TypeInfo {
@@ -53,8 +60,8 @@ struct FrameInfo {
pub struct CameraItem { pub struct CameraItem {
space: Arc<Spatial>, space: Arc<Spatial>,
frame_info: Mutex<FrameInfo>, frame_info: Mutex<FrameInfo>,
sk_tex: OnceCell<SendWrapper<Tex>>, sk_tex: OnceCell<TexWrapper>,
sk_mat: OnceCell<Arc<SendWrapper<Material>>>, sk_mat: OnceCell<Arc<MaterialWrapper>>,
applied_to: Registry<ModelPart>, applied_to: Registry<ModelPart>,
apply_to: Registry<ModelPart>, apply_to: Registry<ModelPart>,
} }
@@ -120,7 +127,7 @@ impl CameraItem {
pub fn update(&self, token: &MainThreadToken) { pub fn update(&self, token: &MainThreadToken) {
let frame_info = self.frame_info.lock(); let frame_info = self.frame_info.lock();
let sk_tex = self.sk_tex.get_or_init(|| { let sk_tex = self.sk_tex.get_or_init(|| {
SendWrapper::new(Tex::gen_color( TexWrapper(Tex::gen_color(
Color128::default(), Color128::default(),
frame_info.px_size.x as i32, frame_info.px_size.x as i32,
frame_info.px_size.y as i32, frame_info.px_size.y as i32,
@@ -130,12 +137,12 @@ impl CameraItem {
}); });
let sk_mat = self let sk_mat = self
.sk_mat .sk_mat
.get_or_try_init(|| -> Result<Arc<SendWrapper<Material>>> { .get_or_try_init(|| -> Result<Arc<MaterialWrapper>> {
let shader = Shader::from_memory(&UNLIT_SHADER_BYTES)?; let shader = Shader::from_memory(&UNLIT_SHADER_BYTES)?;
let mut mat = Material::new(&shader, None); let mut mat = Material::new(&shader, None);
mat.get_all_param_info().set_texture("diffuse", &**sk_tex); mat.get_all_param_info().set_texture("diffuse", &sk_tex.0);
mat.transparency(Transparency::Blend); mat.transparency(Transparency::Blend);
Ok(Arc::new(SendWrapper::new(mat))) Ok(Arc::new(MaterialWrapper(mat)))
}); });
let Ok(sk_mat) = sk_mat else { let Ok(sk_mat) = sk_mat else {
error!("unable to make camera item stereokit texture"); error!("unable to make camera item stereokit texture");
@@ -148,7 +155,7 @@ impl CameraItem {
if !self.applied_to.is_empty() { if !self.applied_to.is_empty() {
Renderer::render_to( Renderer::render_to(
token, token,
&**sk_tex, &sk_tex.0,
self.space.global_transform(), self.space.global_transform(),
frame_info.proj_matrix, frame_info.proj_matrix,
None, None,

View File

@@ -1,11 +1,18 @@
use super::{state::WaylandState, utils::get_data}; use super::{state::WaylandState, utils::get_data};
use crate::{ use crate::{
core::{delta::Delta, destroy_queue, registry::Registry}, core::{delta::Delta, destroy_queue, registry::Registry},
nodes::drawable::{model::ModelPart, shaders::PANEL_SHADER_BYTES}, nodes::{
drawable::{
model::{MaterialWrapper, ModelPart},
shaders::PANEL_SHADER_BYTES,
},
items::camera::TexWrapper,
},
}; };
use mint::Vector2; use mint::Vector2;
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::{ use smithay::{
backend::renderer::{ backend::renderer::{
@@ -42,8 +49,8 @@ pub struct CoreSurface {
pub dh: DisplayHandle, pub dh: DisplayHandle,
pub weak_surface: wayland_server::Weak<WlSurface>, pub weak_surface: wayland_server::Weak<WlSurface>,
mapped_data: Mutex<Option<CoreSurfaceData>>, mapped_data: Mutex<Option<CoreSurfaceData>>,
sk_tex: OnceCell<SendWrapper<Mutex<Tex>>>, sk_tex: OnceCell<Mutex<TexWrapper>>,
sk_mat: OnceCell<SendWrapper<Mutex<Material>>>, sk_mat: OnceCell<Mutex<MaterialWrapper>>,
material_offset: Mutex<Delta<u32>>, material_offset: Mutex<Delta<u32>>,
on_mapped: Mutex<Box<dyn Fn() + Send + Sync>>, on_mapped: Mutex<Box<dyn Fn() + Send + Sync>>,
on_commit: Mutex<Box<dyn Fn(u32) + Send + Sync>>, on_commit: Mutex<Box<dyn Fn(u32) + Send + Sync>>,
@@ -93,7 +100,7 @@ impl CoreSurface {
}; };
let sk_tex = self.sk_tex.get_or_init(|| { let sk_tex = self.sk_tex.get_or_init(|| {
SendWrapper::new(Mutex::new(Tex::new( Mutex::new(TexWrapper(Tex::new(
TexType::ImageNomips, TexType::ImageNomips,
TexFormat::RGBA32Linear, TexFormat::RGBA32Linear,
nanoid::nanoid!(), nanoid::nanoid!(),
@@ -106,9 +113,9 @@ impl CoreSurface {
// }); // });
let mut mat = Material::new(shader, None); let mut mat = Material::new(shader, None);
mat.diffuse_tex(sk_tex.lock().as_ref()); mat.diffuse_tex(&sk_tex.lock().0);
mat.transparency(Transparency::Blend); mat.transparency(Transparency::Blend);
SendWrapper::new(Mutex::new(mat)) Mutex::new(MaterialWrapper(mat))
}); });
// Let smithay handle buffer management (has to be done here as RendererSurfaceStates is not thread safe) // Let smithay handle buffer management (has to be done here as RendererSurfaceStates is not thread safe)
@@ -154,6 +161,7 @@ impl CoreSurface {
}; };
sk_tex sk_tex
.lock() .lock()
.0
.set_native_surface( .set_native_surface(
smithay_tex.tex_id() as usize as *mut c_void, smithay_tex.tex_id() as usize as *mut c_void,
TexType::ImageNomips, TexType::ImageNomips,
@@ -167,7 +175,7 @@ impl CoreSurface {
.address_mode(TexAddress::Clamp); .address_mode(TexAddress::Clamp);
if let Some(material_offset) = self.material_offset.lock().delta() { if let Some(material_offset) = self.material_offset.lock().delta() {
sk_mat.lock().queue_offset(*material_offset as i32); sk_mat.lock().0.queue_offset(*material_offset as i32);
} }
let Some(surface_size) = renderer_surface_state.surface_size() else { let Some(surface_size) = renderer_surface_state.surface_size() else {
@@ -212,7 +220,7 @@ impl CoreSurface {
if let Some(sk_mat) = self.sk_mat.get() { if let Some(sk_mat) = self.sk_mat.get() {
let sk_mat = sk_mat.lock(); let sk_mat = sk_mat.lock();
for model_node in self.pending_material_applications.get_valid_contents() { for model_node in self.pending_material_applications.get_valid_contents() {
model_node.replace_material_now(sk_mat.as_ref()); model_node.replace_material_now(&sk_mat.0);
} }
self.pending_material_applications.clear(); self.pending_material_applications.clear();
} }