mirror of
https://github.com/servo/servo.git
synced 2025-09-27 23:30:08 +01:00
compositor: Allow canvas to upload rendered contents asynchronously (#37776)
Adds epoch to each WR image op command that is sent to compositor. The renderer now has a `FrameDelayer` data structure that is responsible for tracking when a frame is ready to be displayed. When asking canvases to update their rendering, they are given an optional `Epoch` which denotes the `Document`'s canvas epoch. When all image updates for that `Epoch` are seen in the renderer, the frame can be displayed. Testing: Existing WPT tests Fixes: #35733 Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> Signed-off-by: Martin Robinson <mrobinson@igalia.com> Co-authored-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
parent
4700149fcb
commit
8beef6c21f
36 changed files with 452 additions and 100 deletions
|
@ -16,11 +16,14 @@ pub mod print_tree;
|
|||
pub mod text;
|
||||
mod unicode_block;
|
||||
|
||||
use malloc_size_of_derive::MallocSizeOf;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use webrender_api::Epoch as WebRenderEpoch;
|
||||
|
||||
/// A struct for denoting the age of messages; prevents race conditions.
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
|
||||
#[derive(
|
||||
Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize, MallocSizeOf,
|
||||
)]
|
||||
pub struct Epoch(pub u32);
|
||||
|
||||
impl Epoch {
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
use std::default::Default;
|
||||
use std::str::FromStr;
|
||||
|
||||
use base::Epoch;
|
||||
use euclid::Angle;
|
||||
use euclid::approxeq::ApproxEq;
|
||||
use euclid::default::{Point2D, Rect, Size2D, Transform2D};
|
||||
|
@ -516,7 +517,7 @@ pub enum Canvas2dMsg {
|
|||
CompositionOptions,
|
||||
Transform2D<f64>,
|
||||
),
|
||||
UpdateImage(IpcSender<()>),
|
||||
UpdateImage(Option<Epoch>),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
|
||||
|
|
|
@ -7,6 +7,7 @@ use std::fmt;
|
|||
use std::num::{NonZeroU32, NonZeroU64};
|
||||
use std::ops::Deref;
|
||||
|
||||
use base::Epoch;
|
||||
/// Receiver type used in WebGLCommands.
|
||||
pub use base::generic_channel::GenericReceiver as WebGLReceiver;
|
||||
/// Sender type used in WebGLCommands.
|
||||
|
@ -107,7 +108,7 @@ pub enum WebGLMsg {
|
|||
/// The third field contains the time (in ns) when the request
|
||||
/// was initiated. The u64 in the second field will be the time the
|
||||
/// request is fulfilled
|
||||
SwapBuffers(Vec<WebGLContextId>, WebGLSender<u64>, u64),
|
||||
SwapBuffers(Vec<WebGLContextId>, Option<Epoch>, u64),
|
||||
/// Frees all resources and closes the thread.
|
||||
Exit(IpcSender<()>),
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
use std::fmt::{Debug, Error, Formatter};
|
||||
|
||||
use base::Epoch;
|
||||
use base::id::{PipelineId, WebViewId};
|
||||
use crossbeam_channel::Sender;
|
||||
use embedder_traits::{AnimationState, EventLoopWaker, TouchEventResult};
|
||||
|
@ -131,6 +132,11 @@ pub enum CompositorMsg {
|
|||
GenerateImageKeysForPipeline(PipelineId),
|
||||
/// Perform a resource update operation.
|
||||
UpdateImages(SmallVec<[ImageUpdate; 1]>),
|
||||
/// Pause all pipeline display list processing for the given pipeline until the
|
||||
/// following image updates have been received. This is used to ensure that canvas
|
||||
/// elements have had a chance to update their rendering and send the image update to
|
||||
/// the renderer before their associated display list is actually displayed.
|
||||
DelayNewFrameForCanvas(PipelineId, Epoch, Vec<ImageKey>),
|
||||
|
||||
/// Generate a new batch of font keys which can be used to allocate
|
||||
/// keys asynchronously.
|
||||
|
@ -222,6 +228,21 @@ impl CrossProcessCompositorApi {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn delay_new_frame_for_canvas(
|
||||
&self,
|
||||
pipeline_id: PipelineId,
|
||||
canvas_epoch: Epoch,
|
||||
image_keys: Vec<ImageKey>,
|
||||
) {
|
||||
if let Err(error) = self.0.send(CompositorMsg::DelayNewFrameForCanvas(
|
||||
pipeline_id,
|
||||
canvas_epoch,
|
||||
image_keys,
|
||||
)) {
|
||||
warn!("Error delaying frames for canvas image updates {error:?}");
|
||||
}
|
||||
}
|
||||
|
||||
/// Inform WebRender of a new display list for the given pipeline.
|
||||
pub fn send_display_list(
|
||||
&self,
|
||||
|
@ -296,8 +317,9 @@ impl CrossProcessCompositorApi {
|
|||
key: ImageKey,
|
||||
descriptor: ImageDescriptor,
|
||||
data: SerializableImageData,
|
||||
epoch: Option<Epoch>,
|
||||
) {
|
||||
self.update_images([ImageUpdate::UpdateImage(key, descriptor, data)].into());
|
||||
self.update_images([ImageUpdate::UpdateImage(key, descriptor, data, epoch)].into());
|
||||
}
|
||||
|
||||
pub fn delete_image(&self, key: ImageKey) {
|
||||
|
@ -538,7 +560,31 @@ pub enum ImageUpdate {
|
|||
/// Delete a previously registered image registration.
|
||||
DeleteImage(ImageKey),
|
||||
/// Update an existing image registration.
|
||||
UpdateImage(ImageKey, ImageDescriptor, SerializableImageData),
|
||||
UpdateImage(
|
||||
ImageKey,
|
||||
ImageDescriptor,
|
||||
SerializableImageData,
|
||||
Option<Epoch>,
|
||||
),
|
||||
}
|
||||
|
||||
impl Debug for ImageUpdate {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::AddImage(image_key, image_desc, _) => f
|
||||
.debug_tuple("AddImage")
|
||||
.field(image_key)
|
||||
.field(image_desc)
|
||||
.finish(),
|
||||
Self::DeleteImage(image_key) => f.debug_tuple("DeleteImage").field(image_key).finish(),
|
||||
Self::UpdateImage(image_key, image_desc, _, epoch) => f
|
||||
.debug_tuple("UpdateImage")
|
||||
.field(image_key)
|
||||
.field(image_desc)
|
||||
.field(epoch)
|
||||
.finish(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
|
|
|
@ -57,6 +57,10 @@ pub enum EmbedderToConstellationMessage {
|
|||
/// Requests that the constellation instruct script/layout to try to layout again and tick
|
||||
/// animations.
|
||||
TickAnimation(Vec<WebViewId>),
|
||||
/// Notify the `ScriptThread` that the Servo renderer is no longer waiting on
|
||||
/// asynchronous image uploads for the given `Pipeline`. These are mainly used
|
||||
/// by canvas to perform uploads while the display list is being built.
|
||||
NoLongerWaitingOnAsynchronousImageUpdates(Vec<PipelineId>),
|
||||
/// Dispatch a webdriver command
|
||||
WebDriverCommand(WebDriverCommandMsg),
|
||||
/// Reload a top-level browsing context.
|
||||
|
|
|
@ -261,6 +261,10 @@ pub enum ScriptThreadMessage {
|
|||
SendImageKeysBatch(PipelineId, Vec<ImageKey>),
|
||||
/// Preferences were updated in the parent process.
|
||||
PreferencesUpdated(Vec<(String, PrefValue)>),
|
||||
/// Notify the `ScriptThread` that the Servo renderer is no longer waiting on
|
||||
/// asynchronous image uploads for the given `Pipeline`. These are mainly used
|
||||
/// by canvas to perform uploads while the display list is being built.
|
||||
NoLongerWaitingOnAsychronousImageUpdates(PipelineId),
|
||||
}
|
||||
|
||||
impl fmt::Debug for ScriptThreadMessage {
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
//! (usually from the ScriptThread, and more specifically from DOM objects)
|
||||
|
||||
use arrayvec::ArrayVec;
|
||||
use base::Epoch;
|
||||
use base::id::PipelineId;
|
||||
use ipc_channel::ipc::{IpcSender, IpcSharedMemory};
|
||||
use pixels::IpcSnapshot;
|
||||
|
@ -162,6 +163,7 @@ pub enum WebGPURequest {
|
|||
context_id: WebGPUContextId,
|
||||
texture_id: TextureId,
|
||||
encoder_id: CommandEncoderId,
|
||||
canvas_epoch: Option<Epoch>,
|
||||
},
|
||||
/// Obtains image from latest presentation buffer (same as wr update)
|
||||
GetImage {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue