зеркало из https://github.com/mozilla/gecko-dev.git
Backed out 4 changesets (bug 1538710) for webrender-lint
Backed out changeset 6f3f506c7740 (bug 1538710) Backed out changeset 1a529f967061 (bug 1538710) Backed out changeset afa5cc2c6032 (bug 1538710) Backed out changeset ab2083ff97f4 (bug 1538710)
This commit is contained in:
Родитель
9e785cf3e7
Коммит
bf8c3286c2
|
@ -19,8 +19,7 @@ class CompositorController {
|
|||
NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING
|
||||
|
||||
virtual void ScheduleRenderOnCompositorThread(
|
||||
const nsTArray<wr::RenderRoot>& aRenderRoots =
|
||||
nsTArray<wr::RenderRoot>()) = 0;
|
||||
const Maybe<wr::RenderRoot>& aRenderRootid = Nothing()) = 0;
|
||||
virtual void ScheduleHideAllPluginWindows() = 0;
|
||||
virtual void ScheduleShowAllPluginWindows() = 0;
|
||||
|
||||
|
|
|
@ -650,11 +650,11 @@ void CompositorBridgeParent::ActorDestroy(ActorDestroyReason why) {
|
|||
}
|
||||
|
||||
void CompositorBridgeParent::ScheduleRenderOnCompositorThread(
|
||||
const nsTArray<wr::RenderRoot>& aRenderRoots) {
|
||||
const Maybe<wr::RenderRoot>& aRenderRoot) {
|
||||
MOZ_ASSERT(CompositorLoop());
|
||||
CompositorLoop()->PostTask(NewRunnableMethod<nsTArray<wr::RenderRoot>>(
|
||||
CompositorLoop()->PostTask(NewRunnableMethod<Maybe<wr::RenderRoot>>(
|
||||
"layers::CompositorBridgeParent::ScheduleComposition", this,
|
||||
&CompositorBridgeParent::ScheduleComposition, aRenderRoots));
|
||||
&CompositorBridgeParent::ScheduleComposition, aRenderRoot));
|
||||
}
|
||||
|
||||
void CompositorBridgeParent::InvalidateOnCompositorThread() {
|
||||
|
@ -864,14 +864,18 @@ void CompositorBridgeParent::NotifyShadowTreeTransaction(
|
|||
}
|
||||
|
||||
void CompositorBridgeParent::ScheduleComposition(
|
||||
const nsTArray<wr::RenderRoot>& aRenderRoots) {
|
||||
const Maybe<wr::RenderRoot>& aRenderRoot) {
|
||||
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
|
||||
if (mPaused) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mWrBridge) {
|
||||
mWrBridge->ScheduleGenerateFrame(aRenderRoots);
|
||||
if (aRenderRoot.isSome()) {
|
||||
mWrBridge->ScheduleGenerateFrame(aRenderRoot);
|
||||
} else {
|
||||
mWrBridge->ScheduleGenerateFrameAllRenderRoots();
|
||||
}
|
||||
} else {
|
||||
mCompositorScheduler->ScheduleComposition();
|
||||
}
|
||||
|
@ -2060,15 +2064,14 @@ void CompositorBridgeParent::DidComposite(const VsyncId& aId,
|
|||
}
|
||||
|
||||
void CompositorBridgeParent::NotifyDidSceneBuild(
|
||||
const nsTArray<wr::RenderRoot>& aRenderRoots,
|
||||
RefPtr<wr::WebRenderPipelineInfo> aInfo) {
|
||||
wr::RenderRoot aRenderRoot, RefPtr<wr::WebRenderPipelineInfo> aInfo) {
|
||||
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
|
||||
if (mPaused) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mWrBridge) {
|
||||
mWrBridge->NotifyDidSceneBuild(aRenderRoots, aInfo);
|
||||
mWrBridge->NotifyDidSceneBuild(aRenderRoot, aInfo);
|
||||
} else {
|
||||
mCompositorScheduler->ScheduleComposition();
|
||||
}
|
||||
|
|
|
@ -399,7 +399,7 @@ class CompositorBridgeParent final : public CompositorBridgeParentBase,
|
|||
TimeStamp& aCompositeStart,
|
||||
TimeStamp& aRenderStart, TimeStamp& aCompositeEnd,
|
||||
wr::RendererStats* aStats = nullptr);
|
||||
void NotifyDidSceneBuild(const nsTArray<wr::RenderRoot>& aRenderRoots,
|
||||
void NotifyDidSceneBuild(wr::RenderRoot aRenderRoot,
|
||||
RefPtr<wr::WebRenderPipelineInfo> aInfo);
|
||||
RefPtr<AsyncImagePipelineManager> GetAsyncImagePipelineManager() const;
|
||||
|
||||
|
@ -427,8 +427,7 @@ class CompositorBridgeParent final : public CompositorBridgeParentBase,
|
|||
|
||||
// Can be called from any thread
|
||||
void ScheduleRenderOnCompositorThread(
|
||||
const nsTArray<wr::RenderRoot>& aRenderRoots =
|
||||
nsTArray<wr::RenderRoot>()) override;
|
||||
const Maybe<wr::RenderRoot>& aRenderRoot = Nothing()) override;
|
||||
void SchedulePauseOnCompositorThread();
|
||||
void InvalidateOnCompositorThread();
|
||||
/**
|
||||
|
@ -438,9 +437,8 @@ class CompositorBridgeParent final : public CompositorBridgeParentBase,
|
|||
bool ScheduleResumeOnCompositorThread();
|
||||
bool ScheduleResumeOnCompositorThread(int x, int y, int width, int height);
|
||||
|
||||
void ScheduleComposition(const nsTArray<wr::RenderRoot>& aRenderRoots =
|
||||
nsTArray<wr::RenderRoot>());
|
||||
|
||||
void ScheduleComposition(
|
||||
const Maybe<wr::RenderRoot>& aRenderRoot = Nothing());
|
||||
void NotifyShadowTreeTransaction(LayersId aId, bool aIsFirstPaint,
|
||||
const FocusTarget& aFocusTarget,
|
||||
bool aScheduleComposite,
|
||||
|
|
|
@ -2002,7 +2002,6 @@ void WebRenderBridgeParent::MaybeGenerateFrame(VsyncId aId,
|
|||
#endif
|
||||
|
||||
MOZ_ASSERT(framesGenerated > 0);
|
||||
wr::RenderRootArray<wr::TransactionBuilder*> generateFrameTxns;
|
||||
for (auto& api : mApis) {
|
||||
if (!api) {
|
||||
continue;
|
||||
|
@ -2010,11 +2009,9 @@ void WebRenderBridgeParent::MaybeGenerateFrame(VsyncId aId,
|
|||
auto renderRoot = api->GetRenderRoot();
|
||||
if (generateFrame[renderRoot]) {
|
||||
fastTxns[renderRoot]->GenerateFrame();
|
||||
generateFrameTxns[renderRoot] = fastTxns[renderRoot].ptr();
|
||||
api->SendTransaction(*fastTxns[renderRoot]);
|
||||
}
|
||||
}
|
||||
wr::WebRenderAPI::SendTransactions(mApis, generateFrameTxns);
|
||||
|
||||
mMostRecentComposite = TimeStamp::Now();
|
||||
}
|
||||
|
||||
|
@ -2062,16 +2059,13 @@ void WebRenderBridgeParent::NotifySceneBuiltForEpoch(
|
|||
}
|
||||
|
||||
void WebRenderBridgeParent::NotifyDidSceneBuild(
|
||||
const nsTArray<wr::RenderRoot>& aRenderRoots,
|
||||
RefPtr<wr::WebRenderPipelineInfo> aInfo) {
|
||||
wr::RenderRoot aRenderRoot, RefPtr<wr::WebRenderPipelineInfo> aInfo) {
|
||||
MOZ_ASSERT(IsRootWebRenderBridgeParent());
|
||||
if (!mCompositorScheduler) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto renderRoot : aRenderRoots) {
|
||||
mAsyncImageManager->SetWillGenerateFrame(renderRoot);
|
||||
}
|
||||
mAsyncImageManager->SetWillGenerateFrame(aRenderRoot);
|
||||
|
||||
// If the scheduler has a composite more recent than our last composite (which
|
||||
// we missed), and we're within the threshold ms of the last vsync, then
|
||||
|
@ -2202,19 +2196,6 @@ void WebRenderBridgeParent::ScheduleGenerateFrame(
|
|||
}
|
||||
}
|
||||
|
||||
void WebRenderBridgeParent::ScheduleGenerateFrame(
|
||||
const nsTArray<wr::RenderRoot>& aRenderRoots) {
|
||||
if (mCompositorScheduler) {
|
||||
if (aRenderRoots.IsEmpty()) {
|
||||
mAsyncImageManager->SetWillGenerateFrameAllRenderRoots();
|
||||
}
|
||||
for (auto renderRoot : aRenderRoots) {
|
||||
mAsyncImageManager->SetWillGenerateFrame(renderRoot);
|
||||
}
|
||||
mCompositorScheduler->ScheduleComposition();
|
||||
}
|
||||
}
|
||||
|
||||
void WebRenderBridgeParent::FlushRendering(bool aWaitForPresent) {
|
||||
if (mDestroyed) {
|
||||
return;
|
||||
|
|
|
@ -231,7 +231,6 @@ class WebRenderBridgeParent final
|
|||
* want to trigger AsyncImagePipelines update checks.
|
||||
*/
|
||||
void ScheduleGenerateFrame(const Maybe<wr::RenderRoot>& aRenderRoot);
|
||||
void ScheduleGenerateFrame(const nsTArray<wr::RenderRoot>& aRenderRoots);
|
||||
void ScheduleGenerateFrameAllRenderRoots();
|
||||
|
||||
/**
|
||||
|
@ -242,7 +241,7 @@ class WebRenderBridgeParent final
|
|||
*/
|
||||
void ScheduleForcedGenerateFrame();
|
||||
|
||||
void NotifyDidSceneBuild(const nsTArray<wr::RenderRoot>& aRenderRoots,
|
||||
void NotifyDidSceneBuild(wr::RenderRoot aRenderRoot,
|
||||
RefPtr<wr::WebRenderPipelineInfo> aInfo);
|
||||
|
||||
wr::Epoch UpdateWebRender(
|
||||
|
|
|
@ -567,6 +567,8 @@ static void WebRenderDebugPrefChangeCallback(const char* aPrefName, void*) {
|
|||
GFX_WEBRENDER_DEBUG(".texture-cache.clear-evicted",
|
||||
wr::DebugFlags_TEXTURE_CACHE_DBG_CLEAR_EVICTED)
|
||||
GFX_WEBRENDER_DEBUG(".picture-caching", wr::DebugFlags_PICTURE_CACHING_DBG)
|
||||
GFX_WEBRENDER_DEBUG(".texture-cache.disable-shrink",
|
||||
wr::DebugFlags_TEXTURE_CACHE_DBG_DISABLE_SHRINK)
|
||||
GFX_WEBRENDER_DEBUG(".primitives", wr::DebugFlags_PRIMITIVE_DBG)
|
||||
// Bit 18 is for the zoom display, which requires the mouse position and thus
|
||||
// currently only works in wrench.
|
||||
|
|
|
@ -941,41 +941,30 @@ void wr_notifier_external_event(mozilla::wr::WrWindowId aWindowId,
|
|||
}
|
||||
|
||||
void wr_schedule_render(mozilla::wr::WrWindowId aWindowId,
|
||||
const mozilla::wr::WrDocumentId* aDocumentIds,
|
||||
size_t aDocumentIdsCount) {
|
||||
mozilla::wr::WrDocumentId aDocumentId) {
|
||||
RefPtr<mozilla::layers::CompositorBridgeParent> cbp = mozilla::layers::
|
||||
CompositorBridgeParent::GetCompositorBridgeParentFromWindowId(aWindowId);
|
||||
if (cbp) {
|
||||
InfallibleTArray<wr::RenderRoot> renderRoots;
|
||||
renderRoots.SetLength(aDocumentIdsCount);
|
||||
for (size_t i = 0; i < aDocumentIdsCount; ++i) {
|
||||
renderRoots[i] = wr::RenderRootFromId(aDocumentIds[i]);
|
||||
}
|
||||
cbp->ScheduleRenderOnCompositorThread(renderRoots);
|
||||
cbp->ScheduleRenderOnCompositorThread(
|
||||
Some(wr::RenderRootFromId(aDocumentId)));
|
||||
}
|
||||
}
|
||||
|
||||
static void NotifyDidSceneBuild(RefPtr<layers::CompositorBridgeParent> aBridge,
|
||||
const nsTArray<wr::RenderRoot>& aRenderRoots,
|
||||
wr::DocumentId aRenderRootId,
|
||||
RefPtr<wr::WebRenderPipelineInfo> aInfo) {
|
||||
aBridge->NotifyDidSceneBuild(aRenderRoots, aInfo);
|
||||
aBridge->NotifyDidSceneBuild(wr::RenderRootFromId(aRenderRootId), aInfo);
|
||||
}
|
||||
|
||||
void wr_finished_scene_build(mozilla::wr::WrWindowId aWindowId,
|
||||
const mozilla::wr::WrDocumentId* aDocumentIds,
|
||||
size_t aDocumentIdsCount,
|
||||
mozilla::wr::WrDocumentId aDocumentId,
|
||||
mozilla::wr::WrPipelineInfo aInfo) {
|
||||
RefPtr<mozilla::layers::CompositorBridgeParent> cbp = mozilla::layers::
|
||||
CompositorBridgeParent::GetCompositorBridgeParentFromWindowId(aWindowId);
|
||||
RefPtr<wr::WebRenderPipelineInfo> info = new wr::WebRenderPipelineInfo(aInfo);
|
||||
if (cbp) {
|
||||
InfallibleTArray<wr::RenderRoot> renderRoots;
|
||||
renderRoots.SetLength(aDocumentIdsCount);
|
||||
for (size_t i = 0; i < aDocumentIdsCount; ++i) {
|
||||
renderRoots[i] = wr::RenderRootFromId(aDocumentIds[i]);
|
||||
}
|
||||
layers::CompositorThreadHolder::Loop()->PostTask(NewRunnableFunction(
|
||||
"NotifyDidSceneBuild", &NotifyDidSceneBuild, cbp, renderRoots, info));
|
||||
"NotifyDidSceneBuild", &NotifyDidSceneBuild, cbp, aDocumentId, info));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -366,39 +366,6 @@ void WebRenderAPI::SendTransaction(TransactionBuilder& aTxn) {
|
|||
wr_api_send_transaction(mDocHandle, aTxn.Raw(), aTxn.UseSceneBuilderThread());
|
||||
}
|
||||
|
||||
/* static */
|
||||
void WebRenderAPI::SendTransactions(
|
||||
const RenderRootArray<RefPtr<WebRenderAPI>>& aApis,
|
||||
RenderRootArray<TransactionBuilder*>& aTxns) {
|
||||
if (!aApis[RenderRoot::Default]) {
|
||||
return;
|
||||
}
|
||||
|
||||
aApis[RenderRoot::Default]->UpdateDebugFlags(gfx::gfxVars::WebRenderDebugFlags());
|
||||
AutoTArray<DocumentHandle*, kRenderRootCount> documentHandles;
|
||||
AutoTArray<Transaction*, kRenderRootCount> txns;
|
||||
Maybe<bool> useSceneBuilderThread;
|
||||
for (auto& api : aApis) {
|
||||
if (!api) {
|
||||
continue;
|
||||
}
|
||||
auto& txn = aTxns[api->GetRenderRoot()];
|
||||
if (txn) {
|
||||
documentHandles.AppendElement(api->mDocHandle);
|
||||
txns.AppendElement(txn->Raw());
|
||||
if (useSceneBuilderThread.isSome()) {
|
||||
MOZ_ASSERT(txn->UseSceneBuilderThread() == *useSceneBuilderThread);
|
||||
} else {
|
||||
useSceneBuilderThread.emplace(txn->UseSceneBuilderThread());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!txns.IsEmpty()) {
|
||||
wr_api_send_transactions(documentHandles.Elements(), txns.Elements(),
|
||||
txns.Length(), *useSceneBuilderThread);
|
||||
}
|
||||
}
|
||||
|
||||
bool WebRenderAPI::HitTest(const wr::WorldPoint& aPoint,
|
||||
wr::WrPipelineId& aOutPipelineId,
|
||||
layers::ScrollableLayerGuid::ViewID& aOutScrollId,
|
||||
|
|
|
@ -209,9 +209,6 @@ class WebRenderAPI final {
|
|||
RefPtr<widget::CompositorWidget>&& aWidget,
|
||||
const wr::WrWindowId& aWindowId, LayoutDeviceIntSize aSize);
|
||||
|
||||
static void SendTransactions(const RenderRootArray<RefPtr<WebRenderAPI>>& aApis,
|
||||
RenderRootArray<TransactionBuilder*>& aTxns);
|
||||
|
||||
already_AddRefed<WebRenderAPI> CreateDocument(LayoutDeviceIntSize aSize,
|
||||
int8_t aLayerIndex,
|
||||
wr::RenderRoot aRenderRoot);
|
||||
|
|
|
@ -581,13 +581,8 @@ extern "C" {
|
|||
fn wr_notifier_nop_frame_done(window_id: WrWindowId);
|
||||
fn wr_notifier_external_event(window_id: WrWindowId,
|
||||
raw_event: usize);
|
||||
fn wr_schedule_render(window_id: WrWindowId,
|
||||
document_id_array: *const WrDocumentId,
|
||||
document_id_count: usize);
|
||||
fn wr_finished_scene_build(window_id: WrWindowId,
|
||||
document_id_array: *const WrDocumentId,
|
||||
document_id_count: usize,
|
||||
pipeline_info: WrPipelineInfo);
|
||||
fn wr_schedule_render(window_id: WrWindowId, document_id: WrDocumentId);
|
||||
fn wr_finished_scene_build(window_id: WrWindowId, document_id: WrDocumentId, pipeline_info: WrPipelineInfo);
|
||||
|
||||
fn wr_transaction_notification_notified(handler: usize, when: Checkpoint);
|
||||
}
|
||||
|
@ -921,7 +916,7 @@ impl SceneBuilderHooks for APZCallbacks {
|
|||
}
|
||||
}
|
||||
|
||||
fn post_scene_swap(&self, document_ids: &Vec<DocumentId>, info: PipelineInfo, sceneswap_time: u64) {
|
||||
fn post_scene_swap(&self, document_id: DocumentId, info: PipelineInfo, sceneswap_time: u64) {
|
||||
unsafe {
|
||||
let info = WrPipelineInfo::new(&info);
|
||||
record_telemetry_time(TelemetryProbe::SceneSwapTime, sceneswap_time);
|
||||
|
@ -932,12 +927,12 @@ impl SceneBuilderHooks for APZCallbacks {
|
|||
// After a scene swap we should schedule a render for the next vsync,
|
||||
// otherwise there's no guarantee that the new scene will get rendered
|
||||
// anytime soon
|
||||
unsafe { wr_finished_scene_build(self.window_id, document_ids.as_ptr(), document_ids.len(), info) }
|
||||
unsafe { wr_finished_scene_build(self.window_id, document_id, info) }
|
||||
unsafe { gecko_profiler_end_marker(b"SceneBuilding\0".as_ptr() as *const c_char); }
|
||||
}
|
||||
|
||||
fn post_resource_update(&self, document_ids: &Vec<DocumentId>) {
|
||||
unsafe { wr_schedule_render(self.window_id, document_ids.as_ptr(), document_ids.len()) }
|
||||
fn post_resource_update(&self, document_id: DocumentId) {
|
||||
unsafe { wr_schedule_render(self.window_id, document_id) }
|
||||
unsafe { gecko_profiler_end_marker(b"SceneBuilding\0".as_ptr() as *const c_char); }
|
||||
}
|
||||
|
||||
|
@ -1725,30 +1720,6 @@ pub extern "C" fn wr_api_send_transaction(
|
|||
dh.api.send_transaction(dh.document_id, txn);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wr_api_send_transactions(
|
||||
document_handles: *const *const DocumentHandle,
|
||||
transactions: *const *mut Transaction,
|
||||
transaction_count: usize,
|
||||
is_async: bool
|
||||
) {
|
||||
if transaction_count == 0 {
|
||||
return;
|
||||
}
|
||||
let mut out_transactions = Vec::with_capacity(transaction_count);
|
||||
let mut out_documents = Vec::with_capacity(transaction_count);
|
||||
for i in 0..transaction_count {
|
||||
let txn = &mut **transactions.offset(i as isize);
|
||||
debug_assert!(!txn.is_empty());
|
||||
let new_txn = make_transaction(is_async);
|
||||
out_transactions.push(mem::replace(txn, new_txn));
|
||||
out_documents.push((**document_handles.offset(i as isize)).document_id);
|
||||
}
|
||||
(**document_handles).api.send_transactions(
|
||||
out_documents,
|
||||
out_transactions);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wr_transaction_clear_display_list(
|
||||
txn: &mut Transaction,
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use api::{ApiMsg, FrameMsg, SceneMsg, TransactionMsg};
|
||||
use api::{ApiMsg, FrameMsg, SceneMsg};
|
||||
use bincode::serialize;
|
||||
use byteorder::{LittleEndian, WriteBytesExt};
|
||||
use std::any::TypeId;
|
||||
|
@ -61,41 +61,32 @@ impl ApiRecordingReceiver for BinaryRecorder {
|
|||
}
|
||||
}
|
||||
|
||||
fn should_record_transaction_msg(msgs: &TransactionMsg) -> bool {
|
||||
if msgs.generate_frame {
|
||||
return true;
|
||||
}
|
||||
|
||||
for msg in &msgs.scene_ops {
|
||||
match *msg {
|
||||
SceneMsg::SetDisplayList { .. } |
|
||||
SceneMsg::SetRootPipeline { .. } => return true,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
for msg in &msgs.frame_ops {
|
||||
match *msg {
|
||||
FrameMsg::GetScrollNodeState(..) |
|
||||
FrameMsg::HitTest(..) => {}
|
||||
_ => return true,
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
pub fn should_record_msg(msg: &ApiMsg) -> bool {
|
||||
match *msg {
|
||||
ApiMsg::UpdateResources(..) |
|
||||
ApiMsg::AddDocument { .. } |
|
||||
ApiMsg::DeleteDocument(..) => true,
|
||||
ApiMsg::UpdateDocuments(_, ref msgs) => {
|
||||
for msg in msgs {
|
||||
if should_record_transaction_msg(msg) {
|
||||
return true;
|
||||
ApiMsg::UpdateDocument(_, ref msgs) => {
|
||||
if msgs.generate_frame {
|
||||
return true;
|
||||
}
|
||||
|
||||
for msg in &msgs.scene_ops {
|
||||
match *msg {
|
||||
SceneMsg::SetDisplayList { .. } |
|
||||
SceneMsg::SetRootPipeline { .. } => return true,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
for msg in &msgs.frame_ops {
|
||||
match *msg {
|
||||
FrameMsg::GetScrollNodeState(..) |
|
||||
FrameMsg::HitTest(..) => {}
|
||||
_ => return true,
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
_ => false,
|
||||
|
|
|
@ -862,66 +862,57 @@ impl RenderBackend {
|
|||
|
||||
while let Ok(msg) = self.scene_rx.try_recv() {
|
||||
match msg {
|
||||
SceneBuilderResult::Transactions(mut txns, result_tx) => {
|
||||
self.resource_cache.before_frames(SystemTime::now());
|
||||
self.maybe_force_nop_documents(
|
||||
SceneBuilderResult::Transaction(mut txn, result_tx) => {
|
||||
let has_built_scene = txn.built_scene.is_some();
|
||||
if let Some(doc) = self.documents.get_mut(&txn.document_id) {
|
||||
|
||||
doc.removed_pipelines.append(&mut txn.removed_pipelines);
|
||||
|
||||
if let Some(mut built_scene) = txn.built_scene.take() {
|
||||
doc.new_async_scene_ready(
|
||||
built_scene,
|
||||
&mut self.recycler,
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(tx) = result_tx {
|
||||
let (resume_tx, resume_rx) = channel();
|
||||
tx.send(SceneSwapResult::Complete(resume_tx)).unwrap();
|
||||
// Block until the post-swap hook has completed on
|
||||
// the scene builder thread. We need to do this before
|
||||
// we can sample from the sampler hook which might happen
|
||||
// in the update_document call below.
|
||||
resume_rx.recv().ok();
|
||||
}
|
||||
} else {
|
||||
// The document was removed while we were building it, skip it.
|
||||
// TODO: we might want to just ensure that removed documents are
|
||||
// always forwarded to the scene builder thread to avoid this case.
|
||||
if let Some(tx) = result_tx {
|
||||
tx.send(SceneSwapResult::Aborted).unwrap();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
self.resource_cache.add_rasterized_blob_images(
|
||||
txn.rasterized_blobs.take()
|
||||
);
|
||||
if let Some((rasterizer, info)) = txn.blob_rasterizer.take() {
|
||||
self.resource_cache.set_blob_rasterizer(rasterizer, info);
|
||||
}
|
||||
|
||||
self.update_document(
|
||||
txn.document_id,
|
||||
txn.resource_updates.take(),
|
||||
txn.interner_updates.take(),
|
||||
txn.frame_ops.take(),
|
||||
txn.notifications.take(),
|
||||
txn.render_frame,
|
||||
txn.invalidate_rendered_frame,
|
||||
&mut frame_counter,
|
||||
&mut profile_counters,
|
||||
|document_id| txns.iter().any(|txn| txn.document_id == document_id));
|
||||
|
||||
for mut txn in txns.drain(..) {
|
||||
let has_built_scene = txn.built_scene.is_some();
|
||||
if let Some(doc) = self.documents.get_mut(&txn.document_id) {
|
||||
|
||||
doc.removed_pipelines.append(&mut txn.removed_pipelines);
|
||||
|
||||
if let Some(mut built_scene) = txn.built_scene.take() {
|
||||
doc.new_async_scene_ready(
|
||||
built_scene,
|
||||
&mut self.recycler,
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(ref tx) = result_tx {
|
||||
let (resume_tx, resume_rx) = channel();
|
||||
tx.send(SceneSwapResult::Complete(resume_tx)).unwrap();
|
||||
// Block until the post-swap hook has completed on
|
||||
// the scene builder thread. We need to do this before
|
||||
// we can sample from the sampler hook which might happen
|
||||
// in the update_document call below.
|
||||
resume_rx.recv().ok();
|
||||
}
|
||||
} else {
|
||||
// The document was removed while we were building it, skip it.
|
||||
// TODO: we might want to just ensure that removed documents are
|
||||
// always forwarded to the scene builder thread to avoid this case.
|
||||
if let Some(ref tx) = result_tx {
|
||||
tx.send(SceneSwapResult::Aborted).unwrap();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
self.resource_cache.add_rasterized_blob_images(
|
||||
txn.rasterized_blobs.take()
|
||||
);
|
||||
if let Some((rasterizer, info)) = txn.blob_rasterizer.take() {
|
||||
self.resource_cache.set_blob_rasterizer(rasterizer, info);
|
||||
}
|
||||
|
||||
self.update_document(
|
||||
txn.document_id,
|
||||
txn.resource_updates.take(),
|
||||
txn.interner_updates.take(),
|
||||
txn.frame_ops.take(),
|
||||
txn.notifications.take(),
|
||||
txn.render_frame,
|
||||
txn.invalidate_rendered_frame,
|
||||
&mut frame_counter,
|
||||
&mut profile_counters,
|
||||
has_built_scene,
|
||||
);
|
||||
}
|
||||
self.resource_cache.after_frames();
|
||||
has_built_scene,
|
||||
);
|
||||
},
|
||||
SceneBuilderResult::FlushComplete(tx) => {
|
||||
tx.send(()).ok();
|
||||
|
@ -1129,7 +1120,7 @@ impl RenderBackend {
|
|||
preserve_frame_state: false,
|
||||
};
|
||||
let txn = TransactionMsg::scene_message(scene_msg);
|
||||
r.write_msg(*frame_counter, &ApiMsg::UpdateDocuments(vec![*id], vec![txn]));
|
||||
r.write_msg(*frame_counter, &ApiMsg::UpdateDocument(*id, txn));
|
||||
r.write_payload(*frame_counter, &Payload::construct_data(
|
||||
epoch,
|
||||
pipeline_id,
|
||||
|
@ -1186,10 +1177,10 @@ impl RenderBackend {
|
|||
info!("Recycling stats: {:?}", self.recycler);
|
||||
return false;
|
||||
}
|
||||
ApiMsg::UpdateDocuments(document_ids, transaction_msgs) => {
|
||||
self.prepare_transactions(
|
||||
document_ids,
|
||||
transaction_msgs,
|
||||
ApiMsg::UpdateDocument(document_id, transaction_msg) => {
|
||||
self.prepare_transaction(
|
||||
document_id,
|
||||
transaction_msg,
|
||||
frame_counter,
|
||||
profile_counters,
|
||||
);
|
||||
|
@ -1199,152 +1190,99 @@ impl RenderBackend {
|
|||
true
|
||||
}
|
||||
|
||||
fn prepare_transactions(
|
||||
fn prepare_transaction(
|
||||
&mut self,
|
||||
document_ids: Vec<DocumentId>,
|
||||
mut transaction_msgs: Vec<TransactionMsg>,
|
||||
document_id: DocumentId,
|
||||
mut transaction_msg: TransactionMsg,
|
||||
frame_counter: &mut u32,
|
||||
profile_counters: &mut BackendProfileCounters,
|
||||
) {
|
||||
let mut use_scene_builder = transaction_msgs.iter()
|
||||
.any(|transaction_msg| transaction_msg.use_scene_builder_thread);
|
||||
let use_high_priority = transaction_msgs.iter()
|
||||
.any(|transaction_msg| !transaction_msg.low_priority);
|
||||
|
||||
let mut txns : Vec<Box<Transaction>> = document_ids.iter().zip(transaction_msgs.drain(..))
|
||||
.map(|(&document_id, mut transaction_msg)| {
|
||||
let mut txn = Box::new(Transaction {
|
||||
document_id,
|
||||
display_list_updates: Vec::new(),
|
||||
removed_pipelines: Vec::new(),
|
||||
epoch_updates: Vec::new(),
|
||||
request_scene_build: None,
|
||||
blob_rasterizer: None,
|
||||
blob_requests: Vec::new(),
|
||||
resource_updates: transaction_msg.resource_updates,
|
||||
frame_ops: transaction_msg.frame_ops,
|
||||
rasterized_blobs: Vec::new(),
|
||||
notifications: transaction_msg.notifications,
|
||||
set_root_pipeline: None,
|
||||
render_frame: transaction_msg.generate_frame,
|
||||
invalidate_rendered_frame: transaction_msg.invalidate_rendered_frame,
|
||||
});
|
||||
|
||||
self.resource_cache.pre_scene_building_update(
|
||||
&mut txn.resource_updates,
|
||||
&mut profile_counters.resources,
|
||||
);
|
||||
|
||||
// If we've been above the threshold for reclaiming GPU cache memory for
|
||||
// long enough, drop it and rebuild it. This needs to be done before any
|
||||
// updates for this frame are made.
|
||||
if self.gpu_cache.should_reclaim_memory() {
|
||||
self.gpu_cache.clear();
|
||||
}
|
||||
|
||||
for scene_msg in transaction_msg.scene_ops.drain(..) {
|
||||
let _timer = profile_counters.total_time.timer();
|
||||
self.process_scene_msg(
|
||||
document_id,
|
||||
scene_msg,
|
||||
*frame_counter,
|
||||
&mut txn,
|
||||
&mut profile_counters.ipc,
|
||||
)
|
||||
}
|
||||
|
||||
let blobs_to_rasterize = get_blob_image_updates(&txn.resource_updates);
|
||||
if !blobs_to_rasterize.is_empty() {
|
||||
let (blob_rasterizer, blob_requests) = self.resource_cache
|
||||
.create_blob_scene_builder_requests(&blobs_to_rasterize);
|
||||
|
||||
txn.blob_requests = blob_requests;
|
||||
txn.blob_rasterizer = blob_rasterizer;
|
||||
}
|
||||
txn
|
||||
}).collect();
|
||||
|
||||
use_scene_builder = use_scene_builder || txns.iter().any(|txn| {
|
||||
!txn.can_skip_scene_builder() || txn.blob_rasterizer.is_some()
|
||||
let mut txn = Box::new(Transaction {
|
||||
document_id,
|
||||
display_list_updates: Vec::new(),
|
||||
removed_pipelines: Vec::new(),
|
||||
epoch_updates: Vec::new(),
|
||||
request_scene_build: None,
|
||||
blob_rasterizer: None,
|
||||
blob_requests: Vec::new(),
|
||||
resource_updates: transaction_msg.resource_updates,
|
||||
frame_ops: transaction_msg.frame_ops,
|
||||
rasterized_blobs: Vec::new(),
|
||||
notifications: transaction_msg.notifications,
|
||||
set_root_pipeline: None,
|
||||
render_frame: transaction_msg.generate_frame,
|
||||
invalidate_rendered_frame: transaction_msg.invalidate_rendered_frame,
|
||||
});
|
||||
|
||||
if use_scene_builder {
|
||||
for txn in txns.iter_mut() {
|
||||
let doc = self.documents.get_mut(&txn.document_id).unwrap();
|
||||
self.resource_cache.pre_scene_building_update(
|
||||
&mut txn.resource_updates,
|
||||
&mut profile_counters.resources,
|
||||
);
|
||||
|
||||
if txn.should_build_scene() {
|
||||
txn.request_scene_build = Some(SceneRequest {
|
||||
view: doc.view.clone(),
|
||||
font_instances: self.resource_cache.get_font_instances(),
|
||||
output_pipelines: doc.output_pipelines.clone(),
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.resource_cache.before_frames(SystemTime::now());
|
||||
self.maybe_force_nop_documents(
|
||||
// If we've been above the threshold for reclaiming GPU cache memory for
|
||||
// long enough, drop it and rebuild it. This needs to be done before any
|
||||
// updates for this frame are made.
|
||||
if self.gpu_cache.should_reclaim_memory() {
|
||||
self.gpu_cache.clear();
|
||||
}
|
||||
|
||||
for scene_msg in transaction_msg.scene_ops.drain(..) {
|
||||
let _timer = profile_counters.total_time.timer();
|
||||
self.process_scene_msg(
|
||||
document_id,
|
||||
scene_msg,
|
||||
*frame_counter,
|
||||
&mut txn,
|
||||
&mut profile_counters.ipc,
|
||||
)
|
||||
}
|
||||
|
||||
let blobs_to_rasterize = get_blob_image_updates(&txn.resource_updates);
|
||||
if !blobs_to_rasterize.is_empty() {
|
||||
let (blob_rasterizer, blob_requests) = self.resource_cache
|
||||
.create_blob_scene_builder_requests(&blobs_to_rasterize);
|
||||
|
||||
txn.blob_requests = blob_requests;
|
||||
txn.blob_rasterizer = blob_rasterizer;
|
||||
}
|
||||
|
||||
if !transaction_msg.use_scene_builder_thread &&
|
||||
txn.can_skip_scene_builder() &&
|
||||
txn.blob_rasterizer.is_none() {
|
||||
|
||||
self.update_document(
|
||||
txn.document_id,
|
||||
txn.resource_updates.take(),
|
||||
None,
|
||||
txn.frame_ops.take(),
|
||||
txn.notifications.take(),
|
||||
txn.render_frame,
|
||||
txn.invalidate_rendered_frame,
|
||||
frame_counter,
|
||||
profile_counters,
|
||||
|document_id| txns.iter().any(|txn| txn.document_id == document_id));
|
||||
false
|
||||
);
|
||||
|
||||
for mut txn in txns {
|
||||
self.update_document(
|
||||
txn.document_id,
|
||||
txn.resource_updates.take(),
|
||||
None,
|
||||
txn.frame_ops.take(),
|
||||
txn.notifications.take(),
|
||||
txn.render_frame,
|
||||
txn.invalidate_rendered_frame,
|
||||
frame_counter,
|
||||
profile_counters,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
self.resource_cache.after_frames();
|
||||
return;
|
||||
}
|
||||
|
||||
let tx = if use_high_priority {
|
||||
&self.scene_tx
|
||||
} else {
|
||||
let doc = self.documents.get_mut(&document_id).unwrap();
|
||||
|
||||
if txn.should_build_scene() {
|
||||
txn.request_scene_build = Some(SceneRequest {
|
||||
view: doc.view.clone(),
|
||||
font_instances: self.resource_cache.get_font_instances(),
|
||||
output_pipelines: doc.output_pipelines.clone(),
|
||||
});
|
||||
}
|
||||
|
||||
let tx = if transaction_msg.low_priority {
|
||||
&self.low_priority_scene_tx
|
||||
} else {
|
||||
&self.scene_tx
|
||||
};
|
||||
|
||||
tx.send(SceneBuilderRequest::Transactions(txns)).unwrap();
|
||||
}
|
||||
|
||||
/// In certain cases, resources shared by multiple documents have to run
|
||||
/// maintenance operations, like cleaning up unused cache items. In those
|
||||
/// cases, we are forced to build frames for all documents, however we
|
||||
/// may not have a transaction ready for every document - this method
|
||||
/// calls update_document with the details of a fake, nop transaction just
|
||||
/// to force a frame build.
|
||||
fn maybe_force_nop_documents<F>(&mut self,
|
||||
frame_counter: &mut u32,
|
||||
profile_counters: &mut BackendProfileCounters,
|
||||
document_already_present: F) where
|
||||
F: Fn(DocumentId) -> bool {
|
||||
if self.resource_cache.requires_frame_build() {
|
||||
let nop_documents : Vec<DocumentId> = self.documents.keys()
|
||||
.cloned()
|
||||
.filter(|key| !document_already_present(*key))
|
||||
.collect();
|
||||
for &document_id in &nop_documents {
|
||||
self.update_document(
|
||||
document_id,
|
||||
Vec::default(),
|
||||
None,
|
||||
Vec::default(),
|
||||
Vec::default(),
|
||||
false,
|
||||
false,
|
||||
frame_counter,
|
||||
profile_counters,
|
||||
false);
|
||||
}
|
||||
}
|
||||
tx.send(SceneBuilderRequest::Transaction(txn)).unwrap();
|
||||
}
|
||||
|
||||
fn update_document(
|
||||
|
@ -1415,9 +1353,7 @@ impl RenderBackend {
|
|||
}
|
||||
|
||||
// Avoid re-building the frame if the current built frame is still valid.
|
||||
let build_frame = (render_frame && !doc.frame_is_valid) ||
|
||||
self.resource_cache.requires_frame_build() &&
|
||||
doc.frame_builder.is_some();
|
||||
let build_frame = render_frame && !doc.frame_is_valid;
|
||||
|
||||
// Request composite is true when we want to composite frame even when
|
||||
// there is no frame update. This happens when video frame is updated under
|
||||
|
|
|
@ -5496,11 +5496,11 @@ pub trait SceneBuilderHooks {
|
|||
/// This is called after each scene swap occurs. The PipelineInfo contains
|
||||
/// the updated epochs and pipelines removed in the new scene compared to
|
||||
/// the old scene.
|
||||
fn post_scene_swap(&self, document_id: &Vec<DocumentId>, info: PipelineInfo, sceneswap_time: u64);
|
||||
fn post_scene_swap(&self, document_id: DocumentId, info: PipelineInfo, sceneswap_time: u64);
|
||||
/// This is called after a resource update operation on the scene builder
|
||||
/// thread, in the case where resource updates were applied without a scene
|
||||
/// build.
|
||||
fn post_resource_update(&self, document_ids: &Vec<DocumentId>);
|
||||
fn post_resource_update(&self, document_id: DocumentId);
|
||||
/// This is called after a scene build completes without any changes being
|
||||
/// made. We guarantee that each pre_scene_build call will be matched with
|
||||
/// exactly one of post_scene_swap, post_resource_update or
|
||||
|
|
|
@ -42,7 +42,6 @@ use std::os::raw::c_void;
|
|||
#[cfg(any(feature = "capture", feature = "replay"))]
|
||||
use std::path::PathBuf;
|
||||
use std::sync::{Arc, RwLock};
|
||||
use std::time::SystemTime;
|
||||
use texture_cache::{TextureCache, TextureCacheHandle, Eviction};
|
||||
use util::drain_filter;
|
||||
|
||||
|
@ -1569,18 +1568,6 @@ impl ResourceCache {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn before_frames(&mut self, time: SystemTime) {
|
||||
self.texture_cache.before_frames(time);
|
||||
}
|
||||
|
||||
pub fn after_frames(&mut self) {
|
||||
self.texture_cache.after_frames();
|
||||
}
|
||||
|
||||
pub fn requires_frame_build(&self) -> bool {
|
||||
self.texture_cache.requires_frame_build()
|
||||
}
|
||||
|
||||
pub fn begin_frame(&mut self, stamp: FrameStamp) {
|
||||
debug_assert_eq!(self.state, State::Idle);
|
||||
self.state = State::AddResources;
|
||||
|
|
|
@ -28,7 +28,6 @@ use resource_cache::{AsyncBlobImageInfo, FontInstanceMap};
|
|||
use render_backend::DocumentView;
|
||||
use renderer::{PipelineInfo, SceneBuilderHooks};
|
||||
use scene::Scene;
|
||||
use std::iter;
|
||||
use std::sync::mpsc::{channel, Receiver, Sender};
|
||||
use std::mem::replace;
|
||||
use time::precise_time_ns;
|
||||
|
@ -137,7 +136,7 @@ pub struct BuiltScene {
|
|||
|
||||
// Message from render backend to scene builder.
|
||||
pub enum SceneBuilderRequest {
|
||||
Transactions(Vec<Box<Transaction>>),
|
||||
Transaction(Box<Transaction>),
|
||||
ExternalEvent(ExternalEvent),
|
||||
DeleteDocument(DocumentId),
|
||||
WakeUp,
|
||||
|
@ -156,7 +155,7 @@ pub enum SceneBuilderRequest {
|
|||
|
||||
// Message from scene builder to render backend.
|
||||
pub enum SceneBuilderResult {
|
||||
Transactions(Vec<Box<BuiltTransaction>>, Option<Sender<SceneSwapResult>>),
|
||||
Transaction(Box<BuiltTransaction>, Option<Sender<SceneSwapResult>>),
|
||||
ExternalEvent(ExternalEvent),
|
||||
FlushComplete(MsgSender<()>),
|
||||
ClearNamespace(IdNamespace),
|
||||
|
@ -322,11 +321,9 @@ impl SceneBuilder {
|
|||
Ok(SceneBuilderRequest::Flush(tx)) => {
|
||||
self.send(SceneBuilderResult::FlushComplete(tx));
|
||||
}
|
||||
Ok(SceneBuilderRequest::Transactions(mut txns)) => {
|
||||
let built_txns : Vec<Box<BuiltTransaction>> = txns.iter_mut()
|
||||
.map(|txn| self.process_transaction(txn))
|
||||
.collect();
|
||||
self.forward_built_transactions(built_txns);
|
||||
Ok(SceneBuilderRequest::Transaction(mut txn)) => {
|
||||
let built_txn = self.process_transaction(&mut txn);
|
||||
self.forward_built_transaction(built_txn);
|
||||
}
|
||||
Ok(SceneBuilderRequest::DeleteDocument(document_id)) => {
|
||||
self.documents.remove(&document_id);
|
||||
|
@ -432,7 +429,7 @@ impl SceneBuilder {
|
|||
},
|
||||
);
|
||||
|
||||
let txns = vec![Box::new(BuiltTransaction {
|
||||
let txn = Box::new(BuiltTransaction {
|
||||
document_id: item.document_id,
|
||||
render_frame: item.build_frame,
|
||||
invalidate_rendered_frame: false,
|
||||
|
@ -446,9 +443,9 @@ impl SceneBuilder {
|
|||
scene_build_start_time,
|
||||
scene_build_end_time: precise_time_ns(),
|
||||
interner_updates,
|
||||
})];
|
||||
});
|
||||
|
||||
self.forward_built_transactions(txns);
|
||||
self.forward_built_transaction(txn);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -553,49 +550,36 @@ impl SceneBuilder {
|
|||
})
|
||||
}
|
||||
|
||||
/// Send the results of process_transaction back to the render backend.
|
||||
fn forward_built_transactions(&mut self, txns: Vec<Box<BuiltTransaction>>) {
|
||||
let (pipeline_info, result_tx, result_rx) = match &self.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()
|
||||
.scene.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(),
|
||||
};
|
||||
/// Send the result of process_transaction back to the render backend.
|
||||
fn forward_built_transaction(&mut self, txn: Box<BuiltTransaction>) {
|
||||
// We only need the pipeline info and the result channel if we
|
||||
// have a hook callback *and* if this transaction actually built
|
||||
// a new scene that is going to get swapped in. In other cases
|
||||
// pipeline_info can be None and we can avoid some overhead from
|
||||
// invoking the hooks and blocking on the channel.
|
||||
let (pipeline_info, result_tx, result_rx) = match (&self.hooks, &txn.built_scene) {
|
||||
(&Some(ref hooks), &Some(ref built)) => {
|
||||
let info = PipelineInfo {
|
||||
epochs: built.scene.pipeline_epochs.iter()
|
||||
.map(|(&pipeline_id, &epoch)| ((pipeline_id, txn.document_id), epoch))
|
||||
.collect(),
|
||||
removed_pipelines: txn.removed_pipelines.clone(),
|
||||
};
|
||||
let (tx, rx) = channel();
|
||||
|
||||
let (tx, rx) = channel();
|
||||
let txn = txns.iter().find(|txn| txn.built_scene.is_some()).unwrap();
|
||||
hooks.pre_scene_swap(txn.scene_build_end_time - txn.scene_build_start_time);
|
||||
hooks.pre_scene_swap(txn.scene_build_end_time - txn.scene_build_start_time);
|
||||
|
||||
(Some(info), Some(tx), Some(rx))
|
||||
} else {
|
||||
(None, None, None)
|
||||
}
|
||||
(Some(info), Some(tx), Some(rx))
|
||||
}
|
||||
_ => (None, None, None)
|
||||
_ => (None, None, None),
|
||||
};
|
||||
|
||||
let document_id = txn.document_id;
|
||||
let scene_swap_start_time = precise_time_ns();
|
||||
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.clone())
|
||||
.collect()
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
let has_resources_updates = !txn.resource_updates.is_empty();
|
||||
let invalidate_rendered_frame = txn.invalidate_rendered_frame;
|
||||
|
||||
self.tx.send(SceneBuilderResult::Transactions(txns, result_tx)).unwrap();
|
||||
self.tx.send(SceneBuilderResult::Transaction(txn, result_tx)).unwrap();
|
||||
|
||||
let _ = self.api_tx.send(ApiMsg::WakeUp);
|
||||
|
||||
|
@ -603,7 +587,7 @@ impl SceneBuilder {
|
|||
// Block until the swap is done, then invoke the hook.
|
||||
let swap_result = result_rx.unwrap().recv();
|
||||
let scene_swap_time = precise_time_ns() - scene_swap_start_time;
|
||||
self.hooks.as_ref().unwrap().post_scene_swap(&document_ids,
|
||||
self.hooks.as_ref().unwrap().post_scene_swap(document_id,
|
||||
pipeline_info, scene_swap_time);
|
||||
// Once the hook is done, allow the RB thread to resume
|
||||
match swap_result {
|
||||
|
@ -612,9 +596,9 @@ impl SceneBuilder {
|
|||
},
|
||||
_ => (),
|
||||
};
|
||||
} else if !have_resources_updates.is_empty() {
|
||||
} else if has_resources_updates || invalidate_rendered_frame {
|
||||
if let &Some(ref hooks) = &self.hooks {
|
||||
hooks.post_resource_update(&have_resources_updates);
|
||||
hooks.post_resource_update(document_id);
|
||||
}
|
||||
} else {
|
||||
if let &Some(ref hooks) = &self.hooks {
|
||||
|
@ -650,11 +634,9 @@ impl LowPrioritySceneBuilder {
|
|||
pub fn run(&mut self) {
|
||||
loop {
|
||||
match self.rx.recv() {
|
||||
Ok(SceneBuilderRequest::Transactions(mut txns)) => {
|
||||
let txns : Vec<Box<Transaction>> = txns.drain(..)
|
||||
.map(|txn| self.process_transaction(txn))
|
||||
.collect();
|
||||
self.tx.send(SceneBuilderRequest::Transactions(txns)).unwrap();
|
||||
Ok(SceneBuilderRequest::Transaction(txn)) => {
|
||||
let txn = self.process_transaction(txn);
|
||||
self.tx.send(SceneBuilderRequest::Transaction(txn)).unwrap();
|
||||
}
|
||||
Ok(SceneBuilderRequest::DeleteDocument(document_id)) => {
|
||||
self.tx.send(SceneBuilderRequest::DeleteDocument(document_id)).unwrap();
|
||||
|
|
|
@ -34,10 +34,6 @@ const PICTURE_TILE_FORMAT: ImageFormat = ImageFormat::BGRA8;
|
|||
const TEXTURE_REGION_PIXELS: usize =
|
||||
(TEXTURE_REGION_DIMENSIONS as usize) * (TEXTURE_REGION_DIMENSIONS as usize);
|
||||
|
||||
// The minimum number of bytes that we must be able to reclaim in order
|
||||
// to justify clearing the entire shared cache in order to shrink it.
|
||||
const RECLAIM_THRESHOLD_BYTES: usize = 5 * 1024 * 1024;
|
||||
|
||||
/// Items in the texture cache can either be standalone textures,
|
||||
/// or a sub-rect inside the shared cache.
|
||||
#[derive(Debug)]
|
||||
|
@ -516,10 +512,6 @@ pub struct TextureCache {
|
|||
/// begin_frame and moved back in end_frame to solve borrow checker issues.
|
||||
/// We should try removing this when we require a rustc with NLL.
|
||||
doc_data: PerDocumentData,
|
||||
|
||||
/// This indicates that we performed a cleanup operation which requires all
|
||||
/// documents to build a frame.
|
||||
require_frame_build: bool,
|
||||
}
|
||||
|
||||
impl TextureCache {
|
||||
|
@ -589,7 +581,6 @@ impl TextureCache {
|
|||
now: FrameStamp::INVALID,
|
||||
per_doc_data: FastHashMap::default(),
|
||||
doc_data: PerDocumentData::new(),
|
||||
require_frame_build: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -611,6 +602,13 @@ impl TextureCache {
|
|||
|
||||
/// Clear all entries of the specified kind.
|
||||
fn clear_kind(&mut self, kind: EntryKind) {
|
||||
// This pref just helps us avoid crashes when we begin using multiple documents.
|
||||
// What we need to do for clear to work correctly with multiple documents is
|
||||
// to ensure that we generate frames for all documents whenever we do this.
|
||||
if self.debug_flags.contains(DebugFlags::TEXTURE_CACHE_DBG_DISABLE_SHRINK) {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut per_doc_data = mem::replace(&mut self.per_doc_data, FastHashMap::default());
|
||||
for (&_, doc_data) in per_doc_data.iter_mut() {
|
||||
let entry_handles = mem::replace(
|
||||
|
@ -625,7 +623,6 @@ impl TextureCache {
|
|||
}
|
||||
}
|
||||
self.per_doc_data = per_doc_data;
|
||||
self.require_frame_build = true;
|
||||
}
|
||||
|
||||
fn clear_standalone(&mut self) {
|
||||
|
@ -643,6 +640,9 @@ impl TextureCache {
|
|||
}
|
||||
|
||||
fn clear_shared(&mut self) {
|
||||
if self.debug_flags.contains(DebugFlags::TEXTURE_CACHE_DBG_DISABLE_SHRINK) {
|
||||
return;
|
||||
}
|
||||
self.unset_doc_data();
|
||||
self.clear_kind(EntryKind::Shared);
|
||||
self.shared_textures.clear(&mut self.pending_updates);
|
||||
|
@ -669,58 +669,21 @@ impl TextureCache {
|
|||
mem::replace(&mut self.doc_data, PerDocumentData::new()));
|
||||
}
|
||||
|
||||
pub fn before_frames(&mut self, time: SystemTime) {
|
||||
self.maybe_reclaim_shared_memory(time);
|
||||
}
|
||||
|
||||
pub fn after_frames(&mut self) {
|
||||
self.require_frame_build = false;
|
||||
}
|
||||
|
||||
pub fn requires_frame_build(&self) -> bool {
|
||||
return self.require_frame_build;
|
||||
}
|
||||
|
||||
/// Called at the beginning of each frame.
|
||||
pub fn begin_frame(&mut self, stamp: FrameStamp) {
|
||||
debug_assert!(!self.now.is_valid());
|
||||
self.now = stamp;
|
||||
self.set_doc_data();
|
||||
self.maybe_do_periodic_gc();
|
||||
self.maybe_reclaim_shared_cache_memory();
|
||||
}
|
||||
|
||||
fn maybe_reclaim_shared_memory(&mut self, time: SystemTime) {
|
||||
// If we've had a sufficient number of unused layers for a sufficiently
|
||||
// long time, just blow the whole cache away to shrink it.
|
||||
//
|
||||
// We could do this more intelligently with a resize+blit, but that would
|
||||
// add complexity for a rare case.
|
||||
//
|
||||
// This function must be called before the first begin_frame() for a group
|
||||
// of documents, otherwise documents could end up ignoring the
|
||||
// self.require_frame_build flag which is set if we end up calling
|
||||
// clear_shared.
|
||||
debug_assert!(!self.now.is_valid());
|
||||
if self.shared_textures.empty_region_bytes() >= RECLAIM_THRESHOLD_BYTES {
|
||||
self.reached_reclaim_threshold.get_or_insert(time);
|
||||
} else {
|
||||
self.reached_reclaim_threshold = None;
|
||||
}
|
||||
if let Some(t) = self.reached_reclaim_threshold {
|
||||
let dur = time.duration_since(t).unwrap_or(Duration::default());
|
||||
if dur >= Duration::from_secs(5) {
|
||||
self.clear_shared();
|
||||
self.reached_reclaim_threshold = None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Called at the beginning of each frame to periodically GC by expiring
|
||||
/// old shared entries. If necessary, the shared memory opened up as a
|
||||
/// result of expiring these entries will be reclaimed before the next
|
||||
/// group of document frames.
|
||||
fn maybe_do_periodic_gc(&mut self) {
|
||||
/// Called at the beginning of each frame to periodically GC and reclaim
|
||||
/// storage if the cache has grown too large.
|
||||
fn maybe_reclaim_shared_cache_memory(&mut self) {
|
||||
debug_assert!(self.now.is_valid());
|
||||
// The minimum number of bytes that we must be able to reclaim in order
|
||||
// to justify clearing the entire shared cache in order to shrink it.
|
||||
const RECLAIM_THRESHOLD_BYTES: usize = 5 * 1024 * 1024;
|
||||
|
||||
// Normally the shared cache only gets GCed when we fail to allocate.
|
||||
// However, we also perform a periodic, conservative GC to ensure that
|
||||
|
@ -738,6 +701,28 @@ impl TextureCache {
|
|||
.build();
|
||||
self.maybe_expire_old_shared_entries(threshold);
|
||||
}
|
||||
|
||||
// If we've had a sufficient number of unused layers for a sufficiently
|
||||
// long time, just blow the whole cache away to shrink it.
|
||||
//
|
||||
// We could do this more intelligently with a resize+blit, but that would
|
||||
// add complexity for a rare case.
|
||||
//
|
||||
// This block of code is broken with multiple documents, and should be
|
||||
// moved out into a section that runs before building any frames in a
|
||||
// group of documents.
|
||||
if self.shared_textures.empty_region_bytes() >= RECLAIM_THRESHOLD_BYTES {
|
||||
self.reached_reclaim_threshold.get_or_insert(self.now.time());
|
||||
} else {
|
||||
self.reached_reclaim_threshold = None;
|
||||
}
|
||||
if let Some(t) = self.reached_reclaim_threshold {
|
||||
let dur = self.now.time().duration_since(t).unwrap_or(Duration::default());
|
||||
if dur >= Duration::from_secs(5) {
|
||||
self.clear_shared();
|
||||
self.reached_reclaim_threshold = None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn end_frame(&mut self, texture_cache_profile: &mut TextureCacheProfileCounters) {
|
||||
|
|
|
@ -439,11 +439,6 @@ impl Transaction {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct DocumentTransaction {
|
||||
pub document_id: DocumentId,
|
||||
pub transaction: Transaction,
|
||||
}
|
||||
|
||||
/// Represents a transaction in the format sent through the channel.
|
||||
#[derive(Clone, Deserialize, Serialize)]
|
||||
pub struct TransactionMsg {
|
||||
|
@ -731,7 +726,7 @@ pub enum ApiMsg {
|
|||
/// Adds a new document with given initial size.
|
||||
AddDocument(DocumentId, FramebufferIntSize, DocumentLayer),
|
||||
/// A message targeted at a particular document.
|
||||
UpdateDocuments(Vec<DocumentId>, Vec<TransactionMsg>),
|
||||
UpdateDocument(DocumentId, TransactionMsg),
|
||||
/// Deletes an existing document.
|
||||
DeleteDocument(DocumentId),
|
||||
/// An opaque handle that must be passed to the render notifier. It is used by Gecko
|
||||
|
@ -763,7 +758,7 @@ impl fmt::Debug for ApiMsg {
|
|||
ApiMsg::CloneApi(..) => "ApiMsg::CloneApi",
|
||||
ApiMsg::CloneApiByClient(..) => "ApiMsg::CloneApiByClient",
|
||||
ApiMsg::AddDocument(..) => "ApiMsg::AddDocument",
|
||||
ApiMsg::UpdateDocuments(..) => "ApiMsg::UpdateDocuments",
|
||||
ApiMsg::UpdateDocument(..) => "ApiMsg::UpdateDocument",
|
||||
ApiMsg::DeleteDocument(..) => "ApiMsg::DeleteDocument",
|
||||
ApiMsg::ExternalEvent(..) => "ApiMsg::ExternalEvent",
|
||||
ApiMsg::ClearNamespace(..) => "ApiMsg::ClearNamespace",
|
||||
|
@ -1051,14 +1046,15 @@ bitflags! {
|
|||
const TEXTURE_CACHE_DBG_CLEAR_EVICTED = 1 << 14;
|
||||
/// Show picture caching debug overlay
|
||||
const PICTURE_CACHING_DBG = 1 << 15;
|
||||
const TEXTURE_CACHE_DBG_DISABLE_SHRINK = 1 << 16;
|
||||
/// Highlight all primitives with colors based on kind.
|
||||
const PRIMITIVE_DBG = 1 << 16;
|
||||
const PRIMITIVE_DBG = 1 << 17;
|
||||
/// Draw a zoom widget showing part of the framebuffer zoomed in.
|
||||
const ZOOM_DBG = 1 << 17;
|
||||
const ZOOM_DBG = 1 << 18;
|
||||
/// Scale the debug renderer down for a smaller screen. This will disrupt
|
||||
/// any mapping between debug display items and page content, so shouldn't
|
||||
/// be used with overlays like the picture caching or primitive display.
|
||||
const SMALL_SCREEN = 1 << 18;
|
||||
const SMALL_SCREEN = 1 << 19;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1220,7 +1216,7 @@ impl RenderApi {
|
|||
// `RenderApi` instances for layout and compositor.
|
||||
//assert_eq!(document_id.0, self.namespace_id);
|
||||
self.api_sender
|
||||
.send(ApiMsg::UpdateDocuments(vec![document_id], vec![TransactionMsg::scene_message(msg)]))
|
||||
.send(ApiMsg::UpdateDocument(document_id, TransactionMsg::scene_message(msg)))
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
|
@ -1230,7 +1226,7 @@ impl RenderApi {
|
|||
// `RenderApi` instances for layout and compositor.
|
||||
//assert_eq!(document_id.0, self.namespace_id);
|
||||
self.api_sender
|
||||
.send(ApiMsg::UpdateDocuments(vec![document_id], vec![TransactionMsg::frame_message(msg)]))
|
||||
.send(ApiMsg::UpdateDocument(document_id, TransactionMsg::frame_message(msg)))
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
|
@ -1239,24 +1235,7 @@ impl RenderApi {
|
|||
for payload in payloads {
|
||||
self.payload_sender.send_payload(payload).unwrap();
|
||||
}
|
||||
self.api_sender.send(ApiMsg::UpdateDocuments(vec![document_id], vec![msg])).unwrap();
|
||||
}
|
||||
|
||||
pub fn send_transactions(&self, document_ids: Vec<DocumentId>, mut transactions: Vec<Transaction>) {
|
||||
debug_assert!(document_ids.len() == transactions.len());
|
||||
let length = document_ids.len();
|
||||
let (msgs, mut document_payloads) = transactions.drain(..)
|
||||
.fold((Vec::with_capacity(length), Vec::with_capacity(length)),
|
||||
|(mut msgs, mut document_payloads), transaction| {
|
||||
let (msg, payloads) = transaction.finalize();
|
||||
msgs.push(msg);
|
||||
document_payloads.push(payloads);
|
||||
(msgs, document_payloads)
|
||||
});
|
||||
for payload in document_payloads.drain(..).flatten() {
|
||||
self.payload_sender.send_payload(payload).unwrap();
|
||||
}
|
||||
self.api_sender.send(ApiMsg::UpdateDocuments(document_ids.clone(), msgs)).unwrap();
|
||||
self.api_sender.send(ApiMsg::UpdateDocument(document_id, msg)).unwrap();
|
||||
}
|
||||
|
||||
/// Does a hit test on display items in the specified document, at the given
|
||||
|
|
Двоичные данные
gfx/wr/wrench/reftests/border/border-suite-2.png
Двоичные данные
gfx/wr/wrench/reftests/border/border-suite-2.png
Двоичный файл не отображается.
До Ширина: | Высота: | Размер: 48 KiB После Ширина: | Высота: | Размер: 48 KiB |
Двоичные данные
gfx/wr/wrench/reftests/boxshadow/box-shadow-cache.png
Двоичные данные
gfx/wr/wrench/reftests/boxshadow/box-shadow-cache.png
Двоичный файл не отображается.
До Ширина: | Высота: | Размер: 35 KiB После Ширина: | Высота: | Размер: 35 KiB |
|
@ -140,24 +140,21 @@ impl WrenchThing for BinaryFrameReader {
|
|||
// (b) SetDisplayList
|
||||
// (c) GenerateFrame that occurs *after* (a) and (b)
|
||||
match msg {
|
||||
ApiMsg::UpdateDocuments(_, ref txns) => {
|
||||
for txn in txns {
|
||||
if txn.generate_frame {
|
||||
// TODO: is this appropriate, or do we need a ternary value / something else?
|
||||
found_frame_marker = true;
|
||||
}
|
||||
for doc_msg in &txn.scene_ops {
|
||||
match *doc_msg {
|
||||
SceneMsg::SetDisplayList { .. } => {
|
||||
found_frame_marker = false;
|
||||
found_display_list = true;
|
||||
}
|
||||
SceneMsg::SetRootPipeline(..) => {
|
||||
found_frame_marker = false;
|
||||
found_pipeline = true;
|
||||
}
|
||||
_ => {}
|
||||
ApiMsg::UpdateDocument(_, ref txn) => {
|
||||
if txn.generate_frame {
|
||||
found_frame_marker = true;
|
||||
}
|
||||
for doc_msg in &txn.scene_ops {
|
||||
match *doc_msg {
|
||||
SceneMsg::SetDisplayList { .. } => {
|
||||
found_frame_marker = false;
|
||||
found_display_list = true;
|
||||
}
|
||||
SceneMsg::SetRootPipeline(..) => {
|
||||
found_frame_marker = false;
|
||||
found_pipeline = true;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -271,31 +271,6 @@ impl JsonFrameWriter {
|
|||
self.images.insert(key, data);
|
||||
Some(path)
|
||||
}
|
||||
|
||||
fn update_document(&mut self, txn: &TransactionMsg) {
|
||||
self.update_resources(&txn.resource_updates);
|
||||
for doc_msg in &txn.scene_ops {
|
||||
match *doc_msg {
|
||||
SceneMsg::SetDisplayList {
|
||||
ref epoch,
|
||||
ref pipeline_id,
|
||||
ref background,
|
||||
ref viewport_size,
|
||||
ref list_descriptor,
|
||||
..
|
||||
} => {
|
||||
self.begin_write_display_list(
|
||||
epoch,
|
||||
pipeline_id,
|
||||
background,
|
||||
viewport_size,
|
||||
list_descriptor,
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for JsonFrameWriter {
|
||||
|
@ -308,9 +283,29 @@ impl webrender::ApiRecordingReceiver for JsonFrameWriter {
|
|||
fn write_msg(&mut self, _: u32, msg: &ApiMsg) {
|
||||
match *msg {
|
||||
ApiMsg::UpdateResources(ref updates) => self.update_resources(updates),
|
||||
ApiMsg::UpdateDocuments(_, ref txns) => {
|
||||
for txn in txns {
|
||||
self.update_document(txn)
|
||||
|
||||
ApiMsg::UpdateDocument(_, ref txn) => {
|
||||
self.update_resources(&txn.resource_updates);
|
||||
for doc_msg in &txn.scene_ops {
|
||||
match *doc_msg {
|
||||
SceneMsg::SetDisplayList {
|
||||
ref epoch,
|
||||
ref pipeline_id,
|
||||
ref background,
|
||||
ref viewport_size,
|
||||
ref list_descriptor,
|
||||
..
|
||||
} => {
|
||||
self.begin_write_display_list(
|
||||
epoch,
|
||||
pipeline_id,
|
||||
background,
|
||||
viewport_size,
|
||||
list_descriptor,
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
ApiMsg::CloneApi(..) => {}
|
||||
|
|
|
@ -149,31 +149,6 @@ impl RonFrameWriter {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn update_document(&mut self, txn: &TransactionMsg) {
|
||||
self.update_resources(&txn.resource_updates);
|
||||
for doc_msg in &txn.scene_ops {
|
||||
match *doc_msg {
|
||||
SceneMsg::SetDisplayList {
|
||||
ref epoch,
|
||||
ref pipeline_id,
|
||||
ref background,
|
||||
ref viewport_size,
|
||||
ref list_descriptor,
|
||||
..
|
||||
} => {
|
||||
self.begin_write_display_list(
|
||||
epoch,
|
||||
pipeline_id,
|
||||
background,
|
||||
viewport_size,
|
||||
list_descriptor,
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for RonFrameWriter {
|
||||
|
@ -186,9 +161,28 @@ impl webrender::ApiRecordingReceiver for RonFrameWriter {
|
|||
fn write_msg(&mut self, _: u32, msg: &ApiMsg) {
|
||||
match *msg {
|
||||
ApiMsg::UpdateResources(ref updates) => self.update_resources(updates),
|
||||
ApiMsg::UpdateDocuments(_, ref txns) => {
|
||||
for txn in txns {
|
||||
self.update_document(txn)
|
||||
ApiMsg::UpdateDocument(_, ref txn) => {
|
||||
self.update_resources(&txn.resource_updates);
|
||||
for doc_msg in &txn.scene_ops {
|
||||
match *doc_msg {
|
||||
SceneMsg::SetDisplayList {
|
||||
ref epoch,
|
||||
ref pipeline_id,
|
||||
ref background,
|
||||
ref viewport_size,
|
||||
ref list_descriptor,
|
||||
..
|
||||
} => {
|
||||
self.begin_write_display_list(
|
||||
epoch,
|
||||
pipeline_id,
|
||||
background,
|
||||
viewport_size,
|
||||
list_descriptor,
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
ApiMsg::CloneApi(..) => {}
|
||||
|
|
|
@ -443,46 +443,6 @@ impl YamlFrameWriterReceiver {
|
|||
scene: Scene::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn update_document(&mut self, txn: &TransactionMsg) {
|
||||
self.frame_writer.update_resources(&txn.resource_updates);
|
||||
for doc_msg in &txn.scene_ops {
|
||||
match *doc_msg {
|
||||
SceneMsg::SetDisplayList {
|
||||
ref epoch,
|
||||
ref pipeline_id,
|
||||
ref background,
|
||||
ref viewport_size,
|
||||
ref list_descriptor,
|
||||
..
|
||||
} => {
|
||||
self.frame_writer.begin_write_display_list(
|
||||
&mut self.scene,
|
||||
epoch,
|
||||
pipeline_id,
|
||||
background,
|
||||
viewport_size,
|
||||
list_descriptor,
|
||||
);
|
||||
}
|
||||
SceneMsg::SetRootPipeline(ref pipeline_id) => {
|
||||
self.scene.set_root_pipeline_id(pipeline_id.clone());
|
||||
}
|
||||
SceneMsg::RemovePipeline(ref pipeline_id) => {
|
||||
self.scene.remove_pipeline(pipeline_id);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
for doc_msg in &txn.frame_ops {
|
||||
match *doc_msg {
|
||||
FrameMsg::UpdateDynamicProperties(ref properties) => {
|
||||
self.scene.properties.set_properties(properties);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for YamlFrameWriterReceiver {
|
||||
|
@ -1274,9 +1234,43 @@ impl webrender::ApiRecordingReceiver for YamlFrameWriterReceiver {
|
|||
ApiMsg::UpdateResources(ref updates) => {
|
||||
self.frame_writer.update_resources(updates);
|
||||
}
|
||||
ApiMsg::UpdateDocuments(_, ref txns) => {
|
||||
for txn in txns {
|
||||
self.update_document(txn);
|
||||
ApiMsg::UpdateDocument(_, ref txn) => {
|
||||
self.frame_writer.update_resources(&txn.resource_updates);
|
||||
for doc_msg in &txn.scene_ops {
|
||||
match *doc_msg {
|
||||
SceneMsg::SetDisplayList {
|
||||
ref epoch,
|
||||
ref pipeline_id,
|
||||
ref background,
|
||||
ref viewport_size,
|
||||
ref list_descriptor,
|
||||
..
|
||||
} => {
|
||||
self.frame_writer.begin_write_display_list(
|
||||
&mut self.scene,
|
||||
epoch,
|
||||
pipeline_id,
|
||||
background,
|
||||
viewport_size,
|
||||
list_descriptor,
|
||||
);
|
||||
}
|
||||
SceneMsg::SetRootPipeline(ref pipeline_id) => {
|
||||
self.scene.set_root_pipeline_id(pipeline_id.clone());
|
||||
}
|
||||
SceneMsg::RemovePipeline(ref pipeline_id) => {
|
||||
self.scene.remove_pipeline(pipeline_id);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
for doc_msg in &txn.frame_ops {
|
||||
match *doc_msg {
|
||||
FrameMsg::UpdateDynamicProperties(ref properties) => {
|
||||
self.scene.properties.set_properties(properties);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
|
|
|
@ -949,6 +949,7 @@ pref("gfx.webrender.blob.paint-flashing", false);
|
|||
// WebRender debugging utilities.
|
||||
pref("gfx.webrender.debug.texture-cache", false);
|
||||
pref("gfx.webrender.debug.texture-cache.clear-evicted", true);
|
||||
pref("gfx.webrender.debug.texture-cache.disable-shrink", false);
|
||||
pref("gfx.webrender.debug.render-targets", false);
|
||||
pref("gfx.webrender.debug.gpu-cache", false);
|
||||
pref("gfx.webrender.debug.alpha-primitives", false);
|
||||
|
|
Загрузка…
Ссылка в новой задаче