/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ //! The `webrender_api` crate contains an assortment types and functions used //! by WebRender consumers as well as, in many cases, WebRender itself. //! //! This separation allows Servo to parallelize compilation across `webrender` //! and other crates that depend on `webrender_api`. So in practice, we put //! things in this crate when Servo needs to use them. Firefox depends on the //! `webrender` crate directly, and so this distinction is not really relevant //! there. #![cfg_attr(feature = "nightly", feature(nonzero))] #![cfg_attr(feature = "cargo-clippy", allow(clippy::float_cmp, clippy::too_many_arguments))] #![cfg_attr(feature = "cargo-clippy", allow(clippy::unreadable_literal, clippy::new_without_default))] pub extern crate crossbeam_channel; pub extern crate euclid; extern crate app_units; #[macro_use] extern crate bitflags; extern crate byteorder; #[cfg(feature = "nightly")] extern crate core; #[macro_use] extern crate malloc_size_of_derive; extern crate serde; #[macro_use] extern crate serde_derive; extern crate time; extern crate malloc_size_of; extern crate peek_poke; pub mod channel; mod color; mod display_item; mod display_item_cache; mod display_list; mod font; mod gradient_builder; mod image; pub mod units; pub use crate::color::*; pub use crate::display_item::*; pub use crate::display_item_cache::DisplayItemCache; pub use crate::display_list::*; pub use crate::font::*; pub use crate::gradient_builder::*; pub use crate::image::*; use crate::units::*; use crate::channel::Receiver; use std::marker::PhantomData; use std::sync::Arc; use std::os::raw::c_void; use peek_poke::PeekPoke; /// Defined here for cbindgen pub const MAX_RENDER_TASK_SIZE: i32 = 16384; /// Width and height in device pixels of image tiles. pub type TileSize = u16; /// Various settings that the caller can select based on desired tradeoffs /// between rendering quality and performance / power usage. #[derive(Copy, Clone, Deserialize, Serialize)] pub struct QualitySettings { /// If true, disable creating separate picture cache slices when the /// scroll root changes. This gives maximum opportunity to find an /// opaque background, which enables subpixel AA. However, it is /// usually significantly more expensive to render when scrolling. pub force_subpixel_aa_where_possible: bool, } impl Default for QualitySettings { fn default() -> Self { QualitySettings { // Prefer performance over maximum subpixel AA quality, since WR // already enables subpixel AA in more situations than other browsers. force_subpixel_aa_where_possible: false, } } } /// An epoch identifies the state of a pipeline in time. /// /// This is mostly used as a synchronization mechanism to observe how/when particular pipeline /// updates propagate through WebRender and are applied at various stages. #[repr(C)] #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)] pub struct Epoch(pub u32); impl Epoch { /// Magic invalid epoch value. pub fn invalid() -> Epoch { Epoch(u32::MAX) } } /// ID namespaces uniquely identify different users of WebRender's API. /// /// For example in Gecko each content process uses a separate id namespace. #[repr(C)] #[derive(Clone, Copy, Debug, Default, Eq, MallocSizeOf, PartialEq, Hash, Ord, PartialOrd, PeekPoke)] #[derive(Deserialize, Serialize)] pub struct IdNamespace(pub u32); /// A key uniquely identifying a WebRender document. /// /// Instances can manage one or several documents (using the same render backend thread). /// Each document will internally correspond to a single scene, and scenes are made of /// one or several pipelines. #[repr(C)] #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)] pub struct DocumentId { /// pub namespace_id: IdNamespace, /// pub id: u32, } impl DocumentId { /// pub fn new(namespace_id: IdNamespace, id: u32) -> Self { DocumentId { namespace_id, id, } } /// pub const INVALID: DocumentId = DocumentId { namespace_id: IdNamespace(0), id: 0 }; } /// This type carries no valuable semantics for WR. However, it reflects the fact that /// clients (Servo) may generate pipelines by different semi-independent sources. /// These pipelines still belong to the same `IdNamespace` and the same `DocumentId`. /// Having this extra Id field enables them to generate `PipelineId` without collision. pub type PipelineSourceId = u32; /// From the point of view of WR, `PipelineId` is completely opaque and generic as long as /// it's clonable, serializable, comparable, and hashable. #[repr(C)] #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)] pub struct PipelineId(pub PipelineSourceId, pub u32); impl Default for PipelineId { fn default() -> Self { PipelineId::dummy() } } impl PipelineId { /// pub fn dummy() -> Self { PipelineId(!0, !0) } pub const INVALID: Self = PipelineId(!0, !0); } #[repr(C)] #[derive(Clone, Copy, Debug, PartialEq, PartialOrd)] pub struct FramePublishId(pub u64); impl FramePublishId { /// Returns a FramePublishId corresponding to the first frame. /// /// Note that we use 0 as the internal id here because the current code /// increments the frame publish id just before ResultMsg::PublishDocument, /// and we want the first id to be 1. pub fn first() -> Self { FramePublishId(0) } /// Advances this FramePublishId to the next. pub fn advance(&mut self) { self.0 += 1; } /// An invalid sentinel FramePublishId, which will always compare less than /// any valid FrameId. pub const INVALID: Self = FramePublishId(0); } impl Default for FramePublishId { fn default() -> Self { FramePublishId::INVALID } } /// An opaque pointer-sized value. #[repr(C)] #[derive(Clone)] pub struct ExternalEvent { raw: usize, } unsafe impl Send for ExternalEvent {} impl ExternalEvent { /// Creates the event from an opaque pointer-sized value. pub fn from_raw(raw: usize) -> Self { ExternalEvent { raw } } /// Consumes self to make it obvious that the event should be forwarded only once. pub fn unwrap(self) -> usize { self.raw } } pub type APZScrollGeneration = u64; #[repr(C)] #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, Default)] pub struct SampledScrollOffset { pub offset: LayoutVector2D, pub generation: APZScrollGeneration, } /// A flag in each scrollable frame to represent whether the owner of the frame document /// has any scroll-linked effect. /// See https://firefox-source-docs.mozilla.org/performance/scroll-linked_effects.html /// for a definition of scroll-linked effect. #[repr(u8)] #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, PeekPoke)] pub enum HasScrollLinkedEffect { Yes, No, } impl Default for HasScrollLinkedEffect { fn default() -> Self { HasScrollLinkedEffect::No } } /// A handler to integrate WebRender with the thread that contains the `Renderer`. pub trait RenderNotifier: Send { /// fn clone(&self) -> Box; /// Wake the thread containing the `Renderer` up (after updates have been put /// in the renderer's queue). fn wake_up( &self, composite_needed: bool, ); /// Notify the thread containing the `Renderer` that a new frame is ready. fn new_frame_ready(&self, _: DocumentId, scrolled: bool, composite_needed: bool, frame_publish_id: FramePublishId); /// A Gecko-specific notification mechanism to get some code executed on the /// `Renderer`'s thread, mostly replaced by `NotificationHandler`. You should /// probably use the latter instead. fn external_event(&self, _evt: ExternalEvent) { unimplemented!() } /// Notify the thread containing the `Renderer` that the render backend has been /// shut down. fn shut_down(&self) {} } /// A stage of the rendering pipeline. #[repr(u32)] #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum Checkpoint { /// SceneBuilt, /// FrameBuilt, /// FrameTexturesUpdated, /// FrameRendered, /// NotificationRequests get notified with this if they get dropped without having been /// notified. This provides the guarantee that if a request is created it will get notified. TransactionDropped, } /// A handler to notify when a transaction reaches certain stages of the rendering /// pipeline. pub trait NotificationHandler : Send + Sync { /// Entry point of the handler to implement. Invoked by WebRender. fn notify(&self, when: Checkpoint); } /// A request to notify a handler when the transaction reaches certain stages of the /// rendering pipeline. /// /// The request is guaranteed to be notified once and only once, even if the transaction /// is dropped before the requested check-point. pub struct NotificationRequest { handler: Option>, when: Checkpoint, } impl NotificationRequest { /// Constructor. pub fn new(when: Checkpoint, handler: Box) -> Self { NotificationRequest { handler: Some(handler), when, } } /// The specified stage at which point the handler should be notified. pub fn when(&self) -> Checkpoint { self.when } /// Called by WebRender at specified stages to notify the registered handler. pub fn notify(mut self) { if let Some(handler) = self.handler.take() { handler.notify(self.when); } } } /// An object that can perform hit-testing without doing synchronous queries to /// the RenderBackendThread. pub trait ApiHitTester: Send + Sync { /// Does a hit test on display items in the specified document, at the given /// point. The vector of hit results will contain all display items that match, /// ordered from front to back. fn hit_test(&self, point: WorldPoint) -> HitTestResult; } /// A hit tester requested to the render backend thread but not necessarily ready yet. /// /// The request should be resolved as late as possible to reduce the likelihood of blocking. pub struct HitTesterRequest { #[doc(hidden)] pub rx: Receiver>, } impl HitTesterRequest { /// Block until the hit tester is available and return it, consuming teh request. pub fn resolve(self) -> Arc { self.rx.recv().unwrap() } } /// Describe an item that matched a hit-test query. #[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] pub struct HitTestResultItem { /// The pipeline that the display item that was hit belongs to. pub pipeline: PipelineId, /// The tag of the hit display item. pub tag: ItemTag, /// The animation id from the stacking context. pub animation_id: u64, } /// Returned by `RenderApi::hit_test`. #[derive(Clone, Debug, Default, Deserialize, Serialize)] pub struct HitTestResult { /// List of items that are match the hit-test query. pub items: Vec, } impl Drop for NotificationRequest { fn drop(&mut self) { if let Some(ref mut handler) = self.handler { handler.notify(Checkpoint::TransactionDropped); } } } // This Clone impl yields an "empty" request because we don't want the requests // to be notified twice so the request is owned by only one of the API messages // (the original one) after the clone. // This works in practice because the notifications requests are used for // synchronization so we don't need to include them in the recording mechanism // in wrench that clones the messages. impl Clone for NotificationRequest { fn clone(&self) -> Self { NotificationRequest { when: self.when, handler: None, } } } /// A key to identify an animated property binding. #[repr(C)] #[derive(Clone, Copy, Debug, Default, Deserialize, MallocSizeOf, PartialEq, Serialize, Eq, Hash, PeekPoke)] pub struct PropertyBindingId { pub namespace: IdNamespace, pub uid: u32, } impl PropertyBindingId { /// Constructor. pub fn new(value: u64) -> Self { PropertyBindingId { namespace: IdNamespace((value >> 32) as u32), uid: value as u32, } } /// Decompose the ID back into the raw integer. pub fn to_u64(&self) -> u64 { ((self.namespace.0 as u64) << 32) | self.uid as u64 } } /// A unique key that is used for connecting animated property /// values to bindings in the display list. #[repr(C)] #[derive(Clone, Copy, Debug, Default, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)] pub struct PropertyBindingKey { /// pub id: PropertyBindingId, #[doc(hidden)] pub _phantom: PhantomData, } /// Construct a property value from a given key and value. impl PropertyBindingKey { /// pub fn with(self, value: T) -> PropertyValue { PropertyValue { key: self, value } } } impl Into for PropertyBindingKey { fn into(self) -> u64 { self.id.to_u64() } } impl PropertyBindingKey { /// Constructor. pub fn new(value: u64) -> Self { PropertyBindingKey { id: PropertyBindingId::new(value), _phantom: PhantomData, } } } /// A binding property can either be a specific value /// (the normal, non-animated case) or point to a binding location /// to fetch the current value from. /// Note that Binding has also a non-animated value, the value is /// used for the case where the animation is still in-delay phase /// (i.e. the animation doesn't produce any animation values). #[repr(C)] #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)] pub enum PropertyBinding { /// Non-animated value. Value(T), /// Animated binding. Binding(PropertyBindingKey, T), } impl Default for PropertyBinding { fn default() -> Self { PropertyBinding::Value(Default::default()) } } impl From for PropertyBinding { fn from(value: T) -> PropertyBinding { PropertyBinding::Value(value) } } impl From> for PropertyBindingKey { fn from(key: PropertyBindingKey) -> PropertyBindingKey { PropertyBindingKey { id: key.id.clone(), _phantom: PhantomData, } } } impl From> for PropertyBindingKey { fn from(key: PropertyBindingKey) -> PropertyBindingKey { PropertyBindingKey { id: key.id.clone(), _phantom: PhantomData, } } } impl From> for PropertyBinding { fn from(value: PropertyBinding) -> PropertyBinding { match value { PropertyBinding::Value(value) => PropertyBinding::Value(value.into()), PropertyBinding::Binding(k, v) => { PropertyBinding::Binding(k.into(), v.into()) } } } } impl From> for PropertyBinding { fn from(value: PropertyBinding) -> PropertyBinding { match value { PropertyBinding::Value(value) => PropertyBinding::Value(value.into()), PropertyBinding::Binding(k, v) => { PropertyBinding::Binding(k.into(), v.into()) } } } } /// The current value of an animated property. This is /// supplied by the calling code. #[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq)] pub struct PropertyValue { /// pub key: PropertyBindingKey, /// pub value: T, } /// When using `generate_frame()`, a list of `PropertyValue` structures /// can optionally be supplied to provide the current value of any /// animated properties. #[derive(Clone, Deserialize, Serialize, Debug, PartialEq, Default)] pub struct DynamicProperties { /// transform list pub transforms: Vec>, /// opacity pub floats: Vec>, /// background color pub colors: Vec>, } impl DynamicProperties { /// Extend the properties. pub fn extend(&mut self, other: Self) { self.transforms.extend(other.transforms); self.floats.extend(other.floats); self.colors.extend(other.colors); } } /// A C function that takes a pointer to a heap allocation and returns its size. /// /// This is borrowed from the malloc_size_of crate, upon which we want to avoid /// a dependency from WebRender. pub type VoidPtrToSizeFn = unsafe extern "C" fn(ptr: *const c_void) -> usize; /// A configuration option that can be changed at runtime. /// /// # Adding a new configuration option /// /// - Add a new enum variant here. /// - Add the entry in WR_BOOL_PARAMETER_LIST in gfxPlatform.cpp. /// - React to the parameter change anywhere in WebRender where a SetParam message is received. #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum Parameter { Bool(BoolParameter, bool), Int(IntParameter, i32), } /// Boolean configuration option. #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] pub enum BoolParameter { PboUploads = 0, Multithreading = 1, BatchedUploads = 2, DrawCallsForTextureCopy = 3, } /// Integer configuration option. #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] pub enum IntParameter { BatchedUploadThreshold = 0, } bitflags! { /// Flags to track why we are rendering. #[repr(C)] #[derive(Default, Deserialize, MallocSizeOf, Serialize)] pub struct RenderReasons: u32 { /// Equivalent of empty() for the C++ side. const NONE = 0; const SCENE = 1 << 0; const ANIMATED_PROPERTY = 1 << 1; const RESOURCE_UPDATE = 1 << 2; const ASYNC_IMAGE = 1 << 3; const CLEAR_RESOURCES = 1 << 4; const APZ = 1 << 5; /// Window resize const RESIZE = 1 << 6; /// Various widget-related reasons const WIDGET = 1 << 7; /// See Frame::must_be_drawn const TEXTURE_CACHE_FLUSH = 1 << 8; const SNAPSHOT = 1 << 9; const POST_RESOURCE_UPDATES_HOOK = 1 << 10; const CONFIG_CHANGE = 1 << 11; const CONTENT_SYNC = 1 << 12; const FLUSH = 1 << 13; const TESTING = 1 << 14; const OTHER = 1 << 15; /// Vsync isn't actually "why" we render but it can be useful /// to see which frames were driven by the vsync scheduler so /// we store a bit for it. const VSYNC = 1 << 16; const SKIPPED_COMPOSITE = 1 << 17; /// Gecko does some special things when it starts observing vsync /// so it can be useful to know what frames are associated with it. const START_OBSERVING_VSYNC = 1 << 18; const ASYNC_IMAGE_COMPOSITE_UNTIL = 1 << 19; } } impl RenderReasons { pub const NUM_BITS: u32 = 17; } bitflags! { /// Flags to enable/disable various builtin debugging tools. #[repr(C)] #[derive(Default, Deserialize, MallocSizeOf, Serialize)] pub struct DebugFlags: u32 { /// Display the frame profiler on screen. const PROFILER_DBG = 1 << 0; /// Display intermediate render targets on screen. const RENDER_TARGET_DBG = 1 << 1; /// Display all texture cache pages on screen. const TEXTURE_CACHE_DBG = 1 << 2; /// Display GPU timing results. const GPU_TIME_QUERIES = 1 << 3; /// Query the number of pixels that pass the depth test divided and show it /// in the profiler as a percentage of the number of pixels in the screen /// (window width times height). const GPU_SAMPLE_QUERIES = 1 << 4; /// Render each quad with their own draw call. /// /// Terrible for performance but can help with understanding the drawing /// order when inspecting renderdoc or apitrace recordings. const DISABLE_BATCHING = 1 << 5; /// Display the pipeline epochs. const EPOCHS = 1 << 6; /// Print driver messages to stdout. const ECHO_DRIVER_MESSAGES = 1 << 7; /// Show an overlay displaying overdraw amount. const SHOW_OVERDRAW = 1 << 8; /// Display the contents of GPU cache. const GPU_CACHE_DBG = 1 << 9; /// Clear evicted parts of the texture cache for debugging purposes. const TEXTURE_CACHE_DBG_CLEAR_EVICTED = 1 << 10; /// Show picture caching debug overlay const PICTURE_CACHING_DBG = 1 << 11; /// Highlight all primitives with colors based on kind. const PRIMITIVE_DBG = 1 << 12; /// Draw a zoom widget showing part of the framebuffer zoomed in. const ZOOM_DBG = 1 << 13; /// Scale the debug renderer down for a smaller screen. This will disrupt /// any mapping between debug display items and page content, so shouldn't /// be used with overlays like the picture caching or primitive display. const SMALL_SCREEN = 1 << 14; /// Disable various bits of the WebRender pipeline, to help narrow /// down where slowness might be coming from. const DISABLE_OPAQUE_PASS = 1 << 15; /// const DISABLE_ALPHA_PASS = 1 << 16; /// const DISABLE_CLIP_MASKS = 1 << 17; /// const DISABLE_TEXT_PRIMS = 1 << 18; /// const DISABLE_GRADIENT_PRIMS = 1 << 19; /// const OBSCURE_IMAGES = 1 << 20; /// Taint the transparent area of the glyphs with a random opacity to easily /// see when glyphs are re-rasterized. const GLYPH_FLASHING = 1 << 21; /// The profiler only displays information that is out of the ordinary. const SMART_PROFILER = 1 << 22; /// If set, dump picture cache invalidation debug to console. const INVALIDATION_DBG = 1 << 23; /// Collect and dump profiler statistics to captures. const PROFILER_CAPTURE = (1 as u32) << 25; // need "as u32" until we have cbindgen#556 /// Invalidate picture tiles every frames (useful when inspecting GPU work in external tools). const FORCE_PICTURE_INVALIDATION = (1 as u32) << 26; /// Display window visibility on screen. const WINDOW_VISIBILITY_DBG = 1 << 27; /// Render large blobs with at a smaller size (incorrectly). This is a temporary workaround for /// fuzzing. const RESTRICT_BLOB_SIZE = 1 << 28; } } /// Information specific to a primitive type that /// uniquely identifies a primitive template by key. #[derive(Debug, Clone, Eq, MallocSizeOf, PartialEq, Hash, Serialize, Deserialize)] pub enum PrimitiveKeyKind { /// Clear an existing rect, used for special effects on some platforms. Clear, /// Rectangle { /// color: PropertyBinding, }, } /// #[derive(Clone, Copy, Debug)] pub enum ScrollLocation { /// Scroll by a certain amount. Delta(LayoutVector2D), /// Scroll to very top of element. Start, /// Scroll to very bottom of element. End, } /// Crash annotations included in crash reports. #[repr(C)] #[derive(Clone, Copy)] pub enum CrashAnnotation { CompileShader = 0, DrawShader = 1, } /// Handler to expose support for annotating crash reports. pub trait CrashAnnotator : Send { fn set(&self, annotation: CrashAnnotation, value: &std::ffi::CStr); fn clear(&self, annotation: CrashAnnotation); fn box_clone(&self) -> Box; } impl Clone for Box { fn clone(&self) -> Box { self.box_clone() } } /// Guard to add a crash annotation at creation, and clear it at destruction. pub struct CrashAnnotatorGuard<'a> { annotator: &'a Option>, annotation: CrashAnnotation, } impl<'a> CrashAnnotatorGuard<'a> { pub fn new( annotator: &'a Option>, annotation: CrashAnnotation, value: &std::ffi::CStr, ) -> Self { if let Some(ref annotator) = annotator { annotator.set(annotation, value); } Self { annotator, annotation, } } } impl<'a> Drop for CrashAnnotatorGuard<'a> { fn drop(&mut self) { if let Some(ref annotator) = self.annotator { annotator.clear(self.annotation); } } }