From bf2d2561b8dde3e160438428b59c03c38a5f752a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Thu, 12 Nov 2020 02:51:26 +0100 Subject: [PATCH] Batch event processing in `UserInterface::update` --- glutin/src/application.rs | 36 +++++++------- native/src/program/state.rs | 17 ++++--- native/src/user_interface.rs | 93 ++++++++++++++++++++---------------- winit/src/application.rs | 36 +++++++------- 4 files changed, 95 insertions(+), 87 deletions(-) diff --git a/glutin/src/application.rs b/glutin/src/application.rs index 663654b1..e593f0ae 100644 --- a/glutin/src/application.rs +++ b/glutin/src/application.rs @@ -155,21 +155,32 @@ async fn run_instance( user_interface.draw(&mut renderer, state.cursor_position()); let mut mouse_interaction = mouse::Interaction::default(); + let mut events = Vec::new(); let mut messages = Vec::new(); - let mut is_clean = true; debug.startup_finished(); while let Some(event) = receiver.next().await { match event { - event::Event::NewEvents(_) => { - debug.event_processing_started(); - } event::Event::MainEventsCleared => { + if events.is_empty() && messages.is_empty() { + continue; + } + + debug.event_processing_started(); + + let statuses = user_interface.update( + &events, + state.cursor_position(), + clipboard.as_ref().map(|c| c as _), + &mut renderer, + &mut messages, + ); + debug.event_processing_finished(); - if is_clean && messages.is_empty() { - continue; + for event in events.drain(..).zip(statuses.into_iter()) { + runtime.broadcast(event); } if !messages.is_empty() { @@ -203,7 +214,6 @@ async fn run_instance( debug.draw_finished(); context.window().request_redraw(); - is_clean = true; } event::Event::UserEvent(message) => { messages.push(message); @@ -277,17 +287,7 @@ async fn run_instance( state.scale_factor(), state.modifiers(), ) { - let event_status = user_interface.update( - event.clone(), - state.cursor_position(), - clipboard.as_ref().map(|c| c as _), - &mut renderer, - &mut messages, - ); - - runtime.broadcast((event, event_status)); - - is_clean = false; + events.push(event); } } _ => {} diff --git a/native/src/program/state.rs b/native/src/program/state.rs index 5557347b..76283e30 100644 --- a/native/src/program/state.rs +++ b/native/src/program/state.rs @@ -122,17 +122,16 @@ where debug.event_processing_started(); let mut messages = Vec::new(); - for event in self.queued_events.drain(..) { - let _ = user_interface.update( - event, - cursor_position, - clipboard, - renderer, - &mut messages, - ); - } + let _ = user_interface.update( + &self.queued_events, + cursor_position, + clipboard, + renderer, + &mut messages, + ); messages.extend(self.queued_messages.drain(..)); + self.queued_events.clear(); debug.event_processing_finished(); if messages.is_empty() { diff --git a/native/src/user_interface.rs b/native/src/user_interface.rs index 793d341c..31bb6b99 100644 --- a/native/src/user_interface.rs +++ b/native/src/user_interface.rs @@ -182,16 +182,14 @@ where /// &mut renderer, /// ); /// - /// for event in events.drain(..) { - /// // Update the user interface - /// let _event_status = user_interface.update( - /// event, - /// cursor_position, - /// None, - /// &renderer, - /// &mut messages - /// ); - /// } + /// // Update the user interface + /// let event_statuses = user_interface.update( + /// &events, + /// cursor_position, + /// None, + /// &renderer, + /// &mut messages + /// ); /// /// cache = user_interface.into_cache(); /// @@ -203,13 +201,13 @@ where /// ``` pub fn update( &mut self, - event: Event, + events: &[Event], cursor_position: Point, clipboard: Option<&dyn Clipboard>, renderer: &Renderer, messages: &mut Vec, - ) -> event::Status { - let (base_cursor, overlay_status) = if let Some(mut overlay) = + ) -> Vec { + let (base_cursor, overlay_statuses) = if let Some(mut overlay) = self.root.overlay(Layout::new(&self.base.layout)) { let layer = Self::overlay_layer( @@ -219,14 +217,20 @@ where renderer, ); - let event_status = overlay.on_event( - event.clone(), - Layout::new(&layer.layout), - cursor_position, - messages, - renderer, - clipboard, - ); + let event_statuses = events + .iter() + .cloned() + .map(|event| { + overlay.on_event( + event, + Layout::new(&layer.layout), + cursor_position, + messages, + renderer, + clipboard, + ) + }) + .collect(); let base_cursor = if layer.layout.bounds().contains(cursor_position) { @@ -238,21 +242,28 @@ where self.overlay = Some(layer); - (base_cursor, event_status) + (base_cursor, event_statuses) } else { - (cursor_position, event::Status::Ignored) + (cursor_position, vec![event::Status::Ignored; events.len()]) }; - let event_status = self.root.widget.on_event( - event, - Layout::new(&self.base.layout), - base_cursor, - messages, - renderer, - clipboard, - ); + events + .iter() + .cloned() + .zip(overlay_statuses.into_iter()) + .map(|(event, overlay_status)| { + let event_status = self.root.widget.on_event( + event, + Layout::new(&self.base.layout), + base_cursor, + messages, + renderer, + clipboard, + ); - event_status.merge(overlay_status) + event_status.merge(overlay_status) + }) + .collect() } /// Draws the [`UserInterface`] with the provided [`Renderer`]. @@ -305,16 +316,14 @@ where /// &mut renderer, /// ); /// - /// for event in events.drain(..) { - /// // Update the user interface - /// let _event_status = user_interface.update( - /// event, - /// cursor_position, - /// None, - /// &renderer, - /// &mut messages - /// ); - /// } + /// // Update the user interface + /// let event_statuses = user_interface.update( + /// &events, + /// cursor_position, + /// None, + /// &renderer, + /// &mut messages + /// ); /// /// // Draw the user interface /// let mouse_cursor = user_interface.draw(&mut renderer, cursor_position); diff --git a/winit/src/application.rs b/winit/src/application.rs index 5c48fb32..ded60366 100644 --- a/winit/src/application.rs +++ b/winit/src/application.rs @@ -241,21 +241,32 @@ async fn run_instance( user_interface.draw(&mut renderer, state.cursor_position()); let mut mouse_interaction = mouse::Interaction::default(); + let mut events = Vec::new(); let mut messages = Vec::new(); - let mut is_clean = true; debug.startup_finished(); while let Some(event) = receiver.next().await { match event { - event::Event::NewEvents(_) => { - debug.event_processing_started(); - } event::Event::MainEventsCleared => { + if events.is_empty() && messages.is_empty() { + continue; + } + + debug.event_processing_started(); + + let statuses = user_interface.update( + &events, + state.cursor_position(), + clipboard.as_ref().map(|c| c as _), + &mut renderer, + &mut messages, + ); + debug.event_processing_finished(); - if is_clean && messages.is_empty() { - continue; + for event in events.drain(..).zip(statuses.into_iter()) { + runtime.broadcast(event); } if !messages.is_empty() { @@ -288,7 +299,6 @@ async fn run_instance( debug.draw_finished(); window.request_redraw(); - is_clean = true; } event::Event::UserEvent(message) => { messages.push(message); @@ -359,17 +369,7 @@ async fn run_instance( state.scale_factor(), state.modifiers(), ) { - let event_status = user_interface.update( - event.clone(), - state.cursor_position(), - clipboard.as_ref().map(|c| c as _), - &mut renderer, - &mut messages, - ); - - runtime.broadcast((event, event_status)); - - is_clean = false; + events.push(event); } } _ => {}