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