compositing_traits/
lib.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5//! The interface to the `compositing` crate.
6
7use std::fmt::{Debug, Error, Formatter};
8
9use base::Epoch;
10use base::id::{PipelineId, WebViewId};
11use crossbeam_channel::Sender;
12use embedder_traits::{AnimationState, EventLoopWaker, TouchEventResult};
13use ipc_channel::ipc::IpcSender;
14use log::warn;
15use malloc_size_of_derive::MallocSizeOf;
16use smallvec::SmallVec;
17use strum_macros::IntoStaticStr;
18use webrender_api::{DocumentId, FontVariation};
19
20pub mod display_list;
21pub mod rendering_context;
22pub mod viewport_description;
23
24use std::collections::HashMap;
25use std::sync::{Arc, Mutex};
26
27use base::generic_channel::{self, GenericCallback, GenericSender};
28use bitflags::bitflags;
29use display_list::CompositorDisplayListInfo;
30use embedder_traits::ScreenGeometry;
31use euclid::default::Size2D as UntypedSize2D;
32use ipc_channel::ipc::{self, IpcSharedMemory};
33use profile_traits::mem::{OpaqueSender, ReportsChan};
34use serde::{Deserialize, Serialize};
35pub use webrender_api::ExternalImageSource;
36use webrender_api::units::{LayoutVector2D, TexelRect};
37use webrender_api::{
38    BuiltDisplayList, BuiltDisplayListDescriptor, ExternalImage, ExternalImageData,
39    ExternalImageHandler, ExternalImageId, ExternalScrollId, FontInstanceFlags, FontInstanceKey,
40    FontKey, ImageData, ImageDescriptor, ImageKey, NativeFontHandle,
41    PipelineId as WebRenderPipelineId,
42};
43
44use crate::viewport_description::ViewportDescription;
45
46/// Sends messages to the compositor.
47#[derive(Clone)]
48pub struct CompositorProxy {
49    pub sender: Sender<Result<CompositorMsg, ipc_channel::Error>>,
50    /// Access to [`Self::sender`] that is possible to send across an IPC
51    /// channel. These messages are routed via the router thread to
52    /// [`Self::sender`].
53    pub cross_process_compositor_api: CrossProcessCompositorApi,
54    pub event_loop_waker: Box<dyn EventLoopWaker>,
55}
56
57impl OpaqueSender<CompositorMsg> for CompositorProxy {
58    fn send(&self, message: CompositorMsg) {
59        CompositorProxy::send(self, message)
60    }
61}
62
63impl CompositorProxy {
64    pub fn send(&self, msg: CompositorMsg) {
65        self.route_msg(Ok(msg))
66    }
67
68    /// Helper method to route a deserialized IPC message to the receiver.
69    ///
70    /// This method is a temporary solution, and will be removed when migrating
71    /// to `GenericChannel`.
72    pub fn route_msg(&self, msg: Result<CompositorMsg, ipc_channel::Error>) {
73        if let Err(err) = self.sender.send(msg) {
74            warn!("Failed to send response ({:?}).", err);
75        }
76        self.event_loop_waker.wake();
77    }
78}
79
80/// Messages from (or via) the constellation thread to the compositor.
81#[derive(Deserialize, IntoStaticStr, Serialize)]
82pub enum CompositorMsg {
83    /// Alerts the compositor that the given pipeline has changed whether it is running animations.
84    ChangeRunningAnimationsState(WebViewId, PipelineId, AnimationState),
85    /// Create or update a webview, given its frame tree.
86    CreateOrUpdateWebView(SendableFrameTree),
87    /// Remove a webview.
88    RemoveWebView(WebViewId),
89    /// Script has handled a touch event, and either prevented or allowed default actions.
90    TouchEventProcessed(WebViewId, TouchEventResult),
91    /// A reply to the compositor asking if the output image is stable.
92    IsReadyToSaveImageReply(bool),
93    /// Set whether to use less resources by stopping animations.
94    SetThrottled(WebViewId, PipelineId, bool),
95    /// WebRender has produced a new frame. This message informs the compositor that
96    /// the frame is ready. It contains a bool to indicate if it needs to composite and the
97    /// `DocumentId` of the new frame.
98    NewWebRenderFrameReady(DocumentId, bool),
99    /// Script or the Constellation is notifying the renderer that a Pipeline has finished
100    /// shutting down. The renderer will not discard the Pipeline until both report that
101    /// they have fully shut it down, to avoid recreating it due to any subsequent
102    /// messages.
103    PipelineExited(WebViewId, PipelineId, PipelineExitSource),
104    /// The load of a page has completed
105    LoadComplete(WebViewId),
106    /// Inform WebRender of the existence of this pipeline.
107    SendInitialTransaction(WebRenderPipelineId),
108    /// Perform a scroll operation.
109    SendScrollNode(
110        WebViewId,
111        WebRenderPipelineId,
112        LayoutVector2D,
113        ExternalScrollId,
114    ),
115    /// Inform WebRender of a new display list for the given pipeline.
116    SendDisplayList {
117        /// The [`WebViewId`] that this display list belongs to.
118        webview_id: WebViewId,
119        /// A descriptor of this display list used to construct this display list from raw data.
120        display_list_descriptor: BuiltDisplayListDescriptor,
121        /// An [ipc::IpcBytesReceiver] used to send the raw data of the display list.
122        display_list_receiver: ipc::IpcBytesReceiver,
123    },
124    /// Ask the renderer to generate a frame for the current set of display lists that
125    /// have been sent to the renderer.
126    GenerateFrame,
127    /// Create a new image key. The result will be returned via the
128    /// provided channel sender.
129    GenerateImageKey(IpcSender<ImageKey>),
130    /// The same as the above but it will be forwarded to the pipeline instead
131    /// of send via a channel.
132    GenerateImageKeysForPipeline(PipelineId),
133    /// Perform a resource update operation.
134    UpdateImages(SmallVec<[ImageUpdate; 1]>),
135    /// Pause all pipeline display list processing for the given pipeline until the
136    /// following image updates have been received. This is used to ensure that canvas
137    /// elements have had a chance to update their rendering and send the image update to
138    /// the renderer before their associated display list is actually displayed.
139    DelayNewFrameForCanvas(PipelineId, Epoch, Vec<ImageKey>),
140
141    /// Generate a new batch of font keys which can be used to allocate
142    /// keys asynchronously.
143    GenerateFontKeys(
144        usize,
145        usize,
146        GenericSender<(Vec<FontKey>, Vec<FontInstanceKey>)>,
147    ),
148    /// Add a font with the given data and font key.
149    AddFont(FontKey, Arc<IpcSharedMemory>, u32),
150    /// Add a system font with the given font key and handle.
151    AddSystemFont(FontKey, NativeFontHandle),
152    /// Add an instance of a font with the given instance key.
153    AddFontInstance(
154        FontInstanceKey,
155        FontKey,
156        f32,
157        FontInstanceFlags,
158        Vec<FontVariation>,
159    ),
160    /// Remove the given font resources from our WebRender instance.
161    RemoveFonts(Vec<FontKey>, Vec<FontInstanceKey>),
162    /// Measure the current memory usage associated with the compositor.
163    /// The report must be sent on the provided channel once it's complete.
164    CollectMemoryReport(ReportsChan),
165    /// A top-level frame has parsed a viewport metatag and is sending the new constraints.
166    Viewport(WebViewId, ViewportDescription),
167}
168
169impl Debug for CompositorMsg {
170    fn fmt(&self, formatter: &mut Formatter) -> Result<(), Error> {
171        let string: &'static str = self.into();
172        write!(formatter, "{string}")
173    }
174}
175
176#[derive(Deserialize, Serialize)]
177pub struct SendableFrameTree {
178    pub pipeline: CompositionPipeline,
179    pub children: Vec<SendableFrameTree>,
180}
181
182/// The subset of the pipeline that is needed for layer composition.
183#[derive(Clone, Deserialize, Serialize)]
184pub struct CompositionPipeline {
185    pub id: PipelineId,
186    pub webview_id: WebViewId,
187}
188
189/// A mechanism to send messages from ScriptThread to the parent process' WebRender instance.
190#[derive(Clone, Deserialize, MallocSizeOf, Serialize)]
191pub struct CrossProcessCompositorApi(GenericCallback<CompositorMsg>);
192
193impl CrossProcessCompositorApi {
194    /// Create a new [`CrossProcessCompositorApi`] struct.
195    pub fn new(callback: GenericCallback<CompositorMsg>) -> Self {
196        CrossProcessCompositorApi(callback)
197    }
198
199    /// Create a new [`CrossProcessCompositorApi`] struct that does not have a listener on the other
200    /// end to use for unit testing.
201    pub fn dummy() -> Self {
202        let callback = GenericCallback::new(|_msg| ()).unwrap();
203        Self(callback)
204    }
205
206    /// Inform WebRender of the existence of this pipeline.
207    pub fn send_initial_transaction(&self, pipeline: WebRenderPipelineId) {
208        if let Err(e) = self.0.send(CompositorMsg::SendInitialTransaction(pipeline)) {
209            warn!("Error sending initial transaction: {}", e);
210        }
211    }
212
213    /// Perform a scroll operation.
214    pub fn send_scroll_node(
215        &self,
216        webview_id: WebViewId,
217        pipeline_id: WebRenderPipelineId,
218        point: LayoutVector2D,
219        scroll_id: ExternalScrollId,
220    ) {
221        if let Err(e) = self.0.send(CompositorMsg::SendScrollNode(
222            webview_id,
223            pipeline_id,
224            point,
225            scroll_id,
226        )) {
227            warn!("Error sending scroll node: {}", e);
228        }
229    }
230
231    pub fn delay_new_frame_for_canvas(
232        &self,
233        pipeline_id: PipelineId,
234        canvas_epoch: Epoch,
235        image_keys: Vec<ImageKey>,
236    ) {
237        if let Err(error) = self.0.send(CompositorMsg::DelayNewFrameForCanvas(
238            pipeline_id,
239            canvas_epoch,
240            image_keys,
241        )) {
242            warn!("Error delaying frames for canvas image updates {error:?}");
243        }
244    }
245
246    /// Inform WebRender of a new display list for the given pipeline.
247    pub fn send_display_list(
248        &self,
249        webview_id: WebViewId,
250        display_list_info: &CompositorDisplayListInfo,
251        list: BuiltDisplayList,
252    ) {
253        let (display_list_data, display_list_descriptor) = list.into_data();
254        let (display_list_sender, display_list_receiver) = ipc::bytes_channel().unwrap();
255        if let Err(e) = self.0.send(CompositorMsg::SendDisplayList {
256            webview_id,
257            display_list_descriptor,
258            display_list_receiver,
259        }) {
260            warn!("Error sending display list: {}", e);
261        }
262
263        let display_list_info_serialized =
264            bincode::serialize(&display_list_info).unwrap_or_default();
265        if let Err(error) = display_list_sender.send(&display_list_info_serialized) {
266            warn!("Error sending display list info: {error}");
267        }
268
269        if let Err(error) = display_list_sender.send(&display_list_data.items_data) {
270            warn!("Error sending display list items: {error}");
271        }
272        if let Err(error) = display_list_sender.send(&display_list_data.cache_data) {
273            warn!("Error sending display list cache data: {error}");
274        }
275        if let Err(error) = display_list_sender.send(&display_list_data.spatial_tree) {
276            warn!("Error sending display spatial tree: {error}");
277        }
278    }
279
280    /// Ask the Servo renderer to generate a new frame after having new display lists.
281    pub fn generate_frame(&self) {
282        if let Err(error) = self.0.send(CompositorMsg::GenerateFrame) {
283            warn!("Error generating frame: {error}");
284        }
285    }
286
287    /// Create a new image key. Blocks until the key is available.
288    pub fn generate_image_key_blocking(&self) -> Option<ImageKey> {
289        let (sender, receiver) = ipc::channel().unwrap();
290        self.0.send(CompositorMsg::GenerateImageKey(sender)).ok()?;
291        receiver.recv().ok()
292    }
293
294    /// Sends a message to the compositor for creating new image keys.
295    /// The compositor will then send a batch of keys over the constellation to the script_thread
296    /// and the appropriate pipeline.
297    pub fn generate_image_key_async(&self, pipeline_id: PipelineId) {
298        if let Err(e) = self
299            .0
300            .send(CompositorMsg::GenerateImageKeysForPipeline(pipeline_id))
301        {
302            warn!("Could not send image keys to Compositor {}", e);
303        }
304    }
305
306    pub fn add_image(
307        &self,
308        key: ImageKey,
309        descriptor: ImageDescriptor,
310        data: SerializableImageData,
311    ) {
312        self.update_images([ImageUpdate::AddImage(key, descriptor, data)].into());
313    }
314
315    pub fn update_image(
316        &self,
317        key: ImageKey,
318        descriptor: ImageDescriptor,
319        data: SerializableImageData,
320        epoch: Option<Epoch>,
321    ) {
322        self.update_images([ImageUpdate::UpdateImage(key, descriptor, data, epoch)].into());
323    }
324
325    pub fn delete_image(&self, key: ImageKey) {
326        self.update_images([ImageUpdate::DeleteImage(key)].into());
327    }
328
329    /// Perform an image resource update operation.
330    pub fn update_images(&self, updates: SmallVec<[ImageUpdate; 1]>) {
331        if let Err(e) = self.0.send(CompositorMsg::UpdateImages(updates)) {
332            warn!("error sending image updates: {}", e);
333        }
334    }
335
336    pub fn remove_unused_font_resources(
337        &self,
338        keys: Vec<FontKey>,
339        instance_keys: Vec<FontInstanceKey>,
340    ) {
341        if keys.is_empty() && instance_keys.is_empty() {
342            return;
343        }
344        let _ = self.0.send(CompositorMsg::RemoveFonts(keys, instance_keys));
345    }
346
347    pub fn add_font_instance(
348        &self,
349        font_instance_key: FontInstanceKey,
350        font_key: FontKey,
351        size: f32,
352        flags: FontInstanceFlags,
353        variations: Vec<FontVariation>,
354    ) {
355        let _x = self.0.send(CompositorMsg::AddFontInstance(
356            font_instance_key,
357            font_key,
358            size,
359            flags,
360            variations,
361        ));
362    }
363
364    pub fn add_font(&self, font_key: FontKey, data: Arc<IpcSharedMemory>, index: u32) {
365        let _ = self.0.send(CompositorMsg::AddFont(font_key, data, index));
366    }
367
368    pub fn add_system_font(&self, font_key: FontKey, handle: NativeFontHandle) {
369        let _ = self.0.send(CompositorMsg::AddSystemFont(font_key, handle));
370    }
371
372    pub fn fetch_font_keys(
373        &self,
374        number_of_font_keys: usize,
375        number_of_font_instance_keys: usize,
376    ) -> (Vec<FontKey>, Vec<FontInstanceKey>) {
377        let (sender, receiver) = generic_channel::channel().expect("Could not create IPC channel");
378        let _ = self.0.send(CompositorMsg::GenerateFontKeys(
379            number_of_font_keys,
380            number_of_font_instance_keys,
381            sender,
382        ));
383        receiver.recv().unwrap()
384    }
385
386    pub fn viewport(&self, webview_id: WebViewId, description: ViewportDescription) {
387        let _ = self
388            .0
389            .send(CompositorMsg::Viewport(webview_id, description));
390    }
391
392    pub fn pipeline_exited(
393        &self,
394        webview_id: WebViewId,
395        pipeline_id: PipelineId,
396        source: PipelineExitSource,
397    ) {
398        let _ = self.0.send(CompositorMsg::PipelineExited(
399            webview_id,
400            pipeline_id,
401            source,
402        ));
403    }
404}
405
406/// This trait is used as a bridge between the different GL clients
407/// in Servo that handles WebRender ExternalImages and the WebRender
408/// ExternalImageHandler API.
409//
410/// This trait is used to notify lock/unlock messages and get the
411/// required info that WR needs.
412pub trait WebrenderExternalImageApi {
413    fn lock(&mut self, id: u64) -> (ExternalImageSource<'_>, UntypedSize2D<i32>);
414    fn unlock(&mut self, id: u64);
415}
416
417/// Type of Webrender External Image Handler.
418pub enum WebrenderImageHandlerType {
419    WebGL,
420    Media,
421    WebGPU,
422}
423
424/// List of Webrender external images to be shared among all external image
425/// consumers (WebGL, Media, WebGPU).
426/// It ensures that external image identifiers are unique.
427#[derive(Default)]
428pub struct WebrenderExternalImageRegistry {
429    /// Map of all generated external images.
430    external_images: HashMap<ExternalImageId, WebrenderImageHandlerType>,
431    /// Id generator for the next external image identifier.
432    next_image_id: u64,
433}
434
435impl WebrenderExternalImageRegistry {
436    pub fn next_id(&mut self, handler_type: WebrenderImageHandlerType) -> ExternalImageId {
437        self.next_image_id += 1;
438        let key = ExternalImageId(self.next_image_id);
439        self.external_images.insert(key, handler_type);
440        key
441    }
442
443    pub fn remove(&mut self, key: &ExternalImageId) {
444        self.external_images.remove(key);
445    }
446
447    pub fn get(&self, key: &ExternalImageId) -> Option<&WebrenderImageHandlerType> {
448        self.external_images.get(key)
449    }
450}
451
452/// WebRender External Image Handler implementation.
453pub struct WebrenderExternalImageHandlers {
454    /// WebGL handler.
455    webgl_handler: Option<Box<dyn WebrenderExternalImageApi>>,
456    /// Media player handler.
457    media_handler: Option<Box<dyn WebrenderExternalImageApi>>,
458    /// WebGPU handler.
459    webgpu_handler: Option<Box<dyn WebrenderExternalImageApi>>,
460    /// Webrender external images.
461    external_images: Arc<Mutex<WebrenderExternalImageRegistry>>,
462}
463
464impl WebrenderExternalImageHandlers {
465    pub fn new() -> (Self, Arc<Mutex<WebrenderExternalImageRegistry>>) {
466        let external_images = Arc::new(Mutex::new(WebrenderExternalImageRegistry::default()));
467        (
468            Self {
469                webgl_handler: None,
470                media_handler: None,
471                webgpu_handler: None,
472                external_images: external_images.clone(),
473            },
474            external_images,
475        )
476    }
477
478    pub fn set_handler(
479        &mut self,
480        handler: Box<dyn WebrenderExternalImageApi>,
481        handler_type: WebrenderImageHandlerType,
482    ) {
483        match handler_type {
484            WebrenderImageHandlerType::WebGL => self.webgl_handler = Some(handler),
485            WebrenderImageHandlerType::Media => self.media_handler = Some(handler),
486            WebrenderImageHandlerType::WebGPU => self.webgpu_handler = Some(handler),
487        }
488    }
489}
490
491impl ExternalImageHandler for WebrenderExternalImageHandlers {
492    /// Lock the external image. Then, WR could start to read the
493    /// image content.
494    /// The WR client should not change the image content until the
495    /// unlock() call.
496    fn lock(&mut self, key: ExternalImageId, _channel_index: u8) -> ExternalImage<'_> {
497        let external_images = self.external_images.lock().unwrap();
498        let handler_type = external_images
499            .get(&key)
500            .expect("Tried to get unknown external image");
501        match handler_type {
502            WebrenderImageHandlerType::WebGL => {
503                let (source, size) = self.webgl_handler.as_mut().unwrap().lock(key.0);
504                let texture_id = match source {
505                    ExternalImageSource::NativeTexture(b) => b,
506                    _ => panic!("Wrong type"),
507                };
508                ExternalImage {
509                    uv: TexelRect::new(0.0, size.height as f32, size.width as f32, 0.0),
510                    source: ExternalImageSource::NativeTexture(texture_id),
511                }
512            },
513            WebrenderImageHandlerType::Media => {
514                let (source, size) = self.media_handler.as_mut().unwrap().lock(key.0);
515                let texture_id = match source {
516                    ExternalImageSource::NativeTexture(b) => b,
517                    _ => panic!("Wrong type"),
518                };
519                ExternalImage {
520                    uv: TexelRect::new(0.0, size.height as f32, size.width as f32, 0.0),
521                    source: ExternalImageSource::NativeTexture(texture_id),
522                }
523            },
524            WebrenderImageHandlerType::WebGPU => {
525                let (source, size) = self.webgpu_handler.as_mut().unwrap().lock(key.0);
526                let buffer = match source {
527                    ExternalImageSource::RawData(b) => b,
528                    _ => panic!("Wrong type"),
529                };
530                ExternalImage {
531                    uv: TexelRect::new(0.0, size.height as f32, size.width as f32, 0.0),
532                    source: ExternalImageSource::RawData(buffer),
533                }
534            },
535        }
536    }
537
538    /// Unlock the external image. The WR should not read the image
539    /// content after this call.
540    fn unlock(&mut self, key: ExternalImageId, _channel_index: u8) {
541        let external_images = self.external_images.lock().unwrap();
542        let handler_type = external_images
543            .get(&key)
544            .expect("Tried to get unknown external image");
545        match handler_type {
546            WebrenderImageHandlerType::WebGL => self.webgl_handler.as_mut().unwrap().unlock(key.0),
547            WebrenderImageHandlerType::Media => self.media_handler.as_mut().unwrap().unlock(key.0),
548            WebrenderImageHandlerType::WebGPU => {
549                self.webgpu_handler.as_mut().unwrap().unlock(key.0)
550            },
551        };
552    }
553}
554
555#[derive(Deserialize, Serialize)]
556/// Serializable image updates that must be performed by WebRender.
557pub enum ImageUpdate {
558    /// Register a new image.
559    AddImage(ImageKey, ImageDescriptor, SerializableImageData),
560    /// Delete a previously registered image registration.
561    DeleteImage(ImageKey),
562    /// Update an existing image registration.
563    UpdateImage(
564        ImageKey,
565        ImageDescriptor,
566        SerializableImageData,
567        Option<Epoch>,
568    ),
569}
570
571impl Debug for ImageUpdate {
572    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
573        match self {
574            Self::AddImage(image_key, image_desc, _) => f
575                .debug_tuple("AddImage")
576                .field(image_key)
577                .field(image_desc)
578                .finish(),
579            Self::DeleteImage(image_key) => f.debug_tuple("DeleteImage").field(image_key).finish(),
580            Self::UpdateImage(image_key, image_desc, _, epoch) => f
581                .debug_tuple("UpdateImage")
582                .field(image_key)
583                .field(image_desc)
584                .field(epoch)
585                .finish(),
586        }
587    }
588}
589
590#[derive(Debug, Deserialize, Serialize)]
591/// Serialized `ImageData`. It contains IPC byte channel receiver to prevent from loading bytes too
592/// slow.
593pub enum SerializableImageData {
594    /// A simple series of bytes, provided by the embedding and owned by WebRender.
595    /// The format is stored out-of-band, currently in ImageDescriptor.
596    Raw(IpcSharedMemory),
597    /// An image owned by the embedding, and referenced by WebRender. This may
598    /// take the form of a texture or a heap-allocated buffer.
599    External(ExternalImageData),
600}
601
602impl From<SerializableImageData> for ImageData {
603    fn from(value: SerializableImageData) -> Self {
604        match value {
605            SerializableImageData::Raw(shared_memory) => ImageData::new(shared_memory.to_vec()),
606            SerializableImageData::External(image) => ImageData::External(image),
607        }
608    }
609}
610
611/// A trait that exposes the embedding layer's `WebView` to the Servo renderer.
612/// This is to prevent a dependency cycle between the renderer and the embedding
613/// layer.
614pub trait WebViewTrait {
615    fn id(&self) -> WebViewId;
616    fn screen_geometry(&self) -> Option<ScreenGeometry>;
617    fn set_animating(&self, new_value: bool);
618}
619
620/// What entity is reporting that a `Pipeline` has exited. Only when all have
621/// done this will the renderer discard its details.
622#[derive(Clone, Copy, Default, Deserialize, PartialEq, Serialize)]
623pub struct PipelineExitSource(u8);
624
625bitflags! {
626    impl PipelineExitSource: u8 {
627        const Script = 1 << 0;
628        const Constellation = 1 << 1;
629    }
630}