Bug 1343764 - Add ExternalBuffer handling r=nical
authorsotaro <sotaro.ikeda.g@gmail.com>
Tue, 07 Mar 2017 19:37:28 +0900
changeset 395394 48f2b03ac2fcc48b2c086458e68fe4c3946ce54e
parent 395393 0d411df025f5315626bd6a8bfec32d264e24cd84
child 395395 49be4b9eca3aba79de74cd2346ddc922e4ce7d97
push id7391
push usermtabara@mozilla.com
push dateMon, 12 Jun 2017 13:08:53 +0000
treeherdermozilla-beta@2191d7f87e2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnical
bugs1343764
milestone54.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 1343764 - Add ExternalBuffer handling r=nical
gfx/layers/CompositorTypes.h
gfx/layers/basic/TextureHostBasic.cpp
gfx/layers/composite/CompositableHost.h
gfx/layers/composite/TextureHost.cpp
gfx/layers/composite/TextureHost.h
gfx/layers/d3d11/TextureD3D11.cpp
gfx/layers/d3d9/TextureD3D9.cpp
gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp
gfx/layers/ipc/ISurfaceAllocator.h
gfx/layers/moz.build
gfx/layers/opengl/TextureHostOGL.cpp
gfx/layers/wr/WebRenderBridgeParent.cpp
gfx/layers/wr/WebRenderCompositableHolder.cpp
gfx/layers/wr/WebRenderCompositableHolder.h
gfx/layers/wr/WebRenderImageHost.cpp
gfx/layers/wr/WebRenderImageHost.h
gfx/layers/wr/WebRenderLayerManager.cpp
gfx/layers/wr/WebRenderTextureHost.cpp
gfx/layers/wr/WebRenderTextureHost.h
gfx/tests/gtest/TestTextures.cpp
gfx/webrender_bindings/RenderTextureHost.cpp
gfx/webrender_bindings/RenderTextureHost.h
gfx/webrender_bindings/RenderThread.cpp
gfx/webrender_bindings/RenderThread.h
gfx/webrender_bindings/RendererOGL.cpp
gfx/webrender_bindings/RendererOGL.h
gfx/webrender_bindings/WebRenderAPI.cpp
gfx/webrender_bindings/WebRenderAPI.h
gfx/webrender_bindings/moz.build
gfx/webrender_bindings/src/bindings.rs
gfx/webrender_bindings/webrender_ffi.h
--- a/gfx/layers/CompositorTypes.h
+++ b/gfx/layers/CompositorTypes.h
@@ -64,20 +64,22 @@ enum class TextureFlags : uint32_t {
   // to it again.
   IMMEDIATE_UPLOAD   = 1 << 10,
   // The texture is part of a component-alpha pair
   COMPONENT_ALPHA    = 1 << 11,
   // The texture is being allocated for a compositor that no longer exists.
   // This flag is only used in the parent process.
   INVALID_COMPOSITOR = 1 << 12,
   // The texture was created by converting from YCBCR to RGB
-  RGB_FROM_YCBCR = 1 << 13,
+  RGB_FROM_YCBCR     = 1 << 13,
+  // The texture is used for snapshot.
+  SNAPSHOT           = 1 << 14,
 
   // OR union of all valid bits
-  ALL_BITS           = (1 << 14) - 1,
+  ALL_BITS           = (1 << 15) - 1,
   // the default flags
   DEFAULT = NO_FLAGS
 };
 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(TextureFlags)
 
 static inline bool
 TextureRequiresLocking(TextureFlags aFlags)
 {
--- a/gfx/layers/basic/TextureHostBasic.cpp
+++ b/gfx/layers/basic/TextureHostBasic.cpp
@@ -12,22 +12,23 @@ using namespace mozilla::gl;
 using namespace mozilla::gfx;
 
 namespace mozilla {
 namespace layers {
 
 already_AddRefed<TextureHost>
 CreateTextureHostBasic(const SurfaceDescriptor& aDesc,
                        ISurfaceAllocator* aDeallocator,
+                       LayersBackend aBackend,
                        TextureFlags aFlags)
 {
 #ifdef XP_MACOSX
   if (aDesc.type() == SurfaceDescriptor::TSurfaceDescriptorMacIOSurface) {
     const SurfaceDescriptorMacIOSurface& desc =
       aDesc.get_SurfaceDescriptorMacIOSurface();
     return MakeAndAddRef<MacIOSurfaceTextureHostBasic>(aFlags, desc);
   }
 #endif
-  return CreateBackendIndependentTextureHost(aDesc, aDeallocator, aFlags);
+  return CreateBackendIndependentTextureHost(aDesc, aDeallocator, aBackend, aFlags);
 }
 
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/composite/CompositableHost.h
+++ b/gfx/layers/composite/CompositableHost.h
@@ -38,16 +38,17 @@ class DataSourceSurface;
 namespace layers {
 
 class Layer;
 class LayerComposite;
 class Compositor;
 class ThebesBufferData;
 class TiledContentHost;
 class CompositableParentManager;
+class WebRenderImageHost;
 struct EffectChain;
 
 struct ImageCompositeNotificationInfo {
   base::ProcessId mImageBridgeProcessId;
   ImageCompositeNotification mNotification;
 };
 
 struct AsyncCompositableRef
@@ -143,16 +144,17 @@ public:
   {
     return mCompositor;
   }
 
   Layer* GetLayer() const { return mLayer; }
   void SetLayer(Layer* aLayer) { mLayer = aLayer; }
 
   virtual TiledContentHost* AsTiledContentHost() { return nullptr; }
+  virtual WebRenderImageHost* AsWebRenderImageHost() { return nullptr; }
 
   typedef uint32_t AttachFlags;
   static const AttachFlags NO_FLAGS = 0;
   static const AttachFlags ALLOW_REATTACH = 1;
   static const AttachFlags KEEP_ATTACHED = 2;
   static const AttachFlags FORCE_DETACH = 2;
 
   virtual void Attach(Layer* aLayer,
--- a/gfx/layers/composite/TextureHost.cpp
+++ b/gfx/layers/composite/TextureHost.cpp
@@ -4,27 +4,29 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "TextureHost.h"
 
 #include "CompositableHost.h"           // for CompositableHost
 #include "LayerScope.h"
 #include "LayersLogging.h"              // for AppendToString
 #include "mozilla/gfx/2D.h"             // for DataSourceSurface, Factory
+#include "mozilla/gfx/gfxVars.h"
 #include "mozilla/ipc/Shmem.h"          // for Shmem
 #include "mozilla/layers/CompositableTransactionParent.h" // for CompositableParentManager
 #include "mozilla/layers/CompositorBridgeParent.h"
 #include "mozilla/layers/Compositor.h"  // for Compositor
 #include "mozilla/layers/ISurfaceAllocator.h"  // for ISurfaceAllocator
 #include "mozilla/layers/LayersSurfaces.h"  // for SurfaceDescriptor, etc
 #include "mozilla/layers/TextureHostBasic.h"
 #include "mozilla/layers/TextureHostOGL.h"  // for TextureHostOGL
 #include "mozilla/layers/ImageDataSerializer.h"
 #include "mozilla/layers/TextureClient.h"
 #include "mozilla/layers/GPUVideoTextureHost.h"
+#include "mozilla/layers/WebRenderTextureHost.h"
 #include "nsAString.h"
 #include "mozilla/RefPtr.h"                   // for nsRefPtr
 #include "nsPrintfCString.h"            // for nsPrintfCString
 #include "mozilla/layers/PTextureParent.h"
 #include "mozilla/Unused.h"
 #include <limits>
 #include "../opengl/CompositorOGL.h"
 #include "gfxPrefs.h"
@@ -155,106 +157,128 @@ void
 TextureHost::SetLastFwdTransactionId(uint64_t aTransactionId)
 {
   MOZ_ASSERT(mFwdTransactionId <= aTransactionId);
   mFwdTransactionId = aTransactionId;
 }
 
 // implemented in TextureHostOGL.cpp
 already_AddRefed<TextureHost> CreateTextureHostOGL(const SurfaceDescriptor& aDesc,
-                                               ISurfaceAllocator* aDeallocator,
-                                               TextureFlags aFlags);
+                                                   ISurfaceAllocator* aDeallocator,
+                                                   LayersBackend aBackend,
+                                                   TextureFlags aFlags);
 
 // implemented in TextureHostBasic.cpp
 already_AddRefed<TextureHost> CreateTextureHostBasic(const SurfaceDescriptor& aDesc,
-                                                 ISurfaceAllocator* aDeallocator,
-                                                 TextureFlags aFlags);
+                                                     ISurfaceAllocator* aDeallocator,
+                                                     LayersBackend aBackend,
+                                                     TextureFlags aFlags);
 
 // implemented in TextureD3D11.cpp
 already_AddRefed<TextureHost> CreateTextureHostD3D11(const SurfaceDescriptor& aDesc,
-                                                 ISurfaceAllocator* aDeallocator,
-                                                 TextureFlags aFlags);
+                                                     ISurfaceAllocator* aDeallocator,
+                                                     LayersBackend aBackend,
+                                                     TextureFlags aFlags);
 
 // implemented in TextureD3D9.cpp
 already_AddRefed<TextureHost> CreateTextureHostD3D9(const SurfaceDescriptor& aDesc,
-                                                ISurfaceAllocator* aDeallocator,
-                                                TextureFlags aFlags);
+                                                    ISurfaceAllocator* aDeallocator,
+                                                    LayersBackend aBackend,
+                                                    TextureFlags aFlags);
 
 already_AddRefed<TextureHost>
 TextureHost::Create(const SurfaceDescriptor& aDesc,
                     ISurfaceAllocator* aDeallocator,
                     LayersBackend aBackend,
                     TextureFlags aFlags)
 {
   switch (aDesc.type()) {
     case SurfaceDescriptor::TSurfaceDescriptorBuffer:
     case SurfaceDescriptor::TSurfaceDescriptorDIB:
     case SurfaceDescriptor::TSurfaceDescriptorFileMapping:
     case SurfaceDescriptor::TSurfaceDescriptorGPUVideo:
-      return CreateBackendIndependentTextureHost(aDesc, aDeallocator, aFlags);
+      return CreateBackendIndependentTextureHost(aDesc, aDeallocator, aBackend, aFlags);
 
     case SurfaceDescriptor::TEGLImageDescriptor:
     case SurfaceDescriptor::TSurfaceTextureDescriptor:
     case SurfaceDescriptor::TSurfaceDescriptorSharedGLTexture:
-      return CreateTextureHostOGL(aDesc, aDeallocator, aFlags);
+      return CreateTextureHostOGL(aDesc, aDeallocator, aBackend, aFlags);
 
     case SurfaceDescriptor::TSurfaceDescriptorMacIOSurface:
       if (aBackend == LayersBackend::LAYERS_OPENGL ||
           aBackend == LayersBackend::LAYERS_WR) {
-        return CreateTextureHostOGL(aDesc, aDeallocator, aFlags);
+        return CreateTextureHostOGL(aDesc, aDeallocator, aBackend, aFlags);
       } else {
-        return CreateTextureHostBasic(aDesc, aDeallocator, aFlags);
+        return CreateTextureHostBasic(aDesc, aDeallocator, aBackend, aFlags);
       }
 
 #ifdef MOZ_X11
     case SurfaceDescriptor::TSurfaceDescriptorX11: {
       const SurfaceDescriptorX11& desc = aDesc.get_SurfaceDescriptorX11();
       return MakeAndAddRef<X11TextureHost>(aFlags, desc);
     }
 #endif
 
 #ifdef XP_WIN
     case SurfaceDescriptor::TSurfaceDescriptorD3D9:
-      return CreateTextureHostD3D9(aDesc, aDeallocator, aFlags);
+      return CreateTextureHostD3D9(aDesc, aDeallocator, aBackend, aFlags);
 
     case SurfaceDescriptor::TSurfaceDescriptorD3D10:
     case SurfaceDescriptor::TSurfaceDescriptorDXGIYCbCr:
       if (aBackend == LayersBackend::LAYERS_D3D9) {
-        return CreateTextureHostD3D9(aDesc, aDeallocator, aFlags);
+        return CreateTextureHostD3D9(aDesc, aDeallocator, aBackend, aFlags);
       } else {
-        return CreateTextureHostD3D11(aDesc, aDeallocator, aFlags);
+        return CreateTextureHostD3D11(aDesc, aDeallocator, aBackend, aFlags);
       }
 #endif
     default:
       MOZ_CRASH("GFX: Unsupported Surface type host");
   }
 }
 
+bool WrapWithWebRenderTextureHost(LayersBackend aBackend,
+                                  TextureFlags aFlags)
+{
+  if (!gfxVars::UseWebRender() ||
+      (aFlags & TextureFlags::SNAPSHOT) ||
+      (aBackend != LayersBackend::LAYERS_WR)) {
+    return false;
+  }
+  return true;
+}
+
 already_AddRefed<TextureHost>
 CreateBackendIndependentTextureHost(const SurfaceDescriptor& aDesc,
                                     ISurfaceAllocator* aDeallocator,
+                                    LayersBackend aBackend,
                                     TextureFlags aFlags)
 {
   RefPtr<TextureHost> result;
   switch (aDesc.type()) {
     case SurfaceDescriptor::TSurfaceDescriptorBuffer: {
       const SurfaceDescriptorBuffer& bufferDesc = aDesc.get_SurfaceDescriptorBuffer();
       const MemoryOrShmem& data = bufferDesc.data();
       switch (data.type()) {
         case MemoryOrShmem::TShmem: {
           result = new ShmemTextureHost(data.get_Shmem(),
                                         bufferDesc.desc(),
                                         aDeallocator,
                                         aFlags);
+          if (WrapWithWebRenderTextureHost(aBackend, aFlags)) {
+            result = new WebRenderTextureHost(aFlags, result);
+          }
           break;
         }
         case MemoryOrShmem::Tuintptr_t: {
           result = new MemoryTextureHost(reinterpret_cast<uint8_t*>(data.get_uintptr_t()),
                                          bufferDesc.desc(),
                                          aFlags);
+          if (WrapWithWebRenderTextureHost(aBackend, aFlags)) {
+            result = new WebRenderTextureHost(aFlags, result);
+          }
           break;
         }
         default:
           gfxCriticalError() << "Failed texture host for backend " << (int)data.type();
           MOZ_CRASH("GFX: No texture host for backend");
       }
       break;
     }
--- a/gfx/layers/composite/TextureHost.h
+++ b/gfx/layers/composite/TextureHost.h
@@ -50,16 +50,17 @@ class TextureHostOGL;
 class TextureReadLock;
 class TextureSourceOGL;
 class TextureSourceD3D9;
 class TextureSourceD3D11;
 class TextureSourceBasic;
 class DataTextureSource;
 class PTextureParent;
 class TextureParent;
+class WebRenderTextureHost;
 class WrappingTextureSourceYCbCrBasic;
 
 /**
  * A view on a TextureHost where the texture is internally represented as tiles
  * (contrast with a tiled buffer, where each texture is a tile). For iteration by
  * the texture's buffer host.
  * This is only useful when the underlying surface is too big to fit in one
  * device texture, which forces us to split it in smaller parts.
@@ -581,16 +582,18 @@ public:
   void SetReadLock(TextureReadLock* aReadLock);
 
   TextureReadLock* GetReadLock() { return mReadLock; }
 
   virtual Compositor* GetCompositor() = 0;
 
   virtual BufferTextureHost* AsBufferTextureHost() { return nullptr; }
 
+  virtual WebRenderTextureHost* AsWebRenderTextureHost() { return nullptr; }
+
 protected:
   void ReadUnlock();
 
   void RecycleTexture(TextureFlags aFlags);
 
   virtual void UpdatedInternal(const nsIntRegion *Region) {}
 
   /**
@@ -877,14 +880,15 @@ private:
 
 /**
  * Creates a TextureHost that can be used with any of the existing backends
  * Not all SurfaceDescriptor types are supported
  */
 already_AddRefed<TextureHost>
 CreateBackendIndependentTextureHost(const SurfaceDescriptor& aDesc,
                                     ISurfaceAllocator* aDeallocator,
+                                    LayersBackend aBackend,
                                     TextureFlags aFlags);
 
 } // namespace layers
 } // namespace mozilla
 
 #endif
--- a/gfx/layers/d3d11/TextureD3D11.cpp
+++ b/gfx/layers/d3d11/TextureD3D11.cpp
@@ -624,22 +624,23 @@ DXGIYCbCrTextureData::Deallocate(LayersI
   mHoldRefs[0] = nullptr;
   mHoldRefs[1] = nullptr;
   mHoldRefs[2] = nullptr;
 }
 
 already_AddRefed<TextureHost>
 CreateTextureHostD3D11(const SurfaceDescriptor& aDesc,
                        ISurfaceAllocator* aDeallocator,
+                       LayersBackend aBackend,
                        TextureFlags aFlags)
 {
   RefPtr<TextureHost> result;
   switch (aDesc.type()) {
     case SurfaceDescriptor::TSurfaceDescriptorBuffer: {
-      result = CreateBackendIndependentTextureHost(aDesc, aDeallocator, aFlags);
+      result = CreateBackendIndependentTextureHost(aDesc, aDeallocator, aBackend, aFlags);
       break;
     }
     case SurfaceDescriptor::TSurfaceDescriptorD3D10: {
       result = new DXGITextureHostD3D11(aFlags,
                                         aDesc.get_SurfaceDescriptorD3D10());
       break;
     }
     case SurfaceDescriptor::TSurfaceDescriptorDXGIYCbCr: {
--- a/gfx/layers/d3d9/TextureD3D9.cpp
+++ b/gfx/layers/d3d9/TextureD3D9.cpp
@@ -44,22 +44,23 @@ TextureSourceD3D9::~TextureSourceD3D9()
     MOZ_ASSERT(mNextHost->mPreviousHost == this);
     mNextHost->mPreviousHost = mPreviousHost;
   }
 }
 
 already_AddRefed<TextureHost>
 CreateTextureHostD3D9(const SurfaceDescriptor& aDesc,
                       ISurfaceAllocator* aDeallocator,
+                      LayersBackend aBackend,
                       TextureFlags aFlags)
 {
   RefPtr<TextureHost> result;
   switch (aDesc.type()) {
     case SurfaceDescriptor::TSurfaceDescriptorBuffer: {
-      result = CreateBackendIndependentTextureHost(aDesc, aDeallocator, aFlags);
+      result = CreateBackendIndependentTextureHost(aDesc, aDeallocator, aBackend, aFlags);
       break;
     }
     case SurfaceDescriptor::TSurfaceDescriptorD3D9: {
       result = new TextureHostD3D9(aFlags, aDesc);
       break;
     }
     case SurfaceDescriptor::TSurfaceDescriptorD3D10: {
       result = new DXGITextureHostD3D9(aFlags, aDesc);
--- a/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp
+++ b/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp
@@ -217,17 +217,17 @@ CrossProcessCompositorBridgeParent::Allo
   MonitorAutoLock lock(*sIndirectLayerTreesLock);
   MOZ_ASSERT(sIndirectLayerTrees.find(pipelineHandle) != sIndirectLayerTrees.end());
   MOZ_ASSERT(sIndirectLayerTrees[pipelineHandle].mWrBridge == nullptr);
   CompositorBridgeParent* cbp = sIndirectLayerTrees[pipelineHandle].mParent;
   WebRenderBridgeParent* root = sIndirectLayerTrees[cbp->RootLayerTreeId()].mWrBridge.get();
 
   WebRenderBridgeParent* parent = nullptr;
   RefPtr<wr::WebRenderAPI> api = root->GetWebRenderAPI();
-  RefPtr<WebRenderCompositableHolder> holder = root->CompositableHolder();
+  RefPtr<WebRenderCompositableHolder> holder = new WebRenderCompositableHolder();
   parent = new WebRenderBridgeParent(this, aPipelineId, nullptr, root->CompositorScheduler(), Move(api), Move(holder));
 
   parent->AddRef(); // IPDL reference
   sIndirectLayerTrees[pipelineHandle].mCrossProcessParent = this;
   sIndirectLayerTrees[pipelineHandle].mWrBridge = parent;
   *aTextureFactoryIdentifier = parent->GetTextureFactoryIdentifier();
   *aIdNamespace = parent->GetIdNameSpace();
 
--- a/gfx/layers/ipc/ISurfaceAllocator.h
+++ b/gfx/layers/ipc/ISurfaceAllocator.h
@@ -92,16 +92,18 @@ public:
   // ipc info
 
   virtual bool IPCOpen() const { return true; }
 
   virtual bool IsSameProcess() const = 0;
 
   virtual bool UsesImageBridge() const { return false; }
 
+  virtual bool UsesWebRenderBridge() const { return false; }
+
 protected:
   void Finalize() {}
 
   virtual ~ISurfaceAllocator() {}
 };
 
 /// Methods that are specific to the client/child side.
 class ClientIPCAllocator : public ISurfaceAllocator
--- a/gfx/layers/moz.build
+++ b/gfx/layers/moz.build
@@ -210,16 +210,17 @@ EXPORTS.mozilla.layers += [
     'wr/WebRenderBridgeChild.h',
     'wr/WebRenderBridgeParent.h',
     'wr/WebRenderCompositableHolder.h',
     'wr/WebRenderDisplayItemLayer.h',
     'wr/WebRenderImageHost.h',
     'wr/WebRenderLayerManager.h',
     'wr/WebRenderLayersLogging.h',
     'wr/WebRenderMessageUtils.h',
+    'wr/WebRenderTextureHost.h',
 ]
 
 if CONFIG['MOZ_X11']:
     EXPORTS.mozilla.layers += [
         'basic/TextureClientX11.h',
         'basic/X11TextureSourceBasic.h',
         'composite/X11TextureHost.h',
         'ipc/ShadowLayerUtilsX11.h',
@@ -400,16 +401,17 @@ UNIFIED_SOURCES += [
     'wr/WebRenderContainerLayer.cpp',
     'wr/WebRenderDisplayItemLayer.cpp',
     'wr/WebRenderImageHost.cpp',
     'wr/WebRenderImageLayer.cpp',
     'wr/WebRenderLayerManager.cpp',
     'wr/WebRenderLayersLogging.cpp',
     'wr/WebRenderPaintedLayer.cpp',
     'wr/WebRenderTextLayer.cpp',
+    'wr/WebRenderTextureHost.cpp',
 ]
 
 SOURCES += [
     'basic/BasicImageLayer.cpp',
     'ImageContainer.cpp',
     'Layers.cpp',
     'LayerTreeInvalidation.cpp',
     'PersistentBufferProvider.cpp',
--- a/gfx/layers/opengl/TextureHostOGL.cpp
+++ b/gfx/layers/opengl/TextureHostOGL.cpp
@@ -35,23 +35,26 @@ using namespace mozilla::gfx;
 namespace mozilla {
 namespace layers {
 
 class Compositor;
 
 already_AddRefed<TextureHost>
 CreateTextureHostOGL(const SurfaceDescriptor& aDesc,
                      ISurfaceAllocator* aDeallocator,
+                     LayersBackend aBackend,
                      TextureFlags aFlags)
 {
   RefPtr<TextureHost> result;
   switch (aDesc.type()) {
     case SurfaceDescriptor::TSurfaceDescriptorBuffer: {
       result = CreateBackendIndependentTextureHost(aDesc,
-                                                   aDeallocator, aFlags);
+                                                   aDeallocator,
+                                                   aBackend,
+                                                   aFlags);
       break;
     }
 
 #ifdef MOZ_WIDGET_ANDROID
     case SurfaceDescriptor::TSurfaceTextureDescriptor: {
       const SurfaceTextureDescriptor& desc = aDesc.get_SurfaceTextureDescriptor();
       result = new SurfaceTextureHost(aFlags,
                                       (AndroidSurfaceTexture*)desc.surfTex(),
--- a/gfx/layers/wr/WebRenderBridgeParent.cpp
+++ b/gfx/layers/wr/WebRenderBridgeParent.cpp
@@ -13,16 +13,17 @@
 #include "mozilla/layers/Compositor.h"
 #include "mozilla/layers/CompositorBridgeParent.h"
 #include "mozilla/layers/CompositorThread.h"
 #include "mozilla/layers/CompositorVsyncScheduler.h"
 #include "mozilla/layers/ImageBridgeParent.h"
 #include "mozilla/layers/ImageDataSerializer.h"
 #include "mozilla/layers/TextureHost.h"
 #include "mozilla/layers/WebRenderCompositableHolder.h"
+#include "mozilla/layers/WebRenderTextureHost.h"
 #include "mozilla/webrender/RenderThread.h"
 #include "mozilla/widget/CompositorWidget.h"
 
 bool is_in_main_thread()
 {
   return NS_IsMainThread();
 }
 
@@ -288,35 +289,55 @@ WebRenderBridgeParent::ProcessWebrenderC
   std::vector<wr::ImageKey> keysToDelete;
 
   for (InfallibleTArray<WebRenderParentCommand>::index_type i = 0; i < aCommands.Length(); ++i) {
     const WebRenderParentCommand& cmd = aCommands[i];
 
     switch (cmd.type()) {
       case WebRenderParentCommand::TOpAddExternalImage: {
         const OpAddExternalImage& op = cmd.get_OpAddExternalImage();
+        wr::ImageKey key = op.key();
         MOZ_ASSERT(mExternalImageIds.Get(op.externalImageId()).get());
 
         RefPtr<CompositableHost> host = mExternalImageIds.Get(op.externalImageId());
         if (!host) {
+          NS_ERROR("CompositableHost does not exist");
+          break;
+        }
+        // XXX select Texture for video in CompositeToTarget().
+        TextureHost* texture = host->GetAsTextureHost();
+        if (!texture) {
+          NS_ERROR("TextureHost does not exist");
+          break;
+        }
+        WebRenderTextureHost* wrTexture = texture->AsWebRenderTextureHost();
+        if (wrTexture) {
+          // XXX handling YUV
+          gfx::SurfaceFormat format =
+            wrTexture->GetFormat() == SurfaceFormat::YUV ? SurfaceFormat::B8G8R8A8 : wrTexture->GetFormat();
+          mApi->AddExternalImageBuffer(key,
+                                       wrTexture->GetSize(),
+                                       format,
+                                       wrTexture->GetExternalImageKey());
+          mCompositableHolder->HoldExternalImage(aEpoch, texture->AsWebRenderTextureHost());
+          keysToDelete.push_back(key);
           break;
         }
         RefPtr<DataSourceSurface> dSurf = host->GetAsSurface();
         if (!dSurf) {
           break;
         }
 
         DataSourceSurface::MappedSurface map;
         if (!dSurf->Map(gfx::DataSourceSurface::MapType::READ, &map)) {
           break;
         }
 
         IntSize size = dSurf->GetSize();
         wr::ImageDescriptor descriptor(size, map.mStride, SurfaceFormat::B8G8R8A8);
-        wr::ImageKey key = op.key();
         auto slice = Range<uint8_t>(map.mData, size.height * map.mStride);
         mApi->AddImage(key, descriptor, slice);
 
         keysToDelete.push_back(key);
         dSurf->Unmap();
         // XXX workaround for releasing Readlock. See Bug 1339625
         if(host->GetType() == CompositableType::CONTENT_SINGLE) {
           host->CleanupResources();
@@ -426,17 +447,16 @@ WebRenderBridgeParent::RecvAddExternalIm
   }
   if (host->GetType() != CompositableType::IMAGE &&
       host->GetType() != CompositableType::CONTENT_SINGLE &&
       host->GetType() != CompositableType::CONTENT_DOUBLE) {
     NS_ERROR("Incompatible CompositableHost");
     return IPC_OK();
   }
 
-  mCompositableHolder->AddExternalImageId(aImageId, host);
   mExternalImageIds.Put(aImageId, host);
 
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 WebRenderBridgeParent::RecvAddExternalImageIdForCompositable(const uint64_t& aImageId,
                                                              const CompositableHandle& aHandle)
@@ -449,31 +469,29 @@ WebRenderBridgeParent::RecvAddExternalIm
   RefPtr<CompositableHost> host = FindCompositable(aHandle);
   if (host->GetType() != CompositableType::IMAGE &&
       host->GetType() != CompositableType::CONTENT_SINGLE &&
       host->GetType() != CompositableType::CONTENT_DOUBLE) {
     NS_ERROR("Incompatible CompositableHost");
     return IPC_OK();
   }
 
-  mCompositableHolder->AddExternalImageId(aImageId, host);
   mExternalImageIds.Put(aImageId, host);
 
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 WebRenderBridgeParent::RecvRemoveExternalImageId(const uint64_t& aImageId)
 {
   if (mDestroyed) {
     return IPC_OK();
   }
   MOZ_ASSERT(mExternalImageIds.Get(aImageId).get());
   mExternalImageIds.Remove(aImageId);
-  mCompositableHolder->RemoveExternalImageId(aImageId);
 
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 WebRenderBridgeParent::RecvSetLayerObserverEpoch(const uint64_t& aLayerObserverEpoch)
 {
   mChildLayerObserverEpoch = aLayerObserverEpoch;
@@ -529,30 +547,31 @@ WebRenderBridgeParent::FlushPendingTrans
   uint64_t id = 0;
   while (!mPendingTransactionIds.empty()) {
     id = mPendingTransactionIds.front().mId;
     mPendingTransactionIds.pop();
   }
   return id;
 }
 
-
-
 uint64_t
 WebRenderBridgeParent::FlushTransactionIdsForEpoch(const wr::Epoch& aEpoch)
 {
   uint64_t id = 0;
   while (!mPendingTransactionIds.empty()) {
     id = mPendingTransactionIds.front().mId;
     if (mPendingTransactionIds.front().mEpoch == aEpoch) {
       mPendingTransactionIds.pop();
       break;
     }
     mPendingTransactionIds.pop();
   }
+
+  mCompositableHolder->Update(aEpoch);
+
   return id;
 }
 
 WebRenderBridgeParent::~WebRenderBridgeParent()
 {
 }
 
 void
@@ -573,23 +592,24 @@ WebRenderBridgeParent::ScheduleCompositi
 }
 
 void
 WebRenderBridgeParent::ClearResources()
 {
   if (mApi) {
     ++mWrEpoch; // Update webrender epoch
     mApi->ClearRootDisplayList(wr::NewEpoch(mWrEpoch), mPipelineId);
+    if (!mKeysToDelete.empty()) {
+      // XXX Sync wait.
+      mApi->WaitFlushed();
+      DeleteOldImages();
+    }
   }
-  DeleteOldImages();
   if (mCompositableHolder) {
-    for (auto iter = mExternalImageIds.Iter(); !iter.Done(); iter.Next()) {
-      uint64_t externalImageId = iter.Key();
-      mCompositableHolder->RemoveExternalImageId(externalImageId);
-    }
+    mCompositableHolder->Destroy();
   }
   mExternalImageIds.Clear();
 
   if (mWidget && mCompositorScheduler) {
     mCompositorScheduler->Destroy();
   }
   mCompositorScheduler = nullptr;
   mApi = nullptr;
--- a/gfx/layers/wr/WebRenderCompositableHolder.cpp
+++ b/gfx/layers/wr/WebRenderCompositableHolder.cpp
@@ -1,59 +1,60 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * 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 "WebRenderCompositableHolder.h"
 
 #include "CompositableHost.h"
-//#include "mozilla/layers/CompositorBridgeParent.h"
+#include "mozilla/layers/WebRenderImageHost.h"
+#include "mozilla/layers/WebRenderTextureHost.h"
 
 namespace mozilla {
 
 using namespace gfx;
 
 namespace layers {
 
 WebRenderCompositableHolder::WebRenderCompositableHolder()
 {
   MOZ_COUNT_CTOR(WebRenderCompositableHolder);
 }
 
 WebRenderCompositableHolder::~WebRenderCompositableHolder()
 {
   MOZ_COUNT_DTOR(WebRenderCompositableHolder);
-  Destroy();
+  MOZ_ASSERT(mWebRenderTextureHosts.empty());
 }
 
 void
 WebRenderCompositableHolder::Destroy()
 {
-  mCompositableHosts.Clear();
-}
-
-void
-WebRenderCompositableHolder::AddExternalImageId(uint64_t aExternalImageId, CompositableHost* aHost)
-{
-  MOZ_ASSERT(!mCompositableHosts.Get(aExternalImageId));
-  mCompositableHosts.Put(aExternalImageId, aHost);
+  while (!mWebRenderTextureHosts.empty()) {
+    mWebRenderTextureHosts.pop();
+  }
 }
 
 void
-WebRenderCompositableHolder::RemoveExternalImageId(uint64_t aExternalImageId)
+WebRenderCompositableHolder::HoldExternalImage(const wr::Epoch& aEpoch, WebRenderTextureHost* aTexture)
 {
-  MOZ_ASSERT(mCompositableHosts.Get(aExternalImageId));
-  mCompositableHosts.Remove(aExternalImageId);
+  MOZ_ASSERT(aTexture);
+  // Hold WebRenderTextureHost until end of its usage on RenderThread
+  mWebRenderTextureHosts.push(ForwardingTextureHosts(aEpoch, aTexture));
 }
 
 void
-WebRenderCompositableHolder::UpdateExternalImages()
+WebRenderCompositableHolder::Update(const wr::Epoch& aEpoch)
 {
-  for (auto iter = mCompositableHosts.Iter(); !iter.Done(); iter.Next()) {
-    RefPtr<CompositableHost>& host = iter.Data();
-    // XXX Change to correct TextrueSource handling here.
-    host->BindTextureSource();
+  if (mWebRenderTextureHosts.empty()) {
+    return;
+  }
+  while (!mWebRenderTextureHosts.empty()) {
+    if (aEpoch <= mWebRenderTextureHosts.front().mEpoch) {
+      break;
+    }
+    mWebRenderTextureHosts.pop();
   }
 }
 
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/wr/WebRenderCompositableHolder.h
+++ b/gfx/layers/wr/WebRenderCompositableHolder.h
@@ -1,43 +1,58 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * 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/. */
 
 #ifndef MOZILLA_GFX_WEBRENDERCOMPOSITABLE_HOLDER_H
 #define MOZILLA_GFX_WEBRENDERCOMPOSITABLE_HOLDER_H
 
-#include "nsDataHashtable.h"
+#include <queue>
+
+#include "mozilla/layers/TextureHost.h"
+#include "mozilla/webrender/WebRenderTypes.h"
 
 namespace mozilla {
+
+namespace wr {
+class WebRenderAPI;
+}
+
 namespace layers {
 
 class CompositableHost;
+class WebRenderTextureHost;
 
 class WebRenderCompositableHolder final
 {
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WebRenderCompositableHolder)
 
   explicit WebRenderCompositableHolder();
 
 protected:
-  virtual ~WebRenderCompositableHolder();
+  ~WebRenderCompositableHolder();
 
 public:
-
-  virtual void Destroy();
-
-  void AddExternalImageId(uint64_t aExternalImageId, CompositableHost* aHost);
-  void RemoveExternalImageId(uint64_t aExternalImageId);
-  void UpdateExternalImages();
+  void Destroy();
+  void HoldExternalImage(const wr::Epoch& aEpoch, WebRenderTextureHost* aTexture);
+  void Update(const wr::Epoch& aEpoch);
 
 private:
 
-  // Holds CompositableHosts that are bound to external image ids.
-  nsDataHashtable<nsUint64HashKey, RefPtr<CompositableHost> > mCompositableHosts;
+  struct ForwardingTextureHosts {
+    ForwardingTextureHosts(const wr::Epoch& aEpoch, TextureHost* aTexture)
+      : mEpoch(aEpoch)
+      , mTexture(aTexture)
+    {}
+    wr::Epoch mEpoch;
+    CompositableTextureHostRef mTexture;
+  };
+
+  // Holds forwarding WebRenderTextureHosts.
+  std::queue<ForwardingTextureHosts> mWebRenderTextureHosts;
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif /* MOZILLA_GFX_WEBRENDERCOMPOSITABLE_HOLDER_H */
--- a/gfx/layers/wr/WebRenderImageHost.cpp
+++ b/gfx/layers/wr/WebRenderImageHost.cpp
@@ -97,17 +97,20 @@ WebRenderImageHost::GetCompositionTime()
 {
   // XXX temporary workaround
   return TimeStamp::Now();
 }
 
 TextureHost*
 WebRenderImageHost::GetAsTextureHost(IntRect* aPictureRect)
 {
-  MOZ_ASSERT_UNREACHABLE("unexpected to be called");
+  TimedImage* img = ChooseImage();
+  if (img) {
+    return img->mTextureHost;
+  }
   return nullptr;
 }
 
 void WebRenderImageHost::Attach(Layer* aLayer,
                        Compositor* aCompositor,
                        AttachFlags aFlags)
 {
   MOZ_ASSERT_UNREACHABLE("unexpected to be called");
--- a/gfx/layers/wr/WebRenderImageHost.h
+++ b/gfx/layers/wr/WebRenderImageHost.h
@@ -57,16 +57,18 @@ public:
   virtual already_AddRefed<gfx::DataSourceSurface> GetAsSurface() override;
 
   virtual bool Lock() override;
 
   virtual void Unlock() override;
 
   virtual void CleanupResources() override;
 
+  virtual WebRenderImageHost* AsWebRenderImageHost() override { return this; }
+
 protected:
   // ImageComposite
   virtual TimeStamp GetCompositionTime() const override;
 };
 
 } // namespace layers
 } // namespace mozilla
 
--- a/gfx/layers/wr/WebRenderLayerManager.cpp
+++ b/gfx/layers/wr/WebRenderLayerManager.cpp
@@ -343,17 +343,17 @@ WebRenderLayerManager::MakeSnapshotIfReq
   // Only BufferTexture is supported now.
 
   // TODO: fixup for proper surface format.
   RefPtr<TextureClient> texture =
     TextureClient::CreateForRawBufferAccess(WrBridge(),
                                             SurfaceFormat::B8G8R8A8,
                                             aSize.ToUnknownSize(),
                                             BackendType::SKIA,
-                                            TextureFlags::DEFAULT);
+                                            TextureFlags::SNAPSHOT);
   if (!texture) {
     return;
   }
 
   texture->InitIPDLActor(WrBridge());
   if (!texture->GetIPDLActor()) {
     return;
   }
new file mode 100644
--- /dev/null
+++ b/gfx/layers/wr/WebRenderTextureHost.cpp
@@ -0,0 +1,109 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * 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 "WebRenderTextureHost.h"
+
+#include "mozilla/webrender/RenderTextureHost.h"
+#include "mozilla/webrender/RenderThread.h"
+
+namespace mozilla {
+namespace layers {
+
+uint64_t WebRenderTextureHost::sSerialCounter(0);
+
+WebRenderTextureHost::WebRenderTextureHost(TextureFlags aFlags,
+                                           TextureHost* aTexture)
+  : TextureHost(aFlags)
+  , mExternalImageId(++sSerialCounter)
+{
+  MOZ_COUNT_CTOR(WebRenderTextureHost);
+  mWrappedTextureHost = aTexture;
+
+  // XXX support only BufferTextureHost for now.
+  BufferTextureHost* bufferTexture = aTexture->AsBufferTextureHost();
+  MOZ_ASSERT(bufferTexture);
+  RefPtr<wr::RenderTextureHost> texture =
+    new wr::RenderTextureHost(bufferTexture->GetBuffer(),
+                              bufferTexture->GetBufferDescriptor());
+  wr::RenderThread::Get()->RegisterExternalImage(mExternalImageId, texture);
+}
+
+WebRenderTextureHost::~WebRenderTextureHost()
+{
+  MOZ_COUNT_DTOR(WebRenderTextureHost);
+  wr::RenderThread::Get()->UnregisterExternalImage(mExternalImageId);
+}
+
+bool
+WebRenderTextureHost::Lock()
+{
+  MOZ_ASSERT_UNREACHABLE("unexpected to be called");
+  return false;
+}
+
+void
+WebRenderTextureHost::Unlock()
+{
+  MOZ_ASSERT_UNREACHABLE("unexpected to be called");
+  return;
+}
+
+bool
+WebRenderTextureHost::BindTextureSource(CompositableTextureSourceRef& aTexture)
+{
+  MOZ_ASSERT_UNREACHABLE("unexpected to be called");
+  return false;
+}
+
+already_AddRefed<gfx::DataSourceSurface>
+WebRenderTextureHost::GetAsSurface()
+{
+  if (!mWrappedTextureHost) {
+    return nullptr;
+  }
+  return mWrappedTextureHost->GetAsSurface();
+}
+
+Compositor*
+WebRenderTextureHost::GetCompositor()
+{
+  //MOZ_ASSERT_UNREACHABLE("unexpected to be called");
+  return nullptr;
+}
+
+void
+WebRenderTextureHost::SetCompositor(Compositor* aCompositor)
+{
+}
+
+YUVColorSpace
+WebRenderTextureHost::GetYUVColorSpace() const
+{
+  if (mWrappedTextureHost) {
+    return mWrappedTextureHost->GetYUVColorSpace();
+  }
+  return YUVColorSpace::UNKNOWN;
+}
+
+gfx::IntSize
+WebRenderTextureHost::GetSize() const
+{
+  if (!mWrappedTextureHost) {
+    return gfx::IntSize();
+  }
+  return mWrappedTextureHost->GetSize();
+}
+
+gfx::SurfaceFormat
+WebRenderTextureHost::GetFormat() const
+{
+  if (!mWrappedTextureHost) {
+    return gfx::SurfaceFormat::UNKNOWN;
+  }
+  return mWrappedTextureHost->GetFormat();
+}
+
+} // namespace layers
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/layers/wr/WebRenderTextureHost.h
@@ -0,0 +1,58 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * 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/. */
+
+#ifndef MOZILLA_GFX_WEBRENDERTEXTUREHOST_H
+#define MOZILLA_GFX_WEBRENDERTEXTUREHOST_H
+
+#include "mozilla/layers/TextureHost.h"
+
+namespace mozilla {
+namespace layers {
+
+class WebRenderTextureHost : public TextureHost
+{
+public:
+  WebRenderTextureHost(TextureFlags aFlags,
+                       TextureHost* aTexture);
+  virtual ~WebRenderTextureHost();
+
+  virtual void DeallocateDeviceData() override {}
+
+  virtual void SetCompositor(Compositor* aCompositor) override;
+
+  virtual Compositor* GetCompositor() override;
+
+  virtual bool Lock() override;
+
+  virtual void Unlock() override;
+
+  virtual gfx::SurfaceFormat GetFormat() const override;
+
+  virtual bool BindTextureSource(CompositableTextureSourceRef& aTexture) override;
+
+  virtual already_AddRefed<gfx::DataSourceSurface> GetAsSurface() override;
+
+  virtual YUVColorSpace GetYUVColorSpace() const override;
+
+  virtual gfx::IntSize GetSize() const override;
+
+#ifdef MOZ_LAYERS_HAVE_LOG
+  virtual const char* Name() override { return "WebRenderTextureHost"; }
+#endif
+
+  virtual WebRenderTextureHost* AsWebRenderTextureHost() override { return this; }
+
+  uint64_t GetExternalImageKey() { return mExternalImageId; }
+protected:
+  RefPtr<TextureHost> mWrappedTextureHost;
+  uint64_t mExternalImageId;
+
+  static uint64_t sSerialCounter;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif // MOZILLA_GFX_WEBRENDERTEXTUREHOST_H
--- a/gfx/tests/gtest/TestTextures.cpp
+++ b/gfx/tests/gtest/TestTextures.cpp
@@ -143,16 +143,17 @@ void TestTextureClientSurface(TextureCli
   // client serialization
   SurfaceDescriptor descriptor;
   ASSERT_TRUE(texture->ToSurfaceDescriptor(descriptor));
 
   ASSERT_NE(descriptor.type(), SurfaceDescriptor::Tnull_t);
 
   // host deserialization
   RefPtr<TextureHost> host = CreateBackendIndependentTextureHost(descriptor, nullptr,
+                                                                 LayersBackend::LAYERS_NONE,
                                                                  texture->GetFlags());
 
   ASSERT_TRUE(host.get() != nullptr);
   ASSERT_EQ(host->GetFlags(), texture->GetFlags());
 
   // host read
 
   // XXX - this can fail because lock tries to upload the texture but it needs a
@@ -187,16 +188,17 @@ void TestTextureClientYCbCr(TextureClien
   ASSERT_EQ(bufferDesc.desc().type(), BufferDescriptor::TYCbCrDescriptor);
   auto ycbcrDesc = bufferDesc.desc().get_YCbCrDescriptor();
   ASSERT_EQ(ycbcrDesc.ySize(), ycbcrData.mYSize);
   ASSERT_EQ(ycbcrDesc.cbCrSize(), ycbcrData.mCbCrSize);
   ASSERT_EQ(ycbcrDesc.stereoMode(), ycbcrData.mStereoMode);
 
   // host deserialization
   RefPtr<TextureHost> textureHost = CreateBackendIndependentTextureHost(descriptor, nullptr,
+                                                                        LayersBackend::LAYERS_NONE,
                                                                         client->GetFlags());
 
   RefPtr<BufferTextureHost> host = static_cast<BufferTextureHost*>(textureHost.get());
 
   ASSERT_TRUE(host.get() != nullptr);
   ASSERT_EQ(host->GetFlags(), client->GetFlags());
 
   // host read
new file mode 100644
--- /dev/null
+++ b/gfx/webrender_bindings/RenderTextureHost.cpp
@@ -0,0 +1,118 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * 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 "RenderTextureHost.h"
+
+#include "mozilla/gfx/Logging.h"
+#include "mozilla/layers/ImageDataSerializer.h"
+
+namespace mozilla {
+
+using namespace gfx;
+using namespace layers;
+
+namespace wr {
+
+RenderTextureHost::RenderTextureHost(uint8_t* aBuffer, const BufferDescriptor& aDescriptor)
+  : mBuffer(aBuffer)
+  , mDescriptor(aDescriptor)
+  , mLocked(false)
+{
+  MOZ_COUNT_CTOR(RenderTextureHost);
+
+  switch (mDescriptor.type()) {
+    case BufferDescriptor::TYCbCrDescriptor: {
+      const YCbCrDescriptor& ycbcr = mDescriptor.get_YCbCrDescriptor();
+      mSize = ycbcr.ySize();
+      mFormat = gfx::SurfaceFormat::YUV;
+      break;
+    }
+    case BufferDescriptor::TRGBDescriptor: {
+      const RGBDescriptor& rgb = mDescriptor.get_RGBDescriptor();
+      mSize = rgb.size();
+      mFormat = rgb.format();
+      break;
+    }
+    default:
+      gfxCriticalError() << "Bad buffer host descriptor " << (int)mDescriptor.type();
+      MOZ_CRASH("GFX: Bad descriptor");
+  }
+}
+
+RenderTextureHost::~RenderTextureHost()
+{
+  MOZ_COUNT_DTOR(RenderTextureHost);
+}
+
+already_AddRefed<gfx::DataSourceSurface>
+RenderTextureHost::GetAsSurface()
+{
+  RefPtr<gfx::DataSourceSurface> result;
+  if (mFormat == gfx::SurfaceFormat::YUV) {
+    result = ImageDataSerializer::DataSourceSurfaceFromYCbCrDescriptor(
+      GetBuffer(), mDescriptor.get_YCbCrDescriptor());
+    if (NS_WARN_IF(!result)) {
+      return nullptr;
+    }
+  } else {
+    result =
+      gfx::Factory::CreateWrappingDataSourceSurface(GetBuffer(),
+        ImageDataSerializer::GetRGBStride(mDescriptor.get_RGBDescriptor()),
+        mSize, mFormat);
+  }
+  return result.forget();
+}
+
+bool
+RenderTextureHost::Lock()
+{
+  MOZ_ASSERT(!mLocked);
+
+  // XXX temporal workaround for YUV handling
+  if (!mSurface) {
+    mSurface = GetAsSurface();
+    if (!mSurface) {
+      return false;
+    }
+  }
+
+  if (NS_WARN_IF(!mSurface->Map(DataSourceSurface::MapType::READ_WRITE, &mMap))) {
+    mSurface = nullptr;
+    return false;
+  }
+
+  mLocked = true;
+  return true;
+}
+
+void
+RenderTextureHost::Unlock()
+{
+  MOZ_ASSERT(mLocked);
+  mLocked = false;
+  if (mSurface) {
+    mSurface->Unmap();
+  }
+  mSurface = nullptr;
+}
+
+uint8_t*
+RenderTextureHost::GetDataForRender() const
+{
+  MOZ_ASSERT(mLocked);
+  MOZ_ASSERT(mSurface);
+  return mMap.mData;
+}
+
+size_t
+RenderTextureHost::GetBufferSizeForRender() const
+{
+  MOZ_ASSERT(mLocked);
+  MOZ_ASSERT(mSurface);
+  return mMap.mStride * mSurface->GetSize().height;
+}
+
+} // namespace wr
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/webrender_bindings/RenderTextureHost.h
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * 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/. */
+
+#ifndef MOZILLA_GFX_RENDERTEXTUREHOST_H
+#define MOZILLA_GFX_RENDERTEXTUREHOST_H
+
+#include "nsISupportsImpl.h"
+#include "mozilla/gfx/2D.h"
+#include "mozilla/layers/LayersSurfaces.h"
+#include "mozilla/RefPtr.h"
+
+namespace mozilla {
+namespace wr {
+
+class RenderTextureHost
+{
+public:
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RenderTextureHost)
+
+  RenderTextureHost(uint8_t* aBuffer, const layers::BufferDescriptor& aDescriptor);
+
+  bool Lock();
+
+  void Unlock();
+
+  gfx::IntSize GetSize() const { return mSize; }
+
+  gfx::SurfaceFormat GetFormat() const { return mFormat; }
+
+  uint8_t* GetDataForRender() const;
+  size_t GetBufferSizeForRender() const;
+
+protected:
+  ~RenderTextureHost();
+  already_AddRefed<gfx::DataSourceSurface> GetAsSurface();
+  uint8_t* GetBuffer() const { return mBuffer; }
+
+  uint8_t* mBuffer;
+  layers::BufferDescriptor mDescriptor;
+  gfx::IntSize mSize;
+  gfx::SurfaceFormat mFormat;
+  RefPtr<gfx::DataSourceSurface> mSurface;
+  gfx::DataSourceSurface::MappedSurface mMap;
+  bool mLocked;
+};
+
+} // namespace wr
+} // namespace mozilla
+
+#endif // MOZILLA_GFX_RENDERTEXTUREHOST_H
--- a/gfx/webrender_bindings/RenderThread.cpp
+++ b/gfx/webrender_bindings/RenderThread.cpp
@@ -1,29 +1,31 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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 "RenderThread.h"
 #include "nsThreadUtils.h"
-#include "mozilla/webrender/RendererOGL.h"
-#include "mozilla/widget/CompositorWidget.h"
 #include "mozilla/layers/CompositorThread.h"
 #include "mozilla/layers/CompositorBridgeParent.h"
 #include "mozilla/StaticPtr.h"
+#include "mozilla/webrender/RendererOGL.h"
+#include "mozilla/webrender/RenderTextureHost.h"
+#include "mozilla/widget/CompositorWidget.h"
 #include "base/task.h"
 
 namespace mozilla {
 namespace wr {
 
 static StaticRefPtr<RenderThread> sRenderThread;
 
 RenderThread::RenderThread(base::Thread* aThread)
   : mThread(aThread)
+  , mRenderTextureMapLock("RenderThread.mRenderTextureMapLock")
 {
 
 }
 
 RenderThread::~RenderThread()
 {
   delete mThread;
 }
@@ -189,16 +191,40 @@ RenderThread::UpdateAndRender(wr::Window
   layers::CompositorThreadHolder::Loop()->PostTask(NewRunnableFunction(
     &NotifyDidRender,
     renderer->GetCompositorBridge(),
     epochs,
     start, end
   ));
 }
 
+void
+RenderThread::RegisterExternalImage(uint64_t aExternalImageId, RenderTextureHost* aTexture)
+{
+  MutexAutoLock lock(mRenderTextureMapLock);
+  MOZ_ASSERT(!mRenderTextures.Get(aExternalImageId));
+  mRenderTextures.Put(aExternalImageId, aTexture);
+}
+
+void
+RenderThread::UnregisterExternalImage(uint64_t aExternalImageId)
+{
+  MutexAutoLock lock(mRenderTextureMapLock);
+  MOZ_ASSERT(mRenderTextures.Get(aExternalImageId).get());
+  mRenderTextures.Remove(aExternalImageId);
+}
+
+RenderTextureHost*
+RenderThread::GetRenderTexture(uint64_t aExternalImageId)
+{
+  MutexAutoLock lock(mRenderTextureMapLock);
+  MOZ_ASSERT(mRenderTextures.Get(aExternalImageId).get());
+  return mRenderTextures.Get(aExternalImageId).get();
+}
+
 } // namespace wr
 } // namespace mozilla
 
 extern "C" {
 
 void wr_notifier_new_frame_ready(WrWindowId aWindowId)
 {
   mozilla::wr::RenderThread::Get()->NewFrameReady(mozilla::wr::WindowId(aWindowId));
--- a/gfx/webrender_bindings/RenderThread.h
+++ b/gfx/webrender_bindings/RenderThread.h
@@ -8,24 +8,26 @@
 #define MOZILLA_LAYERS_RENDERTHREAD_H
 
 #include "base/basictypes.h"            // for DISALLOW_EVIL_CONSTRUCTORS
 #include "base/platform_thread.h"       // for PlatformThreadId
 #include "base/thread.h"                // for Thread
 #include "base/message_loop.h"
 #include "nsISupportsImpl.h"
 #include "ThreadSafeRefcountingWithMainThreadDestruction.h"
+#include "mozilla/Mutex.h"
 #include "mozilla/webrender/webrender_ffi.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/webrender/WebRenderTypes.h"
 
 namespace mozilla {
 namespace wr {
 
 class RendererOGL;
+class RenderTextureHost;
 class RenderThread;
 
 /// Base class for an event that can be scheduled to run on the render thread.
 ///
 /// The event can be passed through the same channels as regular WebRender messages
 /// to preserve ordering.
 class RendererEvent
 {
@@ -94,23 +96,33 @@ public:
   /// Automatically forwarded to the render thread.
   void PipelineSizeChanged(wr::WindowId aWindowId, uint64_t aPipelineId, float aWidth, float aHeight);
 
   /// Automatically forwarded to the render thread.
   void RunEvent(wr::WindowId aWindowId, UniquePtr<RendererEvent> aCallBack);
 
   /// Can only be called from the render thread.
   void UpdateAndRender(wr::WindowId aWindowId);
+
+  void RegisterExternalImage(uint64_t aExternalImageId, RenderTextureHost* aTexture);
+
+  void UnregisterExternalImage(uint64_t aExternalImageId);
+
+  RenderTextureHost* GetRenderTexture(uint64_t aExternalImageId);
+
 private:
   explicit RenderThread(base::Thread* aThread);
 
   ~RenderThread();
 
 
   base::Thread* const mThread;
 
   std::map<wr::WindowId, UniquePtr<RendererOGL>> mRenderers;
+
+  Mutex mRenderTextureMapLock;
+  nsDataHashtable<nsUint64HashKey, RefPtr<RenderTextureHost> > mRenderTextures;
 };
 
 } // namespace wr
 } // namespace mozilla
 
 #endif
--- a/gfx/webrender_bindings/RendererOGL.cpp
+++ b/gfx/webrender_bindings/RendererOGL.cpp
@@ -4,28 +4,38 @@
  * 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/layers/CompositorBridgeParent.h"
 #include "mozilla/layers/CompositorThread.h"
+#include "mozilla/webrender/RenderTextureHost.h"
 #include "mozilla/widget/CompositorWidget.h"
 
 namespace mozilla {
 namespace wr {
 
 WrExternalImage LockExternalImage(void* aObj, WrExternalImageId aId)
 {
-  return WrExternalImage { /*WrExternalImageIdType::TextureHandle, */0.0f, 0.0f, 0.0f, 0.0f, 0 };
+  RendererOGL* renderer = reinterpret_cast<RendererOGL*>(aObj);
+  RenderTextureHost* texture = renderer->GetRenderTexture(aId.id);
+  MOZ_ASSERT(texture);
+  texture->Lock();
+  return WrExternalImage { WrExternalImageIdType::RawData, 0.0f, 0.0f, 0.0f, 0.0f, 0,
+                           texture->GetDataForRender(), texture->GetBufferSizeForRender() };
 }
 
 void UnlockExternalImage(void* aObj, WrExternalImageId aId)
 {
+  RendererOGL* renderer = reinterpret_cast<RendererOGL*>(aObj);
+  RenderTextureHost* texture = renderer->GetRenderTexture(aId.id);
+  MOZ_ASSERT(texture);
+  texture->Unlock();
 }
 
 void ReleaseExternalImage(void* aObj, WrExternalImageId aId)
 {
 }
 
 RendererOGL::RendererOGL(RefPtr<RenderThread>&& aThread,
                          RefPtr<gl::GLContext>&& aGL,
@@ -115,10 +125,16 @@ RendererOGL::SetProfilerEnabled(bool aEn
 }
 
 WrRenderedEpochs*
 RendererOGL::FlushRenderedEpochs()
 {
   return wr_renderer_flush_rendered_epochs(mWrRenderer);
 }
 
+RenderTextureHost*
+RendererOGL::GetRenderTexture(uint64_t aExternalImageId)
+{
+  return mThread->GetRenderTexture(aExternalImageId);
+}
+
 } // namespace wr
 } // namespace mozilla
--- a/gfx/webrender_bindings/RendererOGL.h
+++ b/gfx/webrender_bindings/RendererOGL.h
@@ -26,16 +26,18 @@ class CompositorBridgeParentBase;
 }
 
 namespace widget {
 class CompositorWidget;
 }
 
 namespace wr {
 
+class RenderTextureHost;
+
 /// Owns the WebRender renderer and GL context.
 ///
 /// There is one renderer per window, all owned by the render thread.
 /// This class is a similar abstraction to CompositorOGL except that it is used
 /// on the render thread instead of the compositor thread.
 class RendererOGL
 {
   friend WrExternalImage LockExternalImage(void* aObj, WrExternalImageId aId);
@@ -67,16 +69,18 @@ public:
               wr::WindowId aWindowId,
               WrRenderer* aWrRenderer,
               layers::CompositorBridgeParentBase* aBridge);
 
   layers::CompositorBridgeParentBase* GetCompositorBridge() { return mBridge; }
 
   WrRenderedEpochs* FlushRenderedEpochs();
 
+  RenderTextureHost* GetRenderTexture(uint64_t aExternalImageId);
+
 protected:
 
   RefPtr<RenderThread> mThread;
   RefPtr<gl::GLContext> mGL;
   RefPtr<widget::CompositorWidget> mWidget;
   WrRenderer* mWrRenderer;
   layers::CompositorBridgeParentBase* mBridge;
   wr::WindowId mWindowId;
--- a/gfx/webrender_bindings/WebRenderAPI.cpp
+++ b/gfx/webrender_bindings/WebRenderAPI.cpp
@@ -245,16 +245,52 @@ WebRenderAPI::Readback(gfx::IntSize size
     // read-back event. Then, we could make sure this read-back event gets the
     // latest result.
     RunOnRenderThread(Move(event));
 
     task.Wait();
 }
 
 void
+WebRenderAPI::WaitFlushed()
+{
+    class WaitFlushedEvent : public RendererEvent
+    {
+        public:
+            explicit WaitFlushedEvent(layers::SynchronousTask* aTask)
+                : mTask(aTask)
+            {
+                MOZ_COUNT_CTOR(WaitFlushedEvent);
+            }
+
+            ~WaitFlushedEvent()
+            {
+                MOZ_COUNT_DTOR(WaitFlushedEvent);
+            }
+
+            virtual void Run(RenderThread& aRenderThread, WindowId aWindowId) override
+            {
+                layers::AutoCompleteTask complete(mTask);
+            }
+
+            layers::SynchronousTask* mTask;
+    };
+
+    layers::SynchronousTask task("WaitFlushed");
+    auto event = MakeUnique<WaitFlushedEvent>(&task);
+    // This event will be passed from wr_backend thread to renderer thread. That
+    // implies that all frame data have been processed when the renderer runs this
+    // read-back event. Then, we could make sure this read-back event gets the
+    // latest result.
+    RunOnRenderThread(Move(event));
+
+    task.Wait();
+}
+
+void
 WebRenderAPI::SetRootPipeline(PipelineId aPipeline)
 {
   wr_api_set_root_pipeline(mWrApi, aPipeline);
 }
 
 void
 WebRenderAPI::AddImage(ImageKey key, const ImageDescriptor& aDescritptor,
                        Range<uint8_t> aBytes)
--- a/gfx/webrender_bindings/WebRenderAPI.h
+++ b/gfx/webrender_bindings/WebRenderAPI.h
@@ -17,26 +17,25 @@
 namespace mozilla {
 
 namespace widget {
 class CompositorWidget;
 }
 
 namespace layers {
 class CompositorBridgeParentBase;
+class WebRenderBridgeParent;
 }
 
 namespace wr {
 
 class DisplayListBuilder;
 class RendererOGL;
 class RendererEvent;
 
-
-
 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,
@@ -101,23 +100,26 @@ protected:
   WebRenderAPI(WrAPI* aRawApi, wr::WindowId aId, GLint aMaxTextureSize, bool aUseANGLE)
     : mWrApi(aRawApi)
     , mId(aId)
     , mMaxTextureSize(aMaxTextureSize)
     , mUseANGLE(aUseANGLE)
   {}
 
   ~WebRenderAPI();
+  // Should be used only for shutdown handling
+  void WaitFlushed();
 
   WrAPI* mWrApi;
   wr::WindowId mId;
   GLint mMaxTextureSize;
   bool mUseANGLE;
 
   friend class DisplayListBuilder;
+  friend class layers::WebRenderBridgeParent;
 };
 
 /// This is a simple C++ wrapper around WrState defined in the rust bindings.
 /// We may want to turn this into a direct wrapper on top of WebRenderFrameBuilder
 /// instead, so the interface may change a bit.
 class DisplayListBuilder {
 public:
   explicit DisplayListBuilder(wr::PipelineId aId);
--- a/gfx/webrender_bindings/moz.build
+++ b/gfx/webrender_bindings/moz.build
@@ -4,23 +4,25 @@
 # 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/.
 
 with Files('**'):
     BUG_COMPONENT = ('Core', 'Graphics: WebRender')
 
 EXPORTS.mozilla.webrender += [
     'RendererOGL.h',
+    'RenderTextureHost.h',
     'RenderThread.h',
     'webrender_ffi.h',
     'WebRenderAPI.h',
     'WebRenderTypes.h',
 ]
 
 UNIFIED_SOURCES += [
     'RendererOGL.cpp',
+    'RenderTextureHost.cpp',
     'RenderThread.cpp',
     'WebRenderAPI.cpp',
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul'
--- a/gfx/webrender_bindings/src/bindings.rs
+++ b/gfx/webrender_bindings/src/bindings.rs
@@ -486,39 +486,39 @@ impl WebRenderFrameBuilder {
 }
 
 pub struct WrState {
     pipeline_id: PipelineId,
     z_index: i32,
     frame_builder: WebRenderFrameBuilder,
 }
 
-// TODO(Jerry): handle shmem or cpu raw buffers.
-//#[repr(C)]
-//enum WrExternalImageType {
-//    TextureHandle,
-//    MemOrShmem,
-//}
+#[repr(C)]
+#[allow(dead_code)]
+enum WrExternalImageType {
+    NativeTexture,
+    RawData,
+}
 
 #[repr(C)]
 struct WrExternalImageStruct {
-    //image_type: WrExternalImageType,
+    image_type: WrExternalImageType,
 
     // Texture coordinate
     u0: f32,
     v0: f32,
     u1: f32,
     v1: f32,
 
     // external buffer handle
     handle: u32,
 
-    // TODO(Jerry): handle shmem or cpu raw buffers.
-    //// buff: *const u8,
-    //// size: usize,
+    // handle RawData.
+    buff: *const u8,
+    size: usize,
 }
 
 type LockExternalImageCallback = fn(*mut c_void, ExternalImageId) -> WrExternalImageStruct;
 type UnlockExternalImageCallback = fn(*mut c_void, ExternalImageId);
 type ReleaseExternalImageCallback = fn(*mut c_void, ExternalImageId);
 
 #[repr(C)]
 pub struct WrExternalImageHandler {
@@ -527,27 +527,34 @@ pub struct WrExternalImageHandler {
     unlock_func: UnlockExternalImageCallback,
     release_func: ReleaseExternalImageCallback,
 }
 
 impl ExternalImageHandler for WrExternalImageHandler {
     fn lock(&mut self, id: ExternalImageId) -> ExternalImage {
         let image = (self.lock_func)(self.external_image_obj, id);
 
-        // TODO(Jerry): handle shmem or cpu raw buffers.
-        //match image.image_type {
-        //    WrExternalImageType::TextureHandle =>
+        match image.image_type {
+            WrExternalImageType::NativeTexture =>
                 ExternalImage {
                     u0: image.u0,
                     v0: image.v0,
                     u1: image.u1,
                     v1: image.v1,
                     source: ExternalImageSource::NativeTexture(image.handle)
-                }
-        //}
+                },
+            WrExternalImageType::RawData =>
+                ExternalImage {
+                    u0: image.u0,
+                    v0: image.v0,
+                    u1: image.u1,
+                    v1: image.v1,
+                    source: ExternalImageSource::RawData(unsafe { slice::from_raw_parts(image.buff, image.size)})
+                },
+        }
     }
 
     fn unlock(&mut self, id: ExternalImageId) {
         (self.unlock_func)(self.external_image_obj, id);
     }
 
     fn release(&mut self, id: ExternalImageId) {
         (self.release_func)(self.external_image_obj, id);
--- a/gfx/webrender_bindings/webrender_ffi.h
+++ b/gfx/webrender_bindings/webrender_ffi.h
@@ -18,16 +18,19 @@ struct WrType {                         
     return mHandle == rhs.mHandle;                \
   }                                               \
   bool operator!=(const WrType& rhs) const {      \
     return mHandle != rhs.mHandle;                \
   }                                               \
   bool operator<(const WrType& rhs) const {       \
     return mHandle < rhs.mHandle;                 \
   }                                               \
+  bool operator<=(const WrType& rhs) const {      \
+    return mHandle <= rhs.mHandle;                \
+  }                                               \
 };                                                \
 // ---
 
 // ---
 #define WR_DECL_FFI_2(WrType, t1, t2)             \
 struct WrType {                                   \
   t1 mNamespace;                                  \
   t2 mHandle;                                     \
@@ -110,24 +113,23 @@ enum class WrImageRendering: uint32_t
 {
   Auto        = 0,
   CrispEdges  = 1,
   Pixelated   = 2,
 
   Sentinel /* this must be last, for IPC serialization purposes */
 };
 
-// TODO(Jerry): handle shmem or cpu raw buffers.
-//enum class WrExternalImageIdType: uint32_t
-//{
-//  TextureHandle = 0,
-//  MemOrShmem    = 1,
-//
-//  Sentinel /* this must be last, for IPC serialization purposes */
-//};
+enum class WrExternalImageIdType: uint32_t
+{
+  NativeTexture, // Currently, we only support gl texture handle.
+  RawData,
+
+  Sentinel /* this must be last, for IPC serialization purposes */
+};
 
 enum class WrMixBlendMode: uint32_t
 {
   Normal      = 0,
   Multiply    = 1,
   Screen      = 2,
   Overlay     = 3,
   Darken      = 4,
@@ -304,29 +306,28 @@ struct WrImageMask
 
 struct WrExternalImageId
 {
   WrImageIdType id;
 };
 
 struct WrExternalImage
 {
-  //WrExternalImageIdType type;
+  WrExternalImageIdType type;
 
   // Texture coordinate
   float u0, v0;
   float u1, v1;
 
   // external buffer handle
   uint32_t handle;
 
-  // TODO(Jerry): handle shmem or cpu raw buffers.
-  //// shmem or memory buffer
-  //// uint8_t* buff;
-  //// size_t size;
+  // handle RawData.
+  uint8_t* buff;
+  size_t size;
 };
 
 typedef WrExternalImage (*LockExternalImageCallback)(void*, WrExternalImageId);
 typedef void (*UnlockExternalImageCallback)(void*, WrExternalImageId);
 typedef void (*ReleaseExternalImageCallback)(void*, WrExternalImageId);
 
 struct WrExternalImageHandler
 {