/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef MOZILLA_GFX_TEXTURECLIENT_H #define MOZILLA_GFX_TEXTURECLIENT_H #include // for size_t #include // for uint32_t, uint8_t, uint64_t #include "GLTextureImage.h" // for TextureImage #include "ImageTypes.h" // for StereoMode #include "mozilla/Assertions.h" // for MOZ_ASSERT, etc #include "mozilla/Atomics.h" #include "mozilla/Attributes.h" // for override #include "mozilla/DebugOnly.h" #include "mozilla/RefPtr.h" // for RefPtr, RefCounted #include "mozilla/gfx/2D.h" // for DrawTarget #include "mozilla/gfx/Point.h" // for IntSize #include "mozilla/gfx/Types.h" // for SurfaceFormat #include "mozilla/ipc/Shmem.h" // for Shmem #include "mozilla/layers/AtomicRefCountedWithFinalize.h" #include "mozilla/layers/CompositorTypes.h" // for TextureFlags, etc #include "mozilla/layers/ISurfaceAllocator.h" #include "mozilla/layers/LayersTypes.h" #include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor #include "mozilla/mozalloc.h" // for operator delete #include "mozilla/gfx/CriticalSection.h" #include "mozilla/webrender/WebRenderTypes.h" #include "nsCOMPtr.h" // for already_AddRefed #include "nsISupportsImpl.h" // for TextureImage::AddRef, etc #include "GfxTexturesReporter.h" #include "pratom.h" #include "nsThreadUtils.h" class gfxImageSurface; struct ID3D11Device; namespace mozilla { // When defined, we track which pool the tile came from and test for // any inconsistencies. This can be defined in release build as well. #ifdef DEBUG # define GFX_DEBUG_TRACK_CLIENTS_IN_POOL 1 #endif namespace layers { class AsyncTransactionWaiter; class BufferTextureData; class CompositableForwarder; class KnowsCompositor; class LayersIPCChannel; class CompositableClient; struct PlanarYCbCrData; class Image; class PTextureChild; class TextureChild; class TextureData; class GPUVideoTextureData; struct RawTextureBuffer; class RawYCbCrTextureBuffer; class TextureClient; class ITextureClientRecycleAllocator; #ifdef GFX_DEBUG_TRACK_CLIENTS_IN_POOL class TextureClientPool; #endif class TextureForwarder; class KeepAlive; class SyncObjectClient; /** * TextureClient is the abstraction that allows us to share data between the * content and the compositor side. */ enum TextureAllocationFlags { ALLOC_DEFAULT = 0, ALLOC_CLEAR_BUFFER = 1 << 1, // Clear the buffer to whatever is best for the draw target ALLOC_CLEAR_BUFFER_WHITE = 1 << 2, // explicit all white ALLOC_CLEAR_BUFFER_BLACK = 1 << 3, // explicit all black ALLOC_DISALLOW_BUFFERTEXTURECLIENT = 1 << 4, // Allocate the texture for out-of-band content updates. This is mostly for // TextureClientD3D11, which may otherwise choose D3D10 or non-KeyedMutex // surfaces when used on the main thread. ALLOC_FOR_OUT_OF_BAND_CONTENT = 1 << 5, // Disable any cross-device synchronization. This is also for // TextureClientD3D11, and creates a texture without KeyedMutex. ALLOC_MANUAL_SYNCHRONIZATION = 1 << 6, // The texture is going to be updated using UpdateFromSurface and needs to // support that call. ALLOC_UPDATE_FROM_SURFACE = 1 << 7, // In practice, this means we support the APPLE_client_storage extension, // meaning the buffer will not be internally copied by the graphics driver. ALLOC_ALLOW_DIRECT_MAPPING = 1 << 8, }; /** * This class may be used to asynchronously receive an update when the content * drawn to this texture client is available for reading in CPU memory. This * can only be used on texture clients that support draw target creation. */ class TextureReadbackSink { NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TextureReadbackSink) public: /** * Callback function to implement in order to receive a DataSourceSurface * containing the data read back from the texture client. This will always * be called on the main thread, and this may not hold on to the * DataSourceSurface beyond the execution of this function. */ virtual void ProcessReadback(gfx::DataSourceSurface* aSourceSurface) = 0; protected: virtual ~TextureReadbackSink() = default; }; enum class BackendSelector { Content, Canvas }; /// Temporary object providing direct access to a Texture's memory. /// /// see TextureClient::CanExposeMappedData() and /// TextureClient::BorrowMappedData(). struct MappedTextureData { uint8_t* data; gfx::IntSize size; int32_t stride; gfx::SurfaceFormat format; }; struct MappedYCbCrChannelData { uint8_t* data; gfx::IntSize size; int32_t stride; int32_t skip; uint32_t bytesPerPixel; bool CopyInto(MappedYCbCrChannelData& aDst); }; struct MappedYCbCrTextureData { MappedYCbCrChannelData y; MappedYCbCrChannelData cb; MappedYCbCrChannelData cr; // Sad but because of how SharedPlanarYCbCrData is used we have to expose this // for now. uint8_t* metadata; StereoMode stereoMode; bool CopyInto(MappedYCbCrTextureData& aDst) { return y.CopyInto(aDst.y) && cb.CopyInto(aDst.cb) && cr.CopyInto(aDst.cr); } }; class ReadLockDescriptor; class NonBlockingTextureReadLock; // A class to help implement copy-on-write semantics for shared textures. // // A TextureClient/Host pair can opt into using a ReadLock by calling // TextureClient::EnableReadLock. This will equip the TextureClient with a // ReadLock object that will be automatically ReadLock()'ed by the texture // itself when it is written into (see TextureClient::Unlock). A // TextureReadLock's counter starts at 1 and is expected to be equal to 1 when // the lock is destroyed. See ShmemTextureReadLock for explanations about why we // use 1 instead of 0 as the initial state. TextureReadLock is mostly internally // managed by the TextureClient/Host pair, and the compositable only has to // forward it during updates. If an update message contains a null_t lock, it // means that the texture was not written into on the content side, and there is // no synchronization required on the compositor side (or it means that the // texture pair did not opt into using ReadLocks). On the compositor side, the // TextureHost can receive a ReadLock during a transaction, and will both // ReadUnlock() it and drop it as soon as the shared data is available again for // writing (the texture upload is done, or the compositor not reading the // texture anymore). The lock is dropped to make sure it is ReadUnlock()'ed only // once. class TextureReadLock { protected: virtual ~TextureReadLock() = default; public: NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TextureReadLock) virtual bool ReadLock() = 0; virtual bool TryReadLock(TimeDuration aTimeout) { return ReadLock(); } virtual int32_t ReadUnlock() = 0; virtual bool IsValid() const = 0; static already_AddRefed Deserialize( const ReadLockDescriptor& aDescriptor, ISurfaceAllocator* aAllocator); virtual bool Serialize(ReadLockDescriptor& aOutput, base::ProcessId aOther) = 0; enum LockType { TYPE_NONBLOCKING_MEMORY, TYPE_NONBLOCKING_SHMEM, TYPE_CROSS_PROCESS_SEMAPHORE }; virtual LockType GetType() = 0; virtual NonBlockingTextureReadLock* AsNonBlockingLock() { return nullptr; } protected: NS_DECL_OWNINGTHREAD }; class NonBlockingTextureReadLock : public TextureReadLock { public: virtual int32_t GetReadCount() = 0; static already_AddRefed Create(LayersIPCChannel* aAllocator); NonBlockingTextureReadLock* AsNonBlockingLock() override { return this; } }; #ifdef XP_WIN class D3D11TextureData; class DXGIYCbCrTextureData; #endif class TextureData { public: struct Info { gfx::IntSize size; gfx::SurfaceFormat format; bool hasIntermediateBuffer; bool hasSynchronization; bool supportsMoz2D; bool canExposeMappedData; bool canConcurrentlyReadLock; Info() : format(gfx::SurfaceFormat::UNKNOWN), hasIntermediateBuffer(false), hasSynchronization(false), supportsMoz2D(false), canExposeMappedData(false), canConcurrentlyReadLock(true) {} }; static TextureData* Create(TextureForwarder* aAllocator, gfx::SurfaceFormat aFormat, gfx::IntSize aSize, LayersBackend aLayersBackend, int32_t aMaxTextureSize, BackendSelector aSelector, TextureFlags aTextureFlags, TextureAllocationFlags aAllocFlags); static bool IsRemote(LayersBackend aLayersBackend, BackendSelector aSelector); virtual ~TextureData() { MOZ_COUNT_DTOR(TextureData); } virtual void FillInfo(TextureData::Info& aInfo) const = 0; virtual bool Lock(OpenMode aMode) = 0; virtual void Unlock() = 0; virtual already_AddRefed BorrowDrawTarget() { return nullptr; } virtual already_AddRefed BorrowSnapshot() { return nullptr; } virtual bool BorrowMappedData(MappedTextureData&) { return false; } virtual bool BorrowMappedYCbCrData(MappedYCbCrTextureData&) { return false; } virtual void Deallocate(LayersIPCChannel* aAllocator) = 0; /// Depending on the texture's flags either Deallocate or Forget is called. virtual void Forget(LayersIPCChannel* aAllocator) {} virtual bool Serialize(SurfaceDescriptor& aDescriptor) = 0; virtual void GetSubDescriptor(GPUVideoSubDescriptor* aOutDesc) {} virtual void OnForwardedToHost() {} virtual TextureData* CreateSimilar( LayersIPCChannel* aAllocator, LayersBackend aLayersBackend, TextureFlags aFlags = TextureFlags::DEFAULT, TextureAllocationFlags aAllocFlags = ALLOC_DEFAULT) const { return nullptr; } virtual bool UpdateFromSurface(gfx::SourceSurface* aSurface) { return false; }; virtual bool ReadBack(TextureReadbackSink* aReadbackSink) { return false; } virtual void SyncWithObject(SyncObjectClient* aSyncObject){}; virtual TextureFlags GetTextureFlags() const { return TextureFlags::NO_FLAGS; } #ifdef XP_WIN virtual D3D11TextureData* AsD3D11TextureData() { return nullptr; } virtual DXGIYCbCrTextureData* AsDXGIYCbCrTextureData() { return nullptr; } #endif virtual BufferTextureData* AsBufferTextureData() { return nullptr; } virtual GPUVideoTextureData* AsGPUVideoTextureData() { return nullptr; } protected: TextureData() { MOZ_COUNT_CTOR(TextureData); } }; /** * TextureClient is a thin abstraction over texture data that need to be shared * between the content process and the compositor process. It is the * content-side half of a TextureClient/TextureHost pair. A corresponding * TextureHost lives on the compositor-side. * * TextureClient's primary purpose is to present texture data in a way that is * understood by the IPC system. There are two ways to use it: * - Use it to serialize image data that is not IPC-friendly (most likely * involving a copy into shared memory) * - preallocate it and paint directly into it, which avoids copy but requires * the painting code to be aware of TextureClient (or at least the underlying * shared memory). * * There is always one and only one TextureClient per TextureHost, and the * TextureClient/Host pair only owns one buffer of image data through its * lifetime. This means that the lifetime of the underlying shared data * matches the lifetime of the TextureClient/Host pair. It also means * TextureClient/Host do not implement double buffering, which is the * responsibility of the compositable (which would use two Texture pairs). * In order to send several different buffers to the compositor side, use * several TextureClients. */ class TextureClient : public AtomicRefCountedWithFinalize { public: TextureClient(TextureData* aData, TextureFlags aFlags, LayersIPCChannel* aAllocator); virtual ~TextureClient(); static already_AddRefed CreateWithData( TextureData* aData, TextureFlags aFlags, LayersIPCChannel* aAllocator); // Creates and allocates a TextureClient usable with Moz2D. static already_AddRefed CreateForDrawing( KnowsCompositor* aAllocator, gfx::SurfaceFormat aFormat, gfx::IntSize aSize, BackendSelector aSelector, TextureFlags aTextureFlags, TextureAllocationFlags flags = ALLOC_DEFAULT); static already_AddRefed CreateFromSurface( KnowsCompositor* aAllocator, gfx::SourceSurface* aSurface, BackendSelector aSelector, TextureFlags aTextureFlags, TextureAllocationFlags aAllocFlags); // Creates and allocates a TextureClient supporting the YCbCr format. static already_AddRefed CreateForYCbCr( KnowsCompositor* aAllocator, gfx::IntSize aYSize, uint32_t aYStride, gfx::IntSize aCbCrSize, uint32_t aCbCrStride, StereoMode aStereoMode, gfx::ColorDepth aColorDepth, gfx::YUVColorSpace aYUVColorSpace, gfx::ColorRange aColorRange, TextureFlags aTextureFlags); // Creates and allocates a TextureClient (can be accessed through raw // pointers). static already_AddRefed CreateForRawBufferAccess( KnowsCompositor* aAllocator, gfx::SurfaceFormat aFormat, gfx::IntSize aSize, gfx::BackendType aMoz2dBackend, TextureFlags aTextureFlags, TextureAllocationFlags flags = ALLOC_DEFAULT); // Creates and allocates a TextureClient of the same type. already_AddRefed CreateSimilar( LayersBackend aLayersBackend = LayersBackend::LAYERS_NONE, TextureFlags aFlags = TextureFlags::DEFAULT, TextureAllocationFlags aAllocFlags = ALLOC_DEFAULT) const; /** * Locks the shared data, allowing the caller to get access to it. * * Please always lock/unlock when accessing the shared data. * If Lock() returns false, you should not attempt to access the shared data. */ bool Lock(OpenMode aMode); void Unlock(); bool IsLocked() const { return mIsLocked; } gfx::IntSize GetSize() const { return mInfo.size; } gfx::SurfaceFormat GetFormat() const { return mInfo.format; } /** * Returns true if this texture has a synchronization mechanism (mutex, fence, * etc.). Textures that do not implement synchronization should be immutable * or should use immediate uploads (see TextureFlags in CompositorTypes.h) * Even if a texture does not implement synchronization, Lock and Unlock need * to be used appropriately since the latter are also there to map/numap data. */ bool HasSynchronization() const { return mInfo.hasSynchronization; } /** * Indicates whether the TextureClient implementation is backed by an * in-memory buffer. The consequence of this is that locking the * TextureClient does not contend with locking the texture on the host side. */ bool HasIntermediateBuffer() const { return mInfo.hasIntermediateBuffer; } bool CanExposeDrawTarget() const { return mInfo.supportsMoz2D; } bool CanExposeMappedData() const { return mInfo.canExposeMappedData; } /** * Returns a DrawTarget to draw into the TextureClient. * This function should never be called when not on the main thread! * * This must never be called on a TextureClient that is not sucessfully * locked. When called several times within one Lock/Unlock pair, this method * should return the same DrawTarget. The DrawTarget is automatically flushed * by the TextureClient when the latter is unlocked, and the DrawTarget that * will be returned within the next lock/unlock pair may or may not be the * same object. Do not keep references to the DrawTarget outside of the * lock/unlock pair. * * This is typically used as follows: * * if (!texture->Lock(OpenMode::OPEN_READ_WRITE)) { * return false; * } * { * // Restrict this code's scope to ensure all references to dt are gone * // when Unlock is called. * DrawTarget* dt = texture->BorrowDrawTarget(); * // use the draw target ... * } * texture->Unlock(); * */ gfx::DrawTarget* BorrowDrawTarget(); already_AddRefed BorrowSnapshot(); /** * Similar to BorrowDrawTarget but provides direct access to the texture's * bits instead of a DrawTarget. */ bool BorrowMappedData(MappedTextureData&); bool BorrowMappedYCbCrData(MappedYCbCrTextureData&); /** * This function can be used to update the contents of the TextureClient * off the main thread. */ void UpdateFromSurface(gfx::SourceSurface* aSurface); /** * This method is strictly for debugging. It causes locking and * needless copies. */ already_AddRefed GetAsSurface(); virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix); /** * Copies a rectangle from this texture client to a position in aTarget. * It is assumed that the necessary locks are in place; so this should at * least have a read lock and aTarget should at least have a write lock. */ bool CopyToTextureClient(TextureClient* aTarget, const gfx::IntRect* aRect, const gfx::IntPoint* aPoint); /** * Allocate and deallocate a TextureChild actor. * * TextureChild is an implementation detail of TextureClient that is not * exposed to the rest of the code base. CreateIPDLActor and DestroyIPDLActor * are for use with the managing IPDL protocols only (so that they can * implement AllocPextureChild and DeallocPTextureChild). */ static PTextureChild* CreateIPDLActor(); static bool DestroyIPDLActor(PTextureChild* actor); /** * Get the TextureClient corresponding to the actor passed in parameter. */ static already_AddRefed AsTextureClient(PTextureChild* actor); /** * TextureFlags contain important information about various aspects * of the texture, like how its liferime is managed, and how it * should be displayed. * See TextureFlags in CompositorTypes.h. */ TextureFlags GetFlags() const { return mFlags; } bool HasFlags(TextureFlags aFlags) const { return (mFlags & aFlags) == aFlags; } void AddFlags(TextureFlags aFlags); void RemoveFlags(TextureFlags aFlags); // Must not be called when TextureClient is in use by CompositableClient. void RecycleTexture(TextureFlags aFlags); /** * After being shared with the compositor side, an immutable texture is never * modified, it can only be read. It is safe to not Lock/Unlock immutable * textures. */ bool IsImmutable() const { return !!(mFlags & TextureFlags::IMMUTABLE); } void MarkImmutable() { AddFlags(TextureFlags::IMMUTABLE); } bool IsSharedWithCompositor() const; /** * If this method returns false users of TextureClient are not allowed * to access the shared data. */ bool IsValid() const { return !!mData; } /** * Called when TextureClient is added to CompositableClient. */ void SetAddedToCompositableClient(); /** * If this method retuns false, TextureClient is already added to * CompositableClient, since its creation or recycling. */ bool IsAddedToCompositableClient() const { return mAddedToCompositableClient; } /** * Create and init the TextureChild/Parent IPDL actor pair * with a CompositableForwarder. * * Should be called only once per TextureClient. * The TextureClient must not be locked when calling this method. */ bool InitIPDLActor(CompositableForwarder* aForwarder); /** * Create and init the TextureChild/Parent IPDL actor pair * with a TextureForwarder. * * Should be called only once per TextureClient. * The TextureClient must not be locked when calling this method. */ bool InitIPDLActor(KnowsCompositor* aKnowsCompositor); /** * Return a pointer to the IPDLActor. * * This is to be used with IPDL messages only. Do not store the returned * pointer. */ PTextureChild* GetIPDLActor(); /** * Triggers the destruction of the shared data and the corresponding * TextureHost. * * If the texture flags contain TextureFlags::DEALLOCATE_CLIENT, the * destruction will be synchronously coordinated with the compositor side, * otherwise it will be done asynchronously. */ void Destroy(); /** * Track how much of this texture is wasted. * For example we might allocate a 256x256 tile but only use 10x10. */ void SetWaste(int aWasteArea) { mWasteTracker.Update(aWasteArea, BytesPerPixel(GetFormat())); } /** * This sets the readback sink that this texture is to use. This will * receive the data for this texture as soon as it becomes available after * texture unlock. */ virtual void SetReadbackSink(TextureReadbackSink* aReadbackSink) { mReadbackSink = aReadbackSink; } void SyncWithObject(SyncObjectClient* aSyncObject) { mData->SyncWithObject(aSyncObject); } LayersIPCChannel* GetAllocator() { return mAllocator; } ITextureClientRecycleAllocator* GetRecycleAllocator() { return mRecycleAllocator; } void SetRecycleAllocator(ITextureClientRecycleAllocator* aAllocator); /// If you add new code that uses this method, you are probably doing /// something wrong. TextureData* GetInternalData() { return mData; } const TextureData* GetInternalData() const { return mData; } uint64_t GetSerial() const { return mSerial; } void GPUVideoDesc(SurfaceDescriptorGPUVideo* aOutDesc); void CancelWaitForNotifyNotUsed(); /** * Set last transaction id of CompositableForwarder. * * Called when TextureClient has TextureFlags::RECYCLE flag. * When CompositableForwarder forwards the TextureClient with * TextureFlags::RECYCLE, it holds TextureClient's ref until host side * releases it. The host side sends TextureClient release message. * The id is used to check if the message is for the last TextureClient * forwarding. */ void SetLastFwdTransactionId(uint64_t aTransactionId) { MOZ_ASSERT(mFwdTransactionId <= aTransactionId); mFwdTransactionId = aTransactionId; } uint64_t GetLastFwdTransactionId() { return mFwdTransactionId; } TextureReadLock* GetReadLock() { return mReadLock; } bool IsReadLocked() const; bool TryReadLock(); void ReadUnlock(); bool OnForwardedToHost(); // Mark that the TextureClient will be used by the paint thread, and should // not free its underlying texture data. This must only be called from the // main thread. void AddPaintThreadRef(); // Mark that the TextureClient is no longer in use by the PaintThread. This // must only be called from the PaintThread. void DropPaintThreadRef(); wr::MaybeExternalImageId GetExternalImageKey() { return mExternalImageId; } private: static void TextureClientRecycleCallback(TextureClient* aClient, void* aClosure); // Internal helpers for creating texture clients using the actual forwarder // instead of KnowsCompositor. TextureClientPool uses these to let it cache // texture clients per-process instead of per ShadowLayerForwarder, but // everyone else should use the public functions instead. friend class TextureClientPool; static already_AddRefed CreateForDrawing( TextureForwarder* aAllocator, gfx::SurfaceFormat aFormat, gfx::IntSize aSize, LayersBackend aLayersBackend, int32_t aMaxTextureSize, BackendSelector aSelector, TextureFlags aTextureFlags, TextureAllocationFlags aAllocFlags = ALLOC_DEFAULT); static already_AddRefed CreateForRawBufferAccess( LayersIPCChannel* aAllocator, gfx::SurfaceFormat aFormat, gfx::IntSize aSize, gfx::BackendType aMoz2dBackend, LayersBackend aLayersBackend, TextureFlags aTextureFlags, TextureAllocationFlags flags = ALLOC_DEFAULT); void EnableReadLock(); void EnableBlockingReadLock(); /** * Called once, during the destruction of the Texture, on the thread in which * texture's reference count reaches 0 (could be any thread). * * Here goes the shut-down code that uses virtual methods. * Must only be called by Release(). */ void Finalize() {} friend class AtomicRefCountedWithFinalize; protected: /** * Should only be called *once* per texture, in TextureClient::InitIPDLActor. * Some texture implementations rely on the fact that the descriptor will be * deserialized. * Calling ToSurfaceDescriptor again after it has already returned true, * or never constructing a TextureHost with aDescriptor may result in a memory * leak (see TextureClientD3D9 for example). */ bool ToSurfaceDescriptor(SurfaceDescriptor& aDescriptor); void LockActor() const; void UnlockActor() const; TextureData::Info mInfo; RefPtr mAllocator; RefPtr mActor; RefPtr mRecycleAllocator; RefPtr mReadLock; TextureData* mData; RefPtr mBorrowedDrawTarget; TextureFlags mFlags; gl::GfxTextureWasteTracker mWasteTracker; OpenMode mOpenMode; #ifdef DEBUG uint32_t mExpectedDtRefs; #endif bool mIsLocked; bool mIsReadLocked; // This member tracks that the texture was written into until the update // is sent to the compositor. We need this remember to lock mReadLock on // behalf of the compositor just before sending the notification. bool mUpdated; // Used when TextureClient is recycled with TextureFlags::RECYCLE flag. bool mAddedToCompositableClient; bool mWorkaroundAnnoyingSharedSurfaceLifetimeIssues; bool mWorkaroundAnnoyingSharedSurfaceOwnershipIssues; RefPtr mReadbackSink; uint64_t mFwdTransactionId; // Serial id of TextureClient. It is unique in current process. const uint64_t mSerial; // When non-zero, texture data must not be freed. mozilla::Atomic mPaintThreadRefs; // External image id. It is unique if it is allocated. // The id is allocated in TextureClient::InitIPDLActor(). // Its allocation is supported by // CompositorBridgeChild and ImageBridgeChild for now. wr::MaybeExternalImageId mExternalImageId; // Used to assign serial ids of TextureClient. static mozilla::Atomic sSerialCounter; friend class TextureChild; friend void TestTextureClientSurface(TextureClient*, gfxImageSurface*); friend void TestTextureClientYCbCr(TextureClient*, PlanarYCbCrData&); friend already_AddRefed CreateTextureHostWithBackend( TextureClient*, ISurfaceAllocator*, LayersBackend&); #ifdef GFX_DEBUG_TRACK_CLIENTS_IN_POOL public: // Pointer to the pool this tile came from. TextureClientPool* mPoolTracker; #endif }; /** * Task that releases TextureClient pointer on a specified thread. */ class TextureClientReleaseTask : public Runnable { public: explicit TextureClientReleaseTask(TextureClient* aClient) : Runnable("layers::TextureClientReleaseTask"), mTextureClient(aClient) {} NS_IMETHOD Run() override { mTextureClient = nullptr; return NS_OK; } private: RefPtr mTextureClient; }; // Automatically lock and unlock a texture. Since texture locking is fallible, // Succeeded() must be checked on the guard object before proceeding. class MOZ_RAII TextureClientAutoLock { MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER; public: TextureClientAutoLock(TextureClient* aTexture, OpenMode aMode MOZ_GUARD_OBJECT_NOTIFIER_PARAM) : mTexture(aTexture), mSucceeded(false) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; mSucceeded = mTexture->Lock(aMode); #ifdef DEBUG mChecked = false; #endif } ~TextureClientAutoLock() { MOZ_ASSERT(mChecked); if (mSucceeded) { mTexture->Unlock(); } } bool Succeeded() { #ifdef DEBUG mChecked = true; #endif return mSucceeded; } private: TextureClient* mTexture; #ifdef DEBUG bool mChecked; #endif bool mSucceeded; }; // Automatically locks and unlocks two texture clients, and exposes them as a // a single draw target dual. Since texture locking is fallible, Succeeded() // must be checked on the guard object before proceeding. class MOZ_RAII DualTextureClientAutoLock { public: DualTextureClientAutoLock(TextureClient* aTexture, TextureClient* aTextureOnWhite, OpenMode aMode) : mTarget(nullptr), mTexture(aTexture), mTextureOnWhite(aTextureOnWhite) { if (!mTexture->Lock(aMode)) { return; } mTarget = mTexture->BorrowDrawTarget(); if (!mTarget) { mTexture->Unlock(); return; } if (!mTextureOnWhite) { return; } if (!mTextureOnWhite->Lock(aMode)) { mTarget = nullptr; mTexture->Unlock(); return; } RefPtr targetOnWhite = mTextureOnWhite->BorrowDrawTarget(); if (!targetOnWhite) { mTarget = nullptr; mTexture->Unlock(); mTextureOnWhite->Unlock(); return; } mTarget = gfx::Factory::CreateDualDrawTarget(mTarget, targetOnWhite); if (!mTarget) { mTarget = nullptr; mTexture->Unlock(); mTextureOnWhite->Unlock(); } } ~DualTextureClientAutoLock() { if (Succeeded()) { mTarget = nullptr; mTexture->Unlock(); if (mTextureOnWhite) { mTextureOnWhite->Unlock(); } } } bool Succeeded() const { return !!mTarget; } operator gfx::DrawTarget*() const { return mTarget; } gfx::DrawTarget* operator->() const { return mTarget; } RefPtr mTarget; private: RefPtr mTexture; RefPtr mTextureOnWhite; }; class KeepAlive { public: virtual ~KeepAlive() = default; }; template class TKeepAlive : public KeepAlive { public: explicit TKeepAlive(T* aData) : mData(aData) {} protected: RefPtr mData; }; /// Convenience function to set the content of ycbcr texture. bool UpdateYCbCrTextureClient(TextureClient* aTexture, const PlanarYCbCrData& aData); } // namespace layers } // namespace mozilla #endif