michael@0: /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- michael@0: // * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef MOZILLA_GFX_TEXTURECLIENT_H michael@0: #define MOZILLA_GFX_TEXTURECLIENT_H michael@0: michael@0: #include // for size_t michael@0: #include // for uint32_t, uint8_t, uint64_t michael@0: #include "GLContextTypes.h" // for GLContext (ptr only), etc michael@0: #include "GLTextureImage.h" // for TextureImage michael@0: #include "ImageTypes.h" // for StereoMode michael@0: #include "mozilla/Assertions.h" // for MOZ_ASSERT, etc michael@0: #include "mozilla/Attributes.h" // for MOZ_OVERRIDE michael@0: #include "mozilla/RefPtr.h" // for RefPtr, RefCounted michael@0: #include "mozilla/gfx/2D.h" // for DrawTarget michael@0: #include "mozilla/gfx/Point.h" // for IntSize michael@0: #include "mozilla/gfx/Types.h" // for SurfaceFormat michael@0: #include "mozilla/layers/FenceUtils.h" // for FenceHandle michael@0: #include "mozilla/ipc/Shmem.h" // for Shmem michael@0: #include "mozilla/layers/AtomicRefCountedWithFinalize.h" michael@0: #include "mozilla/layers/CompositorTypes.h" // for TextureFlags, etc michael@0: #include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor michael@0: #include "mozilla/layers/PTextureChild.h" // for PTextureChild michael@0: #include "mozilla/mozalloc.h" // for operator delete michael@0: #include "nsAutoPtr.h" // for nsRefPtr michael@0: #include "nsCOMPtr.h" // for already_AddRefed michael@0: #include "nsISupportsImpl.h" // for TextureImage::AddRef, etc michael@0: michael@0: class gfxReusableSurfaceWrapper; michael@0: class gfxImageSurface; michael@0: michael@0: namespace mozilla { michael@0: namespace layers { michael@0: michael@0: class ContentClient; michael@0: class CompositableForwarder; michael@0: class ISurfaceAllocator; michael@0: class CompositableClient; michael@0: class PlanarYCbCrImage; michael@0: class PlanarYCbCrData; michael@0: class Image; michael@0: class PTextureChild; michael@0: class TextureChild; michael@0: class BufferTextureClient; michael@0: class TextureClient; michael@0: michael@0: /** michael@0: * TextureClient is the abstraction that allows us to share data between the michael@0: * content and the compositor side. michael@0: */ michael@0: michael@0: enum TextureAllocationFlags { michael@0: ALLOC_DEFAULT = 0, michael@0: ALLOC_CLEAR_BUFFER = 1 michael@0: }; michael@0: michael@0: /** michael@0: * Interface for TextureClients that can be updated using YCbCr data. michael@0: */ michael@0: class TextureClientYCbCr michael@0: { michael@0: public: michael@0: /** michael@0: * Copy aData into this texture client. michael@0: * michael@0: * This must never be called on a TextureClient that is not sucessfully locked. michael@0: */ michael@0: virtual bool UpdateYCbCr(const PlanarYCbCrData& aData) = 0; michael@0: michael@0: /** michael@0: * Allocates for a given surface size, taking into account the pixel format michael@0: * which is part of the state of the TextureClient. michael@0: * michael@0: * Does not clear the surface, since we consider that the surface michael@0: * be painted entirely with opaque content. michael@0: */ michael@0: virtual bool AllocateForYCbCr(gfx::IntSize aYSize, michael@0: gfx::IntSize aCbCrSize, michael@0: StereoMode aStereoMode) = 0; michael@0: }; michael@0: michael@0: /** michael@0: * Holds the shared data of a TextureClient, to be destroyed later. michael@0: * michael@0: * TextureClient's destructor initiates the destruction sequence of the michael@0: * texture client/host pair. If the shared data is to be deallocated on the michael@0: * host side, there is nothing to do. michael@0: * On the other hand, if the client data must be deallocated on the client michael@0: * side, the CompositableClient will ask the TextureClient to drop its shared michael@0: * data in the form of a TextureClientData object. This data will be kept alive michael@0: * until the host side confirms that it is not using the data anymore and that michael@0: * it is completely safe to deallocate the shared data. michael@0: * michael@0: * See: michael@0: * - The PTexture IPDL protocol michael@0: * - CompositableChild in TextureClient.cpp michael@0: */ michael@0: class TextureClientData { michael@0: public: michael@0: virtual void DeallocateSharedData(ISurfaceAllocator* allocator) = 0; michael@0: virtual ~TextureClientData() {} michael@0: }; michael@0: michael@0: /** michael@0: * TextureClient is a thin abstraction over texture data that need to be shared michael@0: * between the content process and the compositor process. It is the michael@0: * content-side half of a TextureClient/TextureHost pair. A corresponding michael@0: * TextureHost lives on the compositor-side. michael@0: * michael@0: * TextureClient's primary purpose is to present texture data in a way that is michael@0: * understood by the IPC system. There are two ways to use it: michael@0: * - Use it to serialize image data that is not IPC-friendly (most likely michael@0: * involving a copy into shared memory) michael@0: * - preallocate it and paint directly into it, which avoids copy but requires michael@0: * the painting code to be aware of TextureClient (or at least the underlying michael@0: * shared memory). michael@0: * michael@0: * There is always one and only one TextureClient per TextureHost, and the michael@0: * TextureClient/Host pair only owns one buffer of image data through its michael@0: * lifetime. This means that the lifetime of the underlying shared data michael@0: * matches the lifetime of the TextureClient/Host pair. It also means michael@0: * TextureClient/Host do not implement double buffering, which is the michael@0: * responsibility of the compositable (which would use two Texture pairs). michael@0: * In order to send several different buffers to the compositor side, use michael@0: * several TextureClients. michael@0: */ michael@0: class TextureClient michael@0: : public AtomicRefCountedWithFinalize michael@0: { michael@0: public: michael@0: TextureClient(TextureFlags aFlags = TEXTURE_FLAGS_DEFAULT); michael@0: virtual ~TextureClient(); michael@0: michael@0: static TemporaryRef michael@0: CreateBufferTextureClient(ISurfaceAllocator* aAllocator, michael@0: gfx::SurfaceFormat aFormat, michael@0: TextureFlags aTextureFlags, michael@0: gfx::BackendType aMoz2dBackend); michael@0: michael@0: static TemporaryRef michael@0: CreateTextureClientForDrawing(ISurfaceAllocator* aAllocator, michael@0: gfx::SurfaceFormat aFormat, michael@0: TextureFlags aTextureFlags, michael@0: gfx::BackendType aMoz2dBackend, michael@0: const gfx::IntSize& aSizeHint); michael@0: michael@0: virtual TextureClientYCbCr* AsTextureClientYCbCr() { return nullptr; } michael@0: michael@0: /** michael@0: * Locks the shared data, allowing the caller to get access to it. michael@0: * michael@0: * Please always lock/unlock when accessing the shared data. michael@0: * If Lock() returns false, you should not attempt to access the shared data. michael@0: */ michael@0: virtual bool Lock(OpenMode aMode) { return IsValid(); } michael@0: michael@0: virtual void Unlock() {} michael@0: michael@0: virtual bool IsLocked() const = 0; michael@0: michael@0: virtual bool CanExposeDrawTarget() const { return false; } michael@0: michael@0: /** michael@0: * Returns a DrawTarget to draw into the TextureClient. michael@0: * michael@0: * This must never be called on a TextureClient that is not sucessfully locked. michael@0: * When called several times within one Lock/Unlock pair, this method should michael@0: * return the same DrawTarget. michael@0: * The DrawTarget is automatically flushed by the TextureClient when the latter michael@0: * is unlocked, and the DrawTarget that will be returned within the next michael@0: * lock/unlock pair may or may not be the same object. michael@0: * Do not keep references to the DrawTarget outside of the lock/unlock pair. michael@0: * michael@0: * This is typically used as follows: michael@0: * michael@0: * if (!texture->Lock(OPEN_READ_WRITE)) { michael@0: * return false; michael@0: * } michael@0: * { michael@0: * // Restrict this code's scope to ensure all references to dt are gone michael@0: * // when Unlock is called. michael@0: * RefPtr dt = texture->GetAsDrawTarget(); michael@0: * // use the draw target ... michael@0: * } michael@0: * texture->Unlock(); michael@0: * michael@0: */ michael@0: virtual TemporaryRef GetAsDrawTarget() { return nullptr; } michael@0: michael@0: // TextureClients that can expose a DrawTarget should override this method. michael@0: virtual gfx::SurfaceFormat GetFormat() const michael@0: { michael@0: return gfx::SurfaceFormat::UNKNOWN; michael@0: } michael@0: michael@0: /** michael@0: * Allocates for a given surface size, taking into account the pixel format michael@0: * which is part of the state of the TextureClient. michael@0: * michael@0: * Does not clear the surface by default, clearing the surface can be done michael@0: * by passing the CLEAR_BUFFER flag. michael@0: * michael@0: * TextureClients that can expose a DrawTarget should override this method. michael@0: */ michael@0: virtual bool AllocateForSurface(gfx::IntSize aSize, michael@0: TextureAllocationFlags flags = ALLOC_DEFAULT) michael@0: { michael@0: return false; michael@0: } michael@0: michael@0: /** michael@0: * Copies a rectangle from this texture client to a position in aTarget. michael@0: * It is assumed that the necessary locks are in place; so this should at michael@0: * least have a read lock and aTarget should at least have a write lock. michael@0: */ michael@0: virtual bool CopyToTextureClient(TextureClient* aTarget, michael@0: const gfx::IntRect* aRect, michael@0: const gfx::IntPoint* aPoint); michael@0: michael@0: /** michael@0: * Returns true if this texture has a lock/unlock mechanism. michael@0: * Textures that do not implement locking should be immutable or should michael@0: * use immediate uploads (see TextureFlags in CompositorTypes.h) michael@0: */ michael@0: virtual bool ImplementsLocking() const { return false; } michael@0: michael@0: /** michael@0: * Indicates whether the TextureClient implementation is backed by an michael@0: * in-memory buffer. The consequence of this is that locking the michael@0: * TextureClient does not contend with locking the texture on the host side. michael@0: */ michael@0: virtual bool HasInternalBuffer() const = 0; michael@0: michael@0: /** michael@0: * Allocate and deallocate a TextureChild actor. michael@0: * michael@0: * TextureChild is an implementation detail of TextureClient that is not michael@0: * exposed to the rest of the code base. CreateIPDLActor and DestroyIPDLActor michael@0: * are for use with the managing IPDL protocols only (so that they can michael@0: * implement AllocPextureChild and DeallocPTextureChild). michael@0: */ michael@0: static PTextureChild* CreateIPDLActor(); michael@0: static bool DestroyIPDLActor(PTextureChild* actor); michael@0: michael@0: /** michael@0: * Get the TextureClient corresponding to the actor passed in parameter. michael@0: */ michael@0: static TextureClient* AsTextureClient(PTextureChild* actor); michael@0: michael@0: virtual bool IsAllocated() const = 0; michael@0: michael@0: virtual gfx::IntSize GetSize() const = 0; michael@0: michael@0: /** michael@0: * TextureFlags contain important information about various aspects michael@0: * of the texture, like how its liferime is managed, and how it michael@0: * should be displayed. michael@0: * See TextureFlags in CompositorTypes.h. michael@0: */ michael@0: TextureFlags GetFlags() const { return mFlags; } michael@0: michael@0: /** michael@0: * valid only for TEXTURE_RECYCLE TextureClient. michael@0: * When called this texture client will grab a strong reference and release michael@0: * it once the compositor notifies that it is done with the texture. michael@0: * NOTE: In this stage the texture client can no longer be used by the michael@0: * client in a transaction. michael@0: */ michael@0: void WaitForCompositorRecycle(); michael@0: michael@0: /** michael@0: * After being shared with the compositor side, an immutable texture is never michael@0: * modified, it can only be read. It is safe to not Lock/Unlock immutable michael@0: * textures. michael@0: */ michael@0: bool IsImmutable() const { return mFlags & TEXTURE_IMMUTABLE; } michael@0: michael@0: void MarkImmutable() { AddFlags(TEXTURE_IMMUTABLE); } michael@0: michael@0: bool IsSharedWithCompositor() const { return mShared; } michael@0: michael@0: bool ShouldDeallocateInDestructor() const; michael@0: michael@0: /** michael@0: * If this method returns false users of TextureClient are not allowed michael@0: * to access the shared data. michael@0: */ michael@0: bool IsValid() const { return mValid; } michael@0: michael@0: /** michael@0: * Create and init the TextureChild/Parent IPDL actor pair. michael@0: * michael@0: * Should be called only once per TextureClient. michael@0: */ michael@0: bool InitIPDLActor(CompositableForwarder* aForwarder); michael@0: michael@0: /** michael@0: * Return a pointer to the IPDLActor. michael@0: * michael@0: * This is to be used with IPDL messages only. Do not store the returned michael@0: * pointer. michael@0: */ michael@0: PTextureChild* GetIPDLActor(); michael@0: michael@0: /** michael@0: * Triggers the destruction of the shared data and the corresponding TextureHost. michael@0: * michael@0: * If the texture flags contain TEXTURE_DEALLOCATE_CLIENT, the destruction michael@0: * will be synchronously coordinated with the compositor side, otherwise it michael@0: * will be done asynchronously. michael@0: */ michael@0: void ForceRemove(); michael@0: michael@0: virtual void SetReleaseFenceHandle(FenceHandle aReleaseFenceHandle) {} michael@0: michael@0: const FenceHandle& GetReleaseFenceHandle() const michael@0: { michael@0: return mReleaseFenceHandle; michael@0: } michael@0: michael@0: /** michael@0: * Wait until the current buffer is no longer being read. michael@0: * michael@0: * Platform support is necessary. gonk JB supports this function. michael@0: */ michael@0: virtual void WaitReleaseFence() {} michael@0: michael@0: private: michael@0: /** michael@0: * Called once, just before the destructor. michael@0: * michael@0: * Here goes the shut-down code that uses virtual methods. michael@0: * Must only be called by Release(). michael@0: */ michael@0: void Finalize(); michael@0: michael@0: friend class AtomicRefCountedWithFinalize; michael@0: michael@0: protected: michael@0: /** michael@0: * An invalid TextureClient cannot provide access to its shared data michael@0: * anymore. This usually means it will soon be destroyed. michael@0: */ michael@0: void MarkInvalid() { mValid = false; } michael@0: michael@0: /** michael@0: * Drop the shared data into a TextureClientData object and mark this michael@0: * TextureClient as invalid. michael@0: * michael@0: * The TextureClient must not hold any reference to the shared data michael@0: * after this method has been called. michael@0: * The TextureClientData is owned by the caller. michael@0: */ michael@0: virtual TextureClientData* DropTextureData() = 0; michael@0: michael@0: /** michael@0: * Should only be called *once* per texture, in TextureClient::InitIPDLActor. michael@0: * Some texture implementations rely on the fact that the descriptor will be michael@0: * deserialized. michael@0: * Calling ToSurfaceDescriptor again after it has already returned true, michael@0: * or never constructing a TextureHost with aDescriptor may result in a memory michael@0: * leak (see CairoTextureClientD3D9 for example). michael@0: */ michael@0: virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aDescriptor) = 0; michael@0: michael@0: void AddFlags(TextureFlags aFlags) michael@0: { michael@0: MOZ_ASSERT(!IsSharedWithCompositor()); michael@0: mFlags |= aFlags; michael@0: } michael@0: michael@0: RefPtr mActor; michael@0: TextureFlags mFlags; michael@0: bool mShared; michael@0: bool mValid; michael@0: FenceHandle mReleaseFenceHandle; michael@0: michael@0: friend class TextureChild; michael@0: friend void TestTextureClientSurface(TextureClient*, gfxImageSurface*); michael@0: friend void TestTextureClientYCbCr(TextureClient*, PlanarYCbCrData&); michael@0: }; michael@0: michael@0: /** michael@0: * TextureClient that wraps a random access buffer such as a Shmem or raw memory. michael@0: * This class must be inherited to implement the memory allocation and access bits. michael@0: * (see ShmemTextureClient and MemoryTextureClient) michael@0: */ michael@0: class BufferTextureClient : public TextureClient michael@0: , public TextureClientYCbCr michael@0: { michael@0: public: michael@0: BufferTextureClient(ISurfaceAllocator* aAllocator, gfx::SurfaceFormat aFormat, michael@0: gfx::BackendType aBackend, TextureFlags aFlags); michael@0: michael@0: virtual ~BufferTextureClient(); michael@0: michael@0: virtual bool IsAllocated() const = 0; michael@0: michael@0: virtual uint8_t* GetBuffer() const = 0; michael@0: michael@0: virtual gfx::IntSize GetSize() const { return mSize; } michael@0: michael@0: virtual bool Lock(OpenMode aMode) MOZ_OVERRIDE; michael@0: michael@0: virtual void Unlock() MOZ_OVERRIDE; michael@0: michael@0: virtual bool IsLocked() const MOZ_OVERRIDE { return mLocked; } michael@0: michael@0: virtual bool CanExposeDrawTarget() const MOZ_OVERRIDE { return true; } michael@0: michael@0: virtual TemporaryRef GetAsDrawTarget() MOZ_OVERRIDE; michael@0: michael@0: virtual bool AllocateForSurface(gfx::IntSize aSize, michael@0: TextureAllocationFlags aFlags = ALLOC_DEFAULT) MOZ_OVERRIDE; michael@0: michael@0: // TextureClientYCbCr michael@0: michael@0: virtual TextureClientYCbCr* AsTextureClientYCbCr() MOZ_OVERRIDE { return this; } michael@0: michael@0: virtual bool UpdateYCbCr(const PlanarYCbCrData& aData) MOZ_OVERRIDE; michael@0: michael@0: virtual bool AllocateForYCbCr(gfx::IntSize aYSize, michael@0: gfx::IntSize aCbCrSize, michael@0: StereoMode aStereoMode) MOZ_OVERRIDE; michael@0: michael@0: virtual gfx::SurfaceFormat GetFormat() const MOZ_OVERRIDE { return mFormat; } michael@0: michael@0: // XXX - Bug 908196 - Make Allocate(uint32_t) and GetBufferSize() protected. michael@0: // these two methods should only be called by methods of BufferTextureClient michael@0: // that are overridden in GrallocTextureClient (which does not implement the michael@0: // two methods below) michael@0: virtual bool Allocate(uint32_t aSize) = 0; michael@0: michael@0: virtual size_t GetBufferSize() const = 0; michael@0: michael@0: virtual bool HasInternalBuffer() const MOZ_OVERRIDE { return true; } michael@0: michael@0: ISurfaceAllocator* GetAllocator() const; michael@0: michael@0: protected: michael@0: RefPtr mDrawTarget; michael@0: RefPtr mAllocator; michael@0: gfx::SurfaceFormat mFormat; michael@0: gfx::IntSize mSize; michael@0: gfx::BackendType mBackend; michael@0: OpenMode mOpenMode; michael@0: bool mUsingFallbackDrawTarget; michael@0: bool mLocked; michael@0: }; michael@0: michael@0: /** michael@0: * TextureClient that wraps shared memory. michael@0: * the corresponding texture on the host side is ShmemTextureHost. michael@0: */ michael@0: class ShmemTextureClient : public BufferTextureClient michael@0: { michael@0: public: michael@0: ShmemTextureClient(ISurfaceAllocator* aAllocator, gfx::SurfaceFormat aFormat, michael@0: gfx::BackendType aBackend, TextureFlags aFlags); michael@0: michael@0: ~ShmemTextureClient(); michael@0: michael@0: virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aDescriptor) MOZ_OVERRIDE; michael@0: michael@0: virtual bool Allocate(uint32_t aSize) MOZ_OVERRIDE; michael@0: michael@0: virtual uint8_t* GetBuffer() const MOZ_OVERRIDE; michael@0: michael@0: virtual size_t GetBufferSize() const MOZ_OVERRIDE; michael@0: michael@0: virtual bool IsAllocated() const MOZ_OVERRIDE { return mAllocated; } michael@0: michael@0: virtual TextureClientData* DropTextureData() MOZ_OVERRIDE; michael@0: michael@0: virtual bool HasInternalBuffer() const MOZ_OVERRIDE { return true; } michael@0: michael@0: mozilla::ipc::Shmem& GetShmem() { return mShmem; } michael@0: michael@0: protected: michael@0: mozilla::ipc::Shmem mShmem; michael@0: bool mAllocated; michael@0: }; michael@0: michael@0: /** michael@0: * TextureClient that wraps raw memory. michael@0: * The corresponding texture on the host side is MemoryTextureHost. michael@0: * Can obviously not be used in a cross process setup. michael@0: */ michael@0: class MemoryTextureClient : public BufferTextureClient michael@0: { michael@0: public: michael@0: MemoryTextureClient(ISurfaceAllocator* aAllocator, gfx::SurfaceFormat aFormat, michael@0: gfx::BackendType aBackend, TextureFlags aFlags); michael@0: michael@0: ~MemoryTextureClient(); michael@0: michael@0: virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aDescriptor) MOZ_OVERRIDE; michael@0: michael@0: virtual bool Allocate(uint32_t aSize) MOZ_OVERRIDE; michael@0: michael@0: virtual uint8_t* GetBuffer() const MOZ_OVERRIDE { return mBuffer; } michael@0: michael@0: virtual size_t GetBufferSize() const MOZ_OVERRIDE { return mBufSize; } michael@0: michael@0: virtual bool IsAllocated() const MOZ_OVERRIDE { return mBuffer != nullptr; } michael@0: michael@0: virtual bool HasInternalBuffer() const MOZ_OVERRIDE { return true; } michael@0: michael@0: virtual TextureClientData* DropTextureData() MOZ_OVERRIDE; michael@0: michael@0: protected: michael@0: uint8_t* mBuffer; michael@0: size_t mBufSize; michael@0: }; michael@0: michael@0: struct TextureClientAutoUnlock michael@0: { michael@0: TextureClient* mTexture; michael@0: michael@0: TextureClientAutoUnlock(TextureClient* aTexture) michael@0: : mTexture(aTexture) {} michael@0: michael@0: ~TextureClientAutoUnlock() michael@0: { michael@0: mTexture->Unlock(); michael@0: } michael@0: }; michael@0: michael@0: } michael@0: } michael@0: #endif