Bug 1265824 - Pass the texture direct mapping info to all texture creating functions r=mattwoodrow
☠☠ backed out by 0051840a2dd0 ☠ ☠
authorDoug Thayer <dothayer@mozilla.com>
Wed, 02 May 2018 18:20:25 -0700
changeset 427223 984133e9614baa845a6dca7fc2cc6ca50cbb1687
parent 427222 efce316a4425c1e91f9b409806c6df3e6a7df99b
child 427224 4731dc56702d56283e2b1b9044afa571347d88e3
push id34296
push userrgurzau@mozilla.com
push dateThu, 19 Jul 2018 09:52:36 +0000
treeherdermozilla-central@25c83a66f294 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow
bugs1265824
milestone63.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 1265824 - Pass the texture direct mapping info to all texture creating functions r=mattwoodrow The client side can't get the GL context in CompositorOGL. So, it can't know the texture direct mapping capability directly. This patch adds the texture direct mapping info in TextureFactoryIdentifier. Then, the client side could get the info form the TextureFactoryIdentifier. MozReview-Commit-ID: KEazDVg0p9Y
gfx/layers/BufferTexture.cpp
gfx/layers/BufferTexture.h
gfx/layers/CompositorTypes.h
gfx/layers/client/ContentClient.cpp
gfx/layers/client/TextureClient.cpp
gfx/layers/client/TextureClient.h
gfx/layers/client/TextureClientPool.cpp
gfx/layers/client/TextureClientPool.h
gfx/layers/ipc/CompositorBridgeChild.cpp
gfx/layers/ipc/KnowsCompositor.h
gfx/layers/ipc/LayersMessageUtils.h
gfx/layers/ipc/SharedPlanarYCbCrImage.cpp
gfx/layers/opengl/CompositorOGL.cpp
gfx/layers/opengl/CompositorOGL.h
--- a/gfx/layers/BufferTexture.cpp
+++ b/gfx/layers/BufferTexture.cpp
@@ -100,18 +100,23 @@ static bool UsingX11Compositor()
 {
 #ifdef MOZ_WIDGET_GTK
   return gfx::gfxVars::UseXRender();
 #endif
   return false;
 }
 
 bool ComputeHasIntermediateBuffer(gfx::SurfaceFormat aFormat,
-                                  LayersBackend aLayersBackend)
+                                  LayersBackend aLayersBackend,
+                                  bool aSupportsTextureDirectMapping)
 {
+  if (aSupportsTextureDirectMapping) {
+    return false;
+  }
+
   return aLayersBackend != LayersBackend::LAYERS_BASIC
       || UsingX11Compositor()
       || aFormat == gfx::SurfaceFormat::UNKNOWN;
 }
 
 BufferTextureData*
 BufferTextureData::Create(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
                           gfx::BackendType aMoz2DBackend,
@@ -163,17 +168,18 @@ BufferTextureData::CreateForYCbCrWithBuf
                                                 uint32_t aBitDepth,
                                                 TextureFlags aTextureFlags)
 {
   if (aBufferSize == 0 || !gfx::Factory::CheckBufferSize(aBufferSize)) {
     return nullptr;
   }
 
   bool hasIntermediateBuffer = aAllocator ? ComputeHasIntermediateBuffer(gfx::SurfaceFormat::YUV,
-                                                                         aAllocator->GetCompositorBackendType())
+                                                                         aAllocator->GetCompositorBackendType(),
+                                                                         aAllocator->SupportsTextureDirectMapping())
                                           : true;
 
   // Initialize the metadata with something, even if it will have to be rewritten
   // afterwards since we don't know the dimensions of the texture at this point.
   BufferDescriptor desc = YCbCrDescriptor(gfx::IntSize(), 0, gfx::IntSize(), 0,
                                           0, 0, 0, StereoMode::MONO,
                                           aYUVColorSpace,
                                           aBitDepth,
@@ -205,17 +211,18 @@ BufferTextureData::CreateForYCbCr(KnowsC
   uint32_t crOffset;
   ImageDataSerializer::ComputeYCbCrOffsets(aYStride, aYSize.height,
                                            aCbCrStride, aCbCrSize.height,
                                            yOffset, cbOffset, crOffset);
 
   bool hasIntermediateBuffer =
     aAllocator
       ? ComputeHasIntermediateBuffer(gfx::SurfaceFormat::YUV,
-                                     aAllocator->GetCompositorBackendType())
+                                     aAllocator->GetCompositorBackendType(),
+                                     aAllocator->SupportsTextureDirectMapping())
       : true;
 
   YCbCrDescriptor descriptor = YCbCrDescriptor(aYSize, aYStride,
                                                aCbCrSize, aCbCrStride,
                                                yOffset, cbOffset, crOffset,
                                                aStereoMode,
                                                aYUVColorSpace,
                                                aBitDepth,
@@ -520,17 +527,19 @@ MemoryTextureData::Create(gfx::IntSize a
     return nullptr;
   }
 
   uint8_t* buf = new (fallible) uint8_t[bufSize];
   if (!InitBuffer(buf, bufSize, aFormat, aAllocFlags, false)) {
     return nullptr;
   }
 
-  bool hasIntermediateBuffer = ComputeHasIntermediateBuffer(aFormat, aLayersBackend);
+  bool hasIntermediateBuffer = ComputeHasIntermediateBuffer(aFormat,
+                                                            aLayersBackend,
+                                                            aAllocFlags & ALLOC_ALLOW_DIRECT_MAPPING);
 
   GfxMemoryImageReporter::DidAlloc(buf);
 
   BufferDescriptor descriptor = RGBDescriptor(aSize, aFormat, hasIntermediateBuffer);
 
   return new MemoryTextureData(descriptor, aMoz2DBackend, buf, bufSize);
 }
 
@@ -596,17 +605,19 @@ ShmemTextureData::Create(gfx::IntSize aS
     return nullptr;
   }
 
   uint8_t* buf = shm.get<uint8_t>();
   if (!InitBuffer(buf, bufSize, aFormat, aAllocFlags, true)) {
     return nullptr;
   }
 
-  bool hasIntermediateBuffer = ComputeHasIntermediateBuffer(aFormat, aLayersBackend);
+  bool hasIntermediateBuffer = ComputeHasIntermediateBuffer(aFormat,
+                                                            aLayersBackend,
+                                                            aAllocFlags & ALLOC_ALLOW_DIRECT_MAPPING);
 
   BufferDescriptor descriptor = RGBDescriptor(aSize, aFormat, hasIntermediateBuffer);
 
   return new ShmemTextureData(descriptor, aMoz2DBackend, shm);
 
   return nullptr;
 }
 
--- a/gfx/layers/BufferTexture.h
+++ b/gfx/layers/BufferTexture.h
@@ -12,17 +12,18 @@
 #include "mozilla/gfx/Types.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/RefPtr.h"
 
 namespace mozilla {
 namespace layers {
 
 bool ComputeHasIntermediateBuffer(gfx::SurfaceFormat aFormat,
-                                  LayersBackend aLayersBackend);
+                                  LayersBackend aLayersBackend,
+                                  bool aSupportsTextureDirectMapping);
 
 class BufferTextureData : public TextureData
 {
 public:
   static BufferTextureData* Create(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
                                    gfx::BackendType aMoz2DBackend,
                                    LayersBackend aLayersBackend,
                                    TextureFlags aFlags,
--- a/gfx/layers/CompositorTypes.h
+++ b/gfx/layers/CompositorTypes.h
@@ -170,51 +170,56 @@ typedef uintptr_t SyncHandle;
  * of the compositor and should (in the future) include information about what
  * kinds of buffer and texture clients to create.
  */
 struct TextureFactoryIdentifier
 {
   LayersBackend mParentBackend;
   GeckoProcessType mParentProcessType;
   int32_t mMaxTextureSize;
+  bool mSupportsTextureDirectMapping;
   bool mCompositorUseANGLE;
   bool mSupportsTextureBlitting;
   bool mSupportsPartialUploads;
   bool mSupportsComponentAlpha;
   bool mUsingAdvancedLayers;
   SyncHandle mSyncHandle;
 
   explicit TextureFactoryIdentifier(LayersBackend aLayersBackend = LayersBackend::LAYERS_NONE,
                                     GeckoProcessType aParentProcessType = GeckoProcessType_Default,
                                     int32_t aMaxTextureSize = 4096,
+                                    bool aSupportsTextureDirectMapping = false,
                                     bool aCompositorUseANGLE = false,
                                     bool aSupportsTextureBlitting = false,
                                     bool aSupportsPartialUploads = false,
                                     bool aSupportsComponentAlpha = true,
                                     SyncHandle aSyncHandle = 0)
     : mParentBackend(aLayersBackend)
     , mParentProcessType(aParentProcessType)
     , mMaxTextureSize(aMaxTextureSize)
+    , mSupportsTextureDirectMapping(aSupportsTextureDirectMapping)
     , mCompositorUseANGLE(aCompositorUseANGLE)
     , mSupportsTextureBlitting(aSupportsTextureBlitting)
     , mSupportsPartialUploads(aSupportsPartialUploads)
     , mSupportsComponentAlpha(aSupportsComponentAlpha)
     , mUsingAdvancedLayers(false)
     , mSyncHandle(aSyncHandle)
   {}
 
   bool operator==(const TextureFactoryIdentifier& aOther) const {
     return
       mParentBackend == aOther.mParentBackend &&
       mParentProcessType == aOther.mParentProcessType &&
       mMaxTextureSize == aOther.mMaxTextureSize &&
+      mSupportsTextureDirectMapping == aOther.mSupportsTextureDirectMapping &&
       mCompositorUseANGLE == aOther.mCompositorUseANGLE &&
       mSupportsTextureBlitting == aOther.mSupportsTextureBlitting &&
       mSupportsPartialUploads == aOther.mSupportsPartialUploads &&
       mSupportsComponentAlpha == aOther.mSupportsComponentAlpha &&
+      mUsingAdvancedLayers == aOther.mUsingAdvancedLayers &&
       mSyncHandle == aOther.mSyncHandle;
   }
 };
 
 /**
  * Information required by the compositor from the content-side for creating or
  * using compositables and textures.
  * XXX - TextureInfo is a bad name: this information is useful for the compositable,
--- a/gfx/layers/client/ContentClient.cpp
+++ b/gfx/layers/client/ContentClient.cpp
@@ -757,20 +757,24 @@ ContentClientRemoteBuffer::CreateBufferI
   );
 
   if (!textureClient || !AddTextureClient(textureClient)) {
     return nullptr;
   }
 
   RefPtr<TextureClient> textureClientOnWhite;
   if (aFlags & TextureFlags::COMPONENT_ALPHA) {
+    TextureAllocationFlags allocFlags = ALLOC_CLEAR_BUFFER_WHITE;
+    if (mForwarder->SupportsTextureDirectMapping()) {
+      allocFlags = TextureAllocationFlags(allocFlags | ALLOC_ALLOW_DIRECT_MAPPING);
+    }
     textureClientOnWhite = textureClient->CreateSimilar(
       mForwarder->GetCompositorBackendType(),
       aFlags | ExtraTextureFlags(),
-      TextureAllocationFlags::ALLOC_CLEAR_BUFFER_WHITE
+      allocFlags
     );
     if (!textureClientOnWhite || !AddTextureClient(textureClientOnWhite)) {
       return nullptr;
     }
     // We don't enable the readlock for the white buffer since we always
     // use them together and waiting on the lock for the black
     // should be sufficient.
   }
--- a/gfx/layers/client/TextureClient.cpp
+++ b/gfx/layers/client/TextureClient.cpp
@@ -655,27 +655,32 @@ TextureClient::UpdateFromSurface(gfx::So
       return;
     }
   }
   NS_WARNING("TextureClient::UpdateFromSurface failed");
 }
 
 
 already_AddRefed<TextureClient>
-TextureClient::CreateSimilar(LayersBackend aLayersBackend, TextureFlags aFlags, TextureAllocationFlags aAllocFlags) const
+TextureClient::CreateSimilar(LayersBackend aLayersBackend,
+                             TextureFlags aFlags,
+                             TextureAllocationFlags aAllocFlags) const
 {
   MOZ_ASSERT(IsValid());
 
   MOZ_ASSERT(!mIsLocked);
   if (mIsLocked) {
     return nullptr;
   }
 
   LockActor();
-  TextureData* data = mData->CreateSimilar(mAllocator, aLayersBackend, aFlags, aAllocFlags);
+  TextureData* data = mData->CreateSimilar(mAllocator,
+                                           aLayersBackend,
+                                           aFlags,
+                                           aAllocFlags);
   UnlockActor();
 
   if (!data) {
     return nullptr;
   }
 
   return MakeAndAddRef<TextureClient>(data, aFlags, mAllocator);
 }
@@ -1055,16 +1060,19 @@ already_AddRefed<TextureClient>
 TextureClient::CreateForDrawing(KnowsCompositor* aAllocator,
                                 gfx::SurfaceFormat aFormat,
                                 gfx::IntSize aSize,
                                 BackendSelector aSelector,
                                 TextureFlags aTextureFlags,
                                 TextureAllocationFlags aAllocFlags)
 {
   LayersBackend layersBackend = aAllocator->GetCompositorBackendType();
+  if (aAllocator->SupportsTextureDirectMapping()) {
+    aAllocFlags = TextureAllocationFlags(aAllocFlags | ALLOC_ALLOW_DIRECT_MAPPING);
+  }
   return TextureClient::CreateForDrawing(aAllocator->GetTextureForwarder(),
                                          aFormat, aSize,
                                          layersBackend,
                                          aAllocator->GetMaxTextureSize(),
                                          aSelector,
                                          aTextureFlags,
                                          aAllocFlags);
 }
@@ -1221,16 +1229,26 @@ TextureClient::CreateFromSurface(KnowsCo
 already_AddRefed<TextureClient>
 TextureClient::CreateForRawBufferAccess(KnowsCompositor* aAllocator,
                                         gfx::SurfaceFormat aFormat,
                                         gfx::IntSize aSize,
                                         gfx::BackendType aMoz2DBackend,
                                         TextureFlags aTextureFlags,
                                         TextureAllocationFlags aAllocFlags)
 {
+  // If we exceed the max texture size for the GPU, then just fall back to no
+  // texture direct mapping. If it becomes a problem we can implement tiling
+  // logic inside DirectMapTextureSource to allow this.
+  bool supportsTextureDirectMapping = aAllocator->SupportsTextureDirectMapping() &&
+    std::max(aSize.width, aSize.height) <= aAllocator->GetMaxTextureSize();
+  if (supportsTextureDirectMapping) {
+    aAllocFlags = TextureAllocationFlags(aAllocFlags | ALLOC_ALLOW_DIRECT_MAPPING);
+  } else {
+    aAllocFlags = TextureAllocationFlags(aAllocFlags & ~ALLOC_ALLOW_DIRECT_MAPPING);
+  }
   return CreateForRawBufferAccess(aAllocator->GetTextureForwarder(),
                                   aFormat, aSize, aMoz2DBackend,
                                   aAllocator->GetCompositorBackendType(),
                                   aTextureFlags, aAllocFlags);
 }
 
 // static
 already_AddRefed<TextureClient>
--- a/gfx/layers/client/TextureClient.h
+++ b/gfx/layers/client/TextureClient.h
@@ -89,16 +89,20 @@ enum TextureAllocationFlags {
 
   // Disable any cross-device synchronization. This is also for TextureClientD3D11,
   // and creates a texture without KeyedMutex.
   ALLOC_MANUAL_SYNCHRONIZATION = 1 << 6,
 
   // The texture is going to be updated using UpdateFromSurface and needs to support
   // that call.
   ALLOC_UPDATE_FROM_SURFACE = 1 << 7,
+
+  // In practice, this means we support the APPLE_client_storage extension, meaning
+  // the buffer will not be internally copied by the graphics driver.
+  ALLOC_ALLOW_DIRECT_MAPPING = 1 << 8,
 };
 
 /**
  * This class may be used to asynchronously receive an update when the content
  * drawn to this texture client is available for reading in CPU memory. This
  * can only be used on texture clients that support draw target creation.
  */
 class TextureReadbackSink
--- a/gfx/layers/client/TextureClientPool.cpp
+++ b/gfx/layers/client/TextureClientPool.cpp
@@ -34,16 +34,17 @@ ShrinkCallback(nsITimer *aTimer, void *a
 // at an inopportune time (e.g. mid-animation).
 static void
 ClearCallback(nsITimer *aTimer, void *aClosure)
 {
   static_cast<TextureClientPool*>(aClosure)->Clear();
 }
 
 TextureClientPool::TextureClientPool(LayersBackend aLayersBackend,
+                                     bool aSupportsTextureDirectMapping,
                                      int32_t aMaxTextureSize,
                                      gfx::SurfaceFormat aFormat,
                                      gfx::IntSize aSize,
                                      TextureFlags aFlags,
                                      uint32_t aShrinkTimeoutMsec,
                                      uint32_t aClearTimeoutMsec,
                                      uint32_t aInitialPoolSize,
                                      uint32_t aPoolUnusedSize,
@@ -55,16 +56,17 @@ TextureClientPool::TextureClientPool(Lay
   , mFlags(aFlags)
   , mShrinkTimeoutMsec(aShrinkTimeoutMsec)
   , mClearTimeoutMsec(aClearTimeoutMsec)
   , mInitialPoolSize(aInitialPoolSize)
   , mPoolUnusedSize(aPoolUnusedSize)
   , mOutstandingClients(0)
   , mSurfaceAllocator(aAllocator)
   , mDestroyed(false)
+  , mSupportsTextureDirectMapping(aSupportsTextureDirectMapping)
 {
   TCP_LOG("TexturePool %p created with maximum unused texture clients %u\n",
       this, mInitialPoolSize);
   mShrinkTimer = NS_NewTimer();
   mClearTimer = NS_NewTimer();
   if (aFormat == gfx::SurfaceFormat::UNKNOWN) {
     gfxWarning() << "Creating texture pool for SurfaceFormat::UNKNOWN format";
   }
@@ -144,33 +146,39 @@ TextureClientPool::GetTextureClient()
 }
 
 void
 TextureClientPool::AllocateTextureClient()
 {
   TCP_LOG("TexturePool %p allocating TextureClient, outstanding %u\n",
       this, mOutstandingClients);
 
+  TextureAllocationFlags allocFlags = ALLOC_DEFAULT;
+
+  if (mSupportsTextureDirectMapping) {
+    allocFlags = TextureAllocationFlags(allocFlags | ALLOC_ALLOW_DIRECT_MAPPING);
+  }
+
   RefPtr<TextureClient> newClient;
   if (gfxPrefs::ForceShmemTiles()) {
     // gfx::BackendType::NONE means use the content backend
     newClient =
       TextureClient::CreateForRawBufferAccess(mSurfaceAllocator,
                                               mFormat, mSize,
                                               gfx::BackendType::NONE,
                                               mBackend,
-                                              mFlags, ALLOC_DEFAULT);
+                                              mFlags, allocFlags);
   } else {
     newClient =
       TextureClient::CreateForDrawing(mSurfaceAllocator,
                                       mFormat, mSize,
                                       mBackend,
                                       mMaxTextureSize,
                                       BackendSelector::Content,
-                                      mFlags);
+                                      mFlags, allocFlags);
   }
 
   if (newClient) {
     mTextureClients.push(newClient);
   }
 }
 
 void
--- a/gfx/layers/client/TextureClientPool.h
+++ b/gfx/layers/client/TextureClientPool.h
@@ -41,16 +41,17 @@ public:
 };
 
 class TextureClientPool final : public TextureClientAllocator
 {
   virtual ~TextureClientPool();
 
 public:
   TextureClientPool(LayersBackend aBackend,
+                    bool aSupportsTextureDirectMapping,
                     int32_t aMaxTextureSize,
                     gfx::SurfaceFormat aFormat,
                     gfx::IntSize aSize,
                     TextureFlags aFlags,
                     uint32_t aShrinkTimeoutMsec,
                     uint32_t aClearTimeoutMsec,
                     uint32_t aInitialPoolSize,
                     uint32_t aPoolUnusedSize,
@@ -165,14 +166,16 @@ private:
   RefPtr<nsITimer> mClearTimer;
   // This mSurfaceAllocator owns us, so no need to hold a ref to it
   TextureForwarder* mSurfaceAllocator;
 
   // Keep track of whether this pool has been destroyed or not. If it has,
   // we won't accept returns of TextureClients anymore, and the refcounting
   // should take care of their destruction.
   bool mDestroyed;
+
+  bool mSupportsTextureDirectMapping;
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif /* MOZILLA_GFX_TEXTURECLIENTPOOL_H */
--- a/gfx/layers/ipc/CompositorBridgeChild.cpp
+++ b/gfx/layers/ipc/CompositorBridgeChild.cpp
@@ -931,16 +931,17 @@ CompositorBridgeChild::GetTexturePool(Kn
         mTexturePools[i]->GetFormat() == aFormat &&
         mTexturePools[i]->GetFlags() == aFlags) {
       return mTexturePools[i];
     }
   }
 
   mTexturePools.AppendElement(
       new TextureClientPool(aAllocator->GetCompositorBackendType(),
+                            aAllocator->SupportsTextureDirectMapping(),
                             aAllocator->GetMaxTextureSize(),
                             aFormat,
                             gfx::gfxVars::TileSize(),
                             aFlags,
                             gfxPrefs::LayersTilePoolShrinkTimeout(),
                             gfxPrefs::LayersTilePoolClearTimeout(),
                             gfxPrefs::LayersTileInitialPoolSize(),
                             gfxPrefs::LayersTilePoolUnusedSize(),
--- a/gfx/layers/ipc/KnowsCompositor.h
+++ b/gfx/layers/ipc/KnowsCompositor.h
@@ -97,16 +97,21 @@ public:
     return mTextureFactoryIdentifier.mSupportsPartialUploads;
   }
 
   bool SupportsComponentAlpha() const
   {
     return mTextureFactoryIdentifier.mSupportsComponentAlpha;
   }
 
+  bool SupportsTextureDirectMapping() const
+  {
+    return mTextureFactoryIdentifier.mSupportsTextureDirectMapping;
+  }
+
   bool SupportsD3D11() const
   {
     return GetCompositorBackendType() == layers::LayersBackend::LAYERS_D3D11 ||
            (GetCompositorBackendType() == layers::LayersBackend::LAYERS_WR && GetCompositorUseANGLE());
   }
 
   bool GetCompositorUseANGLE() const
   {
--- a/gfx/layers/ipc/LayersMessageUtils.h
+++ b/gfx/layers/ipc/LayersMessageUtils.h
@@ -330,29 +330,31 @@ struct ParamTraits<mozilla::layers::Text
 {
   typedef mozilla::layers::TextureFactoryIdentifier paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
     WriteParam(aMsg, aParam.mParentBackend);
     WriteParam(aMsg, aParam.mParentProcessType);
     WriteParam(aMsg, aParam.mMaxTextureSize);
+    WriteParam(aMsg, aParam.mSupportsTextureDirectMapping);
     WriteParam(aMsg, aParam.mCompositorUseANGLE);
     WriteParam(aMsg, aParam.mSupportsTextureBlitting);
     WriteParam(aMsg, aParam.mSupportsPartialUploads);
     WriteParam(aMsg, aParam.mSupportsComponentAlpha);
     WriteParam(aMsg, aParam.mUsingAdvancedLayers);
     WriteParam(aMsg, aParam.mSyncHandle);
   }
 
   static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     bool result = ReadParam(aMsg, aIter, &aResult->mParentBackend) &&
                   ReadParam(aMsg, aIter, &aResult->mParentProcessType) &&
                   ReadParam(aMsg, aIter, &aResult->mMaxTextureSize) &&
+                  ReadParam(aMsg, aIter, &aResult->mSupportsTextureDirectMapping) &&
                   ReadParam(aMsg, aIter, &aResult->mCompositorUseANGLE) &&
                   ReadParam(aMsg, aIter, &aResult->mSupportsTextureBlitting) &&
                   ReadParam(aMsg, aIter, &aResult->mSupportsPartialUploads) &&
                   ReadParam(aMsg, aIter, &aResult->mSupportsComponentAlpha) &&
                   ReadParam(aMsg, aIter, &aResult->mUsingAdvancedLayers) &&
                   ReadParam(aMsg, aIter, &aResult->mSyncHandle);
     return result;
   }
--- a/gfx/layers/ipc/SharedPlanarYCbCrImage.cpp
+++ b/gfx/layers/ipc/SharedPlanarYCbCrImage.cpp
@@ -110,18 +110,21 @@ SharedPlanarYCbCrImage::AdoptData(const 
   mOrigin = gfx::IntPoint(aData.mPicX, aData.mPicY);
 
   uint8_t *base = GetBuffer();
   uint32_t yOffset = aData.mYChannel - base;
   uint32_t cbOffset = aData.mCbChannel - base;
   uint32_t crOffset = aData.mCrChannel - base;
 
   auto fwd = mCompositable->GetForwarder();
+  bool supportsTextureDirectMapping = fwd->SupportsTextureDirectMapping() &&
+    std::max(mSize.width, mSize.height) <= fwd->GetMaxTextureSize();
   bool hasIntermediateBuffer = ComputeHasIntermediateBuffer(
-    gfx::SurfaceFormat::YUV, fwd->GetCompositorBackendType());
+    gfx::SurfaceFormat::YUV, fwd->GetCompositorBackendType(),
+    supportsTextureDirectMapping);
 
   static_cast<BufferTextureData*>(mTextureClient->GetInternalData())
     ->SetDesciptor(YCbCrDescriptor(aData.mYSize,
                                    aData.mYStride,
                                    aData.mCbCrSize,
                                    aData.mCbCrStride,
                                    yOffset,
                                    cbOffset,
--- a/gfx/layers/opengl/CompositorOGL.cpp
+++ b/gfx/layers/opengl/CompositorOGL.cpp
@@ -1915,16 +1915,28 @@ GLuint
 CompositorOGL::GetTemporaryTexture(GLenum aTarget, GLenum aUnit)
 {
   if (!mTexturePool) {
     mTexturePool = new PerUnitTexturePoolOGL(gl());
   }
   return mTexturePool->GetTexture(aTarget, aUnit);
 }
 
+bool
+CompositorOGL::SupportsTextureDirectMapping()
+{
+  if (mGLContext) {
+    mGLContext->MakeCurrent();
+    return mGLContext->IsExtensionSupported(gl::GLContext::APPLE_client_storage) &&
+           mGLContext->IsExtensionSupported(gl::GLContext::APPLE_texture_range);
+  }
+
+  return false;
+}
+
 GLuint
 PerUnitTexturePoolOGL::GetTexture(GLenum aTarget, GLenum aTextureUnit)
 {
   if (mTextureTarget == 0) {
     mTextureTarget = aTarget;
   }
   MOZ_ASSERT(mTextureTarget == aTarget);
 
--- a/gfx/layers/opengl/CompositorOGL.h
+++ b/gfx/layers/opengl/CompositorOGL.h
@@ -136,16 +136,17 @@ public:
   virtual void Destroy() override;
 
   virtual TextureFactoryIdentifier GetTextureFactoryIdentifier() override
   {
     TextureFactoryIdentifier result =
       TextureFactoryIdentifier(LayersBackend::LAYERS_OPENGL,
                                XRE_GetProcessType(),
                                GetMaxTextureSize(),
+                               SupportsTextureDirectMapping(),
                                false,
                                mFBOTextureTarget == LOCAL_GL_TEXTURE_2D,
                                SupportsPartialTextureUpdate());
     return result;
   }
 
   virtual already_AddRefed<CompositingRenderTarget>
   CreateRenderTarget(const gfx::IntRect &aRect, SurfaceInitMode aInit) override;
@@ -268,16 +269,18 @@ private:
                     const gfx::IntRect& aClipRect,
                     const EffectChain& aEffectChain,
                     gfx::Float aOpacity,
                     const gfx::Matrix4x4& aTransform,
                     const gfx::Rect& aVisibleRect);
 
   void PrepareViewport(CompositingRenderTargetOGL *aRenderTarget);
 
+  bool SupportsTextureDirectMapping();
+
   /** Widget associated with this compositor */
   LayoutDeviceIntSize mWidgetSize;
   RefPtr<GLContext> mGLContext;
   UniquePtr<GLBlitTextureImageHelper> mBlitTextureImageHelper;
   gfx::Matrix4x4 mProjMatrix;
 
   /** The size of the surface we are rendering to */
   gfx::IntSize mSurfaceSize;