iris: share resource handle bookkeeping
This commit is contained in:
1 parent
51719ed121
commit
1be6cc2248
9 files changed
+631
-217
No files matched your search
+62
-82
@@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
Align, GlyphAtlas, GlyphKey, PaintId, PlacedGlyph, RegionAlign, Textures, WidgetId,
|
||||
util::{SlotId, SlotVec, Vec2},
|
||||
util::{Resources, RscHandle, StrongRscId, Vec2, WeakRscId},
|
||||
};
|
||||
use parley::{
|
||||
Alignment, AlignmentOptions, FontContext, FontFamily, FontStyle, FontWeight, GenericFamily,
|
||||
@@ -8,15 +8,12 @@ use parley::{
|
||||
fontique::{Blob, FontInfoOverride},
|
||||
};
|
||||
use std::{
|
||||
cell::{Ref, RefCell},
|
||||
cell::{Ref, RefCell, RefMut},
|
||||
collections::HashMap,
|
||||
fmt,
|
||||
ops::{Deref, DerefMut, Range},
|
||||
rc::Rc,
|
||||
sync::{
|
||||
Arc,
|
||||
mpsc::{Receiver, Sender, channel},
|
||||
},
|
||||
sync::Arc,
|
||||
};
|
||||
use swash::{
|
||||
FontRef,
|
||||
@@ -610,7 +607,7 @@ pub struct RenderedText {
|
||||
pub generation: u64,
|
||||
}
|
||||
|
||||
pub struct TextResource {
|
||||
pub struct TextRsc {
|
||||
buffer: TextBuffer,
|
||||
attrs: TextAttrs,
|
||||
rendered: Option<RenderedText>,
|
||||
@@ -619,7 +616,7 @@ pub struct TextResource {
|
||||
owner: Option<WidgetId>,
|
||||
}
|
||||
|
||||
impl TextResource {
|
||||
impl TextRsc {
|
||||
fn new(buffer: TextBuffer, attrs: TextAttrs) -> Self {
|
||||
Self {
|
||||
buffer,
|
||||
@@ -641,57 +638,54 @@ impl TextResource {
|
||||
/// compact [`TextHandle`] into this arena rather than owning Parley layouts.
|
||||
pub struct TextResources {
|
||||
data: TextData,
|
||||
entries: SlotVec<TextResource>,
|
||||
send: Sender<SlotId>,
|
||||
recv: Receiver<SlotId>,
|
||||
entries: Rc<RefCell<Resources<TextRsc>>>,
|
||||
}
|
||||
|
||||
impl TextResources {
|
||||
pub fn new() -> Self {
|
||||
let (send, recv) = channel();
|
||||
Self {
|
||||
data: TextData::default(),
|
||||
entries: SlotVec::new(),
|
||||
send,
|
||||
recv,
|
||||
entries: Rc::new(RefCell::new(Resources::new())),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add(resources: Rc<RefCell<Self>>, buffer: TextBuffer, attrs: TextAttrs) -> TextHandle {
|
||||
let (id, send) = {
|
||||
let entries = {
|
||||
let mut resources = resources.borrow_mut();
|
||||
resources.free_released();
|
||||
let id = resources.entries.add(TextResource::new(buffer, attrs));
|
||||
(id, resources.send.clone())
|
||||
resources.entries.clone()
|
||||
};
|
||||
TextHandle {
|
||||
id,
|
||||
rsc: RscHandle::add(entries, TextRsc::new(buffer, attrs)),
|
||||
resources,
|
||||
send,
|
||||
}
|
||||
}
|
||||
|
||||
fn entry(&self, id: SlotId) -> &TextResource {
|
||||
self.entries
|
||||
.get(id)
|
||||
.expect("text resource handle points at a released slot")
|
||||
pub fn handle(resources: Rc<RefCell<Self>>, id: StrongRscId<TextRsc>) -> TextHandle {
|
||||
let entries = resources.borrow().entries.clone();
|
||||
TextHandle {
|
||||
rsc: RscHandle::new(id, entries),
|
||||
resources,
|
||||
}
|
||||
}
|
||||
|
||||
fn entry_mut(&mut self, id: SlotId) -> &mut TextResource {
|
||||
self.entries
|
||||
.get_mut(id)
|
||||
.expect("text resource handle points at a released slot")
|
||||
pub fn upgrade(resources: Rc<RefCell<Self>>, id: WeakRscId<TextRsc>) -> Option<TextHandle> {
|
||||
let entries = {
|
||||
let mut resources = resources.borrow_mut();
|
||||
resources.free_released();
|
||||
resources.entries.clone()
|
||||
};
|
||||
let id = entries.borrow_mut().upgrade(id)?;
|
||||
Some(Self::handle(resources, id))
|
||||
}
|
||||
|
||||
pub fn free_released(&mut self) {
|
||||
for id in self.recv.try_iter() {
|
||||
self.entries.free(id);
|
||||
}
|
||||
self.entries.borrow_mut().apply(|_, _| {});
|
||||
}
|
||||
|
||||
pub fn invalidate_all(&mut self) -> Vec<WidgetId> {
|
||||
let mut owners = Vec::new();
|
||||
for resource in self.entries.values_mut() {
|
||||
for resource in self.entries.borrow_mut().values_mut() {
|
||||
resource.invalidate();
|
||||
if let Some(owner) = resource.owner
|
||||
&& !owners.contains(&owner)
|
||||
@@ -702,27 +696,22 @@ impl TextResources {
|
||||
owners
|
||||
}
|
||||
|
||||
fn shape(&mut self, id: SlotId) {
|
||||
fn shape(&mut self, resource: &mut TextRsc) {
|
||||
let density = self.data.density;
|
||||
let Self { data, entries, .. } = self;
|
||||
let resource = entries
|
||||
.get_mut(id)
|
||||
.expect("text resource handle points at a released slot");
|
||||
resource
|
||||
.buffer
|
||||
.shape(data, &resource.attrs, resource.width, density);
|
||||
.shape(&mut self.data, &resource.attrs, resource.width, density);
|
||||
}
|
||||
|
||||
fn render(
|
||||
&mut self,
|
||||
id: SlotId,
|
||||
resource: &mut TextRsc,
|
||||
width: Option<f32>,
|
||||
owner: WidgetId,
|
||||
textures: &mut Textures,
|
||||
density: f32,
|
||||
) -> (RenderedText, bool) {
|
||||
let atlas_generation = self.data.atlas.generation();
|
||||
let resource = self.entry_mut(id);
|
||||
resource.owner = Some(owner);
|
||||
if resource.width == width
|
||||
&& resource.density == density
|
||||
@@ -733,11 +722,7 @@ impl TextResources {
|
||||
}
|
||||
resource.width = width;
|
||||
resource.density = density;
|
||||
let Self { data, entries, .. } = self;
|
||||
let resource = entries
|
||||
.get_mut(id)
|
||||
.expect("text resource handle points at a released slot");
|
||||
let rendered = data.render(
|
||||
let rendered = self.data.render(
|
||||
&mut resource.buffer,
|
||||
&resource.attrs,
|
||||
width,
|
||||
@@ -773,28 +758,30 @@ impl DerefMut for TextResources {
|
||||
/// shared once per UI; constructing a handle does not allocate a resource of
|
||||
/// its own.
|
||||
pub struct TextHandle {
|
||||
id: SlotId,
|
||||
rsc: RscHandle<TextRsc>,
|
||||
resources: Rc<RefCell<TextResources>>,
|
||||
send: Sender<SlotId>,
|
||||
}
|
||||
|
||||
impl TextHandle {
|
||||
pub fn strong(&self) -> StrongRscId<TextRsc> {
|
||||
self.rsc.strong()
|
||||
}
|
||||
|
||||
pub fn weak(&self) -> WeakRscId<TextRsc> {
|
||||
self.rsc.weak()
|
||||
}
|
||||
|
||||
pub fn text(&self) -> Ref<'_, str> {
|
||||
Ref::map(self.resources.borrow(), |resources| {
|
||||
resources.entry(self.id).buffer.text()
|
||||
})
|
||||
Ref::map(self.rsc.get(), |resource| resource.buffer.text())
|
||||
}
|
||||
|
||||
pub fn attrs(&self) -> Ref<'_, TextAttrs> {
|
||||
Ref::map(self.resources.borrow(), |resources| {
|
||||
&resources.entry(self.id).attrs
|
||||
})
|
||||
Ref::map(self.rsc.get(), |resource| &resource.attrs)
|
||||
}
|
||||
|
||||
pub fn set_text(&mut self, text: impl Into<String>) -> bool {
|
||||
let text = text.into();
|
||||
let mut resources = self.resources.borrow_mut();
|
||||
let resource = resources.entry_mut(self.id);
|
||||
let mut resource = self.rsc.get_mut();
|
||||
if resource.buffer.text() == text {
|
||||
return false;
|
||||
}
|
||||
@@ -804,46 +791,45 @@ impl TextHandle {
|
||||
}
|
||||
|
||||
pub fn edit_text<R>(&mut self, edit: impl FnOnce(&mut String) -> R) -> R {
|
||||
let mut resources = self.resources.borrow_mut();
|
||||
let resource = resources.entry_mut(self.id);
|
||||
let mut resource = self.rsc.get_mut();
|
||||
resource.rendered = None;
|
||||
edit(resource.buffer.edit())
|
||||
}
|
||||
|
||||
pub fn set_spans(&mut self, spans: Vec<SpanStyle>) {
|
||||
let mut resources = self.resources.borrow_mut();
|
||||
let resource = resources.entry_mut(self.id);
|
||||
let mut resource = self.rsc.get_mut();
|
||||
resource.buffer.set_spans(spans);
|
||||
resource.rendered = None;
|
||||
}
|
||||
|
||||
pub fn update_attrs<R>(&mut self, update: impl FnOnce(&mut TextAttrs) -> R) -> R {
|
||||
let mut resources = self.resources.borrow_mut();
|
||||
let resource = resources.entry_mut(self.id);
|
||||
pub fn attrs_mut(&mut self) -> RefMut<'_, TextAttrs> {
|
||||
let mut resource = self.rsc.get_mut();
|
||||
resource.invalidate();
|
||||
update(&mut resource.attrs)
|
||||
RefMut::map(resource, |resource| &mut resource.attrs)
|
||||
}
|
||||
|
||||
pub fn rendered(&self) -> Option<RenderedText> {
|
||||
self.resources.borrow().entry(self.id).rendered.clone()
|
||||
self.rsc.get().rendered.clone()
|
||||
}
|
||||
|
||||
pub fn width(&self) -> Option<f32> {
|
||||
self.resources.borrow().entry(self.id).width
|
||||
self.rsc.get().width
|
||||
}
|
||||
|
||||
pub fn with_layout<R>(&self, f: impl FnOnce(&Layout<PaintId>, &str) -> R) -> R {
|
||||
let mut resources = self.resources.borrow_mut();
|
||||
resources.shape(self.id);
|
||||
let resource = resources.entry(self.id);
|
||||
let mut resource = self.rsc.get_mut_shared();
|
||||
resources.shape(&mut resource);
|
||||
f(resource.buffer.layout(), resource.buffer.text())
|
||||
}
|
||||
|
||||
pub fn layout(&self) -> Ref<'_, Layout<PaintId>> {
|
||||
self.resources.borrow_mut().shape(self.id);
|
||||
Ref::map(self.resources.borrow(), |resources| {
|
||||
resources.entry(self.id).buffer.layout()
|
||||
})
|
||||
{
|
||||
let mut resources = self.resources.borrow_mut();
|
||||
let mut resource = self.rsc.get_mut_shared();
|
||||
resources.shape(&mut resource);
|
||||
}
|
||||
Ref::map(self.rsc.get(), |resource| resource.buffer.layout())
|
||||
}
|
||||
|
||||
pub fn render(
|
||||
@@ -853,15 +839,9 @@ impl TextHandle {
|
||||
textures: &mut Textures,
|
||||
density: f32,
|
||||
) -> (RenderedText, bool) {
|
||||
self.resources
|
||||
.borrow_mut()
|
||||
.render(self.id, width, owner, textures, density)
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for TextHandle {
|
||||
fn drop(&mut self) {
|
||||
let _ = self.send.send(self.id);
|
||||
let mut resources = self.resources.borrow_mut();
|
||||
let mut resource = self.rsc.get_mut_shared();
|
||||
resources.render(&mut resource, width, owner, textures, density)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -886,11 +866,11 @@ mod tests {
|
||||
TextBuffer::new("temporary"),
|
||||
TextAttrs::default(),
|
||||
);
|
||||
assert_eq!(resources.borrow().entries.len(), 1);
|
||||
assert_eq!(resources.borrow().entries.borrow().len(), 1);
|
||||
|
||||
drop(text);
|
||||
resources.borrow_mut().free_released();
|
||||
|
||||
assert!(resources.borrow().entries.is_empty());
|
||||
assert!(resources.borrow().entries.borrow().is_empty());
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user