diff --git a/api/sixtyfps-cpp/include/sixtyfps.h b/api/sixtyfps-cpp/include/sixtyfps.h index 1af1fda8f..8c3bafeba 100644 --- a/api/sixtyfps-cpp/include/sixtyfps.h +++ b/api/sixtyfps-cpp/include/sixtyfps.h @@ -96,11 +96,9 @@ public: sixtyfps_component_window_set_scale_factor(&inner, value); } - template - void free_graphics_resources(Component *c) const + void free_graphics_resources(const sixtyfps::Slice &items) const { - cbindgen_private::sixtyfps_component_window_free_graphics_resources( - &inner, vtable::VRef { &Component::component_type, c }); + cbindgen_private::sixtyfps_component_window_free_graphics_resources(&inner, &items); } void set_focus_item(vtable::VRef c, vtable::VRef item) diff --git a/sixtyfps_compiler/generator/cpp.rs b/sixtyfps_compiler/generator/cpp.rs index 532cca08e..b686109a9 100644 --- a/sixtyfps_compiler/generator/cpp.rs +++ b/sixtyfps_compiler/generator/cpp.rs @@ -894,6 +894,7 @@ fn generate_component( let mut repeated_input_branch = vec![]; let mut repeater_layout_code = vec![]; let mut tree_array = vec![]; + let mut item_names_and_vt_symbols = vec![]; let mut repeater_count = 0; super::build_array_helper(component, |item_rc, children_offset, is_flickable_rect| { let item = item_rc.borrow(); @@ -944,6 +945,8 @@ fn generate_component( children_offset, )); handle_item(item_rc, &mut component_struct, &mut init); + item_names_and_vt_symbols + .push((item.id.clone(), item.base_type.as_native().vtable_symbol.clone())); } }); @@ -979,7 +982,15 @@ fn generate_component( if component.parent_element.upgrade().is_some() { destructor.push("if (!parent) return;".to_owned()) } - destructor.push("self->window.free_graphics_resources(this);".into()); + if !item_names_and_vt_symbols.is_empty() { + destructor.push("sixtyfps::private_api::ItemRef items[] = {".into()); + destructor.push(item_names_and_vt_symbols.iter() + .map(|(item_name, vt_symbol)| + format!("{{ &sixtyfps::private_api::{vt}, const_cast{id})*>(&this->{id}) }}", id = item_name, vt = vt_symbol) + ).join(",")); + destructor.push("};".into()); + destructor.push("window.free_graphics_resources(sixtyfps::Slice{items, std::size(items)});".into()); + } component_struct.members.push(( Access::Public, diff --git a/sixtyfps_compiler/generator/rust.rs b/sixtyfps_compiler/generator/rust.rs index b3b131444..b00080786 100644 --- a/sixtyfps_compiler/generator/rust.rs +++ b/sixtyfps_compiler/generator/rust.rs @@ -611,7 +611,10 @@ fn generate_component( Some(quote!(impl sixtyfps::re_exports::PinnedDrop for #component_id { fn drop(self: core::pin::Pin<&mut #component_id>) { use sixtyfps::re_exports::*; - self.window.free_graphics_resources(VRef::new_pin(self.as_ref())); + let items = [ + #(VRef::new_pin(Self::FIELD_OFFSETS.#item_names.apply_pin(self.as_ref())),)* + ]; + self.window.free_graphics_resources(&Slice::from_slice(&items)); } })), quote!(#[pin_drop]), diff --git a/sixtyfps_runtime/corelib/eventloop.rs b/sixtyfps_runtime/corelib/eventloop.rs index 24110a238..c18ede91c 100644 --- a/sixtyfps_runtime/corelib/eventloop.rs +++ b/sixtyfps_runtime/corelib/eventloop.rs @@ -13,7 +13,11 @@ LICENSE END */ [GenericWindow] trait used by the generated code and the run-time to change aspects of windows on the screen. */ -use crate::component::{ComponentRc, ComponentVTable}; +use crate::{ + component::{ComponentRc, ComponentVTable}, + items::ItemRef, + slice::Slice, +}; use std::cell::RefCell; use std::{ convert::TryInto, @@ -91,10 +95,7 @@ pub trait GenericWindow { /// This function is called by the generated code when a component and therefore its tree of items are destroyed. The /// implementation typically uses this to free the underlying graphics resources cached via [`crate::graphics::RenderingCache`]. - fn free_graphics_resources( - self: Rc, - component: core::pin::Pin, - ); + fn free_graphics_resources<'a>(self: Rc, items: &Slice<'a, Pin>>); /// Installs a binding on the specified property that's toggled whenever the text cursor is supposed to be visible or not. fn set_cursor_blink_binding(&self, prop: &crate::properties::Property); @@ -151,11 +152,8 @@ impl ComponentWindow { /// This function is called by the generated code when a component and therefore its tree of items are destroyed. The /// implementation typically uses this to free the underlying graphics resources cached via [RenderingCache][`crate::graphics::RenderingCache`]. - pub fn free_graphics_resources( - &self, - component: core::pin::Pin, - ) { - self.0.clone().free_graphics_resources(component); + pub fn free_graphics_resources<'a>(&self, items: &Slice<'a, Pin>>) { + self.0.clone().free_graphics_resources(items); } /// Installs a binding on the specified property that's toggled whenever the text cursor is supposed to be visible or not. @@ -599,12 +597,12 @@ pub mod ffi { /// Sets the window scale factor, merely for testing purposes. #[no_mangle] - pub unsafe extern "C" fn sixtyfps_component_window_free_graphics_resources( + pub unsafe extern "C" fn sixtyfps_component_window_free_graphics_resources<'a>( handle: *const ComponentWindowOpaque, - component: Pin>, + items: &Slice<'a, Pin>>, ) { let window = &*(handle as *const ComponentWindow); - window.free_graphics_resources(component) + window.free_graphics_resources(items) } /// Sets the focus item. diff --git a/sixtyfps_runtime/corelib/graphics.rs b/sixtyfps_runtime/corelib/graphics.rs index f19d5a582..3ccfca747 100644 --- a/sixtyfps_runtime/corelib/graphics.rs +++ b/sixtyfps_runtime/corelib/graphics.rs @@ -20,7 +20,6 @@ LICENSE END */ created by the backend in a type-erased manner. */ extern crate alloc; -use crate::component::{ComponentRc, ComponentWeak}; use crate::input::{KeyEvent, KeyboardModifiers, MouseEvent, MouseEventType}; use crate::items::ItemRef; use crate::properties::{InterpolatedPropertyValue, Property, PropertyTracker}; @@ -29,6 +28,10 @@ use crate::rtti::{BuiltinItem, FieldInfo, PropertyInfo, ValueType}; use crate::SharedArray; #[cfg(feature = "rtti")] use crate::Signal; +use crate::{ + component::{ComponentRc, ComponentWeak}, + slice::Slice, +}; use auto_enums::auto_enum; use cgmath::Matrix4; @@ -820,14 +823,11 @@ impl crate::eventloop::GenericWindow for GraphicsWindo ) } - fn free_graphics_resources( - self: Rc, - component: core::pin::Pin, - ) { + fn free_graphics_resources<'a>(self: Rc, items: &Slice<'a, Pin>>) { match &*self.map_state.borrow() { GraphicsWindowBackendState::Unmapped => {} GraphicsWindowBackendState::Mapped(window) => { - crate::item_rendering::free_item_rendering_data(component, &window.rendering_cache) + crate::item_rendering::free_item_rendering_data(items, &window.rendering_cache) } } } diff --git a/sixtyfps_runtime/corelib/item_rendering.rs b/sixtyfps_runtime/corelib/item_rendering.rs index edfd30352..04aefbb56 100644 --- a/sixtyfps_runtime/corelib/item_rendering.rs +++ b/sixtyfps_runtime/corelib/item_rendering.rs @@ -14,8 +14,8 @@ use super::graphics::{ Frame, GraphicsBackend, GraphicsWindow, RenderingCache, RenderingPrimitivesBuilder, }; use super::items::ItemRef; -use crate::eventloop::ComponentWindow; use crate::item_tree::ItemVisitorResult; +use crate::{eventloop::ComponentWindow, slice::Slice}; use cgmath::{Matrix4, SquareMatrix, Vector3}; use std::cell::{Cell, RefCell}; @@ -123,18 +123,12 @@ pub(crate) fn render_component_items( ); } -pub(crate) fn free_item_rendering_data( - component: crate::component::ComponentRefPin, +pub(crate) fn free_item_rendering_data<'a, Backend: GraphicsBackend>( + items: &Slice<'a, core::pin::Pin>>, rendering_cache: &RefCell>, ) { - crate::item_tree::visit_items( - component, - crate::item_tree::TraversalOrder::FrontToBack, - |_, item, _| { - let cached_rendering_data = item.cached_rendering_data_offset(); - cached_rendering_data.release(rendering_cache); - ItemVisitorResult::Continue(()) - }, - (), - ); + for item in items.iter() { + let cached_rendering_data = item.cached_rendering_data_offset(); + cached_rendering_data.release(rendering_cache); + } } diff --git a/sixtyfps_runtime/interpreter/dynamic_component.rs b/sixtyfps_runtime/interpreter/dynamic_component.rs index 851f1bbc2..c26231d24 100644 --- a/sixtyfps_runtime/interpreter/dynamic_component.rs +++ b/sixtyfps_runtime/interpreter/dynamic_component.rs @@ -77,9 +77,19 @@ impl<'id> ComponentBox<'id> { impl<'id> Drop for ComponentBox<'id> { fn drop(&mut self) { - match eval::window_ref(self.borrow_instance()) { + let instance_ref = self.borrow_instance(); + match eval::window_ref(instance_ref) { Some(window) => { - window.free_graphics_resources(self.borrow()); + let items = self + .component_type + .items + .values() + .map(|item_within_component| unsafe { + item_within_component.item_from_component(instance_ref.as_ptr()) + }) + .collect::>(); + + window.free_graphics_resources(&Slice::from_slice(items.as_slice())); } None => {} }