зеркало из https://github.com/mozilla/gecko-dev.git
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
This commit is contained in:
Родитель
d8ae659ab1
Коммит
074c0fe3ca
|
@ -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<RenderCompositor*>(aCompositor);
|
||||
compositor->Bind(aId, aOffset, aFboId);
|
||||
compositor->Bind(aId, aOffset, aFboId, aDirtyRect);
|
||||
}
|
||||
|
||||
void wr_compositor_create_surface(void* aCompositor, wr::NativeSurfaceId aId,
|
||||
|
|
|
@ -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) {
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -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<uint64_t, Tile> 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);
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -722,6 +722,7 @@ pub struct PictureCacheTarget {
|
|||
pub surface: ResolvedSurfaceTexture,
|
||||
pub alpha_batch_container: AlphaBatchContainer,
|
||||
pub clear_color: Option<ColorF>,
|
||||
pub dirty_rect: DeviceIntRect,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||
|
|
|
@ -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!();
|
||||
|
|
Загрузка…
Ссылка в новой задаче