From 89b724b8e2eef1c24f7761287bd306be2f22c327 Mon Sep 17 00:00:00 2001 From: Schmarni Date: Fri, 12 Dec 2025 23:51:16 +0100 Subject: [PATCH 01/16] feat(protocol): add dmatex infra Signed-off-by: Schmarni --- fusion/src/protocol.rs | 170 ++++++++++++++++++++++++++++++++++++++ protocol/idl/drawable.kdl | 66 +++++++++++++++ 2 files changed, 236 insertions(+) diff --git a/fusion/src/protocol.rs b/fusion/src/protocol.rs index ce58034..1117e6a 100644 --- a/fusion/src/protocol.rs +++ b/fusion/src/protocol.rs @@ -1309,6 +1309,21 @@ pub mod drawable { Exact, Overflow, } + ///Size and Dimensions of a Dmatex + #[derive(Debug, Clone, PartialEq, serde::Deserialize, serde::Serialize)] + #[serde(tag = "t", content = "c")] + pub enum DmatexSize { + Dim1D(u32), + Dim2D(stardust_xr_wire::values::Vector2), + Dim3D(stardust_xr_wire::values::Vector3), + } + ///Drm Node Id used for selecting the correct gpu + #[derive(Debug, Clone, PartialEq, serde::Deserialize, serde::Serialize)] + #[serde(tag = "t", content = "c")] + pub enum DrmNodeId { + DrmRenderNode(u64), + DrmPrimaryNode(u64), + } /// #[derive(Debug, Clone, PartialEq, serde::Deserialize, serde::Serialize)] #[serde(tag = "t", content = "c")] @@ -1322,6 +1337,22 @@ pub mod drawable { Color(stardust_xr_wire::values::Color), Texture(stardust_xr_wire::values::ResourceID), } + ///Description of a format supported by the server + #[derive(Debug, Clone, PartialEq, serde::Deserialize, serde::Serialize)] + pub struct DmatexFormatInfo { + pub format: u32, + pub drm_modifier: u64, + pub supports_srgb: bool, + } + ///A single memory plane of a Dmatex + #[derive(Debug, Clone, PartialEq, serde::Deserialize, serde::Serialize)] + pub struct DmatexPlane { + pub drm_modifier: u64, + pub offset: u32, + pub row_size: u32, + pub array_element_size: u32, + pub depth_slice_size: u32, + } ///A single point on a line #[derive(Debug, Clone, PartialEq, serde::Deserialize, serde::Serialize)] pub struct LinePoint { @@ -1700,6 +1731,145 @@ pub mod drawable { Ok(()) } } + ///Import a Dmatex, the imported Dmatex has to be manually unregistered + pub async fn import_dmatex( + _client: &std::sync::Arc, + size: DmatexPlane, + format: u32, + srgb: bool, + array_layers: Option, + plane_1_dmabuf_fd: std::os::unix::io::OwnedFd, + plane_1_info: DmatexPlane, + timeline_syncobj_fd: std::os::unix::io::OwnedFd, + ) -> crate::node::NodeResult { + let mut _fds = Vec::new(); + let data = ( + size, + format, + srgb, + array_layers.map(|o| Ok::<_, crate::node::NodeError>(o)).transpose()?, + { + _fds.push(plane_1_dmabuf_fd); + (_fds.len() - 1) as u32 + }, + plane_1_info, + { + _fds.push(timeline_syncobj_fd); + (_fds.len() - 1) as u32 + }, + ); + { + let ( + size, + format, + srgb, + array_layers, + plane_1_dmabuf_fd, + plane_1_info, + timeline_syncobj_fd, + ) = &data; + tracing::trace!( + ? size, ? format, ? srgb, ? array_layers, ? plane_1_dmabuf_fd, ? + plane_1_info, ? timeline_syncobj_fd, "Called method on server, {}::{}", + "Interface", "import_dmatex" + ); + } + let serialized_data = stardust_xr_wire::flex::serialize(&data)?; + let message = _client + .message_sender_handle + .method(4u64, 0u64, 5202664904415071827u64, &serialized_data, _fds) + .await? + .map_err(|e| crate::node::NodeError::ReturnedError { + e, + })? + .into_message(); + let result: u64 = stardust_xr_wire::flex::deserialize(&message)?; + let deserialized = result; + tracing::trace!( + "return" = ? deserialized, "Method return from server, {}::{}", "Interface", + "import_dmatex" + ); + Ok(deserialized) + } + ///Mark a Dmatex as unused, this allows the server to destroy its imported representations, this invalidates the Dmatex id + pub fn unregister_dmatex( + _client: &std::sync::Arc, + dmatex_id: u64, + ) -> crate::node::NodeResult<()> { + let mut _fds = Vec::new(); + let data = (dmatex_id); + let serialized_data = stardust_xr_wire::flex::serialize(&data)?; + _client + .message_sender_handle + .signal(4u64, 0u64, 15846108642868241016u64, &serialized_data, _fds)?; + let (dmatex_id) = data; + tracing::trace!( + ? dmatex_id, "Sent signal to server, {}::{}", "Interface", + "unregister_dmatex" + ); + Ok(()) + } + ///get the id of the primary device used for rendering, will return a render node id if possilbe + pub async fn get_primary_render_device_id( + _client: &std::sync::Arc, + ) -> crate::node::NodeResult { + let mut _fds = Vec::new(); + let data = (); + { + let () = &data; + tracing::trace!( + "Called method on server, {}::{}", "Interface", + "get_primary_render_device_id" + ); + } + let serialized_data = stardust_xr_wire::flex::serialize(&data)?; + let message = _client + .message_sender_handle + .method(4u64, 0u64, 16013200258148922551u64, &serialized_data, _fds) + .await? + .map_err(|e| crate::node::NodeError::ReturnedError { + e, + })? + .into_message(); + let result: DrmNodeId = stardust_xr_wire::flex::deserialize(&message)?; + let deserialized = result; + tracing::trace!( + "return" = ? deserialized, "Method return from server, {}::{}", "Interface", + "get_primary_render_device_id" + ); + Ok(deserialized) + } + ///enumerates all the Dmatex formats supported by the server + pub async fn enumerate_dmatex_formats( + _client: &std::sync::Arc, + device_id: DrmNodeId, + ) -> crate::node::NodeResult { + let mut _fds = Vec::new(); + let data = (device_id); + { + let (device_id) = &data; + tracing::trace!( + ? device_id, "Called method on server, {}::{}", "Interface", + "enumerate_dmatex_formats" + ); + } + let serialized_data = stardust_xr_wire::flex::serialize(&data)?; + let message = _client + .message_sender_handle + .method(4u64, 0u64, 14109465327684673699u64, &serialized_data, _fds) + .await? + .map_err(|e| crate::node::NodeError::ReturnedError { + e, + })? + .into_message(); + let result: DmatexFormatInfo = stardust_xr_wire::flex::deserialize(&message)?; + let deserialized = result; + tracing::trace!( + "return" = ? deserialized, "Method return from server, {}::{}", "Interface", + "enumerate_dmatex_formats" + ); + Ok(deserialized) + } ///Set the sky texture to a given HDRI file. pub fn set_sky_tex( _client: &std::sync::Arc, diff --git a/protocol/idl/drawable.kdl b/protocol/idl/drawable.kdl index 850cc25..010d62c 100644 --- a/protocol/idl/drawable.kdl +++ b/protocol/idl/drawable.kdl @@ -2,6 +2,72 @@ version (u32)1 interface (u64)4 description "" + +method "import_dmatex" side="server" { + description "Import a Dmatex, the imported Dmatex has to be manually unregistered" + + argument "size" type="union" union="DmatexPlane" + argument "format" type="uint" description="the texture format as a drm_fourcc" + argument "srgb" type="bool" description="try to use an SRGB color space version of the format, needed because drm_fourcc can't represent this information" + argument "array_layers" type="uint" optional=true description="try to use an SRGB color space version of the format, needed because drm_fourcc can't represent this information" + argument "plane_1_dmabuf_fd" type="fd" description="the underlying dmabuf fd for the first plane" + argument "plane_1_info" type="struct" struct="DmatexPlane" + argument "timeline_syncobj_fd" type="fd" description="the fd carrying info for explicit sync, using the timeline variant of the drm_syncobj" + + return type="id" +} + +signal "unregister_dmatex" side="server" { + description "Mark a Dmatex as unused, this allows the server to destroy its imported representations, this invalidates the Dmatex id" + + argument "dmatex_id" type="id" +} + +method "get_primary_render_device_id" side="server" { + description "get the id of the primary device used for rendering, will return a render node id if possilbe" + + return type="union" union="DrmNodeId" +} + +method "enumerate_dmatex_formats" side="server" { + description "enumerates all the Dmatex formats supported by the server" + + argument "device_id" type="union" union="DrmNodeId" + + return type="struct" struct="DmatexFormatInfo" +} + +struct "DmatexFormatInfo" { + description "Description of a format supported by the server" + field "format" type="uint" description="drm_fourcc for the format" + field "drm_modifier" type="id" + field "supports_srgb" type="bool" +} + +struct "DmatexPlane" { + description "A single memory plane of a Dmatex" + field "drm_modifier" type="id" description="The Drm modifier of this Dmatex memory plane" + field "offset" type="uint" description="offset of the data relevant to this Dmatex plane in the Dmatex memory" + field "row_size" type="uint" description="the number of bytes between the beginning of one pixel row to the next, if the Dmatex is 1d this should be 0" + field "array_element_size" type="uint" description="the number of bytes between the beginning of one array element to the next, if the Dmatex is not an array texture this should be 0" + field "depth_slice_size" type="uint" description="the number of bytes between the beginning of one 3d slice to the next, if the Dmatex is not 3d this should be 0" +} + +union "DmatexSize" { + description "Size and Dimensions of a Dmatex" + + option type="uint" name="dim1d" + option type="vec2" component_type="uint" name="dim2d" + option type="vec3" component_type="uint" name="dim3d" +} + +union "DrmNodeId" { + description "Drm Node Id used for selecting the correct gpu" + + option type="id" name="DrmRenderNode" + option type="id" name="DrmPrimaryNode" +} + signal "set_sky_tex" side="server" { description "Set the sky texture to a given HDRI file." From 010c6b8ff57702d4ee54db8961a567eaeb6b80e8 Mon Sep 17 00:00:00 2001 From: Schmarni Date: Sat, 13 Dec 2025 00:47:26 +0100 Subject: [PATCH 02/16] feat(protocol): add dmatex material param hookup Signed-off-by: Schmarni --- fusion/src/protocol.rs | 8 ++++++++ protocol/idl/drawable.kdl | 7 +++++++ 2 files changed, 15 insertions(+) diff --git a/fusion/src/protocol.rs b/fusion/src/protocol.rs index 1117e6a..f2ef337 100644 --- a/fusion/src/protocol.rs +++ b/fusion/src/protocol.rs @@ -1336,6 +1336,7 @@ pub mod drawable { Vec3(stardust_xr_wire::values::Vector3), Color(stardust_xr_wire::values::Color), Texture(stardust_xr_wire::values::ResourceID), + Dmatex(DmatexMaterialParam), } ///Description of a format supported by the server #[derive(Debug, Clone, PartialEq, serde::Deserialize, serde::Serialize)] @@ -1366,6 +1367,13 @@ pub mod drawable { pub points: Vec, pub cyclic: bool, } + ///Dmatex Material Parameter info + #[derive(Debug, Clone, PartialEq, serde::Deserialize, serde::Serialize)] + pub struct DmatexMaterialParam { + pub dmatex_id: u64, + pub acquire_point: u64, + pub release_point: u64, + } /// #[derive(Debug, Clone, PartialEq, serde::Deserialize, serde::Serialize)] pub struct TextBounds { diff --git a/protocol/idl/drawable.kdl b/protocol/idl/drawable.kdl index 010d62c..2cc0b0f 100644 --- a/protocol/idl/drawable.kdl +++ b/protocol/idl/drawable.kdl @@ -113,6 +113,12 @@ aspect "Lines" { } } +struct "DmatexMaterialParam" { + description "Dmatex Material Parameter info" + field "dmatex_id" type="id" description="The Id of the Dmatex to be applied as the texture" + field "acquire_point" type="id" description="the point the timeline reaches once the client is done mutating the texture" + field "release_point" type="id" description="the point the timeline reaches once the server is done with the dmatex and the client can access it again" +} union "MaterialParameter" { description "" @@ -125,6 +131,7 @@ union "MaterialParameter" { option type="vec3" option type="color" option type="resource" name="texture" + option type="struct" struct="DmatexMaterialParam" name="dmatex" } signal "load_model" side="server" { description "Load a GLTF model into a Model node" From 44ef24a82121e67874821c8bf9e337bee1328b36 Mon Sep 17 00:00:00 2001 From: Schmarni Date: Sat, 13 Dec 2025 01:08:56 +0100 Subject: [PATCH 03/16] feat(fusion/codegen): codegen doc comments for struct fields Signed-off-by: Schmarni --- fusion/build.rs | 19 ++++++++++---- fusion/src/protocol.rs | 56 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 5 deletions(-) diff --git a/fusion/build.rs b/fusion/build.rs index 050deae..557b5e1 100644 --- a/fusion/build.rs +++ b/fusion/build.rs @@ -322,11 +322,7 @@ impl Tokenize for CustomStruct { let name = Ident::new(&self.name.to_case(Case::Pascal), Span::call_site()); let description = &self.description; - let argument_decls = self - .fields - .iter() - .map(|a| generate_argument_decl(a, true)) - .map(|d| quote!(pub #d)); + let argument_decls = self.fields.iter().map(|a| generate_pub_field_decl(a, true)); let derive = if partial_eq { quote!( #[derive(Debug, Clone, PartialEq, serde::Deserialize, serde::Serialize)] ) @@ -945,6 +941,19 @@ fn generate_argument_decl(argument: &Argument, returned: bool) -> TokenStream { } quote!(#name: #_type) } +fn generate_pub_field_decl(argument: &Argument, returned: bool) -> TokenStream { + let name = Ident::new(&argument.name.to_case(Case::Snake), Span::call_site()); + let mut _type = generate_argument_type(&argument._type, returned); + if argument.optional { + _type = quote!(Option<#_type>); + } + let description = argument + .description + .as_ref() + .map(|d| quote!(#[doc = #d])) + .unwrap_or_default(); + quote!(#description pub #name: #_type) +} fn generate_argument_type(argument_type: &ArgumentType, owned: bool) -> TokenStream { match argument_type { ArgumentType::Empty => quote!(()), diff --git a/fusion/src/protocol.rs b/fusion/src/protocol.rs index f2ef337..1303386 100644 --- a/fusion/src/protocol.rs +++ b/fusion/src/protocol.rs @@ -16,14 +16,19 @@ pub mod root { /// #[derive(Debug, Clone, PartialEq, serde::Deserialize, serde::Serialize)] pub struct FrameInfo { + ///The time between this frame and last frame's display time, in seconds. pub delta: f32, + ///The total time in seconds the client has been connected to the server. pub elapsed: f32, } ///The persistent state of a Stardust client. #[derive(Debug, Clone, PartialEq, serde::Deserialize, serde::Serialize)] pub struct ClientState { + ///Data specific to your client, put anything you like here and it'll be saved/restored intact. pub data: Option>, + ///Where the client's root should be positioned on reload. pub root: u64, + ///Spatials that will be in the same place you left them. pub spatial_anchors: stardust_xr_wire::values::Map, } ///The hub of the client. Spatially this is positioned where the client is started so is a stable base to position things relative to. @@ -767,23 +772,33 @@ pub mod field { ///Information about raymarching a field. All vectors are relative to the spatial reference used. #[derive(Debug, Clone, PartialEq, serde::Deserialize, serde::Serialize)] pub struct RayMarchResult { + ///Origin of the ray pub ray_origin: stardust_xr_wire::values::Vector3, + ///Direction of the ray pub ray_direction: stardust_xr_wire::values::Vector3, + ///How close to or far inside the field the ray got. If less than zero, the ray intersected the field. pub min_distance: f32, + ///The distance to the point on the ray that has the least distance to the field/most distance inside it. Useful for finding a "near miss" point or how close to the core of the field you're pointing. pub deepest_point_distance: f32, + ///Maximum length of the ray pub ray_length: f32, + ///Number of steps taken pub ray_steps: u32, } ///Cylinder shape info #[derive(Debug, Clone, PartialEq, serde::Deserialize, serde::Serialize)] pub struct CylinderShape { + ///Length of the cylinder along the Y axis pub length: f32, + ///Radius of the cylinder along the XZ plane pub radius: f32, } ///Torus shape info #[derive(Debug, Clone, PartialEq, serde::Deserialize, serde::Serialize)] pub struct TorusShape { + ///Radius of the ring along the XZ plane pub radius_a: f32, + ///Radius of the tube pub radius_b: f32, } ///A reference to a signed distance field that you can sample @@ -1341,6 +1356,7 @@ pub mod drawable { ///Description of a format supported by the server #[derive(Debug, Clone, PartialEq, serde::Deserialize, serde::Serialize)] pub struct DmatexFormatInfo { + ///drm_fourcc for the format pub format: u32, pub drm_modifier: u64, pub supports_srgb: bool, @@ -1348,30 +1364,42 @@ pub mod drawable { ///A single memory plane of a Dmatex #[derive(Debug, Clone, PartialEq, serde::Deserialize, serde::Serialize)] pub struct DmatexPlane { + ///The Drm modifier of this Dmatex memory plane pub drm_modifier: u64, + ///offset of the data relevant to this Dmatex plane in the Dmatex memory pub offset: u32, + ///the number of bytes between the beginning of one pixel row to the next, if the Dmatex is 1d this should be 0 pub row_size: u32, + ///the number of bytes between the beginning of one array element to the next, if the Dmatex is not an array texture this should be 0 pub array_element_size: u32, + ///the number of bytes between the beginning of one 3d slice to the next, if the Dmatex is not 3d this should be 0 pub depth_slice_size: u32, } ///A single point on a line #[derive(Debug, Clone, PartialEq, serde::Deserialize, serde::Serialize)] pub struct LinePoint { + ///The position of the point relative to the Lines node pub point: stardust_xr_wire::values::Vector3, + ///Thickness in meters, world space pub thickness: f32, + ///Color of the point, premultiplied alpha pub color: stardust_xr_wire::values::Color, } ///A single continuous polyline #[derive(Debug, Clone, PartialEq, serde::Deserialize, serde::Serialize)] pub struct Line { pub points: Vec, + ///Cyclic if first point connects to the last point pub cyclic: bool, } ///Dmatex Material Parameter info #[derive(Debug, Clone, PartialEq, serde::Deserialize, serde::Serialize)] pub struct DmatexMaterialParam { + ///The Id of the Dmatex to be applied as the texture pub dmatex_id: u64, + ///the point the timeline reaches once the client is done mutating the texture pub acquire_point: u64, + ///the point the timeline reaches once the server is done with the dmatex and the client can access it again pub release_point: u64, } /// @@ -1385,7 +1413,9 @@ pub mod drawable { /// #[derive(Debug, Clone, PartialEq, serde::Deserialize, serde::Serialize)] pub struct TextStyle { + ///Height of a character in meters pub character_height: f32, + ///Premultiplied text color pub color: stardust_xr_wire::values::Color, pub font: Option, pub text_align_x: XAlign, @@ -2006,14 +2036,19 @@ pub mod input { ///A hand joint. Distance from input handler's field is given because it's cheap to calculate and laggy to request from the server. #[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] pub struct Joint { + ///Position of the joint relative to the input handler's field. pub position: stardust_xr_wire::values::Vector3, + ///Orientation of the joint relative to the input handler's field. pub rotation: stardust_xr_wire::values::Quaternion, + ///Radius of the joint in meters. pub radius: f32, + ///Distance from the center of the joint to the input handler's field pub distance: f32, } /// #[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] pub struct Finger { + ///Joint inside the fingertip offset by the radius. pub tip: Joint, pub distal: Joint, pub intermediate: Joint, @@ -2046,6 +2081,10 @@ pub mod input { pub struct Pointer { pub origin: stardust_xr_wire::values::Vector3, pub orientation: stardust_xr_wire::values::Quaternion, + /** + The point that is the most inside the input handler's field. + Useful for telling how close to the center it's pointing or for thin objects can take the place of a point of intersection. + */ pub deepest_point: stardust_xr_wire::values::Vector3, } ///Represents a controller, pen tip, spatial cursor, etc. that is just a single point. @@ -2057,11 +2096,17 @@ pub mod input { ///Information about a given input method's state. All coordinates are relative to the InputHandler. #[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] pub struct InputData { + ///Used to uniquely identify the input method so state can be tracked across input events. pub id: u64, + ///All vectors and quaternions are relative to the input handler if deserialized. pub input: InputDataType, + ///Closest distance from the input handler to the field. pub distance: f32, + ///Non-spatial data in a map. pub datamap: stardust_xr_wire::values::Datamap, + ///There are [order] objects that got this input data before this one. pub order: u32, + ///Is this input handler capturing this input method? pub captured: bool, } ///Node representing a spatial input device @@ -3383,12 +3428,19 @@ pub mod item_panel { ///The state of the panel item's toplevel. #[derive(Debug, Clone, PartialEq, serde::Deserialize, serde::Serialize)] pub struct ToplevelInfo { + ///The UID of the panel item of the parent of this toplevel, if it exists pub parent: Option, + ///Equivalent to the window title pub title: Option, + ///Application identifier, see pub app_id: Option, + ///Current size in pixels pub size: stardust_xr_wire::values::Vector2, + ///Recommended minimum size in pixels pub min_size: Option>, + ///Recommended maximum size in pixels pub max_size: Option>, + ///Surface geometry pub logical_rectangle: Geometry, } ///Data on positioning a child. @@ -3397,7 +3449,9 @@ pub mod item_panel { pub id: u64, pub parent: SurfaceId, pub geometry: Geometry, + ///Relative to parent. 0 is same level, -1 is below, 1 is above, etc. pub z_order: i32, + ///Whether this child receives input or is purely visual. pub receives_input: bool, } ///The init data for the panel item. @@ -3406,7 +3460,9 @@ pub mod item_panel { pub cursor: Option, pub toplevel: ToplevelInfo, pub children: Vec, + ///The surface, if any, that has exclusive input to the pointer. pub pointer_grab: Option, + ///The surface, if any, that has exclusive input to the keyboard. pub keyboard_grab: Option, } ///An item that represents a toplevel 2D window's surface (base window) and all its children (context menus, modals, etc.). From 318706f0664fef22c73df091ea99b78ff11c37aa Mon Sep 17 00:00:00 2001 From: Schmarni Date: Sun, 14 Dec 2025 04:35:32 +0100 Subject: [PATCH 04/16] fix(protocol): fix docs and enumerate_dmatex_formats Signed-off-by: Schmarni --- fusion/src/protocol.rs | 16 +++++++++++----- protocol/idl/drawable.kdl | 8 ++++---- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/fusion/src/protocol.rs b/fusion/src/protocol.rs index 1303386..4d6426f 100644 --- a/fusion/src/protocol.rs +++ b/fusion/src/protocol.rs @@ -1351,6 +1351,7 @@ pub mod drawable { Vec3(stardust_xr_wire::values::Vector3), Color(stardust_xr_wire::values::Color), Texture(stardust_xr_wire::values::ResourceID), + ///only accepts 2d Dmatexs without array layers Dmatex(DmatexMaterialParam), } ///Description of a format supported by the server @@ -1399,7 +1400,7 @@ pub mod drawable { pub dmatex_id: u64, ///the point the timeline reaches once the client is done mutating the texture pub acquire_point: u64, - ///the point the timeline reaches once the server is done with the dmatex and the client can access it again + ///the point the timeline reaches once the server is done with the dmatex and the client can access it again pub release_point: u64, } /// @@ -1847,7 +1848,7 @@ pub mod drawable { ); Ok(()) } - ///get the id of the primary device used for rendering, will return a render node id if possilbe + ///get the id of the primary device used for rendering, will return a render node id if possible pub async fn get_primary_render_device_id( _client: &std::sync::Arc, ) -> crate::node::NodeResult { @@ -1881,7 +1882,7 @@ pub mod drawable { pub async fn enumerate_dmatex_formats( _client: &std::sync::Arc, device_id: DrmNodeId, - ) -> crate::node::NodeResult { + ) -> crate::node::NodeResult> { let mut _fds = Vec::new(); let data = (device_id); { @@ -1900,8 +1901,13 @@ pub mod drawable { e, })? .into_message(); - let result: DmatexFormatInfo = stardust_xr_wire::flex::deserialize(&message)?; - let deserialized = result; + let result: Vec = stardust_xr_wire::flex::deserialize( + &message, + )?; + let deserialized = result + .into_iter() + .map(|a| Ok(a)) + .collect::, crate::node::NodeError>>()?; tracing::trace!( "return" = ? deserialized, "Method return from server, {}::{}", "Interface", "enumerate_dmatex_formats" diff --git a/protocol/idl/drawable.kdl b/protocol/idl/drawable.kdl index 2cc0b0f..fec6d0e 100644 --- a/protocol/idl/drawable.kdl +++ b/protocol/idl/drawable.kdl @@ -24,7 +24,7 @@ signal "unregister_dmatex" side="server" { } method "get_primary_render_device_id" side="server" { - description "get the id of the primary device used for rendering, will return a render node id if possilbe" + description "get the id of the primary device used for rendering, will return a render node id if possible" return type="union" union="DrmNodeId" } @@ -34,7 +34,7 @@ method "enumerate_dmatex_formats" side="server" { argument "device_id" type="union" union="DrmNodeId" - return type="struct" struct="DmatexFormatInfo" + return type="vec" member_type="struct" struct="DmatexFormatInfo" } struct "DmatexFormatInfo" { @@ -117,7 +117,7 @@ struct "DmatexMaterialParam" { description "Dmatex Material Parameter info" field "dmatex_id" type="id" description="The Id of the Dmatex to be applied as the texture" field "acquire_point" type="id" description="the point the timeline reaches once the client is done mutating the texture" - field "release_point" type="id" description="the point the timeline reaches once the server is done with the dmatex and the client can access it again" + field "release_point" type="id" description="the point the timeline reaches once the server is done with the dmatex and the client can access it again" } union "MaterialParameter" { @@ -131,7 +131,7 @@ union "MaterialParameter" { option type="vec3" option type="color" option type="resource" name="texture" - option type="struct" struct="DmatexMaterialParam" name="dmatex" + option type="struct" struct="DmatexMaterialParam" name="dmatex" description="only accepts 2d Dmatexs without array layers" } signal "load_model" side="server" { description "Load a GLTF model into a Model node" From b7536938f0f38826a11e262b225ad4e94d0a34b2 Mon Sep 17 00:00:00 2001 From: Schmarni Date: Fri, 19 Dec 2025 23:31:29 +0100 Subject: [PATCH 05/16] feat(drawable/dmatex): add exporting and importing interfaces Signed-off-by: Schmarni --- fusion/src/protocol.rs | 70 ++++++++++++++++++++++++++++++++++++--- protocol/idl/drawable.kdl | 22 +++++++++--- 2 files changed, 84 insertions(+), 8 deletions(-) diff --git a/fusion/src/protocol.rs b/fusion/src/protocol.rs index 4d6426f..ec00948 100644 --- a/fusion/src/protocol.rs +++ b/fusion/src/protocol.rs @@ -1396,7 +1396,7 @@ pub mod drawable { ///Dmatex Material Parameter info #[derive(Debug, Clone, PartialEq, serde::Deserialize, serde::Serialize)] pub struct DmatexMaterialParam { - ///The Id of the Dmatex to be applied as the texture + ///The id of the Dmatex to be applied as the texture pub dmatex_id: u64, ///the point the timeline reaches once the client is done mutating the texture pub acquire_point: u64, @@ -1770,7 +1770,7 @@ pub mod drawable { Ok(()) } } - ///Import a Dmatex, the imported Dmatex has to be manually unregistered + ///Import a Dmatex, the imported Dmatex has to be manually unregistered, the returned id is Client Local pub async fn import_dmatex( _client: &std::sync::Arc, size: DmatexPlane, @@ -1830,7 +1830,69 @@ pub mod drawable { ); Ok(deserialized) } - ///Mark a Dmatex as unused, this allows the server to destroy its imported representations, this invalidates the Dmatex id + ///Exports a Dmatex Uid for sharing between clients + pub async fn export_dmatex_uid( + _client: &std::sync::Arc, + dmatex_id: u64, + ) -> crate::node::NodeResult { + let mut _fds = Vec::new(); + let data = (dmatex_id); + { + let (dmatex_id) = &data; + tracing::trace!( + ? dmatex_id, "Called method on server, {}::{}", "Interface", + "export_dmatex_uid" + ); + } + let serialized_data = stardust_xr_wire::flex::serialize(&data)?; + let message = _client + .message_sender_handle + .method(4u64, 0u64, 2247267269053194767u64, &serialized_data, _fds) + .await? + .map_err(|e| crate::node::NodeError::ReturnedError { + e, + })? + .into_message(); + let result: u64 = stardust_xr_wire::flex::deserialize(&message)?; + let deserialized = result; + tracing::trace!( + "return" = ? deserialized, "Method return from server, {}::{}", "Interface", + "export_dmatex_uid" + ); + Ok(deserialized) + } + ///Imports a shared Dmatex Uid, holding this id will keep the underlying dmatex alive + pub async fn import_dmatex_uid( + _client: &std::sync::Arc, + dmatex_uid: u64, + ) -> crate::node::NodeResult { + let mut _fds = Vec::new(); + let data = (dmatex_uid); + { + let (dmatex_uid) = &data; + tracing::trace!( + ? dmatex_uid, "Called method on server, {}::{}", "Interface", + "import_dmatex_uid" + ); + } + let serialized_data = stardust_xr_wire::flex::serialize(&data)?; + let message = _client + .message_sender_handle + .method(4u64, 0u64, 5604115908701744320u64, &serialized_data, _fds) + .await? + .map_err(|e| crate::node::NodeError::ReturnedError { + e, + })? + .into_message(); + let result: u64 = stardust_xr_wire::flex::deserialize(&message)?; + let deserialized = result; + tracing::trace!( + "return" = ? deserialized, "Method return from server, {}::{}", "Interface", + "import_dmatex_uid" + ); + Ok(deserialized) + } + ///Mark a Dmatex as unused, once all ids referencing the same Dmatex are unregisterd the server may destroy its internal representation of the Dmatex, this invalidates the used handle pub fn unregister_dmatex( _client: &std::sync::Arc, dmatex_id: u64, @@ -1848,7 +1910,7 @@ pub mod drawable { ); Ok(()) } - ///get the id of the primary device used for rendering, will return a render node id if possible + ///get the id of the primary device used for rendering, will return a render node id if supported by the driver pub async fn get_primary_render_device_id( _client: &std::sync::Arc, ) -> crate::node::NodeResult { diff --git a/protocol/idl/drawable.kdl b/protocol/idl/drawable.kdl index fec6d0e..0c0d83e 100644 --- a/protocol/idl/drawable.kdl +++ b/protocol/idl/drawable.kdl @@ -4,7 +4,7 @@ description "" method "import_dmatex" side="server" { - description "Import a Dmatex, the imported Dmatex has to be manually unregistered" + description "Import a Dmatex, the imported Dmatex has to be manually unregistered, the returned id is Client Local" argument "size" type="union" union="DmatexPlane" argument "format" type="uint" description="the texture format as a drm_fourcc" @@ -17,14 +17,28 @@ method "import_dmatex" side="server" { return type="id" } +method "export_dmatex_uid" side="server" { + description "Exports a Dmatex Uid for sharing between clients" + argument "dmatex_id" type="id" + + return type="id" +} + +method "import_dmatex_uid" side="server" { + description "Imports a shared Dmatex Uid, holding this id will keep the underlying dmatex alive" + argument "dmatex_uid" type="id" + + return type="id" +} + signal "unregister_dmatex" side="server" { - description "Mark a Dmatex as unused, this allows the server to destroy its imported representations, this invalidates the Dmatex id" + description "Mark a Dmatex as unused, once all ids referencing the same Dmatex are unregisterd the server may destroy its internal representation of the Dmatex, this invalidates the used handle" argument "dmatex_id" type="id" } method "get_primary_render_device_id" side="server" { - description "get the id of the primary device used for rendering, will return a render node id if possible" + description "get the id of the primary device used for rendering, will return a render node id if supported by the driver" return type="union" union="DrmNodeId" } @@ -115,7 +129,7 @@ aspect "Lines" { struct "DmatexMaterialParam" { description "Dmatex Material Parameter info" - field "dmatex_id" type="id" description="The Id of the Dmatex to be applied as the texture" + field "dmatex_id" type="id" description="The id of the Dmatex to be applied as the texture" field "acquire_point" type="id" description="the point the timeline reaches once the client is done mutating the texture" field "release_point" type="id" description="the point the timeline reaches once the server is done with the dmatex and the client can access it again" } From 657d35a320d67c13497aa9c43022e050f1ef453a Mon Sep 17 00:00:00 2001 From: Schmarni Date: Thu, 25 Dec 2025 05:49:24 +0100 Subject: [PATCH 06/16] refactor: do fd serialization through serde with thread_local sidechannel Signed-off-by: Schmarni --- fusion/build.rs | 31 +- fusion/src/lib.rs | 15 +- fusion/src/node.rs | 11 +- fusion/src/protocol.rs | 688 ++++++++++++----------------------------- wire/src/flex/mod.rs | 37 ++- wire/src/lib.rs | 1 + 6 files changed, 239 insertions(+), 544 deletions(-) diff --git a/fusion/build.rs b/fusion/build.rs index 557b5e1..1e1ae1b 100644 --- a/fusion/build.rs +++ b/fusion/build.rs @@ -639,7 +639,7 @@ fn generate_event_sender_impl(aspect: &Aspect) -> TokenStream { member._type, quote! { #opcode => { - let (#(#field_names),*): (#(#deserialize_types),*) = stardust_xr_wire::flex::deserialize(_data)?; + let (#(#field_names),*): (#(#deserialize_types),*) = stardust_xr_wire::flex::deserialize(_data, _fds)?; #debug Ok(#event_name::#variant_name { #(#field_uses,)* #response_sender }) @@ -728,19 +728,17 @@ fn generate_server_member( MemberType::Signal => { let mut body = if let Some(interface_node_id) = &interface_node_id { quote! { - let mut _fds = Vec::new(); let data = (#(#argument_uses),*); - let serialized_data = stardust_xr_wire::flex::serialize(&data)?; - _client.message_sender_handle.signal(#interface_node_id, #aspect_id, #opcode, &serialized_data, _fds)?; + let (serialized_data, fds) = stardust_xr_wire::flex::serialize(&data)?; + _client.message_sender_handle.signal(#interface_node_id, #aspect_id, #opcode, &serialized_data, fds)?; let (#(#arguments),*) = data; tracing::trace!(#arguments_debug "Sent signal to server, {}::{}", #aspect_name, #name_str); } } else { quote! { - let mut _fds = Vec::new(); let data = (#(#argument_uses),*); - self.node().send_signal(#aspect_id, #opcode, &data, _fds)?; + self.node().send_signal(#aspect_id, #opcode, &data)?; let (#(#arguments),*) = data; tracing::trace!(#arguments_debug "Sent signal to server, {}::{}", #aspect_name, #name_str); @@ -791,28 +789,26 @@ fn generate_server_member( let deserialize = generate_argument_deserialize("result", &argument_type, false); let body = if let Some(interface_node_id) = &interface_node_id { quote! { - let mut _fds = Vec::new(); let data = (#(#argument_uses),*); { let (#(#arguments),*) = &data; tracing::trace!(#arguments_debug "Called method on server, {}::{}", #aspect_name, #name_str); } - let serialized_data = stardust_xr_wire::flex::serialize(&data)?; - let message = _client.message_sender_handle.method(#interface_node_id, #aspect_id, #opcode, &serialized_data, _fds).await?.map_err(|e| crate::node::NodeError::ReturnedError { e })?.into_message(); - let result: #deserializeable_type = stardust_xr_wire::flex::deserialize(&message)?; + let (serialized_data, fds) = stardust_xr_wire::flex::serialize(&data)?; + let (message, message_fds) = _client.message_sender_handle.method(#interface_node_id, #aspect_id, #opcode, &serialized_data, fds).await?.map_err(|e| crate::node::NodeError::ReturnedError { e })?.into_components(); + let result: #deserializeable_type = stardust_xr_wire::flex::deserialize(&message, message_fds)?; let deserialized = #deserialize; tracing::trace!("return" = ?deserialized, "Method return from server, {}::{}", #aspect_name, #name_str); Ok(deserialized) } } else { quote! {{ - let mut _fds = Vec::new(); let data = (#(#argument_uses),*); { let (#(#arguments),*) = &data; tracing::trace!(#arguments_debug "Called method on server, {}::{}", #aspect_name, #name_str); } - let result: #deserializeable_type = self.node().call_method(#aspect_id, #opcode, &data, _fds).await?; + let result: #deserializeable_type = self.node().call_method(#aspect_id, #opcode, &data).await?; let deserialized = #deserialize; tracing::trace!("return" = ?deserialized, "Method return from server, {}::{}", #aspect_name, #name_str); Ok(deserialized) @@ -865,9 +861,6 @@ fn generate_argument_deserialize( let mapping = generate_argument_deserialize("a", v, false); quote!(#name.into_iter().map(|(k, a)| Ok((k, #mapping))).collect::, crate::node::NodeError>>()?) } - ArgumentType::Fd => { - quote!(_fds.remove(0)) - } _ => quote!(#name), } } @@ -924,12 +917,6 @@ fn generate_argument_serialize( let mapping = generate_argument_serialize("a", v, false); quote!(#name.iter().map(|(k, a)| Ok((k, #mapping))).collect::>>()?) } - ArgumentType::Fd => { - quote!({ - _fds.push(#name); - (_fds.len() - 1) as u32 - }) - } _ => quote!(#name), } } @@ -1066,7 +1053,7 @@ fn generate_argument_type(argument_type: &ArgumentType, owned: bool) -> TokenStr } } ArgumentType::Fd => { - quote!(std::os::unix::io::OwnedFd) + quote!(stardust_xr_wire::fd::ProtocolFd) } } } diff --git a/fusion/src/lib.rs b/fusion/src/lib.rs index 0f287ea..805fa50 100644 --- a/fusion/src/lib.rs +++ b/fusion/src/lib.rs @@ -5,7 +5,7 @@ use serde::Serialize; use stardust_xr_wire::{flex::serialize, messenger::MethodResponse, scenegraph::ScenegraphError}; -use std::{error::Error, fmt::Debug, marker::PhantomData, os::fd::OwnedFd}; +use std::{error::Error, fmt::Debug, marker::PhantomData}; pub use client::*; pub use stardust_xr_gluon::*; @@ -44,23 +44,20 @@ impl TypedMethodResponse { return; } }; - let Ok(serialized) = stardust_xr_wire::flex::serialize(data) else { + let Ok((serialized, fds)) = stardust_xr_wire::flex::serialize(data) else { self.0.send(Err(ScenegraphError::MemberError { error: "Internal: Failed to serialize".to_string(), })); return; }; - self.0.send(Ok((&serialized, Vec::::new()))); + self.0.send(Ok((&serialized, fds))); } pub fn wrap Result>(self, f: F) { self.send(f()) } - pub fn wrap_async( - self, - f: impl Future), E>> + Send + 'static, - ) { + pub fn wrap_async(self, f: impl Future> + Send + 'static) { tokio::task::spawn(async move { - let (value, fds) = match f.await { + let value = match f.await { Ok(d) => d, Err(e) => { self.0.send(Err(ScenegraphError::MemberError { @@ -69,7 +66,7 @@ impl TypedMethodResponse { return; } }; - let Ok(serialized) = serialize(value) else { + let Ok((serialized, fds)) = serialize(value) else { self.0.send(Err(ScenegraphError::MemberError { error: "Internal: Failed to serialize".to_string(), })); diff --git a/fusion/src/node.rs b/fusion/src/node.rs index 623a429..2833b1c 100644 --- a/fusion/src/node.rs +++ b/fusion/src/node.rs @@ -7,7 +7,7 @@ use stardust_xr_wire::{ messenger::MessengerError, scenegraph::ScenegraphError, }; -use std::{fmt::Debug, os::fd::OwnedFd, sync::Arc, vec::Vec}; +use std::{fmt::Debug, sync::Arc}; use thiserror::Error; pub use crate::protocol::node::*; @@ -106,9 +106,8 @@ impl NodeCore { aspect: u64, signal: u64, data: &S, - fds: Vec, ) -> Result<(), NodeError> { - let serialized = serialize(data).map_err(|e| NodeError::Serialization { e })?; + let (serialized, fds) = serialize(data).map_err(|e| NodeError::Serialization { e })?; self.client .message_sender_handle .signal(self.id, aspect, signal, &serialized, fds) @@ -124,9 +123,8 @@ impl NodeCore { aspect: u64, method: u64, data: &S, - fds: Vec, ) -> Result { - let serialized = serialize(data).map_err(|e| NodeError::Serialization { e })?; + let (serialized, fds) = serialize(data).map_err(|e| NodeError::Serialization { e })?; let response = self .client @@ -139,7 +137,8 @@ impl NodeCore { })? .map_err(|e| NodeError::ReturnedError { e })?; - deserialize(&response.into_message()).map_err(|e| NodeError::Deserialization { e }) + let (response, fds) = response.into_components(); + deserialize(&response, fds).map_err(|e| NodeError::Deserialization { e }) } } impl NodeType for NodeCore { diff --git a/fusion/src/protocol.rs b/fusion/src/protocol.rs index ec00948..d910cdc 100644 --- a/fusion/src/protocol.rs +++ b/fusion/src/protocol.rs @@ -107,6 +107,7 @@ pub mod root { 2586777469268117179u64 => { let (info): (FrameInfo) = stardust_xr_wire::flex::deserialize( _data, + _fds, )?; tracing::trace!( ? info, "Got signal from server, {}::{}", "Root", "frame" @@ -125,7 +126,7 @@ pub mod root { ) -> Result { match method_id { 1374738518356883234u64 => { - let (): () = stardust_xr_wire::flex::deserialize(_data)?; + let (): () = stardust_xr_wire::flex::deserialize(_data, _fds)?; tracing::trace!("Method called from server, {}::{}", "Root", "ping"); Ok(RootEvent::Ping { response: crate::TypedMethodResponse( @@ -135,7 +136,7 @@ pub mod root { }) } 6559167809188075643u64 => { - let (): () = stardust_xr_wire::flex::deserialize(_data)?; + let (): () = stardust_xr_wire::flex::deserialize(_data, _fds)?; tracing::trace!( "Method called from server, {}::{}", "Root", "save_state" ); @@ -164,7 +165,6 @@ pub mod root { ///Get the current state. Useful to check the state before you initialize your application! async fn get_state(&self) -> crate::node::NodeResult { { - let mut _fds = Vec::new(); let data = (); { let () = &data; @@ -174,12 +174,7 @@ pub mod root { } let result: ClientState = self .node() - .call_method( - 7212020743076450030u64, - 14958324855167218950u64, - &data, - _fds, - ) + .call_method(7212020743076450030u64, 14958324855167218950u64, &data) .await?; let deserialized = result; tracing::trace!( @@ -200,7 +195,6 @@ pub mod root { state: ClientState, ) -> crate::node::NodeResult { { - let mut _fds = Vec::new(); let data = (state); { let (state) = &data; @@ -211,12 +205,7 @@ pub mod root { } let result: String = self .node() - .call_method( - 7212020743076450030u64, - 530863980839400599u64, - &data, - _fds, - ) + .call_method(7212020743076450030u64, 530863980839400599u64, &data) .await?; let deserialized = result; tracing::trace!( @@ -231,7 +220,6 @@ pub mod root { &self, ) -> crate::node::NodeResult> { { - let mut _fds = Vec::new(); let data = (); { let () = &data; @@ -242,12 +230,7 @@ pub mod root { } let result: stardust_xr_wire::values::Map = self .node() - .call_method( - 7212020743076450030u64, - 3344613215577382567u64, - &data, - _fds, - ) + .call_method(7212020743076450030u64, 3344613215577382567u64, &data) .await?; let deserialized = result .into_iter() @@ -267,18 +250,12 @@ pub mod root { } ///Set initial list of folders to look for namespaced resources in fn set_base_prefixes(&self, prefixes: &[String]) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (prefixes .iter() .map(|a| Ok(a)) .collect::>>()?); self.node() - .send_signal( - 7212020743076450030u64, - 3714507829296596139u64, - &data, - _fds, - )?; + .send_signal(7212020743076450030u64, 3714507829296596139u64, &data)?; let (prefixes) = data; tracing::trace!( ? prefixes, "Sent signal to server, {}::{}", "Root", "set_base_prefixes" @@ -287,15 +264,9 @@ pub mod root { } ///Cleanly disconnect from the server fn disconnect(&self) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (); self.node() - .send_signal( - 7212020743076450030u64, - 662137628972844924u64, - &data, - _fds, - )?; + .send_signal(7212020743076450030u64, 662137628972844924u64, &data)?; let () = data; tracing::trace!("Sent signal to server, {}::{}", "Root", "disconnect"); Ok(()) @@ -314,15 +285,9 @@ pub mod node { pub trait OwnedAspect: crate::node::NodeType + std::fmt::Debug { ///Set if this node is enabled or not. Disabled drawables won't render, input handlers won't receive input, etc. fn set_enabled(&self, enabled: bool) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (enabled); self.node() - .send_signal( - 15801764205032075891u64, - 13365497663235993822u64, - &data, - _fds, - )?; + .send_signal(15801764205032075891u64, 13365497663235993822u64, &data)?; let (enabled) = data; tracing::trace!( ? enabled, "Sent signal to server, {}::{}", "Owned", "set_enabled" @@ -331,15 +296,9 @@ pub mod node { } ///Destroy this node immediately. Not all nodes will have this method, those that don't can be dropped client-side without issue. fn destroy(&self) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (); self.node() - .send_signal( - 15801764205032075891u64, - 8637450960623370830u64, - &data, - _fds, - )?; + .send_signal(15801764205032075891u64, 8637450960623370830u64, &data)?; let () = data; tracing::trace!("Sent signal to server, {}::{}", "Owned", "destroy"); Ok(()) @@ -423,7 +382,6 @@ pub mod spatial { ///Get the bounding box of this spatial and its children relative to another spatial async fn get_local_bounding_box(&self) -> crate::node::NodeResult { { - let mut _fds = Vec::new(); let data = (); { let () = &data; @@ -434,12 +392,7 @@ pub mod spatial { } let result: BoundingBox = self .node() - .call_method( - 14774096707642646617u64, - 15184457389419466387u64, - &data, - _fds, - ) + .call_method(14774096707642646617u64, 15184457389419466387u64, &data) .await?; let deserialized = result; tracing::trace!( @@ -455,7 +408,6 @@ pub mod spatial { relative_to: &impl SpatialRefAspect, ) -> crate::node::NodeResult { { - let mut _fds = Vec::new(); let data = (relative_to.node().id); { let (relative_to) = &data; @@ -466,12 +418,7 @@ pub mod spatial { } let result: BoundingBox = self .node() - .call_method( - 14774096707642646617u64, - 8077745023404307052u64, - &data, - _fds, - ) + .call_method(14774096707642646617u64, 8077745023404307052u64, &data) .await?; let deserialized = result; tracing::trace!( @@ -487,7 +434,6 @@ pub mod spatial { relative_to: &impl SpatialRefAspect, ) -> crate::node::NodeResult { { - let mut _fds = Vec::new(); let data = (relative_to.node().id); { let (relative_to) = &data; @@ -498,12 +444,7 @@ pub mod spatial { } let result: Transform = self .node() - .call_method( - 14774096707642646617u64, - 6982810219028106561u64, - &data, - _fds, - ) + .call_method(14774096707642646617u64, 6982810219028106561u64, &data) .await?; let deserialized = result; tracing::trace!( @@ -580,15 +521,9 @@ pub mod spatial { &self, transform: Transform, ) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (transform); self.node() - .send_signal( - 17785849468685298036u64, - 5092462149256736585u64, - &data, - _fds, - )?; + .send_signal(17785849468685298036u64, 5092462149256736585u64, &data)?; let (transform) = data; tracing::trace!( ? transform, "Sent signal to server, {}::{}", "Spatial", @@ -602,15 +537,9 @@ pub mod spatial { relative_to: &impl SpatialRefAspect, transform: Transform, ) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (relative_to.node().id, transform); self.node() - .send_signal( - 17785849468685298036u64, - 15020422542376308840u64, - &data, - _fds, - )?; + .send_signal(17785849468685298036u64, 15020422542376308840u64, &data)?; let (relative_to, transform) = data; tracing::trace!( ? relative_to, ? transform, "Sent signal to server, {}::{}", "Spatial", @@ -626,15 +555,9 @@ pub mod spatial { &self, parent: &impl SpatialRefAspect, ) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (parent.node().id); self.node() - .send_signal( - 17785849468685298036u64, - 12472379656662040034u64, - &data, - _fds, - )?; + .send_signal(17785849468685298036u64, 12472379656662040034u64, &data)?; let (parent) = data; tracing::trace!( ? parent, "Sent signal to server, {}::{}", "Spatial", @@ -650,15 +573,9 @@ pub mod spatial { &self, parent: &impl SpatialRefAspect, ) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (parent.node().id); self.node() - .send_signal( - 17785849468685298036u64, - 1386737540675144626u64, - &data, - _fds, - )?; + .send_signal(17785849468685298036u64, 1386737540675144626u64, &data)?; let (parent) = data; tracing::trace!( ? parent, "Sent signal to server, {}::{}", "Spatial", @@ -669,7 +586,6 @@ pub mod spatial { ///Return a UUID representing this node's SpatialRef that you can send to other clients async fn export_spatial(&self) -> crate::node::NodeResult { { - let mut _fds = Vec::new(); let data = (); { let () = &data; @@ -679,12 +595,7 @@ pub mod spatial { } let result: u64 = self .node() - .call_method( - 17785849468685298036u64, - 3600225297814947977u64, - &data, - _fds, - ) + .call_method(17785849468685298036u64, 3600225297814947977u64, &data) .await?; let deserialized = result; tracing::trace!( @@ -700,7 +611,6 @@ pub mod spatial { _client: &std::sync::Arc, uid: u64, ) -> crate::node::NodeResult { - let mut _fds = Vec::new(); let data = (uid); { let (uid) = &data; @@ -709,16 +619,16 @@ pub mod spatial { "import_spatial_ref" ); } - let serialized_data = stardust_xr_wire::flex::serialize(&data)?; - let message = _client + let (serialized_data, fds) = stardust_xr_wire::flex::serialize(&data)?; + let (message, message_fds) = _client .message_sender_handle - .method(1u64, 0u64, 7309812661610962094u64, &serialized_data, _fds) + .method(1u64, 0u64, 7309812661610962094u64, &serialized_data, fds) .await? .map_err(|e| crate::node::NodeError::ReturnedError { e, })? - .into_message(); - let result: u64 = stardust_xr_wire::flex::deserialize(&message)?; + .into_components(); + let result: u64 = stardust_xr_wire::flex::deserialize(&message, message_fds)?; let deserialized = SpatialRef::from_id(_client, result, false); tracing::trace!( "return" = ? deserialized, "Method return from server, {}::{}", "Interface", @@ -734,12 +644,11 @@ pub mod spatial { transform: Transform, ) -> crate::node::NodeResult { { - let mut _fds = Vec::new(); let data = (id, parent.node().id, transform); - let serialized_data = stardust_xr_wire::flex::serialize(&data)?; + let (serialized_data, fds) = stardust_xr_wire::flex::serialize(&data)?; _client .message_sender_handle - .signal(1u64, 0u64, 3949276749019911643u64, &serialized_data, _fds)?; + .signal(1u64, 0u64, 3949276749019911643u64, &serialized_data, fds)?; let (id, parent, transform) = data; tracing::trace!( ? id, ? parent, ? transform, "Sent signal to server, {}::{}", @@ -860,7 +769,6 @@ pub mod field { point: impl Into>, ) -> crate::node::NodeResult { { - let mut _fds = Vec::new(); let data = (space.node().id, point.into()); { let (space, point) = &data; @@ -871,12 +779,7 @@ pub mod field { } let result: f32 = self .node() - .call_method( - 10662923473076663509u64, - 12706699825100237095u64, - &data, - _fds, - ) + .call_method(10662923473076663509u64, 12706699825100237095u64, &data) .await?; let deserialized = result; tracing::trace!( @@ -893,7 +796,6 @@ pub mod field { point: impl Into>, ) -> crate::node::NodeResult> { { - let mut _fds = Vec::new(); let data = (space.node().id, point.into()); { let (space, point) = &data; @@ -904,12 +806,7 @@ pub mod field { } let result: stardust_xr_wire::values::Vector3 = self .node() - .call_method( - 10662923473076663509u64, - 10933809934326220183u64, - &data, - _fds, - ) + .call_method(10662923473076663509u64, 10933809934326220183u64, &data) .await?; let deserialized = result; tracing::trace!( @@ -926,7 +823,6 @@ pub mod field { point: impl Into>, ) -> crate::node::NodeResult> { { - let mut _fds = Vec::new(); let data = (space.node().id, point.into()); { let (space, point) = &data; @@ -937,12 +833,7 @@ pub mod field { } let result: stardust_xr_wire::values::Vector3 = self .node() - .call_method( - 10662923473076663509u64, - 13473947755141124846u64, - &data, - _fds, - ) + .call_method(10662923473076663509u64, 13473947755141124846u64, &data) .await?; let deserialized = result; tracing::trace!( @@ -960,7 +851,6 @@ pub mod field { ray_direction: impl Into>, ) -> crate::node::NodeResult { { - let mut _fds = Vec::new(); let data = (space.node().id, ray_origin.into(), ray_direction.into()); { let (space, ray_origin, ray_direction) = &data; @@ -971,12 +861,7 @@ pub mod field { } let result: RayMarchResult = self .node() - .call_method( - 10662923473076663509u64, - 7352457860499612292u64, - &data, - _fds, - ) + .call_method(10662923473076663509u64, 7352457860499612292u64, &data) .await?; let deserialized = result; tracing::trace!( @@ -1050,15 +935,9 @@ pub mod field { pub trait FieldAspect: crate::node::NodeType + super::FieldRefAspect + super::SpatialRefAspect + super::SpatialAspect + super::OwnedAspect + std::fmt::Debug { ///Set the shape of this field (and its parameters) fn set_shape(&self, shape: Shape) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (shape); self.node() - .send_signal( - 3948434400034960392u64, - 10076774457453995458u64, - &data, - _fds, - )?; + .send_signal(3948434400034960392u64, 10076774457453995458u64, &data)?; let (shape) = data; tracing::trace!( ? shape, "Sent signal to server, {}::{}", "Field", "set_shape" @@ -1068,7 +947,6 @@ pub mod field { ///Return a UUID representing this node's FieldRef that you can send to other clients async fn export_field(&self) -> crate::node::NodeResult { { - let mut _fds = Vec::new(); let data = (); { let () = &data; @@ -1078,12 +956,7 @@ pub mod field { } let result: u64 = self .node() - .call_method( - 3948434400034960392u64, - 939650650519133349u64, - &data, - _fds, - ) + .call_method(3948434400034960392u64, 939650650519133349u64, &data) .await?; let deserialized = result; tracing::trace!( @@ -1099,7 +972,6 @@ pub mod field { _client: &std::sync::Arc, uid: u64, ) -> crate::node::NodeResult { - let mut _fds = Vec::new(); let data = (uid); { let (uid) = &data; @@ -1107,16 +979,16 @@ pub mod field { ? uid, "Called method on server, {}::{}", "Interface", "import_field_ref" ); } - let serialized_data = stardust_xr_wire::flex::serialize(&data)?; - let message = _client + let (serialized_data, fds) = stardust_xr_wire::flex::serialize(&data)?; + let (message, message_fds) = _client .message_sender_handle - .method(2u64, 0u64, 5844955584634021418u64, &serialized_data, _fds) + .method(2u64, 0u64, 5844955584634021418u64, &serialized_data, fds) .await? .map_err(|e| crate::node::NodeError::ReturnedError { e, })? - .into_message(); - let result: u64 = stardust_xr_wire::flex::deserialize(&message)?; + .into_components(); + let result: u64 = stardust_xr_wire::flex::deserialize(&message, message_fds)?; let deserialized = FieldRef::from_id(_client, result, false); tracing::trace!( "return" = ? deserialized, "Method return from server, {}::{}", "Interface", @@ -1133,12 +1005,11 @@ pub mod field { shape: Shape, ) -> crate::node::NodeResult { { - let mut _fds = Vec::new(); let data = (id, parent.node().id, transform, shape); - let serialized_data = stardust_xr_wire::flex::serialize(&data)?; + let (serialized_data, fds) = stardust_xr_wire::flex::serialize(&data)?; _client .message_sender_handle - .signal(2u64, 0u64, 3216373392735127623u64, &serialized_data, _fds)?; + .signal(2u64, 0u64, 3216373392735127623u64, &serialized_data, fds)?; let (id, parent, transform, shape) = data; tracing::trace!( ? id, ? parent, ? transform, ? shape, "Sent signal to server, {}::{}", @@ -1214,30 +1085,18 @@ pub mod audio { pub trait SoundAspect: crate::node::NodeType + super::SpatialAspect + super::OwnedAspect + super::SpatialRefAspect + std::fmt::Debug { ///Play sound effect fn play(&self) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (); self.node() - .send_signal( - 17761155925539609649u64, - 18267594382511242772u64, - &data, - _fds, - )?; + .send_signal(17761155925539609649u64, 18267594382511242772u64, &data)?; let () = data; tracing::trace!("Sent signal to server, {}::{}", "Sound", "play"); Ok(()) } ///Stop sound effect fn stop(&self) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (); self.node() - .send_signal( - 17761155925539609649u64, - 4968801543080236686u64, - &data, - _fds, - )?; + .send_signal(17761155925539609649u64, 4968801543080236686u64, &data)?; let () = data; tracing::trace!("Sent signal to server, {}::{}", "Sound", "stop"); Ok(()) @@ -1252,12 +1111,11 @@ pub mod audio { resource: &stardust_xr_wire::values::ResourceID, ) -> crate::node::NodeResult { { - let mut _fds = Vec::new(); let data = (id, parent.node().id, transform, resource); - let serialized_data = stardust_xr_wire::flex::serialize(&data)?; + let (serialized_data, fds) = stardust_xr_wire::flex::serialize(&data)?; _client .message_sender_handle - .signal(10u64, 0u64, 3197851813257440734u64, &serialized_data, _fds)?; + .signal(10u64, 0u64, 3197851813257440734u64, &serialized_data, fds)?; let (id, parent, transform, resource) = data; tracing::trace!( ? id, ? parent, ? transform, ? resource, "Sent signal to server, {}::{}", @@ -1482,18 +1340,12 @@ pub mod drawable { pub trait LinesAspect: crate::node::NodeType + super::SpatialAspect + super::OwnedAspect + super::SpatialRefAspect + std::fmt::Debug { ///Replace all polylines with the given lines fn set_lines(&self, lines: &[Line]) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (lines .iter() .map(|a| Ok(a)) .collect::>>()?); self.node() - .send_signal( - 16705186951373789081u64, - 17689001183742889136u64, - &data, - _fds, - )?; + .send_signal(16705186951373789081u64, 17689001183742889136u64, &data)?; let (lines) = data; tracing::trace!( ? lines, "Sent signal to server, {}::{}", "Lines", "set_lines" @@ -1565,14 +1417,12 @@ pub mod drawable { part_path: &str, ) -> crate::node::NodeResult { { - let mut _fds = Vec::new(); let data = (id, part_path); self.node() .send_signal( 11775342128130118047u64, 18406803564448475833u64, &data, - _fds, )?; let (id, part_path) = data; tracing::trace!( @@ -1642,15 +1492,9 @@ pub mod drawable { pub trait ModelPartAspect: crate::node::NodeType + super::SpatialAspect + super::OwnedAspect + super::SpatialRefAspect + std::fmt::Debug { ///Set this model part's material to one that cuts a hole in the world. Often used for overlays/passthrough where you want to show the background through an object. fn apply_holdout_material(&self) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (); self.node() - .send_signal( - 7912164431074553740u64, - 13817793452575402942u64, - &data, - _fds, - )?; + .send_signal(7912164431074553740u64, 13817793452575402942u64, &data)?; let () = data; tracing::trace!( "Sent signal to server, {}::{}", "ModelPart", "apply_holdout_material" @@ -1663,15 +1507,9 @@ pub mod drawable { parameter_name: &str, value: MaterialParameter, ) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (parameter_name, value); self.node() - .send_signal( - 7912164431074553740u64, - 12609900228877593594u64, - &data, - _fds, - )?; + .send_signal(7912164431074553740u64, 12609900228877593594u64, &data)?; let (parameter_name, value) = data; tracing::trace!( ? parameter_name, ? value, "Sent signal to server, {}::{}", "ModelPart", @@ -1739,15 +1577,9 @@ pub mod drawable { pub trait TextAspect: crate::node::NodeType + super::SpatialAspect + super::OwnedAspect + super::SpatialRefAspect + std::fmt::Debug { ///Set the character height in meters fn set_character_height(&self, height: f32) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (height); self.node() - .send_signal( - 3129045917168168339u64, - 1124886941794143568u64, - &data, - _fds, - )?; + .send_signal(3129045917168168339u64, 1124886941794143568u64, &data)?; let (height) = data; tracing::trace!( ? height, "Sent signal to server, {}::{}", "Text", "set_character_height" @@ -1756,15 +1588,9 @@ pub mod drawable { } ///Set the text content fn set_text(&self, text: &str) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (text); self.node() - .send_signal( - 3129045917168168339u64, - 395974856293277940u64, - &data, - _fds, - )?; + .send_signal(3129045917168168339u64, 395974856293277940u64, &data)?; let (text) = data; tracing::trace!(? text, "Sent signal to server, {}::{}", "Text", "set_text"); Ok(()) @@ -1777,25 +1603,18 @@ pub mod drawable { format: u32, srgb: bool, array_layers: Option, - plane_1_dmabuf_fd: std::os::unix::io::OwnedFd, + plane_1_dmabuf_fd: stardust_xr_wire::fd::ProtocolFd, plane_1_info: DmatexPlane, - timeline_syncobj_fd: std::os::unix::io::OwnedFd, + timeline_syncobj_fd: stardust_xr_wire::fd::ProtocolFd, ) -> crate::node::NodeResult { - let mut _fds = Vec::new(); let data = ( size, format, srgb, array_layers.map(|o| Ok::<_, crate::node::NodeError>(o)).transpose()?, - { - _fds.push(plane_1_dmabuf_fd); - (_fds.len() - 1) as u32 - }, + plane_1_dmabuf_fd, plane_1_info, - { - _fds.push(timeline_syncobj_fd); - (_fds.len() - 1) as u32 - }, + timeline_syncobj_fd, ); { let ( @@ -1813,16 +1632,16 @@ pub mod drawable { "Interface", "import_dmatex" ); } - let serialized_data = stardust_xr_wire::flex::serialize(&data)?; - let message = _client + let (serialized_data, fds) = stardust_xr_wire::flex::serialize(&data)?; + let (message, message_fds) = _client .message_sender_handle - .method(4u64, 0u64, 5202664904415071827u64, &serialized_data, _fds) + .method(4u64, 0u64, 5202664904415071827u64, &serialized_data, fds) .await? .map_err(|e| crate::node::NodeError::ReturnedError { e, })? - .into_message(); - let result: u64 = stardust_xr_wire::flex::deserialize(&message)?; + .into_components(); + let result: u64 = stardust_xr_wire::flex::deserialize(&message, message_fds)?; let deserialized = result; tracing::trace!( "return" = ? deserialized, "Method return from server, {}::{}", "Interface", @@ -1835,7 +1654,6 @@ pub mod drawable { _client: &std::sync::Arc, dmatex_id: u64, ) -> crate::node::NodeResult { - let mut _fds = Vec::new(); let data = (dmatex_id); { let (dmatex_id) = &data; @@ -1844,16 +1662,16 @@ pub mod drawable { "export_dmatex_uid" ); } - let serialized_data = stardust_xr_wire::flex::serialize(&data)?; - let message = _client + let (serialized_data, fds) = stardust_xr_wire::flex::serialize(&data)?; + let (message, message_fds) = _client .message_sender_handle - .method(4u64, 0u64, 2247267269053194767u64, &serialized_data, _fds) + .method(4u64, 0u64, 2247267269053194767u64, &serialized_data, fds) .await? .map_err(|e| crate::node::NodeError::ReturnedError { e, })? - .into_message(); - let result: u64 = stardust_xr_wire::flex::deserialize(&message)?; + .into_components(); + let result: u64 = stardust_xr_wire::flex::deserialize(&message, message_fds)?; let deserialized = result; tracing::trace!( "return" = ? deserialized, "Method return from server, {}::{}", "Interface", @@ -1866,7 +1684,6 @@ pub mod drawable { _client: &std::sync::Arc, dmatex_uid: u64, ) -> crate::node::NodeResult { - let mut _fds = Vec::new(); let data = (dmatex_uid); { let (dmatex_uid) = &data; @@ -1875,16 +1692,16 @@ pub mod drawable { "import_dmatex_uid" ); } - let serialized_data = stardust_xr_wire::flex::serialize(&data)?; - let message = _client + let (serialized_data, fds) = stardust_xr_wire::flex::serialize(&data)?; + let (message, message_fds) = _client .message_sender_handle - .method(4u64, 0u64, 5604115908701744320u64, &serialized_data, _fds) + .method(4u64, 0u64, 5604115908701744320u64, &serialized_data, fds) .await? .map_err(|e| crate::node::NodeError::ReturnedError { e, })? - .into_message(); - let result: u64 = stardust_xr_wire::flex::deserialize(&message)?; + .into_components(); + let result: u64 = stardust_xr_wire::flex::deserialize(&message, message_fds)?; let deserialized = result; tracing::trace!( "return" = ? deserialized, "Method return from server, {}::{}", "Interface", @@ -1897,12 +1714,11 @@ pub mod drawable { _client: &std::sync::Arc, dmatex_id: u64, ) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (dmatex_id); - let serialized_data = stardust_xr_wire::flex::serialize(&data)?; + let (serialized_data, fds) = stardust_xr_wire::flex::serialize(&data)?; _client .message_sender_handle - .signal(4u64, 0u64, 15846108642868241016u64, &serialized_data, _fds)?; + .signal(4u64, 0u64, 15846108642868241016u64, &serialized_data, fds)?; let (dmatex_id) = data; tracing::trace!( ? dmatex_id, "Sent signal to server, {}::{}", "Interface", @@ -1914,7 +1730,6 @@ pub mod drawable { pub async fn get_primary_render_device_id( _client: &std::sync::Arc, ) -> crate::node::NodeResult { - let mut _fds = Vec::new(); let data = (); { let () = &data; @@ -1923,16 +1738,19 @@ pub mod drawable { "get_primary_render_device_id" ); } - let serialized_data = stardust_xr_wire::flex::serialize(&data)?; - let message = _client + let (serialized_data, fds) = stardust_xr_wire::flex::serialize(&data)?; + let (message, message_fds) = _client .message_sender_handle - .method(4u64, 0u64, 16013200258148922551u64, &serialized_data, _fds) + .method(4u64, 0u64, 16013200258148922551u64, &serialized_data, fds) .await? .map_err(|e| crate::node::NodeError::ReturnedError { e, })? - .into_message(); - let result: DrmNodeId = stardust_xr_wire::flex::deserialize(&message)?; + .into_components(); + let result: DrmNodeId = stardust_xr_wire::flex::deserialize( + &message, + message_fds, + )?; let deserialized = result; tracing::trace!( "return" = ? deserialized, "Method return from server, {}::{}", "Interface", @@ -1945,7 +1763,6 @@ pub mod drawable { _client: &std::sync::Arc, device_id: DrmNodeId, ) -> crate::node::NodeResult> { - let mut _fds = Vec::new(); let data = (device_id); { let (device_id) = &data; @@ -1954,17 +1771,18 @@ pub mod drawable { "enumerate_dmatex_formats" ); } - let serialized_data = stardust_xr_wire::flex::serialize(&data)?; - let message = _client + let (serialized_data, fds) = stardust_xr_wire::flex::serialize(&data)?; + let (message, message_fds) = _client .message_sender_handle - .method(4u64, 0u64, 14109465327684673699u64, &serialized_data, _fds) + .method(4u64, 0u64, 14109465327684673699u64, &serialized_data, fds) .await? .map_err(|e| crate::node::NodeError::ReturnedError { e, })? - .into_message(); + .into_components(); let result: Vec = stardust_xr_wire::flex::deserialize( &message, + message_fds, )?; let deserialized = result .into_iter() @@ -1981,12 +1799,11 @@ pub mod drawable { _client: &std::sync::Arc, tex: Option<&stardust_xr_wire::values::ResourceID>, ) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (tex.map(|o| Ok::<_, crate::node::NodeError>(o)).transpose()?); - let serialized_data = stardust_xr_wire::flex::serialize(&data)?; + let (serialized_data, fds) = stardust_xr_wire::flex::serialize(&data)?; _client .message_sender_handle - .signal(4u64, 0u64, 4424860741442403592u64, &serialized_data, _fds)?; + .signal(4u64, 0u64, 4424860741442403592u64, &serialized_data, fds)?; let (tex) = data; tracing::trace!( ? tex, "Sent signal to server, {}::{}", "Interface", "set_sky_tex" @@ -1998,12 +1815,11 @@ pub mod drawable { _client: &std::sync::Arc, light: Option<&stardust_xr_wire::values::ResourceID>, ) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (light.map(|o| Ok::<_, crate::node::NodeError>(o)).transpose()?); - let serialized_data = stardust_xr_wire::flex::serialize(&data)?; + let (serialized_data, fds) = stardust_xr_wire::flex::serialize(&data)?; _client .message_sender_handle - .signal(4u64, 0u64, 6210987039553590011u64, &serialized_data, _fds)?; + .signal(4u64, 0u64, 6210987039553590011u64, &serialized_data, fds)?; let (light) = data; tracing::trace!( ? light, "Sent signal to server, {}::{}", "Interface", "set_sky_light" @@ -2019,17 +1835,16 @@ pub mod drawable { lines: &[Line], ) -> crate::node::NodeResult { { - let mut _fds = Vec::new(); let data = ( id, parent.node().id, transform, lines.iter().map(|a| Ok(a)).collect::>>()?, ); - let serialized_data = stardust_xr_wire::flex::serialize(&data)?; + let (serialized_data, fds) = stardust_xr_wire::flex::serialize(&data)?; _client .message_sender_handle - .signal(4u64, 0u64, 17691651736865216822u64, &serialized_data, _fds)?; + .signal(4u64, 0u64, 17691651736865216822u64, &serialized_data, fds)?; let (id, parent, transform, lines) = data; tracing::trace!( ? id, ? parent, ? transform, ? lines, "Sent signal to server, {}::{}", @@ -2047,12 +1862,11 @@ pub mod drawable { model: &stardust_xr_wire::values::ResourceID, ) -> crate::node::NodeResult { { - let mut _fds = Vec::new(); let data = (id, parent.node().id, transform, model); - let serialized_data = stardust_xr_wire::flex::serialize(&data)?; + let (serialized_data, fds) = stardust_xr_wire::flex::serialize(&data)?; _client .message_sender_handle - .signal(4u64, 0u64, 8647852218278439936u64, &serialized_data, _fds)?; + .signal(4u64, 0u64, 8647852218278439936u64, &serialized_data, fds)?; let (id, parent, transform, model) = data; tracing::trace!( ? id, ? parent, ? transform, ? model, "Sent signal to server, {}::{}", @@ -2071,12 +1885,11 @@ pub mod drawable { style: TextStyle, ) -> crate::node::NodeResult { { - let mut _fds = Vec::new(); let data = (id, parent.node().id, transform, text, style); - let serialized_data = stardust_xr_wire::flex::serialize(&data)?; + let (serialized_data, fds) = stardust_xr_wire::flex::serialize(&data)?; _client .message_sender_handle - .signal(4u64, 0u64, 11386227176670607870u64, &serialized_data, _fds)?; + .signal(4u64, 0u64, 11386227176670607870u64, &serialized_data, fds)?; let (id, parent, transform, text, style) = data; tracing::trace!( ? id, ? parent, ? transform, ? text, ? style, @@ -2234,15 +2047,9 @@ pub mod input { &self, handler: &impl InputHandlerAspect, ) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (handler.node().id); self.node() - .send_signal( - 2611007814387963428u64, - 12158986667525139020u64, - &data, - _fds, - )?; + .send_signal(2611007814387963428u64, 12158986667525139020u64, &data)?; let (handler) = data; tracing::trace!( ? handler, "Sent signal to server, {}::{}", "InputMethodRef", @@ -2255,15 +2062,9 @@ pub mod input { &self, handler: &impl InputHandlerAspect, ) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (handler.node().id); self.node() - .send_signal( - 2611007814387963428u64, - 11905596878821798323u64, - &data, - _fds, - )?; + .send_signal(2611007814387963428u64, 11905596878821798323u64, &data)?; let (handler) = data; tracing::trace!( ? handler, "Sent signal to server, {}::{}", "InputMethodRef", "release" @@ -2379,6 +2180,7 @@ pub mod input { 6944316585732678571u64 => { let (handler, field): (u64, u64) = stardust_xr_wire::flex::deserialize( _data, + _fds, )?; tracing::trace!( ? handler, ? field, "Got signal from server, {}::{}", @@ -2390,7 +2192,7 @@ pub mod input { }) } 11807638350036597049u64 => { - let (id): (u64) = stardust_xr_wire::flex::deserialize(_data)?; + let (id): (u64) = stardust_xr_wire::flex::deserialize(_data, _fds)?; tracing::trace!( ? id, "Got signal from server, {}::{}", "InputMethod", "request_capture_handler" @@ -2400,7 +2202,7 @@ pub mod input { }) } 9300665394087171854u64 => { - let (id): (u64) = stardust_xr_wire::flex::deserialize(_data)?; + let (id): (u64) = stardust_xr_wire::flex::deserialize(_data, _fds)?; tracing::trace!( ? id, "Got signal from server, {}::{}", "InputMethod", "release_handler" @@ -2410,7 +2212,7 @@ pub mod input { }) } 7635230773176050803u64 => { - let (id): (u64) = stardust_xr_wire::flex::deserialize(_data)?; + let (id): (u64) = stardust_xr_wire::flex::deserialize(_data, _fds)?; tracing::trace!( ? id, "Got signal from server, {}::{}", "InputMethod", "destroy_handler" @@ -2468,15 +2270,9 @@ pub mod input { input: InputDataType, datamap: &stardust_xr_wire::values::Datamap, ) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (input, datamap); self.node() - .send_signal( - 14883688361483968991u64, - 9469903295692537735u64, - &data, - _fds, - )?; + .send_signal(14883688361483968991u64, 9469903295692537735u64, &data)?; let (input, datamap) = data; tracing::trace!( ? input, ? datamap, "Sent signal to server, {}::{}", "InputMethod", @@ -2489,18 +2285,12 @@ pub mod input { &self, handlers: &[InputHandler], ) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (handlers .iter() .map(|a| Ok(a.node().id)) .collect::>>()?); self.node() - .send_signal( - 14883688361483968991u64, - 4447101880184876824u64, - &data, - _fds, - )?; + .send_signal(14883688361483968991u64, 4447101880184876824u64, &data)?; let (handlers) = data; tracing::trace!( ? handlers, "Sent signal to server, {}::{}", "InputMethod", @@ -2513,18 +2303,12 @@ pub mod input { &self, handlers: &[InputHandler], ) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (handlers .iter() .map(|a| Ok(a.node().id)) .collect::>>()?); self.node() - .send_signal( - 14883688361483968991u64, - 4141712352465076448u64, - &data, - _fds, - )?; + .send_signal(14883688361483968991u64, 4141712352465076448u64, &data)?; let (handlers) = data; tracing::trace!( ? handlers, "Sent signal to server, {}::{}", "InputMethod", @@ -2617,6 +2401,7 @@ pub mod input { 1784186157485816199u64 => { let (method, data): (u64, InputData) = stardust_xr_wire::flex::deserialize( _data, + _fds, )?; tracing::trace!( ? method, ? data, "Got signal from server, {}::{}", @@ -2630,6 +2415,7 @@ pub mod input { 12767704399235128028u64 => { let (data): (InputData) = stardust_xr_wire::flex::deserialize( _data, + _fds, )?; tracing::trace!( ? data, "Got signal from server, {}::{}", "InputHandler", @@ -2640,7 +2426,10 @@ pub mod input { }) } 6474489366123796070u64 => { - let (method): (u64) = stardust_xr_wire::flex::deserialize(_data)?; + let (method): (u64) = stardust_xr_wire::flex::deserialize( + _data, + _fds, + )?; tracing::trace!( ? method, "Got signal from server, {}::{}", "InputHandler", "input_left" @@ -2686,12 +2475,11 @@ pub mod input { datamap: &stardust_xr_wire::values::Datamap, ) -> crate::node::NodeResult { { - let mut _fds = Vec::new(); let data = (id, parent.node().id, transform, initial_data, datamap); - let serialized_data = stardust_xr_wire::flex::serialize(&data)?; + let (serialized_data, fds) = stardust_xr_wire::flex::serialize(&data)?; _client .message_sender_handle - .signal(3u64, 0u64, 11977582531774730283u64, &serialized_data, _fds)?; + .signal(3u64, 0u64, 11977582531774730283u64, &serialized_data, fds)?; let (id, parent, transform, initial_data, datamap) = data; tracing::trace!( ? id, ? parent, ? transform, ? initial_data, ? datamap, @@ -2709,12 +2497,11 @@ pub mod input { field: &impl FieldAspect, ) -> crate::node::NodeResult { { - let mut _fds = Vec::new(); let data = (id, parent.node().id, transform, field.node().id); - let serialized_data = stardust_xr_wire::flex::serialize(&data)?; + let (serialized_data, fds) = stardust_xr_wire::flex::serialize(&data)?; _client .message_sender_handle - .signal(3u64, 0u64, 1654491336591158898u64, &serialized_data, _fds)?; + .signal(3u64, 0u64, 1654491336591158898u64, &serialized_data, fds)?; let (id, parent, transform, field) = data; tracing::trace!( ? id, ? parent, ? transform, ? field, "Sent signal to server, {}::{}", @@ -2790,15 +2577,9 @@ pub mod item { pub trait ItemAspect: crate::node::NodeType + super::SpatialAspect + super::OwnedAspect + super::SpatialRefAspect + std::fmt::Debug { /// fn release(&self) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (); self.node() - .send_signal( - 18318655529277677339u64, - 11905596878821798323u64, - &data, - _fds, - )?; + .send_signal(18318655529277677339u64, 11905596878821798323u64, &data)?; let () = data; tracing::trace!("Sent signal to server, {}::{}", "Item", "release"); Ok(()) @@ -2884,7 +2665,10 @@ pub mod item { ) -> Result { match signal_id { 14821884892980204849u64 => { - let (item_id): (u64) = stardust_xr_wire::flex::deserialize(_data)?; + let (item_id): (u64) = stardust_xr_wire::flex::deserialize( + _data, + _fds, + )?; tracing::trace!( ? item_id, "Got signal from server, {}::{}", "ItemAcceptor", "release_item" @@ -2991,6 +2775,7 @@ pub mod item { 1751367302976798762u64 => { let (item_id, acceptor_id): (u64, u64) = stardust_xr_wire::flex::deserialize( _data, + _fds, )?; tracing::trace!( ? item_id, ? acceptor_id, "Got signal from server, {}::{}", @@ -3004,6 +2789,7 @@ pub mod item { 14821884892980204849u64 => { let (item_id, acceptor_id): (u64, u64) = stardust_xr_wire::flex::deserialize( _data, + _fds, )?; tracing::trace!( ? item_id, ? acceptor_id, "Got signal from server, {}::{}", @@ -3015,14 +2801,14 @@ pub mod item { }) } 11215449886948753686u64 => { - let (id): (u64) = stardust_xr_wire::flex::deserialize(_data)?; + let (id): (u64) = stardust_xr_wire::flex::deserialize(_data, _fds)?; tracing::trace!( ? id, "Got signal from server, {}::{}", "ItemUi", "destroy_item" ); Ok(ItemUiEvent::DestroyItem { id: id }) } 3521554848760623636u64 => { - let (id): (u64) = stardust_xr_wire::flex::deserialize(_data)?; + let (id): (u64) = stardust_xr_wire::flex::deserialize(_data, _fds)?; tracing::trace!( ? id, "Got signal from server, {}::{}", "ItemUi", "destroy_acceptor" @@ -3197,7 +2983,10 @@ pub mod item_camera { ) -> Result { match signal_id { 15524466827491111758u64 => { - let (item): (u64) = stardust_xr_wire::flex::deserialize(_data)?; + let (item): (u64) = stardust_xr_wire::flex::deserialize( + _data, + _fds, + )?; tracing::trace!( ? item, "Got signal from server, {}::{}", "CameraItemUi", "create_item" @@ -3209,6 +2998,7 @@ pub mod item_camera { 16628549773568263004u64 => { let (acceptor, acceptor_field): (u64, u64) = stardust_xr_wire::flex::deserialize( _data, + _fds, )?; tracing::trace!( ? acceptor, ? acceptor_field, "Got signal from server, {}::{}", @@ -3346,7 +3136,10 @@ pub mod item_camera { ) -> Result { match signal_id { 1751367302976798762u64 => { - let (item): (u64) = stardust_xr_wire::flex::deserialize(_data)?; + let (item): (u64) = stardust_xr_wire::flex::deserialize( + _data, + _fds, + )?; tracing::trace!( ? item, "Got signal from server, {}::{}", "CameraItemAcceptor", "capture_item" @@ -3386,15 +3179,9 @@ pub mod item_camera { &self, item: &impl CameraItemAspect, ) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (item.node().id); self.node() - .send_signal( - 5036088114779304421u64, - 1751367302976798762u64, - &data, - _fds, - )?; + .send_signal(5036088114779304421u64, 1751367302976798762u64, &data)?; let (item) = data; tracing::trace!( ? item, "Sent signal to server, {}::{}", "CameraItemAcceptor", @@ -3413,7 +3200,6 @@ pub mod item_camera { px_size: impl Into>, ) -> crate::node::NodeResult { { - let mut _fds = Vec::new(); let data = ( id, parent.node().id, @@ -3421,10 +3207,10 @@ pub mod item_camera { proj_matrix.into(), px_size.into(), ); - let serialized_data = stardust_xr_wire::flex::serialize(&data)?; + let (serialized_data, fds) = stardust_xr_wire::flex::serialize(&data)?; _client .message_sender_handle - .signal(11u64, 0u64, 16398826726504952950u64, &serialized_data, _fds)?; + .signal(11u64, 0u64, 16398826726504952950u64, &serialized_data, fds)?; let (id, parent, transform, proj_matrix, px_size) = data; tracing::trace!( ? id, ? parent, ? transform, ? proj_matrix, ? px_size, @@ -3437,12 +3223,11 @@ pub mod item_camera { pub fn register_camera_item_ui( _client: &std::sync::Arc, ) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (); - let serialized_data = stardust_xr_wire::flex::serialize(&data)?; + let (serialized_data, fds) = stardust_xr_wire::flex::serialize(&data)?; _client .message_sender_handle - .signal(11u64, 0u64, 13470969625663359032u64, &serialized_data, _fds)?; + .signal(11u64, 0u64, 13470969625663359032u64, &serialized_data, fds)?; let () = data; tracing::trace!( "Sent signal to server, {}::{}", "Interface", "register_camera_item_ui" @@ -3458,12 +3243,11 @@ pub mod item_camera { field: &impl FieldAspect, ) -> crate::node::NodeResult { { - let mut _fds = Vec::new(); let data = (id, parent.node().id, transform, field.node().id); - let serialized_data = stardust_xr_wire::flex::serialize(&data)?; + let (serialized_data, fds) = stardust_xr_wire::flex::serialize(&data)?; _client .message_sender_handle - .signal(11u64, 0u64, 13070169044031356364u64, &serialized_data, _fds)?; + .signal(11u64, 0u64, 13070169044031356364u64, &serialized_data, fds)?; let (id, parent, transform, field) = data; tracing::trace!( ? id, ? parent, ? transform, ? field, "Sent signal to server, {}::{}", @@ -3628,7 +3412,10 @@ pub mod item_panel { ) -> Result { match signal_id { 1408884359956576105u64 => { - let (parent_id): (u64) = stardust_xr_wire::flex::deserialize(_data)?; + let (parent_id): (u64) = stardust_xr_wire::flex::deserialize( + _data, + _fds, + )?; tracing::trace!( ? parent_id, "Got signal from server, {}::{}", "PanelItem", "toplevel_parent_changed" @@ -3638,7 +3425,10 @@ pub mod item_panel { }) } 566483566315648641u64 => { - let (title): (String) = stardust_xr_wire::flex::deserialize(_data)?; + let (title): (String) = stardust_xr_wire::flex::deserialize( + _data, + _fds, + )?; tracing::trace!( ? title, "Got signal from server, {}::{}", "PanelItem", "toplevel_title_changed" @@ -3648,7 +3438,10 @@ pub mod item_panel { }) } 8706869778156655494u64 => { - let (app_id): (String) = stardust_xr_wire::flex::deserialize(_data)?; + let (app_id): (String) = stardust_xr_wire::flex::deserialize( + _data, + _fds, + )?; tracing::trace!( ? app_id, "Got signal from server, {}::{}", "PanelItem", "toplevel_app_id_changed" @@ -3658,7 +3451,10 @@ pub mod item_panel { }) } 11059551561818960198u64 => { - let (active): (bool) = stardust_xr_wire::flex::deserialize(_data)?; + let (active): (bool) = stardust_xr_wire::flex::deserialize( + _data, + _fds, + )?; tracing::trace!( ? active, "Got signal from server, {}::{}", "PanelItem", "toplevel_fullscreen_active" @@ -3668,7 +3464,7 @@ pub mod item_panel { }) } 3715781852227007625u64 => { - let (): () = stardust_xr_wire::flex::deserialize(_data)?; + let (): () = stardust_xr_wire::flex::deserialize(_data, _fds)?; tracing::trace!( "Got signal from server, {}::{}", "PanelItem", "toplevel_move_request" @@ -3679,6 +3475,7 @@ pub mod item_panel { 4540754955116125050u64 => { let (up, down, left, right): (bool, bool, bool, bool) = stardust_xr_wire::flex::deserialize( _data, + _fds, )?; tracing::trace!( ? up, ? down, ? left, ? right, "Got signal from server, {}::{}", @@ -3694,6 +3491,7 @@ pub mod item_panel { 3665525014775618530u64 => { let (size): (stardust_xr_wire::values::Vector2) = stardust_xr_wire::flex::deserialize( _data, + _fds, )?; tracing::trace!( ? size, "Got signal from server, {}::{}", "PanelItem", @@ -3706,6 +3504,7 @@ pub mod item_panel { 6092877811616586203u64 => { let (geometry): (Geometry) = stardust_xr_wire::flex::deserialize( _data, + _fds, )?; tracing::trace!( ? geometry, "Got signal from server, {}::{}", "PanelItem", @@ -3716,7 +3515,7 @@ pub mod item_panel { }) } 12365625385177885025u64 => { - let (): () = stardust_xr_wire::flex::deserialize(_data)?; + let (): () = stardust_xr_wire::flex::deserialize(_data, _fds)?; tracing::trace!( "Got signal from server, {}::{}", "PanelItem", "hide_cursor" ); @@ -3725,6 +3524,7 @@ pub mod item_panel { 13878060402106144481u64 => { let (uid, info): (u64, ChildInfo) = stardust_xr_wire::flex::deserialize( _data, + _fds, )?; tracing::trace!( ? uid, ? info, "Got signal from server, {}::{}", "PanelItem", @@ -3738,6 +3538,7 @@ pub mod item_panel { 4614990113965355127u64 => { let (uid, geometry): (u64, Geometry) = stardust_xr_wire::flex::deserialize( _data, + _fds, )?; tracing::trace!( ? uid, ? geometry, "Got signal from server, {}::{}", "PanelItem", @@ -3749,7 +3550,7 @@ pub mod item_panel { }) } 7048616010698587017u64 => { - let (uid): (u64) = stardust_xr_wire::flex::deserialize(_data)?; + let (uid): (u64) = stardust_xr_wire::flex::deserialize(_data, _fds)?; tracing::trace!( ? uid, "Got signal from server, {}::{}", "PanelItem", "destroy_child" @@ -3789,15 +3590,9 @@ pub mod item_panel { &self, model_part: &impl ModelPartAspect, ) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (model_part.node().id); self.node() - .send_signal( - 16007573185838633179u64, - 12984352657777750687u64, - &data, - _fds, - )?; + .send_signal(16007573185838633179u64, 12984352657777750687u64, &data)?; let (model_part) = data; tracing::trace!( ? model_part, "Sent signal to server, {}::{}", "PanelItem", @@ -3811,15 +3606,9 @@ pub mod item_panel { surface: SurfaceId, model_part: &impl ModelPartAspect, ) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (surface, model_part.node().id); self.node() - .send_signal( - 16007573185838633179u64, - 5538717944649978650u64, - &data, - _fds, - )?; + .send_signal(16007573185838633179u64, 5538717944649978650u64, &data)?; let (surface, model_part) = data; tracing::trace!( ? surface, ? model_part, "Sent signal to server, {}::{}", "PanelItem", @@ -3831,15 +3620,9 @@ pub mod item_panel { The panel item UI handler or panel item acceptor will drop the panel item if this succeeds.*/ fn close_toplevel(&self) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (); self.node() - .send_signal( - 16007573185838633179u64, - 11149391162473273576u64, - &data, - _fds, - )?; + .send_signal(16007573185838633179u64, 11149391162473273576u64, &data)?; let () = data; tracing::trace!( "Sent signal to server, {}::{}", "PanelItem", "close_toplevel" @@ -3848,15 +3631,9 @@ pub mod item_panel { } ///Request a resize of the surface to whatever size the 2D app wants. fn auto_size_toplevel(&self) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (); self.node() - .send_signal( - 16007573185838633179u64, - 7177229187692151305u64, - &data, - _fds, - )?; + .send_signal(16007573185838633179u64, 7177229187692151305u64, &data)?; let () = data; tracing::trace!( "Sent signal to server, {}::{}", "PanelItem", "auto_size_toplevel" @@ -3868,15 +3645,9 @@ pub mod item_panel { &self, size: impl Into>, ) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (size.into()); self.node() - .send_signal( - 16007573185838633179u64, - 8102855835344875634u64, - &data, - _fds, - )?; + .send_signal(16007573185838633179u64, 8102855835344875634u64, &data)?; let (size) = data; tracing::trace!( ? size, "Sent signal to server, {}::{}", "PanelItem", "set_toplevel_size" @@ -3888,15 +3659,9 @@ pub mod item_panel { &self, focused: bool, ) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (focused); self.node() - .send_signal( - 16007573185838633179u64, - 3934600665134956080u64, - &data, - _fds, - )?; + .send_signal(16007573185838633179u64, 3934600665134956080u64, &data)?; let (focused) = data; tracing::trace!( ? focused, "Sent signal to server, {}::{}", "PanelItem", @@ -3910,15 +3675,9 @@ pub mod item_panel { surface: SurfaceId, position: impl Into>, ) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (surface, position.into()); self.node() - .send_signal( - 16007573185838633179u64, - 16749501366142443858u64, - &data, - _fds, - )?; + .send_signal(16007573185838633179u64, 16749501366142443858u64, &data)?; let (surface, position) = data; tracing::trace!( ? surface, ? position, "Sent signal to server, {}::{}", "PanelItem", @@ -3932,15 +3691,9 @@ pub mod item_panel { surface: SurfaceId, delta: impl Into>, ) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (surface, delta.into()); self.node() - .send_signal( - 16007573185838633179u64, - 8178111286759258039u64, - &data, - _fds, - )?; + .send_signal(16007573185838633179u64, 8178111286759258039u64, &data)?; let (surface, delta) = data; tracing::trace!( ? surface, ? delta, "Sent signal to server, {}::{}", "PanelItem", @@ -3955,15 +3708,9 @@ pub mod item_panel { button: u32, pressed: bool, ) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (surface, button, pressed); self.node() - .send_signal( - 16007573185838633179u64, - 1617963334017359776u64, - &data, - _fds, - )?; + .send_signal(16007573185838633179u64, 1617963334017359776u64, &data)?; let (surface, button, pressed) = data; tracing::trace!( ? surface, ? button, ? pressed, "Sent signal to server, {}::{}", @@ -3980,15 +3727,9 @@ Scroll steps is a value in columns/rows corresponding to the wheel clicks of a m scroll_distance: impl Into>, scroll_steps: impl Into>, ) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (surface, scroll_distance.into(), scroll_steps.into()); self.node() - .send_signal( - 16007573185838633179u64, - 18077910517219850499u64, - &data, - _fds, - )?; + .send_signal(16007573185838633179u64, 18077910517219850499u64, &data)?; let (surface, scroll_distance, scroll_steps) = data; tracing::trace!( ? surface, ? scroll_distance, ? scroll_steps, @@ -4001,15 +3742,9 @@ Scroll steps is a value in columns/rows corresponding to the wheel clicks of a m &self, surface: SurfaceId, ) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (surface); self.node() - .send_signal( - 16007573185838633179u64, - 13177724628894942354u64, - &data, - _fds, - )?; + .send_signal(16007573185838633179u64, 13177724628894942354u64, &data)?; let (surface) = data; tracing::trace!( ? surface, "Sent signal to server, {}::{}", "PanelItem", @@ -4025,15 +3760,9 @@ Scroll steps is a value in columns/rows corresponding to the wheel clicks of a m key: u32, pressed: bool, ) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (surface, keymap_id, key, pressed); self.node() - .send_signal( - 16007573185838633179u64, - 18230480350930328965u64, - &data, - _fds, - )?; + .send_signal(16007573185838633179u64, 18230480350930328965u64, &data)?; let (surface, keymap_id, key, pressed) = data; tracing::trace!( ? surface, ? keymap_id, ? key, ? pressed, @@ -4048,15 +3777,9 @@ Scroll steps is a value in columns/rows corresponding to the wheel clicks of a m uid: u32, position: impl Into>, ) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (surface, uid, position.into()); self.node() - .send_signal( - 16007573185838633179u64, - 10543081656468919422u64, - &data, - _fds, - )?; + .send_signal(16007573185838633179u64, 10543081656468919422u64, &data)?; let (surface, uid, position) = data; tracing::trace!( ? surface, ? uid, ? position, "Sent signal to server, {}::{}", @@ -4070,15 +3793,9 @@ Scroll steps is a value in columns/rows corresponding to the wheel clicks of a m uid: u32, position: impl Into>, ) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (uid, position.into()); self.node() - .send_signal( - 16007573185838633179u64, - 15126475688563381777u64, - &data, - _fds, - )?; + .send_signal(16007573185838633179u64, 15126475688563381777u64, &data)?; let (uid, position) = data; tracing::trace!( ? uid, ? position, "Sent signal to server, {}::{}", "PanelItem", @@ -4088,15 +3805,9 @@ Scroll steps is a value in columns/rows corresponding to the wheel clicks of a m } ///Release a touch from its surface. fn touch_up(&self, uid: u32) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (uid); self.node() - .send_signal( - 16007573185838633179u64, - 6589027081119653997u64, - &data, - _fds, - )?; + .send_signal(16007573185838633179u64, 6589027081119653997u64, &data)?; let (uid) = data; tracing::trace!( ? uid, "Sent signal to server, {}::{}", "PanelItem", "touch_up" @@ -4105,15 +3816,9 @@ Scroll steps is a value in columns/rows corresponding to the wheel clicks of a m } ///Reset all input, such as pressed keys and pointer clicks and touches. Useful for when it's newly captured into an item acceptor to make sure no input gets stuck. fn reset_input(&self) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (); self.node() - .send_signal( - 16007573185838633179u64, - 14629122800709746500u64, - &data, - _fds, - )?; + .send_signal(16007573185838633179u64, 14629122800709746500u64, &data)?; let () = data; tracing::trace!("Sent signal to server, {}::{}", "PanelItem", "reset_input"); Ok(()) @@ -4209,6 +3914,7 @@ Scroll steps is a value in columns/rows corresponding to the wheel clicks of a m 15524466827491111758u64 => { let (item, initial_data): (u64, PanelItemInitData) = stardust_xr_wire::flex::deserialize( _data, + _fds, )?; tracing::trace!( ? item, ? initial_data, "Got signal from server, {}::{}", @@ -4222,6 +3928,7 @@ Scroll steps is a value in columns/rows corresponding to the wheel clicks of a m 16628549773568263004u64 => { let (acceptor, acceptor_field): (u64, u64) = stardust_xr_wire::flex::deserialize( _data, + _fds, )?; tracing::trace!( ? acceptor, ? acceptor_field, "Got signal from server, {}::{}", @@ -4361,6 +4068,7 @@ Scroll steps is a value in columns/rows corresponding to the wheel clicks of a m 1751367302976798762u64 => { let (item, initial_data): (u64, PanelItemInitData) = stardust_xr_wire::flex::deserialize( _data, + _fds, )?; tracing::trace!( ? item, ? initial_data, "Got signal from server, {}::{}", @@ -4402,15 +4110,9 @@ Scroll steps is a value in columns/rows corresponding to the wheel clicks of a m &self, item: &impl PanelItemAspect, ) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (item.node().id); self.node() - .send_signal( - 6398932320740499836u64, - 1751367302976798762u64, - &data, - _fds, - )?; + .send_signal(6398932320740499836u64, 1751367302976798762u64, &data)?; let (item) = data; tracing::trace!( ? item, "Sent signal to server, {}::{}", "PanelItemAcceptor", @@ -4424,7 +4126,6 @@ Scroll steps is a value in columns/rows corresponding to the wheel clicks of a m _client: &std::sync::Arc, keymap: &str, ) -> crate::node::NodeResult { - let mut _fds = Vec::new(); let data = (keymap); { let (keymap) = &data; @@ -4433,16 +4134,16 @@ Scroll steps is a value in columns/rows corresponding to the wheel clicks of a m "register_keymap" ); } - let serialized_data = stardust_xr_wire::flex::serialize(&data)?; - let message = _client + let (serialized_data, fds) = stardust_xr_wire::flex::serialize(&data)?; + let (message, message_fds) = _client .message_sender_handle - .method(12u64, 0u64, 13267771052011565359u64, &serialized_data, _fds) + .method(12u64, 0u64, 13267771052011565359u64, &serialized_data, fds) .await? .map_err(|e| crate::node::NodeError::ReturnedError { e, })? - .into_message(); - let result: u64 = stardust_xr_wire::flex::deserialize(&message)?; + .into_components(); + let result: u64 = stardust_xr_wire::flex::deserialize(&message, message_fds)?; let deserialized = result; tracing::trace!( "return" = ? deserialized, "Method return from server, {}::{}", "Interface", @@ -4455,7 +4156,6 @@ Scroll steps is a value in columns/rows corresponding to the wheel clicks of a m _client: &std::sync::Arc, keymap_id: u64, ) -> crate::node::NodeResult { - let mut _fds = Vec::new(); let data = (keymap_id); { let (keymap_id) = &data; @@ -4463,16 +4163,16 @@ Scroll steps is a value in columns/rows corresponding to the wheel clicks of a m ? keymap_id, "Called method on server, {}::{}", "Interface", "get_keymap" ); } - let serialized_data = stardust_xr_wire::flex::serialize(&data)?; - let message = _client + let (serialized_data, fds) = stardust_xr_wire::flex::serialize(&data)?; + let (message, message_fds) = _client .message_sender_handle - .method(12u64, 0u64, 18393315648981916968u64, &serialized_data, _fds) + .method(12u64, 0u64, 18393315648981916968u64, &serialized_data, fds) .await? .map_err(|e| crate::node::NodeError::ReturnedError { e, })? - .into_message(); - let result: String = stardust_xr_wire::flex::deserialize(&message)?; + .into_components(); + let result: String = stardust_xr_wire::flex::deserialize(&message, message_fds)?; let deserialized = result; tracing::trace!( "return" = ? deserialized, "Method return from server, {}::{}", "Interface", @@ -4484,12 +4184,11 @@ Scroll steps is a value in columns/rows corresponding to the wheel clicks of a m pub fn register_panel_item_ui( _client: &std::sync::Arc, ) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (); - let serialized_data = stardust_xr_wire::flex::serialize(&data)?; + let (serialized_data, fds) = stardust_xr_wire::flex::serialize(&data)?; _client .message_sender_handle - .signal(12u64, 0u64, 13016197282381545765u64, &serialized_data, _fds)?; + .signal(12u64, 0u64, 13016197282381545765u64, &serialized_data, fds)?; let () = data; tracing::trace!( "Sent signal to server, {}::{}", "Interface", "register_panel_item_ui" @@ -4505,12 +4204,11 @@ Scroll steps is a value in columns/rows corresponding to the wheel clicks of a m field: &impl FieldAspect, ) -> crate::node::NodeResult { { - let mut _fds = Vec::new(); let data = (id, parent.node().id, transform, field.node().id); - let serialized_data = stardust_xr_wire::flex::serialize(&data)?; + let (serialized_data, fds) = stardust_xr_wire::flex::serialize(&data)?; _client .message_sender_handle - .signal(12u64, 0u64, 793626320493717815u64, &serialized_data, _fds)?; + .signal(12u64, 0u64, 793626320493717815u64, &serialized_data, fds)?; let (id, parent, transform, field) = data; tracing::trace!( ? id, ? parent, ? transform, ? field, "Sent signal to server, {}::{}", diff --git a/wire/src/flex/mod.rs b/wire/src/flex/mod.rs index 2819adb..99c39fe 100644 --- a/wire/src/flex/mod.rs +++ b/wire/src/flex/mod.rs @@ -9,12 +9,14 @@ use serde::{ SerializeTupleStruct, SerializeTupleVariant, }, }; -use std::{fmt::Display, marker::PhantomData}; +use std::{fmt::Display, marker::PhantomData, os::fd::OwnedFd}; mod datamap; pub use datamap::*; pub use flexbuffers; +use crate::fd::{with_fd_deserialization_ctx, with_fd_serialization_ctx}; + #[derive(Debug, thiserror::Error)] pub enum FlexSerializeError { #[error("Map key is not a string!")] @@ -33,11 +35,16 @@ impl serde::ser::Error for FlexSerializeError { /// Serialize the given data into flexbuffers, stripping struct field names off /// and putting structs into vectors to save space and computation. -pub fn serialize(to_serialize: S) -> Result, FlexSerializeError> { - let mut fbb = flexbuffers::Builder::default(); - let fs = FlexSerializer { fbb: &mut fbb }; - to_serialize.serialize(fs)?; - Ok(fbb.take_buffer()) +/// This also allows serializing file descriptors. +pub fn serialize( + to_serialize: S, +) -> Result<(Vec, Vec), FlexSerializeError> { + with_fd_serialization_ctx(|| { + let mut fbb = flexbuffers::Builder::default(); + let fs = FlexSerializer { fbb: &mut fbb }; + to_serialize.serialize(fs)?; + Ok(fbb.take_buffer()) + }) } struct FlexSerializer<'b> { @@ -943,10 +950,16 @@ impl SerializeMap for FlexMapSerializer<'_> { /// because it strips the names off of struct fields, /// instead putting the values into vectors with the same /// order to save space and speed up deserialization. -pub fn deserialize<'a, T: Deserialize<'a>>(data: &'a [u8]) -> Result { - let root = flexbuffers::Reader::get_root(data)?; - let deserializer = FlexbuffersDeserializer(root); - T::deserialize(deserializer) +/// This also allows deserializing file descriptors. +pub fn deserialize<'a, T: Deserialize<'a>>( + data: &'a [u8], + fds: impl IntoIterator, +) -> Result { + with_fd_deserialization_ctx(fds.into_iter(), || { + let root = flexbuffers::Reader::get_root(data)?; + let deserializer = FlexbuffersDeserializer(root); + T::deserialize(deserializer) + }) } struct ReaderIteratorWrapper<'d>(ReaderIterator<&'d [u8]>); @@ -1229,9 +1242,9 @@ fn round_trip_flex_serialize() { test_struct: None, }; test_struct.test_struct = Some(Box::new(test_struct.clone())); - let serialized = serialize(test_struct.clone()).unwrap(); + let (serialized, fds) = serialize(test_struct.clone()).unwrap(); let flex = flexbuffers::Reader::get_root(serialized.as_slice()).unwrap(); println!("{flex}"); - let deserialized: TestStruct = deserialize(&serialized).unwrap(); + let deserialized: TestStruct = deserialize(&serialized, fds.into_iter()).unwrap(); assert_eq!(test_struct, deserialized, "Round trip lost data"); } diff --git a/wire/src/lib.rs b/wire/src/lib.rs index ac2b346..0b6bcd0 100644 --- a/wire/src/lib.rs +++ b/wire/src/lib.rs @@ -4,6 +4,7 @@ pub mod client; /// Standard creation of sockets for servers pub mod server; +pub mod fd; /// Message format flatbuffer pub mod message { From 94dfeffbabe9d8c7879af6a1d195ffca073168b3 Mon Sep 17 00:00:00 2001 From: Schmarni Date: Thu, 25 Dec 2025 06:53:54 +0100 Subject: [PATCH 07/16] feat: support multiplane dmatex Signed-off-by: Schmarni --- fusion/src/protocol.rs | 26 ++++++++++---------------- protocol/idl/drawable.kdl | 5 +++-- 2 files changed, 13 insertions(+), 18 deletions(-) diff --git a/fusion/src/protocol.rs b/fusion/src/protocol.rs index d910cdc..ca835c0 100644 --- a/fusion/src/protocol.rs +++ b/fusion/src/protocol.rs @@ -1219,12 +1219,16 @@ pub mod drawable { pub format: u32, pub drm_modifier: u64, pub supports_srgb: bool, + ///How many memory planes does this format use + pub planes: u32, } ///A single memory plane of a Dmatex #[derive(Debug, Clone, PartialEq, serde::Deserialize, serde::Serialize)] pub struct DmatexPlane { ///The Drm modifier of this Dmatex memory plane pub drm_modifier: u64, + ///the underlying dmabuf fd for this plane + pub dmabuf_fd: stardust_xr_wire::fd::ProtocolFd, ///offset of the data relevant to this Dmatex plane in the Dmatex memory pub offset: u32, ///the number of bytes between the beginning of one pixel row to the next, if the Dmatex is 1d this should be 0 @@ -1603,8 +1607,7 @@ pub mod drawable { format: u32, srgb: bool, array_layers: Option, - plane_1_dmabuf_fd: stardust_xr_wire::fd::ProtocolFd, - plane_1_info: DmatexPlane, + planes: &[DmatexPlane], timeline_syncobj_fd: stardust_xr_wire::fd::ProtocolFd, ) -> crate::node::NodeResult { let data = ( @@ -1612,24 +1615,15 @@ pub mod drawable { format, srgb, array_layers.map(|o| Ok::<_, crate::node::NodeError>(o)).transpose()?, - plane_1_dmabuf_fd, - plane_1_info, + planes.iter().map(|a| Ok(a)).collect::>>()?, timeline_syncobj_fd, ); { - let ( - size, - format, - srgb, - array_layers, - plane_1_dmabuf_fd, - plane_1_info, - timeline_syncobj_fd, - ) = &data; + let (size, format, srgb, array_layers, planes, timeline_syncobj_fd) = &data; tracing::trace!( - ? size, ? format, ? srgb, ? array_layers, ? plane_1_dmabuf_fd, ? - plane_1_info, ? timeline_syncobj_fd, "Called method on server, {}::{}", - "Interface", "import_dmatex" + ? size, ? format, ? srgb, ? array_layers, ? planes, ? + timeline_syncobj_fd, "Called method on server, {}::{}", "Interface", + "import_dmatex" ); } let (serialized_data, fds) = stardust_xr_wire::flex::serialize(&data)?; diff --git a/protocol/idl/drawable.kdl b/protocol/idl/drawable.kdl index 0c0d83e..23fe918 100644 --- a/protocol/idl/drawable.kdl +++ b/protocol/idl/drawable.kdl @@ -10,8 +10,7 @@ method "import_dmatex" side="server" { argument "format" type="uint" description="the texture format as a drm_fourcc" argument "srgb" type="bool" description="try to use an SRGB color space version of the format, needed because drm_fourcc can't represent this information" argument "array_layers" type="uint" optional=true description="try to use an SRGB color space version of the format, needed because drm_fourcc can't represent this information" - argument "plane_1_dmabuf_fd" type="fd" description="the underlying dmabuf fd for the first plane" - argument "plane_1_info" type="struct" struct="DmatexPlane" + argument "planes" type="vec" member_type="struct" struct="DmatexPlane" argument "timeline_syncobj_fd" type="fd" description="the fd carrying info for explicit sync, using the timeline variant of the drm_syncobj" return type="id" @@ -56,11 +55,13 @@ struct "DmatexFormatInfo" { field "format" type="uint" description="drm_fourcc for the format" field "drm_modifier" type="id" field "supports_srgb" type="bool" + field "planes" type="uint" description="How many memory planes does this format use" } struct "DmatexPlane" { description "A single memory plane of a Dmatex" field "drm_modifier" type="id" description="The Drm modifier of this Dmatex memory plane" + field "dmabuf_fd" type="fd" description="the underlying dmabuf fd for this plane" field "offset" type="uint" description="offset of the data relevant to this Dmatex plane in the Dmatex memory" field "row_size" type="uint" description="the number of bytes between the beginning of one pixel row to the next, if the Dmatex is 1d this should be 0" field "array_element_size" type="uint" description="the number of bytes between the beginning of one array element to the next, if the Dmatex is not an array texture this should be 0" From 1421a88af4547dc89ebb1226cd06b4bf4913e693 Mon Sep 17 00:00:00 2001 From: Schmarni Date: Thu, 25 Dec 2025 07:53:05 +0100 Subject: [PATCH 08/16] fix(fusion/codegen): don't derive Clone and PartialEq for types that contain fds Signed-off-by: Schmarni --- fusion/build.rs | 99 ++++++++++++++++++++++++++++++++++++++---- fusion/src/protocol.rs | 2 +- 2 files changed, 92 insertions(+), 9 deletions(-) diff --git a/fusion/build.rs b/fusion/build.rs index 1e1ae1b..9c0fa67 100644 --- a/fusion/build.rs +++ b/fusion/build.rs @@ -3,10 +3,14 @@ use convert_case::{Case, Casing}; use proc_macro2::{Ident, Span, TokenStream}; use quote::{ToTokens, quote}; use stardust_xr_protocol::*; +use std::collections::HashMap; use std::env; use std::fs; use std::path::Path; use std::path::PathBuf; +use std::sync::LazyLock; +use std::sync::Mutex; + fn main() { // Watch for changes to KDL schema files let schema_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()) @@ -106,6 +110,48 @@ pub fn get_all_protocols() -> Vec { ] } +static CLONE_PARTIAL_EQ_CACHE: LazyLock>> = + LazyLock::new(Default::default); +fn can_impl_clone_and_partial_eq(arg: &ArgumentType) -> bool { + match dbg!(&arg) { + ArgumentType::Union(name) => *CLONE_PARTIAL_EQ_CACHE.lock().unwrap().get(name).unwrap(), + ArgumentType::Struct(name) => *CLONE_PARTIAL_EQ_CACHE.lock().unwrap().get(name).unwrap(), + ArgumentType::Fd => false, + _ => true, + } +} +fn setup_impl_clone_and_partial_eq(protocol_definitions: &[&Protocol], arg: &ArgumentType) -> bool { + match dbg!(&arg) { + ArgumentType::Union(name) | ArgumentType::Struct(name) => { + if let Some(v) = CLONE_PARTIAL_EQ_CACHE.lock().unwrap().get(name) { + return *v; + }; + let v = protocol_definitions + .iter() + .flat_map(|v| v.custom_unions.iter()) + .filter(|v| &v.name == name) + .flat_map(|v| v.options.iter()) + .map(|v| &v._type) + .chain( + protocol_definitions + .iter() + .flat_map(|v| v.custom_structs.iter()) + .filter(|v| &v.name == name) + .flat_map(|v| v.fields.iter()) + .map(|v| &v._type), + ) + .all(|v| setup_impl_clone_and_partial_eq(protocol_definitions, v)); + CLONE_PARTIAL_EQ_CACHE + .lock() + .unwrap() + .insert(name.clone(), v); + v + } + ArgumentType::Fd => false, + _ => true, + } +} + pub fn generate_protocol_file( protocols: Vec, file_path: &Path, @@ -118,6 +164,25 @@ pub fn generate_protocol_file( let mut protocol_definitions = protocols.iter_mut().map(|(p, _)| p).collect::>(); stardust_xr_protocol::resolve_inherits(&mut protocol_definitions).unwrap(); + let protocol_definitions = protocols.iter().map(|(p, _)| p).collect::>(); + protocol_definitions + .iter() + .flat_map(|v| v.custom_structs.iter()) + .for_each(|v| { + setup_impl_clone_and_partial_eq( + &protocol_definitions, + &ArgumentType::Struct(v.name.clone()), + ); + }); + protocol_definitions + .iter() + .flat_map(|v| v.custom_unions.iter()) + .for_each(|v| { + setup_impl_clone_and_partial_eq( + &protocol_definitions, + &ArgumentType::Union(v.name.clone()), + ); + }); // panic!("{protocol_definitions:# ?}"); @@ -258,10 +323,19 @@ impl Tokenize for CustomUnion { .iter() .map(|e| e.tokenize(_generate_node, partial_eq)); - let derive = if partial_eq { - quote!( #[derive(Debug, Clone, PartialEq, serde::Deserialize, serde::Serialize)] ) - } else { - quote!( #[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] ) + let derive = match ( + partial_eq, + can_impl_clone_and_partial_eq(&ArgumentType::Enum(self.name.clone())), + ) { + (true, true) => { + quote!( #[derive(Debug, Clone, PartialEq, serde::Deserialize, serde::Serialize)] ) + } + (false, true) => { + quote!( #[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] ) + } + (_, false) => { + quote!( #[derive(Debug, serde::Deserialize, serde::Serialize)] ) + } }; quote! { #[doc = #description] @@ -324,10 +398,19 @@ impl Tokenize for CustomStruct { let argument_decls = self.fields.iter().map(|a| generate_pub_field_decl(a, true)); - let derive = if partial_eq { - quote!( #[derive(Debug, Clone, PartialEq, serde::Deserialize, serde::Serialize)] ) - } else { - quote!( #[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] ) + let derive = match ( + partial_eq, + can_impl_clone_and_partial_eq(&ArgumentType::Struct(self.name.clone())), + ) { + (true, true) => { + quote!( #[derive(Debug, Clone, PartialEq, serde::Deserialize, serde::Serialize)] ) + } + (false, true) => { + quote!( #[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] ) + } + (_, false) => { + quote!( #[derive(Debug, serde::Deserialize, serde::Serialize)] ) + } }; quote! { #[doc = #description] diff --git a/fusion/src/protocol.rs b/fusion/src/protocol.rs index ca835c0..52bbf3d 100644 --- a/fusion/src/protocol.rs +++ b/fusion/src/protocol.rs @@ -1223,7 +1223,7 @@ pub mod drawable { pub planes: u32, } ///A single memory plane of a Dmatex - #[derive(Debug, Clone, PartialEq, serde::Deserialize, serde::Serialize)] + #[derive(Debug, serde::Deserialize, serde::Serialize)] pub struct DmatexPlane { ///The Drm modifier of this Dmatex memory plane pub drm_modifier: u64, From 4166702c7c79b202ac53b8dbadd9b25b8abedc5e Mon Sep 17 00:00:00 2001 From: Schmarni Date: Thu, 25 Dec 2025 08:04:05 +0100 Subject: [PATCH 09/16] fix(wire): actually push the new fd module Signed-off-by: Schmarni --- wire/src/fd.rs | 116 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 wire/src/fd.rs diff --git a/wire/src/fd.rs b/wire/src/fd.rs new file mode 100644 index 0000000..e10c4da --- /dev/null +++ b/wire/src/fd.rs @@ -0,0 +1,116 @@ +use std::{ + cell::RefCell, + error::Error, + os::fd::{AsFd, AsRawFd, IntoRawFd, OwnedFd, RawFd}, +}; + +use serde::{Deserialize, Serialize}; +use tracing::warn; + +#[derive(Debug)] +pub struct ProtocolFd(pub OwnedFd); + +pub fn with_fd_serialization_ctx( + func: impl FnOnce() -> Result, +) -> Result<(T, Vec), E> { + FD_SERIALIZATION_CTX.set(Some(Vec::new())); + let v = func(); + let Some(fds) = FD_SERIALIZATION_CTX.with_borrow_mut(|v| v.take()) else { + unreachable!() + }; + Ok((v?, fds)) +} + +pub fn with_fd_deserialization_ctx( + fds: impl IntoIterator, + func: impl FnOnce() -> T, +) -> T { + let fds = fds.into_iter().map(Some).collect::>(); + FD_DESERIALIZATION_CTX.set(Some(fds)); + let v = func(); + let Some(fds) = FD_DESERIALIZATION_CTX.with_borrow_mut(|v| v.take()) else { + unreachable!() + }; + let count = fds.into_iter().filter_map(|v| v).count(); + if count != 0 { + warn!("{count} unused fds during deserialization"); + } + v +} + +impl Serialize for ProtocolFd { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let index = FD_SERIALIZATION_CTX.with_borrow_mut(|ctx| { + let Some(ctx) = ctx else { + return Err(::custom( + "tried to serialize ProtocolFd without fd serialization context", + )); + }; + ctx.push(self.0.try_clone().unwrap()); + Ok(ctx.len() - 1) + })?; + serializer.serialize_u32(index as u32) + } +} +impl<'de> Deserialize<'de> for ProtocolFd { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let fd = FD_DESERIALIZATION_CTX.with_borrow_mut(|ctx| { + let Some(ctx) = ctx else { + return Err(::custom( + "tried to deserialize ProtocolFd without fd deserialization context", + )); + }; + let index = ::deserialize(deserializer)?; + let Some(fd_option) = ctx.get_mut(index as usize) else { + return Err(::custom( + "tried to deserialize fd not present in the deserialization context", + )); + }; + let Some(fd) = fd_option.take() else { + return Err(::custom( + "tried to deserialize the same fd twice, should be impossible", + )); + }; + + Ok(fd) + })?; + Ok(Self(fd)) + } +} + +thread_local! { +static FD_SERIALIZATION_CTX: RefCell>> = RefCell::new(None); +static FD_DESERIALIZATION_CTX: RefCell>>> = RefCell::new(None); +} + +impl AsFd for ProtocolFd { + fn as_fd(&self) -> std::os::unix::prelude::BorrowedFd<'_> { + self.0.as_fd() + } +} +impl AsRawFd for ProtocolFd { + fn as_raw_fd(&self) -> RawFd { + self.0.as_raw_fd() + } +} +impl IntoRawFd for ProtocolFd { + fn into_raw_fd(self) -> RawFd { + self.0.into_raw_fd() + } +} +impl From for ProtocolFd { + fn from(value: OwnedFd) -> Self { + Self(value) + } +} +impl From for OwnedFd { + fn from(value: ProtocolFd) -> OwnedFd { + value.0 + } +} From 97eff24b821a7817941dc2e95697e26bd7f0c96a Mon Sep 17 00:00:00 2001 From: Schmarni Date: Thu, 25 Dec 2025 08:08:35 +0100 Subject: [PATCH 10/16] chore(fusion/codegen): remove some debug logging Signed-off-by: Schmarni --- fusion/build.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fusion/build.rs b/fusion/build.rs index 9c0fa67..5eaeeeb 100644 --- a/fusion/build.rs +++ b/fusion/build.rs @@ -113,7 +113,7 @@ pub fn get_all_protocols() -> Vec { static CLONE_PARTIAL_EQ_CACHE: LazyLock>> = LazyLock::new(Default::default); fn can_impl_clone_and_partial_eq(arg: &ArgumentType) -> bool { - match dbg!(&arg) { + match &arg { ArgumentType::Union(name) => *CLONE_PARTIAL_EQ_CACHE.lock().unwrap().get(name).unwrap(), ArgumentType::Struct(name) => *CLONE_PARTIAL_EQ_CACHE.lock().unwrap().get(name).unwrap(), ArgumentType::Fd => false, @@ -121,7 +121,7 @@ fn can_impl_clone_and_partial_eq(arg: &ArgumentType) -> bool { } } fn setup_impl_clone_and_partial_eq(protocol_definitions: &[&Protocol], arg: &ArgumentType) -> bool { - match dbg!(&arg) { + match &arg { ArgumentType::Union(name) | ArgumentType::Struct(name) => { if let Some(v) = CLONE_PARTIAL_EQ_CACHE.lock().unwrap().get(name) { return *v; From 020fa109c78dcc3384a1efe28731242015bb5b6d Mon Sep 17 00:00:00 2001 From: Schmarni Date: Mon, 29 Dec 2025 05:50:54 +0100 Subject: [PATCH 11/16] refactor(protocol/drawable): remove DrmNodeId union, only ever return render node ids Signed-off-by: Schmarni --- fusion/src/protocol.rs | 24 +++++++----------------- protocol/idl/drawable.kdl | 13 +++---------- 2 files changed, 10 insertions(+), 27 deletions(-) diff --git a/fusion/src/protocol.rs b/fusion/src/protocol.rs index 52bbf3d..2479594 100644 --- a/fusion/src/protocol.rs +++ b/fusion/src/protocol.rs @@ -1190,13 +1190,6 @@ pub mod drawable { Dim2D(stardust_xr_wire::values::Vector2), Dim3D(stardust_xr_wire::values::Vector3), } - ///Drm Node Id used for selecting the correct gpu - #[derive(Debug, Clone, PartialEq, serde::Deserialize, serde::Serialize)] - #[serde(tag = "t", content = "c")] - pub enum DrmNodeId { - DrmRenderNode(u64), - DrmPrimaryNode(u64), - } /// #[derive(Debug, Clone, PartialEq, serde::Deserialize, serde::Serialize)] #[serde(tag = "t", content = "c")] @@ -1720,10 +1713,10 @@ pub mod drawable { ); Ok(()) } - ///get the id of the primary device used for rendering, will return a render node id if supported by the driver + ///get the id of the primary device used for rendering, will return a DrmRenderNode id pub async fn get_primary_render_device_id( _client: &std::sync::Arc, - ) -> crate::node::NodeResult { + ) -> crate::node::NodeResult { let data = (); { let () = &data; @@ -1741,10 +1734,7 @@ pub mod drawable { e, })? .into_components(); - let result: DrmNodeId = stardust_xr_wire::flex::deserialize( - &message, - message_fds, - )?; + let result: u64 = stardust_xr_wire::flex::deserialize(&message, message_fds)?; let deserialized = result; tracing::trace!( "return" = ? deserialized, "Method return from server, {}::{}", "Interface", @@ -1755,13 +1745,13 @@ pub mod drawable { ///enumerates all the Dmatex formats supported by the server pub async fn enumerate_dmatex_formats( _client: &std::sync::Arc, - device_id: DrmNodeId, + render_node_id: u64, ) -> crate::node::NodeResult> { - let data = (device_id); + let data = (render_node_id); { - let (device_id) = &data; + let (render_node_id) = &data; tracing::trace!( - ? device_id, "Called method on server, {}::{}", "Interface", + ? render_node_id, "Called method on server, {}::{}", "Interface", "enumerate_dmatex_formats" ); } diff --git a/protocol/idl/drawable.kdl b/protocol/idl/drawable.kdl index 23fe918..eafd180 100644 --- a/protocol/idl/drawable.kdl +++ b/protocol/idl/drawable.kdl @@ -37,15 +37,15 @@ signal "unregister_dmatex" side="server" { } method "get_primary_render_device_id" side="server" { - description "get the id of the primary device used for rendering, will return a render node id if supported by the driver" + description "get the id of the primary device used for rendering, will return a DrmRenderNode id" - return type="union" union="DrmNodeId" + return type="id" } method "enumerate_dmatex_formats" side="server" { description "enumerates all the Dmatex formats supported by the server" - argument "device_id" type="union" union="DrmNodeId" + argument "render_node_id" type="id" return type="vec" member_type="struct" struct="DmatexFormatInfo" } @@ -76,13 +76,6 @@ union "DmatexSize" { option type="vec3" component_type="uint" name="dim3d" } -union "DrmNodeId" { - description "Drm Node Id used for selecting the correct gpu" - - option type="id" name="DrmRenderNode" - option type="id" name="DrmPrimaryNode" -} - signal "set_sky_tex" side="server" { description "Set the sky texture to a given HDRI file." From d97618022fd0830ec9dc1fdc42ffe31610396b27 Mon Sep 17 00:00:00 2001 From: Schmarni Date: Mon, 29 Dec 2025 07:20:47 +0100 Subject: [PATCH 12/16] fix(protocol/drawable): use dmatex size for size, oops Signed-off-by: Schmarni --- fusion/src/protocol.rs | 2 +- protocol/idl/drawable.kdl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fusion/src/protocol.rs b/fusion/src/protocol.rs index 2479594..2890c0f 100644 --- a/fusion/src/protocol.rs +++ b/fusion/src/protocol.rs @@ -1596,7 +1596,7 @@ pub mod drawable { ///Import a Dmatex, the imported Dmatex has to be manually unregistered, the returned id is Client Local pub async fn import_dmatex( _client: &std::sync::Arc, - size: DmatexPlane, + size: DmatexSize, format: u32, srgb: bool, array_layers: Option, diff --git a/protocol/idl/drawable.kdl b/protocol/idl/drawable.kdl index eafd180..b1e92f8 100644 --- a/protocol/idl/drawable.kdl +++ b/protocol/idl/drawable.kdl @@ -6,7 +6,7 @@ description "" method "import_dmatex" side="server" { description "Import a Dmatex, the imported Dmatex has to be manually unregistered, the returned id is Client Local" - argument "size" type="union" union="DmatexPlane" + argument "size" type="union" union="DmatexSize" argument "format" type="uint" description="the texture format as a drm_fourcc" argument "srgb" type="bool" description="try to use an SRGB color space version of the format, needed because drm_fourcc can't represent this information" argument "array_layers" type="uint" optional=true description="try to use an SRGB color space version of the format, needed because drm_fourcc can't represent this information" From 74406b69d03b84c1cbc90f09d24a9a53bf948c35 Mon Sep 17 00:00:00 2001 From: Schmarni Date: Mon, 29 Dec 2025 07:37:51 +0100 Subject: [PATCH 13/16] refactor(protocol/drawable): let clients provide dmatex ids and make loading a signal Signed-off-by: Schmarni --- protocol/idl/drawable.kdl | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/protocol/idl/drawable.kdl b/protocol/idl/drawable.kdl index b1e92f8..ed23f68 100644 --- a/protocol/idl/drawable.kdl +++ b/protocol/idl/drawable.kdl @@ -3,17 +3,16 @@ interface (u64)4 description "" -method "import_dmatex" side="server" { +signal "import_dmatex" side="server" { description "Import a Dmatex, the imported Dmatex has to be manually unregistered, the returned id is Client Local" + argument "dmatex_id" type="id" argument "size" type="union" union="DmatexSize" argument "format" type="uint" description="the texture format as a drm_fourcc" argument "srgb" type="bool" description="try to use an SRGB color space version of the format, needed because drm_fourcc can't represent this information" argument "array_layers" type="uint" optional=true description="try to use an SRGB color space version of the format, needed because drm_fourcc can't represent this information" argument "planes" type="vec" member_type="struct" struct="DmatexPlane" argument "timeline_syncobj_fd" type="fd" description="the fd carrying info for explicit sync, using the timeline variant of the drm_syncobj" - - return type="id" } method "export_dmatex_uid" side="server" { @@ -23,11 +22,10 @@ method "export_dmatex_uid" side="server" { return type="id" } -method "import_dmatex_uid" side="server" { +signal "import_dmatex_uid" side="server" { description "Imports a shared Dmatex Uid, holding this id will keep the underlying dmatex alive" + argument "dmatex_id" type="id" argument "dmatex_uid" type="id" - - return type="id" } signal "unregister_dmatex" side="server" { From 99cc4b8f0b70961386ff2e82bdf36cfdc1de9bea Mon Sep 17 00:00:00 2001 From: Schmarni Date: Tue, 30 Dec 2025 05:42:58 +0100 Subject: [PATCH 14/16] feat(gluon): make AbortOnDrop usefull outside gluon Signed-off-by: Schmarni --- fusion/src/protocol.rs | 61 ++++++++++++--------------------------- gluon/src/query_stream.rs | 24 +++++++++++---- 2 files changed, 37 insertions(+), 48 deletions(-) diff --git a/fusion/src/protocol.rs b/fusion/src/protocol.rs index 2890c0f..f66fb68 100644 --- a/fusion/src/protocol.rs +++ b/fusion/src/protocol.rs @@ -1594,16 +1594,18 @@ pub mod drawable { } } ///Import a Dmatex, the imported Dmatex has to be manually unregistered, the returned id is Client Local - pub async fn import_dmatex( + pub fn import_dmatex( _client: &std::sync::Arc, + dmatex_id: u64, size: DmatexSize, format: u32, srgb: bool, array_layers: Option, planes: &[DmatexPlane], timeline_syncobj_fd: stardust_xr_wire::fd::ProtocolFd, - ) -> crate::node::NodeResult { + ) -> crate::node::NodeResult<()> { let data = ( + dmatex_id, size, format, srgb, @@ -1611,30 +1613,17 @@ pub mod drawable { planes.iter().map(|a| Ok(a)).collect::>>()?, timeline_syncobj_fd, ); - { - let (size, format, srgb, array_layers, planes, timeline_syncobj_fd) = &data; - tracing::trace!( - ? size, ? format, ? srgb, ? array_layers, ? planes, ? - timeline_syncobj_fd, "Called method on server, {}::{}", "Interface", - "import_dmatex" - ); - } let (serialized_data, fds) = stardust_xr_wire::flex::serialize(&data)?; - let (message, message_fds) = _client + _client .message_sender_handle - .method(4u64, 0u64, 5202664904415071827u64, &serialized_data, fds) - .await? - .map_err(|e| crate::node::NodeError::ReturnedError { - e, - })? - .into_components(); - let result: u64 = stardust_xr_wire::flex::deserialize(&message, message_fds)?; - let deserialized = result; + .signal(4u64, 0u64, 5202664904415071827u64, &serialized_data, fds)?; + let (dmatex_id, size, format, srgb, array_layers, planes, timeline_syncobj_fd) = data; tracing::trace!( - "return" = ? deserialized, "Method return from server, {}::{}", "Interface", + ? dmatex_id, ? size, ? format, ? srgb, ? array_layers, ? planes, ? + timeline_syncobj_fd, "Sent signal to server, {}::{}", "Interface", "import_dmatex" ); - Ok(deserialized) + Ok(()) } ///Exports a Dmatex Uid for sharing between clients pub async fn export_dmatex_uid( @@ -1667,34 +1656,22 @@ pub mod drawable { Ok(deserialized) } ///Imports a shared Dmatex Uid, holding this id will keep the underlying dmatex alive - pub async fn import_dmatex_uid( + pub fn import_dmatex_uid( _client: &std::sync::Arc, + dmatex_id: u64, dmatex_uid: u64, - ) -> crate::node::NodeResult { - let data = (dmatex_uid); - { - let (dmatex_uid) = &data; - tracing::trace!( - ? dmatex_uid, "Called method on server, {}::{}", "Interface", - "import_dmatex_uid" - ); - } + ) -> crate::node::NodeResult<()> { + let data = (dmatex_id, dmatex_uid); let (serialized_data, fds) = stardust_xr_wire::flex::serialize(&data)?; - let (message, message_fds) = _client + _client .message_sender_handle - .method(4u64, 0u64, 5604115908701744320u64, &serialized_data, fds) - .await? - .map_err(|e| crate::node::NodeError::ReturnedError { - e, - })? - .into_components(); - let result: u64 = stardust_xr_wire::flex::deserialize(&message, message_fds)?; - let deserialized = result; + .signal(4u64, 0u64, 5604115908701744320u64, &serialized_data, fds)?; + let (dmatex_id, dmatex_uid) = data; tracing::trace!( - "return" = ? deserialized, "Method return from server, {}::{}", "Interface", + ? dmatex_id, ? dmatex_uid, "Sent signal to server, {}::{}", "Interface", "import_dmatex_uid" ); - Ok(deserialized) + Ok(()) } ///Mark a Dmatex as unused, once all ids referencing the same Dmatex are unregisterd the server may destroy its internal representation of the Dmatex, this invalidates the used handle pub fn unregister_dmatex( diff --git a/gluon/src/query_stream.rs b/gluon/src/query_stream.rs index 5d76052..cb8e4c2 100644 --- a/gluon/src/query_stream.rs +++ b/gluon/src/query_stream.rs @@ -16,7 +16,10 @@ use std::{ sync::Arc, task::{Context, Poll}, }; -use tokio::{sync::watch, task::AbortHandle}; +use tokio::{ + sync::watch, + task::{AbortHandle, JoinHandle}, +}; /// Generic lifecycle event for objects tracked by registry. /// @@ -68,14 +71,23 @@ pub struct AbortOnDrop { abort_handle: AbortHandle, } impl AbortOnDrop { - pub fn abort(&self) { - self.abort_handle.abort(); - } - pub fn is_finished(&self) -> bool { self.abort_handle.is_finished() } } +impl From> for AbortOnDrop { + fn from(value: JoinHandle) -> Self { + Self { + abort_handle: value.abort_handle(), + } + } +} + +impl From for AbortOnDrop { + fn from(abort_handle: AbortHandle) -> Self { + Self { abort_handle } + } +} impl Drop for AbortOnDrop { fn drop(&mut self) { self.abort_handle.abort(); @@ -458,7 +470,7 @@ mod tests { assert!(!abort_handle2.is_finished(), "Task should be running"); let _ = trigger_tx2.send(()); tokio::time::sleep(Duration::from_millis(50)).await; - abort_handle2.abort(); + drop(abort_handle2); tokio::time::sleep(Duration::from_millis(50)).await; } From 2872c05ffd7fc19f44b42c07d053bb4f551789c6 Mon Sep 17 00:00:00 2001 From: Schmarni Date: Wed, 31 Dec 2025 23:24:50 +0100 Subject: [PATCH 15/16] chore: cleanup deps Signed-off-by: Schmarni --- fusion/Cargo.toml | 7 +++---- gluon/Cargo.toml | 3 +-- protocol/Cargo.toml | 2 +- wire/Cargo.toml | 3 +-- 4 files changed, 6 insertions(+), 9 deletions(-) diff --git a/fusion/Cargo.toml b/fusion/Cargo.toml index 45aa199..0e103b9 100644 --- a/fusion/Cargo.toml +++ b/fusion/Cargo.toml @@ -2,9 +2,9 @@ edition = "2024" rust-version = "1.85" name = "stardust-xr-fusion" -version.workspace = true authors = ["Nova King "] description = "High level client library for the Stardust XR display server" +version.workspace = true license.workspace = true repository.workspace = true homepage.workspace = true @@ -37,14 +37,13 @@ zbus = { version = "5.11.0", features = [ "tokio", ], default-features = false } stardust-xr-wire = { version = "0.50.0", path = "../wire" } -stardust-xr-gluon = { version = "2.0.0", path = "../gluon" } +stardust-xr-gluon = { version = "0.50.0", path = "../gluon" } [build-dependencies] convert_case = "0.8.0" quote = "1.0.33" -stardust-xr-protocol = { version = "2.0.0", path = "../protocol" } +stardust-xr-protocol = { version = "0.50.0", path = "../protocol" } proc-macro2 = "1.0.71" -clap = { version = "4.4", features = ["derive"] } color-eyre = "0.6" syn = "2.0.106" prettyplease = "0.2.37" diff --git a/gluon/Cargo.toml b/gluon/Cargo.toml index 80c9eb0..9de6748 100644 --- a/gluon/Cargo.toml +++ b/gluon/Cargo.toml @@ -1,9 +1,9 @@ [package] edition = "2024" name = "stardust-xr-gluon" -version = "2.0.0" authors = ["Nova King "] description = "Base wire/serialization format for the Stardust XR display server" +version.workspace = true license.workspace = true repository.workspace = true homepage.workspace = true @@ -34,7 +34,6 @@ serde = { version = "1.0.196", features = ["derive"] } serde_repr = "0.1.18" # values -color-eyre = "0.6.2" shiva-color-rs = "0.0.1" mint = { version = "0.5.9", features = ["serde"] } From 8cf143b6e6431b449ffa54819522a27d465f88aa Mon Sep 17 00:00:00 2001 From: Schmarni Date: Fri, 2 Jan 2026 00:53:54 +0100 Subject: [PATCH 16/16] refactor(protocol/drawable): make drm_modifier a per dmatex concept instead of a per plane one, as that is how apis like vulkan actually treat it Signed-off-by: Schmarni --- fusion/src/protocol.rs | 23 ++++++++++++++++------- protocol/idl/drawable.kdl | 4 ++-- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/fusion/src/protocol.rs b/fusion/src/protocol.rs index f66fb68..43a9f48 100644 --- a/fusion/src/protocol.rs +++ b/fusion/src/protocol.rs @@ -1211,15 +1211,13 @@ pub mod drawable { ///drm_fourcc for the format pub format: u32, pub drm_modifier: u64, - pub supports_srgb: bool, + pub is_srgb: bool, ///How many memory planes does this format use pub planes: u32, } ///A single memory plane of a Dmatex #[derive(Debug, serde::Deserialize, serde::Serialize)] pub struct DmatexPlane { - ///The Drm modifier of this Dmatex memory plane - pub drm_modifier: u64, ///the underlying dmabuf fd for this plane pub dmabuf_fd: stardust_xr_wire::fd::ProtocolFd, ///offset of the data relevant to this Dmatex plane in the Dmatex memory @@ -1599,6 +1597,7 @@ pub mod drawable { dmatex_id: u64, size: DmatexSize, format: u32, + drm_format_modifier: u64, srgb: bool, array_layers: Option, planes: &[DmatexPlane], @@ -1608,6 +1607,7 @@ pub mod drawable { dmatex_id, size, format, + drm_format_modifier, srgb, array_layers.map(|o| Ok::<_, crate::node::NodeError>(o)).transpose()?, planes.iter().map(|a| Ok(a)).collect::>>()?, @@ -1617,11 +1617,20 @@ pub mod drawable { _client .message_sender_handle .signal(4u64, 0u64, 5202664904415071827u64, &serialized_data, fds)?; - let (dmatex_id, size, format, srgb, array_layers, planes, timeline_syncobj_fd) = data; + let ( + dmatex_id, + size, + format, + drm_format_modifier, + srgb, + array_layers, + planes, + timeline_syncobj_fd, + ) = data; tracing::trace!( - ? dmatex_id, ? size, ? format, ? srgb, ? array_layers, ? planes, ? - timeline_syncobj_fd, "Sent signal to server, {}::{}", "Interface", - "import_dmatex" + ? dmatex_id, ? size, ? format, ? drm_format_modifier, ? srgb, ? array_layers, + ? planes, ? timeline_syncobj_fd, "Sent signal to server, {}::{}", + "Interface", "import_dmatex" ); Ok(()) } diff --git a/protocol/idl/drawable.kdl b/protocol/idl/drawable.kdl index ed23f68..7911407 100644 --- a/protocol/idl/drawable.kdl +++ b/protocol/idl/drawable.kdl @@ -9,6 +9,7 @@ signal "import_dmatex" side="server" { argument "dmatex_id" type="id" argument "size" type="union" union="DmatexSize" argument "format" type="uint" description="the texture format as a drm_fourcc" + argument "drm_format_modifier" type="id" description="The Drm modifier of this format" argument "srgb" type="bool" description="try to use an SRGB color space version of the format, needed because drm_fourcc can't represent this information" argument "array_layers" type="uint" optional=true description="try to use an SRGB color space version of the format, needed because drm_fourcc can't represent this information" argument "planes" type="vec" member_type="struct" struct="DmatexPlane" @@ -52,13 +53,12 @@ struct "DmatexFormatInfo" { description "Description of a format supported by the server" field "format" type="uint" description="drm_fourcc for the format" field "drm_modifier" type="id" - field "supports_srgb" type="bool" + field "is_srgb" type="bool" field "planes" type="uint" description="How many memory planes does this format use" } struct "DmatexPlane" { description "A single memory plane of a Dmatex" - field "drm_modifier" type="id" description="The Drm modifier of this Dmatex memory plane" field "dmabuf_fd" type="fd" description="the underlying dmabuf fd for this plane" field "offset" type="uint" description="offset of the data relevant to this Dmatex plane in the Dmatex memory" field "row_size" type="uint" description="the number of bytes between the beginning of one pixel row to the next, if the Dmatex is 1d this should be 0"