LCOV - code coverage report
Current view: top level - gfx/layers/client - TextureClient.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 265 739 35.9 %
Date: 2017-07-14 16:53:18 Functions: 53 107 49.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
       2             :  * This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #include "mozilla/layers/TextureClient.h"
       7             : #include <stdint.h>                     // for uint8_t, uint32_t, etc
       8             : #include "Layers.h"                     // for Layer, etc
       9             : #include "gfx2DGlue.h"
      10             : #include "gfxPlatform.h"                // for gfxPlatform
      11             : #include "mozilla/Atomics.h"
      12             : #include "mozilla/ipc/SharedMemory.h"   // for SharedMemory, etc
      13             : #include "mozilla/layers/CompositableForwarder.h"
      14             : #include "mozilla/layers/ISurfaceAllocator.h"
      15             : #include "mozilla/layers/ImageBridgeChild.h"
      16             : #include "mozilla/layers/ImageDataSerializer.h"
      17             : #include "mozilla/layers/TextureClientRecycleAllocator.h"
      18             : #include "mozilla/Mutex.h"
      19             : #include "nsDebug.h"                    // for NS_ASSERTION, NS_WARNING, etc
      20             : #include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
      21             : #include "ImageContainer.h"             // for PlanarYCbCrData, etc
      22             : #include "mozilla/gfx/2D.h"
      23             : #include "mozilla/gfx/Logging.h"        // for gfxDebug
      24             : #include "mozilla/layers/TextureClientOGL.h"
      25             : #include "mozilla/layers/PTextureChild.h"
      26             : #include "mozilla/gfx/DataSurfaceHelpers.h" // for CreateDataSourceSurfaceByCloning
      27             : #include "nsPrintfCString.h"            // for nsPrintfCString
      28             : #include "LayersLogging.h"              // for AppendToString
      29             : #include "gfxUtils.h"                   // for gfxUtils::GetAsLZ4Base64Str
      30             : #include "IPDLActor.h"
      31             : #include "BufferTexture.h"
      32             : #include "gfxPrefs.h"
      33             : #include "mozilla/layers/ShadowLayers.h"
      34             : #include "mozilla/ipc/CrossProcessSemaphore.h"
      35             : 
      36             : #ifdef XP_WIN
      37             : #include "mozilla/gfx/DeviceManagerDx.h"
      38             : #include "mozilla/layers/TextureD3D11.h"
      39             : #include "mozilla/layers/TextureDIB.h"
      40             : #include "gfxWindowsPlatform.h"
      41             : #include "gfx2DGlue.h"
      42             : #endif
      43             : #ifdef MOZ_X11
      44             : #include "mozilla/layers/TextureClientX11.h"
      45             : #ifdef GL_PROVIDER_GLX
      46             : #include "GLXLibrary.h"
      47             : #endif
      48             : #endif
      49             : 
      50             : #ifdef XP_MACOSX
      51             : #include "mozilla/layers/MacIOSurfaceTextureClientOGL.h"
      52             : #endif
      53             : 
      54             : #if 0
      55             : #define RECYCLE_LOG(...) printf_stderr(__VA_ARGS__)
      56             : #else
      57             : #define RECYCLE_LOG(...) do { } while (0)
      58             : #endif
      59             : 
      60             : namespace mozilla {
      61             : namespace layers {
      62             : 
      63             : using namespace mozilla::ipc;
      64             : using namespace mozilla::gl;
      65             : using namespace mozilla::gfx;
      66             : 
      67          24 : struct TextureDeallocParams
      68             : {
      69             :   TextureData* data;
      70             :   RefPtr<TextureChild> actor;
      71             :   RefPtr<LayersIPCChannel> allocator;
      72             :   bool clientDeallocation;
      73             :   bool syncDeallocation;
      74             :   bool workAroundSharedSurfaceOwnershipIssue;
      75             : };
      76             : 
      77             : void DeallocateTextureClient(TextureDeallocParams params);
      78             : 
      79             : /**
      80             :  * TextureChild is the content-side incarnation of the PTexture IPDL actor.
      81             :  *
      82             :  * TextureChild is used to synchronize a texture client and its corresponding
      83             :  * TextureHost if needed (a TextureClient that is not shared with the compositor
      84             :  * does not have a TextureChild)
      85             :  *
      86             :  * During the deallocation phase, a TextureChild may hold its recently destroyed
      87             :  * TextureClient's data until the compositor side confirmed that it is safe to
      88             :  * deallocte or recycle the it.
      89             :  */
      90             : class TextureChild final : PTextureChild
      91             : {
      92          12 :   ~TextureChild()
      93          12 :   {
      94             :     // We should have deallocated mTextureData in ActorDestroy
      95           6 :     MOZ_ASSERT(!mTextureData);
      96           6 :     MOZ_ASSERT_IF(!mOwnerCalledDestroy, !mTextureClient);
      97          18 :   }
      98             : public:
      99          66 :   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TextureChild)
     100             : 
     101           9 :   TextureChild()
     102           9 :   : mCompositableForwarder(nullptr)
     103             :   , mTextureForwarder(nullptr)
     104             :   , mTextureClient(nullptr)
     105             :   , mTextureData(nullptr)
     106             :   , mDestroyed(false)
     107             :   , mMainThreadOnly(false)
     108             :   , mIPCOpen(false)
     109             :   , mOwnsTextureData(false)
     110           9 :   , mOwnerCalledDestroy(false)
     111           9 :   {}
     112             : 
     113           6 :   mozilla::ipc::IPCResult Recv__delete__() override { return IPC_OK(); }
     114             : 
     115           6 :   LayersIPCChannel* GetAllocator() { return mTextureForwarder; }
     116             : 
     117             :   void ActorDestroy(ActorDestroyReason why) override;
     118             : 
     119          15 :   bool IPCOpen() const { return mIPCOpen; }
     120             : 
     121          53 :   void Lock() const { if (mCompositableForwarder && mCompositableForwarder->GetTextureForwarder()->UsesImageBridge()) { mLock.Enter(); } }
     122             : 
     123          53 :   void Unlock() const { if (mCompositableForwarder && mCompositableForwarder->GetTextureForwarder()->UsesImageBridge()) { mLock.Leave(); } }
     124             : 
     125             : private:
     126             : 
     127             :   // AddIPDLReference and ReleaseIPDLReference are only to be called by CreateIPDLActor
     128             :   // and DestroyIPDLActor, respectively. We intentionally make them private to prevent misuse.
     129             :   // The purpose of these methods is to be aware of when the IPC system around this
     130             :   // actor goes down: mIPCOpen is then set to false.
     131           9 :   void AddIPDLReference() {
     132           9 :     MOZ_ASSERT(mIPCOpen == false);
     133           9 :     mIPCOpen = true;
     134           9 :     AddRef();
     135           9 :   }
     136           6 :   void ReleaseIPDLReference() {
     137           6 :     MOZ_ASSERT(mIPCOpen == false);
     138           6 :     Release();
     139           6 :   }
     140             : 
     141             :   /// The normal way to destroy the actor.
     142             :   ///
     143             :   /// This will asynchronously send a Destroy message to the parent actor, whom
     144             :   /// will send the delete message.
     145             :   void Destroy(const TextureDeallocParams& aParams);
     146             : 
     147             :   // This lock is used order to prevent several threads to access the
     148             :   // TextureClient's data concurrently. In particular, it prevents shutdown
     149             :   // code to destroy a texture while another thread is reading or writing into
     150             :   // it.
     151             :   // In most places, the lock is held in short and bounded scopes in which we
     152             :   // don't block on any other resource. There are few exceptions to this, which
     153             :   // are discussed below.
     154             :   //
     155             :   // The locking pattern of TextureClient may in some case upset deadlock detection
     156             :   // tools such as TSan.
     157             :   // Typically our tile rendering code will lock all of its tiles, render into them
     158             :   // and unlock them all right after that, which looks something like:
     159             :   //
     160             :   // Lock tile A
     161             :   // Lock tile B
     162             :   // Lock tile C
     163             :   // Apply drawing commands to tiles A, B and C 
     164             :   // Unlock tile A
     165             :   // Unlock tile B
     166             :   // Unlock tile C
     167             :   //
     168             :   // And later, we may end up rendering a tile buffer that has the same tiles,
     169             :   // in a different order, for example:
     170             :   //
     171             :   // Lock tile B
     172             :   // Lock tile A
     173             :   // Lock tile D
     174             :   // Apply drawing commands to tiles A, B and D
     175             :   // Unlock tile B
     176             :   // Unlock tile A
     177             :   // Unlock tile D
     178             :   //
     179             :   // This is because textures being expensive to create, we recycle them as much
     180             :   // as possible and they may reappear in the tile buffer in a different order.
     181             :   //
     182             :   // Unfortunately this is not very friendly to TSan's analysis, which will see
     183             :   // that B was once locked while A was locked, and then A locked while B was
     184             :   // locked. TSan identifies this as a potential dead-lock which would be the
     185             :   // case if this kind of inconsistent and dependent locking order was happening
     186             :   // concurrently.
     187             :   // In the case of TextureClient, dependent locking only ever happens on the
     188             :   // thread that draws into the texture (let's call it the producer thread). Other
     189             :   // threads may call into a method that can lock the texture in a short and
     190             :   // bounded scope inside of which it is not allowed to do anything that could
     191             :   // cause the thread to block. A given texture can only have one producer thread.
     192             :   //
     193             :   // Another example of TSan-unfriendly locking pattern is when copying a texture
     194             :   // into another, which also never happens outside of the producer thread.
     195             :   // Copying A into B looks like this:
     196             :   //
     197             :   // Lock texture B
     198             :   // Lock texture A
     199             :   // Copy A into B
     200             :   // Unlock A
     201             :   // Unlock B
     202             :   //
     203             :   // In a given frame we may need to copy A into B and in another frame copy
     204             :   // B into A. For example A and B can be the Front and Back buffers, alternating
     205             :   // roles and the copy is needed to avoid the cost of re-drawing the valid
     206             :   // region.
     207             :   //
     208             :   // The important rule is that all of the dependent locking must occur only
     209             :   // in the texture's producer thread to avoid deadlocks.
     210             :   mutable gfx::CriticalSection mLock;
     211             : 
     212             :   RefPtr<CompositableForwarder> mCompositableForwarder;
     213             :   RefPtr<TextureForwarder> mTextureForwarder;
     214             : 
     215             :   TextureClient* mTextureClient;
     216             :   TextureData* mTextureData;
     217             :   Atomic<bool> mDestroyed;
     218             :   bool mMainThreadOnly;
     219             :   bool mIPCOpen;
     220             :   bool mOwnsTextureData;
     221             :   bool mOwnerCalledDestroy;
     222             : 
     223             :   friend class TextureClient;
     224             :   friend void DeallocateTextureClient(TextureDeallocParams params);
     225             : };
     226             : 
     227             : 
     228           6 : static void DestroyTextureData(TextureData* aTextureData, LayersIPCChannel* aAllocator,
     229             :                                bool aDeallocate, bool aMainThreadOnly)
     230             : {
     231           6 :   if (!aTextureData) {
     232           0 :     return;
     233             :   }
     234             : 
     235           6 :   if (aMainThreadOnly && !NS_IsMainThread()) {
     236           0 :     RefPtr<LayersIPCChannel> allocatorRef = aAllocator;
     237           0 :     NS_DispatchToMainThread(NS_NewRunnableFunction(
     238             :       "layers::DestroyTextureData",
     239           0 :       [aTextureData, allocatorRef, aDeallocate]() -> void {
     240           0 :         DestroyTextureData(aTextureData, allocatorRef, aDeallocate, true);
     241           0 :       }));
     242           0 :     return;
     243             :   }
     244             : 
     245           6 :   if (aDeallocate) {
     246           0 :     aTextureData->Deallocate(aAllocator);
     247             :   } else {
     248           6 :     aTextureData->Forget(aAllocator);
     249             :   }
     250           6 :   delete aTextureData;
     251             : }
     252             : 
     253             : void
     254           6 : TextureChild::ActorDestroy(ActorDestroyReason why)
     255             : {
     256          12 :   AUTO_PROFILER_LABEL("TextureChild::ActorDestroy", GRAPHICS);
     257           6 :   MOZ_ASSERT(mIPCOpen);
     258           6 :   mIPCOpen = false;
     259             : 
     260           6 :   if (mTextureData) {
     261           6 :     DestroyTextureData(mTextureData, GetAllocator(), mOwnsTextureData, mMainThreadOnly);
     262           6 :     mTextureData = nullptr;
     263             :   }
     264           6 : }
     265             : 
     266             : void
     267           6 : TextureChild::Destroy(const TextureDeallocParams& aParams)
     268             : {
     269           6 :   MOZ_ASSERT(!mOwnerCalledDestroy);
     270           6 :   if (mOwnerCalledDestroy) {
     271           0 :     return;
     272             :   }
     273             : 
     274           6 :   mOwnerCalledDestroy = true;
     275             : 
     276           6 :   if (!IPCOpen()) {
     277           0 :     DestroyTextureData(
     278           0 :       aParams.data,
     279             :       aParams.allocator,
     280           0 :       aParams.clientDeallocation,
     281           0 :       mMainThreadOnly);
     282           0 :     return;
     283             :   }
     284             : 
     285             :   // DestroyTextureData will be called by TextureChild::ActorDestroy
     286           6 :   mTextureData = aParams.data;
     287           6 :   mOwnsTextureData = aParams.clientDeallocation;
     288             : 
     289          12 :   if (!mCompositableForwarder ||
     290           6 :       !mCompositableForwarder->DestroyInTransaction(this))
     291             :   {
     292           4 :     this->SendDestroy();
     293             :   }
     294             : }
     295             : 
     296             : /* static */ Atomic<uint64_t> TextureClient::sSerialCounter(0);
     297             : 
     298           0 : void DeallocateTextureClientSyncProxy(TextureDeallocParams params,
     299             :                                         ReentrantMonitor* aBarrier, bool* aDone)
     300             : {
     301           0 :   DeallocateTextureClient(params);
     302           0 :   ReentrantMonitorAutoEnter autoMon(*aBarrier);
     303           0 :   *aDone = true;
     304           0 :   aBarrier->NotifyAll();
     305           0 : }
     306             : 
     307             : /// The logic for synchronizing a TextureClient's deallocation goes here.
     308             : ///
     309             : /// This funciton takes care of dispatching work to the right thread using
     310             : /// a synchronous proxy if needed, and handles client/host deallocation.
     311             : void
     312           6 : DeallocateTextureClient(TextureDeallocParams params)
     313             : {
     314           6 :   if (!params.actor && !params.data) {
     315             :     // Nothing to do
     316           0 :     return;
     317             :   }
     318             : 
     319           6 :   TextureChild* actor = params.actor;
     320           6 :   MessageLoop* ipdlMsgLoop = nullptr;
     321             : 
     322           6 :   if (params.allocator) {
     323           6 :     ipdlMsgLoop = params.allocator->GetMessageLoop();
     324           6 :     if (!ipdlMsgLoop) {
     325             :       // An allocator with no message loop means we are too late in the shutdown
     326             :       // sequence.
     327           0 :       gfxCriticalError() << "Texture deallocated too late during shutdown";
     328           0 :       return;
     329             :     }
     330             :   }
     331             : 
     332             :   // First make sure that the work is happening on the IPDL thread.
     333           6 :   if (ipdlMsgLoop && MessageLoop::current() != ipdlMsgLoop) {
     334           0 :     if (params.syncDeallocation) {
     335           0 :       bool done = false;
     336           0 :       ReentrantMonitor barrier("DeallocateTextureClient");
     337           0 :       ReentrantMonitorAutoEnter autoMon(barrier);
     338           0 :       ipdlMsgLoop->PostTask(NewRunnableFunction(DeallocateTextureClientSyncProxy,
     339           0 :                                                 params, &barrier, &done));
     340           0 :       while (!done) {
     341           0 :         barrier.Wait();
     342             :       }
     343             :     } else {
     344           0 :       ipdlMsgLoop->PostTask(NewRunnableFunction(DeallocateTextureClient,
     345           0 :                                                 params));
     346             :     }
     347             :     // The work has been forwarded to the IPDL thread, we are done.
     348           0 :     return;
     349             :   }
     350             : 
     351             :   // Below this line, we are either in the IPDL thread or ther is no IPDL
     352             :   // thread anymore.
     353             : 
     354           6 :   if (!ipdlMsgLoop) {
     355             :     // If we don't have a message loop we can't know for sure that we are in
     356             :     // the IPDL thread and use the LayersIPCChannel.
     357             :     // This should ideally not happen outside of gtest, but some shutdown raciness
     358             :     // could put us in this situation.
     359           0 :     params.allocator = nullptr;
     360             :   }
     361             : 
     362           6 :   if (!actor) {
     363             :     // We don't have an IPDL actor, probably because we destroyed the TextureClient
     364             :     // before sharing it with the compositor. It means the data cannot be owned by
     365             :     // the TextureHost since we never created the TextureHost...
     366             :     // ..except if the lovely mWorkaroundAnnoyingSharedSurfaceOwnershipIssues member
     367             :     // is set to true. In this case we are in a special situation where this
     368             :     // TextureClient is in wrapped into another TextureClient which assumes it owns
     369             :     // our data.
     370           0 :     bool shouldDeallocate = !params.workAroundSharedSurfaceOwnershipIssue;
     371           0 :     DestroyTextureData(params.data, params.allocator,
     372             :                        shouldDeallocate,
     373           0 :                        false);  // main-thread deallocation
     374           0 :     return;
     375             :   }
     376             : 
     377           6 :   actor->Destroy(params);
     378             : }
     379             : 
     380           6 : void TextureClient::Destroy()
     381             : {
     382           6 :   if (mActor && !mIsLocked) {
     383           6 :     mActor->Lock();
     384             :   }
     385             : 
     386           6 :   mBorrowedDrawTarget = nullptr;
     387           6 :   mReadLock = nullptr;
     388             : 
     389          12 :   RefPtr<TextureChild> actor = mActor;
     390           6 :   mActor = nullptr;
     391             : 
     392           6 :   if (actor && !actor->mDestroyed.compareExchange(false, true)) {
     393           0 :     actor->Unlock();
     394           0 :     actor = nullptr;
     395             :   }
     396             : 
     397           6 :   TextureData* data = mData;
     398           6 :   if (!mWorkaroundAnnoyingSharedSurfaceLifetimeIssues) {
     399           6 :     mData = nullptr;
     400             :   }
     401             : 
     402           6 :   if (data || actor) {
     403          12 :     TextureDeallocParams params;
     404           6 :     params.actor = actor;
     405           6 :     params.allocator = mAllocator;
     406           6 :     params.clientDeallocation = !!(mFlags & TextureFlags::DEALLOCATE_CLIENT);
     407           6 :     params.workAroundSharedSurfaceOwnershipIssue = mWorkaroundAnnoyingSharedSurfaceOwnershipIssues;
     408           6 :     if (mWorkaroundAnnoyingSharedSurfaceLifetimeIssues) {
     409           0 :       params.data = nullptr;
     410             :     } else {
     411           6 :       params.data = data;
     412             :     }
     413             :     // At the moment we always deallocate synchronously when deallocating on the
     414             :     // client side, but having asynchronous deallocate in some of the cases will
     415             :     // be a worthwhile optimization.
     416           6 :     params.syncDeallocation = !!(mFlags & TextureFlags::DEALLOCATE_CLIENT);
     417             : 
     418             :     // Release the lock before calling DeallocateTextureClient because the latter
     419             :     // may wait for the main thread which could create a dead-lock.
     420             : 
     421           6 :     if (actor) {
     422           6 :       actor->Unlock();
     423             :     }
     424             : 
     425           6 :     DeallocateTextureClient(params);
     426             :   }
     427           6 : }
     428             : 
     429             : void
     430          47 : TextureClient::LockActor() const
     431             : {
     432          47 :   if (mActor) {
     433          47 :     mActor->Lock();
     434             :   }
     435          47 : }
     436             : 
     437             : void
     438          47 : TextureClient::UnlockActor() const
     439             : {
     440          47 :   if (mActor) {
     441          47 :     mActor->Unlock();
     442             :   }
     443          47 : }
     444             : 
     445             : bool
     446           0 : TextureClient::IsReadLocked() const
     447             : {
     448           0 :   if (!mReadLock) {
     449           0 :     return false;
     450             :   }
     451           0 :   MOZ_ASSERT(mReadLock->AsNonBlockingLock(), "Can only check locked for non-blocking locks!");
     452           0 :   return mReadLock->AsNonBlockingLock()->GetReadCount() > 1;
     453             : }
     454             : 
     455             : bool
     456          34 : TextureClient::TryReadLock()
     457             : {
     458          34 :   if (!mReadLock || mIsReadLocked) {
     459           0 :     return true;
     460             :   }
     461             : 
     462          34 :   if (mReadLock->AsNonBlockingLock()) {
     463           0 :     if (IsReadLocked()) {
     464           0 :       return false;
     465             :     }
     466             :   }
     467             : 
     468          34 :   if (!mReadLock->TryReadLock(TimeDuration::FromMilliseconds(500))) {
     469           0 :     return false;
     470             :   }
     471             : 
     472          34 :   mIsReadLocked = true;
     473          34 :   return true;
     474             : }
     475             : 
     476             : void
     477          47 : TextureClient::ReadUnlock()
     478             : {
     479          47 :   if (!mIsReadLocked) {
     480          13 :     return;
     481             :   }
     482          34 :   MOZ_ASSERT(mReadLock);
     483          34 :   mReadLock->ReadUnlock();
     484          34 :   mIsReadLocked = false;
     485             :  }
     486             : 
     487             : bool
     488          47 : TextureClient::Lock(OpenMode aMode)
     489             : {
     490          47 :   MOZ_ASSERT(IsValid());
     491          47 :   MOZ_ASSERT(!mIsLocked);
     492          47 :   if (!IsValid()) {
     493           0 :     return false;
     494             :   }
     495          47 :   if (mIsLocked) {
     496           0 :     return mOpenMode == aMode;
     497             :   }
     498             : 
     499          47 :   if (aMode & OpenMode::OPEN_WRITE && !TryReadLock()) {
     500           0 :     NS_WARNING("Attempt to Lock a texture that is being read by the compositor!");
     501           0 :     return false;
     502             :   }
     503             : 
     504          47 :   LockActor();
     505             : 
     506          47 :   mIsLocked = mData->Lock(aMode);
     507          47 :   mOpenMode = aMode;
     508             : 
     509          47 :   auto format = GetFormat();
     510         141 :   if (mIsLocked && CanExposeDrawTarget() &&
     511          34 :       aMode == OpenMode::OPEN_READ_WRITE &&
     512         149 :       NS_IsMainThread() &&
     513             :       // the formats that we apparently expect, in the cairo backend. Any other
     514             :       // format will trigger an assertion in GfxFormatToCairoFormat.
     515          18 :       (format == SurfaceFormat::A8R8G8B8_UINT32 ||
     516           0 :       format == SurfaceFormat::X8R8G8B8_UINT32 ||
     517           0 :       format == SurfaceFormat::A8 ||
     518             :       format == SurfaceFormat::R5G6B5_UINT16)) {
     519          34 :     if (!BorrowDrawTarget()) {
     520             :       // Failed to get a DrawTarget, means we won't be able to write into the
     521             :       // texture, might as well fail now.
     522           0 :       Unlock();
     523           0 :       return false;
     524             :     }
     525             :   }
     526             : 
     527          47 :   if (!mIsLocked) {
     528           0 :     UnlockActor();
     529           0 :     ReadUnlock();
     530             :   }
     531             : 
     532          47 :   return mIsLocked;
     533             : }
     534             : 
     535             : void
     536          47 : TextureClient::Unlock()
     537             : {
     538          47 :   MOZ_ASSERT(IsValid());
     539          47 :   MOZ_ASSERT(mIsLocked);
     540          47 :   if (!IsValid() || !mIsLocked) {
     541           0 :     return;
     542             :   }
     543             : 
     544          47 :   if (mBorrowedDrawTarget) {
     545          47 :     if (mOpenMode & OpenMode::OPEN_WRITE) {
     546          34 :       mBorrowedDrawTarget->Flush();
     547          34 :       if (mReadbackSink && !mData->ReadBack(mReadbackSink)) {
     548             :         // Fallback implementation for reading back, because mData does not
     549             :         // have a backend-specific implementation and returned false.
     550           0 :         RefPtr<SourceSurface> snapshot = mBorrowedDrawTarget->Snapshot();
     551           0 :         RefPtr<DataSourceSurface> dataSurf = snapshot->GetDataSurface();
     552           0 :         mReadbackSink->ProcessReadback(dataSurf);
     553             :       }
     554             :     }
     555             : 
     556          47 :     mBorrowedDrawTarget->DetachAllSnapshots();
     557             :     // If this assertion is hit, it means something is holding a strong reference
     558             :     // to our DrawTarget externally, which is not allowed.
     559          47 :     MOZ_ASSERT(mBorrowedDrawTarget->refCount() <= mExpectedDtRefs);
     560             : 
     561          47 :     mBorrowedDrawTarget = nullptr;
     562             :   }
     563             : 
     564          47 :   if (mOpenMode & OpenMode::OPEN_WRITE) {
     565          34 :     mUpdated = true;
     566             :   }
     567             : 
     568          47 :   if (mData) {
     569          47 :     mData->Unlock();
     570             :   }
     571          47 :   mIsLocked = false;
     572          47 :   mOpenMode = OpenMode::OPEN_NONE;
     573             : 
     574          47 :   UnlockActor();
     575          47 :   ReadUnlock();
     576             : }
     577             : 
     578             : void
     579           0 : TextureClient::EnableReadLock()
     580             : {
     581           0 :   if (!mReadLock) {
     582           0 :     mReadLock = NonBlockingTextureReadLock::Create(mAllocator);
     583             :   }
     584           0 : }
     585             : 
     586             : bool
     587          33 : TextureClient::SerializeReadLock(ReadLockDescriptor& aDescriptor)
     588             : {
     589          33 :   if (mReadLock && mUpdated) {
     590             :     // Take a read lock on behalf of the TextureHost. The latter will unlock
     591             :     // after the shared data is available again for drawing.
     592          33 :     mReadLock->ReadLock();
     593          33 :     mUpdated = false;
     594          33 :     if (mReadLock->Serialize(aDescriptor, GetAllocator()->GetParentPid())) {
     595          33 :       return true;
     596             :     }
     597             :   }
     598             : 
     599           0 :   aDescriptor = null_t();
     600           0 :   return false;
     601             : }
     602             : 
     603          18 : TextureClient::~TextureClient()
     604             : {
     605           6 :   mReadLock = nullptr;
     606           6 :   Destroy();
     607          18 : }
     608             : 
     609             : void
     610           0 : TextureClient::UpdateFromSurface(gfx::SourceSurface* aSurface)
     611             : {
     612           0 :   MOZ_ASSERT(IsValid());
     613           0 :   MOZ_ASSERT(mIsLocked);
     614           0 :   MOZ_ASSERT(aSurface);
     615             :   // If you run into this assertion, make sure the texture was locked write-only
     616             :   // rather than read-write.
     617           0 :   MOZ_ASSERT(!mBorrowedDrawTarget);
     618             : 
     619             :   // XXX - It would be better to first try the DrawTarget approach and fallback
     620             :   // to the backend-specific implementation because the latter will usually do
     621             :   // an expensive read-back + cpu-side copy if the texture is on the gpu.
     622             :   // There is a bug with the DrawTarget approach, though specific to reading back
     623             :   // from WebGL (where R and B channel end up inverted) to figure out first.
     624           0 :   if (mData->UpdateFromSurface(aSurface)) {
     625           0 :     return;
     626             :   }
     627           0 :   if (CanExposeDrawTarget() && NS_IsMainThread()) {
     628           0 :     RefPtr<DrawTarget> dt = BorrowDrawTarget();
     629             : 
     630           0 :     MOZ_ASSERT(dt);
     631           0 :     if (dt) {
     632           0 :       dt->CopySurface(aSurface,
     633           0 :                       gfx::IntRect(gfx::IntPoint(0, 0), aSurface->GetSize()),
     634           0 :                       gfx::IntPoint(0, 0));
     635           0 :       return;
     636             :     }
     637             :   }
     638           0 :   NS_WARNING("TextureClient::UpdateFromSurface failed");
     639             : }
     640             : 
     641             : 
     642             : already_AddRefed<TextureClient>
     643           0 : TextureClient::CreateSimilar(LayersBackend aLayersBackend, TextureFlags aFlags, TextureAllocationFlags aAllocFlags) const
     644             : {
     645           0 :   MOZ_ASSERT(IsValid());
     646             : 
     647           0 :   MOZ_ASSERT(!mIsLocked);
     648           0 :   if (mIsLocked) {
     649           0 :     return nullptr;
     650             :   }
     651             : 
     652           0 :   LockActor();
     653           0 :   TextureData* data = mData->CreateSimilar(mAllocator, aLayersBackend, aFlags, aAllocFlags);
     654           0 :   UnlockActor();
     655             : 
     656           0 :   if (!data) {
     657           0 :     return nullptr;
     658             :   }
     659             : 
     660           0 :   return MakeAndAddRef<TextureClient>(data, aFlags, mAllocator);
     661             : }
     662             : 
     663             : gfx::DrawTarget*
     664          81 : TextureClient::BorrowDrawTarget()
     665             : {
     666          81 :   MOZ_ASSERT(IsValid());
     667          81 :   MOZ_ASSERT(mIsLocked);
     668             :   // TODO- We can't really assert that at the moment because there is code that Borrows
     669             :   // the DrawTarget, just to get a snapshot, which is legit in term of OpenMode
     670             :   // but we should have a way to get a SourceSurface directly instead.
     671             :   //MOZ_ASSERT(mOpenMode & OpenMode::OPEN_WRITE);
     672             : 
     673          81 :   if (!IsValid() || !mIsLocked) {
     674           0 :     return nullptr;
     675             :   }
     676             : 
     677          81 :   if (!NS_IsMainThread()) {
     678           0 :     return nullptr;
     679             :   }
     680             : 
     681          81 :   if (!mBorrowedDrawTarget) {
     682          47 :     mBorrowedDrawTarget = mData->BorrowDrawTarget();
     683             : #ifdef DEBUG
     684          47 :     mExpectedDtRefs = mBorrowedDrawTarget ? mBorrowedDrawTarget->refCount() : 0;
     685             : #endif
     686             :   }
     687             : 
     688          81 :   return mBorrowedDrawTarget;
     689             : }
     690             : 
     691             : bool
     692           0 : TextureClient::BorrowMappedData(MappedTextureData& aMap)
     693             : {
     694           0 :   MOZ_ASSERT(IsValid());
     695             : 
     696             :   // TODO - SharedRGBImage just accesses the buffer without properly locking
     697             :   // the texture. It's bad.
     698             :   //MOZ_ASSERT(mIsLocked);
     699             :   //if (!mIsLocked) {
     700             :   //  return nullptr;
     701             :   //}
     702             : 
     703           0 :   return mData ? mData->BorrowMappedData(aMap) : false;
     704             : }
     705             : 
     706             : bool
     707           0 : TextureClient::BorrowMappedYCbCrData(MappedYCbCrTextureData& aMap)
     708             : {
     709           0 :   MOZ_ASSERT(IsValid());
     710             : 
     711           0 :   return mData ? mData->BorrowMappedYCbCrData(aMap) : false;
     712             : }
     713             : 
     714             : bool
     715           9 : TextureClient::ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor)
     716             : {
     717           9 :   MOZ_ASSERT(IsValid());
     718             : 
     719           9 :   return mData ? mData->Serialize(aOutDescriptor) : false;
     720             : }
     721             : 
     722             : // static
     723             : PTextureChild*
     724           9 : TextureClient::CreateIPDLActor()
     725             : {
     726           9 :   TextureChild* c = new TextureChild();
     727           9 :   c->AddIPDLReference();
     728           9 :   return c;
     729             : }
     730             : 
     731             : // static
     732             : bool
     733           6 : TextureClient::DestroyIPDLActor(PTextureChild* actor)
     734             : {
     735           6 :   static_cast<TextureChild*>(actor)->ReleaseIPDLReference();
     736           6 :   return true;
     737             : }
     738             : 
     739             : // static
     740             : already_AddRefed<TextureClient>
     741           0 : TextureClient::AsTextureClient(PTextureChild* actor)
     742             : {
     743           0 :   if (!actor) {
     744           0 :     return nullptr;
     745             :   }
     746             : 
     747           0 :   TextureChild* tc = static_cast<TextureChild*>(actor);
     748             : 
     749           0 :   tc->Lock();
     750             : 
     751             :   // Since TextureClient may be destroyed asynchronously with respect to its
     752             :   // IPDL actor, we must acquire a reference within a lock. The mDestroyed bit
     753             :   // tells us whether or not the main thread has disconnected the TextureClient
     754             :   // from its actor.
     755           0 :   if (tc->mDestroyed) {
     756           0 :     tc->Unlock();
     757           0 :     return nullptr;
     758             :   }
     759             : 
     760           0 :   RefPtr<TextureClient> texture = tc->mTextureClient;
     761           0 :   tc->Unlock();
     762             : 
     763           0 :   return texture.forget();
     764             : }
     765             : 
     766             : bool
     767           0 : TextureClient::IsSharedWithCompositor() const {
     768           0 :   return mActor && mActor->IPCOpen();
     769             : }
     770             : 
     771             : void
     772           0 : TextureClient::AddFlags(TextureFlags aFlags)
     773             : {
     774           0 :   MOZ_ASSERT(!IsSharedWithCompositor() ||
     775             :              ((GetFlags() & TextureFlags::RECYCLE) && !IsAddedToCompositableClient()));
     776           0 :   mFlags |= aFlags;
     777           0 : }
     778             : 
     779             : void
     780           0 : TextureClient::RemoveFlags(TextureFlags aFlags)
     781             : {
     782           0 :   MOZ_ASSERT(!IsSharedWithCompositor() ||
     783             :              ((GetFlags() & TextureFlags::RECYCLE) && !IsAddedToCompositableClient()));
     784           0 :   mFlags &= ~aFlags;
     785           0 : }
     786             : 
     787             : void
     788           0 : TextureClient::RecycleTexture(TextureFlags aFlags)
     789             : {
     790           0 :   MOZ_ASSERT(GetFlags() & TextureFlags::RECYCLE);
     791           0 :   MOZ_ASSERT(!mIsLocked);
     792             : 
     793           0 :   mAddedToCompositableClient = false;
     794           0 :   if (mFlags != aFlags) {
     795           0 :     mFlags = aFlags;
     796             :   }
     797           0 : }
     798             : 
     799             : void
     800           9 : TextureClient::SetAddedToCompositableClient()
     801             : {
     802           9 :   if (!mAddedToCompositableClient) {
     803           9 :     mAddedToCompositableClient = true;
     804           9 :     if(!(GetFlags() & TextureFlags::RECYCLE)) {
     805           9 :       return;
     806             :     }
     807           0 :     MOZ_ASSERT(!mIsLocked);
     808           0 :     LockActor();
     809           0 :     if (IsValid() && mActor && !mActor->mDestroyed && mActor->IPCOpen()) {
     810           0 :       mActor->SendRecycleTexture(mFlags);
     811             :     }
     812           0 :     UnlockActor();
     813             :   }
     814             : }
     815             : 
     816           0 : void CancelTextureClientRecycle(uint64_t aTextureId, LayersIPCChannel* aAllocator)
     817             : {
     818           0 :   if (!aAllocator) {
     819           0 :     return;
     820             :   }
     821           0 :   MessageLoop* msgLoop = nullptr;
     822           0 :   msgLoop = aAllocator->GetMessageLoop();
     823           0 :   if (!msgLoop) {
     824           0 :     return;
     825             :   }
     826           0 :   if (MessageLoop::current() == msgLoop) {
     827           0 :     aAllocator->CancelWaitForRecycle(aTextureId);
     828             :   } else {
     829           0 :     msgLoop->PostTask(NewRunnableFunction(CancelTextureClientRecycle,
     830           0 :                                           aTextureId, aAllocator));
     831             :   }
     832             : }
     833             : 
     834             : void
     835           0 : TextureClient::CancelWaitForRecycle()
     836             : {
     837           0 :   if (GetFlags() & TextureFlags::RECYCLE) {
     838           0 :     CancelTextureClientRecycle(mSerial, GetAllocator());
     839           0 :     return;
     840             :   }
     841             : }
     842             : 
     843             : /* static */ void
     844           0 : TextureClient::TextureClientRecycleCallback(TextureClient* aClient, void* aClosure)
     845             : {
     846           0 :   MOZ_ASSERT(aClient->GetRecycleAllocator());
     847           0 :   aClient->GetRecycleAllocator()->RecycleTextureClient(aClient);
     848           0 : }
     849             : 
     850             : void
     851           0 : TextureClient::SetRecycleAllocator(ITextureClientRecycleAllocator* aAllocator)
     852             : {
     853           0 :   mRecycleAllocator = aAllocator;
     854           0 :   if (aAllocator) {
     855           0 :     SetRecycleCallback(TextureClientRecycleCallback, nullptr);
     856             :   } else {
     857           0 :     ClearRecycleCallback();
     858             :   }
     859           0 : }
     860             : 
     861             : bool
     862           9 : TextureClient::InitIPDLActor(CompositableForwarder* aForwarder)
     863             : {
     864           9 :   MOZ_ASSERT(aForwarder && aForwarder->GetTextureForwarder()->GetMessageLoop() == mAllocator->GetMessageLoop());
     865             : 
     866           9 :   if (mActor && !mActor->IPCOpen()) {
     867           0 :     return false;
     868             :   }
     869             : 
     870           9 :   if (mActor && !mActor->mDestroyed) {
     871           0 :     CompositableForwarder* currentFwd = mActor->mCompositableForwarder;
     872           0 :     TextureForwarder* currentTexFwd = mActor->mTextureForwarder;
     873           0 :     if (currentFwd != aForwarder) {
     874             :       // It's a bit iffy but right now ShadowLayerForwarder inherits TextureForwarder
     875             :       // even though it should not. ShadowLayerForwarder::GetTextureForwarder actually
     876             :       // returns a pointer to the CompositorBridgeChild.
     877             :       // It's Ok for a texture to move from a ShadowLayerForwarder to another, but
     878             :       // not form a CompositorBridgeChild to another (they use different channels).
     879           0 :       if (currentTexFwd && currentTexFwd != aForwarder->GetTextureForwarder()) {
     880           0 :         gfxCriticalError() << "Attempt to move a texture to a different channel CF.";
     881           0 :         return false;
     882             :       }
     883           0 :       if (currentFwd && currentFwd->GetCompositorBackendType() != aForwarder->GetCompositorBackendType()) {
     884           0 :         gfxCriticalError() << "Attempt to move a texture to different compositor backend.";
     885           0 :         return false;
     886             :       }
     887           0 :       if (ShadowLayerForwarder* forwarder = aForwarder->AsLayerForwarder()) {
     888             :         // Do the DOM labeling.
     889           0 :         if (nsIEventTarget* target = forwarder->GetEventTarget()) {
     890           0 :           forwarder->GetCompositorBridgeChild()->ReplaceEventTargetForActor(
     891           0 :             mActor, target);
     892             :         }
     893             :       }
     894           0 :       mActor->mCompositableForwarder = aForwarder;
     895             :     }
     896           0 :     return true;
     897             :   }
     898           9 :   MOZ_ASSERT(!mActor || mActor->mDestroyed, "Cannot use a texture on several IPC channels.");
     899             : 
     900          18 :   SurfaceDescriptor desc;
     901           9 :   if (!ToSurfaceDescriptor(desc)) {
     902           0 :     return false;
     903             :   }
     904             : 
     905             :   // Try external image id allocation.
     906           9 :   mExternalImageId = aForwarder->GetTextureForwarder()->GetNextExternalImageId();
     907             : 
     908           9 :   nsIEventTarget* target = nullptr;
     909             :   // Get the layers id if the forwarder is a ShadowLayerForwarder.
     910           9 :   if (ShadowLayerForwarder* forwarder = aForwarder->AsLayerForwarder()) {
     911           9 :     target = forwarder->GetEventTarget();
     912             :   }
     913             : 
     914          27 :   PTextureChild* actor = aForwarder->GetTextureForwarder()->CreateTexture(
     915             :     desc,
     916             :     aForwarder->GetCompositorBackendType(),
     917             :     GetFlags(),
     918           9 :     mSerial,
     919             :     mExternalImageId,
     920          18 :     target);
     921             : 
     922           9 :   if (!actor) {
     923           0 :     gfxCriticalNote << static_cast<int32_t>(desc.type()) << ", "
     924           0 :                     << static_cast<int32_t>(aForwarder->GetCompositorBackendType()) << ", "
     925           0 :                     << static_cast<uint32_t>(GetFlags())
     926           0 :                     << ", " << mSerial;
     927           0 :     return false;
     928             :   }
     929             : 
     930           9 :   mActor = static_cast<TextureChild*>(actor);
     931           9 :   mActor->mCompositableForwarder = aForwarder;
     932           9 :   mActor->mTextureForwarder = aForwarder->GetTextureForwarder();
     933           9 :   mActor->mTextureClient = this;
     934           9 :   mActor->mMainThreadOnly = !!(mFlags & TextureFlags::DEALLOCATE_MAIN_THREAD);
     935             : 
     936             :   // If the TextureClient is already locked, we have to lock TextureChild's mutex
     937             :   // since it will be unlocked in TextureClient::Unlock.
     938           9 :   if (mIsLocked) {
     939           0 :     LockActor();
     940             :   }
     941             : 
     942           9 :   return mActor->IPCOpen();
     943             : }
     944             : 
     945             : bool
     946           0 : TextureClient::InitIPDLActor(KnowsCompositor* aForwarder)
     947             : {
     948           0 :   MOZ_ASSERT(aForwarder && aForwarder->GetTextureForwarder()->GetMessageLoop() == mAllocator->GetMessageLoop());
     949           0 :   TextureForwarder* fwd = aForwarder->GetTextureForwarder();
     950           0 :   if (mActor && !mActor->mDestroyed) {
     951           0 :     CompositableForwarder* currentFwd = mActor->mCompositableForwarder;
     952           0 :     TextureForwarder* currentTexFwd = mActor->mTextureForwarder;
     953             : 
     954           0 :     if (currentFwd) {
     955           0 :       gfxCriticalError() << "Attempt to remove a texture from a CompositableForwarder.";
     956           0 :       return false;
     957             :     }
     958             : 
     959           0 :     if (currentTexFwd && currentTexFwd != fwd) {
     960           0 :       gfxCriticalError() << "Attempt to move a texture to a different channel TF.";
     961           0 :       return false;
     962             :     }
     963           0 :     mActor->mTextureForwarder = fwd;
     964           0 :     return true;
     965             :   }
     966           0 :   MOZ_ASSERT(!mActor || mActor->mDestroyed, "Cannot use a texture on several IPC channels.");
     967             : 
     968           0 :   SurfaceDescriptor desc;
     969           0 :   if (!ToSurfaceDescriptor(desc)) {
     970           0 :     return false;
     971             :   }
     972             : 
     973             :   // Try external image id allocation.
     974           0 :   mExternalImageId = aForwarder->GetTextureForwarder()->GetNextExternalImageId();
     975             : 
     976           0 :   PTextureChild* actor = fwd->CreateTexture(
     977             :     desc,
     978             :     aForwarder->GetCompositorBackendType(),
     979             :     GetFlags(),
     980           0 :     mSerial,
     981           0 :     mExternalImageId);
     982           0 :   if (!actor) {
     983           0 :     gfxCriticalNote << static_cast<int32_t>(desc.type()) << ", "
     984           0 :                     << static_cast<int32_t>(aForwarder->GetCompositorBackendType()) << ", "
     985           0 :                     << static_cast<uint32_t>(GetFlags())
     986           0 :                     << ", " << mSerial;
     987           0 :     return false;
     988             :   }
     989             : 
     990           0 :   mActor = static_cast<TextureChild*>(actor);
     991           0 :   mActor->mTextureForwarder = fwd;
     992           0 :   mActor->mTextureClient = this;
     993           0 :   mActor->mMainThreadOnly = !!(mFlags & TextureFlags::DEALLOCATE_MAIN_THREAD);
     994             : 
     995             :   // If the TextureClient is already locked, we have to lock TextureChild's mutex
     996             :   // since it will be unlocked in TextureClient::Unlock.
     997           0 :   if (mIsLocked) {
     998           0 :     LockActor();
     999             :   }
    1000             : 
    1001           0 :   return mActor->IPCOpen();
    1002             : }
    1003             : 
    1004             : PTextureChild*
    1005          99 : TextureClient::GetIPDLActor()
    1006             : {
    1007          99 :   return mActor;
    1008             : }
    1009             : 
    1010             : static inline gfx::BackendType
    1011           9 : BackendTypeForBackendSelector(LayersBackend aLayersBackend, BackendSelector aSelector)
    1012             : {
    1013           9 :   switch (aSelector) {
    1014             :     case BackendSelector::Canvas:
    1015           0 :       return gfxPlatform::GetPlatform()->GetPreferredCanvasBackend();
    1016             :     case BackendSelector::Content:
    1017           9 :       return gfxPlatform::GetPlatform()->GetContentBackendFor(aLayersBackend);
    1018             :     default:
    1019           0 :       MOZ_ASSERT_UNREACHABLE("Unknown backend selector");
    1020             :       return gfx::BackendType::NONE;
    1021             :   }
    1022             : };
    1023             : 
    1024             : // static
    1025             : already_AddRefed<TextureClient>
    1026           9 : TextureClient::CreateForDrawing(KnowsCompositor* aAllocator,
    1027             :                                 gfx::SurfaceFormat aFormat,
    1028             :                                 gfx::IntSize aSize,
    1029             :                                 BackendSelector aSelector,
    1030             :                                 TextureFlags aTextureFlags,
    1031             :                                 TextureAllocationFlags aAllocFlags)
    1032             : {
    1033           9 :   LayersBackend layersBackend = aAllocator->GetCompositorBackendType();
    1034           9 :   return TextureClient::CreateForDrawing(aAllocator->GetTextureForwarder(),
    1035             :                                          aFormat, aSize,
    1036             :                                          layersBackend,
    1037             :                                          aAllocator->GetMaxTextureSize(),
    1038             :                                          aSelector,
    1039             :                                          aTextureFlags,
    1040          18 :                                          aAllocFlags);
    1041             : }
    1042             : 
    1043             : // static
    1044             : already_AddRefed<TextureClient>
    1045           9 : TextureClient::CreateForDrawing(TextureForwarder* aAllocator,
    1046             :                                 gfx::SurfaceFormat aFormat,
    1047             :                                 gfx::IntSize aSize,
    1048             :                                 LayersBackend aLayersBackend,
    1049             :                                 int32_t aMaxTextureSize,
    1050             :                                 BackendSelector aSelector,
    1051             :                                 TextureFlags aTextureFlags,
    1052             :                                 TextureAllocationFlags aAllocFlags)
    1053             : {
    1054           9 :   gfx::BackendType moz2DBackend = BackendTypeForBackendSelector(aLayersBackend, aSelector);
    1055             : 
    1056             :   // also test the validity of aAllocator
    1057           9 :   if (!aAllocator || !aAllocator->IPCOpen()) {
    1058           0 :     return nullptr;
    1059             :   }
    1060             : 
    1061           9 :   if (!gfx::Factory::AllowedSurfaceSize(aSize)) {
    1062           0 :     return nullptr;
    1063             :   }
    1064             : 
    1065           9 :   TextureData* data = nullptr;
    1066             : 
    1067             : #ifdef XP_WIN
    1068             :   if (aLayersBackend == LayersBackend::LAYERS_D3D11 &&
    1069             :       (moz2DBackend == gfx::BackendType::DIRECT2D ||
    1070             :        moz2DBackend == gfx::BackendType::DIRECT2D1_1 ||
    1071             :        (!!(aAllocFlags & ALLOC_FOR_OUT_OF_BAND_CONTENT) &&
    1072             :         DeviceManagerDx::Get()->GetContentDevice())) &&
    1073             :       aSize.width <= aMaxTextureSize &&
    1074             :       aSize.height <= aMaxTextureSize &&
    1075             :       !(aAllocFlags & ALLOC_UPDATE_FROM_SURFACE))
    1076             :   {
    1077             :     data = DXGITextureData::Create(aSize, aFormat, aAllocFlags);
    1078             :   }
    1079             : 
    1080             :   if (aLayersBackend != LayersBackend::LAYERS_WR &&
    1081             :       !data && aFormat == SurfaceFormat::B8G8R8X8 &&
    1082             :       moz2DBackend == gfx::BackendType::CAIRO &&
    1083             :       NS_IsMainThread()) {
    1084             :     data = DIBTextureData::Create(aSize, aFormat, aAllocator);
    1085             :   }
    1086             : #endif
    1087             : 
    1088             : #ifdef MOZ_X11
    1089             :   gfxSurfaceType type =
    1090           9 :     gfxPlatform::GetPlatform()->ScreenReferenceSurface()->GetType();
    1091             : 
    1092           9 :   if (!data && aLayersBackend == LayersBackend::LAYERS_BASIC &&
    1093           0 :       moz2DBackend == gfx::BackendType::CAIRO &&
    1094             :       type == gfxSurfaceType::Xlib)
    1095             :   {
    1096           0 :     data = X11TextureData::Create(aSize, aFormat, aTextureFlags, aAllocator);
    1097             :   }
    1098             : #ifdef GL_PROVIDER_GLX
    1099          27 :   if (!data && aLayersBackend == LayersBackend::LAYERS_OPENGL &&
    1100           0 :       type == gfxSurfaceType::Xlib &&
    1101           9 :       aFormat != SurfaceFormat::A8 &&
    1102           0 :       gl::sGLXLibrary.UseTextureFromPixmap())
    1103             :   {
    1104           0 :     data = X11TextureData::Create(aSize, aFormat, aTextureFlags, aAllocator);
    1105             :   }
    1106             : #endif
    1107             : #endif
    1108             : 
    1109             : #ifdef XP_MACOSX
    1110             :   if (!data && gfxPrefs::UseIOSurfaceTextures()) {
    1111             :     data = MacIOSurfaceTextureData::Create(aSize, aFormat, moz2DBackend);
    1112             :   }
    1113             : #endif
    1114             : 
    1115           9 :   if (data) {
    1116           0 :     return MakeAndAddRef<TextureClient>(data, aTextureFlags, aAllocator);
    1117             :   }
    1118             : 
    1119           9 :   if (moz2DBackend == BackendType::SKIA && aFormat == SurfaceFormat::B8G8R8X8) {
    1120             :     // Skia doesn't support RGBX, so ensure we clear the buffer for the proper alpha values.
    1121           5 :     aAllocFlags = TextureAllocationFlags(aAllocFlags | ALLOC_CLEAR_BUFFER);
    1122             :   }
    1123             : 
    1124             :   // Can't do any better than a buffer texture client.
    1125             :   return TextureClient::CreateForRawBufferAccess(aAllocator, aFormat, aSize,
    1126             :                                                  moz2DBackend, aLayersBackend,
    1127           9 :                                                  aTextureFlags, aAllocFlags);
    1128             : }
    1129             : 
    1130             : // static
    1131             : already_AddRefed<TextureClient>
    1132           0 : TextureClient::CreateFromSurface(KnowsCompositor* aAllocator,
    1133             :                                  gfx::SourceSurface* aSurface,
    1134             :                                  BackendSelector aSelector,
    1135             :                                  TextureFlags aTextureFlags,
    1136             :                                  TextureAllocationFlags aAllocFlags)
    1137             : {
    1138             :   // also test the validity of aAllocator
    1139           0 :   if (!aAllocator || !aAllocator->GetTextureForwarder()->IPCOpen()) {
    1140           0 :     return nullptr;
    1141             :   }
    1142             : 
    1143           0 :   gfx::IntSize size = aSurface->GetSize();
    1144             : 
    1145           0 :   if (!gfx::Factory::AllowedSurfaceSize(size)) {
    1146           0 :     return nullptr;
    1147             :   }
    1148             : 
    1149           0 :   TextureData* data = nullptr;
    1150             : #if defined(XP_WIN)
    1151             :   LayersBackend layersBackend = aAllocator->GetCompositorBackendType();
    1152             :   gfx::BackendType moz2DBackend = BackendTypeForBackendSelector(layersBackend, aSelector);
    1153             : 
    1154             :   int32_t maxTextureSize = aAllocator->GetMaxTextureSize();
    1155             : 
    1156             :   if (layersBackend == LayersBackend::LAYERS_D3D11 &&
    1157             :     (moz2DBackend == gfx::BackendType::DIRECT2D ||
    1158             :       moz2DBackend == gfx::BackendType::DIRECT2D1_1 ||
    1159             :       (!!(aAllocFlags & ALLOC_FOR_OUT_OF_BAND_CONTENT) &&
    1160             :        DeviceManagerDx::Get()->GetContentDevice())) &&
    1161             :     size.width <= maxTextureSize &&
    1162             :     size.height <= maxTextureSize)
    1163             :   {
    1164             :     data = D3D11TextureData::Create(aSurface, aAllocFlags);
    1165             :   }
    1166             : #endif
    1167             : 
    1168           0 :   if (data) {
    1169           0 :     return MakeAndAddRef<TextureClient>(data, aTextureFlags, aAllocator->GetTextureForwarder());
    1170             :   }
    1171             : 
    1172             :   // Fall back to using UpdateFromSurface
    1173             : 
    1174           0 :   TextureAllocationFlags allocFlags = TextureAllocationFlags(aAllocFlags | ALLOC_UPDATE_FROM_SURFACE);
    1175           0 :   RefPtr<TextureClient> client = CreateForDrawing(aAllocator, aSurface->GetFormat(), size,
    1176           0 :                                                   aSelector, aTextureFlags, allocFlags);
    1177           0 :   if (!client) {
    1178           0 :     return nullptr;
    1179             :   }
    1180             : 
    1181           0 :   TextureClientAutoLock autoLock(client, OpenMode::OPEN_WRITE_ONLY);
    1182           0 :   if (!autoLock.Succeeded()) {
    1183           0 :     return nullptr;
    1184             :   }
    1185             : 
    1186           0 :   client->UpdateFromSurface(aSurface);
    1187           0 :   return client.forget();
    1188             : }
    1189             : 
    1190             : // static
    1191             : already_AddRefed<TextureClient>
    1192           0 : TextureClient::CreateForRawBufferAccess(KnowsCompositor* aAllocator,
    1193             :                                         gfx::SurfaceFormat aFormat,
    1194             :                                         gfx::IntSize aSize,
    1195             :                                         gfx::BackendType aMoz2DBackend,
    1196             :                                         TextureFlags aTextureFlags,
    1197             :                                         TextureAllocationFlags aAllocFlags)
    1198             : {
    1199           0 :   return CreateForRawBufferAccess(aAllocator->GetTextureForwarder(),
    1200             :                                   aFormat, aSize, aMoz2DBackend,
    1201             :                                   aAllocator->GetCompositorBackendType(),
    1202           0 :                                   aTextureFlags, aAllocFlags);
    1203             : }
    1204             : 
    1205             : // static
    1206             : already_AddRefed<TextureClient>
    1207           9 : TextureClient::CreateForRawBufferAccess(LayersIPCChannel* aAllocator,
    1208             :                                         gfx::SurfaceFormat aFormat,
    1209             :                                         gfx::IntSize aSize,
    1210             :                                         gfx::BackendType aMoz2DBackend,
    1211             :                                         LayersBackend aLayersBackend,
    1212             :                                         TextureFlags aTextureFlags,
    1213             :                                         TextureAllocationFlags aAllocFlags)
    1214             : {
    1215             :   // also test the validity of aAllocator
    1216           9 :   if (!aAllocator || !aAllocator->IPCOpen()) {
    1217           0 :     return nullptr;
    1218             :   }
    1219             : 
    1220           9 :   if (aAllocFlags & ALLOC_DISALLOW_BUFFERTEXTURECLIENT) {
    1221           0 :     return nullptr;
    1222             :   }
    1223             : 
    1224           9 :   if (!gfx::Factory::AllowedSurfaceSize(aSize)) {
    1225           0 :     return nullptr;
    1226             :   }
    1227             : 
    1228             :   // D2D backend does not support CreateDrawTargetForData(). Use CAIRO instead.
    1229           9 :   if (aMoz2DBackend == gfx::BackendType::DIRECT2D ||
    1230             :       aMoz2DBackend == gfx::BackendType::DIRECT2D1_1) {
    1231           0 :     aMoz2DBackend = gfx::BackendType::CAIRO;
    1232             :   }
    1233             : 
    1234           9 :   TextureData* texData = BufferTextureData::Create(aSize, aFormat, aMoz2DBackend,
    1235             :                                                    aLayersBackend, aTextureFlags,
    1236           9 :                                                    aAllocFlags, aAllocator);
    1237           9 :   if (!texData) {
    1238           0 :     return nullptr;
    1239             :   }
    1240             : 
    1241           9 :   return MakeAndAddRef<TextureClient>(texData, aTextureFlags, aAllocator);
    1242             : }
    1243             : 
    1244             : // static
    1245             : already_AddRefed<TextureClient>
    1246           0 : TextureClient::CreateForYCbCr(KnowsCompositor* aAllocator,
    1247             :                               gfx::IntSize aYSize,
    1248             :                               gfx::IntSize aCbCrSize,
    1249             :                               StereoMode aStereoMode,
    1250             :                               YUVColorSpace aYUVColorSpace,
    1251             :                               TextureFlags aTextureFlags)
    1252             : {
    1253           0 :   if (!aAllocator || !aAllocator->GetLayersIPCActor()->IPCOpen()) {
    1254           0 :     return nullptr;
    1255             :   }
    1256             : 
    1257           0 :   if (!gfx::Factory::AllowedSurfaceSize(aYSize)) {
    1258           0 :     return nullptr;
    1259             :   }
    1260             : 
    1261           0 :   TextureData* data = BufferTextureData::CreateForYCbCr(aAllocator, aYSize, aCbCrSize,
    1262             :                                                         aStereoMode, aYUVColorSpace,
    1263           0 :                                                         aTextureFlags);
    1264           0 :   if (!data) {
    1265           0 :     return nullptr;
    1266             :   }
    1267             : 
    1268             :   return MakeAndAddRef<TextureClient>(data, aTextureFlags,
    1269           0 :                                       aAllocator->GetTextureForwarder());
    1270             : }
    1271             : 
    1272             : // static
    1273             : already_AddRefed<TextureClient>
    1274           0 : TextureClient::CreateForYCbCrWithBufferSize(KnowsCompositor* aAllocator,
    1275             :                                             size_t aSize,
    1276             :                                             YUVColorSpace aYUVColorSpace,
    1277             :                                             TextureFlags aTextureFlags)
    1278             : {
    1279           0 :   if (!aAllocator || !aAllocator->GetLayersIPCActor()->IPCOpen()) {
    1280           0 :     return nullptr;
    1281             :   }
    1282             : 
    1283             :   TextureData* data =
    1284           0 :     BufferTextureData::CreateForYCbCrWithBufferSize(aAllocator, aSize, aYUVColorSpace,
    1285           0 :                                                     aTextureFlags);
    1286           0 :   if (!data) {
    1287           0 :     return nullptr;
    1288             :   }
    1289             : 
    1290             :   return MakeAndAddRef<TextureClient>(data, aTextureFlags,
    1291           0 :                                       aAllocator->GetTextureForwarder());
    1292             : }
    1293             : 
    1294           9 : TextureClient::TextureClient(TextureData* aData, TextureFlags aFlags, LayersIPCChannel* aAllocator)
    1295             : : AtomicRefCountedWithFinalize("TextureClient")
    1296             : , mAllocator(aAllocator)
    1297             : , mActor(nullptr)
    1298             : , mData(aData)
    1299             : , mFlags(aFlags)
    1300             : , mOpenMode(OpenMode::OPEN_NONE)
    1301             : #ifdef DEBUG
    1302             : , mExpectedDtRefs(0)
    1303             : #endif
    1304             : , mIsLocked(false)
    1305             : , mIsReadLocked(false)
    1306             : , mUpdated(false)
    1307             : , mAddedToCompositableClient(false)
    1308             : , mWorkaroundAnnoyingSharedSurfaceLifetimeIssues(false)
    1309             : , mWorkaroundAnnoyingSharedSurfaceOwnershipIssues(false)
    1310             : , mFwdTransactionId(0)
    1311           9 : , mSerial(++sSerialCounter)
    1312             : #ifdef GFX_DEBUG_TRACK_CLIENTS_IN_POOL
    1313          18 : , mPoolTracker(nullptr)
    1314             : #endif
    1315             : {
    1316           9 :   mData->FillInfo(mInfo);
    1317           9 :   mFlags |= mData->GetTextureFlags();
    1318           9 : }
    1319             : 
    1320           0 : bool TextureClient::CopyToTextureClient(TextureClient* aTarget,
    1321             :                                         const gfx::IntRect* aRect,
    1322             :                                         const gfx::IntPoint* aPoint)
    1323             : {
    1324           0 :   MOZ_ASSERT(IsLocked());
    1325           0 :   MOZ_ASSERT(aTarget->IsLocked());
    1326             : 
    1327           0 :   if (!aTarget->CanExposeDrawTarget() || !CanExposeDrawTarget()) {
    1328           0 :     return false;
    1329             :   }
    1330             : 
    1331           0 :   RefPtr<DrawTarget> destinationTarget = aTarget->BorrowDrawTarget();
    1332           0 :   if (!destinationTarget) {
    1333           0 :       gfxWarning() << "TextureClient::CopyToTextureClient (dest) failed in BorrowDrawTarget";
    1334           0 :     return false;
    1335             :   }
    1336             : 
    1337           0 :   RefPtr<DrawTarget> sourceTarget = BorrowDrawTarget();
    1338           0 :   if (!sourceTarget) {
    1339           0 :     gfxWarning() << "TextureClient::CopyToTextureClient (src) failed in BorrowDrawTarget";
    1340           0 :     return false;
    1341             :   }
    1342             : 
    1343           0 :   RefPtr<gfx::SourceSurface> source = sourceTarget->Snapshot();
    1344           0 :   destinationTarget->CopySurface(source,
    1345           0 :                                  aRect ? *aRect : gfx::IntRect(gfx::IntPoint(0, 0), GetSize()),
    1346           0 :                                  aPoint ? *aPoint : gfx::IntPoint(0, 0));
    1347           0 :   return true;
    1348             : }
    1349             : 
    1350             : already_AddRefed<gfx::DataSourceSurface>
    1351           0 : TextureClient::GetAsSurface()
    1352             : {
    1353           0 :   if (!Lock(OpenMode::OPEN_READ)) {
    1354           0 :     return nullptr;
    1355             :   }
    1356           0 :   RefPtr<gfx::DataSourceSurface> data;
    1357             :   {  // scope so that the DrawTarget is destroyed before Unlock()
    1358           0 :     RefPtr<gfx::DrawTarget> dt = BorrowDrawTarget();
    1359           0 :     if (dt) {
    1360           0 :       RefPtr<gfx::SourceSurface> surf = dt->Snapshot();
    1361           0 :       if (surf) {
    1362           0 :         data = surf->GetDataSurface();
    1363             :       }
    1364             :     }
    1365             :   }
    1366           0 :   Unlock();
    1367           0 :   return data.forget();
    1368             : }
    1369             : 
    1370             : void
    1371           0 : TextureClient::PrintInfo(std::stringstream& aStream, const char* aPrefix)
    1372             : {
    1373           0 :   aStream << aPrefix;
    1374           0 :   aStream << nsPrintfCString("TextureClient (0x%p)", this).get();
    1375           0 :   AppendToString(aStream, GetSize(), " [size=", "]");
    1376           0 :   AppendToString(aStream, GetFormat(), " [format=", "]");
    1377           0 :   AppendToString(aStream, mFlags, " [flags=", "]");
    1378             : 
    1379             : #ifdef MOZ_DUMP_PAINTING
    1380           0 :   if (gfxPrefs::LayersDumpTexture() ||
    1381           0 :       profiler_feature_active(ProfilerFeature::LayersDump)) {
    1382           0 :     nsAutoCString pfx(aPrefix);
    1383           0 :     pfx += "  ";
    1384             : 
    1385           0 :     aStream << "\n" << pfx.get() << "Surface: ";
    1386           0 :     RefPtr<gfx::DataSourceSurface> dSurf = GetAsSurface();
    1387           0 :     if (dSurf) {
    1388           0 :       aStream << gfxUtils::GetAsLZ4Base64Str(dSurf).get();
    1389             :     }
    1390             :   }
    1391             : #endif
    1392           0 : }
    1393             : 
    1394             : class MemoryTextureReadLock : public NonBlockingTextureReadLock {
    1395             : public:
    1396             :   MemoryTextureReadLock();
    1397             : 
    1398             :   ~MemoryTextureReadLock();
    1399             : 
    1400             :   virtual bool ReadLock() override;
    1401             : 
    1402             :   virtual int32_t ReadUnlock() override;
    1403             : 
    1404             :   virtual int32_t GetReadCount() override;
    1405             : 
    1406           0 :   virtual LockType GetType() override { return TYPE_NONBLOCKING_MEMORY; }
    1407             : 
    1408           0 :   virtual bool IsValid() const override { return true; };
    1409             : 
    1410             :   virtual bool Serialize(ReadLockDescriptor& aOutput, base::ProcessId aOther) override;
    1411             : 
    1412             :   int32_t mReadCount;
    1413             : };
    1414             : 
    1415             : // The cross-prcess implementation of TextureReadLock.
    1416             : //
    1417             : // Since we don't use cross-process reference counting for the ReadLock objects,
    1418             : // we use the lock's internal counter as a way to know when to deallocate the
    1419             : // underlying shmem section: when the counter is equal to 1, it means that the
    1420             : // lock is not "held" (the texture is writable), when the counter is equal to 0
    1421             : // it means that we can safely deallocate the shmem section without causing a race
    1422             : // condition with the other process.
    1423             : class ShmemTextureReadLock : public NonBlockingTextureReadLock {
    1424             : public:
    1425             :   struct ShmReadLockInfo {
    1426             :     int32_t readCount;
    1427             :   };
    1428             : 
    1429             :   explicit ShmemTextureReadLock(LayersIPCChannel* aAllocator);
    1430             : 
    1431             :   ~ShmemTextureReadLock();
    1432             : 
    1433             :   virtual bool ReadLock() override;
    1434             : 
    1435             :   virtual int32_t ReadUnlock() override;
    1436             : 
    1437             :   virtual int32_t GetReadCount() override;
    1438             : 
    1439           0 :   virtual bool IsValid() const override { return mAllocSuccess; };
    1440             : 
    1441           0 :   virtual LockType GetType() override { return TYPE_NONBLOCKING_SHMEM; }
    1442             : 
    1443             :   virtual bool Serialize(ReadLockDescriptor& aOutput, base::ProcessId aOther) override;
    1444             : 
    1445           0 :   mozilla::layers::ShmemSection& GetShmemSection() { return mShmemSection; }
    1446             : 
    1447           0 :   explicit ShmemTextureReadLock(const mozilla::layers::ShmemSection& aShmemSection)
    1448           0 :     : mShmemSection(aShmemSection)
    1449           0 :     , mAllocSuccess(true)
    1450             :   {
    1451           0 :     MOZ_COUNT_CTOR(ShmemTextureReadLock);
    1452           0 :   }
    1453             : 
    1454           0 :   ShmReadLockInfo* GetShmReadLockInfoPtr()
    1455             :   {
    1456             :     return reinterpret_cast<ShmReadLockInfo*>
    1457           0 :       (mShmemSection.shmem().get<char>() + mShmemSection.offset());
    1458             :   }
    1459             : 
    1460             :   RefPtr<LayersIPCChannel> mClientAllocator;
    1461             :   mozilla::layers::ShmemSection mShmemSection;
    1462             :   bool mAllocSuccess;
    1463             : };
    1464             : 
    1465         111 : class CrossProcessSemaphoreReadLock : public TextureReadLock
    1466             : {
    1467             : public:
    1468           9 :   CrossProcessSemaphoreReadLock()
    1469           9 :     : mSemaphore(CrossProcessSemaphore::Create("TextureReadLock", 1))
    1470           9 :   {}
    1471          33 :   explicit CrossProcessSemaphoreReadLock(CrossProcessSemaphoreHandle aHandle)
    1472          33 :     : mSemaphore(CrossProcessSemaphore::Create(aHandle))
    1473          33 :   {}
    1474             : 
    1475          33 :   virtual bool ReadLock() override
    1476             :   {
    1477          33 :     if (!IsValid()) {
    1478           0 :       return false;
    1479             :     }
    1480          33 :     return mSemaphore->Wait();
    1481             :   }
    1482          34 :   virtual bool TryReadLock(TimeDuration aTimeout) override
    1483             :   {
    1484          34 :     if (!IsValid()) {
    1485           0 :       return false;
    1486             :     }
    1487          34 :     return mSemaphore->Wait(Some(aTimeout));
    1488             :   }
    1489          65 :   virtual int32_t ReadUnlock() override
    1490             :   {
    1491          65 :     if (!IsValid()) {
    1492           0 :       return 1;
    1493             :     }
    1494          65 :     mSemaphore->Signal();
    1495          65 :     return 1;
    1496             :   }
    1497         165 :   virtual bool IsValid() const override { return !!mSemaphore; }
    1498             : 
    1499             :   virtual bool Serialize(ReadLockDescriptor& aOutput, base::ProcessId aOther) override;
    1500             : 
    1501           0 :   virtual LockType GetType() override { return TYPE_CROSS_PROCESS_SEMAPHORE; }
    1502             : 
    1503             :   UniquePtr<CrossProcessSemaphore> mSemaphore;
    1504             : };
    1505             : 
    1506             : // static
    1507             : already_AddRefed<TextureReadLock>
    1508          33 : TextureReadLock::Deserialize(const ReadLockDescriptor& aDescriptor, ISurfaceAllocator* aAllocator)
    1509             : {
    1510          33 :   switch (aDescriptor.type()) {
    1511             :     case ReadLockDescriptor::TShmemSection: {
    1512           0 :       const ShmemSection& section = aDescriptor.get_ShmemSection();
    1513           0 :       MOZ_RELEASE_ASSERT(section.shmem().IsReadable());
    1514           0 :       return MakeAndAddRef<ShmemTextureReadLock>(section);
    1515             :     }
    1516             :     case ReadLockDescriptor::Tuintptr_t: {
    1517           0 :       if (!aAllocator->IsSameProcess()) {
    1518             :         // Trying to use a memory based lock instead of a shmem based one in
    1519             :         // the cross-process case is a bad security violation.
    1520           0 :         NS_ERROR("A client process may be trying to peek at the host's address space!");
    1521           0 :         return nullptr;
    1522             :       }
    1523             :       RefPtr<TextureReadLock> lock = reinterpret_cast<MemoryTextureReadLock*>(
    1524           0 :         aDescriptor.get_uintptr_t()
    1525           0 :       );
    1526             : 
    1527           0 :       MOZ_ASSERT(lock);
    1528           0 :       if (lock) {
    1529             :         // The corresponding AddRef is in MemoryTextureReadLock::Serialize
    1530           0 :         lock.get()->Release();
    1531             :       }
    1532             : 
    1533           0 :       return lock.forget();
    1534             :     }
    1535             :     case ReadLockDescriptor::TCrossProcessSemaphoreDescriptor: {
    1536          33 :       return MakeAndAddRef<CrossProcessSemaphoreReadLock>(aDescriptor.get_CrossProcessSemaphoreDescriptor().sem());
    1537             :     }
    1538             :     case ReadLockDescriptor::Tnull_t: {
    1539           0 :       return nullptr;
    1540             :     }
    1541             :     default: {
    1542             :       // Invalid descriptor.
    1543           0 :       MOZ_DIAGNOSTIC_ASSERT(false);
    1544             :     }
    1545             :   }
    1546             :   return nullptr;
    1547             : }
    1548             : // static
    1549             : already_AddRefed<TextureReadLock>
    1550           0 : NonBlockingTextureReadLock::Create(LayersIPCChannel* aAllocator)
    1551             : {
    1552           0 :   if (aAllocator->IsSameProcess()) {
    1553             :     // If our compositor is in the same process, we can save some cycles by not
    1554             :     // using shared memory.
    1555           0 :     return MakeAndAddRef<MemoryTextureReadLock>();
    1556             :   }
    1557             : 
    1558           0 :   return MakeAndAddRef<ShmemTextureReadLock>(aAllocator);
    1559             : }
    1560             : 
    1561           0 : MemoryTextureReadLock::MemoryTextureReadLock()
    1562           0 : : mReadCount(1)
    1563             : {
    1564           0 :   MOZ_COUNT_CTOR(MemoryTextureReadLock);
    1565           0 : }
    1566             : 
    1567           0 : MemoryTextureReadLock::~MemoryTextureReadLock()
    1568             : {
    1569             :   // One read count that is added in constructor.
    1570           0 :   MOZ_ASSERT(mReadCount == 1);
    1571           0 :   MOZ_COUNT_DTOR(MemoryTextureReadLock);
    1572           0 : }
    1573             : 
    1574             : bool
    1575           0 : MemoryTextureReadLock::Serialize(ReadLockDescriptor& aOutput, base::ProcessId aOther)
    1576             : {
    1577             :   // AddRef here and Release when receiving on the host side to make sure the
    1578             :   // reference count doesn't go to zero before the host receives the message.
    1579             :   // see TextureReadLock::Deserialize
    1580           0 :   this->AddRef();
    1581           0 :   aOutput = ReadLockDescriptor(uintptr_t(this));
    1582           0 :   return true;
    1583             : }
    1584             : 
    1585             : bool
    1586           0 : MemoryTextureReadLock::ReadLock()
    1587             : {
    1588           0 :   NS_ASSERT_OWNINGTHREAD(MemoryTextureReadLock);
    1589             : 
    1590           0 :   PR_ATOMIC_INCREMENT(&mReadCount);
    1591           0 :   return true;
    1592             : }
    1593             : 
    1594             : int32_t
    1595           0 : MemoryTextureReadLock::ReadUnlock()
    1596             : {
    1597           0 :   int32_t readCount = PR_ATOMIC_DECREMENT(&mReadCount);
    1598           0 :   MOZ_ASSERT(readCount >= 0);
    1599             : 
    1600           0 :   return readCount;
    1601             : }
    1602             : 
    1603             : int32_t
    1604           0 : MemoryTextureReadLock::GetReadCount()
    1605             : {
    1606           0 :   NS_ASSERT_OWNINGTHREAD(MemoryTextureReadLock);
    1607           0 :   return mReadCount;
    1608             : }
    1609             : 
    1610           0 : ShmemTextureReadLock::ShmemTextureReadLock(LayersIPCChannel* aAllocator)
    1611             :   : mClientAllocator(aAllocator)
    1612           0 :   , mAllocSuccess(false)
    1613             : {
    1614           0 :   MOZ_COUNT_CTOR(ShmemTextureReadLock);
    1615           0 :   MOZ_ASSERT(mClientAllocator);
    1616             : #define MOZ_ALIGN_WORD(x) (((x) + 3) & ~3)
    1617           0 :   if (mClientAllocator->GetTileLockAllocator()->AllocShmemSection(
    1618             :       MOZ_ALIGN_WORD(sizeof(ShmReadLockInfo)), &mShmemSection)) {
    1619           0 :     ShmReadLockInfo* info = GetShmReadLockInfoPtr();
    1620           0 :     info->readCount = 1;
    1621           0 :     mAllocSuccess = true;
    1622             :   }
    1623           0 : }
    1624             : 
    1625           0 : ShmemTextureReadLock::~ShmemTextureReadLock()
    1626             : {
    1627           0 :   if (mClientAllocator) {
    1628             :     // Release one read count that is added in constructor.
    1629             :     // The count is kept for calling GetReadCount() by TextureClientPool.
    1630           0 :     ReadUnlock();
    1631             :   }
    1632           0 :   MOZ_COUNT_DTOR(ShmemTextureReadLock);
    1633           0 : }
    1634             : 
    1635             : bool
    1636           0 : ShmemTextureReadLock::Serialize(ReadLockDescriptor& aOutput, base::ProcessId aOther)
    1637             : {
    1638           0 :   aOutput = ReadLockDescriptor(GetShmemSection());
    1639           0 :   return true;
    1640             : }
    1641             : 
    1642             : bool
    1643           0 : ShmemTextureReadLock::ReadLock() {
    1644           0 :   NS_ASSERT_OWNINGTHREAD(ShmemTextureReadLock);
    1645           0 :   if (!mAllocSuccess) {
    1646           0 :     return false;
    1647             :   }
    1648           0 :   ShmReadLockInfo* info = GetShmReadLockInfoPtr();
    1649           0 :   PR_ATOMIC_INCREMENT(&info->readCount);
    1650           0 :   return true;
    1651             : }
    1652             : 
    1653             : int32_t
    1654           0 : ShmemTextureReadLock::ReadUnlock() {
    1655           0 :   if (!mAllocSuccess) {
    1656           0 :     return 0;
    1657             :   }
    1658           0 :   ShmReadLockInfo* info = GetShmReadLockInfoPtr();
    1659           0 :   int32_t readCount = PR_ATOMIC_DECREMENT(&info->readCount);
    1660           0 :   MOZ_ASSERT(readCount >= 0);
    1661           0 :   if (readCount <= 0) {
    1662           0 :     if (mClientAllocator && mClientAllocator->GetTileLockAllocator()) {
    1663           0 :       mClientAllocator->GetTileLockAllocator()->DeallocShmemSection(mShmemSection);
    1664             :     } else {
    1665             :       // we are on the compositor process, or IPC is down.
    1666           0 :       FixedSizeSmallShmemSectionAllocator::FreeShmemSection(mShmemSection);
    1667             :     }
    1668             :   }
    1669           0 :   return readCount;
    1670             : }
    1671             : 
    1672             : int32_t
    1673           0 : ShmemTextureReadLock::GetReadCount() {
    1674           0 :   NS_ASSERT_OWNINGTHREAD(ShmemTextureReadLock);
    1675           0 :   if (!mAllocSuccess) {
    1676           0 :     return 0;
    1677             :   }
    1678           0 :   ShmReadLockInfo* info = GetShmReadLockInfoPtr();
    1679           0 :   return info->readCount;
    1680             : }
    1681             : 
    1682             : bool
    1683          33 : CrossProcessSemaphoreReadLock::Serialize(ReadLockDescriptor& aOutput, base::ProcessId aOther)
    1684             : {
    1685          33 :   if (IsValid()) {
    1686          33 :     aOutput = ReadLockDescriptor(CrossProcessSemaphoreDescriptor(mSemaphore->ShareToProcess(aOther)));
    1687          33 :     return true;
    1688             :   } else {
    1689           0 :     return false;
    1690             :   }
    1691             : }
    1692             : 
    1693             : void
    1694           9 : TextureClient::EnableBlockingReadLock()
    1695             : {
    1696           9 :   if (!mReadLock) {
    1697           9 :     mReadLock = new CrossProcessSemaphoreReadLock();
    1698             :   }
    1699           9 : }
    1700             : 
    1701             : bool
    1702           0 : UpdateYCbCrTextureClient(TextureClient* aTexture, const PlanarYCbCrData& aData)
    1703             : {
    1704           0 :   MOZ_ASSERT(aTexture);
    1705           0 :   MOZ_ASSERT(aTexture->IsLocked());
    1706           0 :   MOZ_ASSERT(aTexture->GetFormat() == gfx::SurfaceFormat::YUV, "This textureClient can only use YCbCr data");
    1707           0 :   MOZ_ASSERT(!aTexture->IsImmutable());
    1708           0 :   MOZ_ASSERT(aTexture->IsValid());
    1709           0 :   MOZ_ASSERT(aData.mCbSkip == aData.mCrSkip);
    1710             : 
    1711           0 :   MappedYCbCrTextureData mapped;
    1712           0 :   if (!aTexture->BorrowMappedYCbCrData(mapped)) {
    1713           0 :     NS_WARNING("Failed to extract YCbCr info!");
    1714           0 :     return false;
    1715             :   }
    1716             : 
    1717           0 :   MappedYCbCrTextureData srcData;
    1718           0 :   srcData.y.data = aData.mYChannel;
    1719           0 :   srcData.y.size = aData.mYSize;
    1720           0 :   srcData.y.stride = aData.mYStride;
    1721           0 :   srcData.y.skip = aData.mYSkip;
    1722           0 :   srcData.cb.data = aData.mCbChannel;
    1723           0 :   srcData.cb.size = aData.mCbCrSize;
    1724           0 :   srcData.cb.stride = aData.mCbCrStride;
    1725           0 :   srcData.cb.skip = aData.mCbSkip;
    1726           0 :   srcData.cr.data = aData.mCrChannel;
    1727           0 :   srcData.cr.size = aData.mCbCrSize;
    1728           0 :   srcData.cr.stride = aData.mCbCrStride;
    1729           0 :   srcData.cr.skip = aData.mCrSkip;
    1730           0 :   srcData.metadata = nullptr;
    1731             : 
    1732           0 :   if (!srcData.CopyInto(mapped)) {
    1733           0 :     NS_WARNING("Failed to copy image data!");
    1734           0 :     return false;
    1735             :   }
    1736             : 
    1737           0 :   if (TextureRequiresLocking(aTexture->GetFlags())) {
    1738             :     // We don't have support for proper locking yet, so we'll
    1739             :     // have to be immutable instead.
    1740           0 :     aTexture->MarkImmutable();
    1741             :   }
    1742           0 :   return true;
    1743             : }
    1744             : 
    1745             : already_AddRefed<SyncObject>
    1746           6 : SyncObject::CreateSyncObject(SyncHandle aHandle
    1747             : #ifdef XP_WIN
    1748             :                              , ID3D11Device* aDevice
    1749             : #endif
    1750             :                              )
    1751             : {
    1752           6 :   if (!aHandle) {
    1753           6 :     return nullptr;
    1754             :   }
    1755             : 
    1756             : #ifdef XP_WIN
    1757             :   return MakeAndAddRef<SyncObjectD3D11>(aHandle, aDevice);
    1758             : #else
    1759           0 :   MOZ_ASSERT_UNREACHABLE();
    1760             :   return nullptr;
    1761             : #endif
    1762             : }
    1763             : 
    1764             : already_AddRefed<TextureClient>
    1765           0 : TextureClient::CreateWithData(TextureData* aData, TextureFlags aFlags, LayersIPCChannel* aAllocator)
    1766             : {
    1767           0 :   if (!aData) {
    1768           0 :     return nullptr;
    1769             :   }
    1770           0 :   return MakeAndAddRef<TextureClient>(aData, aFlags, aAllocator);
    1771             : }
    1772             : 
    1773             : bool
    1774           0 : MappedYCbCrChannelData::CopyInto(MappedYCbCrChannelData& aDst)
    1775             : {
    1776           0 :   if (!data || !aDst.data || size != aDst.size) {
    1777           0 :     return false;
    1778             :   }
    1779             : 
    1780           0 :   if (stride == aDst.stride) {
    1781             :     // fast path!
    1782             :     // We assume that the padding in the destination is there for alignment
    1783             :     // purposes and doesn't contain useful data.
    1784           0 :     memcpy(aDst.data, data, stride * size.height);
    1785           0 :     return true;
    1786             :   }
    1787             : 
    1788           0 :   for (int32_t i = 0; i < size.height; ++i) {
    1789           0 :     if (aDst.skip == 0 && skip == 0) {
    1790             :       // fast-ish path
    1791           0 :       memcpy(aDst.data + i * aDst.stride,
    1792           0 :              data + i * stride,
    1793           0 :              size.width);
    1794             :     } else {
    1795             :       // slow path
    1796           0 :       uint8_t* src = data + i * stride;
    1797           0 :       uint8_t* dst = aDst.data + i * aDst.stride;
    1798           0 :       for (int32_t j = 0; j < size.width; ++j) {
    1799           0 :         *dst = *src;
    1800           0 :         src += 1 + skip;
    1801           0 :         dst += 1 + aDst.skip;
    1802             :       }
    1803             :     }
    1804             :   }
    1805           0 :   return true;
    1806             : }
    1807             : 
    1808             : } // namespace layers
    1809             : } // namespace mozilla

Generated by: LCOV version 1.13