Bug 1390840 - Add prefs to display the debugging view of webrender's texture cache and intermediate targets. r=jrmuizel
☠☠ backed out by 226958859036 ☠ ☠
authorNicolas Silva <nsilva@mozilla.com>
Mon, 21 Aug 2017 18:22:56 +0200
changeset 425496 b9c53ad8893b177521d194a10140eae14da49297
parent 425495 483991689217644c96f455f192999d9514dfe6c2
child 425497 226958859036e7562eead0fa8e321d238f38e9c8
push id7761
push userjlund@mozilla.com
push dateFri, 15 Sep 2017 00:19:52 +0000
treeherdermozilla-beta@c38455951db4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjrmuizel
bugs1390840
milestone57.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1390840 - Add prefs to display the debugging view of webrender's texture cache and intermediate targets. r=jrmuizel
gfx/config/gfxVars.h
gfx/layers/ipc/CompositorBridgeParent.cpp
gfx/layers/ipc/CompositorBridgeParent.h
gfx/layers/wr/WebRenderBridgeParent.cpp
gfx/layers/wr/WebRenderBridgeParent.h
gfx/thebes/gfxPlatform.cpp
gfx/thebes/gfxPrefs.h
gfx/webrender_bindings/RendererOGL.cpp
gfx/webrender_bindings/RendererOGL.h
gfx/webrender_bindings/WebRenderAPI.cpp
gfx/webrender_bindings/WebRenderAPI.h
gfx/webrender_bindings/WebRenderTypes.h
gfx/webrender_bindings/src/bindings.rs
gfx/webrender_bindings/webrender_ffi_generated.h
modules/libpref/init/all.js
--- a/gfx/config/gfxVars.h
+++ b/gfx/config/gfxVars.h
@@ -31,16 +31,17 @@ class gfxVarReceiver;
   _(OffscreenFormat,            gfxImageFormat,   mozilla::gfx::SurfaceFormat::X8R8G8B8_UINT32) \
   _(RequiresAcceleratedGLContextForCompositorOGL, bool, false)          \
   _(CanUseHardwareVideoDecoding, bool,            false)                \
   _(PDMWMFDisableD3D11Dlls,     nsCString,        nsCString())          \
   _(PDMWMFDisableD3D9Dlls,      nsCString,        nsCString())          \
   _(DXInterop2Blocked,          bool,             false)                \
   _(UseWebRender,               bool,             false)                \
   _(UseWebRenderANGLE,          bool,             false)                \
+  _(WebRenderDebugFlags,        int32_t,          0)                    \
   _(ScreenDepth,                int32_t,          0)                    \
   _(GREDirectory,               nsCString,        nsCString())          \
   _(UseOMTP,                    bool,             false)                \
   _(AllowD3D11KeyedMutex,       bool,             false)                \
 
   /* Add new entries above this line. */
 
 // Some graphics settings are computed on the UI process and must be
--- a/gfx/layers/ipc/CompositorBridgeParent.cpp
+++ b/gfx/layers/ipc/CompositorBridgeParent.cpp
@@ -255,30 +255,24 @@ static StaticAutoPtr<CompositorMap> sCom
 
 void
 CompositorBridgeParent::Setup()
 {
   EnsureLayerTreeMapReady();
 
   MOZ_ASSERT(!sCompositorMap);
   sCompositorMap = new CompositorMap;
-
-  gfxPrefs::SetWebRenderProfilerEnabledChangeCallback(
-    [](const GfxPrefValue& aValue) -> void {
-      CompositorBridgeParent::SetWebRenderProfilerEnabled(aValue.get_bool());
-  });
 }
 
 void
 CompositorBridgeParent::Shutdown()
 {
   MOZ_ASSERT(sCompositorMap);
   MOZ_ASSERT(sCompositorMap->empty());
   sCompositorMap = nullptr;
-  gfxPrefs::SetWebRenderProfilerEnabledChangeCallback(nullptr);
 }
 
 void
 CompositorBridgeParent::FinishShutdown()
 {
   // TODO: this should be empty by now...
   sIndirectLayerTrees.clear();
 }
@@ -1696,18 +1690,17 @@ CompositorBridgeParent::AllocPWebRenderB
   MOZ_ASSERT(wr::AsUint64(aPipelineId) == mRootLayerTreeID);
   MOZ_ASSERT(!mWrBridge);
   MOZ_ASSERT(!mCompositor);
   MOZ_ASSERT(!mCompositorScheduler);
 
 
   MOZ_ASSERT(mWidget);
   RefPtr<widget::CompositorWidget> widget = mWidget;
-  RefPtr<wr::WebRenderAPI> api = wr::WebRenderAPI::Create(
-    gfxPrefs::WebRenderProfilerEnabled(), this, Move(widget), aSize);
+  RefPtr<wr::WebRenderAPI> api = wr::WebRenderAPI::Create(this, Move(widget), aSize);
   if (!api) {
     mWrBridge = WebRenderBridgeParent::CreateDestroyed();
     mWrBridge.get()->AddRef(); // IPDL reference
     *aIdNamespace = mWrBridge->GetIdNamespace();
     *aTextureFactoryIdentifier = TextureFactoryIdentifier(LayersBackend::LAYERS_NONE);
     return mWrBridge;
   }
   mAsyncImageManager = new AsyncImagePipelineManager(api->Clone());
@@ -1755,28 +1748,16 @@ CompositorBridgeParent::GetWebRenderBrid
 
 Maybe<TimeStamp>
 CompositorBridgeParent::GetTestingTimeStamp() const
 {
   return mIsTesting ? Some(mTestTime) : Nothing();
 }
 
 void
-CompositorBridgeParent::SetWebRenderProfilerEnabled(bool aEnabled)
-{
-  MonitorAutoLock lock(*sIndirectLayerTreesLock);
-  for (auto it = sIndirectLayerTrees.begin(); it != sIndirectLayerTrees.end(); it++) {
-    LayerTreeState* state = &it->second;
-    if (state->mWrBridge) {
-      state->mWrBridge->SetWebRenderProfilerEnabled(aEnabled);
-    }
-  }
-}
-
-void
 EraseLayerState(uint64_t aId)
 {
   MonitorAutoLock lock(*sIndirectLayerTreesLock);
 
   auto iter = sIndirectLayerTrees.find(aId);
   if (iter != sIndirectLayerTrees.end()) {
     CompositorBridgeParent* parent = iter->second.mParent;
     if (parent) {
--- a/gfx/layers/ipc/CompositorBridgeParent.h
+++ b/gfx/layers/ipc/CompositorBridgeParent.h
@@ -445,18 +445,16 @@ public:
   PWebRenderBridgeParent* AllocPWebRenderBridgeParent(const wr::PipelineId& aPipelineId,
                                                       const LayoutDeviceIntSize& aSize,
                                                       TextureFactoryIdentifier* aTextureFactoryIdentifier,
                                                       wr::IdNamespace* aIdNamespace) override;
   bool DeallocPWebRenderBridgeParent(PWebRenderBridgeParent* aActor) override;
   RefPtr<WebRenderBridgeParent> GetWebRenderBridgeParent() const;
   Maybe<TimeStamp> GetTestingTimeStamp() const;
 
-  static void SetWebRenderProfilerEnabled(bool aEnabled);
-
   static CompositorBridgeParent* GetCompositorBridgeParentFromLayersId(const uint64_t& aLayersId);
 
 #if defined(MOZ_WIDGET_ANDROID)
   gfx::IntSize GetEGLSurfaceSize() {
     return mEGLSurfaceSize;
   }
 
   uint64_t GetRootLayerTreeId() {
--- a/gfx/layers/wr/WebRenderBridgeParent.cpp
+++ b/gfx/layers/wr/WebRenderBridgeParent.cpp
@@ -1415,25 +1415,16 @@ WebRenderBridgeParent::RecvInitReadLocks
     return IPC_OK();
   }
   if (!AddReadLocks(Move(aReadLocks))) {
     return IPC_FAIL_NO_REASON(this);
   }
   return IPC_OK();
 }
 
-void
-WebRenderBridgeParent::SetWebRenderProfilerEnabled(bool aEnabled)
-{
-  if (mWidget) {
-    // Only set the flag to "root" WebRenderBridgeParent.
-    mApi->SetProfilerEnabled(aEnabled);
-  }
-}
-
 TextureFactoryIdentifier
 WebRenderBridgeParent::GetTextureFactoryIdentifier()
 {
   MOZ_ASSERT(mApi);
 
   return TextureFactoryIdentifier(LayersBackend::LAYERS_WR,
                                   XRE_GetProcessType(),
                                   mApi->GetMaxTextureSize(),
--- a/gfx/layers/wr/WebRenderBridgeParent.h
+++ b/gfx/layers/wr/WebRenderBridgeParent.h
@@ -147,17 +147,16 @@ public:
                                                    const float& aX,
                                                    const float& aY) override;
   mozilla::ipc::IPCResult RecvSetAsyncZoom(const FrameMetrics::ViewID& aScrollId,
                                            const float& aZoom) override;
   mozilla::ipc::IPCResult RecvFlushApzRepaints() override;
   mozilla::ipc::IPCResult RecvGetAPZTestData(APZTestData* data) override;
 
   void ActorDestroy(ActorDestroyReason aWhy) override;
-  void SetWebRenderProfilerEnabled(bool aEnabled);
 
   void Pause();
   bool Resume();
 
   void Destroy();
 
   // CompositorVsyncSchedulerOwner
   bool IsPendingComposite() override { return false; }
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -593,16 +593,37 @@ void RecordingPrefChanged(const char *aP
     gPlatform->mRecorder = Factory::CreateEventRecorderForFile(fileName.BeginReading());
     printf_stderr("Recording to %s\n", fileName.get());
     Factory::SetGlobalEventRecorder(gPlatform->mRecorder);
   } else {
     Factory::SetGlobalEventRecorder(nullptr);
   }
 }
 
+#define WR_DEBUG_PREF "gfx.webrender.debug"
+
+void
+WebRenderDebugPrefChangeCallback(const char* aPrefName, void*)
+{
+  int32_t flags = 0;
+  // TODO: It would be nice to get the bit patterns directly from the rust code.
+  if (Preferences::GetBool(WR_DEBUG_PREF".profiler", false)) {
+    flags |= (1 << 0);
+  }
+  if (Preferences::GetBool(WR_DEBUG_PREF".texture-cache", false)) {
+    flags |= (1 << 1);
+  }
+  if (Preferences::GetBool(WR_DEBUG_PREF".render-targets", false)) {
+    flags |= (1 << 2);
+  }
+
+  gfx::gfxVars::SetWebRenderDebugFlags(flags);
+}
+
+
 #if defined(USE_SKIA)
 static uint32_t GetSkiaGlyphCacheSize()
 {
     // Only increase font cache size on non-android to save memory.
 #if !defined(MOZ_WIDGET_ANDROID)
     // 10mb as the default pref cache size on desktop due to talos perf tweaking.
     // Chromium uses 20mb and skia default uses 2mb.
     // We don't need to change the font cache count since we usually
@@ -1034,16 +1055,18 @@ gfxPlatform::ShutdownLayersIPC()
     } else if (XRE_IsParentProcess()) {
         gfx::VRManagerChild::ShutDown();
         layers::CompositorManagerChild::Shutdown();
         layers::ImageBridgeChild::ShutDown();
         // This has to happen after shutting down the child protocols.
         layers::CompositorThreadHolder::Shutdown();
         if (gfxVars::UseWebRender()) {
           wr::RenderThread::ShutDown();
+
+          Preferences::UnregisterCallback(WebRenderDebugPrefChangeCallback, WR_DEBUG_PREF);
         }
 
     } else {
       // TODO: There are other kind of processes and we should make sure gfx
       // stuff is either not created there or shut down properly.
     }
 }
 
@@ -2491,16 +2514,21 @@ gfxPlatform::InitWebRenderConfig()
     }
   }
 #endif
 
   // gfxFeature is not usable in the GPU process, so we use gfxVars to transmit this feature
   if (gfxConfig::IsEnabled(Feature::WEBRENDER)) {
     gfxVars::SetUseWebRender(true);
     reporter.SetSuccessful();
+
+    if (XRE_IsParentProcess()) {
+      Preferences::RegisterPrefixCallbackAndCall(WebRenderDebugPrefChangeCallback,
+                                                 WR_DEBUG_PREF);
+    }
   }
 }
 
 void
 gfxPlatform::InitOMTPConfig()
 {
   bool prefEnabled = Preferences::GetBool("layers.omtp.enabled", false);
 
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -482,17 +482,16 @@ private:
   DECL_GFX_PREF(Once, "gfx.touch.resample.vsync-adjust",       TouchVsyncSampleAdjust, int32_t, 5);
 
   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(Live, "gfx.webrender.blob-images",             WebRenderBlobImages, bool, false);
   DECL_GFX_PREF(Live, "gfx.webrender.highlight-painted-layers",WebRenderHighlightPaintedLayers, bool, false);
   DECL_GFX_PREF(Live, "gfx.webrender.layers-free",             WebRenderLayersFree, bool, false);
-  DECL_GFX_PREF(Live, "gfx.webrender.profiler.enabled",        WebRenderProfilerEnabled, bool, false);
   DECL_GFX_PREF(Live, "gfx.webrendest.enabled",                WebRendestEnabled, bool, false);
 
   // Use vsync events generated by hardware
   DECL_GFX_PREF(Once, "gfx.work-around-driver-bugs",           WorkAroundDriverBugs, bool, true);
   DECL_GFX_PREF(Once, "gfx.screen-mirroring.enabled",          ScreenMirroringEnabled, bool, false);
 
   DECL_GFX_PREF(Live, "gl.ignore-dx-interop2-blacklist",       IgnoreDXInterop2Blacklist, bool, false);
   DECL_GFX_PREF(Live, "gl.msaa-level",                         MSAALevel, uint32_t, 2);
--- a/gfx/webrender_bindings/RendererOGL.cpp
+++ b/gfx/webrender_bindings/RendererOGL.cpp
@@ -2,16 +2,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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/. */
 
 #include "RendererOGL.h"
 #include "GLContext.h"
 #include "GLContextProvider.h"
 #include "mozilla/gfx/Logging.h"
+#include "mozilla/gfx/gfxVars.h"
 #include "mozilla/layers/CompositorBridgeParent.h"
 #include "mozilla/layers/CompositorThread.h"
 #include "mozilla/layers/LayersTypes.h"
 #include "mozilla/webrender/RenderBufferTextureHost.h"
 #include "mozilla/webrender/RenderTextureHostOGL.h"
 #include "mozilla/widget/CompositorWidget.h"
 
 namespace mozilla {
@@ -60,16 +61,17 @@ RendererOGL::RendererOGL(RefPtr<RenderTh
                          wr::Renderer* aRenderer,
                          layers::CompositorBridgeParentBase* aBridge)
   : mThread(aThread)
   , mGL(aGL)
   , mWidget(aWidget)
   , mRenderer(aRenderer)
   , mBridge(aBridge)
   , mWindowId(aWindowId)
+  , mDebugFlags({ 0 })
 {
   MOZ_ASSERT(mThread);
   MOZ_ASSERT(mGL);
   MOZ_ASSERT(mWidget);
   MOZ_ASSERT(mRenderer);
   MOZ_ASSERT(mBridge);
   MOZ_COUNT_CTOR(RendererOGL);
 
@@ -122,16 +124,23 @@ void
 RendererOGL::Update()
 {
   wr_renderer_update(mRenderer);
 }
 
 bool
 RendererOGL::Render()
 {
+  uint32_t flags = gfx::gfxVars::WebRenderDebugFlags();
+
+  if (mDebugFlags.mBits != flags) {
+    mDebugFlags.mBits = flags;
+    wr_renderer_set_debug_flags(mRenderer, mDebugFlags);
+  }
+
   if (!mGL->MakeCurrent()) {
     gfxCriticalNote << "Failed to make render context current, can't draw.";
     // XXX This could cause oom in webrender since pending_texture_updates is not handled.
     // It needs to be addressed.
     return false;
   }
 
   mozilla::widget::WidgetRenderingContext widgetContext;
@@ -199,22 +208,16 @@ RendererOGL::Resume()
   // RenewSurface internally calls MakeCurrent.
   return mGL->RenewSurface(mWidget);
 #else
   return true;
 #endif
 }
 
 void
-RendererOGL::SetProfilerEnabled(bool aEnabled)
-{
-  wr_renderer_set_profiler_enabled(mRenderer, aEnabled);
-}
-
-void
 RendererOGL::SetFrameStartTime(const TimeStamp& aTime)
 {
   if (mFrameStartTime) {
     // frame start time is already set. This could happen when multiple
     // generate frame requests are merged by webrender.
     return;
   }
   mFrameStartTime = aTime;
--- a/gfx/webrender_bindings/RendererOGL.h
+++ b/gfx/webrender_bindings/RendererOGL.h
@@ -94,14 +94,15 @@ protected:
   RefPtr<RenderThread> mThread;
   RefPtr<gl::GLContext> mGL;
   RefPtr<widget::CompositorWidget> mWidget;
   wr::Renderer* mRenderer;
   layers::CompositorBridgeParentBase* mBridge;
   wr::WindowId mWindowId;
   TimeStamp mFrameStartTime;
   RefPtr<layers::SyncObjectHost> mSyncObject;
+  wr::DebugFlags mDebugFlags;
 };
 
 } // namespace wr
 } // namespace mozilla
 
 #endif
--- a/gfx/webrender_bindings/WebRenderAPI.cpp
+++ b/gfx/webrender_bindings/WebRenderAPI.cpp
@@ -23,26 +23,24 @@ using layers::Stringify;
 class NewRenderer : public RendererEvent
 {
 public:
   NewRenderer(wr::DocumentHandle** aDocHandle, layers::CompositorBridgeParentBase* aBridge,
               uint32_t* aMaxTextureSize,
               bool* aUseANGLE,
               RefPtr<widget::CompositorWidget>&& aWidget,
               layers::SynchronousTask* aTask,
-              bool aEnableProfiler,
               LayoutDeviceIntSize aSize,
               layers::SyncHandle* aHandle)
     : mDocHandle(aDocHandle)
     , mMaxTextureSize(aMaxTextureSize)
     , mUseANGLE(aUseANGLE)
     , mBridge(aBridge)
     , mCompositorWidget(Move(aWidget))
     , mTask(aTask)
-    , mEnableProfiler(aEnableProfiler)
     , mSize(aSize)
     , mSyncHandle(aHandle)
   {
     MOZ_COUNT_CTOR(NewRenderer);
   }
 
   ~NewRenderer()
   {
@@ -69,17 +67,17 @@ public:
       return;
     }
 
     *mUseANGLE = gl->IsANGLE();
 
     wr::Renderer* wrRenderer = nullptr;
     if (!wr_window_new(aWindowId, mSize.width, mSize.height, gl.get(),
                        aRenderThread.ThreadPool().Raw(),
-                       this->mEnableProfiler, mDocHandle, &wrRenderer,
+                       mDocHandle, &wrRenderer,
                        mMaxTextureSize)) {
       // wr_window_new puts a message into gfxCriticalNote if it returns false
       return;
     }
     MOZ_ASSERT(wrRenderer);
 
     RefPtr<RenderThread> thread = &aRenderThread;
     auto renderer = MakeUnique<RendererOGL>(Move(thread),
@@ -137,18 +135,17 @@ public:
 
 private:
   layers::SynchronousTask* mTask;
 };
 
 
 //static
 already_AddRefed<WebRenderAPI>
-WebRenderAPI::Create(bool aEnableProfiler,
-                     layers::CompositorBridgeParentBase* aBridge,
+WebRenderAPI::Create(layers::CompositorBridgeParentBase* aBridge,
                      RefPtr<widget::CompositorWidget>&& aWidget,
                      LayoutDeviceIntSize aSize)
 {
   MOZ_ASSERT(aBridge);
   MOZ_ASSERT(aWidget);
 
   static uint64_t sNextId = 1;
   auto id = NewWindowId(sNextId++);
@@ -158,17 +155,17 @@ WebRenderAPI::Create(bool aEnableProfile
   bool useANGLE = false;
   layers::SyncHandle syncHandle = 0;
 
   // Dispatch a synchronous task because the DocumentHandle object needs to be created
   // on the render thread. If need be we could delay waiting on this task until
   // the next time we need to access the DocumentHandle object.
   layers::SynchronousTask task("Create Renderer");
   auto event = MakeUnique<NewRenderer>(&docHandle, aBridge, &maxTextureSize, &useANGLE,
-                                       Move(aWidget), &task, aEnableProfiler, aSize,
+                                       Move(aWidget), &task, aSize,
                                        &syncHandle);
   RenderThread::Get()->RunEvent(id, Move(event));
 
   task.Wait();
 
   if (!docHandle) {
     return nullptr;
   }
@@ -523,49 +520,16 @@ WebRenderAPI::AddRawFont(wr::FontKey aKe
 }
 
 void
 WebRenderAPI::DeleteFont(wr::FontKey aKey)
 {
   wr_api_delete_font(mDocHandle, aKey);
 }
 
-class EnableProfiler : public RendererEvent
-{
-public:
-  explicit EnableProfiler(bool aEnabled)
-    : mEnabled(aEnabled)
-  {
-    MOZ_COUNT_CTOR(EnableProfiler);
-  }
-
-  ~EnableProfiler()
-  {
-    MOZ_COUNT_DTOR(EnableProfiler);
-  }
-
-  virtual void Run(RenderThread& aRenderThread, WindowId aWindowId) override
-  {
-    auto renderer = aRenderThread.GetRenderer(aWindowId);
-    if (renderer) {
-      renderer->SetProfilerEnabled(mEnabled);
-    }
-  }
-
-private:
-  bool mEnabled;
-};
-
-void
-WebRenderAPI::SetProfilerEnabled(bool aEnabled)
-{
-  auto event = MakeUnique<EnableProfiler>(aEnabled);
-  RunOnRenderThread(Move(event));
-}
-
 class FrameStartTime : public RendererEvent
 {
 public:
   explicit FrameStartTime(const TimeStamp& aTime)
     : mTime(aTime)
   {
     MOZ_COUNT_CTOR(FrameStartTime);
   }
--- a/gfx/webrender_bindings/WebRenderAPI.h
+++ b/gfx/webrender_bindings/WebRenderAPI.h
@@ -49,18 +49,17 @@ struct Line {
 };
 
 class WebRenderAPI
 {
   NS_INLINE_DECL_REFCOUNTING(WebRenderAPI);
 
 public:
   /// This can be called on the compositor thread only.
-  static already_AddRefed<WebRenderAPI> Create(bool aEnableProfiler,
-                                               layers::CompositorBridgeParentBase* aBridge,
+  static already_AddRefed<WebRenderAPI> Create(layers::CompositorBridgeParentBase* aBridge,
                                                RefPtr<widget::CompositorWidget>&& aWidget,
                                                LayoutDeviceIntSize aSize);
 
   already_AddRefed<WebRenderAPI> Clone();
 
   wr::WindowId GetId() const { return mId; }
 
   void UpdateScrollPosition(const wr::WrPipelineId& aPipelineId,
--- a/gfx/webrender_bindings/WebRenderTypes.h
+++ b/gfx/webrender_bindings/WebRenderTypes.h
@@ -24,32 +24,39 @@ namespace mozilla {
 namespace wr {
 
 typedef wr::WrWindowId WindowId;
 typedef wr::WrPipelineId PipelineId;
 typedef wr::WrImageKey ImageKey;
 typedef wr::WrFontKey FontKey;
 typedef wr::WrEpoch Epoch;
 typedef wr::WrExternalImageId ExternalImageId;
+typedef wr::WrDebugFlags DebugFlags;
 
 typedef mozilla::Maybe<mozilla::wr::WrImageMask> MaybeImageMask;
 typedef Maybe<ExternalImageId> MaybeExternalImageId;
 
 inline WindowId NewWindowId(uint64_t aId) {
   WindowId id;
   id.mHandle = aId;
   return id;
 }
 
 inline Epoch NewEpoch(uint32_t aEpoch) {
   Epoch e;
   e.mHandle = aEpoch;
   return e;
 }
 
+inline DebugFlags NewDebugFlags(uint32_t aFlags) {
+  DebugFlags flags;
+  flags.mBits = aFlags;
+  return flags;
+}
+
 inline Maybe<wr::ImageFormat>
 SurfaceFormatToImageFormat(gfx::SurfaceFormat aFormat) {
   switch (aFormat) {
     case gfx::SurfaceFormat::R8G8B8X8:
       // TODO: use RGBA + opaque flag
       return Some(wr::ImageFormat::BGRA8);
     case gfx::SurfaceFormat::B8G8R8X8:
       // TODO: WebRender will have a BGRA + opaque flag for this but does not
--- a/gfx/webrender_bindings/src/bindings.rs
+++ b/gfx/webrender_bindings/src/bindings.rs
@@ -4,17 +4,17 @@ use std::{mem, slice};
 use std::path::PathBuf;
 use std::sync::Arc;
 use std::os::raw::{c_void, c_char, c_float};
 use gleam::gl;
 
 use webrender_api::*;
 use webrender::renderer::{ReadPixelsFormat, Renderer, RendererOptions};
 use webrender::renderer::{ExternalImage, ExternalImageHandler, ExternalImageSource};
-use webrender::renderer::{DebugFlags, PROFILER_DBG};
+use webrender::renderer::DebugFlags;
 use webrender::{ApiRecordingReceiver, BinaryRecorder};
 use thread_profiler::register_thread_with_profiler;
 use moz2d_renderer::Moz2dImageRenderer;
 use app_units::Au;
 use rayon;
 use euclid::SideOffsets2D;
 
 extern crate webrender_api;
@@ -457,22 +457,32 @@ pub unsafe extern "C" fn wr_renderer_rea
     let mut slice = make_slice_mut(dst_buffer, buffer_size);
     renderer.read_pixels_into(DeviceUintRect::new(
                                 DeviceUintPoint::new(0, 0),
                                 DeviceUintSize::new(width, height)),
                               ReadPixelsFormat::Bgra8,
                               &mut slice);
 }
 
+/// cbindgen:field-names=[mBits]
+#[repr(C)]
+pub struct WrDebugFlags {
+    bits: u32,
+}
+
 #[no_mangle]
-pub extern "C" fn wr_renderer_set_profiler_enabled(renderer: &mut Renderer,
-                                                   enabled: bool) {
-    let mut flags = renderer.get_debug_flags();
-    flags.set(PROFILER_DBG, enabled);
-    renderer.set_debug_flags(flags);
+pub extern "C" fn wr_renderer_get_debug_flags(renderer: &mut Renderer) -> WrDebugFlags {
+    WrDebugFlags { bits: renderer.get_debug_flags().bits() }
+}
+
+#[no_mangle]
+pub extern "C" fn wr_renderer_set_debug_flags(renderer: &mut Renderer, flags: WrDebugFlags) {
+    if let Some(dbg_flags) = DebugFlags::from_bits(flags.bits) {
+        renderer.set_debug_flags(dbg_flags);
+    }
 }
 
 #[no_mangle]
 pub extern "C" fn wr_renderer_current_epoch(renderer: &mut Renderer,
                                             pipeline_id: WrPipelineId,
                                             out_epoch: &mut WrEpoch)
                                             -> bool {
     if let Some(epoch) = renderer.current_epoch(pipeline_id) {
@@ -545,17 +555,16 @@ pub unsafe extern "C" fn wr_thread_pool_
 
 // Call MakeCurrent before this.
 #[no_mangle]
 pub extern "C" fn wr_window_new(window_id: WrWindowId,
                                 window_width: u32,
                                 window_height: u32,
                                 gl_context: *mut c_void,
                                 thread_pool: *mut WrThreadPool,
-                                enable_profiler: bool,
                                 out_handle: &mut *mut DocumentHandle,
                                 out_renderer: &mut *mut Renderer,
                                 out_max_texture_size: *mut u32)
                                 -> bool {
     assert!(unsafe { is_in_render_thread() });
 
     let recorder: Option<Box<ApiRecordingReceiver>> = if unsafe { gfx_use_wrench() } {
         let name = format!("wr-record-{}.bin", window_id.0);
@@ -575,22 +584,19 @@ pub extern "C" fn wr_window_new(window_i
     let version = gl.get_string(gl::VERSION);
 
     println!("WebRender - OpenGL version new {}", version);
 
     let workers = unsafe {
         Arc::clone(&(*thread_pool).0)
     };
 
-    let mut debug_flags = DebugFlags::empty();
-    debug_flags.set(PROFILER_DBG, enable_profiler);
     let opts = RendererOptions {
         enable_aa: true,
         enable_subpixel_aa: true,
-        debug_flags: debug_flags,
         recorder: recorder,
         blob_image_renderer: Some(Box::new(Moz2dImageRenderer::new(workers.clone()))),
         workers: Some(workers.clone()),
         enable_render_on_scroll: false,
         ..Default::default()
     };
 
     let (renderer, sender) = match Renderer::new(gl, opts) {
--- a/gfx/webrender_bindings/webrender_ffi_generated.h
+++ b/gfx/webrender_bindings/webrender_ffi_generated.h
@@ -623,16 +623,24 @@ struct WrWindowId {
   bool operator<(const WrWindowId& aOther) const {
     return mHandle < aOther.mHandle;
   }
   bool operator<=(const WrWindowId& aOther) const {
     return mHandle <= aOther.mHandle;
   }
 };
 
+struct WrDebugFlags {
+  uint32_t mBits;
+
+  bool operator==(const WrDebugFlags& aOther) const {
+    return mBits == aOther.mBits;
+  }
+};
+
 struct WrExternalImage {
   WrExternalImageType image_type;
   uint32_t handle;
   float u0;
   float v0;
   float u1;
   float v1;
   const uint8_t *buff;
@@ -1108,37 +1116,41 @@ WR_INLINE
 void wr_renderer_delete(Renderer *aRenderer)
 WR_DESTRUCTOR_SAFE_FUNC;
 
 WR_INLINE
 WrRenderedEpochs *wr_renderer_flush_rendered_epochs(Renderer *aRenderer)
 WR_FUNC;
 
 WR_INLINE
+WrDebugFlags wr_renderer_get_debug_flags(Renderer *aRenderer)
+WR_FUNC;
+
+WR_INLINE
 void wr_renderer_readback(Renderer *aRenderer,
                           uint32_t aWidth,
                           uint32_t aHeight,
                           uint8_t *aDstBuffer,
                           size_t aBufferSize)
 WR_FUNC;
 
 WR_INLINE
 void wr_renderer_render(Renderer *aRenderer,
                         uint32_t aWidth,
                         uint32_t aHeight)
 WR_FUNC;
 
 WR_INLINE
-void wr_renderer_set_external_image_handler(Renderer *aRenderer,
-                                            WrExternalImageHandler *aExternalImageHandler)
+void wr_renderer_set_debug_flags(Renderer *aRenderer,
+                                 WrDebugFlags aFlags)
 WR_FUNC;
 
 WR_INLINE
-void wr_renderer_set_profiler_enabled(Renderer *aRenderer,
-                                      bool aEnabled)
+void wr_renderer_set_external_image_handler(Renderer *aRenderer,
+                                            WrExternalImageHandler *aExternalImageHandler)
 WR_FUNC;
 
 WR_INLINE
 void wr_renderer_update(Renderer *aRenderer)
 WR_FUNC;
 
 WR_INLINE
 void wr_scroll_layer_with_id(DocumentHandle *aDh,
@@ -1169,17 +1181,16 @@ void wr_vec_u8_free(WrVecU8 aV)
 WR_FUNC;
 
 WR_INLINE
 bool wr_window_new(WrWindowId aWindowId,
                    uint32_t aWindowWidth,
                    uint32_t aWindowHeight,
                    void *aGlContext,
                    WrThreadPool *aThreadPool,
-                   bool aEnableProfiler,
                    DocumentHandle **aOutHandle,
                    Renderer **aOutRenderer,
                    uint32_t *aOutMaxTextureSize)
 WR_FUNC;
 
 } // namespace wr
 } // namespace mozilla
 
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -893,19 +893,23 @@ pref("gfx.webrender.enabled", true);
 pref("gfx.webrender.enabled", false);
 #endif
 #ifdef XP_WIN
 pref("gfx.webrender.force-angle", true);
 #endif
 
 pref("gfx.webrender.highlight-painted-layers", false);
 pref("gfx.webrender.layers-free", false);
-pref("gfx.webrender.profiler.enabled", false);
 pref("gfx.webrender.blob-images", false);
 
+// WebRender debugging utilities.
+pref("gfx.webrender.debug.texture-cache", false);
+pref("gfx.webrender.debug.render-targets", false);
+pref("gfx.webrender.debug.profiler", false);
+
 // Whether webrender should be used as much as possible.
 pref("gfx.webrendest.enabled", false);
 
 pref("accessibility.browsewithcaret", false);
 pref("accessibility.warn_on_browsewithcaret", true);
 
 pref("accessibility.browsewithcaret_shortcut.enabled", true);