/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- * 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_TEXTUREHOST_H #define MOZILLA_GFX_TEXTUREHOST_H #include "mozilla/layers/LayersTypes.h" #include "nsRect.h" #include "nsRegion.h" #include "mozilla/gfx/Rect.h" #include "mozilla/layers/CompositorTypes.h" #include "nsAutoPtr.h" #include "mozilla/RefPtr.h" #include "mozilla/layers/ISurfaceAllocator.h" class gfxReusableSurfaceWrapper; class gfxImageSurface; namespace mozilla { namespace layers { class Compositor; class SurfaceDescriptor; class ISurfaceAllocator; class TextureSourceOGL; class TextureSourceD3D11; class TextureSourceBasic; class TextureParent; /** * A view on a TextureHost where the texture is internally represented as tiles * (contrast with a tiled buffer, where each texture is a tile). For iteration by * the texture's buffer host. * This is only useful when the underlying surface is too big to fit in one * device texture, which forces us to split it in smaller parts. * Tiled Compositable is a different thing. */ class TileIterator { public: virtual void BeginTileIteration() = 0; virtual void EndTileIteration() {}; virtual nsIntRect GetTileRect() = 0; virtual size_t GetTileCount() = 0; virtual bool NextTile() = 0; }; /** * TextureSource is the interface for texture objects that can be composited * by a given compositor backend. Since the drawing APIs are different * between backends, the TextureSource interface is split into different * interfaces (TextureSourceOGL, etc.), and TextureSource mostly provide * access to these interfaces. * * This class is used on the compositor side. */ class TextureSource : public RefCounted { public: TextureSource() { MOZ_COUNT_CTOR(TextureSource); } virtual ~TextureSource() { MOZ_COUNT_DTOR(TextureSource); } /** * Returns the size of the texture in texels. * If the underlying texture host is a tile iterator, GetSize must return the * size of the current tile. */ virtual gfx::IntSize GetSize() const = 0; /** * Cast to an TextureSource for the OpenGL backend. */ virtual TextureSourceOGL* AsSourceOGL() { return nullptr; } /** * Cast to an TextureSource for the D3D11 backend. */ virtual TextureSourceD3D11* AsSourceD3D11() { return nullptr; } virtual TextureSourceBasic* AsSourceBasic() { return nullptr; } /** * In some rare cases we currently need to consider a group of textures as one * TextureSource, that can be split in sub-TextureSources. */ virtual TextureSource* GetSubSource(int index) { return nullptr; } /** * Overload this if the TextureSource supports big textures that don't fit in * one device texture and must be tiled internally. */ virtual TileIterator* AsTileIterator() { return nullptr; } #ifdef MOZ_LAYERS_HAVE_LOG virtual void PrintInfo(nsACString& aTo, const char* aPrefix); #endif }; /** * TextureHost is a thin abstraction over texture data that need to be shared * or transfered from the content process to the compositor process. It is the * compositor-side half of a TextureClient/TextureHost pair. A corresponding * TextureClient lives on the client-side. * * TextureHost only knows how to deserialize or synchronize generic image data * (SurfaceDescriptor) and provide access to one or more TextureSource objects * (these provide the necessary APIs for compositor backends to composite the * image). * * A TextureHost should mostly correspond to one or several SurfaceDescriptor * types. This means that for YCbCr planes, even though they are represented as * 3 textures internally, use 1 TextureHost and not 3, because the 3 planes * arrive in the same IPC message. * * The Lock/Unlock mecanism here mirrors Lock/Unlock in TextureClient. These two * methods don't always have to use blocking locks, unless a resource is shared * between the two sides (like shared texture handles). For instance, in some * cases the data received in Update(...) is a copy in shared memory of the data * owned by the content process, in which case no blocking lock is required. * * TextureHosts can be changed at any time, for example if we receive a * SurfaceDescriptor type that was not expected. This should be an incentive * to keep the ownership model simple (especially on the OpenGL case, where * we have additionnal constraints). * * There are two fundamental operations carried out on texture hosts - update * from the content thread and composition. Texture upload can occur in either * phase. Update happens in response to an IPDL message from content and * composition when the compositor 'ticks'. We may composite many times before * update. * * Update ends up at TextureHost::UpdateImpl. It always occurs in a layers * transacton. (TextureParent should call EnsureTexture before updating to * ensure the TextureHost exists and is of the correct type). * * CompositableHost::Composite does compositing. It should check the texture * host exists (and give up otherwise), then lock the texture host * (TextureHost::Lock). Then it passes the texture host to the Compositor in an * effect as a texture source, which does the actual composition. Finally the * compositable calls Unlock on the TextureHost. * * The class TextureImageTextureHostOGL is a good example of a TextureHost * implementation. * * This class is used only on the compositor side. */ class TextureHost : public TextureSource { public: /** * Create a new texture host to handle surfaces of aDescriptorType * * @param aDescriptorType The SurfaceDescriptor type being passed * @param aTextureHostFlags Modifier flags that specify changes in * the usage of a aDescriptorType, see TextureHostFlags * @param aTextureFlags Flags to pass to the new TextureHost */ static TemporaryRef CreateTextureHost(SurfaceDescriptorType aDescriptorType, uint32_t aTextureHostFlags, uint32_t aTextureFlags); TextureHost(); virtual ~TextureHost(); virtual gfx::SurfaceFormat GetFormat() const { return mFormat; } virtual bool IsValid() const { return true; } /** * Update the texture host using the data from aSurfaceDescriptor. * * @param aImage Source image to update with. * @param aRegion Region of the texture host to update. * @param aOffset Offset in the source to update from */ void Update(const SurfaceDescriptor& aImage, nsIntRegion *aRegion = nullptr, nsIntPoint* aOffset = nullptr); /** * Change the current surface of the texture host to aImage. aResult will return * the previous surface. */ void SwapTextures(const SurfaceDescriptor& aImage, SurfaceDescriptor* aResult = nullptr, nsIntRegion *aRegion = nullptr); /** * Update for tiled texture hosts could probably have a better signature, but we * will replace it with PTexture stuff anyway, so nm. */ virtual void Update(gfxReusableSurfaceWrapper* aReusableSurface, TextureFlags aFlags, const gfx::IntSize& aSize) {} /** * Lock the texture host for compositing, returns true if the TextureHost is * valid for composition. */ virtual bool Lock() { return IsValid(); } /** * Unlock the texture host after compositing. * Should handle the case where Lock failed without crashing. */ virtual void Unlock() {} void SetFlags(TextureFlags aFlags) { mFlags = aFlags; } void AddFlag(TextureFlags aFlag) { mFlags |= aFlag; } TextureFlags GetFlags() { return mFlags; } /** * Sets ths TextureHost's compositor. * A TextureHost can change compositor on certain occasions, in particular if * it belongs to an async Compositable. * aCompositor can be null, in which case the TextureHost must cleanup all * of it's device textures. */ virtual void SetCompositor(Compositor* aCompositor) {} ISurfaceAllocator* GetDeAllocator() { return mDeAllocator; } bool operator== (const TextureHost& o) const { return GetIdentifier() == o.GetIdentifier(); } bool operator!= (const TextureHost& o) const { return GetIdentifier() != o.GetIdentifier(); } LayerRenderState GetRenderState() { return LayerRenderState(mBuffer, mFlags & NeedsYFlip ? LAYER_RENDER_STATE_Y_FLIPPED : 0); } virtual already_AddRefed GetAsSurface() = 0; #ifdef MOZ_LAYERS_HAVE_LOG virtual const char *Name() = 0; virtual void PrintInfo(nsACString& aTo, const char* aPrefix); #endif /** * TEMPORARY. * * Ensure that a buffer of the given size/type has been allocated so that * we can update it using Update and/or CopyTo. */ virtual void EnsureBuffer(const nsIntSize& aSize, gfxASurface::gfxContentType aType) { NS_RUNTIMEABORT("TextureHost doesn't support EnsureBuffer"); } /** * Copy the contents of this TextureHost to aDest. aDest must already * have a suitable buffer allocated using EnsureBuffer. * * @param aSourceRect Area of this texture host to copy. * @param aDest Destination texture host. * @param aDestRect Destination rect. */ virtual void CopyTo(const nsIntRect& aSourceRect, TextureHost *aDest, const nsIntRect& aDestRect) { NS_RUNTIMEABORT("TextureHost doesn't support CopyTo"); } SurfaceDescriptor* GetBuffer() const { return mBuffer; } /** * Set a SurfaceDescriptor for this texture host. By setting a buffer and * allocator/de-allocator for the TextureHost, you cause the TextureHost to * retain a SurfaceDescriptor. * Ownership of the SurfaceDescriptor passes to this. */ // only made virtual to allow overriding in GrallocTextureHostOGL, for hacky fix in gecko 23 for bug 862324. // see bug 865908 about fixing this. virtual void SetBuffer(SurfaceDescriptor* aBuffer, ISurfaceAllocator* aAllocator) { MOZ_ASSERT(!mBuffer, "Will leak the old mBuffer"); mBuffer = aBuffer; mDeAllocator = aAllocator; } // used only for hacky fix in gecko 23 for bug 862324 // see bug 865908 about fixing this. virtual void ForgetBuffer() {} protected: /** * Should be implemented by the backend-specific TextureHost classes * * It should not take a reference to aImage, unless it knows the data * to be thread-safe. */ virtual void UpdateImpl(const SurfaceDescriptor& aImage, nsIntRegion *aRegion, nsIntPoint *aOffset = nullptr) { NS_RUNTIMEABORT("Should not be reached"); } /** * Should be implemented by the backend-specific TextureHost classes. * * Doesn't need to do the actual surface descriptor swap, just * any preparation work required to use the new descriptor. * * If the implementation doesn't define anything in particular * for handling swaps, then we can just do an update instead. */ virtual void SwapTexturesImpl(const SurfaceDescriptor& aImage, nsIntRegion *aRegion) { UpdateImpl(aImage, aRegion, nullptr); } // An internal identifier for this texture host. Two texture hosts // should be considered equal iff their identifiers match. Should // not be exposed publicly. virtual uint64_t GetIdentifier() const { return reinterpret_cast(this); } // Texture info TextureFlags mFlags; SurfaceDescriptor* mBuffer; // FIXME [bjacob] it's terrible to have a SurfaceDescriptor here, // because SurfaceDescriptor's may have raw pointers to IPDL actors, // which can go away under our feet at any time. This is the cause // of bug 862324 among others. Our current understanding is that // this will be gone in Gecko 24. See bug 858914. gfx::SurfaceFormat mFormat; ISurfaceAllocator* mDeAllocator; }; class AutoLockTextureHost { public: AutoLockTextureHost(TextureHost* aHost) : mTextureHost(aHost) , mIsValid(true) { if (mTextureHost) { mIsValid = mTextureHost->Lock(); } } ~AutoLockTextureHost() { if (mTextureHost && mIsValid) { mTextureHost->Unlock(); } } bool IsValid() { return mIsValid; } private: TextureHost *mTextureHost; bool mIsValid; }; /** * This can be used as an offscreen rendering target by the compositor, and * subsequently can be used as a source by the compositor. */ class CompositingRenderTarget : public TextureSource { public: virtual ~CompositingRenderTarget() {} #ifdef MOZ_DUMP_PAINTING virtual already_AddRefed Dump(Compositor* aCompositor) { return nullptr; } #endif }; } } #endif