gfx/gl/GLTextureImage.cpp

branch
TOR_BUG_3246
changeset 7
129ffea94266
equal deleted inserted replaced
-1:000000000000 0:7fa140cdfdb9
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 #include "GLTextureImage.h"
7 #include "GLContext.h"
8 #include "gfxContext.h"
9 #include "gfxPlatform.h"
10 #include "gfxUtils.h"
11 #include "gfx2DGlue.h"
12 #include "ScopedGLHelpers.h"
13 #include "GLUploadHelpers.h"
14
15 #include "TextureImageEGL.h"
16 #ifdef XP_MACOSX
17 #include "TextureImageCGL.h"
18 #endif
19
20 namespace mozilla {
21 namespace gl {
22
23 already_AddRefed<TextureImage>
24 CreateTextureImage(GLContext* gl,
25 const gfx::IntSize& aSize,
26 TextureImage::ContentType aContentType,
27 GLenum aWrapMode,
28 TextureImage::Flags aFlags,
29 TextureImage::ImageFormat aImageFormat)
30 {
31 switch (gl->GetContextType()) {
32 #ifdef XP_MACOSX
33 case GLContextType::CGL:
34 return CreateTextureImageCGL(gl, aSize, aContentType, aWrapMode, aFlags, aImageFormat);
35 #endif
36 case GLContextType::EGL:
37 return CreateTextureImageEGL(gl, aSize, aContentType, aWrapMode, aFlags, aImageFormat);
38 default:
39 return CreateBasicTextureImage(gl, aSize, aContentType, aWrapMode, aFlags, aImageFormat);
40 }
41 }
42
43
44 static already_AddRefed<TextureImage>
45 TileGenFunc(GLContext* gl,
46 const nsIntSize& aSize,
47 TextureImage::ContentType aContentType,
48 TextureImage::Flags aFlags,
49 TextureImage::ImageFormat aImageFormat)
50 {
51 switch (gl->GetContextType()) {
52 #ifdef XP_MACOSX
53 case GLContextType::CGL:
54 return TileGenFuncCGL(gl, aSize, aContentType, aFlags, aImageFormat);
55 #endif
56 case GLContextType::EGL:
57 return TileGenFuncEGL(gl, aSize, aContentType, aFlags, aImageFormat);
58 default:
59 return nullptr;
60 }
61 }
62
63 already_AddRefed<TextureImage>
64 TextureImage::Create(GLContext* gl,
65 const nsIntSize& size,
66 TextureImage::ContentType contentType,
67 GLenum wrapMode,
68 TextureImage::Flags flags)
69 {
70 return Create(gl, size.ToIntSize(), contentType, wrapMode, flags);
71 }
72
73 // Moz2D equivalent...
74 already_AddRefed<TextureImage>
75 TextureImage::Create(GLContext* gl,
76 const gfx::IntSize& size,
77 TextureImage::ContentType contentType,
78 GLenum wrapMode,
79 TextureImage::Flags flags)
80 {
81 return CreateTextureImage(gl, size, contentType, wrapMode, flags);
82 }
83
84 bool
85 TextureImage::UpdateFromDataSource(gfx::DataSourceSurface *aSurface,
86 const nsIntRegion* aDestRegion,
87 const gfx::IntPoint* aSrcPoint)
88 {
89 nsIntRegion destRegion = aDestRegion ? *aDestRegion
90 : nsIntRect(0, 0,
91 aSurface->GetSize().width,
92 aSurface->GetSize().height);
93 gfx::IntPoint srcPoint = aSrcPoint ? *aSrcPoint
94 : gfx::IntPoint(0, 0);
95 return DirectUpdate(aSurface, destRegion, srcPoint);
96 }
97
98 gfx::IntRect TextureImage::GetTileRect() {
99 return gfx::IntRect(gfx::IntPoint(0,0), mSize);
100 }
101
102 gfx::IntRect TextureImage::GetSrcTileRect() {
103 return GetTileRect();
104 }
105
106 BasicTextureImage::~BasicTextureImage()
107 {
108 GLContext *ctx = mGLContext;
109 if (ctx->IsDestroyed() || !ctx->IsOwningThreadCurrent()) {
110 ctx = ctx->GetSharedContext();
111 }
112
113 // If we have a context, then we need to delete the texture;
114 // if we don't have a context (either real or shared),
115 // then they went away when the contex was deleted, because it
116 // was the only one that had access to it.
117 if (ctx && ctx->MakeCurrent()) {
118 ctx->fDeleteTextures(1, &mTexture);
119 }
120 }
121
122 gfx::DrawTarget*
123 BasicTextureImage::BeginUpdate(nsIntRegion& aRegion)
124 {
125 NS_ASSERTION(!mUpdateDrawTarget, "BeginUpdate() without EndUpdate()?");
126
127 // determine the region the client will need to repaint
128 if (CanUploadSubTextures(mGLContext)) {
129 GetUpdateRegion(aRegion);
130 } else {
131 aRegion = nsIntRect(nsIntPoint(0, 0), gfx::ThebesIntSize(mSize));
132 }
133
134 mUpdateRegion = aRegion;
135
136 nsIntRect rgnSize = mUpdateRegion.GetBounds();
137 if (!nsIntRect(nsIntPoint(0, 0), gfx::ThebesIntSize(mSize)).Contains(rgnSize)) {
138 NS_ERROR("update outside of image");
139 return nullptr;
140 }
141
142 gfx::SurfaceFormat format =
143 (GetContentType() == gfxContentType::COLOR) ?
144 gfx::SurfaceFormat::B8G8R8X8 : gfx::SurfaceFormat::B8G8R8A8;
145 mUpdateDrawTarget =
146 GetDrawTargetForUpdate(gfx::IntSize(rgnSize.width, rgnSize.height), format);
147
148 return mUpdateDrawTarget;
149 }
150
151 void
152 BasicTextureImage::GetUpdateRegion(nsIntRegion& aForRegion)
153 {
154 // if the texture hasn't been initialized yet, or something important
155 // changed, we need to recreate our backing surface and force the
156 // client to paint everything
157 if (mTextureState != Valid)
158 aForRegion = nsIntRect(nsIntPoint(0, 0), gfx::ThebesIntSize(mSize));
159 }
160
161 void
162 BasicTextureImage::EndUpdate()
163 {
164 NS_ASSERTION(!!mUpdateDrawTarget, "EndUpdate() without BeginUpdate()?");
165
166 // FIXME: this is the slow boat. Make me fast (with GLXPixmap?).
167
168 RefPtr<gfx::SourceSurface> updateSnapshot = mUpdateDrawTarget->Snapshot();
169 RefPtr<gfx::DataSourceSurface> updateData = updateSnapshot->GetDataSurface();
170
171 bool relative = FinishedSurfaceUpdate();
172
173 mTextureFormat =
174 UploadSurfaceToTexture(mGLContext,
175 updateData,
176 mUpdateRegion,
177 mTexture,
178 mTextureState == Created,
179 mUpdateOffset,
180 relative);
181 FinishedSurfaceUpload();
182
183 mUpdateDrawTarget = nullptr;
184 mTextureState = Valid;
185 }
186
187 void
188 BasicTextureImage::BindTexture(GLenum aTextureUnit)
189 {
190 mGLContext->fActiveTexture(aTextureUnit);
191 mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
192 mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0);
193 }
194
195 TemporaryRef<gfx::DrawTarget>
196 BasicTextureImage::GetDrawTargetForUpdate(const gfx::IntSize& aSize, gfx::SurfaceFormat aFmt)
197 {
198 return gfx::Factory::CreateDrawTarget(gfx::BackendType::CAIRO, aSize, aFmt);
199 }
200
201 bool
202 BasicTextureImage::FinishedSurfaceUpdate()
203 {
204 return false;
205 }
206
207 void
208 BasicTextureImage::FinishedSurfaceUpload()
209 {
210 }
211
212 bool
213 BasicTextureImage::DirectUpdate(gfx::DataSourceSurface* aSurf, const nsIntRegion& aRegion, const gfx::IntPoint& aFrom /* = gfx::IntPoint(0, 0) */)
214 {
215 nsIntRect bounds = aRegion.GetBounds();
216 nsIntRegion region;
217 if (mTextureState != Valid) {
218 bounds = nsIntRect(0, 0, mSize.width, mSize.height);
219 region = nsIntRegion(bounds);
220 } else {
221 region = aRegion;
222 }
223
224 mTextureFormat =
225 UploadSurfaceToTexture(mGLContext,
226 aSurf,
227 region,
228 mTexture,
229 mTextureState == Created,
230 bounds.TopLeft() + nsIntPoint(aFrom.x, aFrom.y),
231 false);
232 mTextureState = Valid;
233 return true;
234 }
235
236 void
237 BasicTextureImage::Resize(const gfx::IntSize& aSize)
238 {
239 NS_ASSERTION(!mUpdateDrawTarget, "Resize() while in update?");
240
241 mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
242
243 mGLContext->fTexImage2D(LOCAL_GL_TEXTURE_2D,
244 0,
245 LOCAL_GL_RGBA,
246 aSize.width,
247 aSize.height,
248 0,
249 LOCAL_GL_RGBA,
250 LOCAL_GL_UNSIGNED_BYTE,
251 nullptr);
252
253 mTextureState = Allocated;
254 mSize = aSize;
255 }
256
257 gfx::IntSize TextureImage::GetSize() const {
258 return mSize;
259 }
260
261 TextureImage::TextureImage(const gfx::IntSize& aSize,
262 GLenum aWrapMode, ContentType aContentType,
263 Flags aFlags)
264 : mSize(aSize)
265 , mWrapMode(aWrapMode)
266 , mContentType(aContentType)
267 , mFilter(GraphicsFilter::FILTER_GOOD)
268 , mFlags(aFlags)
269 {}
270
271 BasicTextureImage::BasicTextureImage(GLuint aTexture,
272 const nsIntSize& aSize,
273 GLenum aWrapMode,
274 ContentType aContentType,
275 GLContext* aContext,
276 TextureImage::Flags aFlags /* = TextureImage::NoFlags */,
277 TextureImage::ImageFormat aImageFormat /* = gfxImageFormat::Unknown */)
278 : TextureImage(aSize, aWrapMode, aContentType, aFlags, aImageFormat)
279 , mTexture(aTexture)
280 , mTextureState(Created)
281 , mGLContext(aContext)
282 , mUpdateOffset(0, 0)
283 {
284 }
285
286 BasicTextureImage::BasicTextureImage(GLuint aTexture,
287 const gfx::IntSize& aSize,
288 GLenum aWrapMode,
289 ContentType aContentType,
290 GLContext* aContext,
291 TextureImage::Flags aFlags,
292 TextureImage::ImageFormat aImageFormat)
293 : TextureImage(ThebesIntSize(aSize), aWrapMode, aContentType, aFlags, aImageFormat)
294 , mTexture(aTexture)
295 , mTextureState(Created)
296 , mGLContext(aContext)
297 , mUpdateOffset(0, 0)
298 {}
299
300 static bool
301 WantsSmallTiles(GLContext* gl)
302 {
303 // We must use small tiles for good performance if we can't use
304 // glTexSubImage2D() for some reason.
305 if (!CanUploadSubTextures(gl))
306 return true;
307
308 // We can't use small tiles on the SGX 540, because of races in texture upload.
309 if (gl->WorkAroundDriverBugs() &&
310 gl->Renderer() == GLRenderer::SGX540)
311 return false;
312
313 // Don't use small tiles otherwise. (If we implement incremental texture upload,
314 // then we will want to revisit this.)
315 return false;
316 }
317
318 TiledTextureImage::TiledTextureImage(GLContext* aGL,
319 gfx::IntSize aSize,
320 TextureImage::ContentType aContentType,
321 TextureImage::Flags aFlags,
322 TextureImage::ImageFormat aImageFormat)
323 : TextureImage(aSize, LOCAL_GL_CLAMP_TO_EDGE, aContentType, aFlags)
324 , mCurrentImage(0)
325 , mIterationCallback(nullptr)
326 , mInUpdate(false)
327 , mRows(0)
328 , mColumns(0)
329 , mGL(aGL)
330 , mTextureState(Created)
331 , mImageFormat(aImageFormat)
332 {
333 if (!(aFlags & TextureImage::DisallowBigImage) && WantsSmallTiles(mGL)) {
334 mTileSize = 256;
335 } else {
336 mGL->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, (GLint*) &mTileSize);
337 }
338 if (aSize.width != 0 && aSize.height != 0) {
339 Resize(aSize);
340 }
341 }
342
343 TiledTextureImage::~TiledTextureImage()
344 {
345 }
346
347 bool
348 TiledTextureImage::DirectUpdate(gfx::DataSourceSurface* aSurf, const nsIntRegion& aRegion, const gfx::IntPoint& aFrom /* = gfx::IntPoint(0, 0) */)
349 {
350 if (mSize.width == 0 || mSize.height == 0) {
351 return true;
352 }
353
354 nsIntRegion region;
355
356 if (mTextureState != Valid) {
357 nsIntRect bounds = nsIntRect(0, 0, mSize.width, mSize.height);
358 region = nsIntRegion(bounds);
359 } else {
360 region = aRegion;
361 }
362
363 bool result = true;
364 int oldCurrentImage = mCurrentImage;
365 BeginTileIteration();
366 do {
367 nsIntRect tileRect = ThebesIntRect(GetSrcTileRect());
368 int xPos = tileRect.x;
369 int yPos = tileRect.y;
370
371 nsIntRegion tileRegion;
372 tileRegion.And(region, tileRect); // intersect with tile
373
374 if (tileRegion.IsEmpty())
375 continue;
376
377 if (CanUploadSubTextures(mGL)) {
378 tileRegion.MoveBy(-xPos, -yPos); // translate into tile local space
379 } else {
380 // If sub-textures are unsupported, expand to tile boundaries
381 tileRect.x = tileRect.y = 0;
382 tileRegion = nsIntRegion(tileRect);
383 }
384
385 result &= mImages[mCurrentImage]->
386 DirectUpdate(aSurf, tileRegion, aFrom + gfx::IntPoint(xPos, yPos));
387
388 if (mCurrentImage == mImages.Length() - 1) {
389 // We know we're done, but we still need to ensure that the callback
390 // gets called (e.g. to update the uploaded region).
391 NextTile();
392 break;
393 }
394 // Override a callback cancelling iteration if the texture wasn't valid.
395 // We need to force the update in that situation, or we may end up
396 // showing invalid/out-of-date texture data.
397 } while (NextTile() || (mTextureState != Valid));
398 mCurrentImage = oldCurrentImage;
399
400 mTextureFormat = mImages[0]->GetTextureFormat();
401 mTextureState = Valid;
402 return result;
403 }
404
405 void
406 TiledTextureImage::GetUpdateRegion(nsIntRegion& aForRegion)
407 {
408 if (mTextureState != Valid) {
409 // if the texture hasn't been initialized yet, or something important
410 // changed, we need to recreate our backing surface and force the
411 // client to paint everything
412 aForRegion = nsIntRect(nsIntPoint(0, 0), gfx::ThebesIntSize(mSize));
413 return;
414 }
415
416 nsIntRegion newRegion;
417
418 // We need to query each texture with the region it will be drawing and
419 // set aForRegion to be the combination of all of these regions
420 for (unsigned i = 0; i < mImages.Length(); i++) {
421 int xPos = (i % mColumns) * mTileSize;
422 int yPos = (i / mColumns) * mTileSize;
423 nsIntRect imageRect = nsIntRect(nsIntPoint(xPos,yPos),
424 ThebesIntSize(mImages[i]->GetSize()));
425
426 if (aForRegion.Intersects(imageRect)) {
427 // Make a copy of the region
428 nsIntRegion subRegion;
429 subRegion.And(aForRegion, imageRect);
430 // Translate it into tile-space
431 subRegion.MoveBy(-xPos, -yPos);
432 // Query region
433 mImages[i]->GetUpdateRegion(subRegion);
434 // Translate back
435 subRegion.MoveBy(xPos, yPos);
436 // Add to the accumulated region
437 newRegion.Or(newRegion, subRegion);
438 }
439 }
440
441 aForRegion = newRegion;
442 }
443
444 gfx::DrawTarget*
445 TiledTextureImage::BeginUpdate(nsIntRegion& aRegion)
446 {
447 NS_ASSERTION(!mInUpdate, "nested update");
448 mInUpdate = true;
449
450 // Note, we don't call GetUpdateRegion here as if the updated region is
451 // fully contained in a single tile, we get to avoid iterating through
452 // the tiles again (and a little copying).
453 if (mTextureState != Valid)
454 {
455 // if the texture hasn't been initialized yet, or something important
456 // changed, we need to recreate our backing surface and force the
457 // client to paint everything
458 aRegion = nsIntRect(nsIntPoint(0, 0), gfx::ThebesIntSize(mSize));
459 }
460
461 nsIntRect bounds = aRegion.GetBounds();
462
463 for (unsigned i = 0; i < mImages.Length(); i++) {
464 int xPos = (i % mColumns) * mTileSize;
465 int yPos = (i / mColumns) * mTileSize;
466 nsIntRegion imageRegion =
467 nsIntRegion(nsIntRect(nsIntPoint(xPos,yPos),
468 ThebesIntSize(mImages[i]->GetSize())));
469
470 // a single Image can handle this update request
471 if (imageRegion.Contains(aRegion)) {
472 // adjust for tile offset
473 aRegion.MoveBy(-xPos, -yPos);
474 // forward the actual call
475 RefPtr<gfx::DrawTarget> drawTarget = mImages[i]->BeginUpdate(aRegion);
476 // caller expects container space
477 aRegion.MoveBy(xPos, yPos);
478 // we don't have a temp surface
479 mUpdateDrawTarget = nullptr;
480 // remember which image to EndUpdate
481 mCurrentImage = i;
482 return drawTarget.get();
483 }
484 }
485
486 // Get the real updated region, taking into account the capabilities of
487 // each TextureImage tile
488 GetUpdateRegion(aRegion);
489 mUpdateRegion = aRegion;
490 bounds = aRegion.GetBounds();
491
492 // update covers multiple Images - create a temp surface to paint in
493 gfx::SurfaceFormat format =
494 (GetContentType() == gfxContentType::COLOR) ?
495 gfx::SurfaceFormat::B8G8R8X8: gfx::SurfaceFormat::B8G8R8A8;
496 mUpdateDrawTarget = gfx::Factory::CreateDrawTarget(gfx::BackendType::CAIRO,
497 bounds.Size().ToIntSize(),
498 format);
499
500 return mUpdateDrawTarget;;
501 }
502
503 void
504 TiledTextureImage::EndUpdate()
505 {
506 NS_ASSERTION(mInUpdate, "EndUpdate not in update");
507 if (!mUpdateDrawTarget) { // update was to a single TextureImage
508 mImages[mCurrentImage]->EndUpdate();
509 mInUpdate = false;
510 mTextureState = Valid;
511 mTextureFormat = mImages[mCurrentImage]->GetTextureFormat();
512 return;
513 }
514
515 RefPtr<gfx::SourceSurface> updateSnapshot = mUpdateDrawTarget->Snapshot();
516 RefPtr<gfx::DataSourceSurface> updateData = updateSnapshot->GetDataSurface();
517 nsRefPtr<gfxASurface> updateSurface = new gfxImageSurface(updateData->GetData(),
518 gfx::ThebesIntSize(updateData->GetSize()),
519 updateData->Stride(),
520 gfx::SurfaceFormatToImageFormat(updateData->GetFormat()));
521
522 // upload tiles from temp surface
523 for (unsigned i = 0; i < mImages.Length(); i++) {
524 int xPos = (i % mColumns) * mTileSize;
525 int yPos = (i / mColumns) * mTileSize;
526 nsIntRect imageRect = nsIntRect(nsIntPoint(xPos,yPos),
527 ThebesIntSize(mImages[i]->GetSize()));
528
529 nsIntRegion subregion;
530 subregion.And(mUpdateRegion, imageRect);
531 if (subregion.IsEmpty())
532 continue;
533 subregion.MoveBy(-xPos, -yPos); // Tile-local space
534 // copy tile from temp target
535 gfx::DrawTarget* drawTarget = mImages[i]->BeginUpdate(subregion);
536 nsRefPtr<gfxContext> ctx = new gfxContext(drawTarget);
537 gfxUtils::ClipToRegion(ctx, subregion);
538 ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
539 ctx->SetSource(updateSurface, gfxPoint(-xPos, -yPos));
540 ctx->Paint();
541 mImages[i]->EndUpdate();
542 }
543
544 mUpdateDrawTarget = nullptr;
545 mInUpdate = false;
546 mTextureFormat = mImages[0]->GetTextureFormat();
547 mTextureState = Valid;
548 }
549
550 void TiledTextureImage::BeginTileIteration()
551 {
552 mCurrentImage = 0;
553 }
554
555 bool TiledTextureImage::NextTile()
556 {
557 bool continueIteration = true;
558
559 if (mIterationCallback)
560 continueIteration = mIterationCallback(this, mCurrentImage,
561 mIterationCallbackData);
562
563 if (mCurrentImage + 1 < mImages.Length()) {
564 mCurrentImage++;
565 return continueIteration;
566 }
567 return false;
568 }
569
570 void TiledTextureImage::SetIterationCallback(TileIterationCallback aCallback,
571 void* aCallbackData)
572 {
573 mIterationCallback = aCallback;
574 mIterationCallbackData = aCallbackData;
575 }
576
577 gfx::IntRect TiledTextureImage::GetTileRect()
578 {
579 if (!GetTileCount()) {
580 return gfx::IntRect();
581 }
582 gfx::IntRect rect = mImages[mCurrentImage]->GetTileRect();
583 unsigned int xPos = (mCurrentImage % mColumns) * mTileSize;
584 unsigned int yPos = (mCurrentImage / mColumns) * mTileSize;
585 rect.MoveBy(xPos, yPos);
586 return rect;
587 }
588
589 gfx::IntRect TiledTextureImage::GetSrcTileRect()
590 {
591 gfx::IntRect rect = GetTileRect();
592 unsigned int srcY = mFlags & NeedsYFlip
593 ? mSize.height - rect.height - rect.y
594 : rect.y;
595 return gfx::IntRect(rect.x, srcY, rect.width, rect.height);
596 }
597
598 void
599 TiledTextureImage::BindTexture(GLenum aTextureUnit)
600 {
601 if (!GetTileCount()) {
602 return;
603 }
604 mImages[mCurrentImage]->BindTexture(aTextureUnit);
605 }
606
607 /*
608 * Resize, trying to reuse tiles. The reuse strategy is to decide on reuse per
609 * column. A tile on a column is reused if it hasn't changed size, otherwise it
610 * is discarded/replaced. Extra tiles on a column are pruned after iterating
611 * each column, and extra rows are pruned after iteration over the entire image
612 * finishes.
613 */
614 void TiledTextureImage::Resize(const gfx::IntSize& aSize)
615 {
616 if (mSize == aSize && mTextureState != Created) {
617 return;
618 }
619
620 // calculate rows and columns, rounding up
621 unsigned int columns = (aSize.width + mTileSize - 1) / mTileSize;
622 unsigned int rows = (aSize.height + mTileSize - 1) / mTileSize;
623
624 // Iterate over old tile-store and insert/remove tiles as necessary
625 int row;
626 unsigned int i = 0;
627 for (row = 0; row < (int)rows; row++) {
628 // If we've gone beyond how many rows there were before, set mColumns to
629 // zero so that we only create new tiles.
630 if (row >= (int)mRows)
631 mColumns = 0;
632
633 // Similarly, if we're on the last row of old tiles and the height has
634 // changed, discard all tiles in that row.
635 // This will cause the pruning of columns not to work, but we don't need
636 // to worry about that, as no more tiles will be reused past this point
637 // anyway.
638 if ((row == (int)mRows - 1) && (aSize.height != mSize.height))
639 mColumns = 0;
640
641 int col;
642 for (col = 0; col < (int)columns; col++) {
643 nsIntSize size( // use tilesize first, then the remainder
644 (col+1) * mTileSize > (unsigned int)aSize.width ? aSize.width % mTileSize : mTileSize,
645 (row+1) * mTileSize > (unsigned int)aSize.height ? aSize.height % mTileSize : mTileSize);
646
647 bool replace = false;
648
649 // Check if we can re-use old tiles.
650 if (col < (int)mColumns) {
651 // Reuse an existing tile. If the tile is an end-tile and the
652 // width differs, replace it instead.
653 if (mSize.width != aSize.width) {
654 if (col == (int)mColumns - 1) {
655 // Tile at the end of the old column, replace it with
656 // a new one.
657 replace = true;
658 } else if (col == (int)columns - 1) {
659 // Tile at the end of the new column, create a new one.
660 } else {
661 // Before the last column on both the old and new sizes,
662 // reuse existing tile.
663 i++;
664 continue;
665 }
666 } else {
667 // Width hasn't changed, reuse existing tile.
668 i++;
669 continue;
670 }
671 }
672
673 // Create a new tile.
674 nsRefPtr<TextureImage> teximg =
675 TileGenFunc(mGL, size, mContentType, mFlags, mImageFormat);
676 if (replace)
677 mImages.ReplaceElementAt(i, teximg);
678 else
679 mImages.InsertElementAt(i, teximg);
680 i++;
681 }
682
683 // Prune any unused tiles on the end of the column.
684 if (row < (int)mRows) {
685 for (col = (int)mColumns - col; col > 0; col--) {
686 mImages.RemoveElementAt(i);
687 }
688 }
689 }
690
691 // Prune any unused tiles at the end of the store.
692 unsigned int length = mImages.Length();
693 for (; i < length; i++)
694 mImages.RemoveElementAt(mImages.Length()-1);
695
696 // Reset tile-store properties.
697 mRows = rows;
698 mColumns = columns;
699 mSize = aSize;
700 mTextureState = Allocated;
701 mCurrentImage = 0;
702 }
703
704 uint32_t TiledTextureImage::GetTileCount()
705 {
706 return mImages.Length();
707 }
708
709 already_AddRefed<TextureImage>
710 CreateBasicTextureImage(GLContext* aGL,
711 const gfx::IntSize& aSize,
712 TextureImage::ContentType aContentType,
713 GLenum aWrapMode,
714 TextureImage::Flags aFlags,
715 TextureImage::ImageFormat aImageFormat)
716 {
717 bool useNearestFilter = aFlags & TextureImage::UseNearestFilter;
718 if (!aGL->MakeCurrent()) {
719 return nullptr;
720 }
721
722 GLuint texture = 0;
723 aGL->fGenTextures(1, &texture);
724
725 ScopedBindTexture bind(aGL, texture);
726
727 GLint texfilter = useNearestFilter ? LOCAL_GL_NEAREST : LOCAL_GL_LINEAR;
728 aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, texfilter);
729 aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, texfilter);
730 aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, aWrapMode);
731 aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, aWrapMode);
732
733 nsRefPtr<BasicTextureImage> texImage =
734 new BasicTextureImage(texture, aSize, aWrapMode, aContentType,
735 aGL, aFlags, aImageFormat);
736 return texImage.forget();
737 }
738
739 } // namespace
740 } // namespace

mercurial