Bug 1462611 - Update webrender to commit bb354abbf84602d3d8357c63c4f0b1139ec4deb1. r?Gankro
MozReview-Commit-ID: KiJVmU52MMd
--- a/gfx/webrender/src/internal_types.rs
+++ b/gfx/webrender/src/internal_types.rs
@@ -124,35 +124,26 @@ impl TextureUpdateList {
}
#[inline]
pub fn push(&mut self, update: TextureUpdate) {
self.updates.push(update);
}
}
-/// Mostly wraps a tiling::Frame, adding a bit of extra information.
+/// Wraps a tiling::Frame, but conceptually could hold more information
pub struct RenderedDocument {
- /// The pipeline info contains:
- /// - The last rendered epoch for each pipeline present in the frame.
- /// This information is used to know if a certain transformation on the layout has
- /// been rendered, which is necessary for reftests.
- /// - Pipelines that were removed from the scene.
- pub pipeline_info: PipelineInfo,
-
pub frame: tiling::Frame,
}
impl RenderedDocument {
pub fn new(
- pipeline_info: PipelineInfo,
frame: tiling::Frame,
) -> Self {
RenderedDocument {
- pipeline_info,
frame,
}
}
}
pub enum DebugOutput {
FetchDocuments(String),
FetchClipScrollTree(String),
@@ -166,16 +157,17 @@ pub enum ResultMsg {
DebugCommand(DebugCommand),
DebugOutput(DebugOutput),
RefreshShader(PathBuf),
UpdateGpuCache(GpuCacheUpdateList),
UpdateResources {
updates: TextureUpdateList,
cancel_rendering: bool,
},
+ PublishPipelineInfo(PipelineInfo),
PublishDocument(
DocumentId,
RenderedDocument,
TextureUpdateList,
BackendProfileCounters,
),
}
--- a/gfx/webrender/src/render_backend.rs
+++ b/gfx/webrender/src/render_backend.rs
@@ -37,16 +37,17 @@ use serde::{Serialize, Deserialize};
#[cfg(feature = "debugger")]
use serde_json;
#[cfg(any(feature = "capture", feature = "replay"))]
use std::path::PathBuf;
use std::sync::atomic::{ATOMIC_USIZE_INIT, AtomicUsize, Ordering};
use std::mem::replace;
use std::sync::mpsc::{channel, Sender, Receiver};
use std::u32;
+#[cfg(feature = "replay")]
use tiling::Frame;
use time::precise_time_ns;
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(Clone)]
pub struct DocumentView {
pub window_size: DeviceUintSize,
@@ -165,23 +166,25 @@ impl Document {
render_on_hittest: false,
hit_tester: None,
dynamic_properties: SceneProperties::new(),
}
}
fn can_render(&self) -> bool { self.frame_builder.is_some() }
+ fn has_pixels(&self) -> bool {
+ !self.view.window_size.is_empty_or_negative()
+ }
+
// TODO: We will probably get rid of this soon and always forward to the scene building thread.
fn build_scene(&mut self, resource_cache: &mut ResourceCache) {
let max_texture_size = resource_cache.max_texture_size();
- if self.view.window_size.width == 0 ||
- self.view.window_size.height == 0 ||
- self.view.window_size.width > max_texture_size ||
+ if self.view.window_size.width > max_texture_size ||
self.view.window_size.height > max_texture_size {
error!("ERROR: Invalid window dimensions {}x{}. Please call api.set_window_size()",
self.view.window_size.width,
self.view.window_size.height,
);
return;
}
@@ -236,20 +239,16 @@ impl Document {
// Do as much of the error handling as possible here before dispatching to
// the scene builder thread.
let build_scene: bool = document_ops.build
&& self.pending.scene.root_pipeline_id.map(
|id| { self.pending.scene.pipelines.contains_key(&id) }
).unwrap_or(false);
let scene_request = if build_scene {
- if self.view.window_size.width == 0 || self.view.window_size.height == 0 {
- error!("ERROR: Invalid window dimensions! Please call api.set_window_size()");
- }
-
Some(SceneRequest {
scene: self.pending.scene.clone(),
removed_pipelines: replace(&mut self.pending.removed_pipelines, Vec::new()),
view: self.view.clone(),
font_instances: resource_cache.get_font_instances(),
output_pipelines: self.output_pipelines.clone(),
})
} else {
@@ -268,17 +267,16 @@ impl Document {
fn render(
&mut self,
resource_cache: &mut ResourceCache,
gpu_cache: &mut GpuCache,
resource_profile: &mut ResourceProfileCounters,
) -> RenderedDocument {
let accumulated_scale_factor = self.view.accumulated_scale_factor();
let pan = self.view.pan.to_f32() / accumulated_scale_factor;
- let removed_pipelines = replace(&mut self.current.removed_pipelines, Vec::new());
let frame = {
let frame_builder = self.frame_builder.as_mut().unwrap();
let frame = frame_builder.build(
resource_cache,
gpu_cache,
self.frame_id,
&mut self.clip_scroll_tree,
@@ -289,27 +287,25 @@ impl Document {
&mut resource_profile.texture_cache,
&mut resource_profile.gpu_cache,
&self.dynamic_properties,
);
self.hit_tester = Some(frame_builder.create_hit_tester(&self.clip_scroll_tree));
frame
};
- self.make_rendered_document(frame, removed_pipelines)
+ RenderedDocument::new(frame)
}
- pub fn make_rendered_document(&mut self, frame: Frame, removed_pipelines: Vec<PipelineId>) -> RenderedDocument {
- RenderedDocument::new(
- PipelineInfo {
- epochs: self.current.scene.pipeline_epochs.clone(),
- removed_pipelines,
- },
- frame
- )
+ pub fn updated_pipeline_info(&mut self) -> PipelineInfo {
+ let removed_pipelines = replace(&mut self.current.removed_pipelines, Vec::new());
+ PipelineInfo {
+ epochs: self.current.scene.pipeline_epochs.clone(),
+ removed_pipelines,
+ }
}
pub fn discard_frame_state_for_pipeline(&mut self, pipeline_id: PipelineId) {
self.clip_scroll_tree
.discard_frame_state_for_pipeline(pipeline_id);
}
/// Returns true if any nodes actually changed position or false otherwise.
@@ -1039,17 +1035,17 @@ impl RenderBackend {
// scroll at the same time. we should keep track of the fact that we skipped
// composition here and do it as soon as we receive the scene.
op.render = false;
op.composite = false;
}
debug_assert!(op.render || !op.composite);
- if op.render {
+ if op.render && doc.has_pixels() {
profile_scope!("generate frame");
*frame_counter += 1;
// borrow ck hack for profile_counters
let (pending_update, rendered_document) = {
let _timer = profile_counters.total_time.timer();
@@ -1064,26 +1060,36 @@ impl RenderBackend {
let msg = ResultMsg::UpdateGpuCache(self.gpu_cache.extract_updates());
self.result_tx.send(msg).unwrap();
let pending_update = self.resource_cache.pending_updates();
(pending_update, rendered_document)
};
+ let msg = ResultMsg::PublishPipelineInfo(doc.updated_pipeline_info());
+ self.result_tx.send(msg).unwrap();
+
// Publish the frame
let msg = ResultMsg::PublishDocument(
document_id,
rendered_document,
pending_update,
profile_counters.clone()
);
self.result_tx.send(msg).unwrap();
profile_counters.reset();
doc.render_on_hittest = false;
+ } else if op.render {
+ // WR-internal optimization to avoid doing a bunch of render work if
+ // there's no pixels. We still want to pretend to render and request
+ // a composite to make sure that the callbacks (particularly the
+ // new_frame_ready callback below) has the right flags.
+ let msg = ResultMsg::PublishPipelineInfo(doc.updated_pipeline_info());
+ self.result_tx.send(msg).unwrap();
}
if transaction_msg.generate_frame {
self.notifier.new_frame_ready(document_id, op.scroll, op.composite);
}
}
#[cfg(not(feature = "debugger"))]
@@ -1235,17 +1241,17 @@ impl RenderBackend {
config.serialize(&doc.current.scene, file_name);
}
if config.bits.contains(CaptureBits::FRAME) {
let rendered_document = doc.render(
&mut self.resource_cache,
&mut self.gpu_cache,
&mut profile_counters.resources,
);
- //TODO: write down full `RenderedDocument`?
+ //TODO: write down doc's pipeline info?
// it has `pipeline_epoch_map`,
// which may capture necessary details for some cases.
let file_name = format!("frame-{}-{}", (id.0).0, id.1);
config.serialize(&rendered_document.frame, file_name);
}
}
debug!("\tresource cache");
@@ -1346,17 +1352,17 @@ impl RenderBackend {
dynamic_properties: SceneProperties::new(),
hit_tester: None,
};
let frame_name = format!("frame-{}-{}", (id.0).0, id.1);
let render_doc = match CaptureConfig::deserialize::<Frame, _>(root, frame_name) {
Some(frame) => {
info!("\tloaded a built frame with {} passes", frame.passes.len());
- doc.make_rendered_document(frame, Vec::new())
+ RenderedDocument::new(frame)
}
None => {
doc.build_scene(&mut self.resource_cache);
doc.render(
&mut self.resource_cache,
&mut self.gpu_cache,
&mut profile_counters.resources,
)
--- a/gfx/webrender/src/renderer.rs
+++ b/gfx/webrender/src/renderer.rs
@@ -1793,29 +1793,28 @@ impl Renderer {
/// Processes the result queue.
///
/// Should be called before `render()`, as texture cache updates are done here.
pub fn update(&mut self) {
profile_scope!("update");
// Pull any pending results and return the most recent.
while let Ok(msg) = self.result_rx.try_recv() {
match msg {
+ ResultMsg::PublishPipelineInfo(mut pipeline_info) => {
+ for (pipeline_id, epoch) in pipeline_info.epochs {
+ self.pipeline_info.epochs.insert(pipeline_id, epoch);
+ }
+ self.pipeline_info.removed_pipelines.extend(pipeline_info.removed_pipelines.drain(..));
+ }
ResultMsg::PublishDocument(
document_id,
mut doc,
texture_update_list,
profile_counters,
) => {
- // Update the list of available epochs for use during reftests.
- // This is a workaround for https://github.com/servo/servo/issues/13149.
- for (pipeline_id, epoch) in &doc.pipeline_info.epochs {
- self.pipeline_info.epochs.insert(*pipeline_id, *epoch);
- }
- self.pipeline_info.removed_pipelines.extend(doc.pipeline_info.removed_pipelines.drain(..));
-
// Add a new document to the active set, expressed as a `Vec` in order
// to re-order based on `DocumentLayer` during rendering.
match self.active_documents.iter().position(|&(id, _)| id == document_id) {
Some(pos) => {
// If the document we are replacing must be drawn
// (in order to update the texture cache), issue
// a render just to off-screen targets.
if self.active_documents[pos].1.frame.must_be_drawn() {
--- a/gfx/webrender_bindings/revision.txt
+++ b/gfx/webrender_bindings/revision.txt
@@ -1,1 +1,1 @@
-672f480af48b0ad69c1b2781151278d99816763a
+bb354abbf84602d3d8357c63c4f0b1139ec4deb1
--- a/gfx/wrench/src/rawtest.rs
+++ b/gfx/wrench/src/rawtest.rs
@@ -42,16 +42,17 @@ impl<'a> RawtestHarness<'a> {
self.test_hit_testing();
self.test_retained_blob_images_test();
self.test_blob_update_test();
self.test_blob_update_epoch_test();
self.test_tile_decomposition();
self.test_very_large_blob();
self.test_save_restore();
self.test_capture();
+ self.test_zero_height_window();
}
fn render_and_get_pixels(&mut self, window_rect: DeviceUintRect) -> Vec<u8> {
self.rx.recv().unwrap();
self.wrench.render();
self.wrench.renderer.read_pixels_rgba8(window_rect)
}
@@ -654,16 +655,44 @@ impl<'a> RawtestHarness<'a> {
let mut txn = Transaction::new();
txn.set_root_pipeline(captured.root_pipeline_id.unwrap());
txn.generate_frame();
self.wrench.api.send_transaction(captured.document_id, txn);
let pixels2 = self.render_and_get_pixels(window_rect);
assert!(pixels0 == pixels2);
}
+ fn test_zero_height_window(&mut self) {
+ println!("\tzero height test...");
+
+ let layout_size = LayoutSize::new(120.0, 0.0);
+ let window_size = DeviceUintSize::new(layout_size.width as u32, layout_size.height as u32);
+ let doc_id = self.wrench.api.add_document(window_size, 1);
+
+ let mut builder = DisplayListBuilder::new(self.wrench.root_pipeline_id, layout_size);
+ let info = LayoutPrimitiveInfo::new(LayoutRect::new(LayoutPoint::zero(), LayoutSize::new(100.0, 100.0)));
+ builder.push_rect(&info, ColorF::new(0.0, 1.0, 0.0, 1.0));
+
+ let mut txn = Transaction::new();
+ txn.set_root_pipeline(self.wrench.root_pipeline_id);
+ txn.set_display_list(
+ Epoch(1),
+ Some(ColorF::new(1.0, 0.0, 0.0, 1.0)),
+ layout_size,
+ builder.finalize(),
+ false,
+ );
+ txn.generate_frame();
+ self.wrench.api.send_transaction(doc_id, txn);
+
+ // Ensure we get a notification from rendering the above, even though
+ // there are zero visible pixels
+ assert!(self.rx.recv().unwrap() == NotifierEvent::WakeUp);
+ }
+
fn test_hit_testing(&mut self) {
println!("\thit testing test...");
let layout_size = LayoutSize::new(400., 400.);
let mut builder = DisplayListBuilder::new(self.wrench.root_pipeline_id, layout_size);
// Add a rectangle that covers the entire scene.