From 7ae79fcba5d918dc100e58754683f4433cf7a5b8 Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Wed, 29 Dec 2021 15:55:44 +0100 Subject: [PATCH] winit: Support damage-tracking --- src/backend/winit/mod.rs | 72 +++++++++++++++++++++++++++++----------- 1 file changed, 53 insertions(+), 19 deletions(-) diff --git a/src/backend/winit/mod.rs b/src/backend/winit/mod.rs index 63a7a3f..46f5f7b 100644 --- a/src/backend/winit/mod.rs +++ b/src/backend/winit/mod.rs @@ -27,11 +27,11 @@ use crate::{ }, input::InputEvent, renderer::{ - gles2::{Gles2Error, Gles2Frame, Gles2Renderer}, - Bind, Renderer, Transform, Unbind, + gles2::{Gles2Error, Gles2Renderer}, + Bind, }, }, - utils::{Logical, Physical, Size}, + utils::{Logical, Physical, Rectangle, Size}, }; use std::{cell::RefCell, rc::Rc, time::Instant}; use wayland_egl as wegl; @@ -90,6 +90,7 @@ pub struct WinitGraphicsBackend { egl: Rc, window: Rc, size: Rc>, + damage_tracking: bool, resize_notification: Rc>>>, } @@ -220,6 +221,10 @@ where let egl = Rc::new(surface); let renderer = unsafe { Gles2Renderer::new(context, log.clone())? }; let resize_notification = Rc::new(Cell::new(None)); + let damage_tracking = display.extensions.iter().any(|ext| ext == "EGL_EXT_buffer_age") + && display.extensions.iter().any(|ext| { + ext == "EGL_KHR_swap_buffers_with_damage" || ext == "EGL_EXT_swap_buffers_with_damage" + }); Ok(( WinitGraphicsBackend { @@ -227,6 +232,7 @@ where _display: display, egl, renderer, + damage_tracking, size: size.clone(), resize_notification: resize_notification.clone(), }, @@ -281,28 +287,56 @@ impl WinitGraphicsBackend { &mut self.renderer } - /// Shortcut to `Renderer::render` with the current window dimensions - /// and this window set as the rendering target. - pub fn render(&mut self, rendering: F) -> Result - where - F: FnOnce(&mut Gles2Renderer, &mut Gles2Frame) -> R, - { + /// Bind the underlying window to the underlying renderer + pub fn bind(&mut self) -> Result<(), crate::backend::SwapBuffersError> { // Were we told to resize? if let Some(size) = self.resize_notification.take() { self.egl.resize(size.w, size.h, 0, 0); } - let size = { - let size = self.size.borrow(); - size.physical_size - }; - self.renderer.bind(self.egl.clone())?; - // Why is winit falling out of place with the coordinate system? - let result = self.renderer.render(size, Transform::Flipped180, rendering)?; - self.egl.swap_buffers()?; - self.renderer.unbind()?; - Ok(result) + Ok(()) + } + + /// Retrieve the buffer age of the current backbuffer of the window + pub fn buffer_age(&self) -> usize { + if self.damage_tracking { + self.egl.buffer_age() as usize + } else { + 0 + } + } + + /// Submits the back buffer to the window by swapping, requires the window to be previously bound (see [`WinitGraphicsBackend::bind`]). + pub fn submit( + &mut self, + damage: Option<&[Rectangle]>, + scale: f64, + ) -> Result<(), crate::backend::SwapBuffersError> { + let mut damage = if self.damage_tracking && damage.is_some() && !damage.unwrap().is_empty() { + let size = self + .size + .borrow() + .physical_size + .to_f64() + .to_logical(scale) + .to_i32_round::(); + let damage = damage + .unwrap() + .iter() + .map(|rect| { + Rectangle::from_loc_and_size((rect.loc.x, size.h - rect.loc.y - rect.size.h), rect.size) + .to_f64() + .to_physical(scale) + .to_i32_round::() + }) + .collect::>(); + Some(damage) + } else { + None + }; + self.egl.swap_buffers(damage.as_mut().map(|x| &mut **x))?; + Ok(()) } }