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 http://mozilla.org/MPL/2.0/. */
4
5 #![deny(missing_docs)]
6
7 use std::cell::Cell;
8 use std::fmt;
9 use std::marker::PhantomData;
10 use std::path::PathBuf;
11 use std::sync::Arc;
12 use std::u32;
13 use time::precise_time_ns;
14 //use crate::api::peek_poke::PeekPoke;
15 use crate::api::channel::{Sender, single_msg_channel, unbounded_channel};
16 use crate::api::{ColorF, BuiltDisplayList, IdNamespace, ExternalScrollId};
17 use crate::api::{SharedFontInstanceMap, FontKey, FontInstanceKey, NativeFontHandle};
18 use crate::api::{BlobImageData, BlobImageKey, ImageData, ImageDescriptor, ImageKey, Epoch, QualitySettings};
19 use crate::api::{BlobImageParams, BlobImageRequest, BlobImageResult, AsyncBlobImageRasterizer, BlobImageHandler};
20 use crate::api::{DocumentId, PipelineId, PropertyBindingId, PropertyBindingKey, ExternalEvent};
21 use crate::api::{HitTestResult, HitTesterRequest, ApiHitTester, PropertyValue, DynamicProperties};
22 use crate::api::{ScrollClamping, TileSize, NotificationRequest, DebugFlags, ScrollNodeState};
23 use crate::api::{GlyphDimensionRequest, GlyphIndexRequest, GlyphIndex, GlyphDimensions};
24 use crate::api::{FontInstanceOptions, FontInstancePlatformOptions, FontVariation};
25 use crate::api::DEFAULT_TILE_SIZE;
26 use crate::api::units::*;
27 use crate::api_resources::ApiResources;
28 use crate::scene_builder_thread::{SceneBuilderRequest, SceneBuilderResult};
29 use crate::intern::InterningMemoryReport;
30 use crate::profiler::{self, TransactionProfile};
31
32 #[repr(C)]
33 #[derive(Clone, Copy, Debug)]
34 #[cfg_attr(any(feature = "serde"), derive(Deserialize, Serialize))]
35 struct ResourceId(pub u32);
36
37 /// Update of a persistent resource in WebRender.
38 ///
39 /// ResourceUpdate changes keep theirs effect across display list changes.
40 #[derive(Clone)]
41 #[cfg_attr(any(feature = "serde"), derive(Deserialize, Serialize))]
42 pub enum ResourceUpdate {
43 /// See `AddImage`.
44 AddImage(AddImage),
45 /// See `UpdateImage`.
46 UpdateImage(UpdateImage),
47 /// Delete an existing image resource.
48 ///
49 /// It is invalid to continue referring to the image key in any display list
50 /// in the transaction that contains the `DeleteImage` message and subsequent
51 /// transactions.
52 DeleteImage(ImageKey),
53 /// See `AddBlobImage`.
54 AddBlobImage(AddBlobImage),
55 /// See `UpdateBlobImage`.
56 UpdateBlobImage(UpdateBlobImage),
57 /// Delete existing blob image resource.
58 DeleteBlobImage(BlobImageKey),
59 /// See `AddBlobImage::visible_area`.
60 SetBlobImageVisibleArea(BlobImageKey, DeviceIntRect),
61 /// See `AddFont`.
62 AddFont(AddFont),
63 /// Deletes an already existing font resource.
64 ///
65 /// It is invalid to continue referring to the font key in any display list
66 /// in the transaction that contains the `DeleteImage` message and subsequent
67 /// transactions.
68 DeleteFont(FontKey),
69 /// See `AddFontInstance`.
70 AddFontInstance(AddFontInstance),
71 /// Deletes an already existing font instance resource.
72 ///
73 /// It is invalid to continue referring to the font instance in any display
74 /// list in the transaction that contains the `DeleteImage` message and
75 /// subsequent transactions.
76 DeleteFontInstance(FontInstanceKey),
77 }
78
79 impl fmt::Debug for ResourceUpdate {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result80 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
81 match self {
82 ResourceUpdate::AddImage(ref i) => f.write_fmt(format_args!(
83 "ResourceUpdate::AddImage size({:?})",
84 &i.descriptor.size
85 )),
86 ResourceUpdate::UpdateImage(ref i) => f.write_fmt(format_args!(
87 "ResourceUpdate::UpdateImage size({:?})",
88 &i.descriptor.size
89 )),
90 ResourceUpdate::AddBlobImage(ref i) => f.write_fmt(format_args!(
91 "ResourceUFpdate::AddBlobImage size({:?})",
92 &i.descriptor.size
93 )),
94 ResourceUpdate::UpdateBlobImage(i) => f.write_fmt(format_args!(
95 "ResourceUpdate::UpdateBlobImage size({:?})",
96 &i.descriptor.size
97 )),
98 ResourceUpdate::DeleteImage(..) => f.write_str("ResourceUpdate::DeleteImage"),
99 ResourceUpdate::DeleteBlobImage(..) => f.write_str("ResourceUpdate::DeleteBlobImage"),
100 ResourceUpdate::SetBlobImageVisibleArea(..) => f.write_str("ResourceUpdate::SetBlobImageVisibleArea"),
101 ResourceUpdate::AddFont(..) => f.write_str("ResourceUpdate::AddFont"),
102 ResourceUpdate::DeleteFont(..) => f.write_str("ResourceUpdate::DeleteFont"),
103 ResourceUpdate::AddFontInstance(..) => f.write_str("ResourceUpdate::AddFontInstance"),
104 ResourceUpdate::DeleteFontInstance(..) => f.write_str("ResourceUpdate::DeleteFontInstance"),
105 }
106 }
107 }
108
109 /// Whether to generate a frame, and if so, an id that allows tracking this
110 /// transaction through the various frame stages.
111 #[derive(Clone, Debug)]
112 pub enum GenerateFrame {
113 /// Generate a frame if something changed.
114 Yes {
115 /// An id that allows tracking the frame transaction through the various
116 /// frame stages. Specified by the caller of generate_frame().
117 id: u64,
118 },
119 /// Don't generate a frame even if something has changed.
120 No,
121 }
122
123 impl GenerateFrame {
124 ///
as_bool(&self) -> bool125 pub fn as_bool(&self) -> bool {
126 match self {
127 GenerateFrame::Yes { .. } => true,
128 GenerateFrame::No => false,
129 }
130 }
131
132 /// Return the frame ID, if a frame is generated.
id(&self) -> Option<u64>133 pub fn id(&self) -> Option<u64> {
134 match self {
135 GenerateFrame::Yes { id } => Some(*id),
136 GenerateFrame::No => None,
137 }
138 }
139 }
140
141 /// A Transaction is a group of commands to apply atomically to a document.
142 ///
143 /// This mechanism ensures that:
144 /// - no other message can be interleaved between two commands that need to be applied together.
145 /// - no redundant work is performed if two commands in the same transaction cause the scene or
146 /// the frame to be rebuilt.
147 pub struct Transaction {
148 /// Operations affecting the scene (applied before scene building).
149 scene_ops: Vec<SceneMsg>,
150 /// Operations affecting the generation of frames (applied after scene building).
151 frame_ops: Vec<FrameMsg>,
152
153 notifications: Vec<NotificationRequest>,
154
155 /// Persistent resource updates to apply as part of this transaction.
156 pub resource_updates: Vec<ResourceUpdate>,
157
158 /// True if the transaction needs the scene building thread's attention.
159 /// False for things that can skip the scene builder, like APZ changes and
160 /// async images.
161 ///
162 /// Before this `Transaction` is converted to a `TransactionMsg`, we look
163 /// over its contents and set this if we're doing anything the scene builder
164 /// needs to know about, so this is only a default.
165 use_scene_builder_thread: bool,
166
167 /// Whether to generate a frame, and if so, an id that allows tracking this
168 /// transaction through the various frame stages. Specified by the caller of
169 /// generate_frame().
170 generate_frame: GenerateFrame,
171
172 /// Set to true in order to force re-rendering even if WebRender can't internally
173 /// detect that something has changed.
174 pub invalidate_rendered_frame: bool,
175
176 low_priority: bool,
177 }
178
179 impl Transaction {
180 /// Constructor.
new() -> Self181 pub fn new() -> Self {
182 Transaction {
183 scene_ops: Vec::new(),
184 frame_ops: Vec::new(),
185 resource_updates: Vec::new(),
186 notifications: Vec::new(),
187 use_scene_builder_thread: true,
188 generate_frame: GenerateFrame::No,
189 invalidate_rendered_frame: false,
190 low_priority: false,
191 }
192 }
193
194 /// Marks this transaction to allow it to skip going through the scene builder
195 /// thread.
196 ///
197 /// This is useful to avoid jank in transaction associated with animated
198 /// property updates, panning and zooming.
199 ///
200 /// Note that transactions that skip the scene builder thread can race ahead of
201 /// transactions that don't skip it.
skip_scene_builder(&mut self)202 pub fn skip_scene_builder(&mut self) {
203 self.use_scene_builder_thread = false;
204 }
205
206 /// Marks this transaction to enforce going through the scene builder thread.
use_scene_builder_thread(&mut self)207 pub fn use_scene_builder_thread(&mut self) {
208 self.use_scene_builder_thread = true;
209 }
210
211 /// Returns true if the transaction has no effect.
is_empty(&self) -> bool212 pub fn is_empty(&self) -> bool {
213 !self.generate_frame.as_bool() &&
214 !self.invalidate_rendered_frame &&
215 self.scene_ops.is_empty() &&
216 self.frame_ops.is_empty() &&
217 self.resource_updates.is_empty() &&
218 self.notifications.is_empty()
219 }
220
221 /// Update a pipeline's epoch.
update_epoch(&mut self, pipeline_id: PipelineId, epoch: Epoch)222 pub fn update_epoch(&mut self, pipeline_id: PipelineId, epoch: Epoch) {
223 // We track epochs before and after scene building.
224 // This one will be applied to the pending scene right away:
225 self.scene_ops.push(SceneMsg::UpdateEpoch(pipeline_id, epoch));
226 // And this one will be applied to the currently built scene at the end
227 // of the transaction (potentially long after the scene_ops one).
228 self.frame_ops.push(FrameMsg::UpdateEpoch(pipeline_id, epoch));
229 // We could avoid the duplication here by storing the epoch updates in a
230 // separate array and let the render backend schedule the updates at the
231 // proper times, but it wouldn't make things simpler.
232 }
233
234 /// Sets the root pipeline.
235 ///
236 /// # Examples
237 ///
238 /// ```
239 /// # use webrender::api::{PipelineId};
240 /// # use webrender::api::units::{DeviceIntSize};
241 /// # use webrender::render_api::{RenderApiSender, Transaction};
242 /// # fn example() {
243 /// let pipeline_id = PipelineId(0, 0);
244 /// let mut txn = Transaction::new();
245 /// txn.set_root_pipeline(pipeline_id);
246 /// # }
247 /// ```
set_root_pipeline(&mut self, pipeline_id: PipelineId)248 pub fn set_root_pipeline(&mut self, pipeline_id: PipelineId) {
249 self.scene_ops.push(SceneMsg::SetRootPipeline(pipeline_id));
250 }
251
252 /// Removes data associated with a pipeline from the internal data structures.
253 /// If the specified `pipeline_id` is for the root pipeline, the root pipeline
254 /// is reset back to `None`.
remove_pipeline(&mut self, pipeline_id: PipelineId)255 pub fn remove_pipeline(&mut self, pipeline_id: PipelineId) {
256 self.scene_ops.push(SceneMsg::RemovePipeline(pipeline_id));
257 }
258
259 /// Supplies a new frame to WebRender.
260 ///
261 /// Non-blocking, it notifies a worker process which processes the display list.
262 ///
263 /// Note: Scrolling doesn't require an own Frame.
264 ///
265 /// Arguments:
266 ///
267 /// * `epoch`: The unique Frame ID, monotonically increasing.
268 /// * `background`: The background color of this pipeline.
269 /// * `viewport_size`: The size of the viewport for this frame.
270 /// * `pipeline_id`: The ID of the pipeline that is supplying this display list.
271 /// * `display_list`: The root Display list used in this frame.
272 /// * `preserve_frame_state`: If a previous frame exists which matches this pipeline
273 /// id, this setting determines if frame state (such as scrolling
274 /// position) should be preserved for this new display list.
set_display_list( &mut self, epoch: Epoch, background: Option<ColorF>, viewport_size: LayoutSize, (pipeline_id, mut display_list): (PipelineId, BuiltDisplayList), preserve_frame_state: bool, )275 pub fn set_display_list(
276 &mut self,
277 epoch: Epoch,
278 background: Option<ColorF>,
279 viewport_size: LayoutSize,
280 (pipeline_id, mut display_list): (PipelineId, BuiltDisplayList),
281 preserve_frame_state: bool,
282 ) {
283 display_list.set_send_time_ns(precise_time_ns());
284 self.scene_ops.push(
285 SceneMsg::SetDisplayList {
286 display_list,
287 epoch,
288 pipeline_id,
289 background,
290 viewport_size,
291 preserve_frame_state,
292 }
293 );
294 }
295
296 /// Add a set of persistent resource updates to apply as part of this transaction.
update_resources(&mut self, mut resources: Vec<ResourceUpdate>)297 pub fn update_resources(&mut self, mut resources: Vec<ResourceUpdate>) {
298 self.resource_updates.append(&mut resources);
299 }
300
301 // Note: Gecko uses this to get notified when a transaction that contains
302 // potentially long blob rasterization or scene build is ready to be rendered.
303 // so that the tab-switching integration can react adequately when tab
304 // switching takes too long. For this use case when matters is that the
305 // notification doesn't fire before scene building and blob rasterization.
306
307 /// Trigger a notification at a certain stage of the rendering pipeline.
308 ///
309 /// Not that notification requests are skipped during serialization, so is is
310 /// best to use them for synchronization purposes and not for things that could
311 /// affect the WebRender's state.
notify(&mut self, event: NotificationRequest)312 pub fn notify(&mut self, event: NotificationRequest) {
313 self.notifications.push(event);
314 }
315
316 /// Setup the output region in the framebuffer for a given document.
set_document_view( &mut self, device_rect: DeviceIntRect, )317 pub fn set_document_view(
318 &mut self,
319 device_rect: DeviceIntRect,
320 ) {
321 window_size_sanity_check(device_rect.size());
322 self.scene_ops.push(
323 SceneMsg::SetDocumentView {
324 device_rect,
325 },
326 );
327 }
328
329 /// Scrolls the node identified by the given external scroll id to the
330 /// given scroll position, relative to the pre-scrolled offset for the
331 /// scrolling layer. That is, providing an origin of (0,0) will reset
332 /// any WR-side scrolling and just render the display items at the
333 /// pre-scrolled offsets as provided in the display list. Larger `origin`
334 /// values will cause the layer to be scrolled further towards the end of
335 /// the scroll range.
336 /// If the ScrollClamping argument is set to clamp, the scroll position
337 /// is clamped to what WebRender understands to be the bounds of the
338 /// scroll range, based on the sizes of the scrollable content and the
339 /// scroll port.
scroll_node_with_id( &mut self, origin: LayoutPoint, id: ExternalScrollId, clamp: ScrollClamping, )340 pub fn scroll_node_with_id(
341 &mut self,
342 origin: LayoutPoint,
343 id: ExternalScrollId,
344 clamp: ScrollClamping,
345 ) {
346 self.frame_ops.push(FrameMsg::ScrollNodeWithId(origin, id, clamp));
347 }
348
349 /// Set the current quality / performance settings for this document.
set_quality_settings(&mut self, settings: QualitySettings)350 pub fn set_quality_settings(&mut self, settings: QualitySettings) {
351 self.scene_ops.push(SceneMsg::SetQualitySettings { settings });
352 }
353
354 ///
set_is_transform_async_zooming(&mut self, is_zooming: bool, animation_id: PropertyBindingId)355 pub fn set_is_transform_async_zooming(&mut self, is_zooming: bool, animation_id: PropertyBindingId) {
356 self.frame_ops.push(FrameMsg::SetIsTransformAsyncZooming(is_zooming, animation_id));
357 }
358
359 /// Generate a new frame. When it's done and a RenderNotifier has been set
360 /// in `webrender::Renderer`, [new_frame_ready()][notifier] gets called.
361 /// Note that the notifier is called even if the frame generation was a
362 /// no-op; the arguments passed to `new_frame_ready` will provide information
363 /// as to when happened.
364 ///
365 /// [notifier]: trait.RenderNotifier.html#tymethod.new_frame_ready
generate_frame(&mut self, id: u64)366 pub fn generate_frame(&mut self, id: u64) {
367 self.generate_frame = GenerateFrame::Yes{ id };
368 }
369
370 /// Invalidate rendered frame. It ensure that frame will be rendered during
371 /// next frame generation. WebRender could skip frame rendering if there
372 /// is no update.
373 /// But there are cases that needs to force rendering.
374 /// - Content of image is updated by reusing same ExternalImageId.
375 /// - Platform requests it if pixels become stale (like wakeup from standby).
invalidate_rendered_frame(&mut self)376 pub fn invalidate_rendered_frame(&mut self) {
377 self.invalidate_rendered_frame = true;
378 }
379
380 /// Supply a list of animated property bindings that should be used to resolve
381 /// bindings in the current display list.
update_dynamic_properties(&mut self, properties: DynamicProperties)382 pub fn update_dynamic_properties(&mut self, properties: DynamicProperties) {
383 self.frame_ops.push(FrameMsg::UpdateDynamicProperties(properties));
384 }
385
386 /// Add to the list of animated property bindings that should be used to
387 /// resolve bindings in the current display list. This is a convenience method
388 /// so the caller doesn't have to figure out all the dynamic properties before
389 /// setting them on the transaction but can do them incrementally.
append_dynamic_transform_properties(&mut self, transforms: Vec<PropertyValue<LayoutTransform>>)390 pub fn append_dynamic_transform_properties(&mut self, transforms: Vec<PropertyValue<LayoutTransform>>) {
391 self.frame_ops.push(FrameMsg::AppendDynamicTransformProperties(transforms));
392 }
393
394 /// Consumes this object and just returns the frame ops.
get_frame_ops(self) -> Vec<FrameMsg>395 pub fn get_frame_ops(self) -> Vec<FrameMsg> {
396 self.frame_ops
397 }
398
finalize(self, document_id: DocumentId) -> Box<TransactionMsg>399 fn finalize(self, document_id: DocumentId) -> Box<TransactionMsg> {
400 Box::new(TransactionMsg {
401 document_id,
402 scene_ops: self.scene_ops,
403 frame_ops: self.frame_ops,
404 resource_updates: self.resource_updates,
405 notifications: self.notifications,
406 use_scene_builder_thread: self.use_scene_builder_thread,
407 generate_frame: self.generate_frame,
408 invalidate_rendered_frame: self.invalidate_rendered_frame,
409 low_priority: self.low_priority,
410 blob_rasterizer: None,
411 blob_requests: Vec::new(),
412 rasterized_blobs: Vec::new(),
413 profile: TransactionProfile::new(),
414 })
415 }
416
417 /// See `ResourceUpdate::AddImage`.
add_image( &mut self, key: ImageKey, descriptor: ImageDescriptor, data: ImageData, tiling: Option<TileSize>, )418 pub fn add_image(
419 &mut self,
420 key: ImageKey,
421 descriptor: ImageDescriptor,
422 data: ImageData,
423 tiling: Option<TileSize>,
424 ) {
425 self.resource_updates.push(ResourceUpdate::AddImage(AddImage {
426 key,
427 descriptor,
428 data,
429 tiling,
430 }));
431 }
432
433 /// See `ResourceUpdate::UpdateImage`.
update_image( &mut self, key: ImageKey, descriptor: ImageDescriptor, data: ImageData, dirty_rect: &ImageDirtyRect, )434 pub fn update_image(
435 &mut self,
436 key: ImageKey,
437 descriptor: ImageDescriptor,
438 data: ImageData,
439 dirty_rect: &ImageDirtyRect,
440 ) {
441 self.resource_updates.push(ResourceUpdate::UpdateImage(UpdateImage {
442 key,
443 descriptor,
444 data,
445 dirty_rect: *dirty_rect,
446 }));
447 }
448
449 /// See `ResourceUpdate::DeleteImage`.
delete_image(&mut self, key: ImageKey)450 pub fn delete_image(&mut self, key: ImageKey) {
451 self.resource_updates.push(ResourceUpdate::DeleteImage(key));
452 }
453
454 /// See `ResourceUpdate::AddBlobImage`.
add_blob_image( &mut self, key: BlobImageKey, descriptor: ImageDescriptor, data: Arc<BlobImageData>, visible_rect: DeviceIntRect, tile_size: Option<TileSize>, )455 pub fn add_blob_image(
456 &mut self,
457 key: BlobImageKey,
458 descriptor: ImageDescriptor,
459 data: Arc<BlobImageData>,
460 visible_rect: DeviceIntRect,
461 tile_size: Option<TileSize>,
462 ) {
463 self.resource_updates.push(
464 ResourceUpdate::AddBlobImage(AddBlobImage {
465 key,
466 descriptor,
467 data,
468 visible_rect,
469 tile_size: tile_size.unwrap_or(DEFAULT_TILE_SIZE),
470 })
471 );
472 }
473
474 /// See `ResourceUpdate::UpdateBlobImage`.
update_blob_image( &mut self, key: BlobImageKey, descriptor: ImageDescriptor, data: Arc<BlobImageData>, visible_rect: DeviceIntRect, dirty_rect: &BlobDirtyRect, )475 pub fn update_blob_image(
476 &mut self,
477 key: BlobImageKey,
478 descriptor: ImageDescriptor,
479 data: Arc<BlobImageData>,
480 visible_rect: DeviceIntRect,
481 dirty_rect: &BlobDirtyRect,
482 ) {
483 self.resource_updates.push(
484 ResourceUpdate::UpdateBlobImage(UpdateBlobImage {
485 key,
486 descriptor,
487 data,
488 visible_rect,
489 dirty_rect: *dirty_rect,
490 })
491 );
492 }
493
494 /// See `ResourceUpdate::DeleteBlobImage`.
delete_blob_image(&mut self, key: BlobImageKey)495 pub fn delete_blob_image(&mut self, key: BlobImageKey) {
496 self.resource_updates.push(ResourceUpdate::DeleteBlobImage(key));
497 }
498
499 /// See `ResourceUpdate::SetBlobImageVisibleArea`.
set_blob_image_visible_area(&mut self, key: BlobImageKey, area: DeviceIntRect)500 pub fn set_blob_image_visible_area(&mut self, key: BlobImageKey, area: DeviceIntRect) {
501 self.resource_updates.push(ResourceUpdate::SetBlobImageVisibleArea(key, area));
502 }
503
504 /// See `ResourceUpdate::AddFont`.
add_raw_font(&mut self, key: FontKey, bytes: Vec<u8>, index: u32)505 pub fn add_raw_font(&mut self, key: FontKey, bytes: Vec<u8>, index: u32) {
506 self.resource_updates
507 .push(ResourceUpdate::AddFont(AddFont::Raw(key, Arc::new(bytes), index)));
508 }
509
510 /// See `ResourceUpdate::AddFont`.
add_native_font(&mut self, key: FontKey, native_handle: NativeFontHandle)511 pub fn add_native_font(&mut self, key: FontKey, native_handle: NativeFontHandle) {
512 self.resource_updates
513 .push(ResourceUpdate::AddFont(AddFont::Native(key, native_handle)));
514 }
515
516 /// See `ResourceUpdate::DeleteFont`.
delete_font(&mut self, key: FontKey)517 pub fn delete_font(&mut self, key: FontKey) {
518 self.resource_updates.push(ResourceUpdate::DeleteFont(key));
519 }
520
521 /// See `ResourceUpdate::AddFontInstance`.
add_font_instance( &mut self, key: FontInstanceKey, font_key: FontKey, glyph_size: f32, options: Option<FontInstanceOptions>, platform_options: Option<FontInstancePlatformOptions>, variations: Vec<FontVariation>, )522 pub fn add_font_instance(
523 &mut self,
524 key: FontInstanceKey,
525 font_key: FontKey,
526 glyph_size: f32,
527 options: Option<FontInstanceOptions>,
528 platform_options: Option<FontInstancePlatformOptions>,
529 variations: Vec<FontVariation>,
530 ) {
531 self.resource_updates
532 .push(ResourceUpdate::AddFontInstance(AddFontInstance {
533 key,
534 font_key,
535 glyph_size,
536 options,
537 platform_options,
538 variations,
539 }));
540 }
541
542 /// See `ResourceUpdate::DeleteFontInstance`.
delete_font_instance(&mut self, key: FontInstanceKey)543 pub fn delete_font_instance(&mut self, key: FontInstanceKey) {
544 self.resource_updates.push(ResourceUpdate::DeleteFontInstance(key));
545 }
546
547 /// A hint that this transaction can be processed at a lower priority. High-
548 /// priority transactions can jump ahead of regular-priority transactions,
549 /// but both high- and regular-priority transactions are processed in order
550 /// relative to other transactions of the same priority.
set_low_priority(&mut self, low_priority: bool)551 pub fn set_low_priority(&mut self, low_priority: bool) {
552 self.low_priority = low_priority;
553 }
554
555 /// Returns whether this transaction is marked as low priority.
is_low_priority(&self) -> bool556 pub fn is_low_priority(&self) -> bool {
557 self.low_priority
558 }
559 }
560
561 ///
562 pub struct DocumentTransaction {
563 ///
564 pub document_id: DocumentId,
565 ///
566 pub transaction: Transaction,
567 }
568
569 /// Represents a transaction in the format sent through the channel.
570 pub struct TransactionMsg {
571 ///
572 pub document_id: DocumentId,
573 /// Changes that require re-building the scene.
574 pub scene_ops: Vec<SceneMsg>,
575 /// Changes to animated properties that do not require re-building the scene.
576 pub frame_ops: Vec<FrameMsg>,
577 /// Updates to resources that persist across display lists.
578 pub resource_updates: Vec<ResourceUpdate>,
579 /// Whether to trigger frame building and rendering if something has changed.
580 pub generate_frame: GenerateFrame,
581 /// Whether to force frame building and rendering even if no changes are internally
582 /// observed.
583 pub invalidate_rendered_frame: bool,
584 /// Whether to enforce that this transaction go through the scene builder.
585 pub use_scene_builder_thread: bool,
586 ///
587 pub low_priority: bool,
588
589 /// Handlers to notify at certain points of the pipeline.
590 pub notifications: Vec<NotificationRequest>,
591 ///
592 pub blob_rasterizer: Option<Box<dyn AsyncBlobImageRasterizer>>,
593 ///
594 pub blob_requests: Vec<BlobImageParams>,
595 ///
596 pub rasterized_blobs: Vec<(BlobImageRequest, BlobImageResult)>,
597 /// Collect various data along the rendering pipeline to display it in the embedded profiler.
598 pub profile: TransactionProfile,
599 }
600
601 impl fmt::Debug for TransactionMsg {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result602 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
603 writeln!(f, "threaded={}, genframe={:?}, invalidate={}, low_priority={}",
604 self.use_scene_builder_thread,
605 self.generate_frame,
606 self.invalidate_rendered_frame,
607 self.low_priority,
608 ).unwrap();
609 for scene_op in &self.scene_ops {
610 writeln!(f, "\t\t{:?}", scene_op).unwrap();
611 }
612
613 for frame_op in &self.frame_ops {
614 writeln!(f, "\t\t{:?}", frame_op).unwrap();
615 }
616
617 for resource_update in &self.resource_updates {
618 writeln!(f, "\t\t{:?}", resource_update).unwrap();
619 }
620 Ok(())
621 }
622 }
623
624 impl TransactionMsg {
625 /// Returns true if this transaction has no effect.
is_empty(&self) -> bool626 pub fn is_empty(&self) -> bool {
627 !self.generate_frame.as_bool() &&
628 !self.invalidate_rendered_frame &&
629 self.scene_ops.is_empty() &&
630 self.frame_ops.is_empty() &&
631 self.resource_updates.is_empty() &&
632 self.notifications.is_empty()
633 }
634 }
635
636 /// Creates an image resource with provided parameters.
637 ///
638 /// Must be matched with a `DeleteImage` at some point to prevent memory leaks.
639 #[derive(Clone)]
640 #[cfg_attr(any(feature = "serde"), derive(Deserialize, Serialize))]
641 pub struct AddImage {
642 /// A key to identify the image resource.
643 pub key: ImageKey,
644 /// Properties of the image.
645 pub descriptor: ImageDescriptor,
646 /// The pixels of the image.
647 pub data: ImageData,
648 /// An optional tiling scheme to apply when storing the image's data
649 /// on the GPU. Applies to both width and heights of the tiles.
650 ///
651 /// Note that WebRender may internally chose to tile large images
652 /// even if this member is set to `None`.
653 pub tiling: Option<TileSize>,
654 }
655
656 /// Updates an already existing image resource.
657 #[derive(Clone)]
658 #[cfg_attr(any(feature = "serde"), derive(Deserialize, Serialize))]
659 pub struct UpdateImage {
660 /// The key identfying the image resource to update.
661 pub key: ImageKey,
662 /// Properties of the image.
663 pub descriptor: ImageDescriptor,
664 /// The pixels of the image.
665 pub data: ImageData,
666 /// An optional dirty rect that lets WebRender optimize the amount of
667 /// data to transfer to the GPU.
668 ///
669 /// The data provided must still represent the entire image.
670 pub dirty_rect: ImageDirtyRect,
671 }
672
673 /// Creates a blob-image resource with provided parameters.
674 ///
675 /// Must be matched with a `DeleteImage` at some point to prevent memory leaks.
676 #[derive(Clone)]
677 #[cfg_attr(any(feature = "serde"), derive(Deserialize, Serialize))]
678 pub struct AddBlobImage {
679 /// A key to identify the blob-image resource.
680 pub key: BlobImageKey,
681 /// Properties of the image.
682 pub descriptor: ImageDescriptor,
683 /// The blob-image's serialized commands.
684 pub data: Arc<BlobImageData>,
685 /// The portion of the plane in the blob-image's internal coordinate
686 /// system that is stretched to fill the image display item.
687 ///
688 /// Unlike regular images, blob images are not limited in size. The
689 /// top-left corner of their internal coordinate system is also not
690 /// necessary at (0, 0).
691 /// This means that blob images can be updated to insert/remove content
692 /// in any direction to support panning and zooming.
693 pub visible_rect: DeviceIntRect,
694 /// The blob image's tile size to apply when rasterizing the blob-image
695 /// and when storing its rasterized data on the GPU.
696 /// Applies to both width and heights of the tiles.
697 ///
698 /// All blob images are tiled.
699 pub tile_size: TileSize,
700 }
701
702 /// Updates an already existing blob-image resource.
703 #[derive(Clone)]
704 #[cfg_attr(any(feature = "serde"), derive(Deserialize, Serialize))]
705 pub struct UpdateBlobImage {
706 /// The key identfying the blob-image resource to update.
707 pub key: BlobImageKey,
708 /// Properties of the image.
709 pub descriptor: ImageDescriptor,
710 /// The blob-image's serialized commands.
711 pub data: Arc<BlobImageData>,
712 /// See `AddBlobImage::visible_rect`.
713 pub visible_rect: DeviceIntRect,
714 /// An optional dirty rect that lets WebRender optimize the amount of
715 /// data to to rasterize and transfer to the GPU.
716 pub dirty_rect: BlobDirtyRect,
717 }
718
719 /// Creates a font resource.
720 ///
721 /// Must be matched with a corresponding `ResourceUpdate::DeleteFont` at some point to prevent
722 /// memory leaks.
723 #[derive(Clone)]
724 #[cfg_attr(any(feature = "serde"), derive(Deserialize, Serialize))]
725 pub enum AddFont {
726 ///
727 Raw(FontKey, Arc<Vec<u8>>, u32),
728 ///
729 Native(FontKey, NativeFontHandle),
730 }
731
732 /// Creates a font instance resource.
733 ///
734 /// Must be matched with a corresponding `DeleteFontInstance` at some point
735 /// to prevent memory leaks.
736 #[derive(Clone)]
737 #[cfg_attr(any(feature = "serde"), derive(Deserialize, Serialize))]
738 pub struct AddFontInstance {
739 /// A key to identify the font instance.
740 pub key: FontInstanceKey,
741 /// The font resource's key.
742 pub font_key: FontKey,
743 /// Glyph size in app units.
744 pub glyph_size: f32,
745 ///
746 pub options: Option<FontInstanceOptions>,
747 ///
748 pub platform_options: Option<FontInstancePlatformOptions>,
749 ///
750 pub variations: Vec<FontVariation>,
751 }
752
753 /// Frame messages affect building the scene.
754 pub enum SceneMsg {
755 ///
756 UpdateEpoch(PipelineId, Epoch),
757 ///
758 SetRootPipeline(PipelineId),
759 ///
760 RemovePipeline(PipelineId),
761 ///
762 SetDisplayList {
763 ///
764 display_list: BuiltDisplayList,
765 ///
766 epoch: Epoch,
767 ///
768 pipeline_id: PipelineId,
769 ///
770 background: Option<ColorF>,
771 ///
772 viewport_size: LayoutSize,
773 ///
774 preserve_frame_state: bool,
775 },
776 ///
777 SetDocumentView {
778 ///
779 device_rect: DeviceIntRect,
780 },
781 /// Set the current quality / performance configuration for this document.
782 SetQualitySettings {
783 /// The set of available quality / performance config values.
784 settings: QualitySettings,
785 },
786 }
787
788 /// Frame messages affect frame generation (applied after building the scene).
789 pub enum FrameMsg {
790 ///
791 UpdateEpoch(PipelineId, Epoch),
792 ///
793 HitTest(Option<PipelineId>, WorldPoint, Sender<HitTestResult>),
794 ///
795 RequestHitTester(Sender<Arc<dyn ApiHitTester>>),
796 ///
797 ScrollNodeWithId(LayoutPoint, ExternalScrollId, ScrollClamping),
798 ///
799 GetScrollNodeState(Sender<Vec<ScrollNodeState>>),
800 ///
801 UpdateDynamicProperties(DynamicProperties),
802 ///
803 AppendDynamicTransformProperties(Vec<PropertyValue<LayoutTransform>>),
804 ///
805 SetIsTransformAsyncZooming(bool, PropertyBindingId),
806 }
807
808 impl fmt::Debug for SceneMsg {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result809 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
810 f.write_str(match *self {
811 SceneMsg::UpdateEpoch(..) => "SceneMsg::UpdateEpoch",
812 SceneMsg::SetDisplayList { .. } => "SceneMsg::SetDisplayList",
813 SceneMsg::RemovePipeline(..) => "SceneMsg::RemovePipeline",
814 SceneMsg::SetDocumentView { .. } => "SceneMsg::SetDocumentView",
815 SceneMsg::SetRootPipeline(..) => "SceneMsg::SetRootPipeline",
816 SceneMsg::SetQualitySettings { .. } => "SceneMsg::SetQualitySettings",
817 })
818 }
819 }
820
821 impl fmt::Debug for FrameMsg {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result822 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
823 f.write_str(match *self {
824 FrameMsg::UpdateEpoch(..) => "FrameMsg::UpdateEpoch",
825 FrameMsg::HitTest(..) => "FrameMsg::HitTest",
826 FrameMsg::RequestHitTester(..) => "FrameMsg::RequestHitTester",
827 FrameMsg::ScrollNodeWithId(..) => "FrameMsg::ScrollNodeWithId",
828 FrameMsg::GetScrollNodeState(..) => "FrameMsg::GetScrollNodeState",
829 FrameMsg::UpdateDynamicProperties(..) => "FrameMsg::UpdateDynamicProperties",
830 FrameMsg::AppendDynamicTransformProperties(..) => "FrameMsg::AppendDynamicTransformProperties",
831 FrameMsg::SetIsTransformAsyncZooming(..) => "FrameMsg::SetIsTransformAsyncZooming",
832 })
833 }
834 }
835
836 bitflags!{
837 /// Bit flags for WR stages to store in a capture.
838 // Note: capturing `FRAME` without `SCENE` is not currently supported.
839 pub struct CaptureBits: u8 {
840 ///
841 const SCENE = 0x1;
842 ///
843 const FRAME = 0x2;
844 ///
845 const TILE_CACHE = 0x4;
846 ///
847 const EXTERNAL_RESOURCES = 0x8;
848 }
849 }
850
851 bitflags!{
852 /// Mask for clearing caches in debug commands.
853 pub struct ClearCache: u8 {
854 ///
855 const IMAGES = 0b1;
856 ///
857 const GLYPHS = 0b10;
858 ///
859 const GLYPH_DIMENSIONS = 0b100;
860 ///
861 const RENDER_TASKS = 0b1000;
862 ///
863 const TEXTURE_CACHE = 0b10000;
864 /// Clear render target pool
865 const RENDER_TARGETS = 0b100000;
866 }
867 }
868
869 /// Information about a loaded capture of each document
870 /// that is returned by `RenderBackend`.
871 #[derive(Clone, Debug)]
872 pub struct CapturedDocument {
873 ///
874 pub document_id: DocumentId,
875 ///
876 pub root_pipeline_id: Option<PipelineId>,
877 }
878
879 /// Update of the state of built-in debugging facilities.
880 #[derive(Clone)]
881 pub enum DebugCommand {
882 /// Sets the provided debug flags.
883 SetFlags(DebugFlags),
884 /// Configure if dual-source blending is used, if available.
885 EnableDualSourceBlending(bool),
886 /// Save a capture of all the documents state.
887 SaveCapture(PathBuf, CaptureBits),
888 /// Load a capture of all the documents state.
889 LoadCapture(PathBuf, Option<(u32, u32)>, Sender<CapturedDocument>),
890 /// Start capturing a sequence of scene/frame changes.
891 StartCaptureSequence(PathBuf, CaptureBits),
892 /// Stop capturing a sequence of scene/frame changes.
893 StopCaptureSequence,
894 /// Clear cached resources, forcing them to be re-uploaded from templates.
895 ClearCaches(ClearCache),
896 /// Enable/disable native compositor usage
897 EnableNativeCompositor(bool),
898 /// Enable/disable parallel job execution with rayon.
899 EnableMultithreading(bool),
900 /// Sets the maximum amount of existing batches to visit before creating a new one.
901 SetBatchingLookback(u32),
902 /// Invalidate GPU cache, forcing the update from the CPU mirror.
903 InvalidateGpuCache,
904 /// Causes the scene builder to pause for a given amount of milliseconds each time it
905 /// processes a transaction.
906 SimulateLongSceneBuild(u32),
907 /// Set an override tile size to use for picture caches
908 SetPictureTileSize(Option<DeviceIntSize>),
909 }
910
911 /// Message sent by the `RenderApi` to the render backend thread.
912 pub enum ApiMsg {
913 /// Adds a new document namespace.
914 CloneApi(Sender<IdNamespace>),
915 /// Adds a new document namespace.
916 CloneApiByClient(IdNamespace),
917 /// Adds a new document with given initial size.
918 AddDocument(DocumentId, DeviceIntSize),
919 /// A message targeted at a particular document.
920 UpdateDocuments(Vec<Box<TransactionMsg>>),
921 /// Flush from the caches anything that isn't necessary, to free some memory.
922 MemoryPressure,
923 /// Collects a memory report.
924 ReportMemory(Sender<Box<MemoryReport>>),
925 /// Change debugging options.
926 DebugCommand(DebugCommand),
927 /// Message from the scene builder thread.
928 SceneBuilderResult(SceneBuilderResult),
929 }
930
931 impl fmt::Debug for ApiMsg {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result932 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
933 f.write_str(match *self {
934 ApiMsg::CloneApi(..) => "ApiMsg::CloneApi",
935 ApiMsg::CloneApiByClient(..) => "ApiMsg::CloneApiByClient",
936 ApiMsg::AddDocument(..) => "ApiMsg::AddDocument",
937 ApiMsg::UpdateDocuments(..) => "ApiMsg::UpdateDocuments",
938 ApiMsg::MemoryPressure => "ApiMsg::MemoryPressure",
939 ApiMsg::ReportMemory(..) => "ApiMsg::ReportMemory",
940 ApiMsg::DebugCommand(..) => "ApiMsg::DebugCommand",
941 ApiMsg::SceneBuilderResult(..) => "ApiMsg::SceneBuilderResult",
942 })
943 }
944 }
945
946 /// Allows the API to communicate with WebRender.
947 ///
948 /// This object is created along with the `Renderer` and it's main use from a
949 /// user perspective is to create one or several `RenderApi` objects.
950 pub struct RenderApiSender {
951 api_sender: Sender<ApiMsg>,
952 scene_sender: Sender<SceneBuilderRequest>,
953 low_priority_scene_sender: Sender<SceneBuilderRequest>,
954 blob_image_handler: Option<Box<dyn BlobImageHandler>>,
955 shared_font_instances: SharedFontInstanceMap,
956 }
957
958 impl RenderApiSender {
959 /// Used internally by the `Renderer`.
new( api_sender: Sender<ApiMsg>, scene_sender: Sender<SceneBuilderRequest>, low_priority_scene_sender: Sender<SceneBuilderRequest>, blob_image_handler: Option<Box<dyn BlobImageHandler>>, shared_font_instances: SharedFontInstanceMap, ) -> Self960 pub fn new(
961 api_sender: Sender<ApiMsg>,
962 scene_sender: Sender<SceneBuilderRequest>,
963 low_priority_scene_sender: Sender<SceneBuilderRequest>,
964 blob_image_handler: Option<Box<dyn BlobImageHandler>>,
965 shared_font_instances: SharedFontInstanceMap,
966 ) -> Self {
967 RenderApiSender {
968 api_sender,
969 scene_sender,
970 low_priority_scene_sender,
971 blob_image_handler,
972 shared_font_instances,
973 }
974 }
975
976 /// Creates a new resource API object with a dedicated namespace.
create_api(&self) -> RenderApi977 pub fn create_api(&self) -> RenderApi {
978 let (sync_tx, sync_rx) = single_msg_channel();
979 let msg = ApiMsg::CloneApi(sync_tx);
980 self.api_sender.send(msg).expect("Failed to send CloneApi message");
981 let namespace_id = sync_rx.recv().expect("Failed to receive CloneApi reply");
982 RenderApi {
983 api_sender: self.api_sender.clone(),
984 scene_sender: self.scene_sender.clone(),
985 low_priority_scene_sender: self.low_priority_scene_sender.clone(),
986 namespace_id,
987 next_id: Cell::new(ResourceId(0)),
988 resources: ApiResources::new(
989 self.blob_image_handler.as_ref().map(|handler| handler.create_similar()),
990 self.shared_font_instances.clone(),
991 ),
992 }
993 }
994
995 /// Creates a new resource API object with a dedicated namespace.
996 /// Namespace id is allocated by client.
997 ///
998 /// The function could be used only when RendererOptions::namespace_alloc_by_client is true.
999 /// When the option is true, create_api() could not be used to prevent namespace id conflict.
create_api_by_client(&self, namespace_id: IdNamespace) -> RenderApi1000 pub fn create_api_by_client(&self, namespace_id: IdNamespace) -> RenderApi {
1001 let msg = ApiMsg::CloneApiByClient(namespace_id);
1002 self.api_sender.send(msg).expect("Failed to send CloneApiByClient message");
1003 RenderApi {
1004 api_sender: self.api_sender.clone(),
1005 scene_sender: self.scene_sender.clone(),
1006 low_priority_scene_sender: self.low_priority_scene_sender.clone(),
1007 namespace_id,
1008 next_id: Cell::new(ResourceId(0)),
1009 resources: ApiResources::new(
1010 self.blob_image_handler.as_ref().map(|handler| handler.create_similar()),
1011 self.shared_font_instances.clone(),
1012 ),
1013 }
1014 }
1015 }
1016
1017 /// The main entry point to interact with WebRender.
1018 pub struct RenderApi {
1019 api_sender: Sender<ApiMsg>,
1020 scene_sender: Sender<SceneBuilderRequest>,
1021 low_priority_scene_sender: Sender<SceneBuilderRequest>,
1022 namespace_id: IdNamespace,
1023 next_id: Cell<ResourceId>,
1024 resources: ApiResources,
1025 }
1026
1027 impl RenderApi {
1028 /// Returns the namespace ID used by this API object.
get_namespace_id(&self) -> IdNamespace1029 pub fn get_namespace_id(&self) -> IdNamespace {
1030 self.namespace_id
1031 }
1032
1033 ///
create_sender(&self) -> RenderApiSender1034 pub fn create_sender(&self) -> RenderApiSender {
1035 RenderApiSender::new(
1036 self.api_sender.clone(),
1037 self.scene_sender.clone(),
1038 self.low_priority_scene_sender.clone(),
1039 self.resources.blob_image_handler.as_ref().map(|handler| handler.create_similar()),
1040 self.resources.get_shared_font_instances(),
1041 )
1042 }
1043
1044 /// Add a document to the WebRender instance.
1045 ///
1046 /// Instances can manage one or several documents (using the same render backend thread).
1047 /// Each document will internally correspond to a single scene, and scenes are made of
1048 /// one or several pipelines.
add_document(&self, initial_size: DeviceIntSize) -> DocumentId1049 pub fn add_document(&self, initial_size: DeviceIntSize) -> DocumentId {
1050 let new_id = self.next_unique_id();
1051 self.add_document_with_id(initial_size, new_id)
1052 }
1053
1054 /// See `add_document`
add_document_with_id(&self, initial_size: DeviceIntSize, id: u32) -> DocumentId1055 pub fn add_document_with_id(&self,
1056 initial_size: DeviceIntSize,
1057 id: u32) -> DocumentId {
1058 window_size_sanity_check(initial_size);
1059
1060 let document_id = DocumentId::new(self.namespace_id, id);
1061
1062 // We send this message to both the render backend and the scene builder instead of having
1063 // the scene builder thread forward it to the render backend as we do elswhere. This is because
1064 // some transactions can skip the scene builder thread and we want to avoid them arriving before
1065 // the render backend knows about the existence of the corresponding document id.
1066 // It may not be necessary, though.
1067 self.api_sender.send(
1068 ApiMsg::AddDocument(document_id, initial_size)
1069 ).unwrap();
1070 self.scene_sender.send(
1071 SceneBuilderRequest::AddDocument(document_id, initial_size)
1072 ).unwrap();
1073
1074 document_id
1075 }
1076
1077 /// Delete a document.
delete_document(&self, document_id: DocumentId)1078 pub fn delete_document(&self, document_id: DocumentId) {
1079 self.low_priority_scene_sender.send(
1080 SceneBuilderRequest::DeleteDocument(document_id)
1081 ).unwrap();
1082 }
1083
1084 /// Generate a new font key
generate_font_key(&self) -> FontKey1085 pub fn generate_font_key(&self) -> FontKey {
1086 let new_id = self.next_unique_id();
1087 FontKey::new(self.namespace_id, new_id)
1088 }
1089
1090 /// Generate a new font instance key
generate_font_instance_key(&self) -> FontInstanceKey1091 pub fn generate_font_instance_key(&self) -> FontInstanceKey {
1092 let new_id = self.next_unique_id();
1093 FontInstanceKey::new(self.namespace_id, new_id)
1094 }
1095
1096 /// Gets the dimensions for the supplied glyph keys
1097 ///
1098 /// Note: Internally, the internal texture cache doesn't store
1099 /// 'empty' textures (height or width = 0)
1100 /// This means that glyph dimensions e.g. for spaces (' ') will mostly be None.
get_glyph_dimensions( &self, key: FontInstanceKey, glyph_indices: Vec<GlyphIndex>, ) -> Vec<Option<GlyphDimensions>>1101 pub fn get_glyph_dimensions(
1102 &self,
1103 key: FontInstanceKey,
1104 glyph_indices: Vec<GlyphIndex>,
1105 ) -> Vec<Option<GlyphDimensions>> {
1106 let (sender, rx) = single_msg_channel();
1107 let msg = SceneBuilderRequest::GetGlyphDimensions(GlyphDimensionRequest {
1108 key,
1109 glyph_indices,
1110 sender
1111 });
1112 self.low_priority_scene_sender.send(msg).unwrap();
1113 rx.recv().unwrap()
1114 }
1115
1116 /// Gets the glyph indices for the supplied string. These
1117 /// can be used to construct GlyphKeys.
get_glyph_indices(&self, key: FontKey, text: &str) -> Vec<Option<u32>>1118 pub fn get_glyph_indices(&self, key: FontKey, text: &str) -> Vec<Option<u32>> {
1119 let (sender, rx) = single_msg_channel();
1120 let msg = SceneBuilderRequest::GetGlyphIndices(GlyphIndexRequest {
1121 key,
1122 text: text.to_string(),
1123 sender,
1124 });
1125 self.low_priority_scene_sender.send(msg).unwrap();
1126 rx.recv().unwrap()
1127 }
1128
1129 /// Creates an `ImageKey`.
generate_image_key(&self) -> ImageKey1130 pub fn generate_image_key(&self) -> ImageKey {
1131 let new_id = self.next_unique_id();
1132 ImageKey::new(self.namespace_id, new_id)
1133 }
1134
1135 /// Creates a `BlobImageKey`.
generate_blob_image_key(&self) -> BlobImageKey1136 pub fn generate_blob_image_key(&self) -> BlobImageKey {
1137 BlobImageKey(self.generate_image_key())
1138 }
1139
1140 /// A Gecko-specific notification mechanism to get some code executed on the
1141 /// `Renderer`'s thread, mostly replaced by `NotificationHandler`. You should
1142 /// probably use the latter instead.
send_external_event(&self, evt: ExternalEvent)1143 pub fn send_external_event(&self, evt: ExternalEvent) {
1144 let msg = SceneBuilderRequest::ExternalEvent(evt);
1145 self.low_priority_scene_sender.send(msg).unwrap();
1146 }
1147
1148 /// Notify WebRender that now is a good time to flush caches and release
1149 /// as much memory as possible.
notify_memory_pressure(&self)1150 pub fn notify_memory_pressure(&self) {
1151 self.api_sender.send(ApiMsg::MemoryPressure).unwrap();
1152 }
1153
1154 /// Synchronously requests memory report.
report_memory(&self, _ops: malloc_size_of::MallocSizeOfOps) -> MemoryReport1155 pub fn report_memory(&self, _ops: malloc_size_of::MallocSizeOfOps) -> MemoryReport {
1156 let (tx, rx) = single_msg_channel();
1157 self.api_sender.send(ApiMsg::ReportMemory(tx)).unwrap();
1158 *rx.recv().unwrap()
1159 }
1160
1161 /// Update debugging flags.
set_debug_flags(&self, flags: DebugFlags)1162 pub fn set_debug_flags(&self, flags: DebugFlags) {
1163 let cmd = DebugCommand::SetFlags(flags);
1164 self.api_sender.send(ApiMsg::DebugCommand(cmd)).unwrap();
1165 }
1166
1167 /// Stop RenderBackend's task until shut down
stop_render_backend(&self)1168 pub fn stop_render_backend(&self) {
1169 self.low_priority_scene_sender.send(SceneBuilderRequest::StopRenderBackend).unwrap();
1170 }
1171
1172 /// Shut the WebRender instance down.
shut_down(&self, synchronously: bool)1173 pub fn shut_down(&self, synchronously: bool) {
1174 if synchronously {
1175 let (tx, rx) = single_msg_channel();
1176 self.low_priority_scene_sender.send(SceneBuilderRequest::ShutDown(Some(tx))).unwrap();
1177 rx.recv().unwrap();
1178 } else {
1179 self.low_priority_scene_sender.send(SceneBuilderRequest::ShutDown(None)).unwrap();
1180 }
1181 }
1182
1183 /// Create a new unique key that can be used for
1184 /// animated property bindings.
generate_property_binding_key<T: Copy>(&self) -> PropertyBindingKey<T>1185 pub fn generate_property_binding_key<T: Copy>(&self) -> PropertyBindingKey<T> {
1186 let new_id = self.next_unique_id();
1187 PropertyBindingKey {
1188 id: PropertyBindingId {
1189 namespace: self.namespace_id,
1190 uid: new_id,
1191 },
1192 _phantom: PhantomData,
1193 }
1194 }
1195
1196 #[inline]
next_unique_id(&self) -> u321197 fn next_unique_id(&self) -> u32 {
1198 let ResourceId(id) = self.next_id.get();
1199 self.next_id.set(ResourceId(id + 1));
1200 id
1201 }
1202
1203 // For use in Wrench only
1204 #[doc(hidden)]
send_message(&self, msg: ApiMsg)1205 pub fn send_message(&self, msg: ApiMsg) {
1206 self.api_sender.send(msg).unwrap();
1207 }
1208
1209 /// Creates a transaction message from a single frame message.
frame_message(&self, msg: FrameMsg, document_id: DocumentId) -> Box<TransactionMsg>1210 fn frame_message(&self, msg: FrameMsg, document_id: DocumentId) -> Box<TransactionMsg> {
1211 Box::new(TransactionMsg {
1212 document_id,
1213 scene_ops: Vec::new(),
1214 frame_ops: vec![msg],
1215 resource_updates: Vec::new(),
1216 notifications: Vec::new(),
1217 generate_frame: GenerateFrame::No,
1218 invalidate_rendered_frame: false,
1219 use_scene_builder_thread: false,
1220 low_priority: false,
1221 blob_rasterizer: None,
1222 blob_requests: Vec::new(),
1223 rasterized_blobs: Vec::new(),
1224 profile: TransactionProfile::new(),
1225 })
1226 }
1227
1228 /// A helper method to send document messages.
send_frame_msg(&self, document_id: DocumentId, msg: FrameMsg)1229 fn send_frame_msg(&self, document_id: DocumentId, msg: FrameMsg) {
1230 // This assertion fails on Servo use-cases, because it creates different
1231 // `RenderApi` instances for layout and compositor.
1232 //assert_eq!(document_id.0, self.namespace_id);
1233 self.api_sender
1234 .send(ApiMsg::UpdateDocuments(vec![self.frame_message(msg, document_id)]))
1235 .unwrap()
1236 }
1237
1238 /// Send a transaction to WebRender.
send_transaction(&mut self, document_id: DocumentId, transaction: Transaction)1239 pub fn send_transaction(&mut self, document_id: DocumentId, transaction: Transaction) {
1240 let mut transaction = transaction.finalize(document_id);
1241
1242 self.resources.update(&mut transaction);
1243
1244 if transaction.generate_frame.as_bool() {
1245 transaction.profile.start_time(profiler::API_SEND_TIME);
1246 transaction.profile.start_time(profiler::TOTAL_FRAME_CPU_TIME);
1247 }
1248
1249 if transaction.use_scene_builder_thread {
1250 let sender = if transaction.low_priority {
1251 &mut self.low_priority_scene_sender
1252 } else {
1253 &mut self.scene_sender
1254 };
1255
1256 sender.send(SceneBuilderRequest::Transactions(vec![transaction])).unwrap();
1257 } else {
1258 self.api_sender.send(ApiMsg::UpdateDocuments(vec![transaction])).unwrap();
1259 }
1260 }
1261
1262 /// Does a hit test on display items in the specified document, at the given
1263 /// point. If a pipeline_id is specified, it is used to further restrict the
1264 /// hit results so that only items inside that pipeline are matched. The vector
1265 /// of hit results will contain all display items that match, ordered from
1266 /// front to back.
hit_test(&self, document_id: DocumentId, pipeline_id: Option<PipelineId>, point: WorldPoint, ) -> HitTestResult1267 pub fn hit_test(&self,
1268 document_id: DocumentId,
1269 pipeline_id: Option<PipelineId>,
1270 point: WorldPoint,
1271 ) -> HitTestResult {
1272 let (tx, rx) = single_msg_channel();
1273
1274 self.send_frame_msg(
1275 document_id,
1276 FrameMsg::HitTest(pipeline_id, point, tx)
1277 );
1278 rx.recv().unwrap()
1279 }
1280
1281 /// Synchronously request an object that can perform fast hit testing queries.
request_hit_tester(&self, document_id: DocumentId) -> HitTesterRequest1282 pub fn request_hit_tester(&self, document_id: DocumentId) -> HitTesterRequest {
1283 let (tx, rx) = single_msg_channel();
1284 self.send_frame_msg(
1285 document_id,
1286 FrameMsg::RequestHitTester(tx)
1287 );
1288
1289 HitTesterRequest { rx }
1290 }
1291
1292 ///
get_scroll_node_state(&self, document_id: DocumentId) -> Vec<ScrollNodeState>1293 pub fn get_scroll_node_state(&self, document_id: DocumentId) -> Vec<ScrollNodeState> {
1294 let (tx, rx) = single_msg_channel();
1295 self.send_frame_msg(document_id, FrameMsg::GetScrollNodeState(tx));
1296 rx.recv().unwrap()
1297 }
1298
1299 // Some internal scheduling magic that leaked into the API.
1300 // Buckle up and see APZUpdater.cpp for more info about what this is about.
1301 #[doc(hidden)]
wake_scene_builder(&self)1302 pub fn wake_scene_builder(&self) {
1303 self.scene_sender.send(SceneBuilderRequest::WakeUp).unwrap();
1304 }
1305
1306 /// Block until a round-trip to the scene builder thread has completed. This
1307 /// ensures that any transactions (including ones deferred to the scene
1308 /// builder thread) have been processed.
flush_scene_builder(&self)1309 pub fn flush_scene_builder(&self) {
1310 let (tx, rx) = single_msg_channel();
1311 self.low_priority_scene_sender.send(SceneBuilderRequest::Flush(tx)).unwrap();
1312 rx.recv().unwrap(); // Block until done.
1313 }
1314
1315 /// Save a capture of the current frame state for debugging.
save_capture(&self, path: PathBuf, bits: CaptureBits)1316 pub fn save_capture(&self, path: PathBuf, bits: CaptureBits) {
1317 let msg = ApiMsg::DebugCommand(DebugCommand::SaveCapture(path, bits));
1318 self.send_message(msg);
1319 }
1320
1321 /// Load a capture of the current frame state for debugging.
load_capture(&self, path: PathBuf, ids: Option<(u32, u32)>) -> Vec<CapturedDocument>1322 pub fn load_capture(&self, path: PathBuf, ids: Option<(u32, u32)>) -> Vec<CapturedDocument> {
1323 // First flush the scene builder otherwise async scenes might clobber
1324 // the capture we are about to load.
1325 self.flush_scene_builder();
1326
1327 let (tx, rx) = unbounded_channel();
1328 let msg = ApiMsg::DebugCommand(DebugCommand::LoadCapture(path, ids, tx));
1329 self.send_message(msg);
1330
1331 let mut documents = Vec::new();
1332 while let Ok(captured_doc) = rx.recv() {
1333 documents.push(captured_doc);
1334 }
1335 documents
1336 }
1337
1338 /// Start capturing a sequence of frames.
start_capture_sequence(&self, path: PathBuf, bits: CaptureBits)1339 pub fn start_capture_sequence(&self, path: PathBuf, bits: CaptureBits) {
1340 let msg = ApiMsg::DebugCommand(DebugCommand::StartCaptureSequence(path, bits));
1341 self.send_message(msg);
1342 }
1343
1344 /// Stop capturing sequences of frames.
stop_capture_sequence(&self)1345 pub fn stop_capture_sequence(&self) {
1346 let msg = ApiMsg::DebugCommand(DebugCommand::StopCaptureSequence);
1347 self.send_message(msg);
1348 }
1349
1350 /// Update the state of builtin debugging facilities.
send_debug_cmd(&mut self, cmd: DebugCommand)1351 pub fn send_debug_cmd(&mut self, cmd: DebugCommand) {
1352 if let DebugCommand::EnableMultithreading(enable) = cmd {
1353 // TODO(nical) we should enable it for all RenderApis.
1354 self.resources.enable_multithreading(enable);
1355 }
1356 let msg = ApiMsg::DebugCommand(cmd);
1357 self.send_message(msg);
1358 }
1359 }
1360
1361 impl Drop for RenderApi {
drop(&mut self)1362 fn drop(&mut self) {
1363 let msg = SceneBuilderRequest::ClearNamespace(self.namespace_id);
1364 let _ = self.low_priority_scene_sender.send(msg);
1365 }
1366 }
1367
1368
window_size_sanity_check(size: DeviceIntSize)1369 fn window_size_sanity_check(size: DeviceIntSize) {
1370 // Anything bigger than this will crash later when attempting to create
1371 // a render task.
1372 use crate::render_task::MAX_RENDER_TASK_SIZE;
1373 if size.width > MAX_RENDER_TASK_SIZE || size.height > MAX_RENDER_TASK_SIZE {
1374 panic!("Attempting to create a {}x{} window/document", size.width, size.height);
1375 }
1376 }
1377
1378 /// Collection of heap sizes, in bytes.
1379 /// cbindgen:derive-eq=false
1380 /// cbindgen:derive-ostream=false
1381 #[repr(C)]
1382 #[allow(missing_docs)]
1383 #[derive(AddAssign, Clone, Debug, Default)]
1384 pub struct MemoryReport {
1385 //
1386 // CPU Memory.
1387 //
1388 pub clip_stores: usize,
1389 pub gpu_cache_metadata: usize,
1390 pub gpu_cache_cpu_mirror: usize,
1391 pub render_tasks: usize,
1392 pub hit_testers: usize,
1393 pub fonts: usize,
1394 pub weak_fonts: usize,
1395 pub images: usize,
1396 pub rasterized_blobs: usize,
1397 pub shader_cache: usize,
1398 pub interning: InterningMemoryReport,
1399 pub display_list: usize,
1400 pub upload_staging_memory: usize,
1401 pub swgl: usize,
1402
1403 //
1404 // GPU memory.
1405 //
1406 pub gpu_cache_textures: usize,
1407 pub vertex_data_textures: usize,
1408 pub render_target_textures: usize,
1409 pub picture_tile_textures: usize,
1410 pub atlas_textures: usize,
1411 pub standalone_textures: usize,
1412 pub texture_cache_structures: usize,
1413 pub depth_target_textures: usize,
1414 pub texture_upload_pbos: usize,
1415 pub swap_chain: usize,
1416 pub render_texture_hosts: usize,
1417 pub upload_staging_textures: usize,
1418 }
1419