Source code

Revision control

Other Tools

/* -*- 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 <stddef.h> // for size_t
#include <stdint.h> // for uint32_t, uint8_t, uint64_t
#include "GLTextureImage.h" // for TextureImage
#include "GfxTexturesReporter.h"
#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/CriticalSection.h"
#include "mozilla/gfx/Point.h" // for IntSize
#include "mozilla/gfx/Types.h" // for SurfaceFormat
#include "mozilla/ipc/FileDescriptor.h"
#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/LayersSurfaces.h" // for SurfaceDescriptor
#include "mozilla/layers/LayersTypes.h"
#include "mozilla/layers/SyncObject.h"
#include "mozilla/mozalloc.h" // for operator delete
#include "mozilla/webrender/WebRenderTypes.h"
#include "nsCOMPtr.h" // for already_AddRefed
#include "nsISupportsImpl.h" // for TextureImage::AddRef, etc
#include "nsThreadUtils.h"
#include "pratom.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 AndroidHardwareBufferTextureData;
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;
/**
* 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<TextureReadLock> 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<TextureReadLock> 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,
KnowsCompositor* aKnowsCompositor,
BackendSelector aSelector,
TextureFlags aTextureFlags,
TextureAllocationFlags aAllocFlags);
static bool IsRemote(KnowsCompositor* aKnowsCompositor,
BackendSelector aSelector);
MOZ_COUNTED_DTOR_VIRTUAL(TextureData)
virtual void FillInfo(TextureData::Info& aInfo) const = 0;
virtual bool Lock(OpenMode aMode) = 0;
virtual void Unlock() = 0;
virtual already_AddRefed<gfx::DrawTarget> BorrowDrawTarget() {
return nullptr;
}
virtual already_AddRefed<gfx::SourceSurface> 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(RemoteDecoderVideoSubDescriptor* 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(RefPtr<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; }
virtual AndroidHardwareBufferTextureData*
AsAndroidHardwareBufferTextureData() {
return nullptr;
}
// It is used by AndroidHardwareBufferTextureData and
// SharedSurfaceTextureData. Returns buffer id when it owns
// AndroidHardwareBuffer. It is used only on android.
virtual Maybe<uint64_t> GetBufferId() const { return Nothing(); }
// The acquire fence is a fence that is used for waiting until rendering to
// its AHardwareBuffer is completed.
// It is used only on android.
virtual mozilla::ipc::FileDescriptor GetAcquireFence() {
return mozilla::ipc::FileDescriptor();
}
protected:
MOZ_COUNTED_DEFAULT_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 pairs of Textures).
* In order to send several different buffers to the compositor side, use
* several TextureClients.
*/
class TextureClient : public AtomicRefCountedWithFinalize<TextureClient> {
public:
TextureClient(TextureData* aData, TextureFlags aFlags,
LayersIPCChannel* aAllocator);
virtual ~TextureClient();
static already_AddRefed<TextureClient> CreateWithData(
TextureData* aData, TextureFlags aFlags, LayersIPCChannel* aAllocator);
// Creates and allocates a TextureClient usable with Moz2D.
static already_AddRefed<TextureClient> CreateForDrawing(
KnowsCompositor* aAllocator, gfx::SurfaceFormat aFormat,
gfx::IntSize aSize, BackendSelector aSelector, TextureFlags aTextureFlags,
TextureAllocationFlags flags = ALLOC_DEFAULT);
static already_AddRefed<TextureClient> CreateFromSurface(
KnowsCompositor* aAllocator, gfx::SourceSurface* aSurface,
BackendSelector aSelector, TextureFlags aTextureFlags,
TextureAllocationFlags aAllocFlags);
// Creates and allocates a TextureClient supporting the YCbCr format.
static already_AddRefed<TextureClient> CreateForYCbCr(
KnowsCompositor* aAllocator, const gfx::IntRect& aDisplay,
const gfx::IntSize& aYSize, uint32_t aYStride,
const 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<TextureClient> 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<TextureClient> 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<gfx::SourceSurface> 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<gfx::DataSourceSurface> 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<TextureClient> 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(RefPtr<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 GetSurfaceDescriptorRemoteDecoder(
SurfaceDescriptorRemoteDecoder* 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<TextureClient> CreateForDrawing(
TextureForwarder* aAllocator, gfx::SurfaceFormat aFormat,
gfx::IntSize aSize, KnowsCompositor* aKnowsCompositor,
BackendSelector aSelector, TextureFlags aTextureFlags,
TextureAllocationFlags aAllocFlags = ALLOC_DEFAULT);
static already_AddRefed<TextureClient> 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<TextureClient>;
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<LayersIPCChannel> mAllocator;
RefPtr<TextureChild> mActor;
RefPtr<ITextureClientRecycleAllocator> mRecycleAllocator;
RefPtr<TextureReadLock> mReadLock;
TextureData* mData;
RefPtr<gfx::DrawTarget> 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;
RefPtr<TextureReadbackSink> 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<uintptr_t> 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<uint64_t> sSerialCounter;
friend class TextureChild;
friend void TestTextureClientSurface(TextureClient*, gfxImageSurface*);
friend void TestTextureClientYCbCr(TextureClient*, PlanarYCbCrData&);
friend already_AddRefed<TextureHost> 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<TextureClient> 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 {
public:
TextureClientAutoLock(TextureClient* aTexture, OpenMode aMode)
: mTexture(aTexture), mSucceeded(false) {
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<gfx::DrawTarget> 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<gfx::DrawTarget> mTarget;
private:
RefPtr<TextureClient> mTexture;
RefPtr<TextureClient> mTextureOnWhite;
};
class KeepAlive {
public:
virtual ~KeepAlive() = default;
};
template <typename T>
class TKeepAlive : public KeepAlive {
public:
explicit TKeepAlive(T* aData) : mData(aData) {}
protected:
RefPtr<T> mData;
};
/// Convenience function to set the content of ycbcr texture.
bool UpdateYCbCrTextureClient(TextureClient* aTexture,
const PlanarYCbCrData& aData);
TextureType PreferredCanvasTextureType(KnowsCompositor* aKnowsCompositor);
} // namespace layers
} // namespace mozilla
#endif