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

View File

@@ -9,7 +9,7 @@ use glam::{Mat4, Vec2, Vec3};
use once_cell::sync::OnceCell;
use parking_lot::Mutex;
use rustc_hash::FxHashMap;
use send_wrapper::SendWrapper;
use stardust_xr::values::ResourceID;
use stereokit_rust::material::Transparency;
use stereokit_rust::maths::Bounds;
@@ -21,8 +21,12 @@ use std::sync::{Arc, Weak};
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 HOLDOUT_MATERIAL: OnceCell<Arc<SendWrapper<Material>>> = OnceCell::new();
static HOLDOUT_MATERIAL: OnceCell<Arc<MaterialWrapper>> = OnceCell::new();
impl MaterialParameter {
fn apply_to_material(&self, client: &Client, material: &Material, parameter_name: &str) {
@@ -72,7 +76,7 @@ pub struct ModelPart {
space: Arc<Spatial>,
model: Weak<Model>,
pending_material_parameters: Mutex<FxHashMap<String, MaterialParameter>>,
pending_material_replacement: Mutex<Option<Arc<SendWrapper<Material>>>>,
pending_material_replacement: Mutex<Option<Arc<MaterialWrapper>>>,
aliases: AliasList,
}
impl ModelPart {
@@ -81,7 +85,7 @@ impl ModelPart {
let mut mat = Material::copy(Material::unlit());
mat.transparency(Transparency::None);
mat.color_tint(Color128::BLACK_TRANSPARENT);
Arc::new(SendWrapper::new(mat))
Arc::new(MaterialWrapper(mat))
});
let nodes = sk_model.get_nodes();
@@ -151,7 +155,7 @@ impl ModelPart {
Some(model_part)
}
pub fn replace_material(&self, replacement: Arc<SendWrapper<Material>>) {
pub fn replace_material(&self, replacement: Arc<MaterialWrapper>) {
self.pending_material_replacement
.lock()
.replace(replacement);
@@ -195,7 +199,7 @@ impl ModelPart {
};
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

View File

@@ -45,12 +45,12 @@ impl InputMethod {
handler_field_aliases: AliasList::default(),
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() {
method.handle_new_handler(&handler);
}
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());
Ok(method)
}

View File

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

View File

@@ -1,11 +1,18 @@
use super::{state::WaylandState, utils::get_data};
use crate::{
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 once_cell::sync::OnceCell;
use parking_lot::Mutex;
use send_wrapper::SendWrapper;
use smithay::{
backend::renderer::{
@@ -42,8 +49,8 @@ pub struct CoreSurface {
pub dh: DisplayHandle,
pub weak_surface: wayland_server::Weak<WlSurface>,
mapped_data: Mutex<Option<CoreSurfaceData>>,
sk_tex: OnceCell<SendWrapper<Mutex<Tex>>>,
sk_mat: OnceCell<SendWrapper<Mutex<Material>>>,
sk_tex: OnceCell<Mutex<TexWrapper>>,
sk_mat: OnceCell<Mutex<MaterialWrapper>>,
material_offset: Mutex<Delta<u32>>,
on_mapped: Mutex<Box<dyn Fn() + 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(|| {
SendWrapper::new(Mutex::new(Tex::new(
Mutex::new(TexWrapper(Tex::new(
TexType::ImageNomips,
TexFormat::RGBA32Linear,
nanoid::nanoid!(),
@@ -106,9 +113,9 @@ impl CoreSurface {
// });
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);
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)
@@ -154,6 +161,7 @@ impl CoreSurface {
};
sk_tex
.lock()
.0
.set_native_surface(
smithay_tex.tex_id() as usize as *mut c_void,
TexType::ImageNomips,
@@ -167,7 +175,7 @@ impl CoreSurface {
.address_mode(TexAddress::Clamp);
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 {
@@ -212,7 +220,7 @@ impl CoreSurface {
if let Some(sk_mat) = self.sk_mat.get() {
let sk_mat = sk_mat.lock();
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();
}