mirror of
https://github.com/slint-ui/slint.git
synced 2025-10-01 06:11:16 +00:00

This is in preparation for allowing the run-time / items to clone VRc's of the component. ComponentVTable functions like visit_children_item contine to take a ComponentRefPin as "self" parameter type, as a VRc would not be supported by rust right now. That means the implementation then uses self_weak to obtain a strong self-reference.
136 lines
5 KiB
Rust
136 lines
5 KiB
Rust
/* LICENSE BEGIN
|
|
This file is part of the SixtyFPS Project -- https://sixtyfps.io
|
|
Copyright (c) 2020 Olivier Goffart <olivier.goffart@sixtyfps.io>
|
|
Copyright (c) 2020 Simon Hausmann <simon.hausmann@sixtyfps.io>
|
|
|
|
SPDX-License-Identifier: GPL-3.0-only
|
|
This file is also available under commercial licensing terms.
|
|
Please contact info@sixtyfps.io for more information.
|
|
LICENSE END */
|
|
#![warn(missing_docs)]
|
|
//! module for rendering the tree of items
|
|
|
|
use super::graphics::{
|
|
Frame, GraphicsBackend, GraphicsWindow, RenderingCache, RenderingPrimitivesBuilder,
|
|
};
|
|
use super::items::ItemRef;
|
|
use crate::component::ComponentRc;
|
|
use crate::eventloop::ComponentWindow;
|
|
use crate::item_tree::ItemVisitorResult;
|
|
use crate::slice::Slice;
|
|
use cgmath::{Matrix4, SquareMatrix, Vector3};
|
|
use std::cell::{Cell, RefCell};
|
|
|
|
/// This structure must be present in items that are Rendered and contains information.
|
|
/// Used by the backend.
|
|
#[derive(Default, Debug)]
|
|
#[repr(C)]
|
|
pub struct CachedRenderingData {
|
|
/// Used and modified by the backend, should be initialized to 0 by the user code
|
|
pub(crate) cache_index: Cell<usize>,
|
|
/// Set to false initially and when changes happen that require updating the cache
|
|
pub(crate) cache_ok: Cell<bool>,
|
|
}
|
|
|
|
impl CachedRenderingData {
|
|
pub(crate) fn ensure_up_to_date<Backend: GraphicsBackend>(
|
|
&self,
|
|
cache: &RefCell<RenderingCache<Backend>>,
|
|
item: core::pin::Pin<ItemRef>,
|
|
rendering_primitives_builder: &mut Backend::RenderingPrimitivesBuilder,
|
|
window: &std::rc::Rc<GraphicsWindow<Backend>>,
|
|
) {
|
|
let update_fn = || {
|
|
rendering_primitives_builder
|
|
.create(item.as_ref().rendering_primitive(&ComponentWindow::new(window.clone())))
|
|
};
|
|
|
|
if self.cache_ok.get() {
|
|
let index = self.cache_index.get();
|
|
let mut cache = cache.borrow_mut();
|
|
let existing_entry = cache.get_mut(index).unwrap();
|
|
if existing_entry.dependency_tracker.is_dirty() {
|
|
existing_entry.primitive =
|
|
existing_entry.dependency_tracker.as_ref().evaluate(update_fn)
|
|
}
|
|
} else {
|
|
self.cache_index.set(
|
|
cache
|
|
.borrow_mut()
|
|
.insert(crate::graphics::TrackingRenderingPrimitive::new(update_fn)),
|
|
);
|
|
self.cache_ok.set(true);
|
|
}
|
|
}
|
|
|
|
fn release<Backend: GraphicsBackend>(&self, cache: &RefCell<RenderingCache<Backend>>) {
|
|
if self.cache_ok.get() {
|
|
let index = self.cache_index.get();
|
|
cache.borrow_mut().remove(index);
|
|
}
|
|
}
|
|
}
|
|
|
|
pub(crate) fn update_item_rendering_data<Backend: GraphicsBackend>(
|
|
item: core::pin::Pin<ItemRef>,
|
|
rendering_cache: &RefCell<RenderingCache<Backend>>,
|
|
rendering_primitives_builder: &mut Backend::RenderingPrimitivesBuilder,
|
|
window: &std::rc::Rc<GraphicsWindow<Backend>>,
|
|
) {
|
|
let rendering_data = item.cached_rendering_data_offset();
|
|
rendering_data.ensure_up_to_date(rendering_cache, item, rendering_primitives_builder, window);
|
|
}
|
|
|
|
pub(crate) fn render_component_items<Backend: GraphicsBackend>(
|
|
component: &ComponentRc,
|
|
frame: &mut Backend::Frame,
|
|
rendering_cache: &RefCell<RenderingCache<Backend>>,
|
|
window: &std::rc::Rc<GraphicsWindow<Backend>>,
|
|
) {
|
|
let transform = Matrix4::identity();
|
|
let window = ComponentWindow::new(window.clone());
|
|
|
|
let frame = RefCell::new(frame);
|
|
|
|
crate::item_tree::visit_items_with_post_visit(
|
|
component,
|
|
crate::item_tree::TraversalOrder::BackToFront,
|
|
|_, item, transform| {
|
|
let origin = item.as_ref().geometry().origin;
|
|
let transform =
|
|
transform * Matrix4::from_translation(Vector3::new(origin.x, origin.y, 0.));
|
|
|
|
let cached_rendering_data = item.cached_rendering_data_offset();
|
|
let cleanup_primitives = if cached_rendering_data.cache_ok.get() {
|
|
let cache = rendering_cache.borrow();
|
|
let primitive =
|
|
&cache.get(cached_rendering_data.cache_index.get()).unwrap().primitive;
|
|
frame.borrow_mut().render_primitive(
|
|
&primitive,
|
|
&transform,
|
|
item.as_ref().rendering_variables(&window),
|
|
)
|
|
} else {
|
|
Vec::new()
|
|
};
|
|
|
|
(ItemVisitorResult::Continue(transform), (transform, cleanup_primitives))
|
|
},
|
|
|_, _, (transform, cleanup_primitives)| {
|
|
cleanup_primitives.into_iter().for_each(|primitive| {
|
|
frame.borrow_mut().render_primitive(&primitive, &transform, Default::default());
|
|
})
|
|
},
|
|
transform,
|
|
);
|
|
}
|
|
|
|
pub(crate) fn free_item_rendering_data<'a, Backend: GraphicsBackend>(
|
|
items: &Slice<'a, core::pin::Pin<ItemRef<'a>>>,
|
|
rendering_cache: &RefCell<RenderingCache<Backend>>,
|
|
) {
|
|
for item in items.iter() {
|
|
let cached_rendering_data = item.cached_rendering_data_offset();
|
|
cached_rendering_data.release(rendering_cache);
|
|
}
|
|
}
|