michael@0: /* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */ 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 GLTEXTUREIMAGE_H_ michael@0: #define GLTEXTUREIMAGE_H_ michael@0: michael@0: #include "nsAutoPtr.h" michael@0: #include "nsRegion.h" michael@0: #include "nsTArray.h" michael@0: #include "gfxTypes.h" michael@0: #include "GLContextTypes.h" michael@0: #include "GraphicsFilter.h" michael@0: #include "mozilla/gfx/Rect.h" michael@0: #include "mozilla/RefPtr.h" michael@0: michael@0: class gfxASurface; michael@0: michael@0: namespace mozilla { michael@0: namespace gfx { michael@0: class DataSourceSurface; michael@0: class DrawTarget; michael@0: } michael@0: } michael@0: michael@0: namespace mozilla { michael@0: namespace gl { michael@0: class GLContext; michael@0: michael@0: /** michael@0: * A TextureImage encapsulates a surface that can be drawn to by a michael@0: * Thebes gfxContext and (hopefully efficiently!) synchronized to a michael@0: * texture in the server. TextureImages are associated with one and michael@0: * only one GLContext. michael@0: * michael@0: * Implementation note: TextureImages attempt to unify two categories michael@0: * of backends michael@0: * michael@0: * (1) proxy to server-side object that can be bound to a texture; michael@0: * e.g. Pixmap on X11. michael@0: * michael@0: * (2) efficient manager of texture memory; e.g. by having clients draw michael@0: * into a scratch buffer which is then uploaded with michael@0: * glTexSubImage2D(). michael@0: */ michael@0: class TextureImage michael@0: { michael@0: NS_INLINE_DECL_REFCOUNTING(TextureImage) michael@0: public: michael@0: enum TextureState michael@0: { michael@0: Created, // Texture created, but has not had glTexImage called to initialize it. michael@0: Allocated, // Texture memory exists, but contents are invalid. michael@0: Valid // Texture fully ready to use. michael@0: }; michael@0: michael@0: enum Flags { michael@0: NoFlags = 0x0, michael@0: UseNearestFilter = 0x1, michael@0: NeedsYFlip = 0x2, michael@0: DisallowBigImage = 0x4 michael@0: }; michael@0: michael@0: typedef gfxContentType ContentType; michael@0: typedef gfxImageFormat ImageFormat; michael@0: michael@0: static already_AddRefed Create( michael@0: GLContext* gl, michael@0: const nsIntSize& aSize, michael@0: TextureImage::ContentType aContentType, michael@0: GLenum aWrapMode, michael@0: TextureImage::Flags aFlags = TextureImage::NoFlags); michael@0: // Moz2D equivalent... michael@0: static already_AddRefed Create( michael@0: GLContext* gl, michael@0: const gfx::IntSize& aSize, michael@0: TextureImage::ContentType aContentType, michael@0: GLenum aWrapMode, michael@0: TextureImage::Flags aFlags = TextureImage::NoFlags); michael@0: michael@0: /** michael@0: * Returns a gfxASurface for updating |aRegion| of the client's michael@0: * image if successul, nullptr if not. |aRegion|'s bounds must fit michael@0: * within Size(); its coordinate space (if any) is ignored. If michael@0: * the update begins successfully, the returned gfxASurface is michael@0: * owned by this. Otherwise, nullptr is returned. michael@0: * michael@0: * |aRegion| is an inout param: the returned region is what the michael@0: * client must repaint. Category (1) regions above can michael@0: * efficiently handle repaints to "scattered" regions, while (2) michael@0: * can only efficiently handle repaints to rects. michael@0: * michael@0: * Painting the returned surface outside of |aRegion| results michael@0: * in undefined behavior. michael@0: * michael@0: * BeginUpdate() calls cannot be "nested", and each successful michael@0: * BeginUpdate() must be followed by exactly one EndUpdate() (see michael@0: * below). Failure to do so can leave this in a possibly michael@0: * inconsistent state. Unsuccessful BeginUpdate()s must not be michael@0: * followed by EndUpdate(). michael@0: */ michael@0: virtual gfx::DrawTarget* BeginUpdate(nsIntRegion& aRegion) = 0; michael@0: /** michael@0: * Retrieves the region that will require updating, given a michael@0: * region that needs to be updated. This can be used for michael@0: * making decisions about updating before calling BeginUpdate(). michael@0: * michael@0: * |aRegion| is an inout param. michael@0: */ michael@0: virtual void GetUpdateRegion(nsIntRegion& aForRegion) { michael@0: } michael@0: /** michael@0: * Finish the active update and synchronize with the server, if michael@0: * necessary. michael@0: * michael@0: * BeginUpdate() must have been called exactly once before michael@0: * EndUpdate(). michael@0: */ michael@0: virtual void EndUpdate() = 0; michael@0: michael@0: /** michael@0: * The Image may contain several textures for different regions (tiles). michael@0: * These functions iterate over each sub texture image tile. michael@0: */ michael@0: virtual void BeginTileIteration() { michael@0: } michael@0: michael@0: virtual bool NextTile() { michael@0: return false; michael@0: } michael@0: michael@0: // Function prototype for a tile iteration callback. Returning false will michael@0: // cause iteration to be interrupted (i.e. the corresponding NextTile call michael@0: // will return false). michael@0: typedef bool (* TileIterationCallback)(TextureImage* aImage, michael@0: int aTileNumber, michael@0: void* aCallbackData); michael@0: michael@0: // Sets a callback to be called every time NextTile is called. michael@0: virtual void SetIterationCallback(TileIterationCallback aCallback, michael@0: void* aCallbackData) { michael@0: } michael@0: michael@0: virtual gfx::IntRect GetTileRect(); michael@0: michael@0: virtual GLuint GetTextureID() = 0; michael@0: michael@0: virtual uint32_t GetTileCount() { michael@0: return 1; michael@0: } michael@0: michael@0: /** michael@0: * Set this TextureImage's size, and ensure a texture has been michael@0: * allocated. Must not be called between BeginUpdate and EndUpdate. michael@0: * After a resize, the contents are undefined. michael@0: * michael@0: * If this isn't implemented by a subclass, it will just perform michael@0: * a dummy BeginUpdate/EndUpdate pair. michael@0: */ michael@0: virtual void Resize(const gfx::IntSize& aSize) { michael@0: mSize = aSize; michael@0: nsIntRegion r(nsIntRect(0, 0, aSize.width, aSize.height)); michael@0: BeginUpdate(r); michael@0: EndUpdate(); michael@0: } michael@0: michael@0: /** michael@0: * Mark this texture as having valid contents. Call this after modifying michael@0: * the texture contents externally. michael@0: */ michael@0: virtual void MarkValid() {} michael@0: michael@0: /** michael@0: * aSurf - the source surface to update from michael@0: * aRegion - the region in this image to update michael@0: * aFrom - offset in the source to update from michael@0: */ michael@0: virtual bool DirectUpdate(gfx::DataSourceSurface* aSurf, const nsIntRegion& aRegion, const gfx::IntPoint& aFrom = gfx::IntPoint(0,0)) = 0; michael@0: bool UpdateFromDataSource(gfx::DataSourceSurface *aSurf, michael@0: const nsIntRegion* aDstRegion = nullptr, michael@0: const gfx::IntPoint* aSrcOffset = nullptr); michael@0: michael@0: virtual void BindTexture(GLenum aTextureUnit) = 0; michael@0: michael@0: /** michael@0: * Returns the image format of the texture. Only valid after a matching michael@0: * BeginUpdate/EndUpdate pair have been called. michael@0: */ michael@0: virtual gfx::SurfaceFormat GetTextureFormat() { michael@0: return mTextureFormat; michael@0: } michael@0: michael@0: /** Can be called safely at any time. */ michael@0: michael@0: /** michael@0: * If this TextureImage has a permanent gfxASurface backing, michael@0: * return it. Otherwise return nullptr. michael@0: */ michael@0: virtual already_AddRefed GetBackingSurface() michael@0: { return nullptr; } michael@0: michael@0: michael@0: gfx::IntSize GetSize() const; michael@0: ContentType GetContentType() const { return mContentType; } michael@0: ImageFormat GetImageFormat() const { return mImageFormat; } michael@0: virtual bool InUpdate() const = 0; michael@0: GLenum GetWrapMode() const { return mWrapMode; } michael@0: michael@0: void SetFilter(GraphicsFilter aFilter) { mFilter = aFilter; } michael@0: michael@0: protected: michael@0: friend class GLContext; michael@0: michael@0: /** michael@0: * After the ctor, the TextureImage is invalid. Implementations michael@0: * must allocate resources successfully before returning the new michael@0: * TextureImage from GLContext::CreateTextureImage(). That is, michael@0: * clients must not be given partially-constructed TextureImages. michael@0: */ michael@0: TextureImage(const nsIntSize& aSize, michael@0: GLenum aWrapMode, ContentType aContentType, michael@0: Flags aFlags = NoFlags, michael@0: ImageFormat aImageFormat = gfxImageFormat::Unknown) michael@0: : mSize(aSize.ToIntSize()) michael@0: , mWrapMode(aWrapMode) michael@0: , mContentType(aContentType) michael@0: , mImageFormat(aImageFormat) michael@0: , mFilter(GraphicsFilter::FILTER_GOOD) michael@0: , mFlags(aFlags) michael@0: {} michael@0: michael@0: // Moz2D equivalent... michael@0: TextureImage(const gfx::IntSize& aSize, michael@0: GLenum aWrapMode, ContentType aContentType, michael@0: Flags aFlags = NoFlags); michael@0: michael@0: // Protected destructor, to discourage deletion outside of Release(): michael@0: virtual ~TextureImage() {} michael@0: michael@0: virtual gfx::IntRect GetSrcTileRect(); michael@0: michael@0: gfx::IntSize mSize; michael@0: GLenum mWrapMode; michael@0: ContentType mContentType; michael@0: ImageFormat mImageFormat; michael@0: gfx::SurfaceFormat mTextureFormat; michael@0: GraphicsFilter mFilter; michael@0: Flags mFlags; michael@0: }; michael@0: michael@0: /** michael@0: * BasicTextureImage is the baseline TextureImage implementation --- michael@0: * it updates its texture by allocating a scratch buffer for the michael@0: * client to draw into, then using glTexSubImage2D() to upload the new michael@0: * pixels. Platforms must provide the code to create a new surface michael@0: * into which the updated pixels will be drawn, and the code to michael@0: * convert the update surface's pixels into an image on which we can michael@0: * glTexSubImage2D(). michael@0: */ michael@0: class BasicTextureImage michael@0: : public TextureImage michael@0: { michael@0: public: michael@0: virtual ~BasicTextureImage(); michael@0: michael@0: BasicTextureImage(GLuint aTexture, michael@0: const nsIntSize& aSize, michael@0: GLenum aWrapMode, michael@0: ContentType aContentType, michael@0: GLContext* aContext, michael@0: TextureImage::Flags aFlags = TextureImage::NoFlags, michael@0: TextureImage::ImageFormat aImageFormat = gfxImageFormat::Unknown); michael@0: BasicTextureImage(GLuint aTexture, michael@0: const gfx::IntSize& aSize, michael@0: GLenum aWrapMode, michael@0: ContentType aContentType, michael@0: GLContext* aContext, michael@0: TextureImage::Flags aFlags = TextureImage::NoFlags, michael@0: TextureImage::ImageFormat aImageFormat = gfxImageFormat::Unknown); michael@0: michael@0: virtual void BindTexture(GLenum aTextureUnit); michael@0: michael@0: virtual gfx::DrawTarget* BeginUpdate(nsIntRegion& aRegion); michael@0: virtual void GetUpdateRegion(nsIntRegion& aForRegion); michael@0: virtual void EndUpdate(); michael@0: virtual bool DirectUpdate(gfx::DataSourceSurface* aSurf, const nsIntRegion& aRegion, const gfx::IntPoint& aFrom = gfx::IntPoint(0,0)); michael@0: virtual GLuint GetTextureID() { return mTexture; } michael@0: virtual TemporaryRef michael@0: GetDrawTargetForUpdate(const gfx::IntSize& aSize, gfx::SurfaceFormat aFmt); michael@0: michael@0: virtual void MarkValid() { mTextureState = Valid; } michael@0: michael@0: // Call when drawing into the update surface is complete. michael@0: // Returns true if textures should be upload with a relative michael@0: // offset - See UploadSurfaceToTexture. michael@0: virtual bool FinishedSurfaceUpdate(); michael@0: michael@0: // Call after surface data has been uploaded to a texture. michael@0: virtual void FinishedSurfaceUpload(); michael@0: michael@0: virtual bool InUpdate() const { return !!mUpdateDrawTarget; } michael@0: michael@0: virtual void Resize(const gfx::IntSize& aSize); michael@0: michael@0: protected: michael@0: GLuint mTexture; michael@0: TextureState mTextureState; michael@0: nsRefPtr mGLContext; michael@0: RefPtr mUpdateDrawTarget; michael@0: nsIntRegion mUpdateRegion; michael@0: michael@0: // The offset into the update surface at which the update rect is located. michael@0: nsIntPoint mUpdateOffset; michael@0: }; michael@0: michael@0: /** michael@0: * A container class that complements many sub TextureImages into a big TextureImage. michael@0: * Aims to behave just like the real thing. michael@0: */ michael@0: michael@0: class TiledTextureImage michael@0: : public TextureImage michael@0: { michael@0: public: michael@0: TiledTextureImage(GLContext* aGL, michael@0: gfx::IntSize aSize, michael@0: TextureImage::ContentType, michael@0: TextureImage::Flags aFlags = TextureImage::NoFlags, michael@0: TextureImage::ImageFormat aImageFormat = gfxImageFormat::Unknown); michael@0: ~TiledTextureImage(); michael@0: void DumpDiv(); michael@0: virtual gfx::DrawTarget* BeginUpdate(nsIntRegion& aRegion); michael@0: virtual void GetUpdateRegion(nsIntRegion& aForRegion); michael@0: virtual void EndUpdate(); michael@0: virtual void Resize(const gfx::IntSize& aSize); michael@0: virtual uint32_t GetTileCount(); michael@0: virtual void BeginTileIteration(); michael@0: virtual bool NextTile(); michael@0: virtual void SetIterationCallback(TileIterationCallback aCallback, michael@0: void* aCallbackData); michael@0: virtual gfx::IntRect GetTileRect(); michael@0: virtual GLuint GetTextureID() { michael@0: return mImages[mCurrentImage]->GetTextureID(); michael@0: } michael@0: virtual bool DirectUpdate(gfx::DataSourceSurface* aSurf, const nsIntRegion& aRegion, const gfx::IntPoint& aFrom = gfx::IntPoint(0,0)); michael@0: virtual bool InUpdate() const { return mInUpdate; } michael@0: virtual void BindTexture(GLenum); michael@0: michael@0: protected: michael@0: virtual gfx::IntRect GetSrcTileRect(); michael@0: michael@0: unsigned int mCurrentImage; michael@0: TileIterationCallback mIterationCallback; michael@0: void* mIterationCallbackData; michael@0: nsTArray< nsRefPtr > mImages; michael@0: bool mInUpdate; michael@0: gfx::IntSize mSize; michael@0: unsigned int mTileSize; michael@0: unsigned int mRows, mColumns; michael@0: GLContext* mGL; michael@0: // A temporary draw target to faciliate cross-tile updates. michael@0: RefPtr mUpdateDrawTarget; michael@0: // The region of update requested michael@0: nsIntRegion mUpdateRegion; michael@0: TextureState mTextureState; michael@0: TextureImage::ImageFormat mImageFormat; michael@0: }; michael@0: michael@0: /** michael@0: * Creates a TextureImage of the basic implementation, can be useful in cases michael@0: * where we know we don't want to use platform-specific TextureImage. michael@0: * In doubt, use GLContext::CreateTextureImage instead. michael@0: */ michael@0: already_AddRefed michael@0: CreateBasicTextureImage(GLContext* aGL, michael@0: const gfx::IntSize& aSize, michael@0: TextureImage::ContentType aContentType, michael@0: GLenum aWrapMode, michael@0: TextureImage::Flags aFlags, michael@0: TextureImage::ImageFormat aImageFormat = gfxImageFormat::Unknown); michael@0: michael@0: /** michael@0: * Return a valid, allocated TextureImage of |aSize| with michael@0: * |aContentType|. If |aContentType| is COLOR, |aImageFormat| can be used michael@0: * to hint at the preferred RGB format, however it is not necessarily michael@0: * respected. The TextureImage's texture is configured to use michael@0: * |aWrapMode| (usually GL_CLAMP_TO_EDGE or GL_REPEAT) and by michael@0: * default, GL_LINEAR filtering. Specify michael@0: * |aFlags=UseNearestFilter| for GL_NEAREST filtering. Specify michael@0: * |aFlags=NeedsYFlip| if the image is flipped. Return michael@0: * nullptr if creating the TextureImage fails. michael@0: * michael@0: * The returned TextureImage may only be used with this GLContext. michael@0: * Attempting to use the returned TextureImage after this michael@0: * GLContext is destroyed will result in undefined (and likely michael@0: * crashy) behavior. michael@0: */ michael@0: already_AddRefed michael@0: CreateTextureImage(GLContext* gl, michael@0: const gfx::IntSize& aSize, michael@0: TextureImage::ContentType aContentType, michael@0: GLenum aWrapMode, michael@0: TextureImage::Flags aFlags = TextureImage::NoFlags, michael@0: TextureImage::ImageFormat aImageFormat = gfxImageFormat::Unknown); michael@0: michael@0: } // namespace gl michael@0: } // namespace mozilla michael@0: michael@0: #endif /* GLTEXTUREIMAGE_H_ */