1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/gl/GLTextureImage.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,410 @@ 1.4 +/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#ifndef GLTEXTUREIMAGE_H_ 1.10 +#define GLTEXTUREIMAGE_H_ 1.11 + 1.12 +#include "nsAutoPtr.h" 1.13 +#include "nsRegion.h" 1.14 +#include "nsTArray.h" 1.15 +#include "gfxTypes.h" 1.16 +#include "GLContextTypes.h" 1.17 +#include "GraphicsFilter.h" 1.18 +#include "mozilla/gfx/Rect.h" 1.19 +#include "mozilla/RefPtr.h" 1.20 + 1.21 +class gfxASurface; 1.22 + 1.23 +namespace mozilla { 1.24 +namespace gfx { 1.25 +class DataSourceSurface; 1.26 +class DrawTarget; 1.27 +} 1.28 +} 1.29 + 1.30 +namespace mozilla { 1.31 +namespace gl { 1.32 +class GLContext; 1.33 + 1.34 +/** 1.35 + * A TextureImage encapsulates a surface that can be drawn to by a 1.36 + * Thebes gfxContext and (hopefully efficiently!) synchronized to a 1.37 + * texture in the server. TextureImages are associated with one and 1.38 + * only one GLContext. 1.39 + * 1.40 + * Implementation note: TextureImages attempt to unify two categories 1.41 + * of backends 1.42 + * 1.43 + * (1) proxy to server-side object that can be bound to a texture; 1.44 + * e.g. Pixmap on X11. 1.45 + * 1.46 + * (2) efficient manager of texture memory; e.g. by having clients draw 1.47 + * into a scratch buffer which is then uploaded with 1.48 + * glTexSubImage2D(). 1.49 + */ 1.50 +class TextureImage 1.51 +{ 1.52 + NS_INLINE_DECL_REFCOUNTING(TextureImage) 1.53 +public: 1.54 + enum TextureState 1.55 + { 1.56 + Created, // Texture created, but has not had glTexImage called to initialize it. 1.57 + Allocated, // Texture memory exists, but contents are invalid. 1.58 + Valid // Texture fully ready to use. 1.59 + }; 1.60 + 1.61 + enum Flags { 1.62 + NoFlags = 0x0, 1.63 + UseNearestFilter = 0x1, 1.64 + NeedsYFlip = 0x2, 1.65 + DisallowBigImage = 0x4 1.66 + }; 1.67 + 1.68 + typedef gfxContentType ContentType; 1.69 + typedef gfxImageFormat ImageFormat; 1.70 + 1.71 + static already_AddRefed<TextureImage> Create( 1.72 + GLContext* gl, 1.73 + const nsIntSize& aSize, 1.74 + TextureImage::ContentType aContentType, 1.75 + GLenum aWrapMode, 1.76 + TextureImage::Flags aFlags = TextureImage::NoFlags); 1.77 + // Moz2D equivalent... 1.78 + static already_AddRefed<TextureImage> Create( 1.79 + GLContext* gl, 1.80 + const gfx::IntSize& aSize, 1.81 + TextureImage::ContentType aContentType, 1.82 + GLenum aWrapMode, 1.83 + TextureImage::Flags aFlags = TextureImage::NoFlags); 1.84 + 1.85 + /** 1.86 + * Returns a gfxASurface for updating |aRegion| of the client's 1.87 + * image if successul, nullptr if not. |aRegion|'s bounds must fit 1.88 + * within Size(); its coordinate space (if any) is ignored. If 1.89 + * the update begins successfully, the returned gfxASurface is 1.90 + * owned by this. Otherwise, nullptr is returned. 1.91 + * 1.92 + * |aRegion| is an inout param: the returned region is what the 1.93 + * client must repaint. Category (1) regions above can 1.94 + * efficiently handle repaints to "scattered" regions, while (2) 1.95 + * can only efficiently handle repaints to rects. 1.96 + * 1.97 + * Painting the returned surface outside of |aRegion| results 1.98 + * in undefined behavior. 1.99 + * 1.100 + * BeginUpdate() calls cannot be "nested", and each successful 1.101 + * BeginUpdate() must be followed by exactly one EndUpdate() (see 1.102 + * below). Failure to do so can leave this in a possibly 1.103 + * inconsistent state. Unsuccessful BeginUpdate()s must not be 1.104 + * followed by EndUpdate(). 1.105 + */ 1.106 + virtual gfx::DrawTarget* BeginUpdate(nsIntRegion& aRegion) = 0; 1.107 + /** 1.108 + * Retrieves the region that will require updating, given a 1.109 + * region that needs to be updated. This can be used for 1.110 + * making decisions about updating before calling BeginUpdate(). 1.111 + * 1.112 + * |aRegion| is an inout param. 1.113 + */ 1.114 + virtual void GetUpdateRegion(nsIntRegion& aForRegion) { 1.115 + } 1.116 + /** 1.117 + * Finish the active update and synchronize with the server, if 1.118 + * necessary. 1.119 + * 1.120 + * BeginUpdate() must have been called exactly once before 1.121 + * EndUpdate(). 1.122 + */ 1.123 + virtual void EndUpdate() = 0; 1.124 + 1.125 + /** 1.126 + * The Image may contain several textures for different regions (tiles). 1.127 + * These functions iterate over each sub texture image tile. 1.128 + */ 1.129 + virtual void BeginTileIteration() { 1.130 + } 1.131 + 1.132 + virtual bool NextTile() { 1.133 + return false; 1.134 + } 1.135 + 1.136 + // Function prototype for a tile iteration callback. Returning false will 1.137 + // cause iteration to be interrupted (i.e. the corresponding NextTile call 1.138 + // will return false). 1.139 + typedef bool (* TileIterationCallback)(TextureImage* aImage, 1.140 + int aTileNumber, 1.141 + void* aCallbackData); 1.142 + 1.143 + // Sets a callback to be called every time NextTile is called. 1.144 + virtual void SetIterationCallback(TileIterationCallback aCallback, 1.145 + void* aCallbackData) { 1.146 + } 1.147 + 1.148 + virtual gfx::IntRect GetTileRect(); 1.149 + 1.150 + virtual GLuint GetTextureID() = 0; 1.151 + 1.152 + virtual uint32_t GetTileCount() { 1.153 + return 1; 1.154 + } 1.155 + 1.156 + /** 1.157 + * Set this TextureImage's size, and ensure a texture has been 1.158 + * allocated. Must not be called between BeginUpdate and EndUpdate. 1.159 + * After a resize, the contents are undefined. 1.160 + * 1.161 + * If this isn't implemented by a subclass, it will just perform 1.162 + * a dummy BeginUpdate/EndUpdate pair. 1.163 + */ 1.164 + virtual void Resize(const gfx::IntSize& aSize) { 1.165 + mSize = aSize; 1.166 + nsIntRegion r(nsIntRect(0, 0, aSize.width, aSize.height)); 1.167 + BeginUpdate(r); 1.168 + EndUpdate(); 1.169 + } 1.170 + 1.171 + /** 1.172 + * Mark this texture as having valid contents. Call this after modifying 1.173 + * the texture contents externally. 1.174 + */ 1.175 + virtual void MarkValid() {} 1.176 + 1.177 + /** 1.178 + * aSurf - the source surface to update from 1.179 + * aRegion - the region in this image to update 1.180 + * aFrom - offset in the source to update from 1.181 + */ 1.182 + virtual bool DirectUpdate(gfx::DataSourceSurface* aSurf, const nsIntRegion& aRegion, const gfx::IntPoint& aFrom = gfx::IntPoint(0,0)) = 0; 1.183 + bool UpdateFromDataSource(gfx::DataSourceSurface *aSurf, 1.184 + const nsIntRegion* aDstRegion = nullptr, 1.185 + const gfx::IntPoint* aSrcOffset = nullptr); 1.186 + 1.187 + virtual void BindTexture(GLenum aTextureUnit) = 0; 1.188 + 1.189 + /** 1.190 + * Returns the image format of the texture. Only valid after a matching 1.191 + * BeginUpdate/EndUpdate pair have been called. 1.192 + */ 1.193 + virtual gfx::SurfaceFormat GetTextureFormat() { 1.194 + return mTextureFormat; 1.195 + } 1.196 + 1.197 + /** Can be called safely at any time. */ 1.198 + 1.199 + /** 1.200 + * If this TextureImage has a permanent gfxASurface backing, 1.201 + * return it. Otherwise return nullptr. 1.202 + */ 1.203 + virtual already_AddRefed<gfxASurface> GetBackingSurface() 1.204 + { return nullptr; } 1.205 + 1.206 + 1.207 + gfx::IntSize GetSize() const; 1.208 + ContentType GetContentType() const { return mContentType; } 1.209 + ImageFormat GetImageFormat() const { return mImageFormat; } 1.210 + virtual bool InUpdate() const = 0; 1.211 + GLenum GetWrapMode() const { return mWrapMode; } 1.212 + 1.213 + void SetFilter(GraphicsFilter aFilter) { mFilter = aFilter; } 1.214 + 1.215 +protected: 1.216 + friend class GLContext; 1.217 + 1.218 + /** 1.219 + * After the ctor, the TextureImage is invalid. Implementations 1.220 + * must allocate resources successfully before returning the new 1.221 + * TextureImage from GLContext::CreateTextureImage(). That is, 1.222 + * clients must not be given partially-constructed TextureImages. 1.223 + */ 1.224 + TextureImage(const nsIntSize& aSize, 1.225 + GLenum aWrapMode, ContentType aContentType, 1.226 + Flags aFlags = NoFlags, 1.227 + ImageFormat aImageFormat = gfxImageFormat::Unknown) 1.228 + : mSize(aSize.ToIntSize()) 1.229 + , mWrapMode(aWrapMode) 1.230 + , mContentType(aContentType) 1.231 + , mImageFormat(aImageFormat) 1.232 + , mFilter(GraphicsFilter::FILTER_GOOD) 1.233 + , mFlags(aFlags) 1.234 + {} 1.235 + 1.236 + // Moz2D equivalent... 1.237 + TextureImage(const gfx::IntSize& aSize, 1.238 + GLenum aWrapMode, ContentType aContentType, 1.239 + Flags aFlags = NoFlags); 1.240 + 1.241 + // Protected destructor, to discourage deletion outside of Release(): 1.242 + virtual ~TextureImage() {} 1.243 + 1.244 + virtual gfx::IntRect GetSrcTileRect(); 1.245 + 1.246 + gfx::IntSize mSize; 1.247 + GLenum mWrapMode; 1.248 + ContentType mContentType; 1.249 + ImageFormat mImageFormat; 1.250 + gfx::SurfaceFormat mTextureFormat; 1.251 + GraphicsFilter mFilter; 1.252 + Flags mFlags; 1.253 +}; 1.254 + 1.255 +/** 1.256 + * BasicTextureImage is the baseline TextureImage implementation --- 1.257 + * it updates its texture by allocating a scratch buffer for the 1.258 + * client to draw into, then using glTexSubImage2D() to upload the new 1.259 + * pixels. Platforms must provide the code to create a new surface 1.260 + * into which the updated pixels will be drawn, and the code to 1.261 + * convert the update surface's pixels into an image on which we can 1.262 + * glTexSubImage2D(). 1.263 + */ 1.264 +class BasicTextureImage 1.265 + : public TextureImage 1.266 +{ 1.267 +public: 1.268 + virtual ~BasicTextureImage(); 1.269 + 1.270 + BasicTextureImage(GLuint aTexture, 1.271 + const nsIntSize& aSize, 1.272 + GLenum aWrapMode, 1.273 + ContentType aContentType, 1.274 + GLContext* aContext, 1.275 + TextureImage::Flags aFlags = TextureImage::NoFlags, 1.276 + TextureImage::ImageFormat aImageFormat = gfxImageFormat::Unknown); 1.277 + BasicTextureImage(GLuint aTexture, 1.278 + const gfx::IntSize& aSize, 1.279 + GLenum aWrapMode, 1.280 + ContentType aContentType, 1.281 + GLContext* aContext, 1.282 + TextureImage::Flags aFlags = TextureImage::NoFlags, 1.283 + TextureImage::ImageFormat aImageFormat = gfxImageFormat::Unknown); 1.284 + 1.285 + virtual void BindTexture(GLenum aTextureUnit); 1.286 + 1.287 + virtual gfx::DrawTarget* BeginUpdate(nsIntRegion& aRegion); 1.288 + virtual void GetUpdateRegion(nsIntRegion& aForRegion); 1.289 + virtual void EndUpdate(); 1.290 + virtual bool DirectUpdate(gfx::DataSourceSurface* aSurf, const nsIntRegion& aRegion, const gfx::IntPoint& aFrom = gfx::IntPoint(0,0)); 1.291 + virtual GLuint GetTextureID() { return mTexture; } 1.292 + virtual TemporaryRef<gfx::DrawTarget> 1.293 + GetDrawTargetForUpdate(const gfx::IntSize& aSize, gfx::SurfaceFormat aFmt); 1.294 + 1.295 + virtual void MarkValid() { mTextureState = Valid; } 1.296 + 1.297 + // Call when drawing into the update surface is complete. 1.298 + // Returns true if textures should be upload with a relative 1.299 + // offset - See UploadSurfaceToTexture. 1.300 + virtual bool FinishedSurfaceUpdate(); 1.301 + 1.302 + // Call after surface data has been uploaded to a texture. 1.303 + virtual void FinishedSurfaceUpload(); 1.304 + 1.305 + virtual bool InUpdate() const { return !!mUpdateDrawTarget; } 1.306 + 1.307 + virtual void Resize(const gfx::IntSize& aSize); 1.308 + 1.309 +protected: 1.310 + GLuint mTexture; 1.311 + TextureState mTextureState; 1.312 + nsRefPtr<GLContext> mGLContext; 1.313 + RefPtr<gfx::DrawTarget> mUpdateDrawTarget; 1.314 + nsIntRegion mUpdateRegion; 1.315 + 1.316 + // The offset into the update surface at which the update rect is located. 1.317 + nsIntPoint mUpdateOffset; 1.318 +}; 1.319 + 1.320 +/** 1.321 + * A container class that complements many sub TextureImages into a big TextureImage. 1.322 + * Aims to behave just like the real thing. 1.323 + */ 1.324 + 1.325 +class TiledTextureImage 1.326 + : public TextureImage 1.327 +{ 1.328 +public: 1.329 + TiledTextureImage(GLContext* aGL, 1.330 + gfx::IntSize aSize, 1.331 + TextureImage::ContentType, 1.332 + TextureImage::Flags aFlags = TextureImage::NoFlags, 1.333 + TextureImage::ImageFormat aImageFormat = gfxImageFormat::Unknown); 1.334 + ~TiledTextureImage(); 1.335 + void DumpDiv(); 1.336 + virtual gfx::DrawTarget* BeginUpdate(nsIntRegion& aRegion); 1.337 + virtual void GetUpdateRegion(nsIntRegion& aForRegion); 1.338 + virtual void EndUpdate(); 1.339 + virtual void Resize(const gfx::IntSize& aSize); 1.340 + virtual uint32_t GetTileCount(); 1.341 + virtual void BeginTileIteration(); 1.342 + virtual bool NextTile(); 1.343 + virtual void SetIterationCallback(TileIterationCallback aCallback, 1.344 + void* aCallbackData); 1.345 + virtual gfx::IntRect GetTileRect(); 1.346 + virtual GLuint GetTextureID() { 1.347 + return mImages[mCurrentImage]->GetTextureID(); 1.348 + } 1.349 + virtual bool DirectUpdate(gfx::DataSourceSurface* aSurf, const nsIntRegion& aRegion, const gfx::IntPoint& aFrom = gfx::IntPoint(0,0)); 1.350 + virtual bool InUpdate() const { return mInUpdate; } 1.351 + virtual void BindTexture(GLenum); 1.352 + 1.353 +protected: 1.354 + virtual gfx::IntRect GetSrcTileRect(); 1.355 + 1.356 + unsigned int mCurrentImage; 1.357 + TileIterationCallback mIterationCallback; 1.358 + void* mIterationCallbackData; 1.359 + nsTArray< nsRefPtr<TextureImage> > mImages; 1.360 + bool mInUpdate; 1.361 + gfx::IntSize mSize; 1.362 + unsigned int mTileSize; 1.363 + unsigned int mRows, mColumns; 1.364 + GLContext* mGL; 1.365 + // A temporary draw target to faciliate cross-tile updates. 1.366 + RefPtr<gfx::DrawTarget> mUpdateDrawTarget; 1.367 + // The region of update requested 1.368 + nsIntRegion mUpdateRegion; 1.369 + TextureState mTextureState; 1.370 + TextureImage::ImageFormat mImageFormat; 1.371 +}; 1.372 + 1.373 +/** 1.374 + * Creates a TextureImage of the basic implementation, can be useful in cases 1.375 + * where we know we don't want to use platform-specific TextureImage. 1.376 + * In doubt, use GLContext::CreateTextureImage instead. 1.377 + */ 1.378 +already_AddRefed<TextureImage> 1.379 +CreateBasicTextureImage(GLContext* aGL, 1.380 + const gfx::IntSize& aSize, 1.381 + TextureImage::ContentType aContentType, 1.382 + GLenum aWrapMode, 1.383 + TextureImage::Flags aFlags, 1.384 + TextureImage::ImageFormat aImageFormat = gfxImageFormat::Unknown); 1.385 + 1.386 +/** 1.387 + * Return a valid, allocated TextureImage of |aSize| with 1.388 + * |aContentType|. If |aContentType| is COLOR, |aImageFormat| can be used 1.389 + * to hint at the preferred RGB format, however it is not necessarily 1.390 + * respected. The TextureImage's texture is configured to use 1.391 + * |aWrapMode| (usually GL_CLAMP_TO_EDGE or GL_REPEAT) and by 1.392 + * default, GL_LINEAR filtering. Specify 1.393 + * |aFlags=UseNearestFilter| for GL_NEAREST filtering. Specify 1.394 + * |aFlags=NeedsYFlip| if the image is flipped. Return 1.395 + * nullptr if creating the TextureImage fails. 1.396 + * 1.397 + * The returned TextureImage may only be used with this GLContext. 1.398 + * Attempting to use the returned TextureImage after this 1.399 + * GLContext is destroyed will result in undefined (and likely 1.400 + * crashy) behavior. 1.401 + */ 1.402 +already_AddRefed<TextureImage> 1.403 +CreateTextureImage(GLContext* gl, 1.404 + const gfx::IntSize& aSize, 1.405 + TextureImage::ContentType aContentType, 1.406 + GLenum aWrapMode, 1.407 + TextureImage::Flags aFlags = TextureImage::NoFlags, 1.408 + TextureImage::ImageFormat aImageFormat = gfxImageFormat::Unknown); 1.409 + 1.410 +} // namespace gl 1.411 +} // namespace mozilla 1.412 + 1.413 +#endif /* GLTEXTUREIMAGE_H_ */