Bug 900133 - Add TEXTURE_IMMEDIATE_UPLOAD to avoid racing when single buffered. r=nical
authorMatt Woodrow <mwoodrow@mozilla.com>
Sat, 03 Aug 2013 13:30:28 -0400
changeset 141311 64ab855db547f7d6a01d848b57b70f41e0496d44
parent 141310 fa5a3c887c7b07c15877167052705f6854bcfe01
child 141312 ea053dd62478deb0b81be664ec5c315017b9ba3a
push id25054
push usercbook@mozilla.com
push dateMon, 05 Aug 2013 09:19:53 +0000
treeherdermozilla-central@54434a926c5f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnical
bugs900133
milestone25.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 900133 - Add TEXTURE_IMMEDIATE_UPLOAD to avoid racing when single buffered. r=nical
gfx/layers/CompositorTypes.h
gfx/layers/client/CanvasClient.cpp
gfx/layers/client/CanvasClient.h
gfx/layers/client/ClientCanvasLayer.cpp
gfx/layers/client/CompositableClient.cpp
gfx/layers/client/CompositableClient.h
gfx/layers/client/ImageClient.cpp
gfx/layers/client/ImageClient.h
gfx/layers/client/TextureClient.cpp
gfx/layers/client/TextureClient.h
gfx/layers/composite/TextureHost.cpp
gfx/layers/composite/TextureHost.h
gfx/layers/ipc/ShadowLayers.cpp
--- a/gfx/layers/CompositorTypes.h
+++ b/gfx/layers/CompositorTypes.h
@@ -62,21 +62,40 @@ const TextureFlags TEXTURE_COPY_PREVIOUS
 // be a choice from another part of gecko that wants to keep the data alive
 // for some reason. The default behaviour is to deallocate on the host side.
 const TextureFlags TEXTURE_DEALLOCATE_CLIENT  = 1 << 25;
 const TextureFlags TEXTURE_DEALLOCATE_HOST    = 1 << 26;
 // After being shared ith the compositor side, an immutable texture is never
 // modified, it can only be read. It is safe to not Lock/Unlock immutable
 // textures.
 const TextureFlags TEXTURE_IMMUTABLE          = 1 << 27;
+// The contents of the texture must be uploaded or copied immediately
+// during the transaction, because the producer may want to write
+// to it again.
+const TextureFlags TEXTURE_IMMEDIATE_UPLOAD   = 1 << 28;
+// The texture is going to be used as part of a double
+// buffered pair, and so we can guarantee that the producer/consumer
+// won't be racing to access its contents.
+const TextureFlags TEXTURE_DOUBLE_BUFFERED    = 1 << 29;
 
 // the default flags
 const TextureFlags TEXTURE_FLAGS_DEFAULT = TEXTURE_DEALLOCATE_HOST
                                          | TEXTURE_FRONT;
 
+static inline bool
+TextureRequiresLocking(TextureFlags aFlags)
+{
+  // If we're not double buffered, or uploading
+  // within a transaction, then we need to support
+  // locking correctly.
+  return !(aFlags & (TEXTURE_IMMEDIATE_UPLOAD |
+                     TEXTURE_DOUBLE_BUFFERED |
+                     TEXTURE_IMMUTABLE));
+}
+
 /**
  * See gfx/layers/Effects.h
  */
 enum EffectTypes
 {
   EFFECT_MASK,
   EFFECT_MAX_SECONDARY, // sentinel for the count of secondary effect types
   EFFECT_BGRX,
--- a/gfx/layers/client/CanvasClient.cpp
+++ b/gfx/layers/client/CanvasClient.cpp
@@ -71,16 +71,23 @@ CanvasClient2D::Update(gfx::IntSize aSiz
   mBuffer->Unlock();
 
   if (surface) {
     GetForwarder()->UpdatedTexture(this, mBuffer, nullptr);
     GetForwarder()->UseTexture(this, mBuffer);
   }
 }
 
+TemporaryRef<BufferTextureClient>
+CanvasClient2D::CreateBufferTextureClient(gfx::SurfaceFormat aFormat)
+{
+  return CompositableClient::CreateBufferTextureClient(aFormat,
+                                                       mTextureInfo.mTextureFlags);
+}
+
 void
 DeprecatedCanvasClient2D::Updated()
 {
   mForwarder->UpdateTexture(this, 1, mDeprecatedTextureClient->GetDescriptor());
 }
 
 
 DeprecatedCanvasClient2D::DeprecatedCanvasClient2D(CompositableForwarder* aFwd,
--- a/gfx/layers/client/CanvasClient.h
+++ b/gfx/layers/client/CanvasClient.h
@@ -64,20 +64,23 @@ public:
   {
     return TextureInfo(COMPOSITABLE_IMAGE);
   }
 
   virtual void Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer) MOZ_OVERRIDE;
 
   virtual void AddTextureClient(TextureClient* aTexture) MOZ_OVERRIDE
   {
-    aTexture->AddFlags(mTextureInfo.mTextureFlags);
+    MOZ_ASSERT((mTextureInfo.mTextureFlags & aTexture->GetFlags()) == mTextureInfo.mTextureFlags);
     CompositableClient::AddTextureClient(aTexture);
   }
 
+  virtual TemporaryRef<BufferTextureClient>
+  CreateBufferTextureClient(gfx::SurfaceFormat aFormat) MOZ_OVERRIDE;
+
   virtual void Detach() MOZ_OVERRIDE
   {
     mBuffer = nullptr;
   }
 
 private:
   RefPtr<TextureClient> mBuffer;
 };
--- a/gfx/layers/client/ClientCanvasLayer.cpp
+++ b/gfx/layers/client/ClientCanvasLayer.cpp
@@ -76,17 +76,17 @@ ClientCanvasLayer::RenderLayer()
     return;
   }
 
   if (GetMaskLayer()) {
     ToClientLayer(GetMaskLayer())->RenderLayer();
   }
   
   if (!mCanvasClient) {
-    TextureFlags flags = 0;
+    TextureFlags flags = TEXTURE_IMMEDIATE_UPLOAD;
     if (mNeedsYFlip) {
       flags |= NeedsYFlip;
     }
 
     bool isCrossProcess = !(XRE_GetProcessType() == GeckoProcessType_Default);
     //Append TEXTURE_DEALLOCATE_CLIENT flag for streaming buffer under OOPC case
     if (isCrossProcess && mGLContext) {
       GLScreenBuffer* screen = mGLContext->Screen();
--- a/gfx/layers/client/CompositableClient.cpp
+++ b/gfx/layers/client/CompositableClient.cpp
@@ -142,26 +142,32 @@ CompositableClient::CreateDeprecatedText
   MOZ_ASSERT(result->SupportsType(aDeprecatedTextureClientType),
              "Created the wrong texture client?");
   result->SetFlags(GetTextureInfo().mTextureFlags);
 
   return result.forget();
 }
 
 TemporaryRef<BufferTextureClient>
-CompositableClient::CreateBufferTextureClient(gfx::SurfaceFormat aFormat)
+CompositableClient::CreateBufferTextureClient(gfx::SurfaceFormat aFormat,
+                                              uint32_t aTextureFlags)
 {
   if (gfxPlatform::GetPlatform()->PreferMemoryOverShmem()) {
-    RefPtr<BufferTextureClient> result = new MemoryTextureClient(this, aFormat);
+    RefPtr<BufferTextureClient> result = new MemoryTextureClient(this, aFormat, aTextureFlags);
     return result.forget();
   }
-  RefPtr<BufferTextureClient> result = new ShmemTextureClient(this, aFormat);
+  RefPtr<BufferTextureClient> result = new ShmemTextureClient(this, aFormat, aTextureFlags);
   return result.forget();
 }
 
+TemporaryRef<BufferTextureClient>
+CompositableClient::CreateBufferTextureClient(gfx::SurfaceFormat aFormat)
+{
+  return CreateBufferTextureClient(aFormat, TEXTURE_FLAGS_DEFAULT);
+}
 
 void
 CompositableClient::AddTextureClient(TextureClient* aClient)
 {
   ++mNextTextureID;
   // 0 is always an invalid ID
   if (mNextTextureID == 0) {
     ++mNextTextureID;
--- a/gfx/layers/client/CompositableClient.h
+++ b/gfx/layers/client/CompositableClient.h
@@ -72,16 +72,19 @@ public:
   virtual TextureInfo GetTextureInfo() const = 0;
 
   LayersBackend GetCompositorBackendType() const;
 
   TemporaryRef<DeprecatedTextureClient>
   CreateDeprecatedTextureClient(DeprecatedTextureClientType aDeprecatedTextureClientType);
 
   TemporaryRef<BufferTextureClient>
+  CreateBufferTextureClient(gfx::SurfaceFormat aFormat, TextureFlags aFlags);
+
+  virtual TemporaryRef<BufferTextureClient>
   CreateBufferTextureClient(gfx::SurfaceFormat aFormat);
 
   virtual void SetDescriptorFromReply(TextureIdentifier aTextureId,
                                       const SurfaceDescriptor& aDescriptor)
   {
     MOZ_CRASH("If you want to call this, you should have implemented it");
   }
 
--- a/gfx/layers/client/ImageClient.cpp
+++ b/gfx/layers/client/ImageClient.cpp
@@ -192,20 +192,26 @@ ImageClientBuffered::UpdateImage(ImageCo
   mFrontBuffer = mBackBuffer;
   mBackBuffer = temp;
   return ImageClientSingle::UpdateImage(aContainer, aContentFlags);
 }
 
 void
 ImageClientSingle::AddTextureClient(TextureClient* aTexture)
 {
-  aTexture->AddFlags(mTextureFlags);
+  MOZ_ASSERT((mTextureFlags & aTexture->GetFlags()) == mTextureFlags);
   CompositableClient::AddTextureClient(aTexture);
 }
 
+TemporaryRef<BufferTextureClient>
+ImageClientSingle::CreateBufferTextureClient(gfx::SurfaceFormat aFormat)
+{
+  return CompositableClient::CreateBufferTextureClient(aFormat, mTextureFlags);
+}
+
 void
 ImageClientSingle::Detach()
 {
   mFrontBuffer = nullptr;
 }
 
 void
 ImageClientBuffered::Detach()
--- a/gfx/layers/client/ImageClient.h
+++ b/gfx/layers/client/ImageClient.h
@@ -72,16 +72,19 @@ public:
                     CompositableType aType);
 
   virtual bool UpdateImage(ImageContainer* aContainer, uint32_t aContentFlags);
 
   virtual void Detach() MOZ_OVERRIDE;
 
   virtual void AddTextureClient(TextureClient* aTexture) MOZ_OVERRIDE;
 
+  virtual TemporaryRef<BufferTextureClient>
+  CreateBufferTextureClient(gfx::SurfaceFormat aFormat) MOZ_OVERRIDE;
+
   virtual TextureInfo GetTextureInfo() const MOZ_OVERRIDE;
 protected:
   RefPtr<TextureClient> mFrontBuffer;
   // Some layers may want to enforce some flags to all their textures
   // (like disallowing tiling)
   TextureFlags mTextureFlags;
 };
 
--- a/gfx/layers/client/TextureClient.cpp
+++ b/gfx/layers/client/TextureClient.cpp
@@ -83,18 +83,19 @@ ShmemTextureClient::GetBuffer() const
 
 size_t
 ShmemTextureClient::GetBufferSize() const
 {
   return mShmem.Size<uint8_t>();
 }
 
 ShmemTextureClient::ShmemTextureClient(CompositableClient* aCompositable,
-                                       gfx::SurfaceFormat aFormat)
-  : BufferTextureClient(aCompositable, aFormat)
+                                       gfx::SurfaceFormat aFormat,
+                                       TextureFlags aFlags)
+  : BufferTextureClient(aCompositable, aFormat, aFlags)
   , mAllocated(false)
 {
   MOZ_COUNT_CTOR(ShmemTextureClient);
 }
 
 ShmemTextureClient::~ShmemTextureClient()
 {
   MOZ_COUNT_DTOR(ShmemTextureClient);
@@ -120,18 +121,20 @@ bool
 MemoryTextureClient::Allocate(uint32_t aSize)
 {
   MOZ_ASSERT(!mBuffer);
   mBuffer = new uint8_t[aSize];
   mBufSize = aSize;
   return true;
 }
 
-MemoryTextureClient::MemoryTextureClient(CompositableClient* aCompositable, gfx::SurfaceFormat aFormat)
-  : BufferTextureClient(aCompositable, aFormat)
+MemoryTextureClient::MemoryTextureClient(CompositableClient* aCompositable,
+                                         gfx::SurfaceFormat aFormat,
+                                         TextureFlags aFlags)
+  : BufferTextureClient(aCompositable, aFormat, aFlags)
   , mBuffer(nullptr)
   , mBufSize(0)
 {
   MOZ_COUNT_CTOR(MemoryTextureClient);
 }
 
 MemoryTextureClient::~MemoryTextureClient()
 {
@@ -139,18 +142,19 @@ MemoryTextureClient::~MemoryTextureClien
   if (ShouldDeallocateInDestructor()) {
     // if the buffer has never been shared we must deallocate it or ir would
     // leak.
     delete mBuffer;
   }
 }
 
 BufferTextureClient::BufferTextureClient(CompositableClient* aCompositable,
-                                         gfx::SurfaceFormat aFormat)
-  : TextureClient()
+                                         gfx::SurfaceFormat aFormat,
+                                         TextureFlags aFlags)
+  : TextureClient(aFlags)
   , mCompositable(aCompositable)
   , mFormat(aFormat)
 {}
 
 BufferTextureClient::~BufferTextureClient()
 {}
 
 bool
@@ -167,16 +171,22 @@ BufferTextureClient::UpdateSurface(gfxAS
   if (!surf) {
     return false;
   }
 
   nsRefPtr<gfxContext> tmpCtx = new gfxContext(surf.get());
   tmpCtx->SetOperator(gfxContext::OPERATOR_SOURCE);
   tmpCtx->DrawSurface(aSurface, gfxSize(serializer.GetSize().width,
                                         serializer.GetSize().height));
+
+  if (TextureRequiresLocking(mFlags)) {
+    // We don't have support for proper locking yet, so we'll
+    // have to be immutable instead.
+    MarkImmutable();
+  }
   return true;
 }
 
 already_AddRefed<gfxASurface>
 BufferTextureClient::GetAsSurface()
 {
   ImageDataSerializer serializer(GetBuffer());
   if (!serializer.IsValid()) {
@@ -215,16 +225,22 @@ BufferTextureClient::UpdateYCbCr(const P
   MOZ_ASSERT(serializer.IsValid());
   if (!serializer.CopyData(aData.mYChannel, aData.mCbChannel, aData.mCrChannel,
                            aData.mYSize, aData.mYStride,
                            aData.mCbCrSize, aData.mCbCrStride,
                            aData.mYSkip, aData.mCbSkip)) {
     NS_WARNING("Failed to copy image data!");
     return false;
   }
+
+  if (TextureRequiresLocking(mFlags)) {
+    // We don't have support for proper locking yet, so we'll
+    // have to be immutable instead.
+    MarkImmutable();
+  }
   return true;
 }
 
 bool
 BufferTextureClient::AllocateForYCbCr(gfx::IntSize aYSize, gfx::IntSize aCbCrSize)
 {
   size_t bufSize = YCbCrImageDataSerializer::ComputeMinBufferSize(aYSize,
                                                                   aCbCrSize);
--- a/gfx/layers/client/TextureClient.h
+++ b/gfx/layers/client/TextureClient.h
@@ -122,72 +122,61 @@ public:
   }
 
   virtual bool IsAllocated() const = 0;
 
   virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aDescriptor) = 0;
 
   virtual gfx::IntSize GetSize() const = 0;
 
-  void SetFlags(TextureFlags aFlags)
-  {
-    MOZ_ASSERT(!IsSharedWithCompositor());
-    mFlags = aFlags;
-  }
-
-  void AddFlags(TextureFlags  aFlags)
-  {
-    MOZ_ASSERT(!IsSharedWithCompositor());
-    // make sure we don't deallocate on both client and host;
-    MOZ_ASSERT(!(aFlags & TEXTURE_DEALLOCATE_CLIENT && aFlags & TEXTURE_DEALLOCATE_HOST));
-    if (aFlags & TEXTURE_DEALLOCATE_CLIENT) {
-      mFlags &= ~TEXTURE_DEALLOCATE_HOST;
-    } else if (aFlags & TEXTURE_DEALLOCATE_HOST) {
-      mFlags &= ~TEXTURE_DEALLOCATE_CLIENT;
-    }
-    mFlags |= aFlags;
-  }
-
-  void RemoveFlags(TextureFlags  aFlags)
-  {
-    MOZ_ASSERT(!IsSharedWithCompositor());
-    mFlags &= (~aFlags);
-  }
-
   TextureFlags GetFlags() const { return mFlags; }
 
   /**
    * After being shared ith the compositor side, an immutable texture is never
    * modified, it can only be read. It is safe to not Lock/Unlock immutable
    * textures.
    */
   bool IsImmutable() const { return mFlags & TEXTURE_IMMUTABLE; }
 
   void MarkImmutable() { AddFlags(TEXTURE_IMMUTABLE); }
 
   bool IsSharedWithCompositor() const { return GetID() != 0; }
 
   bool ShouldDeallocateInDestructor() const;
 protected:
+  void AddFlags(TextureFlags  aFlags)
+  {
+    MOZ_ASSERT(!IsSharedWithCompositor());
+    // make sure we don't deallocate on both client and host;
+    MOZ_ASSERT(!(aFlags & TEXTURE_DEALLOCATE_CLIENT && aFlags & TEXTURE_DEALLOCATE_HOST));
+    if (aFlags & TEXTURE_DEALLOCATE_CLIENT) {
+      mFlags &= ~TEXTURE_DEALLOCATE_HOST;
+    } else if (aFlags & TEXTURE_DEALLOCATE_HOST) {
+      mFlags &= ~TEXTURE_DEALLOCATE_CLIENT;
+    }
+    mFlags |= aFlags;
+  }
+
   uint64_t mID;
   RefPtr<TextureClient> mNextSibling;
   TextureFlags mFlags;
 };
 
 /**
  * TextureClient that wraps a random access buffer such as a Shmem or raw memory.
  * This class must be inherited to implement the memory allocation and access bits.
  * (see ShmemTextureClient and MemoryTextureClient)
  */
 class BufferTextureClient : public TextureClient
                           , public TextureClientSurface
                           , TextureClientYCbCr
 {
 public:
-  BufferTextureClient(CompositableClient* aCompositable, gfx::SurfaceFormat aFormat);
+  BufferTextureClient(CompositableClient* aCompositable, gfx::SurfaceFormat aFormat,
+                      TextureFlags aFlags);
 
   virtual ~BufferTextureClient();
 
   virtual bool IsAllocated() const = 0;
 
   virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aDescriptor) = 0;
 
   virtual bool Allocate(uint32_t aSize) = 0;
@@ -226,17 +215,18 @@ protected:
 
 /**
  * TextureClient that wraps shared memory.
  * the corresponding texture on the host side is ShmemTextureHost.
  */
 class ShmemTextureClient : public BufferTextureClient
 {
 public:
-  ShmemTextureClient(CompositableClient* aCompositable, gfx::SurfaceFormat aFormat);
+  ShmemTextureClient(CompositableClient* aCompositable, gfx::SurfaceFormat aFormat,
+                     TextureFlags aFlags);
 
   ~ShmemTextureClient();
 
   virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aDescriptor) MOZ_OVERRIDE;
 
   virtual bool Allocate(uint32_t aSize) MOZ_OVERRIDE;
 
   virtual uint8_t* GetBuffer() const MOZ_OVERRIDE;
@@ -258,17 +248,18 @@ protected:
 /**
  * TextureClient that wraps raw memory.
  * The corresponding texture on the host side is MemoryTextureHost.
  * Can obviously not be used in a cross process setup.
  */
 class MemoryTextureClient : public BufferTextureClient
 {
 public:
-  MemoryTextureClient(CompositableClient* aCompositable, gfx::SurfaceFormat aFormat);
+  MemoryTextureClient(CompositableClient* aCompositable, gfx::SurfaceFormat aFormat,
+                      TextureFlags aFlags);
 
   ~MemoryTextureClient();
 
   virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aDescriptor) MOZ_OVERRIDE;
 
   virtual bool Allocate(uint32_t aSize) MOZ_OVERRIDE;
 
   virtual uint8_t* GetBuffer() const MOZ_OVERRIDE { return mBuffer; }
--- a/gfx/layers/composite/TextureHost.cpp
+++ b/gfx/layers/composite/TextureHost.cpp
@@ -224,16 +224,19 @@ BufferTextureHost::Updated(const nsIntRe
 {
   ++mUpdateSerial;
   if (aRegion) {
     mPartialUpdate = true;
     mMaybeUpdatedRegion = *aRegion;
   } else {
     mPartialUpdate = false;
   }
+  if (GetFlags() & TEXTURE_IMMEDIATE_UPLOAD) {
+    MaybeUpload(mPartialUpdate ? &mMaybeUpdatedRegion : nullptr);
+  }
 }
 
 void
 BufferTextureHost::SetCompositor(Compositor* aCompositor)
 {
   if (mCompositor == aCompositor) {
     return;
   }
@@ -263,21 +266,18 @@ BufferTextureHost::Unlock()
 {
   mLocked = false;
 }
 
 NewTextureSource*
 BufferTextureHost::GetTextureSources()
 {
   MOZ_ASSERT(mLocked, "should never be called while not locked");
-  if (!mFirstSource || mUpdateSerial != mFirstSource->GetUpdateSerial()) {
-    if (!Upload(mPartialUpdate ? &mMaybeUpdatedRegion : nullptr)) {
+  if (!MaybeUpload(mPartialUpdate ? &mMaybeUpdatedRegion : nullptr)) {
       return nullptr;
-    }
-    mFirstSource->SetUpdateSerial(mUpdateSerial);
   }
   return mFirstSource;
 }
 
 gfx::SurfaceFormat
 BufferTextureHost::GetFormat() const
 {
   // mFormat is the format of the data that we share with the content process.
@@ -289,16 +289,29 @@ BufferTextureHost::GetFormat() const
     mCompositor &&
     !mCompositor->SupportsEffect(EFFECT_YCBCR)) {
     return gfx::FORMAT_R8G8B8X8;
   }
   return mFormat;
 }
 
 bool
+BufferTextureHost::MaybeUpload(nsIntRegion *aRegion)
+{
+  if (mFirstSource && mFirstSource->GetUpdateSerial() == mUpdateSerial) {
+    return true;
+  }
+  if (!Upload(aRegion)) {
+    return false;
+  }
+  mFirstSource->SetUpdateSerial(mUpdateSerial);
+  return true;
+}
+
+bool
 BufferTextureHost::Upload(nsIntRegion *aRegion)
 {
   if (mFormat == gfx::FORMAT_UNKNOWN) {
     NS_WARNING("BufferTextureHost: unsupported format!");
     return false;
   } else if (mFormat == gfx::FORMAT_YUV) {
     YCbCrImageDataDeserializer yuvDeserializer(GetBuffer());
     MOZ_ASSERT(yuvDeserializer.IsValid());
--- a/gfx/layers/composite/TextureHost.h
+++ b/gfx/layers/composite/TextureHost.h
@@ -444,16 +444,17 @@ public:
   virtual gfx::SurfaceFormat GetFormat() const MOZ_OVERRIDE;
 
   virtual already_AddRefed<gfxImageSurface> GetAsSurface() MOZ_OVERRIDE;
 
   virtual gfx::IntSize GetSize() const MOZ_OVERRIDE { return mSize; }
 
 protected:
   bool Upload(nsIntRegion *aRegion = nullptr);
+  bool MaybeUpload(nsIntRegion *aRegion = nullptr);
 
   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;
--- a/gfx/layers/ipc/ShadowLayers.cpp
+++ b/gfx/layers/ipc/ShadowLayers.cpp
@@ -402,19 +402,26 @@ ShadowLayerForwarder::RemoveTexture(Comp
 
 void
 ShadowLayerForwarder::UpdatedTexture(CompositableClient* aCompositable,
                                      TextureClient* aTexture,
                                      nsIntRegion* aRegion)
 {
   MaybeRegion region = aRegion ? MaybeRegion(*aRegion)
                                : MaybeRegion(null_t());
-  mTxn->AddEdit(OpUpdateTexture(nullptr, aCompositable->GetIPDLActor(),
-                                aTexture->GetID(),
-                                region));
+  if (aTexture->GetFlags() & TEXTURE_IMMEDIATE_UPLOAD) {
+    mTxn->AddPaint(OpUpdateTexture(nullptr, aCompositable->GetIPDLActor(),
+                                   aTexture->GetID(),
+                                   region));
+  } else {
+    mTxn->AddNoSwapPaint(OpUpdateTexture(nullptr, aCompositable->GetIPDLActor(),
+                                         aTexture->GetID(),
+                                         region));
+
+  }
 }
 
 void
 ShadowLayerForwarder::UseTexture(CompositableClient* aCompositable,
                                  TextureClient* aTexture)
 {
   mTxn->AddEdit(OpUseTexture(nullptr, aCompositable->GetIPDLActor(),
                              aTexture->GetID()));