From 074c0fe3ca6b67603558c60a7cf33b260f6c867c Mon Sep 17 00:00:00 2001 From: Glenn Watson Date: Mon, 28 Oct 2019 20:56:42 +0000 Subject: [PATCH] Bug 1591527 - Integrate partial repainting with OS compositor surfaces. r=kvark,mstange This passes the existing dirty rect for a picture cache update through the native compositor interface, allowing compositors to only update a sub-rect of a tile. Also update the example to pass dirty rect to DirectComposition, and add debug drawing for compositor redraw region. Differential Revision: https://phabricator.services.mozilla.com/D50767 --HG-- extra : moz-landing-system : lando --- gfx/webrender_bindings/RenderCompositor.cpp | 5 ++- gfx/webrender_bindings/RenderCompositor.h | 2 +- gfx/webrender_bindings/src/bindings.rs | 3 ++ .../compositor-windows/src/lib.cpp | 38 +++++++++++++++---- .../compositor-windows/src/lib.rs | 12 ++++++ .../example-compositor/compositor/src/main.rs | 36 +++++++++++++++++- gfx/wr/webrender/src/composite.rs | 10 ++++- gfx/wr/webrender/src/frame_builder.rs | 5 ++- gfx/wr/webrender/src/render_target.rs | 1 + gfx/wr/webrender/src/renderer.rs | 2 +- 10 files changed, 99 insertions(+), 15 deletions(-) diff --git a/gfx/webrender_bindings/RenderCompositor.cpp b/gfx/webrender_bindings/RenderCompositor.cpp index 4997f68c6b89..392e65320bed 100644 --- a/gfx/webrender_bindings/RenderCompositor.cpp +++ b/gfx/webrender_bindings/RenderCompositor.cpp @@ -36,9 +36,10 @@ void wr_compositor_begin_frame(void* aCompositor) { } void wr_compositor_bind(void* aCompositor, wr::NativeSurfaceId aId, - wr::DeviceIntPoint* aOffset, uint32_t* aFboId) { + wr::DeviceIntPoint* aOffset, uint32_t* aFboId, + wr::DeviceIntRect aDirtyRect) { RenderCompositor* compositor = static_cast(aCompositor); - compositor->Bind(aId, aOffset, aFboId); + compositor->Bind(aId, aOffset, aFboId, aDirtyRect); } void wr_compositor_create_surface(void* aCompositor, wr::NativeSurfaceId aId, diff --git a/gfx/webrender_bindings/RenderCompositor.h b/gfx/webrender_bindings/RenderCompositor.h index 60ef2a4b224c..38072ccbd0c0 100644 --- a/gfx/webrender_bindings/RenderCompositor.h +++ b/gfx/webrender_bindings/RenderCompositor.h @@ -69,7 +69,7 @@ class RenderCompositor { virtual void CompositorBeginFrame() {} virtual void CompositorEndFrame() {} virtual void Bind(wr::NativeSurfaceId aId, wr::DeviceIntPoint* aOffset, - uint32_t* aFboId) {} + uint32_t* aFboId, wr::DeviceIntRect aDirtyRect) {} virtual void Unbind() {} virtual void CreateSurface(wr::NativeSurfaceId aId, wr::DeviceIntSize aSize) { } diff --git a/gfx/webrender_bindings/src/bindings.rs b/gfx/webrender_bindings/src/bindings.rs index 8f38864ecf67..5b2629ccf50a 100644 --- a/gfx/webrender_bindings/src/bindings.rs +++ b/gfx/webrender_bindings/src/bindings.rs @@ -1150,6 +1150,7 @@ extern "C" { id: NativeSurfaceId, offset: &mut DeviceIntPoint, fbo_id: &mut u32, + dirty_rect: DeviceIntRect, ); fn wr_compositor_unbind(compositor: *mut c_void); fn wr_compositor_begin_frame(compositor: *mut c_void); @@ -1194,6 +1195,7 @@ impl Compositor for WrCompositor { fn bind( &mut self, id: NativeSurfaceId, + dirty_rect: DeviceIntRect, ) -> NativeSurfaceInfo { let mut surface_info = NativeSurfaceInfo { origin: DeviceIntPoint::zero(), @@ -1206,6 +1208,7 @@ impl Compositor for WrCompositor { id, &mut surface_info.origin, &mut surface_info.fbo_id, + dirty_rect, ); } diff --git a/gfx/wr/example-compositor/compositor-windows/src/lib.cpp b/gfx/wr/example-compositor/compositor-windows/src/lib.cpp index 3a949c4195fa..58c22907d22d 100644 --- a/gfx/wr/example-compositor/compositor-windows/src/lib.cpp +++ b/gfx/wr/example-compositor/compositor-windows/src/lib.cpp @@ -23,7 +23,7 @@ struct Tile { // Represents the underlying DirectComposition surface texture that gets drawn into. IDCompositionSurface *pSurface; // Represents the node in the visual tree that defines the properties of this tile (clip, position etc). - IDCompositionVisual *pVisual; + IDCompositionVisual2 *pVisual; }; struct Window { @@ -37,7 +37,7 @@ struct Window { // Main interfaces to D3D11 and DirectComposition ID3D11Device *pD3D11Device; - IDCompositionDevice *pDCompDevice; + IDCompositionDesktopDevice *pDCompDevice; IDCompositionTarget *pDCompTarget; IDXGIDevice *pDXGIDevice; @@ -55,7 +55,8 @@ struct Window { // The root of the DC visual tree. Nothing is drawn on this, but // all child tiles are parented to here. - IDCompositionVisual *pRoot; + IDCompositionVisual2 *pRoot; + IDCompositionVisualDebug *pVisualDebug; // Maps the WR surface IDs to the DC representation of each tile. std::map tiles; }; @@ -145,9 +146,9 @@ extern "C" { assert(SUCCEEDED(hr)); // Create a DirectComposition device - hr = DCompositionCreateDevice( + hr = DCompositionCreateDevice2( window->pDXGIDevice, - __uuidof(IDCompositionDevice), + __uuidof(IDCompositionDesktopDevice), (void **) &window->pDCompDevice ); assert(SUCCEEDED(hr)); @@ -237,6 +238,15 @@ extern "C" { hr = window->pDCompTarget->SetRoot(window->pRoot); assert(SUCCEEDED(hr)); + hr = window->pRoot->QueryInterface( + __uuidof(IDCompositionVisualDebug), + (void **) &window->pVisualDebug + ); + assert(SUCCEEDED(hr)); + + // Uncomment this to see redraw regions during composite + //window->pVisualDebug->EnableRedrawRegions(); + EGLBoolean ok = eglMakeCurrent( window->EGLDisplay, window->fb_surface, @@ -262,6 +272,7 @@ extern "C" { eglReleaseDeviceANGLE(window->EGLDevice); window->pRoot->Release(); + window->pVisualDebug->Release(); window->pD3D11Device->Release(); window->pDXGIDevice->Release(); window->pDCompDevice->Release(); @@ -348,7 +359,11 @@ extern "C" { Window *window, uint64_t id, int *x_offset, - int *y_offset + int *y_offset, + int dirty_x0, + int dirty_y0, + int dirty_width, + int dirty_height ) { assert(window->tiles.count(id) == 1); Tile &tile = window->tiles[id]; @@ -359,15 +374,24 @@ extern "C" { // Inform DC that we want to draw on this surface. DC uses texture // atlases when the tiles are small. It returns an offset where the // client code must draw into this surface when this happens. + RECT update_rect; + update_rect.left = dirty_x0; + update_rect.top = dirty_y0; + update_rect.right = dirty_x0 + dirty_width; + update_rect.bottom = dirty_y0 + dirty_height; POINT offset; D3D11_TEXTURE2D_DESC desc; ID3D11Texture2D *pTexture; HRESULT hr = tile.pSurface->BeginDraw( - NULL, + &update_rect, __uuidof(ID3D11Texture2D), (void **) &pTexture, &offset ); + // DC includes the origin of the dirty / update rect in the draw offset, + // undo that here since WR expects it to be an absolute offset. + offset.x -= dirty_x0; + offset.y -= dirty_y0; assert(SUCCEEDED(hr)); pTexture->GetDesc(&desc); diff --git a/gfx/wr/example-compositor/compositor-windows/src/lib.rs b/gfx/wr/example-compositor/compositor-windows/src/lib.rs index 7193679fbbcb..e9d42ba36137 100644 --- a/gfx/wr/example-compositor/compositor-windows/src/lib.rs +++ b/gfx/wr/example-compositor/compositor-windows/src/lib.rs @@ -45,6 +45,10 @@ extern { id: u64, x_offset: &mut i32, y_offset: &mut i32, + dirty_x0: i32, + dirty_y0: i32, + dirty_width: i32, + dirty_height: i32, ); fn com_dc_unbind_surface(window: *mut Window); @@ -119,6 +123,10 @@ pub fn destroy_surface( pub fn bind_surface( window: *mut Window, id: u64, + dirty_x0: i32, + dirty_y0: i32, + dirty_width: i32, + dirty_height: i32, ) -> (i32, i32) { unsafe { let mut x_offset = 0; @@ -129,6 +137,10 @@ pub fn bind_surface( id, &mut x_offset, &mut y_offset, + dirty_x0, + dirty_y0, + dirty_width, + dirty_height, ); (x_offset, y_offset) diff --git a/gfx/wr/example-compositor/compositor/src/main.rs b/gfx/wr/example-compositor/compositor/src/main.rs index 0ec3877ee89a..71637b365c65 100644 --- a/gfx/wr/example-compositor/compositor/src/main.rs +++ b/gfx/wr/example-compositor/compositor/src/main.rs @@ -12,6 +12,7 @@ */ +use euclid::Angle; use gleam::gl; use std::ffi::CString; use std::sync::mpsc; @@ -55,10 +56,15 @@ impl webrender::Compositor for DirectCompositeInterface { fn bind( &mut self, id: webrender::NativeSurfaceId, + dirty_rect: DeviceIntRect, ) -> webrender::NativeSurfaceInfo { let (x, y) = compositor::bind_surface( self.window, id.0, + dirty_rect.origin.x, + dirty_rect.origin.y, + dirty_rect.size.width, + dirty_rect.size.height, ); webrender::NativeSurfaceInfo { @@ -148,7 +154,7 @@ fn main() { let debug_flags = DebugFlags::empty(); let compositor_config = if enable_compositor { webrender::CompositorConfig::Native { - max_update_rects: 0, + max_update_rects: 1, compositor: Box::new(DirectCompositeInterface::new(window)), } } else { @@ -192,6 +198,7 @@ fn main() { txn.set_root_pipeline(root_pipeline_id); txn.generate_frame(); api.send_transaction(document_id, txn); + let mut rotation_angle = 0.0; // Tick the compositor (in this sample, we don't block on UI events) while compositor::tick(window) { @@ -218,6 +225,33 @@ fn main() { ), ColorF::new(0.3, 0.3, 0.3, 1.0), ); + let rotation = LayoutTransform::create_rotation(0.0, 0.0, 1.0, Angle::degrees(rotation_angle)); + rotation_angle += 1.0; + if rotation_angle > 360.0 { + rotation_angle = 0.0; + } + let transform_origin = LayoutVector3D::new(400.0, 400.0, 0.0); + let transform = rotation.pre_translate(-transform_origin).post_translate(transform_origin); + let spatial_id = root_builder.push_reference_frame( + LayoutPoint::zero(), + SpatialId::root_scroll_node(root_pipeline_id), + TransformStyle::Flat, + PropertyBinding::Value(transform), + ReferenceFrameKind::Transform, + ); + root_builder.push_rect( + &CommonItemProperties::new( + LayoutRect::new( + LayoutPoint::new(300.0, 300.0), + LayoutSize::new(200.0, 200.0), + ), + SpaceAndClipInfo { + spatial_id, + clip_id: ClipId::root(root_pipeline_id), + }, + ), + ColorF::new(1.0, 0.0, 0.0, 1.0), + ); txn.set_display_list( current_epoch, None, diff --git a/gfx/wr/webrender/src/composite.rs b/gfx/wr/webrender/src/composite.rs index 0d6abc394a01..0103aba4fbdb 100644 --- a/gfx/wr/webrender/src/composite.rs +++ b/gfx/wr/webrender/src/composite.rs @@ -242,10 +242,18 @@ pub trait Compositor { /// Bind this surface such that WR can issue OpenGL commands /// that will target the surface. Returns an (x, y) offset /// where WR should draw into the surface. This can be set - /// to (0, 0) if the OS doesn't use texture atlases. + /// to (0, 0) if the OS doesn't use texture atlases. The dirty + /// rect is a local surface rect that specifies which part + /// of the surface needs to be updated. If max_update_rects + /// in CompositeConfig is 0, this will always be the size + /// of the entire surface. The returned offset is only + /// relevant to compositors that store surfaces in a texture + /// atlas (that is, WR expects that the dirty rect doesn't + /// affect the coordinates of the returned origin). fn bind( &mut self, id: NativeSurfaceId, + dirty_rect: DeviceIntRect, ) -> NativeSurfaceInfo; /// Unbind the surface. This is called by WR when it has diff --git a/gfx/wr/webrender/src/frame_builder.rs b/gfx/wr/webrender/src/frame_builder.rs index afaf83d7b44c..3c4ebfbd91ca 100644 --- a/gfx/wr/webrender/src/frame_builder.rs +++ b/gfx/wr/webrender/src/frame_builder.rs @@ -850,9 +850,9 @@ pub fn build_render_pass( let scissor_rect = match render_tasks[task_id].kind { RenderTaskKind::Picture(ref info) => info.scissor_rect, _ => unreachable!(), - }; + }.expect("bug: dirty rect must be set for picture cache tasks"); let mut batch_containers = Vec::new(); - let mut alpha_batch_container = AlphaBatchContainer::new(scissor_rect); + let mut alpha_batch_container = AlphaBatchContainer::new(Some(scissor_rect)); batcher.build( &mut batch_containers, &mut alpha_batch_container, @@ -865,6 +865,7 @@ pub fn build_render_pass( surface: surface.clone(), clear_color, alpha_batch_container, + dirty_rect: scissor_rect, }; picture_cache.push(target); diff --git a/gfx/wr/webrender/src/render_target.rs b/gfx/wr/webrender/src/render_target.rs index 3d3136bcaf3f..28c7d862a466 100644 --- a/gfx/wr/webrender/src/render_target.rs +++ b/gfx/wr/webrender/src/render_target.rs @@ -722,6 +722,7 @@ pub struct PictureCacheTarget { pub surface: ResolvedSurfaceTexture, pub alpha_batch_container: AlphaBatchContainer, pub clear_color: Option, + pub dirty_rect: DeviceIntRect, } #[cfg_attr(feature = "capture", derive(Serialize))] diff --git a/gfx/wr/webrender/src/renderer.rs b/gfx/wr/webrender/src/renderer.rs index a5e2debc48d7..4b233312129a 100644 --- a/gfx/wr/webrender/src/renderer.rs +++ b/gfx/wr/webrender/src/renderer.rs @@ -5057,7 +5057,7 @@ impl Renderer { ResolvedSurfaceTexture::NativeSurface { id, size, .. } => { let surface_info = match self.compositor_config { CompositorConfig::Native { ref mut compositor, .. } => { - compositor.bind(id) + compositor.bind(id, picture_target.dirty_rect) } CompositorConfig::Draw { .. } => { unreachable!();