/* This Source Code Form is subject to the terms of the Mozilla Publi *License,v.2.0.IfacopyoftheMPLwasnotdistributedwiththis
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use api::{AsyncBlobImageRasterizer, BlobImageResult, DebugFlags, Parameter}; use api::{DocumentId, PipelineId, ExternalEvent, BlobImageRequest}; use api::{NotificationRequest, Checkpoint, IdNamespace, QualitySettings}; use api::{GlyphDimensionRequest, GlyphIndexRequest}; use api::channel::{unbounded_channel, single_msg_channel, Receiver, Sender}; use api::units::*; usecrate::render_api::{ApiMsg, FrameMsg, SceneMsg, ResourceUpdate, TransactionMsg, MemoryReport}; usecrate::box_shadow::BoxShadow; usecrate::prim_store::rectangle::RectanglePrim; #[cfg(feature = "capture")] usecrate::capture::CaptureConfig; usecrate::frame_builder::FrameBuilderConfig; usecrate::scene_building::{SceneBuilder, SceneRecycler}; usecrate::clip::{ClipIntern, PolygonIntern}; usecrate::filterdata::FilterDataIntern; use glyph_rasterizer::SharedFontResources; usecrate::intern::{Internable, Interner, UpdateList}; usecrate::internal_types::{FastHashMap, FastHashSet}; use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; usecrate::prim_store::backdrop::{BackdropCapture, BackdropRender}; usecrate::prim_store::borders::{ImageBorder, NormalBorderPrim}; usecrate::prim_store::gradient::{LinearGradient, RadialGradient, ConicGradient}; usecrate::prim_store::image::{Image, YuvImage}; usecrate::prim_store::line_dec::LineDecoration; usecrate::prim_store::picture::Picture; usecrate::prim_store::text_run::TextRun; usecrate::profiler::{self, TransactionProfile}; usecrate::render_backend::SceneView; usecrate::renderer::{FullFrameStats, PipelineInfo}; usecrate::scene::{BuiltScene, Scene, SceneStats}; usecrate::spatial_tree::{SceneSpatialTree, SpatialTreeUpdates}; usecrate::telemetry::Telemetry; usecrate::SceneBuilderHooks; use std::iter; usecrate::util::drain_filter; use std::thread; use std::time::Duration;
// Message from scene builder to render backend. pubenum SceneBuilderResult {
Transactions(Vec<Box<BuiltTransaction>>, Option<Sender<SceneSwapResult>>),
ExternalEvent(ExternalEvent),
FlushComplete(Sender<()>),
DeleteDocument(DocumentId),
ClearNamespace(IdNamespace),
GetGlyphDimensions(GlyphDimensionRequest),
GetGlyphIndices(GlyphIndexRequest),
SetParameter(Parameter),
StopRenderBackend,
ShutDown(Option<Sender<()>>),
#[cfg(feature = "capture")] /// The same as `Transactions`, but also supplies a `CaptureConfig` that the /// render backend should use for sequence capture, until the next /// `CapturedTransactions` or `StopCaptureSequence` result.
CapturedTransactions(Vec<Box<BuiltTransaction>>, CaptureConfig, Option<Sender<SceneSwapResult>>),
#[cfg(feature = "capture")] /// The scene builder has stopped sequence capture, so the render backend /// should do the same.
StopCaptureSequence,
}
// Message from render backend to scene builder to indicate the // scene swap was completed. We need a separate channel for this // so that they don't get mixed with SceneBuilderRequest messages. pubenum SceneSwapResult {
Complete(Sender<()>),
Aborted,
}
macro_rules! declare_interners {
( $( $name:ident : $ty:ident, )+ ) => { /// This struct contains all items that can be shared between /// display lists. We want to intern and share the same clips, /// primitives and other things between display lists so that: /// - GPU cache handles remain valid, reducing GPU cache updates. /// - Comparison of primitives and pictures between two /// display lists is (a) fast (b) done during scene building. #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] #[derive(Default)] pubstruct Interners {
$( pub $name: Interner<$ty>,
)+
}
// A document in the scene builder contains the current scene, // as well as a persistent clip interner. This allows clips // to be de-duplicated, and persisted in the GPU cache between // display lists. struct Document {
scene: Scene,
interners: Interners,
stats: SceneStats,
view: SceneView,
spatial_tree: SceneSpatialTree,
}
/// Send a message to the render backend thread. /// /// We first put something in the result queue and then send a wake-up /// message to the api queue that the render backend is blocking on. pubfn send(&self, msg: SceneBuilderResult) { self.tx.send(ApiMsg::SceneBuilderResult(msg)).unwrap();
}
/// The scene builder thread's event loop. pubfn run(&mutself) { iflet Some(ref hooks) = self.hooks {
hooks.register();
}
/// Do the bulk of the work of the scene builder thread. fn process_transaction(&mutself, mut txn: TransactionMsg) -> Box<BuiltTransaction> {
profile_scope!("process_transaction");
// Note: We could further reduce the amount of unnecessary scene // building by keeping track of which pipelines are used by the // scene (bug 1490751).
rebuild_scene = true;
/// Send the results of process_transaction back to the render backend. fn forward_built_transactions(&mutself, txns: Vec<Box<BuiltTransaction>>) { let (pipeline_info, result_tx, result_rx) = matchself.hooks {
Some(ref hooks) => { if txns.iter().any(|txn| txn.built_scene.is_some()) { let info = PipelineInfo {
epochs: txns.iter()
.filter(|txn| txn.built_scene.is_some())
.map(|txn| {
txn.built_scene.as_ref().unwrap()
.pipeline_epochs.iter()
.zip(iter::repeat(txn.document_id))
.map(|((&pipeline_id, &epoch), document_id)| ((pipeline_id, document_id), epoch))
}).flatten().collect(),
removed_pipelines: txns.iter()
.map(|txn| txn.removed_pipelines.clone())
.flatten().collect(),
};
let (tx, rx) = single_msg_channel(); let txn = txns.iter().find(|txn| txn.built_scene.is_some()).unwrap();
Telemetry::record_scenebuild_time(Duration::from_millis(txn.profile.get(profiler::SCENE_BUILD_TIME).unwrap() as u64));
hooks.pre_scene_swap();
let timer_id = Telemetry::start_sceneswap_time(); let document_ids = txns.iter().map(|txn| txn.document_id).collect(); let have_resources_updates : Vec<DocumentId> = if pipeline_info.is_none() {
txns.iter()
.filter(|txn| !txn.resource_updates.is_empty() || txn.invalidate_rendered_frame)
.map(|txn| txn.document_id)
.collect()
} else {
Vec::new()
};
// Unless a transaction generates a frame immediately, the compositor should // schedule one whenever appropriate (probably at the next vsync) to present // the changes in the scene. let compositor_should_schedule_a_frame = !txns.iter().any(|txn| {
txn.render_frame
});
iflet Some(pipeline_info) = pipeline_info { // Block until the swap is done, then invoke the hook. let swap_result = result_rx.unwrap().recv();
Telemetry::stop_and_accumulate_sceneswap_time(timer_id); self.hooks.as_ref().unwrap().post_scene_swap(&document_ids,
pipeline_info,
compositor_should_schedule_a_frame); // Once the hook is done, allow the RB thread to resume iflet Ok(SceneSwapResult::Complete(resume_tx)) = swap_result {
resume_tx.send(()).ok();
}
} else {
Telemetry::cancel_sceneswap_time(timer_id); if !have_resources_updates.is_empty() { iflet Some(ref hooks) = self.hooks {
hooks.post_resource_update(&have_resources_updates);
}
} elseiflet Some(ref hooks) = self.hooks {
hooks.post_empty_scene_build();
}
}
}
/// Reports CPU heap memory used by the SceneBuilder. fn report_memory(&mutself) -> MemoryReport { let ops = self.size_of_ops.as_mut().unwrap(); letmut report = MemoryReport::default(); for doc inself.documents.values() {
doc.interners.report_memory(ops, &mut report);
doc.scene.report_memory(ops, &mut report);
}
report
}
}
/// A scene builder thread which executes expensive operations such as blob rasterization /// with a lower priority than the normal scene builder thread. /// /// After rasterizing blobs, the secene building request is forwarded to the normal scene /// builder where the FrameBuilder is generated. pubstruct LowPrioritySceneBuilderThread { pub rx: Receiver<SceneBuilderRequest>, pub tx: Sender<SceneBuilderRequest>, pub tile_pool: api::BlobTilePool,
}
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.