mirror of
https://github.com/servo/servo.git
synced 2025-08-01 19:50:30 +01:00
Fix a compositor race condition that can result in the most recent buffer not being painted.
This commit is contained in:
parent
885068207f
commit
79942f0920
4 changed files with 44 additions and 22 deletions
|
@ -25,7 +25,7 @@ use layers::layers::{BufferRequest, Layer, LayerBuffer, LayerBufferSet};
|
|||
use layers::rendergl::RenderContext;
|
||||
use layers::rendergl;
|
||||
use layers::scene::Scene;
|
||||
use msg::compositor_msg::{Epoch, LayerId};
|
||||
use msg::compositor_msg::{Epoch, FrameTreeId, LayerId};
|
||||
use msg::compositor_msg::{ReadyState, PaintState, ScrollPolicy};
|
||||
use msg::constellation_msg::AnimationState;
|
||||
use msg::constellation_msg::Msg as ConstellationMsg;
|
||||
|
@ -119,8 +119,8 @@ pub struct IOCompositor<Window: WindowMethods> {
|
|||
/// many times for a single page.
|
||||
got_load_complete_message: bool,
|
||||
|
||||
/// Whether we have received a `SetFrameTree` message.
|
||||
got_set_frame_tree_message: bool,
|
||||
/// The current frame tree ID (used to reject old paint buffers)
|
||||
frame_tree_id: FrameTreeId,
|
||||
|
||||
/// The channel on which messages can be sent to the constellation.
|
||||
constellation_chan: ConstellationChan,
|
||||
|
@ -269,7 +269,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
zoom_action: false,
|
||||
zoom_time: 0f64,
|
||||
got_load_complete_message: false,
|
||||
got_set_frame_tree_message: false,
|
||||
frame_tree_id: FrameTreeId(0),
|
||||
constellation_chan: constellation_chan,
|
||||
time_profiler_chan: time_profiler_chan,
|
||||
mem_profiler_chan: mem_profiler_chan,
|
||||
|
@ -372,13 +372,14 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
self.set_layer_rect(pipeline_id, layer_id, &rect);
|
||||
}
|
||||
|
||||
(Msg::AssignPaintedBuffers(pipeline_id, epoch, replies),
|
||||
(Msg::AssignPaintedBuffers(pipeline_id, epoch, replies, frame_tree_id),
|
||||
ShutdownState::NotShuttingDown) => {
|
||||
for (layer_id, new_layer_buffer_set) in replies.into_iter() {
|
||||
self.assign_painted_buffers(pipeline_id,
|
||||
layer_id,
|
||||
new_layer_buffer_set,
|
||||
epoch);
|
||||
epoch,
|
||||
frame_tree_id);
|
||||
}
|
||||
self.remove_outstanding_paint_msg();
|
||||
}
|
||||
|
@ -606,7 +607,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
self.constellation_chan = new_constellation_chan;
|
||||
self.send_window_size();
|
||||
|
||||
self.got_set_frame_tree_message = true;
|
||||
self.frame_tree_id.next();
|
||||
self.composite_if_necessary(CompositingReason::NewFrameTree);
|
||||
}
|
||||
|
||||
|
@ -796,11 +797,19 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
pipeline_id: PipelineId,
|
||||
layer_id: LayerId,
|
||||
new_layer_buffer_set: Box<LayerBufferSet>,
|
||||
epoch: Epoch) {
|
||||
epoch: Epoch,
|
||||
frame_tree_id: FrameTreeId) {
|
||||
// If the frame tree id has changed since this paint request was sent,
|
||||
// reject the buffers and send them back to the paint task. If this isn't handled
|
||||
// correctly, the content_age in the tile grid can get out of sync when iframes are
|
||||
// loaded and the frame tree changes. This can result in the compositor thinking it
|
||||
// has already drawn the most recently painted buffer, and missing a frame.
|
||||
if frame_tree_id == self.frame_tree_id {
|
||||
if let Some(layer) = self.find_layer_with_pipeline_and_layer_id(pipeline_id, layer_id) {
|
||||
self.assign_painted_buffers_to_layer(layer, new_layer_buffer_set, epoch);
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
let pipeline = self.get_pipeline(pipeline_id);
|
||||
let message = PaintMsg::UnusedBuffer(new_layer_buffer_set.buffers);
|
||||
|
@ -1183,7 +1192,8 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
let mut num_paint_msgs_sent = 0;
|
||||
for (pipeline_id, requests) in pipeline_requests.into_iter() {
|
||||
num_paint_msgs_sent += 1;
|
||||
let _ = self.get_pipeline(pipeline_id).paint_chan.send(PaintMsg::Paint(requests));
|
||||
let msg = PaintMsg::Paint(requests, self.frame_tree_id);
|
||||
let _ = self.get_pipeline(pipeline_id).paint_chan.send(msg);
|
||||
}
|
||||
|
||||
self.add_outstanding_paint_msg(num_paint_msgs_sent);
|
||||
|
@ -1207,7 +1217,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
return false;
|
||||
}
|
||||
|
||||
if !self.got_set_frame_tree_message {
|
||||
if self.frame_tree_id == FrameTreeId(0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ use geom::rect::Rect;
|
|||
use geom::size::Size2D;
|
||||
use layers::platform::surface::{NativeCompositingGraphicsContext, NativeGraphicsMetadata};
|
||||
use layers::layers::LayerBufferSet;
|
||||
use msg::compositor_msg::{Epoch, LayerId, LayerMetadata, ReadyState};
|
||||
use msg::compositor_msg::{Epoch, LayerId, LayerMetadata, FrameTreeId, ReadyState};
|
||||
use msg::compositor_msg::{PaintListener, PaintState, ScriptListener, ScrollPolicy};
|
||||
use msg::constellation_msg::{AnimationState, ConstellationChan, PipelineId};
|
||||
use msg::constellation_msg::{Key, KeyState, KeyModifiers};
|
||||
|
@ -134,8 +134,9 @@ impl PaintListener for Box<CompositorProxy+'static+Send> {
|
|||
fn assign_painted_buffers(&mut self,
|
||||
pipeline_id: PipelineId,
|
||||
epoch: Epoch,
|
||||
replies: Vec<(LayerId, Box<LayerBufferSet>)>) {
|
||||
self.send(Msg::AssignPaintedBuffers(pipeline_id, epoch, replies));
|
||||
replies: Vec<(LayerId, Box<LayerBufferSet>)>,
|
||||
frame_tree_id: FrameTreeId) {
|
||||
self.send(Msg::AssignPaintedBuffers(pipeline_id, epoch, replies, frame_tree_id));
|
||||
}
|
||||
|
||||
fn initialize_layers_for_pipeline(&mut self,
|
||||
|
@ -194,7 +195,7 @@ pub enum Msg {
|
|||
/// Scroll a page in a window
|
||||
ScrollFragmentPoint(PipelineId, LayerId, Point2D<f32>),
|
||||
/// Requests that the compositor assign the painted buffers to the given layers.
|
||||
AssignPaintedBuffers(PipelineId, Epoch, Vec<(LayerId, Box<LayerBufferSet>)>),
|
||||
AssignPaintedBuffers(PipelineId, Epoch, Vec<(LayerId, Box<LayerBufferSet>)>, FrameTreeId),
|
||||
/// Alerts the compositor to the current status of page loading.
|
||||
ChangeReadyState(PipelineId, ReadyState),
|
||||
/// Alerts the compositor to the current status of painting.
|
||||
|
|
|
@ -20,7 +20,7 @@ use layers::platform::surface::{NativeGraphicsMetadata, NativePaintingGraphicsCo
|
|||
use layers::platform::surface::NativeSurface;
|
||||
use layers::layers::{BufferRequest, LayerBuffer, LayerBufferSet};
|
||||
use layers;
|
||||
use msg::compositor_msg::{Epoch, PaintState, LayerId};
|
||||
use msg::compositor_msg::{Epoch, FrameTreeId, PaintState, LayerId};
|
||||
use msg::compositor_msg::{LayerMetadata, PaintListener, ScrollPolicy};
|
||||
use msg::constellation_msg::Msg as ConstellationMsg;
|
||||
use msg::constellation_msg::{ConstellationChan, Failure, PipelineId};
|
||||
|
@ -68,7 +68,7 @@ pub struct PaintRequest {
|
|||
|
||||
pub enum Msg {
|
||||
PaintInit(Arc<StackingContext>),
|
||||
Paint(Vec<PaintRequest>),
|
||||
Paint(Vec<PaintRequest>, FrameTreeId),
|
||||
UnusedBuffer(Vec<Box<LayerBuffer>>),
|
||||
PaintPermissionGranted,
|
||||
PaintPermissionRevoked,
|
||||
|
@ -210,7 +210,7 @@ impl<C> PaintTask<C> where C: PaintListener + Send + 'static {
|
|||
self.epoch.next();
|
||||
self.initialize_layers();
|
||||
}
|
||||
Msg::Paint(requests) => {
|
||||
Msg::Paint(requests, frame_tree_id) => {
|
||||
if !self.paint_permission {
|
||||
debug!("PaintTask: paint ready msg");
|
||||
let ConstellationChan(ref mut c) = self.constellation_chan;
|
||||
|
@ -238,7 +238,7 @@ impl<C> PaintTask<C> where C: PaintListener + Send + 'static {
|
|||
}
|
||||
|
||||
debug!("PaintTask: returning surfaces");
|
||||
self.compositor.assign_painted_buffers(self.id, self.epoch, replies);
|
||||
self.compositor.assign_painted_buffers(self.id, self.epoch, replies, frame_tree_id);
|
||||
}
|
||||
Msg::UnusedBuffer(unused_buffers) => {
|
||||
debug!("PaintTask: Received {} unused buffers", unused_buffers.len());
|
||||
|
|
|
@ -43,6 +43,16 @@ impl Epoch {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Debug, Copy, Clone)]
|
||||
pub struct FrameTreeId(pub u32);
|
||||
|
||||
impl FrameTreeId {
|
||||
pub fn next(&mut self) {
|
||||
let FrameTreeId(ref mut u) = *self;
|
||||
*u += 1;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Copy)]
|
||||
pub struct LayerId(pub usize, pub u32);
|
||||
|
||||
|
@ -99,7 +109,8 @@ pub trait PaintListener {
|
|||
fn assign_painted_buffers(&mut self,
|
||||
pipeline_id: PipelineId,
|
||||
epoch: Epoch,
|
||||
replies: Vec<(LayerId, Box<LayerBufferSet>)>);
|
||||
replies: Vec<(LayerId, Box<LayerBufferSet>)>,
|
||||
frame_tree_id: FrameTreeId);
|
||||
|
||||
fn paint_msg_discarded(&mut self);
|
||||
fn set_paint_state(&mut self, PipelineId, PaintState);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue