Draw only once on next frame callbacks
This commit is contained in:
parent
ed20397a2b
commit
bf73b40529
6 changed files with 47 additions and 78 deletions
|
@ -8,9 +8,9 @@ pub use model_context::*;
|
||||||
use refineable::Refineable;
|
use refineable::Refineable;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
current_platform, image_cache::ImageCache, AssetSource, Context, DisplayLinker, Executor,
|
current_platform, image_cache::ImageCache, AssetSource, Context, DisplayId, Executor, LayoutId,
|
||||||
LayoutId, MainThread, MainThreadOnly, Platform, RootView, SvgRenderer, Task, TextStyle,
|
MainThread, MainThreadOnly, Platform, PlatformDisplayLinker, RootView, SvgRenderer, Task,
|
||||||
TextStyleRefinement, TextSystem, Window, WindowContext, WindowHandle, WindowId,
|
TextStyle, TextStyleRefinement, TextSystem, Window, WindowContext, WindowHandle, WindowId,
|
||||||
};
|
};
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use collections::{HashMap, VecDeque};
|
use collections::{HashMap, VecDeque};
|
||||||
|
@ -56,13 +56,14 @@ impl App {
|
||||||
Self(Arc::new_cyclic(|this| {
|
Self(Arc::new_cyclic(|this| {
|
||||||
Mutex::new(AppContext {
|
Mutex::new(AppContext {
|
||||||
this: this.clone(),
|
this: this.clone(),
|
||||||
display_linker: Arc::new(DisplayLinker::new(platform.display_linker())),
|
|
||||||
text_system: Arc::new(TextSystem::new(platform.text_system())),
|
text_system: Arc::new(TextSystem::new(platform.text_system())),
|
||||||
|
pending_updates: 0,
|
||||||
|
display_linker: platform.display_linker(),
|
||||||
|
next_frame_callbacks: Default::default(),
|
||||||
platform: MainThreadOnly::new(platform, executor.clone()),
|
platform: MainThreadOnly::new(platform, executor.clone()),
|
||||||
executor,
|
executor,
|
||||||
svg_renderer: SvgRenderer::new(asset_source),
|
svg_renderer: SvgRenderer::new(asset_source),
|
||||||
image_cache: ImageCache::new(http_client),
|
image_cache: ImageCache::new(http_client),
|
||||||
pending_updates: 0,
|
|
||||||
text_style_stack: Vec::new(),
|
text_style_stack: Vec::new(),
|
||||||
state_stacks_by_type: HashMap::default(),
|
state_stacks_by_type: HashMap::default(),
|
||||||
unit_entity,
|
unit_entity,
|
||||||
|
@ -90,14 +91,16 @@ impl App {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Handlers = SmallVec<[Arc<dyn Fn(&mut AppContext) -> bool + Send + Sync + 'static>; 2]>;
|
type Handlers = SmallVec<[Arc<dyn Fn(&mut AppContext) -> bool + Send + Sync + 'static>; 2]>;
|
||||||
|
type FrameCallback = Box<dyn FnOnce(&mut WindowContext) + Send>;
|
||||||
|
|
||||||
pub struct AppContext {
|
pub struct AppContext {
|
||||||
this: Weak<Mutex<AppContext>>,
|
this: Weak<Mutex<AppContext>>,
|
||||||
platform: MainThreadOnly<dyn Platform>,
|
platform: MainThreadOnly<dyn Platform>,
|
||||||
text_system: Arc<TextSystem>,
|
text_system: Arc<TextSystem>,
|
||||||
pending_updates: usize,
|
pending_updates: usize,
|
||||||
|
pub(crate) display_linker: Arc<dyn PlatformDisplayLinker>,
|
||||||
|
pub(crate) next_frame_callbacks: HashMap<DisplayId, Vec<FrameCallback>>,
|
||||||
pub(crate) executor: Executor,
|
pub(crate) executor: Executor,
|
||||||
pub(crate) display_linker: Arc<DisplayLinker>,
|
|
||||||
pub(crate) svg_renderer: SvgRenderer,
|
pub(crate) svg_renderer: SvgRenderer,
|
||||||
pub(crate) image_cache: ImageCache,
|
pub(crate) image_cache: ImageCache,
|
||||||
pub(crate) text_style_stack: Vec<TextStyleRefinement>,
|
pub(crate) text_style_stack: Vec<TextStyleRefinement>,
|
||||||
|
@ -146,7 +149,6 @@ impl AppContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn flush_effects(&mut self) {
|
fn flush_effects(&mut self) {
|
||||||
dbg!("flush effects");
|
|
||||||
while let Some(effect) = self.pending_effects.pop_front() {
|
while let Some(effect) = self.pending_effects.pop_front() {
|
||||||
match effect {
|
match effect {
|
||||||
Effect::Notify(entity_id) => self.apply_notify_effect(entity_id),
|
Effect::Notify(entity_id) => self.apply_notify_effect(entity_id),
|
||||||
|
|
|
@ -1,56 +0,0 @@
|
||||||
use crate::{DisplayId, PlatformDisplayLinker, VideoTimestamp};
|
|
||||||
use collections::HashMap;
|
|
||||||
use parking_lot::Mutex;
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
type FrameCallback = Box<dyn FnOnce(&VideoTimestamp, &VideoTimestamp) + Send>;
|
|
||||||
|
|
||||||
pub struct DisplayLinker {
|
|
||||||
platform_linker: Arc<dyn PlatformDisplayLinker>,
|
|
||||||
next_frame_callbacks: Arc<Mutex<HashMap<DisplayId, Vec<FrameCallback>>>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DisplayLinker {
|
|
||||||
pub(crate) fn new(platform_linker: Arc<dyn PlatformDisplayLinker>) -> Self {
|
|
||||||
Self {
|
|
||||||
platform_linker,
|
|
||||||
next_frame_callbacks: Default::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn on_next_frame(
|
|
||||||
&self,
|
|
||||||
display_id: DisplayId,
|
|
||||||
callback: impl FnOnce(&VideoTimestamp, &VideoTimestamp) + Send + 'static,
|
|
||||||
) {
|
|
||||||
let next_frame_callbacks = self.next_frame_callbacks.clone();
|
|
||||||
let callback = Box::new(callback);
|
|
||||||
match self.next_frame_callbacks.lock().entry(display_id) {
|
|
||||||
collections::hash_map::Entry::Occupied(mut entry) => {
|
|
||||||
if entry.get().is_empty() {
|
|
||||||
self.platform_linker.start(display_id);
|
|
||||||
}
|
|
||||||
entry.get_mut().push(callback)
|
|
||||||
}
|
|
||||||
collections::hash_map::Entry::Vacant(entry) => {
|
|
||||||
// let platform_linker = self.platform_linker.clone();
|
|
||||||
self.platform_linker.set_output_callback(
|
|
||||||
display_id,
|
|
||||||
Box::new(move |current_time, output_time| {
|
|
||||||
for callback in next_frame_callbacks
|
|
||||||
.lock()
|
|
||||||
.get_mut(&display_id)
|
|
||||||
.unwrap()
|
|
||||||
.drain(..)
|
|
||||||
{
|
|
||||||
callback(current_time, output_time);
|
|
||||||
}
|
|
||||||
// platform_linker.stop(display_id);
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
self.platform_linker.start(display_id);
|
|
||||||
entry.insert(vec![callback]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -77,9 +77,7 @@ impl<S: Send + Sync + 'static> Element for Img<S> {
|
||||||
} else {
|
} else {
|
||||||
cx.spawn(|_, mut cx| async move {
|
cx.spawn(|_, mut cx| async move {
|
||||||
if image_future.await.log_err().is_some() {
|
if image_future.await.log_err().is_some() {
|
||||||
cx.on_next_frame(|cx| {
|
cx.on_next_frame(|cx| cx.notify());
|
||||||
cx.notify();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.detach()
|
.detach()
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
mod app;
|
mod app;
|
||||||
mod assets;
|
mod assets;
|
||||||
mod color;
|
mod color;
|
||||||
mod display_linker;
|
|
||||||
mod element;
|
mod element;
|
||||||
mod elements;
|
mod elements;
|
||||||
mod executor;
|
mod executor;
|
||||||
|
@ -23,7 +22,6 @@ pub use anyhow::Result;
|
||||||
pub use app::*;
|
pub use app::*;
|
||||||
pub use assets::*;
|
pub use assets::*;
|
||||||
pub use color::*;
|
pub use color::*;
|
||||||
pub use display_linker::*;
|
|
||||||
pub use element::*;
|
pub use element::*;
|
||||||
pub use elements::*;
|
pub use elements::*;
|
||||||
pub use executor::*;
|
pub use executor::*;
|
||||||
|
|
|
@ -131,8 +131,6 @@ impl MetalRenderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw(&mut self, scene: &mut Scene) {
|
pub fn draw(&mut self, scene: &mut Scene) {
|
||||||
dbg!("draw scene");
|
|
||||||
|
|
||||||
let layer = self.layer.clone();
|
let layer = self.layer.clone();
|
||||||
let viewport_size = layer.drawable_size();
|
let viewport_size = layer.drawable_size();
|
||||||
let viewport_size: Size<DevicePixels> = size(
|
let viewport_size: Size<DevicePixels> = size(
|
||||||
|
|
|
@ -144,11 +144,42 @@ impl<'a, 'w> WindowContext<'a, 'w> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_next_frame(&mut self, f: impl FnOnce(&mut WindowContext) + Send + 'static) {
|
pub fn on_next_frame(&mut self, f: impl FnOnce(&mut WindowContext) + Send + 'static) {
|
||||||
let cx = self.to_async();
|
let f = Box::new(f);
|
||||||
let display_id = self.window.display_id;
|
let display_id = self.window.display_id;
|
||||||
self.display_linker.on_next_frame(display_id, move |_, _| {
|
let async_cx = self.to_async();
|
||||||
cx.update(f).ok();
|
let app_cx = self.app_mut();
|
||||||
});
|
match app_cx.next_frame_callbacks.entry(display_id) {
|
||||||
|
collections::hash_map::Entry::Occupied(mut entry) => {
|
||||||
|
if entry.get().is_empty() {
|
||||||
|
app_cx.display_linker.start(display_id);
|
||||||
|
}
|
||||||
|
entry.get_mut().push(f);
|
||||||
|
}
|
||||||
|
collections::hash_map::Entry::Vacant(entry) => {
|
||||||
|
app_cx.display_linker.set_output_callback(
|
||||||
|
display_id,
|
||||||
|
Box::new(move |_current_time, _output_time| {
|
||||||
|
let _ = async_cx.update(|cx| {
|
||||||
|
let callbacks = cx
|
||||||
|
.next_frame_callbacks
|
||||||
|
.get_mut(&display_id)
|
||||||
|
.unwrap()
|
||||||
|
.drain(..)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
for callback in callbacks {
|
||||||
|
callback(cx);
|
||||||
|
}
|
||||||
|
|
||||||
|
if cx.next_frame_callbacks.get(&display_id).unwrap().is_empty() {
|
||||||
|
cx.display_linker.stop(display_id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
app_cx.display_linker.start(display_id);
|
||||||
|
entry.insert(vec![f]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn spawn<Fut, R>(
|
pub fn spawn<Fut, R>(
|
||||||
|
@ -590,11 +621,9 @@ impl<'a, 'w, S: Send + Sync + 'static> ViewContext<'a, 'w, S> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_next_frame(&mut self, f: impl FnOnce(&mut S, &mut ViewContext<S>) + Send + 'static) {
|
pub fn on_next_frame(&mut self, f: impl FnOnce(&mut S, &mut ViewContext<S>) + Send + 'static) {
|
||||||
let mut cx = self.to_async();
|
|
||||||
let entity = self.handle();
|
let entity = self.handle();
|
||||||
let display_id = self.window.display_id;
|
self.window_cx.on_next_frame(move |cx| {
|
||||||
self.display_linker.on_next_frame(display_id, move |_, _| {
|
entity.update(cx, f).ok();
|
||||||
entity.update(&mut cx, f).ok();
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue