mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 22:01:30 +00:00
Bug 1428766 - Update webrender to commit 722e8b104bf99d29d61ecb1fe456eebe89ad81fd. r=jrmuizel
MozReview-Commit-ID: GsDbUIfQFlm --HG-- extra : rebase_source : 073d14ce480c795fc6a1c0c3cd2d243a1f7d190c
This commit is contained in:
parent
1bc58767e9
commit
90321eec03
@ -175,4 +175,4 @@ Troubleshooting tips:
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
The version of WebRender currently in the tree is:
|
||||
a422f907be948b92bf5c7003a01f7744391a795e
|
||||
722e8b104bf99d29d61ecb1fe456eebe89ad81fd
|
||||
|
@ -582,61 +582,21 @@ impl AlphaBatcher {
|
||||
match prim_metadata.prim_kind {
|
||||
PrimitiveKind::Brush => {
|
||||
let brush = &ctx.prim_store.cpu_brushes[prim_metadata.cpu_prim_index.0];
|
||||
let base_instance = BrushInstance {
|
||||
picture_address: task_address,
|
||||
prim_address: prim_cache_address,
|
||||
|
||||
self.add_brush_to_batch(
|
||||
brush,
|
||||
prim_metadata,
|
||||
blend_mode,
|
||||
clip_chain_rect_index,
|
||||
scroll_id,
|
||||
clip_task_address,
|
||||
item_bounding_rect,
|
||||
prim_cache_address,
|
||||
scroll_id,
|
||||
task_address,
|
||||
transform_kind,
|
||||
z,
|
||||
segment_index: 0,
|
||||
user_data0: 0,
|
||||
user_data1: 0,
|
||||
};
|
||||
|
||||
match brush.segment_desc {
|
||||
Some(ref segment_desc) => {
|
||||
let opaque_batch = self.batch_list.opaque_batch_list.get_suitable_batch(
|
||||
brush.get_batch_key(
|
||||
BlendMode::None
|
||||
),
|
||||
item_bounding_rect
|
||||
);
|
||||
let alpha_batch = self.batch_list.alpha_batch_list.get_suitable_batch(
|
||||
brush.get_batch_key(
|
||||
BlendMode::PremultipliedAlpha
|
||||
),
|
||||
item_bounding_rect
|
||||
);
|
||||
|
||||
for (i, segment) in segment_desc.segments.iter().enumerate() {
|
||||
let is_inner = segment.edge_flags.is_empty();
|
||||
let needs_blending = !prim_metadata.opacity.is_opaque ||
|
||||
segment.clip_task_id.is_some() ||
|
||||
(!is_inner && transform_kind == TransformedRectKind::Complex);
|
||||
|
||||
let clip_task_address = segment
|
||||
.clip_task_id
|
||||
.map_or(OPAQUE_TASK_ADDRESS, |id| render_tasks.get_task_address(id));
|
||||
|
||||
let instance = PrimitiveInstance::from(BrushInstance {
|
||||
segment_index: i as i32,
|
||||
clip_task_address,
|
||||
..base_instance
|
||||
});
|
||||
|
||||
if needs_blending {
|
||||
alpha_batch.push(instance);
|
||||
} else {
|
||||
opaque_batch.push(instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
None => {
|
||||
let batch = self.batch_list.get_suitable_batch(brush.get_batch_key(blend_mode), item_bounding_rect);
|
||||
batch.push(PrimitiveInstance::from(base_instance));
|
||||
}
|
||||
}
|
||||
render_tasks,
|
||||
);
|
||||
}
|
||||
PrimitiveKind::Border => {
|
||||
let border_cpu =
|
||||
@ -1020,16 +980,20 @@ impl AlphaBatcher {
|
||||
secondary_textures,
|
||||
);
|
||||
let batch = self.batch_list.get_suitable_batch(key, &item_bounding_rect);
|
||||
let device_offset = (offset * LayerToWorldScale::new(1.0) * ctx.device_pixel_scale).round().to_i32();
|
||||
let content_rect = prim_metadata.local_rect.translate(&-offset);
|
||||
let rect =
|
||||
(content_rect * LayerToWorldScale::new(1.0) * ctx.device_pixel_scale).round()
|
||||
.to_i32();
|
||||
|
||||
let instance = CompositePrimitiveInstance::new(
|
||||
task_address,
|
||||
secondary_task_address,
|
||||
RenderTaskAddress(0),
|
||||
item_bounding_rect.origin.x - device_offset.x,
|
||||
item_bounding_rect.origin.y - device_offset.y,
|
||||
rect.origin.x,
|
||||
rect.origin.y,
|
||||
z,
|
||||
item_bounding_rect.size.width,
|
||||
item_bounding_rect.size.height,
|
||||
rect.size.width,
|
||||
rect.size.height,
|
||||
);
|
||||
|
||||
batch.push(PrimitiveInstance::from(instance));
|
||||
@ -1256,6 +1220,78 @@ impl AlphaBatcher {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn add_brush_to_batch(
|
||||
&mut self,
|
||||
brush: &BrushPrimitive,
|
||||
prim_metadata: &PrimitiveMetadata,
|
||||
blend_mode: BlendMode,
|
||||
clip_chain_rect_index: ClipChainRectIndex,
|
||||
clip_task_address: RenderTaskAddress,
|
||||
item_bounding_rect: &DeviceIntRect,
|
||||
prim_cache_address: GpuCacheAddress,
|
||||
scroll_id: ClipScrollNodeIndex,
|
||||
task_address: RenderTaskAddress,
|
||||
transform_kind: TransformedRectKind,
|
||||
z: i32,
|
||||
render_tasks: &RenderTaskTree,
|
||||
) {
|
||||
let base_instance = BrushInstance {
|
||||
picture_address: task_address,
|
||||
prim_address: prim_cache_address,
|
||||
clip_chain_rect_index,
|
||||
scroll_id,
|
||||
clip_task_address,
|
||||
z,
|
||||
segment_index: 0,
|
||||
user_data0: 0,
|
||||
user_data1: 0,
|
||||
};
|
||||
|
||||
match brush.segment_desc {
|
||||
Some(ref segment_desc) => {
|
||||
let opaque_batch = self.batch_list.opaque_batch_list.get_suitable_batch(
|
||||
brush.get_batch_key(
|
||||
BlendMode::None
|
||||
),
|
||||
item_bounding_rect
|
||||
);
|
||||
let alpha_batch = self.batch_list.alpha_batch_list.get_suitable_batch(
|
||||
brush.get_batch_key(
|
||||
BlendMode::PremultipliedAlpha
|
||||
),
|
||||
item_bounding_rect
|
||||
);
|
||||
|
||||
for (i, segment) in segment_desc.segments.iter().enumerate() {
|
||||
let is_inner = segment.edge_flags.is_empty();
|
||||
let needs_blending = !prim_metadata.opacity.is_opaque ||
|
||||
segment.clip_task_id.is_some() ||
|
||||
(!is_inner && transform_kind == TransformedRectKind::Complex);
|
||||
|
||||
let clip_task_address = segment
|
||||
.clip_task_id
|
||||
.map_or(OPAQUE_TASK_ADDRESS, |id| render_tasks.get_task_address(id));
|
||||
|
||||
let instance = PrimitiveInstance::from(BrushInstance {
|
||||
segment_index: i as i32,
|
||||
clip_task_address,
|
||||
..base_instance
|
||||
});
|
||||
|
||||
if needs_blending {
|
||||
alpha_batch.push(instance);
|
||||
} else {
|
||||
opaque_batch.push(instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
None => {
|
||||
let batch = self.batch_list.get_suitable_batch(brush.get_batch_key(blend_mode), item_bounding_rect);
|
||||
batch.push(PrimitiveInstance::from(base_instance));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl BrushPrimitive {
|
||||
|
@ -300,6 +300,7 @@ impl PicturePrimitive {
|
||||
prim_context: &PrimitiveContext,
|
||||
render_tasks: &mut RenderTaskTree,
|
||||
prim_screen_rect: &DeviceIntRect,
|
||||
prim_local_rect: &LayerRect,
|
||||
child_tasks: Vec<RenderTaskId>,
|
||||
parent_tasks: &mut Vec<RenderTaskId>,
|
||||
) {
|
||||
@ -344,12 +345,12 @@ impl PicturePrimitive {
|
||||
self.render_task_id = Some(blur_render_task_id);
|
||||
}
|
||||
Some(PictureCompositeMode::Filter(FilterOp::DropShadow(offset, blur_radius, color))) => {
|
||||
let screen_offset = (offset * content_scale).round().to_i32();
|
||||
let rect = (prim_local_rect.translate(&-offset) * content_scale).round().to_i32();
|
||||
let picture_task = RenderTask::new_picture(
|
||||
Some(prim_screen_rect.size),
|
||||
Some(rect.size),
|
||||
prim_index,
|
||||
RenderTargetKind::Color,
|
||||
ContentOrigin::Screen(prim_screen_rect.origin - screen_offset),
|
||||
ContentOrigin::Screen(rect.origin),
|
||||
PremultipliedColorF::TRANSPARENT,
|
||||
ClearMode::Transparent,
|
||||
child_tasks,
|
||||
|
@ -1175,6 +1175,7 @@ impl PrimitiveStore {
|
||||
prim_context,
|
||||
render_tasks,
|
||||
metadata.screen_rect.as_ref().expect("bug: trying to draw an off-screen picture!?"),
|
||||
&metadata.local_rect,
|
||||
child_tasks,
|
||||
parent_tasks,
|
||||
);
|
||||
@ -1770,7 +1771,7 @@ impl PrimitiveStore {
|
||||
let metadata = &mut self.cpu_metadata[prim_index.0];
|
||||
if metadata.local_rect.size.width <= 0.0 ||
|
||||
metadata.local_rect.size.height <= 0.0 {
|
||||
warn!("invalid primitive rect {:?}", metadata.local_rect);
|
||||
//warn!("invalid primitive rect {:?}", metadata.local_rect);
|
||||
return None;
|
||||
}
|
||||
|
||||
|
@ -66,12 +66,15 @@ pub fn should_record_msg(msg: &ApiMsg) -> bool {
|
||||
ApiMsg::UpdateResources(..) |
|
||||
ApiMsg::AddDocument { .. } |
|
||||
ApiMsg::DeleteDocument(..) => true,
|
||||
ApiMsg::UpdateDocument(_, ref msg) => {
|
||||
match *msg {
|
||||
DocumentMsg::GetScrollNodeState(..) |
|
||||
DocumentMsg::HitTest(..) => false,
|
||||
_ => true,
|
||||
ApiMsg::UpdateDocument(_, ref msgs) => {
|
||||
for msg in msgs {
|
||||
match *msg {
|
||||
DocumentMsg::GetScrollNodeState(..) |
|
||||
DocumentMsg::HitTest(..) => {}
|
||||
_ => { return true; }
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
|
@ -145,12 +145,33 @@ impl Document {
|
||||
}
|
||||
}
|
||||
|
||||
enum DocumentOp {
|
||||
Nop,
|
||||
Built,
|
||||
ScrolledNop,
|
||||
Scrolled(RenderedDocument),
|
||||
Rendered(RenderedDocument),
|
||||
struct DocumentOps {
|
||||
scroll: bool,
|
||||
build: bool,
|
||||
render: bool,
|
||||
}
|
||||
|
||||
impl DocumentOps {
|
||||
fn nop() -> Self {
|
||||
DocumentOps {
|
||||
scroll: false,
|
||||
build: false,
|
||||
render: false,
|
||||
}
|
||||
}
|
||||
|
||||
fn build() -> Self {
|
||||
DocumentOps {
|
||||
build: true,
|
||||
..DocumentOps::nop()
|
||||
}
|
||||
}
|
||||
|
||||
fn combine(&mut self, other: Self) {
|
||||
self.scroll = self.scroll || other.scroll;
|
||||
self.build = self.build || other.build;
|
||||
self.render = self.render || other.render;
|
||||
}
|
||||
}
|
||||
|
||||
/// The unique id for WR resource identification.
|
||||
@ -232,14 +253,14 @@ impl RenderBackend {
|
||||
message: DocumentMsg,
|
||||
frame_counter: u32,
|
||||
profile_counters: &mut BackendProfileCounters,
|
||||
) -> DocumentOp {
|
||||
) -> DocumentOps {
|
||||
let doc = self.documents.get_mut(&document_id).expect("No document?");
|
||||
|
||||
match message {
|
||||
//TODO: move view-related messages in a separate enum?
|
||||
DocumentMsg::SetPageZoom(factor) => {
|
||||
doc.view.page_zoom_factor = factor.get();
|
||||
DocumentOp::Nop
|
||||
DocumentOps::nop()
|
||||
}
|
||||
DocumentMsg::EnableFrameOutput(pipeline_id, enable) => {
|
||||
if enable {
|
||||
@ -247,15 +268,15 @@ impl RenderBackend {
|
||||
} else {
|
||||
doc.output_pipelines.remove(&pipeline_id);
|
||||
}
|
||||
DocumentOp::Nop
|
||||
DocumentOps::nop()
|
||||
}
|
||||
DocumentMsg::SetPinchZoom(factor) => {
|
||||
doc.view.pinch_zoom_factor = factor.get();
|
||||
DocumentOp::Nop
|
||||
DocumentOps::nop()
|
||||
}
|
||||
DocumentMsg::SetPan(pan) => {
|
||||
doc.view.pan = pan;
|
||||
DocumentOp::Nop
|
||||
DocumentOps::nop()
|
||||
}
|
||||
DocumentMsg::SetWindowParameters {
|
||||
window_size,
|
||||
@ -265,7 +286,7 @@ impl RenderBackend {
|
||||
doc.view.window_size = window_size;
|
||||
doc.view.inner_rect = inner_rect;
|
||||
doc.view.device_pixel_ratio = device_pixel_ratio;
|
||||
DocumentOp::Nop
|
||||
DocumentOps::nop()
|
||||
}
|
||||
DocumentMsg::SetDisplayList {
|
||||
epoch,
|
||||
@ -277,10 +298,13 @@ impl RenderBackend {
|
||||
preserve_frame_state,
|
||||
resources,
|
||||
} => {
|
||||
profile_scope!("SetDisplayList");
|
||||
// TODO: this will be removed from the SetDisplayList message soon.
|
||||
self.resource_cache.update_resources(
|
||||
resources,
|
||||
&mut profile_counters.resources
|
||||
);
|
||||
|
||||
self.resource_cache
|
||||
.update_resources(resources, &mut profile_counters.resources);
|
||||
profile_scope!("SetDisplayList");
|
||||
|
||||
let mut data;
|
||||
while {
|
||||
@ -316,7 +340,6 @@ impl RenderBackend {
|
||||
viewport_size,
|
||||
content_size,
|
||||
);
|
||||
doc.build_scene(&mut self.resource_cache);
|
||||
}
|
||||
|
||||
if let Some(ref mut ros) = doc.render_on_scroll {
|
||||
@ -337,7 +360,22 @@ impl RenderBackend {
|
||||
display_list_len,
|
||||
);
|
||||
|
||||
DocumentOp::Built
|
||||
DocumentOps::build()
|
||||
}
|
||||
DocumentMsg::UpdateResources(updates) => {
|
||||
profile_scope!("UpdateResources");
|
||||
|
||||
self.resource_cache.update_resources(
|
||||
updates,
|
||||
&mut profile_counters.resources
|
||||
);
|
||||
|
||||
DocumentOps::nop()
|
||||
}
|
||||
DocumentMsg::UpdateEpoch(pipeline_id, epoch) => {
|
||||
doc.scene.update_epoch(pipeline_id, epoch);
|
||||
doc.frame_ctx.update_epoch(pipeline_id, epoch);
|
||||
DocumentOps::nop()
|
||||
}
|
||||
DocumentMsg::UpdatePipelineResources { resources, pipeline_id, epoch } => {
|
||||
profile_scope!("UpdateResources");
|
||||
@ -348,40 +386,35 @@ impl RenderBackend {
|
||||
doc.scene.update_epoch(pipeline_id, epoch);
|
||||
doc.frame_ctx.update_epoch(pipeline_id, epoch);
|
||||
|
||||
DocumentOp::Nop
|
||||
DocumentOps::nop()
|
||||
}
|
||||
DocumentMsg::SetRootPipeline(pipeline_id) => {
|
||||
profile_scope!("SetRootPipeline");
|
||||
|
||||
doc.scene.set_root_pipeline_id(pipeline_id);
|
||||
if doc.scene.pipelines.get(&pipeline_id).is_some() {
|
||||
let _timer = profile_counters.total_time.timer();
|
||||
doc.build_scene(&mut self.resource_cache);
|
||||
DocumentOp::Built
|
||||
DocumentOps::build()
|
||||
} else {
|
||||
DocumentOp::Nop
|
||||
DocumentOps::nop()
|
||||
}
|
||||
}
|
||||
DocumentMsg::RemovePipeline(pipeline_id) => {
|
||||
profile_scope!("RemovePipeline");
|
||||
|
||||
doc.scene.remove_pipeline(pipeline_id);
|
||||
DocumentOp::Nop
|
||||
DocumentOps::nop()
|
||||
}
|
||||
DocumentMsg::Scroll(delta, cursor, move_phase) => {
|
||||
profile_scope!("Scroll");
|
||||
let _timer = profile_counters.total_time.timer();
|
||||
|
||||
if doc.frame_ctx.scroll(delta, cursor, move_phase) && doc.render_on_scroll == Some(true)
|
||||
{
|
||||
let frame = doc.render(
|
||||
&mut self.resource_cache,
|
||||
&mut self.gpu_cache,
|
||||
&mut profile_counters.resources,
|
||||
);
|
||||
DocumentOp::Scrolled(frame)
|
||||
} else {
|
||||
DocumentOp::ScrolledNop
|
||||
let should_render = doc.frame_ctx.scroll(delta, cursor, move_phase)
|
||||
&& doc.render_on_scroll == Some(true);
|
||||
|
||||
DocumentOps {
|
||||
scroll: true,
|
||||
build: false,
|
||||
render: should_render,
|
||||
}
|
||||
}
|
||||
DocumentMsg::HitTest(pipeline_id, point, flags, tx) => {
|
||||
@ -392,21 +425,19 @@ impl RenderBackend {
|
||||
.unwrap()
|
||||
.hit_test(cst, pipeline_id, point, flags);
|
||||
tx.send(result).unwrap();
|
||||
DocumentOp::Nop
|
||||
DocumentOps::nop()
|
||||
}
|
||||
DocumentMsg::ScrollNodeWithId(origin, id, clamp) => {
|
||||
profile_scope!("ScrollNodeWithScrollId");
|
||||
let _timer = profile_counters.total_time.timer();
|
||||
|
||||
if doc.frame_ctx.scroll_node(origin, id, clamp) && doc.render_on_scroll == Some(true) {
|
||||
let frame = doc.render(
|
||||
&mut self.resource_cache,
|
||||
&mut self.gpu_cache,
|
||||
&mut profile_counters.resources,
|
||||
);
|
||||
DocumentOp::Scrolled(frame)
|
||||
} else {
|
||||
DocumentOp::ScrolledNop
|
||||
let should_render = doc.frame_ctx.scroll_node(origin, id, clamp)
|
||||
&& doc.render_on_scroll == Some(true);
|
||||
|
||||
DocumentOps {
|
||||
scroll: true,
|
||||
build: false,
|
||||
render: should_render,
|
||||
}
|
||||
}
|
||||
DocumentMsg::TickScrollingBounce => {
|
||||
@ -414,44 +445,46 @@ impl RenderBackend {
|
||||
let _timer = profile_counters.total_time.timer();
|
||||
|
||||
doc.frame_ctx.tick_scrolling_bounce_animations();
|
||||
if doc.render_on_scroll == Some(true) {
|
||||
let frame = doc.render(
|
||||
&mut self.resource_cache,
|
||||
&mut self.gpu_cache,
|
||||
&mut profile_counters.resources,
|
||||
);
|
||||
DocumentOp::Scrolled(frame)
|
||||
} else {
|
||||
DocumentOp::ScrolledNop
|
||||
|
||||
DocumentOps {
|
||||
scroll: true,
|
||||
build: false,
|
||||
render: doc.render_on_scroll == Some(true),
|
||||
}
|
||||
}
|
||||
DocumentMsg::GetScrollNodeState(tx) => {
|
||||
profile_scope!("GetScrollNodeState");
|
||||
tx.send(doc.frame_ctx.get_scroll_node_state()).unwrap();
|
||||
DocumentOp::Nop
|
||||
DocumentOps::nop()
|
||||
}
|
||||
DocumentMsg::GenerateFrame(property_bindings) => {
|
||||
profile_scope!("GenerateFrame");
|
||||
DocumentMsg::UpdateDynamicProperties(property_bindings) => {
|
||||
// Ideally, when there are property bindings present,
|
||||
// we won't need to rebuild the entire frame here.
|
||||
// However, to avoid conflicts with the ongoing work to
|
||||
// refactor how scroll roots + transforms work, this
|
||||
// just rebuilds the frame if there are animated property
|
||||
// bindings present for now.
|
||||
// TODO(gw): Once the scrolling / reference frame changes
|
||||
// are completed, optimize the internals of
|
||||
// animated properties to not require a full
|
||||
// rebuild of the frame!
|
||||
doc.scene.properties.set_properties(property_bindings);
|
||||
DocumentOps::build()
|
||||
}
|
||||
DocumentMsg::GenerateFrame => {
|
||||
let _timer = profile_counters.total_time.timer();
|
||||
|
||||
if let Some(property_bindings) = property_bindings {
|
||||
doc.scene.properties.set_properties(property_bindings);
|
||||
}
|
||||
let mut op = DocumentOps::nop();
|
||||
|
||||
if let Some(ref mut ros) = doc.render_on_scroll {
|
||||
*ros = true;
|
||||
}
|
||||
|
||||
if doc.scene.root_pipeline_id.is_some() {
|
||||
let frame = doc.render(
|
||||
&mut self.resource_cache,
|
||||
&mut self.gpu_cache,
|
||||
&mut profile_counters.resources,
|
||||
);
|
||||
DocumentOp::Rendered(frame)
|
||||
} else {
|
||||
DocumentOp::ScrolledNop
|
||||
op.render = true;
|
||||
}
|
||||
|
||||
op
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -515,30 +548,6 @@ impl RenderBackend {
|
||||
);
|
||||
self.documents.insert(document_id, document);
|
||||
}
|
||||
ApiMsg::UpdateDocument(document_id, doc_msg) => match self.process_document(
|
||||
document_id,
|
||||
doc_msg,
|
||||
frame_counter,
|
||||
&mut profile_counters,
|
||||
) {
|
||||
DocumentOp::Nop => {}
|
||||
DocumentOp::Built => {}
|
||||
DocumentOp::ScrolledNop => {
|
||||
self.notify_compositor_of_new_scroll_document(document_id, false);
|
||||
}
|
||||
DocumentOp::Scrolled(doc) => {
|
||||
self.publish_document(document_id, doc, &mut profile_counters);
|
||||
self.notify_compositor_of_new_scroll_document(document_id, true);
|
||||
}
|
||||
DocumentOp::Rendered(doc) => {
|
||||
frame_counter += 1;
|
||||
self.publish_document_and_notify_compositor(
|
||||
document_id,
|
||||
doc,
|
||||
&mut profile_counters,
|
||||
);
|
||||
}
|
||||
},
|
||||
ApiMsg::DeleteDocument(document_id) => {
|
||||
self.documents.remove(&document_id);
|
||||
}
|
||||
@ -614,42 +623,71 @@ impl RenderBackend {
|
||||
self.notifier.shut_down();
|
||||
break;
|
||||
}
|
||||
ApiMsg::UpdateDocument(document_id, doc_msgs) => {
|
||||
self.update_document(
|
||||
document_id,
|
||||
doc_msgs,
|
||||
&mut frame_counter,
|
||||
&mut profile_counters
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn publish_document(
|
||||
fn update_document(
|
||||
&mut self,
|
||||
document_id: DocumentId,
|
||||
document: RenderedDocument,
|
||||
doc_msgs: Vec<DocumentMsg>,
|
||||
frame_counter: &mut u32,
|
||||
profile_counters: &mut BackendProfileCounters,
|
||||
) {
|
||||
let pending_update = self.resource_cache.pending_updates();
|
||||
let msg = ResultMsg::PublishDocument(document_id, document, pending_update, profile_counters.clone());
|
||||
self.result_tx.send(msg).unwrap();
|
||||
profile_counters.reset();
|
||||
let mut op = DocumentOps::nop();
|
||||
for doc_msg in doc_msgs {
|
||||
op.combine(
|
||||
self.process_document(
|
||||
document_id,
|
||||
doc_msg,
|
||||
*frame_counter,
|
||||
profile_counters,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
let doc = self.documents.get_mut(&document_id).unwrap();
|
||||
|
||||
if op.build {
|
||||
profile_scope!("build scene");
|
||||
doc.build_scene(&mut self.resource_cache);
|
||||
}
|
||||
|
||||
if op.render {
|
||||
profile_scope!("generate frame");
|
||||
|
||||
*frame_counter += 1;
|
||||
let rendered_document = doc.render(
|
||||
&mut self.resource_cache,
|
||||
&mut self.gpu_cache,
|
||||
&mut profile_counters.resources,
|
||||
);
|
||||
|
||||
// Publish the frame
|
||||
let pending_update = self.resource_cache.pending_updates();
|
||||
let msg = ResultMsg::PublishDocument(
|
||||
document_id,
|
||||
rendered_document,
|
||||
pending_update,
|
||||
profile_counters.clone()
|
||||
);
|
||||
self.result_tx.send(msg).unwrap();
|
||||
profile_counters.reset();
|
||||
}
|
||||
|
||||
if op.render || op.scroll {
|
||||
self.notifier.new_document_ready(document_id, op.scroll, op.render);
|
||||
}
|
||||
}
|
||||
|
||||
fn publish_document_and_notify_compositor(
|
||||
&mut self,
|
||||
document_id: DocumentId,
|
||||
document: RenderedDocument,
|
||||
profile_counters: &mut BackendProfileCounters,
|
||||
) {
|
||||
self.publish_document(document_id, document, profile_counters);
|
||||
|
||||
self.notifier.new_document_ready(document_id, false, true);
|
||||
}
|
||||
|
||||
fn notify_compositor_of_new_scroll_document(
|
||||
&self,
|
||||
document_id: DocumentId,
|
||||
composite_needed: bool,
|
||||
) {
|
||||
self.notifier.new_document_ready(document_id, true, composite_needed);
|
||||
}
|
||||
|
||||
|
||||
#[cfg(not(feature = "debugger"))]
|
||||
fn get_docs_for_debugger(&self) -> String {
|
||||
String::new()
|
||||
@ -870,7 +908,18 @@ impl RenderBackend {
|
||||
&mut self.gpu_cache,
|
||||
&mut profile_counters.resources,
|
||||
);
|
||||
self.publish_document_and_notify_compositor(id, render_doc, profile_counters);
|
||||
|
||||
let pending_update = self.resource_cache.pending_updates();
|
||||
let msg = ResultMsg::PublishDocument(
|
||||
id,
|
||||
render_doc,
|
||||
pending_update,
|
||||
profile_counters.clone()
|
||||
);
|
||||
self.result_tx.send(msg).unwrap();
|
||||
profile_counters.reset();
|
||||
|
||||
self.notifier.new_document_ready(id, false, true);
|
||||
|
||||
self.documents.insert(id, doc);
|
||||
}
|
||||
|
@ -2470,6 +2470,16 @@ impl Renderer {
|
||||
fn debug_alpha_target(target: &AlphaRenderTarget) -> debug_server::Target {
|
||||
let mut debug_target = debug_server::Target::new("A8");
|
||||
|
||||
debug_target.add(
|
||||
debug_server::BatchKind::Cache,
|
||||
"Scalings",
|
||||
target.scalings.len(),
|
||||
);
|
||||
debug_target.add(
|
||||
debug_server::BatchKind::Cache,
|
||||
"Zero Clears",
|
||||
target.zero_clears.len(),
|
||||
);
|
||||
debug_target.add(
|
||||
debug_server::BatchKind::Clip,
|
||||
"Clear",
|
||||
@ -2516,6 +2526,16 @@ impl Renderer {
|
||||
fn debug_color_target(target: &ColorRenderTarget) -> debug_server::Target {
|
||||
let mut debug_target = debug_server::Target::new("RGBA8");
|
||||
|
||||
debug_target.add(
|
||||
debug_server::BatchKind::Cache,
|
||||
"Scalings",
|
||||
target.scalings.len(),
|
||||
);
|
||||
debug_target.add(
|
||||
debug_server::BatchKind::Cache,
|
||||
"Readbacks",
|
||||
target.readbacks.len(),
|
||||
);
|
||||
debug_target.add(
|
||||
debug_server::BatchKind::Cache,
|
||||
"Vertical Blur",
|
||||
|
@ -123,6 +123,174 @@ impl ResourceUpdates {
|
||||
}
|
||||
}
|
||||
|
||||
/// A Transaction is a group of commands to apply atomically to a document.
|
||||
///
|
||||
/// This mechanism ensures that:
|
||||
/// - no other message can be interleaved between two commands that need to be applied together.
|
||||
/// - no redundant work is performed if two commands in the same transaction cause the scene or
|
||||
/// the frame to be rebuilt.
|
||||
pub struct Transaction {
|
||||
ops: Vec<DocumentMsg>,
|
||||
payloads: Vec<Payload>,
|
||||
}
|
||||
|
||||
impl Transaction {
|
||||
pub fn new() -> Self {
|
||||
Transaction {
|
||||
ops: Vec::new(),
|
||||
payloads: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.ops.is_empty()
|
||||
}
|
||||
|
||||
pub fn update_epoch(&mut self, pipeline_id: PipelineId, epoch: Epoch) {
|
||||
self.ops.push(DocumentMsg::UpdateEpoch(pipeline_id, epoch));
|
||||
}
|
||||
|
||||
/// Sets the root pipeline.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use webrender_api::{DeviceUintSize, PipelineId, RenderApiSender, Transaction};
|
||||
/// # fn example() {
|
||||
/// let pipeline_id = PipelineId(0, 0);
|
||||
/// let mut txn = Transaction::new();
|
||||
/// txn.set_root_pipeline(pipeline_id);
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn set_root_pipeline(&mut self, pipeline_id: PipelineId) {
|
||||
self.ops.push(DocumentMsg::SetRootPipeline(pipeline_id));
|
||||
}
|
||||
|
||||
/// Removes data associated with a pipeline from the internal data structures.
|
||||
/// If the specified `pipeline_id` is for the root pipeline, the root pipeline
|
||||
/// is reset back to `None`.
|
||||
pub fn remove_pipeline(&mut self, pipeline_id: PipelineId) {
|
||||
self.ops.push(DocumentMsg::RemovePipeline(pipeline_id));
|
||||
}
|
||||
|
||||
/// Supplies a new frame to WebRender.
|
||||
///
|
||||
/// Non-blocking, it notifies a worker process which processes the display list.
|
||||
/// When it's done and a RenderNotifier has been set in `webrender::Renderer`,
|
||||
/// [new_frame_ready()][notifier] gets called.
|
||||
///
|
||||
/// Note: Scrolling doesn't require an own Frame.
|
||||
///
|
||||
/// Arguments:
|
||||
///
|
||||
/// * `document_id`: Target Document ID.
|
||||
/// * `epoch`: The unique Frame ID, monotonically increasing.
|
||||
/// * `background`: The background color of this pipeline.
|
||||
/// * `viewport_size`: The size of the viewport for this frame.
|
||||
/// * `pipeline_id`: The ID of the pipeline that is supplying this display list.
|
||||
/// * `content_size`: The total screen space size of this display list's display items.
|
||||
/// * `display_list`: The root Display list used in this frame.
|
||||
/// * `preserve_frame_state`: If a previous frame exists which matches this pipeline
|
||||
/// id, this setting determines if frame state (such as scrolling
|
||||
/// position) should be preserved for this new display list.
|
||||
/// * `resources`: A set of resource updates that must be applied at the same time as the
|
||||
/// display list.
|
||||
///
|
||||
/// [notifier]: trait.RenderNotifier.html#tymethod.new_frame_ready
|
||||
pub fn set_display_list(
|
||||
&mut self,
|
||||
epoch: Epoch,
|
||||
background: Option<ColorF>,
|
||||
viewport_size: LayoutSize,
|
||||
(pipeline_id, content_size, display_list): (PipelineId, LayoutSize, BuiltDisplayList),
|
||||
preserve_frame_state: bool,
|
||||
) {
|
||||
let (display_list_data, list_descriptor) = display_list.into_data();
|
||||
self.ops.push(
|
||||
DocumentMsg::SetDisplayList {
|
||||
epoch,
|
||||
pipeline_id,
|
||||
background,
|
||||
viewport_size,
|
||||
content_size,
|
||||
list_descriptor,
|
||||
preserve_frame_state,
|
||||
resources: ResourceUpdates::new(),
|
||||
}
|
||||
);
|
||||
self.payloads.push(Payload { epoch, pipeline_id, display_list_data });
|
||||
}
|
||||
|
||||
pub fn update_resources(&mut self, resources: ResourceUpdates) {
|
||||
self.ops.push(DocumentMsg::UpdateResources(resources));
|
||||
}
|
||||
|
||||
pub fn set_window_parameters(
|
||||
&mut self,
|
||||
window_size: DeviceUintSize,
|
||||
inner_rect: DeviceUintRect,
|
||||
device_pixel_ratio: f32,
|
||||
) {
|
||||
self.ops.push(
|
||||
DocumentMsg::SetWindowParameters {
|
||||
window_size,
|
||||
inner_rect,
|
||||
device_pixel_ratio,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// Scrolls the scrolling layer under the `cursor`
|
||||
///
|
||||
/// WebRender looks for the layer closest to the user
|
||||
/// which has `ScrollPolicy::Scrollable` set.
|
||||
pub fn scroll(
|
||||
&mut self,
|
||||
scroll_location: ScrollLocation,
|
||||
cursor: WorldPoint,
|
||||
phase: ScrollEventPhase,
|
||||
) {
|
||||
self.ops.push(DocumentMsg::Scroll(scroll_location, cursor, phase));
|
||||
}
|
||||
|
||||
pub fn scroll_node_with_id(
|
||||
&mut self,
|
||||
origin: LayoutPoint,
|
||||
id: ClipId,
|
||||
clamp: ScrollClamping,
|
||||
) {
|
||||
self.ops.push(DocumentMsg::ScrollNodeWithId(origin, id, clamp));
|
||||
}
|
||||
|
||||
pub fn set_page_zoom(&mut self, page_zoom: ZoomFactor) {
|
||||
self.ops.push(DocumentMsg::SetPageZoom(page_zoom));
|
||||
}
|
||||
|
||||
pub fn set_pinch_zoom(&mut self, pinch_zoom: ZoomFactor) {
|
||||
self.ops.push(DocumentMsg::SetPinchZoom(pinch_zoom));
|
||||
}
|
||||
|
||||
pub fn set_pan(&mut self, pan: DeviceIntPoint) {
|
||||
self.ops.push(DocumentMsg::SetPan(pan));
|
||||
}
|
||||
|
||||
pub fn tick_scrolling_bounce_animations(&mut self) {
|
||||
self.ops.push(DocumentMsg::TickScrollingBounce);
|
||||
}
|
||||
|
||||
/// Generate a new frame.
|
||||
pub fn generate_frame(&mut self) {
|
||||
self.ops.push(DocumentMsg::GenerateFrame);
|
||||
}
|
||||
|
||||
/// Supply a list of animated property bindings that should be used to resolve
|
||||
/// bindings in the current display list.
|
||||
pub fn update_dynamic_properties(&mut self, properties: DynamicProperties) {
|
||||
self.ops.push(DocumentMsg::UpdateDynamicProperties(properties));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Clone, Deserialize, Serialize)]
|
||||
pub struct AddImage {
|
||||
pub key: ImageKey,
|
||||
@ -199,11 +367,14 @@ pub enum DocumentMsg {
|
||||
preserve_frame_state: bool,
|
||||
resources: ResourceUpdates,
|
||||
},
|
||||
UpdateResources(ResourceUpdates),
|
||||
// TODO(nical): Remove this once gecko doesn't use it anymore.
|
||||
UpdatePipelineResources {
|
||||
resources: ResourceUpdates,
|
||||
pipeline_id: PipelineId,
|
||||
epoch: Epoch,
|
||||
},
|
||||
UpdateEpoch(PipelineId, Epoch),
|
||||
SetPageZoom(ZoomFactor),
|
||||
SetPinchZoom(ZoomFactor),
|
||||
SetPan(DeviceIntPoint),
|
||||
@ -219,7 +390,8 @@ pub enum DocumentMsg {
|
||||
ScrollNodeWithId(LayoutPoint, ClipId, ScrollClamping),
|
||||
TickScrollingBounce,
|
||||
GetScrollNodeState(MsgSender<Vec<ScrollLayerState>>),
|
||||
GenerateFrame(Option<DynamicProperties>),
|
||||
GenerateFrame,
|
||||
UpdateDynamicProperties(DynamicProperties),
|
||||
}
|
||||
|
||||
impl fmt::Debug for DocumentMsg {
|
||||
@ -238,8 +410,11 @@ impl fmt::Debug for DocumentMsg {
|
||||
DocumentMsg::ScrollNodeWithId(..) => "DocumentMsg::ScrollNodeWithId",
|
||||
DocumentMsg::TickScrollingBounce => "DocumentMsg::TickScrollingBounce",
|
||||
DocumentMsg::GetScrollNodeState(..) => "DocumentMsg::GetScrollNodeState",
|
||||
DocumentMsg::GenerateFrame(..) => "DocumentMsg::GenerateFrame",
|
||||
DocumentMsg::GenerateFrame => "DocumentMsg::GenerateFrame",
|
||||
DocumentMsg::EnableFrameOutput(..) => "DocumentMsg::EnableFrameOutput",
|
||||
DocumentMsg::UpdateResources(..) => "DocumentMsg::UpdateResources",
|
||||
DocumentMsg::UpdateEpoch(..) => "DocumentMsg::UpdateEpoch",
|
||||
DocumentMsg::UpdateDynamicProperties(..) => "DocumentMsg::UpdateDynamicProperties",
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -293,7 +468,7 @@ pub enum ApiMsg {
|
||||
/// Adds a new document with given initial size.
|
||||
AddDocument(DocumentId, DeviceUintSize, DocumentLayer),
|
||||
/// A message targeted at a particular document.
|
||||
UpdateDocument(DocumentId, DocumentMsg),
|
||||
UpdateDocument(DocumentId, Vec<DocumentMsg>),
|
||||
/// Deletes an existing document.
|
||||
DeleteDocument(DocumentId),
|
||||
/// An opaque handle that must be passed to the render notifier. It is used by Gecko
|
||||
@ -570,10 +745,15 @@ impl RenderApi {
|
||||
// `RenderApi` instances for layout and compositor.
|
||||
//assert_eq!(document_id.0, self.namespace_id);
|
||||
self.api_sender
|
||||
.send(ApiMsg::UpdateDocument(document_id, msg))
|
||||
.send(ApiMsg::UpdateDocument(document_id, vec![msg]))
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
// TODO(nical) - decide what to do with the methods that are duplicated in Transaction.
|
||||
// I think that we should remove them from RenderApi but we could also leave them here if
|
||||
// it makes things easier for servo.
|
||||
// They are all equivalent to creating a transaction with a single command.
|
||||
|
||||
/// Sets the root pipeline.
|
||||
///
|
||||
/// # Examples
|
||||
@ -630,8 +810,14 @@ impl RenderApi {
|
||||
viewport_size: LayoutSize,
|
||||
(pipeline_id, content_size, display_list): (PipelineId, LayoutSize, BuiltDisplayList),
|
||||
preserve_frame_state: bool,
|
||||
resources: ResourceUpdates,
|
||||
resources: ResourceUpdates, // TODO: this will be removed soon.
|
||||
) {
|
||||
// TODO(nical) set_display_list uses the epoch to match the displaylist and the payload
|
||||
// coming from different channels when receiving in the render backend.
|
||||
// It would be cleaner to use a separate id that is implicitly generated for the displaylist-payload
|
||||
// matching so that the semantics of epochs is really up to the api user and so that the latter can't
|
||||
// introduce bugs by accidently using the same epoch twice.
|
||||
|
||||
let (display_list_data, list_descriptor) = display_list.into_data();
|
||||
self.send(
|
||||
document_id,
|
||||
@ -656,6 +842,13 @@ impl RenderApi {
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
pub fn send_transaction(&mut self, document_id: DocumentId, transaction: Transaction) {
|
||||
for payload in transaction.payloads {
|
||||
self.payload_sender.send_payload(payload).unwrap();
|
||||
}
|
||||
self.api_sender.send(ApiMsg::UpdateDocument(document_id, transaction.ops)).unwrap();
|
||||
}
|
||||
|
||||
/// Scrolls the scrolling layer under the `cursor`
|
||||
///
|
||||
/// WebRender looks for the layer closest to the user
|
||||
@ -764,7 +957,10 @@ impl RenderApi {
|
||||
document_id: DocumentId,
|
||||
property_bindings: Option<DynamicProperties>,
|
||||
) {
|
||||
self.send(document_id, DocumentMsg::GenerateFrame(property_bindings));
|
||||
if let Some(properties) = property_bindings {
|
||||
self.send(document_id, DocumentMsg::UpdateDynamicProperties(properties));
|
||||
}
|
||||
self.send(document_id, DocumentMsg::GenerateFrame);
|
||||
}
|
||||
|
||||
/// Save a capture of the current frame state for debugging.
|
||||
|
Loading…
Reference in New Issue
Block a user