mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 13:21:05 +00:00
Backed out 3 changesets (bug 1538710) for Wrench bustage. CLOSED TREE
Backed out changeset 9a80bc4d626a (bug 1538710) Backed out changeset f5f916011032 (bug 1538710) Backed out changeset 585b51bba30d (bug 1538710)
This commit is contained in:
parent
d3d11b05a5
commit
d0e6f0880f
@ -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,
|
||||
|
@ -2004,7 +2004,6 @@ void WebRenderBridgeParent::MaybeGenerateFrame(VsyncId aId,
|
||||
#endif
|
||||
|
||||
MOZ_ASSERT(framesGenerated > 0);
|
||||
wr::RenderRootArray<wr::TransactionBuilder*> generateFrameTxns;
|
||||
for (auto& api : mApis) {
|
||||
if (!api) {
|
||||
continue;
|
||||
@ -2012,11 +2011,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();
|
||||
}
|
||||
|
||||
@ -2064,16 +2061,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
|
||||
@ -2204,19 +2198,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(
|
||||
|
@ -568,6 +568,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.
|
||||
|
@ -937,41 +937,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 {
|
||||
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,8 +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();
|
||||
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
|
||||
|
@ -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);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
|
@ -947,6 +947,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);
|
||||
|
Loading…
Reference in New Issue
Block a user