--- a/gfx/layers/wr/WebRenderCommandBuilder.cpp
+++ b/gfx/layers/wr/WebRenderCommandBuilder.cpp
@@ -1185,20 +1185,25 @@ WebRenderCommandBuilder::BuildWebRenderC
wr::LayoutSize& aContentSize,
const nsTArray<wr::WrFilterOp>& aFilters)
{
StackingContextHelper sc;
aScrollData = WebRenderScrollData(mManager);
MOZ_ASSERT(mLayerScrollData.empty());
mLastCanvasDatas.Clear();
mLastAsr = nullptr;
+ mBuilderDumpIndex = 0;
+ MOZ_ASSERT(mDumpIndent == 0);
mClipManager.BeginBuild(mManager, aBuilder);
{
StackingContextHelper pageRootSc(sc, aBuilder, aFilters);
+ if (ShouldDumpDisplayList()) {
+ mBuilderDumpIndex = aBuilder.Dump(mDumpIndent + 1, Some(mBuilderDumpIndex), Nothing());
+ }
CreateWebRenderCommandsFromDisplayList(aDisplayList, nullptr, aDisplayListBuilder,
pageRootSc, aBuilder, aResourceUpdates);
}
// Make a "root" layer data that has everything else as descendants
mLayerScrollData.emplace_back();
mLayerScrollData.back().InitializeRoot(mLayerScrollData.size() - 1);
auto callback = [&aScrollData](FrameMetrics::ViewID aScrollId) -> bool {
@@ -1217,31 +1222,46 @@ WebRenderCommandBuilder::BuildWebRenderC
mLayerScrollData.clear();
mClipManager.EndBuild();
// Remove the user data those are not displayed on the screen and
// also reset the data to unused for next transaction.
RemoveUnusedAndResetWebRenderUserData();
}
+bool
+WebRenderCommandBuilder::ShouldDumpDisplayList()
+{
+ return (XRE_IsParentProcess() && gfxPrefs::WebRenderDLDumpParent()) ||
+ (XRE_IsContentProcess() && gfxPrefs::WebRenderDLDumpContent());
+}
+
void
WebRenderCommandBuilder::CreateWebRenderCommandsFromDisplayList(nsDisplayList* aDisplayList,
nsDisplayItem* aWrappingItem,
nsDisplayListBuilder* aDisplayListBuilder,
const StackingContextHelper& aSc,
wr::DisplayListBuilder& aBuilder,
wr::IpcResourceUpdateQueue& aResources)
{
if (mDoGrouping) {
MOZ_RELEASE_ASSERT(aWrappingItem, "Only the root list should have a null wrapping item, and mDoGrouping should never be true for the root list.");
GP("actually entering the grouping code\n");
DoGroupingForDisplayList(aDisplayList, aWrappingItem, aDisplayListBuilder, aSc, aBuilder, aResources);
return;
}
+ bool dumpEnabled = ShouldDumpDisplayList();
+ if (dumpEnabled) {
+ // If we're inside a nested display list, print the WR DL items from the
+ // wrapper item before we start processing the nested items.
+ mBuilderDumpIndex = aBuilder.Dump(mDumpIndent + 1, Some(mBuilderDumpIndex), Nothing());
+ }
+
+ mDumpIndent++;
mClipManager.BeginList(aSc);
bool apzEnabled = mManager->AsyncPanZoomEnabled();
FlattenedDisplayItemIterator iter(aDisplayListBuilder, aDisplayList);
while (nsDisplayItem* i = iter.GetNext()) {
nsDisplayItem* item = i;
DisplayItemType itemType = item->GetType();
@@ -1304,25 +1324,35 @@ WebRenderCommandBuilder::CreateWebRender
mDoGrouping = true;
GP("attempting to enter the grouping code\n");
}/* else if (itemType == DisplayItemType::TYPE_FOREIGN_OBJECT) {
// We do not want to apply grouping inside <foreignObject>.
// TODO: TYPE_FOREIGN_OBJECT does not exist yet, make it exist
mDoGrouping = false;
}*/
+ if (dumpEnabled) {
+ std::stringstream ss;
+ nsFrame::PrintDisplayItem(aDisplayListBuilder, item, ss, static_cast<uint32_t>(mDumpIndent));
+ printf_stderr("%s", ss.str().c_str());
+ }
+
// Note: this call to CreateWebRenderCommands can recurse back into
// this function if the |item| is a wrapper for a sublist.
item->SetPaintRect(item->GetBuildingRect());
bool createdWRCommands =
item->CreateWebRenderCommands(aBuilder, aResources, aSc, mManager,
aDisplayListBuilder);
if (!createdWRCommands) {
PushItemAsImage(item, aBuilder, aResources, aSc, aDisplayListBuilder);
}
+
+ if (dumpEnabled) {
+ mBuilderDumpIndex = aBuilder.Dump(mDumpIndent + 1, Some(mBuilderDumpIndex), Nothing());
+ }
}
if (apzEnabled) {
if (forceNewLayerData) {
// Pop the thing we pushed before the recursion, so the topmost item on
// the stack is enclosing display item's ASR (or the stack is empty)
mAsrStack.pop_back();
const ActiveScrolledRoot* stopAtAsr =
@@ -1375,16 +1405,17 @@ WebRenderCommandBuilder::CreateWebRender
mLayerScrollData.emplace_back();
mLayerScrollData.back().Initialize(mManager->GetScrollData(), item,
descendants, stopAtAsr, deferred ? Some((*deferred)->GetTransform().GetMatrix()) : Nothing());
}
}
}
}
+ mDumpIndent--;
mClipManager.EndList(aSc);
}
void
WebRenderCommandBuilder::PushOverrideForASR(const ActiveScrolledRoot* aASR,
const Maybe<wr::WrClipId>& aClipId)
{
mClipManager.PushOverrideForASR(aASR, aClipId);
--- a/gfx/layers/wr/WebRenderCommandBuilder.h
+++ b/gfx/layers/wr/WebRenderCommandBuilder.h
@@ -33,16 +33,18 @@ class WebRenderUserData;
class WebRenderCommandBuilder {
typedef nsTHashtable<nsRefPtrHashKey<WebRenderUserData>> WebRenderUserDataRefTable;
typedef nsTHashtable<nsRefPtrHashKey<WebRenderCanvasData>> CanvasDataSet;
public:
explicit WebRenderCommandBuilder(WebRenderLayerManager* aManager)
: mManager(aManager)
, mLastAsr(nullptr)
+ , mBuilderDumpIndex(0)
+ , mDumpIndent(0)
, mDoGrouping(false)
{}
void Destroy();
void EmptyTransaction();
bool NeedsEmptyTransaction();
@@ -109,16 +111,19 @@ public:
wr::IpcResourceUpdateQueue& aResources,
const StackingContextHelper& aSc,
nsDisplayListBuilder* aDisplayListBuilder,
LayoutDeviceRect& aImageRect);
void RemoveUnusedAndResetWebRenderUserData();
void ClearCachedResources();
+ bool ShouldDumpDisplayList();
+ wr::usize GetBuilderDumpIndex() { return mBuilderDumpIndex; }
+
// Those are data that we kept between transactions. We used to cache some
// data in the layer. But in layers free mode, we don't have layer which
// means we need some other place to cached the data between transaction.
// We store the data in frame's property.
template<class T> already_AddRefed<T>
CreateOrRecycleWebRenderUserData(nsDisplayItem* aItem,
bool* aOutIsRecycled = nullptr)
{
@@ -177,16 +182,18 @@ private:
std::vector<const ActiveScrolledRoot*> mAsrStack;
const ActiveScrolledRoot* mLastAsr;
WebRenderUserDataRefTable mWebRenderUserDatas;
// Store of WebRenderCanvasData objects for use in empty transactions
CanvasDataSet mLastCanvasDatas;
+ wr::usize mBuilderDumpIndex;
+ wr::usize mDumpIndent;
// Whether consecutive inactive display items should be grouped into one
// blob image.
bool mDoGrouping;
};
} // namespace layers
} // namespace mozilla
--- a/gfx/layers/wr/WebRenderLayerManager.cpp
+++ b/gfx/layers/wr/WebRenderLayerManager.cpp
@@ -21,20 +21,16 @@
#include "mozilla/layers/UpdateImageHelper.h"
#include "nsDisplayList.h"
#include "WebRenderCanvasRenderer.h"
#ifdef XP_WIN
#include "gfxDWriteFonts.h"
#endif
-// Useful for debugging, it dumps the Gecko display list *before* we try to
-// build WR commands from it, and dumps the WR display list after building it.
-#define DUMP_LISTS 0
-
namespace mozilla {
using namespace gfx;
namespace layers {
WebRenderLayerManager::WebRenderLayerManager(nsIWidget* aWidget)
: mWidget(aWidget)
@@ -244,63 +240,68 @@ WebRenderLayerManager::EndTransaction(Dr
void
WebRenderLayerManager::EndTransactionWithoutLayer(nsDisplayList* aDisplayList,
nsDisplayListBuilder* aDisplayListBuilder,
const nsTArray<wr::WrFilterOp>& aFilters,
WebRenderBackgroundData* aBackground)
{
AUTO_PROFILER_TRACING("Paint", "RenderLayers");
-#if DUMP_LISTS
- // Useful for debugging, it dumps the display list *before* we try to build
- // WR commands from it
- if (XRE_IsContentProcess() && aDisplayList) nsFrame::PrintDisplayList(aDisplayListBuilder, *aDisplayList);
-#endif
-
#ifdef XP_WIN
gfxDWriteFont::UpdateClearTypeUsage();
#endif
// Since we don't do repeat transactions right now, just set the time
mAnimationReadyTime = TimeStamp::Now();
WrBridge()->BeginTransaction();
LayoutDeviceIntSize size = mWidget->GetClientSize();
wr::LayoutSize contentSize { (float)size.width, (float)size.height };
wr::DisplayListBuilder builder(WrBridge()->GetPipeline(), contentSize, mLastDisplayListSize);
wr::IpcResourceUpdateQueue resourceUpdates(WrBridge());
+ wr::usize builderDumpIndex = 0;
+ bool dumpEnabled = mWebRenderCommandBuilder.ShouldDumpDisplayList();
+ if (dumpEnabled) {
+ printf_stderr("-- WebRender display list build --\n");
+ }
if (aDisplayList) {
MOZ_ASSERT(aDisplayListBuilder && !aBackground);
// Record the time spent "layerizing". WR doesn't actually layerize but
// generating the WR display list is the closest equivalent
PaintTelemetry::AutoRecord record(PaintTelemetry::Metric::Layerization);
mWebRenderCommandBuilder.BuildWebRenderCommands(builder,
resourceUpdates,
aDisplayList,
aDisplayListBuilder,
mScrollData,
contentSize,
aFilters);
+ builderDumpIndex = mWebRenderCommandBuilder.GetBuilderDumpIndex();
} else {
// ViewToPaint does not have frame yet, then render only background clolor.
MOZ_ASSERT(!aDisplayListBuilder && aBackground);
aBackground->AddWebRenderCommands(builder);
+ if (dumpEnabled) {
+ printf_stderr("(no display list; background only)\n");
+ builderDumpIndex = builder.Dump(/*indent*/ 1, Some(builderDumpIndex), Nothing());
+ }
}
DiscardCompositorAnimations();
mWidget->AddWindowOverlayWebRenderCommands(WrBridge(), builder, resourceUpdates);
mWindowOverlayChanged = false;
+ if (dumpEnabled) {
+ printf_stderr("(window overlay)\n");
+ Unused << builder.Dump(/*indent*/ 1, Some(builderDumpIndex), Nothing());
+ }
-#if DUMP_LISTS
- if (XRE_IsContentProcess()) mScrollData.Dump();
-#endif
if (AsyncPanZoomEnabled()) {
mScrollData.SetFocusTarget(mFocusTarget);
mFocusTarget = FocusTarget();
if (mIsFirstPaint) {
mScrollData.SetIsFirstPaint();
mIsFirstPaint = false;
}
@@ -325,20 +326,16 @@ WebRenderLayerManager::EndTransactionWit
// device-reset status.
if (!gfxPlatform::GetPlatform()->DidRenderingDeviceReset()) {
if (WrBridge()->GetSyncObject() &&
WrBridge()->GetSyncObject()->IsSyncObjectValid()) {
WrBridge()->GetSyncObject()->Synchronize();
}
}
-#if DUMP_LISTS
- if (XRE_IsContentProcess()) builder.Dump();
-#endif
-
wr::BuiltDisplayList dl;
builder.Finalize(contentSize, dl);
mLastDisplayListSize = dl.dl.inner.capacity;
{
AUTO_PROFILER_TRACING("Paint", "ForwardDPTransaction");
WrBridge()->EndTransaction(contentSize, dl, resourceUpdates, size.ToUnknownSize(),
mLatestTransactionId, mScrollData, refreshStart, mTransactionStart);
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -515,16 +515,18 @@ private:
DECL_GFX_PREF(Live, "gfx.vsync.collect-scroll-transforms", CollectScrollTransforms, bool, false);
DECL_GFX_PREF(Once, "gfx.vsync.compositor.unobserve-count", CompositorUnobserveCount, int32_t, 10);
DECL_GFX_PREF(Once, "gfx.webrender.all", WebRenderAll, bool, false);
DECL_GFX_PREF(Once, "gfx.webrender.all.qualified", WebRenderAllQualified, bool, false);
DECL_GFX_PREF(Live, "gfx.webrender.blob-images", WebRenderBlobImages, bool, true);
DECL_GFX_PREF(Live, "gfx.webrender.blob.invalidation", WebRenderBlobInvalidation, bool, false);
+ DECL_GFX_PREF(Live, "gfx.webrender.dl.dump-parent", WebRenderDLDumpParent, bool, false);
+ DECL_GFX_PREF(Live, "gfx.webrender.dl.dump-content", WebRenderDLDumpContent, bool, false);
DECL_GFX_PREF(Once, "gfx.webrender.enabled", WebRenderEnabledDoNotUseDirectly, bool, false);
DECL_GFX_PREF(Once, "gfx.webrender.force-disabled", WebRenderForceDisabled, bool, false);
DECL_GFX_PREF(Live, "gfx.webrender.highlight-painted-layers",WebRenderHighlightPaintedLayers, bool, false);
// Use vsync events generated by hardware
DECL_GFX_PREF(Once, "gfx.work-around-driver-bugs", WorkAroundDriverBugs, bool, true);
DECL_GFX_PREF(Live, "gl.ignore-dx-interop2-blacklist", IgnoreDXInterop2Blacklist, bool, false);
--- a/gfx/webrender_bindings/WebRenderAPI.cpp
+++ b/gfx/webrender_bindings/WebRenderAPI.cpp
@@ -751,17 +751,23 @@ DisplayListBuilder::~DisplayListBuilder(
{
MOZ_COUNT_DTOR(DisplayListBuilder);
wr_state_delete(mWrState);
}
void DisplayListBuilder::Save() { wr_dp_save(mWrState); }
void DisplayListBuilder::Restore() { wr_dp_restore(mWrState); }
void DisplayListBuilder::ClearSave() { wr_dp_clear_save(mWrState); }
-void DisplayListBuilder::Dump() { wr_dump_display_list(mWrState); }
+
+usize DisplayListBuilder::Dump(usize aIndent,
+ const Maybe<usize>& aStart,
+ const Maybe<usize>& aEnd)
+{
+ return wr_dump_display_list(mWrState, aIndent, aStart.ptrOr(nullptr), aEnd.ptrOr(nullptr));
+}
void
DisplayListBuilder::Finalize(wr::LayoutSize& aOutContentSize,
BuiltDisplayList& aOutDisplayList)
{
wr_api_finalize_builder(mWrState,
&aOutContentSize,
&aOutDisplayList.dl_desc,
--- a/gfx/webrender_bindings/WebRenderAPI.h
+++ b/gfx/webrender_bindings/WebRenderAPI.h
@@ -277,17 +277,17 @@ public:
size_t aCapacity = 0);
DisplayListBuilder(DisplayListBuilder&&) = default;
~DisplayListBuilder();
void Save();
void Restore();
void ClearSave();
- void Dump();
+ usize Dump(usize aIndent, const Maybe<usize>& aStart, const Maybe<usize>& aEnd);
void Finalize(wr::LayoutSize& aOutContentSize,
wr::BuiltDisplayList& aOutDisplayList);
Maybe<wr::WrClipId> PushStackingContext(
const wr::LayoutRect& aBounds, // TODO: We should work with strongly typed rects
const wr::WrClipId* aClipNodeId,
const wr::WrAnimationProperty* aAnimation,
--- a/gfx/webrender_bindings/WebRenderTypes.h
+++ b/gfx/webrender_bindings/WebRenderTypes.h
@@ -24,16 +24,21 @@
namespace mozilla {
namespace ipc {
class ByteBuf;
} // namespace ipc
namespace wr {
+// Using uintptr_t in C++ code for "size" types seems weird, so let's use a
+// better-sounding typedef. The name comes from the fact that we generally
+// have to deal with uintptr_t because that's what rust's usize maps to.
+typedef uintptr_t usize;
+
typedef wr::WrWindowId WindowId;
typedef wr::WrPipelineId PipelineId;
typedef wr::WrImageKey ImageKey;
typedef wr::WrFontKey FontKey;
typedef wr::WrFontInstanceKey FontInstanceKey;
typedef wr::WrEpoch Epoch;
typedef wr::WrExternalImageId ExternalImageId;
typedef wr::WrDebugFlags DebugFlags;
--- a/gfx/webrender_bindings/src/bindings.rs
+++ b/gfx/webrender_bindings/src/bindings.rs
@@ -2349,20 +2349,25 @@ pub extern "C" fn wr_dp_push_box_shadow(
color,
blur_radius,
spread_radius,
border_radius,
clip_mode);
}
#[no_mangle]
-pub extern "C" fn wr_dump_display_list(state: &mut WrState) {
+pub extern "C" fn wr_dump_display_list(state: &mut WrState,
+ indent: usize,
+ start: *const usize,
+ end: *const usize) -> usize {
+ let start = unsafe { start.as_ref().cloned() };
+ let end = unsafe { end.as_ref().cloned() };
state.frame_builder
.dl_builder
- .print_display_list(0, None, None);
+ .print_display_list(indent, start, end)
}
#[no_mangle]
pub unsafe extern "C" fn wr_api_finalize_builder(state: &mut WrState,
content_size: &mut LayoutSize,
dl_descriptor: &mut BuiltDisplayListDescriptor,
dl_data: &mut WrVecU8) {
let frame_builder = mem::replace(&mut state.frame_builder,
--- a/gfx/webrender_bindings/webrender_ffi_generated.h
+++ b/gfx/webrender_bindings/webrender_ffi_generated.h
@@ -1415,17 +1415,20 @@ WR_INLINE
void wr_dp_restore(WrState *aState)
WR_FUNC;
WR_INLINE
void wr_dp_save(WrState *aState)
WR_FUNC;
WR_INLINE
-void wr_dump_display_list(WrState *aState)
+uintptr_t wr_dump_display_list(WrState *aState,
+ uintptr_t aIndent,
+ const uintptr_t *aStart,
+ const uintptr_t *aEnd)
WR_FUNC;
extern bool wr_moz2d_render_cb(ByteSlice aBlob,
uint32_t aWidth,
uint32_t aHeight,
ImageFormat aFormat,
const uint16_t *aTileSize,
const TileOffset *aTileOffset,
--- a/layout/base/nsLayoutDebugger.cpp
+++ b/layout/base/nsLayoutDebugger.cpp
@@ -255,16 +255,27 @@ void
nsFrame::PrintDisplayList(nsDisplayListBuilder* aBuilder,
const nsDisplayList& aList,
std::stringstream& aStream,
bool aDumpHtml)
{
PrintDisplayListTo(aBuilder, aList, aStream, 0, aDumpHtml);
}
+void
+nsFrame::PrintDisplayItem(nsDisplayListBuilder* aBuilder,
+ nsDisplayItem* aItem,
+ std::stringstream& aStream,
+ uint32_t aIndent,
+ bool aDumpSublist,
+ bool aDumpHtml)
+{
+ PrintDisplayItemTo(aBuilder, aItem, aStream, aIndent, aDumpSublist, aDumpHtml);
+}
+
/**
* The two functions below are intended to be called from a debugger.
*/
void
PrintDisplayItemToStdout(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem)
{
std::stringstream stream;
PrintDisplayItemTo(aBuilder, aItem, stream, 0, true, false);
--- a/layout/generic/nsFrame.h
+++ b/layout/generic/nsFrame.h
@@ -746,16 +746,22 @@ public:
std::stringstream ss;
PrintDisplayList(aBuilder, aList, ss, aDumpHtml);
fprintf_stderr(stderr, "%s", ss.str().c_str());
}
static void PrintDisplayList(nsDisplayListBuilder* aBuilder,
const nsDisplayList& aList,
std::stringstream& aStream,
bool aDumpHtml = false);
+ static void PrintDisplayItem(nsDisplayListBuilder* aBuilder,
+ nsDisplayItem* aItem,
+ std::stringstream& aStream,
+ uint32_t aIndent = 0,
+ bool aDumpSublist = false,
+ bool aDumpHtml = false);
static void PrintDisplayListSet(nsDisplayListBuilder* aBuilder,
const nsDisplayListSet& aList,
std::stringstream& aStream,
bool aDumpHtml = false);
};
// Start Display Reflow Debugging
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -884,16 +884,18 @@ pref("gfx.webrender.debug.profiler", fal
pref("gfx.webrender.debug.gpu-time-queries", false);
pref("gfx.webrender.debug.gpu-sample-queries", false);
pref("gfx.webrender.debug.disable-batching", false);
pref("gfx.webrender.debug.epochs", false);
pref("gfx.webrender.debug.compact-profiler", false);
pref("gfx.webrender.debug.echo-driver-messages", false);
pref("gfx.webrender.debug.new-frame-indicator", false);
pref("gfx.webrender.debug.new-scene-indicator", false);
+pref("gfx.webrender.dl.dump-parent", false);
+pref("gfx.webrender.dl.dump-content", false);
pref("accessibility.browsewithcaret", false);
pref("accessibility.warn_on_browsewithcaret", true);
pref("accessibility.browsewithcaret_shortcut.enabled", true);
#ifndef XP_MACOSX
// Tab focus model bit field: