/* This Source Code Form is subject to the terms of the Mozilla Public *License,v.2.0.IfacopyoftheMPLwasnotdistributedwiththis
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#![deny(missing_docs)]
use std::cell::Cell; use std::fmt; use std::marker::PhantomData; use std::path::PathBuf; use std::sync::Arc; use std::u32; use api::{MinimapData, SnapshotImageKey}; usecrate::api::channel::{Sender, single_msg_channel, unbounded_channel}; usecrate::api::{BuiltDisplayList, IdNamespace, ExternalScrollId, Parameter, BoolParameter}; usecrate::api::{FontKey, FontInstanceKey, NativeFontHandle}; usecrate::api::{BlobImageData, BlobImageKey, ImageData, ImageDescriptor, ImageKey, Epoch, QualitySettings}; usecrate::api::{BlobImageParams, BlobImageRequest, BlobImageResult, AsyncBlobImageRasterizer, BlobImageHandler}; usecrate::api::{DocumentId, PipelineId, PropertyBindingId, PropertyBindingKey, ExternalEvent}; usecrate::api::{HitTestResult, HitTesterRequest, ApiHitTester, PropertyValue, DynamicProperties}; usecrate::api::{SampledScrollOffset, TileSize, NotificationRequest, DebugFlags}; usecrate::api::{GlyphDimensionRequest, GlyphIndexRequest, GlyphIndex, GlyphDimensions}; usecrate::api::{FontInstanceOptions, FontInstancePlatformOptions, FontVariation, RenderReasons}; usecrate::api::DEFAULT_TILE_SIZE; usecrate::api::units::*; usecrate::api_resources::ApiResources; use glyph_rasterizer::SharedFontResources; usecrate::scene_builder_thread::{SceneBuilderRequest, SceneBuilderResult}; usecrate::intern::InterningMemoryReport; usecrate::profiler::{self, TransactionProfile}; #[cfg(feature = "debugger")] usecrate::debugger::{DebugQuery, DebuggerClient};
/// Update of a persistent resource in WebRender. /// /// ResourceUpdate changes keep theirs effect across display list changes. #[derive(Clone)] #[cfg_attr(any(feature = "serde"), derive(Deserialize, Serialize))] pubenum ResourceUpdate { /// See `AddImage`.
AddImage(AddImage), /// See `UpdateImage`.
UpdateImage(UpdateImage), /// Delete an existing image resource. /// /// It is invalid to continue referring to the image key in any display list /// in the transaction that contains the `DeleteImage` message and subsequent /// transactions.
DeleteImage(ImageKey), /// See `AddBlobImage`.
AddBlobImage(AddBlobImage), /// See `UpdateBlobImage`.
UpdateBlobImage(UpdateBlobImage), /// Delete existing blob image resource.
DeleteBlobImage(BlobImageKey), /// See `AddBlobImage::visible_area`.
SetBlobImageVisibleArea(BlobImageKey, DeviceIntRect), /// See `AddSnapshotImage`.
AddSnapshotImage(AddSnapshotImage), /// See `AddSnapshotImage`.
DeleteSnapshotImage(SnapshotImageKey), /// See `AddFont`.
AddFont(AddFont), /// Deletes an already existing font resource. /// /// It is invalid to continue referring to the font key in any display list /// in the transaction that contains the `DeleteImage` message and subsequent /// transactions.
DeleteFont(FontKey), /// See `AddFontInstance`.
AddFontInstance(AddFontInstance), /// Deletes an already existing font instance resource. /// /// It is invalid to continue referring to the font instance in any display /// list in the transaction that contains the `DeleteImage` message and /// subsequent transactions.
DeleteFontInstance(FontInstanceKey),
}
/// Whether to generate a frame, and if so, an id that allows tracking this /// transaction through the various frame stages. #[derive(Clone, Debug)] pubenum GenerateFrame { /// Generate a frame if something changed.
Yes { /// An id that allows tracking the frame transaction through the various /// frame stages. Specified by the caller of generate_frame().
id: u64, /// If false, (a subset of) the frame will be rendered, but nothing will /// be presented on the window.
present: bool, /// This flag is used by Firefox to differentiate between frames that /// participate or not in the frame throttling mechanism.
tracked: bool,
}, /// Don't generate a frame even if something has changed.
No,
}
/// If false, a frame may be (partially) generated but it will not be /// presented to the window. pubfn present(&self) -> bool { matchself {
GenerateFrame::Yes { present, .. } => *present,
GenerateFrame::No => false,
}
}
/// This flag is used by Gecko to indicate whether the transaction /// participates in frame throttling mechanisms. pubfn tracked(&self) -> bool { matchself {
GenerateFrame::Yes { tracked, .. } => *tracked,
GenerateFrame::No => false,
}
}
/// Return the frame ID, if a frame is generated. pubfn id(&self) -> Option<u64> { matchself {
GenerateFrame::Yes { id, .. } => Some(*id),
GenerateFrame::No => None,
}
}
}
/// A Transaction is a group of commands to apply atomically to a document. /// /// This mechanism ensures that: /// - no other message can be interleaved between two commands that need to be applied together. /// - no redundant work is performed if two commands in the same transaction cause the scene or /// the frame to be rebuilt. pubstruct Transaction { /// Operations affecting the scene (applied before scene building).
scene_ops: Vec<SceneMsg>, /// Operations affecting the generation of frames (applied after scene building).
frame_ops: Vec<FrameMsg>,
notifications: Vec<NotificationRequest>,
/// Persistent resource updates to apply as part of this transaction. pub resource_updates: Vec<ResourceUpdate>,
/// True if the transaction needs the scene building thread's attention. /// False for things that can skip the scene builder, like APZ changes and /// async images. /// /// Before this `Transaction` is converted to a `TransactionMsg`, we look /// over its contents and set this if we're doing anything the scene builder /// needs to know about, so this is only a default.
use_scene_builder_thread: bool,
/// Whether to generate a frame, and if so, an id that allows tracking this /// transaction through the various frame stages. Specified by the caller of /// generate_frame().
generate_frame: GenerateFrame,
/// Time when this transaction was constructed.
creation_time: u64,
/// Set to true in order to force re-rendering even if WebRender can't internally /// detect that something has changed. pub invalidate_rendered_frame: bool,
/// Marks this transaction to allow it to skip going through the scene builder /// thread. /// /// This is useful to avoid jank in transaction associated with animated /// property updates, panning and zooming. /// /// Note that transactions that skip the scene builder thread can race ahead of /// transactions that don't skip it. pubfn skip_scene_builder(&mutself) { self.use_scene_builder_thread = false;
}
/// Marks this transaction to enforce going through the scene builder thread. pubfn use_scene_builder_thread(&mutself) { self.use_scene_builder_thread = true;
}
/// Returns true if the transaction has no effect. pubfn is_empty(&self) -> bool {
!self.generate_frame.as_bool() &&
!self.invalidate_rendered_frame && self.scene_ops.is_empty() && self.frame_ops.is_empty() && self.resource_updates.is_empty() && self.notifications.is_empty()
}
/// Update a pipeline's epoch. pubfn update_epoch(&mutself, pipeline_id: PipelineId, epoch: Epoch) { // We track epochs before and after scene building. // This one will be applied to the pending scene right away: self.scene_ops.push(SceneMsg::UpdateEpoch(pipeline_id, epoch)); // And this one will be applied to the currently built scene at the end // of the transaction (potentially long after the scene_ops one). self.frame_ops.push(FrameMsg::UpdateEpoch(pipeline_id, epoch)); // We could avoid the duplication here by storing the epoch updates in a // separate array and let the render backend schedule the updates at the // proper times, but it wouldn't make things simpler.
}
/// Sets the root pipeline. /// /// # Examples /// /// ``` /// # use webrender::api::{PipelineId}; /// # use webrender::api::units::{DeviceIntSize}; /// # use webrender::render_api::{RenderApiSender, Transaction}; /// # fn example() { /// let pipeline_id = PipelineId(0, 0); /// let mut txn = Transaction::new(); /// txn.set_root_pipeline(pipeline_id); /// # } /// ``` pubfn set_root_pipeline(&mutself, pipeline_id: PipelineId) { self.scene_ops.push(SceneMsg::SetRootPipeline(pipeline_id));
}
/// Removes data associated with a pipeline from the internal data structures. /// If the specified `pipeline_id` is for the root pipeline, the root pipeline /// is reset back to `None`. pubfn remove_pipeline(&mutself, pipeline_id: PipelineId) { self.scene_ops.push(SceneMsg::RemovePipeline(pipeline_id));
}
/// Supplies a new frame to WebRender. /// /// Non-blocking, it notifies a worker process which processes the display list. /// /// Note: Scrolling doesn't require an own Frame. /// /// Arguments: /// /// * `epoch`: The unique Frame ID, monotonically increasing. /// * `pipeline_id`: The ID of the pipeline that is supplying this display list. /// * `display_list`: The root Display list used in this frame. pubfn set_display_list(
&mutself,
epoch: Epoch,
(pipeline_id, mut display_list): (PipelineId, BuiltDisplayList),
) {
display_list.set_send_time_ns(zeitstempel::now()); self.scene_ops.push(
SceneMsg::SetDisplayList {
display_list,
epoch,
pipeline_id,
}
);
}
/// Add a set of persistent resource updates to apply as part of this transaction. pubfn update_resources(&mutself, mut resources: Vec<ResourceUpdate>) { self.resource_updates.append(&mut resources);
}
// Note: Gecko uses this to get notified when a transaction that contains // potentially long blob rasterization or scene build is ready to be rendered. // so that the tab-switching integration can react adequately when tab // switching takes too long. For this use case when matters is that the // notification doesn't fire before scene building and blob rasterization.
/// Trigger a notification at a certain stage of the rendering pipeline. /// /// Not that notification requests are skipped during serialization, so is is /// best to use them for synchronization purposes and not for things that could /// affect the WebRender's state. pubfn notify(&mutself, event: NotificationRequest) { self.notifications.push(event);
}
/// Setup the output region in the framebuffer for a given document. pubfn set_document_view(
&mutself,
device_rect: DeviceIntRect,
) {
window_size_sanity_check(device_rect.size()); self.scene_ops.push(
SceneMsg::SetDocumentView {
device_rect,
},
);
}
/// Set multiple scroll offsets with generations to the node identified by /// the given external scroll id, the scroll offsets are relative to the /// pre-scrolled offset for the scrolling layer. pubfn set_scroll_offsets(
&mutself,
id: ExternalScrollId,
sampled_scroll_offsets: Vec<SampledScrollOffset>,
) { self.frame_ops.push(FrameMsg::SetScrollOffsets(id, sampled_scroll_offsets));
}
/// Set the current quality / performance settings for this document. pubfn set_quality_settings(&mutself, settings: QualitySettings) { self.scene_ops.push(SceneMsg::SetQualitySettings { settings });
}
/// Specify data for APZ minimap debug overlay to be composited pubfn set_minimap_data(&mutself, id: ExternalScrollId, minimap_data: MinimapData) { self.frame_ops.push(FrameMsg::SetMinimapData(id, minimap_data));
}
/// Generate a new frame. When it's done and a RenderNotifier has been set /// in `webrender::Renderer`, [new_frame_ready()][notifier] gets called. /// Note that the notifier is called even if the frame generation was a /// no-op; the arguments passed to `new_frame_ready` will provide information /// as to when happened. /// /// [notifier]: trait.RenderNotifier.html#tymethod.new_frame_ready pubfn generate_frame(&mutself, id: u64, present: bool, tracked: bool, reasons: RenderReasons) { self.generate_frame = GenerateFrame::Yes{ id, present, tracked }; self.render_reasons |= reasons;
}
/// Invalidate rendered frame. It ensure that frame will be rendered during /// next frame generation. WebRender could skip frame rendering if there /// is no update. /// But there are cases that needs to force rendering. /// - Content of image is updated by reusing same ExternalImageId. /// - Platform requests it if pixels become stale (like wakeup from standby). pubfn invalidate_rendered_frame(&mutself, reasons: RenderReasons) { self.invalidate_rendered_frame = true; self.render_reasons |= reasons
}
/// Reset the list of animated property bindings that should be used to resolve /// bindings in the current display list. pubfn reset_dynamic_properties(&mutself) { self.frame_ops.push(FrameMsg::ResetDynamicProperties);
}
/// Add to the list of animated property bindings that should be used to resolve /// bindings in the current display list. pubfn append_dynamic_properties(&mutself, properties: DynamicProperties) { self.frame_ops.push(FrameMsg::AppendDynamicProperties(properties));
}
/// Add to the list of animated property bindings that should be used to /// resolve bindings in the current display list. This is a convenience method /// so the caller doesn't have to figure out all the dynamic properties before /// setting them on the transaction but can do them incrementally. pubfn append_dynamic_transform_properties(&mutself, transforms: Vec<PropertyValue<LayoutTransform>>) { self.frame_ops.push(FrameMsg::AppendDynamicTransformProperties(transforms));
}
/// Consumes this object and just returns the frame ops. pubfn get_frame_ops(self) -> Vec<FrameMsg> { self.frame_ops
}
/// See `ResourceUpdate::DeleteFontInstance`. pubfn delete_font_instance(&mutself, key: FontInstanceKey) { self.resource_updates.push(ResourceUpdate::DeleteFontInstance(key));
}
/// A hint that this transaction can be processed at a lower priority. High- /// priority transactions can jump ahead of regular-priority transactions, /// but both high- and regular-priority transactions are processed in order /// relative to other transactions of the same priority. pubfn set_low_priority(&mutself, low_priority: bool) { self.low_priority = low_priority;
}
/// Returns whether this transaction is marked as low priority. pubfn is_low_priority(&self) -> bool { self.low_priority
}
/// Render a pipeline offscreen immediately without waiting for vsync /// and without affecting the state of the current scene. /// /// Snapshotted stacking contexts will be persisted in the texture cache. pubfn render_offscreen(&mutself, pipeline_id: PipelineId) { self.scene_ops.push(SceneMsg::RenderOffscreen(pipeline_id));
}
}
/// Represents a transaction in the format sent through the channel. pubstruct TransactionMsg { /// pub document_id: DocumentId, /// Changes that require re-building the scene. pub scene_ops: Vec<SceneMsg>, /// Changes to animated properties that do not require re-building the scene. pub frame_ops: Vec<FrameMsg>, /// Updates to resources that persist across display lists. pub resource_updates: Vec<ResourceUpdate>, /// Whether to trigger frame building and rendering if something has changed. pub generate_frame: GenerateFrame, /// Creation time of this transaction. pub creation_time: Option<u64>, /// Whether to force frame building and rendering even if no changes are internally /// observed. pub invalidate_rendered_frame: bool, /// Whether to enforce that this transaction go through the scene builder. pub use_scene_builder_thread: bool, /// pub low_priority: bool,
/// Handlers to notify at certain points of the pipeline. pub notifications: Vec<NotificationRequest>, /// pub blob_rasterizer: Option<Box<dyn AsyncBlobImageRasterizer>>, /// pub blob_requests: Vec<BlobImageParams>, /// pub rasterized_blobs: Vec<(BlobImageRequest, BlobImageResult)>, /// Collect various data along the rendering pipeline to display it in the embedded profiler. pub profile: TransactionProfile, /// Keep track of who asks rendering to happen. pub render_reasons: RenderReasons,
}
for frame_op in &self.frame_ops {
writeln!(f, "\t\t{:?}", frame_op).unwrap();
}
for resource_update in &self.resource_updates {
writeln!(f, "\t\t{:?}", resource_update).unwrap();
}
Ok(())
}
}
impl TransactionMsg { /// Returns true if this transaction has no effect. pubfn is_empty(&self) -> bool {
!self.generate_frame.as_bool() &&
!self.invalidate_rendered_frame && self.scene_ops.is_empty() && self.frame_ops.is_empty() && self.resource_updates.is_empty() && self.notifications.is_empty()
}
}
/// Creates an image resource with provided parameters. /// /// Must be matched with a `DeleteImage` at some point to prevent memory leaks. #[derive(Clone)] #[cfg_attr(any(feature = "serde"), derive(Deserialize, Serialize))] pubstruct AddImage { /// A key to identify the image resource. pub key: ImageKey, /// Properties of the image. pub descriptor: ImageDescriptor, /// The pixels of the image. pub data: ImageData, /// An optional tiling scheme to apply when storing the image's data /// on the GPU. Applies to both width and heights of the tiles. /// /// Note that WebRender may internally chose to tile large images /// even if this member is set to `None`. pub tiling: Option<TileSize>,
}
/// Updates an already existing image resource. #[derive(Clone)] #[cfg_attr(any(feature = "serde"), derive(Deserialize, Serialize))] pubstruct UpdateImage { /// The key identfying the image resource to update. pub key: ImageKey, /// Properties of the image. pub descriptor: ImageDescriptor, /// The pixels of the image. pub data: ImageData, /// An optional dirty rect that lets WebRender optimize the amount of /// data to transfer to the GPU. /// /// The data provided must still represent the entire image. pub dirty_rect: ImageDirtyRect,
}
/// Creates a blob-image resource with provided parameters. /// /// Must be matched with a `DeleteImage` at some point to prevent memory leaks. #[derive(Clone)] #[cfg_attr(any(feature = "serde"), derive(Deserialize, Serialize))] pubstruct AddBlobImage { /// A key to identify the blob-image resource. pub key: BlobImageKey, /// Properties of the image. pub descriptor: ImageDescriptor, /// The blob-image's serialized commands. pub data: Arc<BlobImageData>, /// The portion of the plane in the blob-image's internal coordinate /// system that is stretched to fill the image display item. /// /// Unlike regular images, blob images are not limited in size. The /// top-left corner of their internal coordinate system is also not /// necessary at (0, 0). /// This means that blob images can be updated to insert/remove content /// in any direction to support panning and zooming. pub visible_rect: DeviceIntRect, /// The blob image's tile size to apply when rasterizing the blob-image /// and when storing its rasterized data on the GPU. /// Applies to both width and heights of the tiles. /// /// All blob images are tiled. pub tile_size: TileSize,
}
/// Updates an already existing blob-image resource. #[derive(Clone)] #[cfg_attr(any(feature = "serde"), derive(Deserialize, Serialize))] pubstruct UpdateBlobImage { /// The key identfying the blob-image resource to update. pub key: BlobImageKey, /// Properties of the image. pub descriptor: ImageDescriptor, /// The blob-image's serialized commands. pub data: Arc<BlobImageData>, /// See `AddBlobImage::visible_rect`. pub visible_rect: DeviceIntRect, /// An optional dirty rect that lets WebRender optimize the amount of /// data to to rasterize and transfer to the GPU. pub dirty_rect: BlobDirtyRect,
}
/// Creates a snapshot image resource. /// /// Must be matched with a `DeleteSnapshotImage` at some point to prevent memory leaks. #[derive(Clone)] #[cfg_attr(any(feature = "serde"), derive(Deserialize, Serialize))] pubstruct AddSnapshotImage { /// The key identfying the snapshot resource. pub key: SnapshotImageKey,
}
/// Creates a font resource. /// /// Must be matched with a corresponding `ResourceUpdate::DeleteFont` at some point to prevent /// memory leaks. #[derive(Clone)] #[cfg_attr(any(feature = "serde"), derive(Deserialize, Serialize))] pubenum AddFont { ///
Raw(FontKey, Arc<Vec<u8>>, u32), ///
Native(FontKey, NativeFontHandle),
}
/// Creates a font instance resource. /// /// Must be matched with a corresponding `DeleteFontInstance` at some point /// to prevent memory leaks. #[derive(Clone)] #[cfg_attr(any(feature = "serde"), derive(Deserialize, Serialize))] pubstruct AddFontInstance { /// A key to identify the font instance. pub key: FontInstanceKey, /// The font resource's key. pub font_key: FontKey, /// Glyph size in app units. pub glyph_size: f32, /// pub options: Option<FontInstanceOptions>, /// pub platform_options: Option<FontInstancePlatformOptions>, /// pub variations: Vec<FontVariation>,
}
/// Frame messages affect building the scene. pubenum SceneMsg { ///
UpdateEpoch(PipelineId, Epoch), ///
SetRootPipeline(PipelineId), ///
RemovePipeline(PipelineId), ///
SetDisplayList { ///
display_list: BuiltDisplayList, ///
epoch: Epoch, ///
pipeline_id: PipelineId,
}, /// Build a scene without affecting any retained state. /// /// Useful to render an offscreen scene in the background without affecting /// what is currently displayed.
RenderOffscreen(PipelineId), ///
SetDocumentView { ///
device_rect: DeviceIntRect,
}, /// Set the current quality / performance configuration for this document.
SetQualitySettings { /// The set of available quality / performance config values.
settings: QualitySettings,
},
}
/// Information about a loaded capture of each document /// that is returned by `RenderBackend`. #[derive(Clone, Debug)] pubstruct CapturedDocument { /// pub document_id: DocumentId, /// pub root_pipeline_id: Option<PipelineId>,
}
/// Update of the state of built-in debugging facilities. pubenum DebugCommand { /// Sets the provided debug flags.
SetFlags(DebugFlags), /// Get current debug flags
GetDebugFlags(Sender<DebugFlags>), /// Enable/Disable render command logging.
SetRenderCommandLog(bool), /// Save a capture of all the documents state.
SaveCapture(PathBuf, CaptureBits), /// Load a capture of all the documents state.
LoadCapture(PathBuf, Option<(u32, u32)>, Sender<CapturedDocument>), /// Start capturing a sequence of scene/frame changes.
StartCaptureSequence(PathBuf, CaptureBits), /// Stop capturing a sequence of scene/frame changes.
StopCaptureSequence, /// Clear cached resources, forcing them to be re-uploaded from templates.
ClearCaches(ClearCache), /// Enable/disable native compositor usage
EnableNativeCompositor(bool), /// Sets the maximum amount of existing batches to visit before creating a new one.
SetBatchingLookback(u32), /// Causes the scene builder to pause for a given amount of milliseconds each time it /// processes a transaction.
SimulateLongSceneBuild(u32), /// Set an override tile size to use for picture caches
SetPictureTileSize(Option<DeviceIntSize>), /// Set an override for max off-screen surface size
SetMaximumSurfaceSize(Option<usize>), /// Generate a frame to force a redraw / recomposite
GenerateFrame, #[cfg(feature = "debugger")] /// Query internal information about WR
Query(DebugQuery), #[cfg(feature = "debugger")] /// Add a new profiler consumer
AddDebugClient(DebuggerClient), #[cfg(feature = "debugger")] /// Capture the next composited frame with RenderDoc, replying with the /// written .rdc path (or an error message).
CaptureRenderDoc(Sender<crate::api::debugger::RenderDocReply>),
}
/// Message sent by the `RenderApi` to the render backend thread. pubenum ApiMsg { /// Adds a new document namespace.
CloneApi(Sender<IdNamespace>), /// Adds a new document namespace.
CloneApiByClient(IdNamespace), /// Adds a new document with given initial size.
AddDocument(DocumentId, DeviceIntSize), /// A message targeted at a particular document.
UpdateDocuments(Vec<Box<TransactionMsg>>), /// Flush from the caches anything that isn't necessary, to free some memory.
MemoryPressure, /// Collects a memory report.
ReportMemory(Sender<Box<MemoryReport>>), /// Change debugging options.
DebugCommand(DebugCommand), /// Message from the scene builder thread.
SceneBuilderResult(SceneBuilderResult),
}
/// Allows the API to communicate with WebRender. /// /// This object is created along with the `Renderer` and it's main use from a /// user perspective is to create one or several `RenderApi` objects. pubstruct RenderApiSender {
api_sender: Sender<ApiMsg>,
scene_sender: Sender<SceneBuilderRequest>,
low_priority_scene_sender: Sender<SceneBuilderRequest>,
blob_image_handler: Option<Box<dyn BlobImageHandler>>,
fonts: SharedFontResources,
}
/// Creates a new resource API object with a dedicated namespace. pubfn create_api(&self) -> RenderApi { let (sync_tx, sync_rx) = single_msg_channel(); let msg = ApiMsg::CloneApi(sync_tx); self.api_sender.send(msg).expect("Failed to send CloneApi message"); let namespace_id = sync_rx.recv().expect("Failed to receive CloneApi reply");
RenderApi {
api_sender: self.api_sender.clone(),
scene_sender: self.scene_sender.clone(),
low_priority_scene_sender: self.low_priority_scene_sender.clone(),
namespace_id,
next_id: Cell::new(ResourceId(0)),
resources: ApiResources::new( self.blob_image_handler.as_ref().map(|handler| handler.create_similar()), self.fonts.clone(),
),
}
}
/// Creates a new resource API object with a dedicated namespace. /// Namespace id is allocated by client. /// /// The function could be used only when WebRenderOptions::namespace_alloc_by_client is true. /// When the option is true, create_api() could not be used to prevent namespace id conflict. pubfn create_api_by_client(&self, namespace_id: IdNamespace) -> RenderApi { let msg = ApiMsg::CloneApiByClient(namespace_id); self.api_sender.send(msg).expect("Failed to send CloneApiByClient message");
RenderApi {
api_sender: self.api_sender.clone(),
scene_sender: self.scene_sender.clone(),
low_priority_scene_sender: self.low_priority_scene_sender.clone(),
namespace_id,
next_id: Cell::new(ResourceId(0)),
resources: ApiResources::new( self.blob_image_handler.as_ref().map(|handler| handler.create_similar()), self.fonts.clone(),
),
}
}
}
/// The main entry point to interact with WebRender. pubstruct RenderApi {
api_sender: Sender<ApiMsg>,
scene_sender: Sender<SceneBuilderRequest>,
low_priority_scene_sender: Sender<SceneBuilderRequest>,
namespace_id: IdNamespace,
next_id: Cell<ResourceId>,
resources: ApiResources,
}
impl RenderApi { /// Returns the namespace ID used by this API object. pubfn get_namespace_id(&self) -> IdNamespace { self.namespace_id
}
/// Returns a clone of the API message sender for internal use #[allow(unused)] pub(crate) fn get_api_sender(&self) -> Sender<ApiMsg> { self.api_sender.clone()
}
/// Add a document to the WebRender instance. /// /// 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. pubfn add_document(&self, initial_size: DeviceIntSize) -> DocumentId { let new_id = self.next_unique_id(); self.add_document_with_id(initial_size, new_id)
}
let document_id = DocumentId::new(self.namespace_id, id);
// We send this message to both the render backend and the scene builder instead of having // the scene builder thread forward it to the render backend as we do elswhere. This is because // some transactions can skip the scene builder thread and we want to avoid them arriving before // the render backend knows about the existence of the corresponding document id. // It may not be necessary, though. self.api_sender.send(
ApiMsg::AddDocument(document_id, initial_size)
).unwrap(); self.scene_sender.send(
SceneBuilderRequest::AddDocument(document_id, initial_size)
).unwrap();
/// Generate a new font key pubfn generate_font_key(&self) -> FontKey { let new_id = self.next_unique_id();
FontKey::new(self.namespace_id, new_id)
}
/// Generate a new font instance key pubfn generate_font_instance_key(&self) -> FontInstanceKey { let new_id = self.next_unique_id();
FontInstanceKey::new(self.namespace_id, new_id)
}
/// Gets the dimensions for the supplied glyph keys /// /// Note: Internally, the internal texture cache doesn't store /// 'empty' textures (height or width = 0) /// This means that glyph dimensions e.g. for spaces (' ') will mostly be None. pubfn get_glyph_dimensions(
&self,
key: FontInstanceKey,
glyph_indices: Vec<GlyphIndex>,
) -> Vec<Option<GlyphDimensions>> { let (sender, rx) = single_msg_channel(); let msg = SceneBuilderRequest::GetGlyphDimensions(GlyphDimensionRequest {
key,
glyph_indices,
sender
}); self.low_priority_scene_sender.send(msg).unwrap();
rx.recv().unwrap()
}
/// Gets the glyph indices for the supplied string. These /// can be used to construct GlyphKeys. pubfn get_glyph_indices(&self, key: FontKey, text: &str) -> Vec<Option<u32>> { let (sender, rx) = single_msg_channel(); let msg = SceneBuilderRequest::GetGlyphIndices(GlyphIndexRequest {
key,
text: text.to_string(),
sender,
}); self.low_priority_scene_sender.send(msg).unwrap();
rx.recv().unwrap()
}
/// Creates an `ImageKey`. pubfn generate_image_key(&self) -> ImageKey { let new_id = self.next_unique_id();
ImageKey::new(self.namespace_id, new_id)
}
/// 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. pubfn send_external_event(&self, evt: ExternalEvent) { let msg = SceneBuilderRequest::ExternalEvent(evt); self.low_priority_scene_sender.send(msg).unwrap();
}
/// Notify WebRender that now is a good time to flush caches and release /// as much memory as possible. pubfn notify_memory_pressure(&self) { self.api_sender.send(ApiMsg::MemoryPressure).unwrap();
}
/// Stop RenderBackend's task until shut down pubfn stop_render_backend(&self) { self.low_priority_scene_sender.send(SceneBuilderRequest::StopRenderBackend).unwrap();
}
/// Shut the WebRender instance down. pubfn shut_down(&self, synchronously: bool) { if synchronously { let (tx, rx) = single_msg_channel(); self.low_priority_scene_sender.send(SceneBuilderRequest::ShutDown(Some(tx))).unwrap();
rx.recv().unwrap();
} else { self.low_priority_scene_sender.send(SceneBuilderRequest::ShutDown(None)).unwrap();
}
}
/// Create a new unique key that can be used for /// animated property bindings. pubfn generate_property_binding_key<T: Copy>(&self) -> PropertyBindingKey<T> { let new_id = self.next_unique_id();
PropertyBindingKey {
id: PropertyBindingId {
namespace: self.namespace_id,
uid: new_id,
},
_phantom: PhantomData,
}
}
#[inline] fn next_unique_id(&self) -> u32 { let ResourceId(id) = self.next_id.get(); self.next_id.set(ResourceId(id + 1));
id
}
// For use in Wrench only #[doc(hidden)] pubfn send_message(&self, msg: ApiMsg) { self.api_sender.send(msg).unwrap();
}
/// A helper method to send document messages. fn send_frame_msg(&self, document_id: DocumentId, msg: FrameMsg) { // This assertion fails on Servo use-cases, because it creates different // `RenderApi` instances for layout and compositor. //assert_eq!(document_id.0, self.namespace_id); self.api_sender
.send(ApiMsg::UpdateDocuments(vec![self.frame_message(msg, document_id)]))
.unwrap()
}
/// Send a transaction to WebRender. pubfn send_transaction(&mutself, document_id: DocumentId, transaction: Transaction) { letmut transaction = transaction.finalize(document_id);
self.resources.update(&mut transaction);
if transaction.generate_frame.as_bool() {
transaction.profile.start_time(profiler::API_SEND_TIME);
transaction.profile.start_time(profiler::TOTAL_FRAME_CPU_TIME);
}
if transaction.use_scene_builder_thread { let sender = if transaction.low_priority {
&mutself.low_priority_scene_sender
} else {
&mutself.scene_sender
};
sender.send(SceneBuilderRequest::Transactions(vec![transaction]))
.expect("send by scene sender failed");
} else { self.api_sender.send(ApiMsg::UpdateDocuments(vec![transaction]))
.expect("send by api sender failed");
}
}
/// Does a hit test on display items in the specified document, at the given /// point. If a pipeline_id is specified, it is used to further restrict the /// hit results so that only items inside that pipeline are matched. The vector /// of hit results will contain all display items that match, ordered from /// front to back. pubfn hit_test(&self,
document_id: DocumentId,
point: WorldPoint,
) -> HitTestResult { let (tx, rx) = single_msg_channel();
/// Synchronously request an object that can perform fast hit testing queries. pubfn request_hit_tester(&self, document_id: DocumentId) -> HitTesterRequest { let (tx, rx) = single_msg_channel(); self.send_frame_msg(
document_id,
FrameMsg::RequestHitTester(tx)
);
HitTesterRequest { rx }
}
// Some internal scheduling magic that leaked into the API. // Buckle up and see APZUpdater.cpp for more info about what this is about. #[doc(hidden)] pubfn wake_scene_builder(&self) { self.scene_sender.send(SceneBuilderRequest::WakeUp).unwrap();
}
/// Block until a round-trip to the scene builder thread has completed. This /// ensures that any transactions (including ones deferred to the scene /// builder thread) have been processed. pubfn flush_scene_builder(&self) { let (tx, rx) = single_msg_channel(); self.low_priority_scene_sender.send(SceneBuilderRequest::Flush(tx)).unwrap();
rx.recv().unwrap(); // Block until done.
}
/// Save a capture of the current frame state for debugging. pubfn save_capture(&self, path: PathBuf, bits: CaptureBits) { let msg = ApiMsg::DebugCommand(DebugCommand::SaveCapture(path, bits)); self.send_message(msg);
}
/// Load a capture of the current frame state for debugging. pubfn load_capture(&self, path: PathBuf, ids: Option<(u32, u32)>) -> Vec<CapturedDocument> { // First flush the scene builder otherwise async scenes might clobber // the capture we are about to load. self.flush_scene_builder();
let (tx, rx) = unbounded_channel(); let msg = ApiMsg::DebugCommand(DebugCommand::LoadCapture(path, ids, tx)); self.send_message(msg);
/// Start capturing a sequence of frames. pubfn start_capture_sequence(&self, path: PathBuf, bits: CaptureBits) { let msg = ApiMsg::DebugCommand(DebugCommand::StartCaptureSequence(path, bits)); self.send_message(msg);
}
/// Stop capturing sequences of frames. pubfn stop_capture_sequence(&self) { let msg = ApiMsg::DebugCommand(DebugCommand::StopCaptureSequence); self.send_message(msg);
}
/// Get the current debug flags pubfn get_debug_flags(&self) -> DebugFlags { let (tx, rx) = unbounded_channel(); let msg = ApiMsg::DebugCommand(DebugCommand::GetDebugFlags(tx)); self.send_message(msg);
rx.recv().unwrap()
}
/// Update the state of builtin debugging facilities. pubfn send_debug_cmd(&self, cmd: DebugCommand) { let msg = ApiMsg::DebugCommand(cmd); self.send_message(msg);
}
let _ = self.low_priority_scene_sender.send(
SceneBuilderRequest::SetParameter(parameter)
);
}
}
impl Drop for RenderApi { fn drop(&mutself) { let msg = SceneBuilderRequest::ClearNamespace(self.namespace_id); let _ = self.low_priority_scene_sender.send(msg);
}
}
fn window_size_sanity_check(size: DeviceIntSize) { // Anything bigger than this will crash later when attempting to create // a render task. usecrate::api::MAX_RENDER_TASK_SIZE; if size.width > MAX_RENDER_TASK_SIZE || size.height > MAX_RENDER_TASK_SIZE {
panic!("Attempting to create a {}x{} window/document", size.width, size.height);
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.