update dependencies, add sort of busy loop

This commit is contained in:
Daniel Bulant 2023-10-26 11:30:49 +02:00
parent 7609ab3de3
commit 8d6cecdfb1
4 changed files with 679 additions and 250 deletions

814
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -7,9 +7,9 @@ edition = "2021"
[dependencies]
femtovg = "0.7.1"
glutin = "0.30.10"
glutin = "0.31.0"
raw-window-handle = "0.5.0"
winit = { version = "0.28.7", default-features = false }
glutin-winit = "0.3.0"
winit = { version = "0.29.2" }
glutin-winit = "0.4.2"
taffy = "0.3.16"
weak-table = "0.3.2"

View file

@ -1,8 +1,8 @@
use std::ops::{AddAssign, Add, SubAssign, Sub};
use taffy::{prelude::Size, style::Dimension, geometry::Point};
use winit::event::ElementState;
pub use winit::event::{TouchPhase, MouseScrollDelta, DeviceId, ModifiersState, VirtualKeyCode, ScanCode, MouseButton};
use winit::{event::ElementState, keyboard::{Key, KeyCode, ModifiersState}};
pub use winit::event::{TouchPhase, MouseScrollDelta, DeviceId, Modifiers, MouseButton};
use crate::SharedNode;
pub mod handler;
@ -62,16 +62,16 @@ pub enum InnerEvent {
#[derive(Clone, Debug, PartialEq)]
pub struct KeyboardEvent {
/// Logical location ("it's effect") of the key
pub key: Option<VirtualKeyCode>,
pub key: Option<Key>,
/// Physical location of the key
pub code: ScanCode,
pub code: KeyCode,
// altKey: bool,
// ctrlKey: bool,
// metaKey: bool,
// shiftKey: bool,
/// modifier keys pressed (alt, ctrl, shift or meta/logo/windows)
pub modifiers: ModifiersState,
pub modifiers: Modifiers,
// repeat: bool,
// char_code: u32,
@ -94,7 +94,7 @@ pub struct MouseEvent {
// metaKey: bool,
// shiftKey: bool,
/// modifier keys pressed (alt, ctrl, shift or meta/logo/windows)
pub modifiers: ModifiersState,
pub modifiers: Modifiers,
/// The location of the mouse relative to window
pub client: Location,
@ -194,19 +194,19 @@ impl Into<Size<Dimension>> for Location {
impl MouseEvent {
/// Returns `true` if the shift key is pressed.
pub fn shift(&self) -> bool {
self.modifiers.intersects(ModifiersState::SHIFT)
self.modifiers.state().intersects(ModifiersState::SHIFT)
}
/// Returns `true` if the control key is pressed.
pub fn ctrl(&self) -> bool {
self.modifiers.intersects(ModifiersState::CTRL)
self.modifiers.state().intersects(ModifiersState::CONTROL)
}
/// Returns `true` if the alt key is pressed.
pub fn alt(&self) -> bool {
self.modifiers.intersects(ModifiersState::ALT)
self.modifiers.state().intersects(ModifiersState::ALT)
}
/// Returns `true` if the logo key is pressed.
pub fn logo(&self) -> bool {
self.modifiers.intersects(ModifiersState::LOGO)
self.modifiers.state().intersects(ModifiersState::SUPER)
}
pub fn button_to_buttons(button: MouseButton) -> u8 {
@ -214,7 +214,9 @@ impl MouseEvent {
MouseButton::Left => 1,
MouseButton::Right => 2,
MouseButton::Middle => 4,
MouseButton::Other(n) => 1 << n
MouseButton::Back => 8,
MouseButton::Forward => 16,
MouseButton::Other(n) => 1 << (n + 4)
}
}
}

View file

@ -2,6 +2,7 @@ use std::collections::HashMap;
use std::num::NonZeroU32;
use std::ops::Deref;
use std::sync::{Arc, RwLock, Weak};
use std::time::Duration;
use events::{Location, MouseValue, NodeEvent, MouseEvent};
use femtovg::renderer::OpenGl;
@ -11,7 +12,7 @@ use glutin::{context::PossiblyCurrentContext, display::Display};
use glutin_winit::DisplayBuilder;
use nodes::{get_element_at, run_event_handlers, run_single_event_handlers};
use raw_window_handle::HasRawWindowHandle;
use winit::event::{Event, WindowEvent, ModifiersState, DeviceId};
use winit::event::{Event, WindowEvent, Modifiers, DeviceId};
use winit::event_loop::{ControlFlow, EventLoop};
use winit::window::WindowBuilder;
use winit::{dpi::PhysicalSize, window::Window};
@ -40,10 +41,14 @@ type WeakNode = Weak<RwLock<dyn Node>>;
type NodePtr = Option<Vec<WeakNode>>;
type NodeLayoutMap = PtrWeakKeyHashMap<Weak<RwLock<dyn Node>>, taffy::node::Node>;
pub fn run_event_loop(root_node: SharedNode) -> ! {
let event_loop = EventLoop::new();
pub fn run_event_loop(root_node: SharedNode) -> () {
let event_loop = EventLoop::new().unwrap();
let (buffer_context, gl_display, window, surface) = create_window(&event_loop);
if let Err(res) = surface.set_swap_interval(&buffer_context, glutin::surface::SwapInterval::Wait(NonZeroU32::new(1).unwrap())) {
dbg!("Could not set swap interval (vsync)", res);
}
let renderer = unsafe { OpenGl::new_from_function_cstr(|s| gl_display.get_proc_address(s) as *const _) }
.expect("Cannot create renderer");
@ -72,11 +77,11 @@ pub fn run_event_loop(root_node: SharedNode) -> ! {
let mut should_recompute = true;
let mut modifiers = ModifiersState::default();
let mut modifiers = Modifiers::default();
let focus_path: Option<Vec<WeakNode>> = None;
let mut mouse_values: HashMap<DeviceId, MouseValue> = HashMap::new();
event_loop.run(move |event, _target, control_flow| match event {
event_loop.run(move |event, target| match event {
Event::WindowEvent { event, .. } => match event {
WindowEvent::MouseWheel { device_id, delta, phase, .. } => {},
WindowEvent::CursorMoved { device_id, position, .. } => {
@ -162,7 +167,7 @@ pub fn run_event_loop(root_node: SharedNode) -> ! {
};
},
WindowEvent::ModifiersChanged(new_modifiers) => { modifiers = new_modifiers; },
WindowEvent::KeyboardInput { device_id, input, is_synthetic } => {},
WindowEvent::KeyboardInput { device_id, event, is_synthetic } => {},
WindowEvent::MouseInput { device_id, state, button, .. } => {
let mouse_value = mouse_values.get(&device_id);
let mut mouse_value = match mouse_value {
@ -206,7 +211,7 @@ pub fn run_event_loop(root_node: SharedNode) -> ! {
None => {}
}
},
WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
WindowEvent::CloseRequested => target.exit(),
WindowEvent::Resized(size) => {
let width: NonZeroU32 = NonZeroU32::new(size.width).unwrap();
let height: NonZeroU32 = NonZeroU32::new(size.height).unwrap();
@ -218,41 +223,51 @@ pub fn run_event_loop(root_node: SharedNode) -> ! {
window.request_redraw();
should_recompute = true;
},
WindowEvent::RedrawRequested => {
if should_recompute {
layout_recursively(&root, &mut context);
let src_nodes = context.node_layout.values().map(|v| v.to_owned()).collect::<Vec<_>>();
context.node_layout.remove_expired();
let dst_nodes = context.node_layout.values().map(|v| v.to_owned()).collect::<Vec<_>>();
for src_node in src_nodes {
if !dst_nodes.contains(&src_node) {
context.taffy.remove(src_node).unwrap();
dbg!("Removed node", src_node);
}
}
for (node, taffy_node) in context.node_layout.iter() {
let node = node.read().unwrap();
let node_style = node.style();
context.taffy.set_style(*taffy_node, node_style.layout.to_owned()).unwrap();
}
context.taffy.compute_layout(*context.node_layout.get(&root).unwrap(), Size::MAX_CONTENT).unwrap();
should_recompute = false;
// Additional optimizations could be done here
// - When setting styles, check that the styles aren't the same (taffy doesn't do that and instead always mark it as dirty)
// - taffy seems to always recompute (maybe internally checks dirtyness, I didn't look into it that much)
// - the weakmap dance (src_nodes, dst_nodes) could be avoided by changing the weakmap used
// (weakmap removes keys when you attempt to read them, we could change it so that we could iterate on them and remove them in one go)
// could perhaps be a significant boost regarding memory usage (and performance) during large layout changes
// dbg!("recomputed");
}
// dbg!(&root);
render(&buffer_context, &surface, &window, &mut context, &root);
}
_ => {}
},
Event::RedrawRequested(_) => {
if should_recompute {
layout_recursively(&root, &mut context);
let src_nodes = context.node_layout.values().map(|v| v.to_owned()).collect::<Vec<_>>();
context.node_layout.remove_expired();
let dst_nodes = context.node_layout.values().map(|v| v.to_owned()).collect::<Vec<_>>();
for src_node in src_nodes {
if !dst_nodes.contains(&src_node) {
context.taffy.remove(src_node).unwrap();
dbg!("Removed node", src_node);
}
Event::NewEvents(_) => {
if let Some(monitor) = window.current_monitor() {
if let Some(refresh_rate) = monitor.refresh_rate_millihertz() {
// dbg!(refresh_rate);
// some leeway before vsync
target.set_control_flow(ControlFlow::wait_duration(Duration::from_millis(1000 / refresh_rate as u64 - 100/refresh_rate as u64)));
window.request_redraw();
}
for (node, taffy_node) in context.node_layout.iter() {
let node = node.read().unwrap();
let node_style = node.style();
context.taffy.set_style(*taffy_node, node_style.layout.to_owned()).unwrap();
}
context.taffy.compute_layout(*context.node_layout.get(&root).unwrap(), Size::MAX_CONTENT).unwrap();
should_recompute = false;
// Additional optimizations could be done here
// - When setting styles, check that the styles aren't the same (taffy doesn't do that and instead always mark it as dirty)
// - taffy seems to always recompute (maybe internally checks dirtyness, I didn't look into it that much)
// - the weakmap dance (src_nodes, dst_nodes) could be avoided by changing the weakmap used
// (weakmap removes keys when you attempt to read them, we could change it so that we could iterate on them and remove them in one go)
// could perhaps be a significant boost regarding memory usage (and performance) during large layout changes
// dbg!("recomputed");
}
// dbg!(&root);
render(&buffer_context, &surface, &window, &mut context, &root);
},
// In the future, window should be created after resuming from suspend (for android support)
_ => {}
})
}).unwrap();
}
/// I have no idea if there's a better way to do this in rust...