mirror of
https://github.com/servo/servo.git
synced 2025-06-20 15:18:58 +01:00
Instead of exposing many different kinds of messages to the compositor that are routed through the constellation, expose a single message type which can be sent across IPC channels. In addition, this IPC channel and the route to the crossbeam channel with the compositor is created along with the `CompositorProxy`, simplifying what needs to be passed around during pipeline initialization. Previously, some image updates (from video) were sent over IPC with a special serialization routine and some were sent via crossbeam channels (canvas). Now all updates go over the IPC channel `IpcSharedMemory` is used to avoid serialization penalties. This should improve performance and reduce copies for video, but add a memory copy overhead for canvas. This will improve in the future when canvas renders directly into a texture. All-in-all this is a simplification which opens the path toward having a standard compositor API and reduces the number of duplicate messages and proxying that had to happen in libservo. Signed-off-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
parent
30cbf01280
commit
9195344b75
28 changed files with 547 additions and 800 deletions
|
@ -17,7 +17,7 @@ use headers::{ContentLength, ContentRange, HeaderMapExt};
|
|||
use html5ever::{local_name, namespace_url, ns, LocalName, Prefix};
|
||||
use http::header::{self, HeaderMap, HeaderValue};
|
||||
use http::StatusCode;
|
||||
use ipc_channel::ipc;
|
||||
use ipc_channel::ipc::{self, IpcSharedMemory};
|
||||
use ipc_channel::router::ROUTER;
|
||||
use js::jsapi::JSAutoRealm;
|
||||
use media::{glplayer_channel, GLPlayerMsg, GLPlayerMsgForward, WindowGLContext};
|
||||
|
@ -35,10 +35,10 @@ use servo_media::player::{PlaybackState, Player, PlayerError, PlayerEvent, SeekL
|
|||
use servo_media::{ClientContextId, ServoMedia, SupportsMediaType};
|
||||
use servo_url::ServoUrl;
|
||||
use webrender_api::{
|
||||
ExternalImageData, ExternalImageId, ExternalImageType, ImageBufferKind, ImageData,
|
||||
ImageDescriptor, ImageDescriptorFlags, ImageFormat, ImageKey,
|
||||
ExternalImageData, ExternalImageId, ExternalImageType, ImageBufferKind, ImageDescriptor,
|
||||
ImageDescriptorFlags, ImageFormat, ImageKey,
|
||||
};
|
||||
use webrender_traits::{ImageUpdate, WebRenderScriptApi};
|
||||
use webrender_traits::{CrossProcessCompositorApi, ImageUpdate, SerializableImageData};
|
||||
|
||||
use crate::document_loader::{LoadBlocker, LoadType};
|
||||
use crate::dom::attr::Attr;
|
||||
|
@ -157,7 +157,7 @@ impl FrameHolder {
|
|||
|
||||
pub struct MediaFrameRenderer {
|
||||
player_id: Option<u64>,
|
||||
api: WebRenderScriptApi,
|
||||
compositor_api: CrossProcessCompositorApi,
|
||||
current_frame: Option<(ImageKey, i32, i32)>,
|
||||
old_frame: Option<ImageKey>,
|
||||
very_old_frame: Option<ImageKey>,
|
||||
|
@ -166,10 +166,10 @@ pub struct MediaFrameRenderer {
|
|||
}
|
||||
|
||||
impl MediaFrameRenderer {
|
||||
fn new(render_api_sender: WebRenderScriptApi) -> Self {
|
||||
fn new(compositor_api: CrossProcessCompositorApi) -> Self {
|
||||
Self {
|
||||
player_id: None,
|
||||
api: render_api_sender,
|
||||
compositor_api,
|
||||
current_frame: None,
|
||||
old_frame: None,
|
||||
very_old_frame: None,
|
||||
|
@ -214,7 +214,7 @@ impl VideoFrameRenderer for MediaFrameRenderer {
|
|||
updates.push(ImageUpdate::UpdateImage(
|
||||
*image_key,
|
||||
descriptor,
|
||||
ImageData::Raw(frame.get_data()),
|
||||
SerializableImageData::Raw(IpcSharedMemory::from_bytes(&frame.get_data())),
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -229,7 +229,7 @@ impl VideoFrameRenderer for MediaFrameRenderer {
|
|||
Some((ref mut image_key, ref mut width, ref mut height)) => {
|
||||
self.old_frame = Some(*image_key);
|
||||
|
||||
let Some(new_image_key) = self.api.generate_image_key() else {
|
||||
let Some(new_image_key) = self.compositor_api.generate_image_key() else {
|
||||
return;
|
||||
};
|
||||
|
||||
|
@ -245,13 +245,13 @@ impl VideoFrameRenderer for MediaFrameRenderer {
|
|||
ImageBufferKind::Texture2D
|
||||
};
|
||||
|
||||
ImageData::External(ExternalImageData {
|
||||
SerializableImageData::External(ExternalImageData {
|
||||
id: ExternalImageId(self.player_id.unwrap()),
|
||||
channel_index: 0,
|
||||
image_type: ExternalImageType::TextureHandle(texture_target),
|
||||
})
|
||||
} else {
|
||||
ImageData::Raw(frame.get_data())
|
||||
SerializableImageData::Raw(IpcSharedMemory::from_bytes(&frame.get_data()))
|
||||
};
|
||||
|
||||
self.current_frame_holder
|
||||
|
@ -261,7 +261,7 @@ impl VideoFrameRenderer for MediaFrameRenderer {
|
|||
updates.push(ImageUpdate::AddImage(new_image_key, descriptor, image_data));
|
||||
},
|
||||
None => {
|
||||
let Some(image_key) = self.api.generate_image_key() else {
|
||||
let Some(image_key) = self.compositor_api.generate_image_key() else {
|
||||
return;
|
||||
};
|
||||
self.current_frame = Some((image_key, frame.get_width(), frame.get_height()));
|
||||
|
@ -273,13 +273,13 @@ impl VideoFrameRenderer for MediaFrameRenderer {
|
|||
ImageBufferKind::Texture2D
|
||||
};
|
||||
|
||||
ImageData::External(ExternalImageData {
|
||||
SerializableImageData::External(ExternalImageData {
|
||||
id: ExternalImageId(self.player_id.unwrap()),
|
||||
channel_index: 0,
|
||||
image_type: ExternalImageType::TextureHandle(texture_target),
|
||||
})
|
||||
} else {
|
||||
ImageData::Raw(frame.get_data())
|
||||
SerializableImageData::Raw(IpcSharedMemory::from_bytes(&frame.get_data()))
|
||||
};
|
||||
|
||||
self.current_frame_holder = Some(FrameHolder::new(frame));
|
||||
|
@ -287,7 +287,7 @@ impl VideoFrameRenderer for MediaFrameRenderer {
|
|||
updates.push(ImageUpdate::AddImage(image_key, descriptor, image_data));
|
||||
},
|
||||
}
|
||||
self.api.update_images(updates);
|
||||
self.compositor_api.update_images(updates);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -446,7 +446,7 @@ impl HTMLMediaElement {
|
|||
in_flight_play_promises_queue: Default::default(),
|
||||
player: Default::default(),
|
||||
video_renderer: Arc::new(Mutex::new(MediaFrameRenderer::new(
|
||||
document.window().get_webrender_api_sender(),
|
||||
document.window().compositor_api().clone(),
|
||||
))),
|
||||
audio_renderer: Default::default(),
|
||||
show_poster: Cell::new(true),
|
||||
|
|
|
@ -5,16 +5,14 @@
|
|||
use dom_struct::dom_struct;
|
||||
use euclid::Size2D;
|
||||
use profile_traits::ipc;
|
||||
use script_traits::ScriptMsg;
|
||||
use style_traits::CSSPixel;
|
||||
use webrender_api::units::DeviceIntSize;
|
||||
use webrender_traits::CrossProcessCompositorMessage;
|
||||
|
||||
use crate::dom::bindings::codegen::Bindings::ScreenBinding::ScreenMethods;
|
||||
use crate::dom::bindings::inheritance::Castable;
|
||||
use crate::dom::bindings::num::Finite;
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
|
||||
use crate::dom::bindings::root::{Dom, DomRoot};
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::window::Window;
|
||||
|
||||
#[dom_struct]
|
||||
|
@ -39,9 +37,9 @@ impl Screen {
|
|||
let (send, recv) =
|
||||
ipc::channel::<DeviceIntSize>(self.global().time_profiler_chan().clone()).unwrap();
|
||||
self.window
|
||||
.upcast::<GlobalScope>()
|
||||
.script_to_constellation_chan()
|
||||
.send(ScriptMsg::GetScreenSize(send))
|
||||
.compositor_api()
|
||||
.sender()
|
||||
.send(CrossProcessCompositorMessage::GetScreenSize(send))
|
||||
.unwrap();
|
||||
let dpr = self.window.device_pixel_ratio();
|
||||
let screen = recv.recv().unwrap_or(Size2D::zero());
|
||||
|
@ -52,9 +50,9 @@ impl Screen {
|
|||
let (send, recv) =
|
||||
ipc::channel::<DeviceIntSize>(self.global().time_profiler_chan().clone()).unwrap();
|
||||
self.window
|
||||
.upcast::<GlobalScope>()
|
||||
.script_to_constellation_chan()
|
||||
.send(ScriptMsg::GetScreenAvailSize(send))
|
||||
.compositor_api()
|
||||
.sender()
|
||||
.send(CrossProcessCompositorMessage::GetAvailableScreenSize(send))
|
||||
.unwrap();
|
||||
let dpr = self.window.device_pixel_ratio();
|
||||
let screen = recv.recv().unwrap_or(Size2D::zero());
|
||||
|
|
|
@ -76,9 +76,9 @@ use style::str::HTML_SPACE_CHARACTERS;
|
|||
use style::stylesheets::{CssRuleType, Origin, UrlExtraData};
|
||||
use style_traits::{CSSPixel, DevicePixel, ParsingMode};
|
||||
use url::Position;
|
||||
use webrender_api::units::{DeviceIntPoint, DeviceIntSize, LayoutPixel};
|
||||
use webrender_api::units::{DeviceIntRect, LayoutPixel};
|
||||
use webrender_api::{DocumentId, ExternalScrollId};
|
||||
use webrender_traits::WebRenderScriptApi;
|
||||
use webrender_traits::CrossProcessCompositorApi;
|
||||
|
||||
use super::bindings::codegen::Bindings::MessagePortBinding::StructuredSerializeOptions;
|
||||
use super::bindings::trace::HashMapTracedValues;
|
||||
|
@ -312,10 +312,10 @@ pub struct Window {
|
|||
/// Flag to identify whether mutation observers are present(true)/absent(false)
|
||||
exists_mut_observer: Cell<bool>,
|
||||
|
||||
/// Webrender API Sender
|
||||
/// Cross-process access to the compositor.
|
||||
#[ignore_malloc_size_of = "Wraps an IpcSender"]
|
||||
#[no_trace]
|
||||
webrender_api_sender: WebRenderScriptApi,
|
||||
compositor_api: CrossProcessCompositorApi,
|
||||
|
||||
/// Indicate whether a SetDocumentStatus message has been sent after a reflow is complete.
|
||||
/// It is used to avoid sending idle message more than once, which is unneccessary.
|
||||
|
@ -526,8 +526,8 @@ impl Window {
|
|||
self.add_pending_reflow();
|
||||
}
|
||||
|
||||
pub fn get_webrender_api_sender(&self) -> WebRenderScriptApi {
|
||||
self.webrender_api_sender.clone()
|
||||
pub fn compositor_api(&self) -> &CrossProcessCompositorApi {
|
||||
&self.compositor_api
|
||||
}
|
||||
|
||||
pub fn get_userscripts_path(&self) -> Option<String> {
|
||||
|
@ -1773,14 +1773,16 @@ impl Window {
|
|||
|
||||
fn client_window(&self) -> (Size2D<u32, CSSPixel>, Point2D<i32, CSSPixel>) {
|
||||
let timer_profile_chan = self.global().time_profiler_chan().clone();
|
||||
let (send, recv) =
|
||||
ProfiledIpc::channel::<(DeviceIntSize, DeviceIntPoint)>(timer_profile_chan).unwrap();
|
||||
self.send_to_constellation(ScriptMsg::GetClientWindow(send));
|
||||
let (size, point) = recv.recv().unwrap_or((Size2D::zero(), Point2D::zero()));
|
||||
let (send, recv) = ProfiledIpc::channel::<DeviceIntRect>(timer_profile_chan).unwrap();
|
||||
let _ = self
|
||||
.compositor_api
|
||||
.sender()
|
||||
.send(webrender_traits::CrossProcessCompositorMessage::GetClientWindowRect(send));
|
||||
let rect = recv.recv().unwrap_or_default();
|
||||
let dpr = self.device_pixel_ratio();
|
||||
(
|
||||
(size.to_f32() / dpr).to_u32(),
|
||||
(point.to_f32() / dpr).to_i32(),
|
||||
(rect.size().to_f32() / dpr).to_u32(),
|
||||
(rect.min.to_f32() / dpr).to_i32(),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -2548,7 +2550,7 @@ impl Window {
|
|||
webxr_registry: webxr_api::Registry,
|
||||
microtask_queue: Rc<MicrotaskQueue>,
|
||||
webrender_document: DocumentId,
|
||||
webrender_api_sender: WebRenderScriptApi,
|
||||
compositor_api: CrossProcessCompositorApi,
|
||||
relayout_event: bool,
|
||||
prepare_for_screenshot: bool,
|
||||
unminify_js: bool,
|
||||
|
@ -2633,7 +2635,7 @@ impl Window {
|
|||
paint_worklet: Default::default(),
|
||||
webrender_document,
|
||||
exists_mut_observer: Cell::new(false),
|
||||
webrender_api_sender,
|
||||
compositor_api,
|
||||
has_sent_idle_message: Cell::new(false),
|
||||
relayout_event,
|
||||
prepare_for_screenshot,
|
||||
|
|
|
@ -95,7 +95,7 @@ use style::thread_state::{self, ThreadState};
|
|||
use url::Position;
|
||||
use webgpu::{WebGPUDevice, WebGPUMsg};
|
||||
use webrender_api::DocumentId;
|
||||
use webrender_traits::WebRenderScriptApi;
|
||||
use webrender_traits::CrossProcessCompositorApi;
|
||||
|
||||
use crate::document_loader::DocumentLoader;
|
||||
use crate::dom::bindings::cell::DomRefCell;
|
||||
|
@ -669,9 +669,9 @@ pub struct ScriptThread {
|
|||
#[no_trace]
|
||||
webrender_document: DocumentId,
|
||||
|
||||
/// Webrender API sender.
|
||||
/// Cross-process access to the compositor's API.
|
||||
#[no_trace]
|
||||
webrender_api_sender: WebRenderScriptApi,
|
||||
compositor_api: CrossProcessCompositorApi,
|
||||
|
||||
/// Periodically print out on which events script threads spend their processing time.
|
||||
profile_script_events: bool,
|
||||
|
@ -1399,7 +1399,7 @@ impl ScriptThread {
|
|||
custom_element_reaction_stack: CustomElementReactionStack::new(),
|
||||
|
||||
webrender_document: state.webrender_document,
|
||||
webrender_api_sender: state.webrender_api_sender,
|
||||
compositor_api: state.compositor_api,
|
||||
|
||||
profile_script_events: opts.debug.profile_script_events,
|
||||
print_pwm: opts.print_pwm,
|
||||
|
@ -3661,7 +3661,7 @@ impl ScriptThread {
|
|||
system_font_service: self.system_font_service.clone(),
|
||||
resource_threads: self.resource_threads.clone(),
|
||||
time_profiler_chan: self.time_profiler_chan.clone(),
|
||||
webrender_api_sender: self.webrender_api_sender.clone(),
|
||||
compositor_api: self.compositor_api.clone(),
|
||||
paint_time_metrics,
|
||||
window_size: incomplete.window_size,
|
||||
};
|
||||
|
@ -3692,7 +3692,7 @@ impl ScriptThread {
|
|||
self.webxr_registry.clone(),
|
||||
self.microtask_queue.clone(),
|
||||
self.webrender_document,
|
||||
self.webrender_api_sender.clone(),
|
||||
self.compositor_api.clone(),
|
||||
self.relayout_event,
|
||||
self.prepare_for_screenshot,
|
||||
self.unminify_js,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue