|
1 /* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 #ifndef GLTEXTUREIMAGE_H_ |
|
7 #define GLTEXTUREIMAGE_H_ |
|
8 |
|
9 #include "nsAutoPtr.h" |
|
10 #include "nsRegion.h" |
|
11 #include "nsTArray.h" |
|
12 #include "gfxTypes.h" |
|
13 #include "GLContextTypes.h" |
|
14 #include "GraphicsFilter.h" |
|
15 #include "mozilla/gfx/Rect.h" |
|
16 #include "mozilla/RefPtr.h" |
|
17 |
|
18 class gfxASurface; |
|
19 |
|
20 namespace mozilla { |
|
21 namespace gfx { |
|
22 class DataSourceSurface; |
|
23 class DrawTarget; |
|
24 } |
|
25 } |
|
26 |
|
27 namespace mozilla { |
|
28 namespace gl { |
|
29 class GLContext; |
|
30 |
|
31 /** |
|
32 * A TextureImage encapsulates a surface that can be drawn to by a |
|
33 * Thebes gfxContext and (hopefully efficiently!) synchronized to a |
|
34 * texture in the server. TextureImages are associated with one and |
|
35 * only one GLContext. |
|
36 * |
|
37 * Implementation note: TextureImages attempt to unify two categories |
|
38 * of backends |
|
39 * |
|
40 * (1) proxy to server-side object that can be bound to a texture; |
|
41 * e.g. Pixmap on X11. |
|
42 * |
|
43 * (2) efficient manager of texture memory; e.g. by having clients draw |
|
44 * into a scratch buffer which is then uploaded with |
|
45 * glTexSubImage2D(). |
|
46 */ |
|
47 class TextureImage |
|
48 { |
|
49 NS_INLINE_DECL_REFCOUNTING(TextureImage) |
|
50 public: |
|
51 enum TextureState |
|
52 { |
|
53 Created, // Texture created, but has not had glTexImage called to initialize it. |
|
54 Allocated, // Texture memory exists, but contents are invalid. |
|
55 Valid // Texture fully ready to use. |
|
56 }; |
|
57 |
|
58 enum Flags { |
|
59 NoFlags = 0x0, |
|
60 UseNearestFilter = 0x1, |
|
61 NeedsYFlip = 0x2, |
|
62 DisallowBigImage = 0x4 |
|
63 }; |
|
64 |
|
65 typedef gfxContentType ContentType; |
|
66 typedef gfxImageFormat ImageFormat; |
|
67 |
|
68 static already_AddRefed<TextureImage> Create( |
|
69 GLContext* gl, |
|
70 const nsIntSize& aSize, |
|
71 TextureImage::ContentType aContentType, |
|
72 GLenum aWrapMode, |
|
73 TextureImage::Flags aFlags = TextureImage::NoFlags); |
|
74 // Moz2D equivalent... |
|
75 static already_AddRefed<TextureImage> Create( |
|
76 GLContext* gl, |
|
77 const gfx::IntSize& aSize, |
|
78 TextureImage::ContentType aContentType, |
|
79 GLenum aWrapMode, |
|
80 TextureImage::Flags aFlags = TextureImage::NoFlags); |
|
81 |
|
82 /** |
|
83 * Returns a gfxASurface for updating |aRegion| of the client's |
|
84 * image if successul, nullptr if not. |aRegion|'s bounds must fit |
|
85 * within Size(); its coordinate space (if any) is ignored. If |
|
86 * the update begins successfully, the returned gfxASurface is |
|
87 * owned by this. Otherwise, nullptr is returned. |
|
88 * |
|
89 * |aRegion| is an inout param: the returned region is what the |
|
90 * client must repaint. Category (1) regions above can |
|
91 * efficiently handle repaints to "scattered" regions, while (2) |
|
92 * can only efficiently handle repaints to rects. |
|
93 * |
|
94 * Painting the returned surface outside of |aRegion| results |
|
95 * in undefined behavior. |
|
96 * |
|
97 * BeginUpdate() calls cannot be "nested", and each successful |
|
98 * BeginUpdate() must be followed by exactly one EndUpdate() (see |
|
99 * below). Failure to do so can leave this in a possibly |
|
100 * inconsistent state. Unsuccessful BeginUpdate()s must not be |
|
101 * followed by EndUpdate(). |
|
102 */ |
|
103 virtual gfx::DrawTarget* BeginUpdate(nsIntRegion& aRegion) = 0; |
|
104 /** |
|
105 * Retrieves the region that will require updating, given a |
|
106 * region that needs to be updated. This can be used for |
|
107 * making decisions about updating before calling BeginUpdate(). |
|
108 * |
|
109 * |aRegion| is an inout param. |
|
110 */ |
|
111 virtual void GetUpdateRegion(nsIntRegion& aForRegion) { |
|
112 } |
|
113 /** |
|
114 * Finish the active update and synchronize with the server, if |
|
115 * necessary. |
|
116 * |
|
117 * BeginUpdate() must have been called exactly once before |
|
118 * EndUpdate(). |
|
119 */ |
|
120 virtual void EndUpdate() = 0; |
|
121 |
|
122 /** |
|
123 * The Image may contain several textures for different regions (tiles). |
|
124 * These functions iterate over each sub texture image tile. |
|
125 */ |
|
126 virtual void BeginTileIteration() { |
|
127 } |
|
128 |
|
129 virtual bool NextTile() { |
|
130 return false; |
|
131 } |
|
132 |
|
133 // Function prototype for a tile iteration callback. Returning false will |
|
134 // cause iteration to be interrupted (i.e. the corresponding NextTile call |
|
135 // will return false). |
|
136 typedef bool (* TileIterationCallback)(TextureImage* aImage, |
|
137 int aTileNumber, |
|
138 void* aCallbackData); |
|
139 |
|
140 // Sets a callback to be called every time NextTile is called. |
|
141 virtual void SetIterationCallback(TileIterationCallback aCallback, |
|
142 void* aCallbackData) { |
|
143 } |
|
144 |
|
145 virtual gfx::IntRect GetTileRect(); |
|
146 |
|
147 virtual GLuint GetTextureID() = 0; |
|
148 |
|
149 virtual uint32_t GetTileCount() { |
|
150 return 1; |
|
151 } |
|
152 |
|
153 /** |
|
154 * Set this TextureImage's size, and ensure a texture has been |
|
155 * allocated. Must not be called between BeginUpdate and EndUpdate. |
|
156 * After a resize, the contents are undefined. |
|
157 * |
|
158 * If this isn't implemented by a subclass, it will just perform |
|
159 * a dummy BeginUpdate/EndUpdate pair. |
|
160 */ |
|
161 virtual void Resize(const gfx::IntSize& aSize) { |
|
162 mSize = aSize; |
|
163 nsIntRegion r(nsIntRect(0, 0, aSize.width, aSize.height)); |
|
164 BeginUpdate(r); |
|
165 EndUpdate(); |
|
166 } |
|
167 |
|
168 /** |
|
169 * Mark this texture as having valid contents. Call this after modifying |
|
170 * the texture contents externally. |
|
171 */ |
|
172 virtual void MarkValid() {} |
|
173 |
|
174 /** |
|
175 * aSurf - the source surface to update from |
|
176 * aRegion - the region in this image to update |
|
177 * aFrom - offset in the source to update from |
|
178 */ |
|
179 virtual bool DirectUpdate(gfx::DataSourceSurface* aSurf, const nsIntRegion& aRegion, const gfx::IntPoint& aFrom = gfx::IntPoint(0,0)) = 0; |
|
180 bool UpdateFromDataSource(gfx::DataSourceSurface *aSurf, |
|
181 const nsIntRegion* aDstRegion = nullptr, |
|
182 const gfx::IntPoint* aSrcOffset = nullptr); |
|
183 |
|
184 virtual void BindTexture(GLenum aTextureUnit) = 0; |
|
185 |
|
186 /** |
|
187 * Returns the image format of the texture. Only valid after a matching |
|
188 * BeginUpdate/EndUpdate pair have been called. |
|
189 */ |
|
190 virtual gfx::SurfaceFormat GetTextureFormat() { |
|
191 return mTextureFormat; |
|
192 } |
|
193 |
|
194 /** Can be called safely at any time. */ |
|
195 |
|
196 /** |
|
197 * If this TextureImage has a permanent gfxASurface backing, |
|
198 * return it. Otherwise return nullptr. |
|
199 */ |
|
200 virtual already_AddRefed<gfxASurface> GetBackingSurface() |
|
201 { return nullptr; } |
|
202 |
|
203 |
|
204 gfx::IntSize GetSize() const; |
|
205 ContentType GetContentType() const { return mContentType; } |
|
206 ImageFormat GetImageFormat() const { return mImageFormat; } |
|
207 virtual bool InUpdate() const = 0; |
|
208 GLenum GetWrapMode() const { return mWrapMode; } |
|
209 |
|
210 void SetFilter(GraphicsFilter aFilter) { mFilter = aFilter; } |
|
211 |
|
212 protected: |
|
213 friend class GLContext; |
|
214 |
|
215 /** |
|
216 * After the ctor, the TextureImage is invalid. Implementations |
|
217 * must allocate resources successfully before returning the new |
|
218 * TextureImage from GLContext::CreateTextureImage(). That is, |
|
219 * clients must not be given partially-constructed TextureImages. |
|
220 */ |
|
221 TextureImage(const nsIntSize& aSize, |
|
222 GLenum aWrapMode, ContentType aContentType, |
|
223 Flags aFlags = NoFlags, |
|
224 ImageFormat aImageFormat = gfxImageFormat::Unknown) |
|
225 : mSize(aSize.ToIntSize()) |
|
226 , mWrapMode(aWrapMode) |
|
227 , mContentType(aContentType) |
|
228 , mImageFormat(aImageFormat) |
|
229 , mFilter(GraphicsFilter::FILTER_GOOD) |
|
230 , mFlags(aFlags) |
|
231 {} |
|
232 |
|
233 // Moz2D equivalent... |
|
234 TextureImage(const gfx::IntSize& aSize, |
|
235 GLenum aWrapMode, ContentType aContentType, |
|
236 Flags aFlags = NoFlags); |
|
237 |
|
238 // Protected destructor, to discourage deletion outside of Release(): |
|
239 virtual ~TextureImage() {} |
|
240 |
|
241 virtual gfx::IntRect GetSrcTileRect(); |
|
242 |
|
243 gfx::IntSize mSize; |
|
244 GLenum mWrapMode; |
|
245 ContentType mContentType; |
|
246 ImageFormat mImageFormat; |
|
247 gfx::SurfaceFormat mTextureFormat; |
|
248 GraphicsFilter mFilter; |
|
249 Flags mFlags; |
|
250 }; |
|
251 |
|
252 /** |
|
253 * BasicTextureImage is the baseline TextureImage implementation --- |
|
254 * it updates its texture by allocating a scratch buffer for the |
|
255 * client to draw into, then using glTexSubImage2D() to upload the new |
|
256 * pixels. Platforms must provide the code to create a new surface |
|
257 * into which the updated pixels will be drawn, and the code to |
|
258 * convert the update surface's pixels into an image on which we can |
|
259 * glTexSubImage2D(). |
|
260 */ |
|
261 class BasicTextureImage |
|
262 : public TextureImage |
|
263 { |
|
264 public: |
|
265 virtual ~BasicTextureImage(); |
|
266 |
|
267 BasicTextureImage(GLuint aTexture, |
|
268 const nsIntSize& aSize, |
|
269 GLenum aWrapMode, |
|
270 ContentType aContentType, |
|
271 GLContext* aContext, |
|
272 TextureImage::Flags aFlags = TextureImage::NoFlags, |
|
273 TextureImage::ImageFormat aImageFormat = gfxImageFormat::Unknown); |
|
274 BasicTextureImage(GLuint aTexture, |
|
275 const gfx::IntSize& aSize, |
|
276 GLenum aWrapMode, |
|
277 ContentType aContentType, |
|
278 GLContext* aContext, |
|
279 TextureImage::Flags aFlags = TextureImage::NoFlags, |
|
280 TextureImage::ImageFormat aImageFormat = gfxImageFormat::Unknown); |
|
281 |
|
282 virtual void BindTexture(GLenum aTextureUnit); |
|
283 |
|
284 virtual gfx::DrawTarget* BeginUpdate(nsIntRegion& aRegion); |
|
285 virtual void GetUpdateRegion(nsIntRegion& aForRegion); |
|
286 virtual void EndUpdate(); |
|
287 virtual bool DirectUpdate(gfx::DataSourceSurface* aSurf, const nsIntRegion& aRegion, const gfx::IntPoint& aFrom = gfx::IntPoint(0,0)); |
|
288 virtual GLuint GetTextureID() { return mTexture; } |
|
289 virtual TemporaryRef<gfx::DrawTarget> |
|
290 GetDrawTargetForUpdate(const gfx::IntSize& aSize, gfx::SurfaceFormat aFmt); |
|
291 |
|
292 virtual void MarkValid() { mTextureState = Valid; } |
|
293 |
|
294 // Call when drawing into the update surface is complete. |
|
295 // Returns true if textures should be upload with a relative |
|
296 // offset - See UploadSurfaceToTexture. |
|
297 virtual bool FinishedSurfaceUpdate(); |
|
298 |
|
299 // Call after surface data has been uploaded to a texture. |
|
300 virtual void FinishedSurfaceUpload(); |
|
301 |
|
302 virtual bool InUpdate() const { return !!mUpdateDrawTarget; } |
|
303 |
|
304 virtual void Resize(const gfx::IntSize& aSize); |
|
305 |
|
306 protected: |
|
307 GLuint mTexture; |
|
308 TextureState mTextureState; |
|
309 nsRefPtr<GLContext> mGLContext; |
|
310 RefPtr<gfx::DrawTarget> mUpdateDrawTarget; |
|
311 nsIntRegion mUpdateRegion; |
|
312 |
|
313 // The offset into the update surface at which the update rect is located. |
|
314 nsIntPoint mUpdateOffset; |
|
315 }; |
|
316 |
|
317 /** |
|
318 * A container class that complements many sub TextureImages into a big TextureImage. |
|
319 * Aims to behave just like the real thing. |
|
320 */ |
|
321 |
|
322 class TiledTextureImage |
|
323 : public TextureImage |
|
324 { |
|
325 public: |
|
326 TiledTextureImage(GLContext* aGL, |
|
327 gfx::IntSize aSize, |
|
328 TextureImage::ContentType, |
|
329 TextureImage::Flags aFlags = TextureImage::NoFlags, |
|
330 TextureImage::ImageFormat aImageFormat = gfxImageFormat::Unknown); |
|
331 ~TiledTextureImage(); |
|
332 void DumpDiv(); |
|
333 virtual gfx::DrawTarget* BeginUpdate(nsIntRegion& aRegion); |
|
334 virtual void GetUpdateRegion(nsIntRegion& aForRegion); |
|
335 virtual void EndUpdate(); |
|
336 virtual void Resize(const gfx::IntSize& aSize); |
|
337 virtual uint32_t GetTileCount(); |
|
338 virtual void BeginTileIteration(); |
|
339 virtual bool NextTile(); |
|
340 virtual void SetIterationCallback(TileIterationCallback aCallback, |
|
341 void* aCallbackData); |
|
342 virtual gfx::IntRect GetTileRect(); |
|
343 virtual GLuint GetTextureID() { |
|
344 return mImages[mCurrentImage]->GetTextureID(); |
|
345 } |
|
346 virtual bool DirectUpdate(gfx::DataSourceSurface* aSurf, const nsIntRegion& aRegion, const gfx::IntPoint& aFrom = gfx::IntPoint(0,0)); |
|
347 virtual bool InUpdate() const { return mInUpdate; } |
|
348 virtual void BindTexture(GLenum); |
|
349 |
|
350 protected: |
|
351 virtual gfx::IntRect GetSrcTileRect(); |
|
352 |
|
353 unsigned int mCurrentImage; |
|
354 TileIterationCallback mIterationCallback; |
|
355 void* mIterationCallbackData; |
|
356 nsTArray< nsRefPtr<TextureImage> > mImages; |
|
357 bool mInUpdate; |
|
358 gfx::IntSize mSize; |
|
359 unsigned int mTileSize; |
|
360 unsigned int mRows, mColumns; |
|
361 GLContext* mGL; |
|
362 // A temporary draw target to faciliate cross-tile updates. |
|
363 RefPtr<gfx::DrawTarget> mUpdateDrawTarget; |
|
364 // The region of update requested |
|
365 nsIntRegion mUpdateRegion; |
|
366 TextureState mTextureState; |
|
367 TextureImage::ImageFormat mImageFormat; |
|
368 }; |
|
369 |
|
370 /** |
|
371 * Creates a TextureImage of the basic implementation, can be useful in cases |
|
372 * where we know we don't want to use platform-specific TextureImage. |
|
373 * In doubt, use GLContext::CreateTextureImage instead. |
|
374 */ |
|
375 already_AddRefed<TextureImage> |
|
376 CreateBasicTextureImage(GLContext* aGL, |
|
377 const gfx::IntSize& aSize, |
|
378 TextureImage::ContentType aContentType, |
|
379 GLenum aWrapMode, |
|
380 TextureImage::Flags aFlags, |
|
381 TextureImage::ImageFormat aImageFormat = gfxImageFormat::Unknown); |
|
382 |
|
383 /** |
|
384 * Return a valid, allocated TextureImage of |aSize| with |
|
385 * |aContentType|. If |aContentType| is COLOR, |aImageFormat| can be used |
|
386 * to hint at the preferred RGB format, however it is not necessarily |
|
387 * respected. The TextureImage's texture is configured to use |
|
388 * |aWrapMode| (usually GL_CLAMP_TO_EDGE or GL_REPEAT) and by |
|
389 * default, GL_LINEAR filtering. Specify |
|
390 * |aFlags=UseNearestFilter| for GL_NEAREST filtering. Specify |
|
391 * |aFlags=NeedsYFlip| if the image is flipped. Return |
|
392 * nullptr if creating the TextureImage fails. |
|
393 * |
|
394 * The returned TextureImage may only be used with this GLContext. |
|
395 * Attempting to use the returned TextureImage after this |
|
396 * GLContext is destroyed will result in undefined (and likely |
|
397 * crashy) behavior. |
|
398 */ |
|
399 already_AddRefed<TextureImage> |
|
400 CreateTextureImage(GLContext* gl, |
|
401 const gfx::IntSize& aSize, |
|
402 TextureImage::ContentType aContentType, |
|
403 GLenum aWrapMode, |
|
404 TextureImage::Flags aFlags = TextureImage::NoFlags, |
|
405 TextureImage::ImageFormat aImageFormat = gfxImageFormat::Unknown); |
|
406 |
|
407 } // namespace gl |
|
408 } // namespace mozilla |
|
409 |
|
410 #endif /* GLTEXTUREIMAGE_H_ */ |