Bug 1133007 - Send the content of a texture only if its was altered since previous transmission. r=kamidphish, r=boris
authorCJKu <cku@mozilla.com>
Tue, 02 Jun 2015 06:21:00 -0400
changeset 269380 f86c710c4074ea4700404c6d050c3d544e5c4655
parent 269379 1b20b43558e980a21b4d244e577b706ee74f6195
child 269381 b9efa70a359a85bbf673ba4d52e15315fe19c1df
push id2501
push userjosea.olivera@gmail.com
push dateWed, 03 Jun 2015 06:55:32 +0000
reviewerskamidphish, boris
bugs1133007
milestone41.0a1
Bug 1133007 - Send the content of a texture only if its was altered since previous transmission. r=kamidphish, r=boris
gfx/layers/LayerScope.cpp
gfx/layers/LayerScope.h
gfx/layers/TextureDIB.cpp
gfx/layers/TextureDIB.h
gfx/layers/composite/TextureHost.cpp
gfx/layers/composite/TextureHost.h
gfx/layers/d3d9/TextureD3D9.cpp
gfx/layers/d3d9/TextureD3D9.h
gfx/layers/opengl/GrallocTextureHost.h
--- a/gfx/layers/LayerScope.cpp
+++ b/gfx/layers/LayerScope.cpp
@@ -173,47 +173,151 @@ public:
     void DispatchDebugData();
 private:
     nsTArray<nsRefPtr<LayerScopeWebSocketHandler> > mHandlers;
     nsCOMPtr<nsIThread> mDebugSenderThread;
     nsRefPtr<DebugDataSender> mCurrentSender;
     nsCOMPtr<nsIServerSocket> mServerSocket;
 };
 
-// Static class to create and destory LayerScopeWebSocketManager object
-class WebSocketHelper
-{
+class DrawSession {
 public:
-    static void CreateServerSocket()
-    {
-        // Create Web Server Socket (which has to be on the main thread)
-        MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
-        if (!sWebSocketManager) {
-            sWebSocketManager = new LayerScopeWebSocketManager();
+    DrawSession()
+      : mOffsetX(0.0)
+      , mOffsetY(0.0)
+      , mRects(0)
+    { }
+
+    float mOffsetX;
+    float mOffsetY;
+    gfx::Matrix4x4 mMVMatrix;
+    size_t mRects;
+    gfx::Rect mLayerRects[4];
+};
+
+class ContentMonitor {
+public:
+    using THArray = nsTArray<const TextureHost *>;
+
+    // Notify the content of a TextureHost was changed.
+    void SetChangedHost(const TextureHost* host) {
+        if (THArray::NoIndex == mChangedHosts.IndexOf(host)) {
+            mChangedHosts.AppendElement(host);
+        }
+    }
+
+    // Clear changed flag of a host.
+    void ClearChangedHost(const TextureHost* host) {
+        if (THArray::NoIndex != mChangedHosts.IndexOf(host)) {
+          mChangedHosts.RemoveElement(host);
         }
     }
 
-    static void DestroyServerSocket()
+    // Return true iff host is a new one or the content of it had been changed.
+    bool IsChangedOrNew(const TextureHost* host) {
+        if (THArray::NoIndex == mSeenHosts.IndexOf(host)) {
+            mSeenHosts.AppendElement(host);
+            return true;
+        }
+
+        if (decltype(mChangedHosts)::NoIndex != mChangedHosts.IndexOf(host)) {
+            return true;
+        }
+
+        return false;
+    }
+
+    void Empty() {
+        mSeenHosts.SetLength(0);
+        mChangedHosts.SetLength(0);
+    }
+private:
+    THArray mSeenHosts;
+    THArray mChangedHosts;
+};
+
+// Hold all singleton objects used by LayerScope
+class LayerScopeManager
+{
+public:
+    void CreateServerSocket()
     {
-        // Destroy Web Server Socket
-        if (sWebSocketManager) {
-            sWebSocketManager->RemoveAllConnections();
+        //  WebSocketManager must be created on the main thread.
+        if (NS_IsMainThread()) {
+            mWebSocketManager = mozilla::MakeUnique<LayerScopeWebSocketManager>();
+        } else {
+            // Dispatch creation to main thread, and make sure we
+            // dispatch this only once after booting
+            static bool dispatched = false;
+            if (dispatched) {
+                return;
+            }
+
+            DebugOnly<nsresult> rv =
+              NS_DispatchToMainThread(new CreateServerSocketRunnable(this));
+            MOZ_ASSERT(NS_SUCCEEDED(rv),
+                  "Failed to dispatch WebSocket Creation to main thread");
+            dispatched = true;
         }
     }
 
-    static LayerScopeWebSocketManager* GetSocketManager()
+    void DestroyServerSocket()
+    {
+        // Destroy Web Server Socket
+        if (mWebSocketManager) {
+            mWebSocketManager->RemoveAllConnections();
+        }
+    }
+
+    LayerScopeWebSocketManager* GetSocketManager()
     {
-        return sWebSocketManager;
+        return mWebSocketManager.get();
+    }
+
+    ContentMonitor* GetContentMonitor()
+    {
+        if (!mContentMonitor.get()) {
+            mContentMonitor = mozilla::MakeUnique<ContentMonitor>();
+        }
+
+        return mContentMonitor.get();
+    }
+
+    void NewDrawSession() {
+        mSession = mozilla::MakeUnique<DrawSession>();
+    }
+
+    DrawSession& CurrentSession() {
+        return *mSession;
     }
 
 private:
-    static StaticAutoPtr<LayerScopeWebSocketManager> sWebSocketManager;
+    friend class CreateServerSocketRunnable;
+    class CreateServerSocketRunnable : public nsRunnable
+    {
+    public:
+        CreateServerSocketRunnable(LayerScopeManager *aLayerScopeManager)
+            : mLayerScopeManager(aLayerScopeManager)
+        {
+        }
+        NS_IMETHOD Run() {
+            mLayerScopeManager->mWebSocketManager =
+                mozilla::MakeUnique<LayerScopeWebSocketManager>();
+            return NS_OK;
+        }
+    private:
+        LayerScopeManager* mLayerScopeManager;
+    };
+
+    mozilla::UniquePtr<LayerScopeWebSocketManager> mWebSocketManager;
+    mozilla::UniquePtr<DrawSession> mSession;
+    mozilla::UniquePtr<ContentMonitor> mContentMonitor;
 };
 
-StaticAutoPtr<LayerScopeWebSocketManager> WebSocketHelper::sWebSocketManager;
+LayerScopeManager gLayerScopeManager;
 
 /*
  * DebugGLData is the base class of
  * 1. DebugGLFrameStatusData (Frame start/end packet)
  * 2. DebugGLColorData (Color data packet)
  * 3. DebugGLTextureData (Texture data packet)
  * 4. DebugGLLayersData (Layers Tree data packet)
  * 5. DebugGLMetaData (Meta data packet)
@@ -225,23 +329,23 @@ public:
     { }
 
     virtual ~DebugGLData() { }
 
     virtual bool Write() = 0;
 
 protected:
     static bool WriteToStream(Packet& aPacket) {
-        if (!WebSocketHelper::GetSocketManager())
+        if (!gLayerScopeManager.GetSocketManager())
             return true;
 
         uint32_t size = aPacket.ByteSize();
         auto data = MakeUnique<uint8_t[]>(size);
         aPacket.SerializeToArray(data.get(), size);
-        return WebSocketHelper::GetSocketManager()->WriteAll(data.get(), size);
+        return gLayerScopeManager.GetSocketManager()->WriteAll(data.get(), size);
     }
 
     Packet::DataType mDataType;
 };
 
 class DebugGLFrameStatusData final: public DebugGLData
 {
 public:
@@ -285,66 +389,74 @@ public:
           mState(aState)
     {
     }
 
     virtual bool Write() override {
         return WriteToStream(mPacket);
     }
 
-    bool TryPack() {
+    bool TryPack(bool packData) {
         android::sp<android::GraphicBuffer> buffer = mState.mSurface;
         MOZ_ASSERT(buffer.get());
 
         mPacket.set_type(mDataType);
         TexturePacket* tp = mPacket.mutable_texture();
         tp->set_layerref(mLayerRef);
         tp->set_name(mName);
         tp->set_target(mTarget);
 
-        int format = buffer->getPixelFormat();
-        if (HAL_PIXEL_FORMAT_RGBA_8888 != format &&
-            HAL_PIXEL_FORMAT_RGBX_8888 != format) {
-            return false;
-        }
-
-        uint8_t* grallocData;
-        if (BAD_VALUE == buffer->lock(GRALLOC_USAGE_SW_READ_OFTEN |
-                                       GRALLOC_USAGE_SW_WRITE_NEVER,
-                                       reinterpret_cast<void**>(&grallocData))) {
+        int pFormat = buffer->getPixelFormat();
+        if (HAL_PIXEL_FORMAT_RGBA_8888 != pFormat &&
+            HAL_PIXEL_FORMAT_RGBX_8888 != pFormat) {
             return false;
         }
 
         int32_t stride = buffer->getStride() * 4;
         int32_t height = buffer->getHeight();
         int32_t width = buffer->getWidth();
         int32_t sourceSize = stride * height;
-        bool    ret = false;
+        if (sourceSize <= 0) {
+            return false;
+        }
+
+        uint32_t dFormat = mState.FormatRBSwapped() ?
+                           LOCAL_GL_BGRA : LOCAL_GL_RGBA;
+        tp->set_dataformat(dFormat);
+        tp->set_dataformat((1 << 16 | tp->dataformat()));
+        tp->set_width(width);
+        tp->set_height(height);
+        tp->set_stride(stride);
 
-        if (sourceSize > 0) {
-            auto compressedData = MakeUnique<char[]>(LZ4::maxCompressedSize(sourceSize));
+        if (packData) {
+            uint8_t* grallocData = nullptr;
+            if (BAD_VALUE == buffer->lock(GRALLOC_USAGE_SW_READ_OFTEN |
+                                           GRALLOC_USAGE_SW_WRITE_NEVER,
+                                           reinterpret_cast<void**>(&grallocData)))
+            {
+                return false;
+            }
+            // Do not return before buffer->unlock();
+            auto compressedData =
+                 MakeUnique<char[]>(LZ4::maxCompressedSize(sourceSize));
             int compressedSize = LZ4::compress((char*)grallocData,
                                                sourceSize,
                                                compressedData.get());
 
             if (compressedSize > 0) {
-                uint32_t format = mState.FormatRBSwapped() ?
-                  LOCAL_GL_BGRA : LOCAL_GL_RGBA;
-                tp->set_dataformat(format);
-                tp->set_dataformat((1 << 16 | tp->dataformat()));
-                tp->set_width(width);
-                tp->set_height(height);
-                tp->set_stride(stride);
                 tp->set_data(compressedData.get(), compressedSize);
-                ret = true;
-            }
+            } else {
+                buffer->unlock();
+                return false;
+             }
+
+            buffer->unlock();
         }
 
-        buffer->unlock();
-        return ret;
+        return true;
     }
 
 private:
     uint64_t mLayerRef;
     GLenum mTarget;
     GLuint mName;
     const LayerRenderState &mState;
     Packet mPacket;
@@ -571,21 +683,22 @@ public:
 
     DebugListener() { }
 
     /* nsIServerSocketListener */
 
     NS_IMETHODIMP OnSocketAccepted(nsIServerSocket *aServ,
                                    nsISocketTransport *aTransport) override
     {
-        if (!WebSocketHelper::GetSocketManager())
+        if (!gLayerScopeManager.GetSocketManager())
             return NS_OK;
 
         printf_stderr("*** LayerScope: Accepted connection\n");
-        WebSocketHelper::GetSocketManager()->AddConnection(aTransport);
+        gLayerScopeManager.GetSocketManager()->AddConnection(aTransport);
+        gLayerScopeManager.GetContentMonitor()->Empty();
         return NS_OK;
     }
 
     NS_IMETHODIMP OnStopListening(nsIServerSocket *aServ,
                                   nsresult aStatus) override
     {
         return NS_OK;
     }
@@ -614,55 +727,44 @@ public:
         if (mList.isEmpty())
             return;
 
         DebugGLData *d;
         while ((d = mList.popFirst()) != nullptr)
             delete d;
     }
 
-    /* nsIRunnable impl; send the data */
-
     NS_IMETHODIMP Run() override {
         DebugGLData *d;
         nsresult rv = NS_OK;
 
         while ((d = mList.popFirst()) != nullptr) {
             UniquePtr<DebugGLData> cleaner(d);
             if (!d->Write()) {
                 rv = NS_ERROR_FAILURE;
                 break;
             }
         }
 
         Cleanup();
 
         if (NS_FAILED(rv)) {
-            WebSocketHelper::DestroyServerSocket();
+            gLayerScopeManager.DestroyServerSocket();
         }
 
         return NS_OK;
     }
 
 protected:
     LinkedList<DebugGLData> mList;
 };
 
 NS_IMPL_ISUPPORTS(DebugDataSender, nsIRunnable);
 
 
-class CreateServerSocketRunnable : public nsRunnable
-{
-public:
-    NS_IMETHOD Run() {
-        WebSocketHelper::CreateServerSocket();
-        return NS_OK;
-    }
-};
-
 /*
  * LayerScope SendXXX Structure
  * 1. SendLayer
  * 2. SendEffectChain
  *   1. SendTexturedEffect
  *      -> SendTextureSource
  *   2. SendYCbCrEffect
  *      -> SendTextureSource
@@ -794,17 +896,17 @@ SenderHelper::SendLayer(LayerComposite* 
 }
 
 void
 SenderHelper::SendColor(void* aLayerRef,
                         const gfxRGBA& aColor,
                         int aWidth,
                         int aHeight)
 {
-    WebSocketHelper::GetSocketManager()->AppendDebugData(
+    gLayerScopeManager.GetSocketManager()->AppendDebugData(
         new DebugGLColorData(aLayerRef, aColor, aWidth, aHeight));
 }
 
 GLuint
 SenderHelper::GetTextureID(GLContext* aGLContext,
                            TextureSourceOGL* aSource) {
     GLenum textureTarget = aSource->GetTextureTarget();
     aSource->BindTexture(LOCAL_GL_TEXTURE0, gfx::Filter::LINEAR);
@@ -843,17 +945,17 @@ SenderHelper::SendTextureSource(GLContex
     gfx::IntSize size = aSource->GetSize();
 
     // By sending 0 to ReadTextureImage rely upon aSource->BindTexture binding
     // texture correctly. texID is used for tracking in DebugGLTextureData.
     RefPtr<DataSourceSurface> img =
         aGLContext->ReadTexImageHelper()->ReadTexImage(0, textureTarget,
                                                          size,
                                                          shaderConfig, aFlipY);
-    WebSocketHelper::GetSocketManager()->AppendDebugData(
+    gLayerScopeManager.GetSocketManager()->AppendDebugData(
         new DebugGLTextureData(aGLContext, aLayerRef, textureTarget,
                                aTexID, img));
 
     sTextureIdList.push_back(aTexID);
 }
 
 #ifdef MOZ_WIDGET_GONK
 bool
@@ -864,23 +966,29 @@ SenderHelper::SendGraphicBuffer(void* aL
     if (!aEffect->mState.mSurface.get()) {
         return false;
     }
 
     GLenum target = aSource->GetTextureTarget();
     mozilla::UniquePtr<DebugGLGraphicBuffer> package =
         MakeUnique<DebugGLGraphicBuffer>(aLayerRef, target, aTexID, aEffect->mState);
 
-    if (!package->TryPack()) {
+    // The texure content in this TexureHost is not altered,
+    // we don't need to send it again.
+    bool changed = gLayerScopeManager.GetContentMonitor()->IsChangedOrNew(
+        aEffect->mState.mTexture);
+    if (!package->TryPack(changed)) {
         return false;
     }
 
     // Transfer ownership to SocketManager.
-    WebSocketHelper::GetSocketManager()->AppendDebugData(package.release());
+    gLayerScopeManager.GetSocketManager()->AppendDebugData(package.release());
     sTextureIdList.push_back(aTexID);
+
+    gLayerScopeManager.GetContentMonitor()->ClearChangedHost(aEffect->mState.mTexture);
     return true;
 }
 #endif
 
 void
 SenderHelper::SendTexturedEffect(GLContext* aGLContext,
                                  void* aLayerRef,
                                  const TexturedEffect* aEffect)
@@ -892,19 +1000,20 @@ SenderHelper::SendTexturedEffect(GLConte
 
     GLuint texID = GetTextureID(aGLContext, source);
     if (IsTextureIdContainsInList(texID)) {
         return;
     }
 
 #ifdef MOZ_WIDGET_GONK
     if (SendGraphicBuffer(aLayerRef, source, texID, aEffect)) {
-         return;
+        return;
     }
 #endif
+    // Fallback texture sending path.
     // Render to texture and read pixels back.
     SendTextureSource(aGLContext, aLayerRef, source, texID, false);
 }
 
 void
 SenderHelper::SendYCbCrEffect(GLContext* aGLContext,
                               void* aLayerRef,
                               const EffectYCbCr* aEffect)
@@ -971,16 +1080,26 @@ SenderHelper::SendEffectChain(GLContext*
         default:
             break;
     }
 
     //const Effect* secondaryEffect = aEffectChain.mSecondaryEffects[EffectTypes::MASK];
     // TODO:
 }
 
+void
+LayerScope::ContentChanged(TextureHost *host)
+{
+    if (!CheckSendable()) {
+      return;
+    }
+
+    gLayerScopeManager.GetContentMonitor()->SetChangedHost(host);
+}
+
 // ----------------------------------------------
 // LayerScopeWebSocketHandler implementation
 // ----------------------------------------------
 void
 LayerScopeWebSocketHandler::OpenStream(nsISocketTransport* aTransport)
 {
     MOZ_ASSERT(aTransport);
 
@@ -1378,17 +1497,17 @@ LayerScopeWebSocketHandler::HandleDataFr
             break;
     }
     return true;
 }
 
 void
 LayerScopeWebSocketHandler::CloseConnection()
 {
-    WebSocketHelper::GetSocketManager()->CleanDebugData();
+    gLayerScopeManager.GetSocketManager()->CleanDebugData();
     if (mInputStream) {
         mInputStream->AsyncWait(nullptr, 0, 0, nullptr);
         mInputStream = nullptr;
     }
     if (mOutputStream) {
         mOutputStream = nullptr;
     }
     if (mTransport) {
@@ -1448,126 +1567,79 @@ LayerScopeWebSocketManager::DispatchDebu
 // ----------------------------------------------
 void
 LayerScope::Init()
 {
     if (!gfxPrefs::LayerScopeEnabled()) {
         return;
     }
 
-    if (NS_IsMainThread()) {
-        WebSocketHelper::CreateServerSocket();
-    } else {
-        // Dispatch creation to main thread, and make sure we
-        // dispatch this only once after booting
-        static bool dispatched = false;
-        if (dispatched) {
-            return;
-        }
-        DebugOnly<nsresult> rv = NS_DispatchToMainThread(new CreateServerSocketRunnable());
-        MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed to dispatch WebSocket Creation to main thread");
-        dispatched = true;
-    }
+    gLayerScopeManager.CreateServerSocket();
 }
 
-class DrawSession {
-public:
-    NS_INLINE_DECL_REFCOUNTING(DrawSession)
-
-    DrawSession()
-      : mOffsetX(0.0),
-        mOffsetY(0.0),
-        mRects(0)
-    { }
-
-    float mOffsetX;
-    float mOffsetY;
-    gfx::Matrix4x4 mMVMatrix;
-    size_t mRects;
-    gfx::Rect mLayerRects[4];
-private:
-    ~DrawSession() {}
-};
-
-class DrawSessionHolder {
-public:
-    static void setSession(DrawSession *aSession) {
-        mSession = aSession;
-    }
-
-    static DrawSession& current() {
-        return *mSession;
-    }
-
-private:
-    static nsRefPtr<DrawSession> mSession;
-};
-
-nsRefPtr<DrawSession> DrawSessionHolder::mSession;
-
 void
 LayerScope::DrawBegin()
 {
     if (!CheckSendable()) {
         return;
     }
 
-    DrawSessionHolder::setSession(new DrawSession());
+    gLayerScopeManager.NewDrawSession();
 }
 
 void LayerScope::SetRenderOffset(float aX, float aY)
 {
     if (!CheckSendable()) {
         return;
     }
 
-    DrawSessionHolder::current().mOffsetX = aX;
-    DrawSessionHolder::current().mOffsetY = aY;
+    gLayerScopeManager.CurrentSession().mOffsetX = aX;
+    gLayerScopeManager.CurrentSession().mOffsetY = aY;
 }
 
 void LayerScope::SetLayerTransform(const gfx::Matrix4x4& aMatrix)
 {
     if (!CheckSendable()) {
         return;
     }
 
-    DrawSessionHolder::current().mMVMatrix = aMatrix;
+    gLayerScopeManager.CurrentSession().mMVMatrix = aMatrix;
 }
 
 void LayerScope::SetLayerRects(size_t aRects, const gfx::Rect* aLayerRects)
 {
     if (!CheckSendable()) {
         return;
     }
 
     MOZ_ASSERT(aRects > 0 && aRects <= 4);
     MOZ_ASSERT(aLayerRects);
 
-    DrawSessionHolder::current().mRects = aRects;
+    gLayerScopeManager.CurrentSession().mRects = aRects;
 
     for (size_t i = 0; i < aRects; i++){
-        DrawSessionHolder::current().mLayerRects[i] = aLayerRects[i];
+        gLayerScopeManager.CurrentSession().mLayerRects[i] = aLayerRects[i];
     }
 }
 
 void
 LayerScope::DrawEnd(gl::GLContext* aGLContext,
                     const EffectChain& aEffectChain,
                     int aWidth,
                     int aHeight)
 {
     // Protect this public function
     if (!CheckSendable()) {
         return;
     }
 
     // 1. Send parameters of draw call, such as uniforms and attributes of
     // vertex adnd fragment shader.
-    DrawSession& draws = DrawSessionHolder::current();
-    WebSocketHelper::GetSocketManager()->AppendDebugData(
+    DrawSession& draws = gLayerScopeManager.CurrentSession();
+    gLayerScopeManager.GetSocketManager()->AppendDebugData(
         new DebugGLDrawData(draws.mOffsetX, draws.mOffsetY,
                             draws.mMVMatrix, draws.mRects,
                             draws.mLayerRects,
                             aEffectChain.mLayerRef));
 
     // 2. Send textures.
     SenderHelper::SendEffectChain(aGLContext, aEffectChain, aWidth, aHeight);
 }
@@ -1586,52 +1658,52 @@ LayerScope::SendLayer(LayerComposite* aL
 
 void
 LayerScope::SendLayerDump(UniquePtr<Packet> aPacket)
 {
     // Protect this public function
     if (!CheckSendable() || !SenderHelper::GetLayersTreeSendable()) {
         return;
     }
-    WebSocketHelper::GetSocketManager()->AppendDebugData(
+    gLayerScopeManager.GetSocketManager()->AppendDebugData(
         new DebugGLLayersData(Move(aPacket)));
 }
 
 bool
 LayerScope::CheckSendable()
 {
     // Only compositor threads check LayerScope status
     MOZ_ASSERT(CompositorParent::IsInCompositorThread() || gIsGtest);
 
     if (!gfxPrefs::LayerScopeEnabled()) {
         return false;
     }
-    if (!WebSocketHelper::GetSocketManager()) {
+    if (!gLayerScopeManager.GetSocketManager()) {
         Init();
         return false;
     }
-    if (!WebSocketHelper::GetSocketManager()->IsConnected()) {
+    if (!gLayerScopeManager.GetSocketManager()->IsConnected()) {
         return false;
     }
     return true;
 }
 
 void
 LayerScope::CleanLayer()
 {
     if (CheckSendable()) {
-        WebSocketHelper::GetSocketManager()->CleanDebugData();
+        gLayerScopeManager.GetSocketManager()->CleanDebugData();
     }
 }
 
 void
 LayerScope::SetHWComposed()
 {
     if (CheckSendable()) {
-        WebSocketHelper::GetSocketManager()->AppendDebugData(
+        gLayerScopeManager.GetSocketManager()->AppendDebugData(
             new DebugGLMetaData(Packet::META, true));
     }
 }
 
 // ----------------------------------------------
 // LayerScopeAutoFrame implementation
 // ----------------------------------------------
 LayerScopeAutoFrame::LayerScopeAutoFrame(int64_t aFrameStamp)
@@ -1650,26 +1722,26 @@ void
 LayerScopeAutoFrame::BeginFrame(int64_t aFrameStamp)
 {
     SenderHelper::ClearTextureIdList();
 
     if (!LayerScope::CheckSendable()) {
         return;
     }
 
-    WebSocketHelper::GetSocketManager()->AppendDebugData(
+    gLayerScopeManager.GetSocketManager()->AppendDebugData(
         new DebugGLFrameStatusData(Packet::FRAMESTART, aFrameStamp));
 }
 
 void
 LayerScopeAutoFrame::EndFrame()
 {
     if (!LayerScope::CheckSendable()) {
         return;
     }
 
-    WebSocketHelper::GetSocketManager()->AppendDebugData(
+    gLayerScopeManager.GetSocketManager()->AppendDebugData(
         new DebugGLFrameStatusData(Packet::FRAMEEND));
-    WebSocketHelper::GetSocketManager()->DispatchDebugData();
+    gLayerScopeManager.GetSocketManager()->DispatchDebugData();
 }
 
 } /* layers */
 } /* mozilla */
--- a/gfx/layers/LayerScope.h
+++ b/gfx/layers/LayerScope.h
@@ -35,16 +35,17 @@ public:
     static void SendLayer(LayerComposite* aLayer,
                           int aWidth,
                           int aHeight);
     static void SendLayerDump(UniquePtr<layerscope::Packet> aPacket);
     static bool CheckSendable();
     static void CleanLayer();
     static void SetHWComposed();
 
+    static void ContentChanged(TextureHost *host);
 private:
     static void Init();
 };
 
 // Perform BeginFrame and EndFrame automatically
 class LayerScopeAutoFrame {
 public:
     explicit LayerScopeAutoFrame(int64_t aFrameStamp);
--- a/gfx/layers/TextureDIB.cpp
+++ b/gfx/layers/TextureDIB.cpp
@@ -292,17 +292,17 @@ DIBTextureHost::DIBTextureHost(TextureFl
   MOZ_ASSERT(mSurface);
 
   mSize = mSurface->GetSize();
   mFormat = ImageFormatToSurfaceFormat(
     gfxPlatform::GetPlatform()->OptimalFormatForContent(mSurface->GetContentType()));
 }
 
 void
-DIBTextureHost::Updated(const nsIntRegion* aRegion)
+DIBTextureHost::UpdatedInternal(const nsIntRegion* aRegion)
 {
   if (!mCompositor) {
     // This can happen if we send textures to a compositable that isn't yet
     // attached to a layer.
     return;
   }
 
   if (!mTextureSource) {
@@ -326,17 +326,17 @@ TextureHostFileMapping::TextureHostFileM
 }
 
 TextureHostFileMapping::~TextureHostFileMapping()
 {
   ::CloseHandle(mFileMapping);
 }
 
 void
-TextureHostFileMapping::Updated(const nsIntRegion* aRegion)
+TextureHostFileMapping::UpdatedInternal(const nsIntRegion* aRegion)
 {
   if (!mCompositor) {
     // This can happen if we send textures to a compositable that isn't yet
     // attached to a layer.
     return;
   }
 
   if (!mTextureSource) {
--- a/gfx/layers/TextureDIB.h
+++ b/gfx/layers/TextureDIB.h
@@ -150,43 +150,43 @@ protected:
 };
 
 class DIBTextureHost : public TextureHostDirectUpload
 {
 public:
   DIBTextureHost(TextureFlags aFlags,
                  const SurfaceDescriptorDIB& aDescriptor);
 
-  virtual void Updated(const nsIntRegion* aRegion = nullptr) override;
-
   virtual TemporaryRef<gfx::DataSourceSurface> GetAsSurface() override
   {
     return nullptr; // TODO: cf bug 872568
   }
 
 protected:
+  virtual void UpdatedInternal(const nsIntRegion* aRegion = nullptr) override;
+
   nsRefPtr<gfxWindowsSurface> mSurface;
 };
 
 class TextureHostFileMapping : public TextureHostDirectUpload
 {
 public:
   TextureHostFileMapping(TextureFlags aFlags,
                          const SurfaceDescriptorFileMapping& aDescriptor);
   ~TextureHostFileMapping();
 
-  virtual void Updated(const nsIntRegion* aRegion = nullptr) override;
-
   virtual TemporaryRef<gfx::DataSourceSurface> GetAsSurface() override
   {
     MOZ_CRASH(); // Not implemented! It would be tricky to keep track of the
                  // scope of the file mapping. We could do this through UserData
                  // on the DataSourceSurface but we don't need this right now.
   }
 
 protected:
+  virtual void UpdatedInternal(const nsIntRegion* aRegion = nullptr) override;
+
   HANDLE mFileMapping;
 };
 
 }
 }
 
 #endif /* MOZILLA_GFX_TEXTUREDIB_H */
--- a/gfx/layers/composite/TextureHost.cpp
+++ b/gfx/layers/composite/TextureHost.cpp
@@ -348,16 +348,23 @@ TextureHost::PrintInfo(std::stringstream
     RefPtr<gfx::DataSourceSurface> dSurf = GetAsSurface();
     if (dSurf) {
       aStream << gfxUtils::GetAsLZ4Base64Str(dSurf).get();
     }
   }
 #endif
 }
 
+void
+TextureHost::Updated(const nsIntRegion* aRegion)
+{
+    LayerScope::ContentChanged(this);
+    UpdatedInternal(aRegion);
+}
+
 TextureSource::TextureSource()
 : mCompositableCount(0)
 {
     MOZ_COUNT_CTOR(TextureSource);
 }
 
 TextureSource::~TextureSource()
 {
@@ -396,17 +403,17 @@ BufferTextureHost::InitSize()
     }
   }
 }
 
 BufferTextureHost::~BufferTextureHost()
 {}
 
 void
-BufferTextureHost::Updated(const nsIntRegion* aRegion)
+BufferTextureHost::UpdatedInternal(const nsIntRegion* aRegion)
 {
   ++mUpdateSerial;
   // If the last frame wasn't uploaded yet, and we -don't- have a partial update,
   // we still need to update the full surface.
   if (aRegion && !mNeedsFullUpdate) {
     mMaybeUpdatedRegion = mMaybeUpdatedRegion.Or(mMaybeUpdatedRegion, *aRegion);
   } else {
     mNeedsFullUpdate = true;
--- a/gfx/layers/composite/TextureHost.h
+++ b/gfx/layers/composite/TextureHost.h
@@ -383,17 +383,17 @@ public:
    * Is called before compositing if the shared data has changed since last
    * composition.
    * This method should be overload in cases like when we need to do a texture
    * upload for example.
    *
    * @param aRegion The region that has been changed, if nil, it means that the
    * entire surface should be updated.
    */
-  virtual void Updated(const nsIntRegion* aRegion = nullptr) {}
+   void Updated(const nsIntRegion* aRegion = nullptr);
 
   /**
    * Sets this TextureHost's compositor.
    * A TextureHost can change compositor on certain occasions, in particular if
    * it belongs to an async Compositable.
    * aCompositor can be null, in which case the TextureHost must cleanup  all
    * of it's device textures.
    */
@@ -533,16 +533,18 @@ public:
 
 protected:
   FenceHandle mReleaseFenceHandle;
 
   FenceHandle mAcquireFenceHandle;
 
   void RecycleTexture(TextureFlags aFlags);
 
+  virtual void UpdatedInternal(const nsIntRegion *Region) {}
+
   PTextureParent* mActor;
   TextureFlags mFlags;
   int mCompositableCount;
 
   friend class TextureParent;
 };
 
 /**
@@ -565,18 +567,16 @@ public:
                     TextureFlags aFlags);
 
   ~BufferTextureHost();
 
   virtual uint8_t* GetBuffer() = 0;
 
   virtual size_t GetBufferSize() = 0;
 
-  virtual void Updated(const nsIntRegion* aRegion = nullptr) override;
-
   virtual bool Lock() override;
 
   virtual void Unlock() override;
 
   virtual bool BindTextureSource(CompositableTextureSourceRef& aTexture) override;
 
   virtual void DeallocateDeviceData() override;
 
@@ -598,16 +598,18 @@ public:
   virtual bool HasInternalBuffer() const override { return true; }
 
 protected:
   bool Upload(nsIntRegion *aRegion = nullptr);
   bool MaybeUpload(nsIntRegion *aRegion = nullptr);
 
   void InitSize();
 
+  virtual void UpdatedInternal(const nsIntRegion* aRegion = nullptr) override;
+
   RefPtr<Compositor> mCompositor;
   RefPtr<DataTextureSource> mFirstSource;
   nsIntRegion mMaybeUpdatedRegion;
   gfx::IntSize mSize;
   // format of the data that is shared with the content process.
   gfx::SurfaceFormat mFormat;
   uint32_t mUpdateSerial;
   bool mLocked;
--- a/gfx/layers/d3d9/TextureD3D9.cpp
+++ b/gfx/layers/d3d9/TextureD3D9.cpp
@@ -909,17 +909,17 @@ DataTextureSourceD3D9::UpdateFromTexture
       return false;
     }
   }
   mIsTiled = false;
   return true;
 }
 
 void
-TextureHostD3D9::Updated(const nsIntRegion* aRegion)
+TextureHostD3D9::UpdatedInternal(const nsIntRegion* aRegion)
 {
   MOZ_ASSERT(mTexture);
   if (!mTexture) {
     return;
   }
 
   if (!mTextureSource) {
     mTextureSource = new DataTextureSourceD3D9(mFormat, mSize, mCompositor,
--- a/gfx/layers/d3d9/TextureD3D9.h
+++ b/gfx/layers/d3d9/TextureD3D9.h
@@ -303,31 +303,31 @@ public:
   virtual void SetCompositor(Compositor* aCompositor) override;
 
   virtual gfx::SurfaceFormat GetFormat() const override { return mFormat; }
 
   virtual bool Lock() override;
 
   virtual void Unlock() override;
 
-  virtual void Updated(const nsIntRegion* aRegion) override;
-
   virtual gfx::IntSize GetSize() const override { return mSize; }
 
   virtual TemporaryRef<gfx::DataSourceSurface> GetAsSurface() override
   {
     return nullptr;
   }
 
   virtual bool HasInternalBuffer() const override { return true; }
 
 protected:
   TextureHostD3D9(TextureFlags aFlags);
   IDirect3DDevice9* GetDevice();
 
+  virtual void UpdatedInternal(const nsIntRegion* aRegion) override;
+
   RefPtr<DataTextureSourceD3D9> mTextureSource;
   RefPtr<IDirect3DTexture9> mTexture;
   RefPtr<CompositorD3D9> mCompositor;
   gfx::IntSize mSize;
   gfx::SurfaceFormat mFormat;
   bool mIsLocked;
 };
 
--- a/gfx/layers/opengl/GrallocTextureHost.h
+++ b/gfx/layers/opengl/GrallocTextureHost.h
@@ -19,18 +19,16 @@ class GrallocTextureHostOGL : public Tex
 {
   friend class GrallocBufferActor;
 public:
   GrallocTextureHostOGL(TextureFlags aFlags,
                         const NewSurfaceDescriptorGralloc& aDescriptor);
 
   virtual ~GrallocTextureHostOGL();
 
-  virtual void Updated(const nsIntRegion* aRegion) override {}
-
   virtual bool Lock() override;
 
   virtual void Unlock() override;
 
   virtual void SetCompositor(Compositor* aCompositor) override;
 
   virtual void DeallocateSharedData() override;