Bumping gaia.json for 2 gaia revision(s) a=gaia-bump
[gecko.git] / gfx / gl / GLTextureImage.cpp
blob8dd8f2f5a3104057a4312cdf668d7025253a4f10
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/. */
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 "mozilla/gfx/2D.h"
13 #include "ScopedGLHelpers.h"
14 #include "GLUploadHelpers.h"
16 #include "TextureImageEGL.h"
17 #ifdef XP_MACOSX
18 #include "TextureImageCGL.h"
19 #endif
21 using namespace mozilla::gfx;
23 namespace mozilla {
24 namespace gl {
26 already_AddRefed<TextureImage>
27 CreateTextureImage(GLContext* gl,
28 const gfx::IntSize& aSize,
29 TextureImage::ContentType aContentType,
30 GLenum aWrapMode,
31 TextureImage::Flags aFlags,
32 TextureImage::ImageFormat aImageFormat)
34 switch (gl->GetContextType()) {
35 #ifdef XP_MACOSX
36 case GLContextType::CGL:
37 return CreateTextureImageCGL(gl, aSize, aContentType, aWrapMode, aFlags, aImageFormat);
38 #endif
39 case GLContextType::EGL:
40 return CreateTextureImageEGL(gl, aSize, aContentType, aWrapMode, aFlags, aImageFormat);
41 default:
42 return CreateBasicTextureImage(gl, aSize, aContentType, aWrapMode, aFlags, aImageFormat);
47 static already_AddRefed<TextureImage>
48 TileGenFunc(GLContext* gl,
49 const nsIntSize& aSize,
50 TextureImage::ContentType aContentType,
51 TextureImage::Flags aFlags,
52 TextureImage::ImageFormat aImageFormat)
54 switch (gl->GetContextType()) {
55 #ifdef XP_MACOSX
56 case GLContextType::CGL:
57 return TileGenFuncCGL(gl, aSize, aContentType, aFlags, aImageFormat);
58 #endif
59 case GLContextType::EGL:
60 return TileGenFuncEGL(gl, aSize, aContentType, aFlags, aImageFormat);
61 default:
62 return nullptr;
66 already_AddRefed<TextureImage>
67 TextureImage::Create(GLContext* gl,
68 const gfx::IntSize& size,
69 TextureImage::ContentType contentType,
70 GLenum wrapMode,
71 TextureImage::Flags flags)
73 return CreateTextureImage(gl, size, contentType, wrapMode, flags);
76 bool
77 TextureImage::UpdateFromDataSource(gfx::DataSourceSurface *aSurface,
78 const nsIntRegion* aDestRegion,
79 const gfx::IntPoint* aSrcPoint)
81 nsIntRegion destRegion = aDestRegion ? *aDestRegion
82 : nsIntRect(0, 0,
83 aSurface->GetSize().width,
84 aSurface->GetSize().height);
85 gfx::IntPoint srcPoint = aSrcPoint ? *aSrcPoint
86 : gfx::IntPoint(0, 0);
87 return DirectUpdate(aSurface, destRegion, srcPoint);
90 gfx::IntRect TextureImage::GetTileRect() {
91 return gfx::IntRect(gfx::IntPoint(0,0), mSize);
94 gfx::IntRect TextureImage::GetSrcTileRect() {
95 return GetTileRect();
98 BasicTextureImage::~BasicTextureImage()
100 GLContext *ctx = mGLContext;
101 if (ctx->IsDestroyed() || !ctx->IsOwningThreadCurrent()) {
102 ctx = ctx->GetSharedContext();
105 // If we have a context, then we need to delete the texture;
106 // if we don't have a context (either real or shared),
107 // then they went away when the contex was deleted, because it
108 // was the only one that had access to it.
109 if (ctx && ctx->MakeCurrent()) {
110 ctx->fDeleteTextures(1, &mTexture);
114 gfx::DrawTarget*
115 BasicTextureImage::BeginUpdate(nsIntRegion& aRegion)
117 NS_ASSERTION(!mUpdateDrawTarget, "BeginUpdate() without EndUpdate()?");
119 // determine the region the client will need to repaint
120 if (CanUploadSubTextures(mGLContext)) {
121 GetUpdateRegion(aRegion);
122 } else {
123 aRegion = nsIntRect(nsIntPoint(0, 0), gfx::ThebesIntSize(mSize));
126 mUpdateRegion = aRegion;
128 nsIntRect rgnSize = mUpdateRegion.GetBounds();
129 if (!nsIntRect(nsIntPoint(0, 0), gfx::ThebesIntSize(mSize)).Contains(rgnSize)) {
130 NS_ERROR("update outside of image");
131 return nullptr;
134 gfx::SurfaceFormat format =
135 (GetContentType() == gfxContentType::COLOR) ?
136 gfx::SurfaceFormat::B8G8R8X8 : gfx::SurfaceFormat::B8G8R8A8;
137 mUpdateDrawTarget =
138 GetDrawTargetForUpdate(gfx::IntSize(rgnSize.width, rgnSize.height), format);
140 return mUpdateDrawTarget;
143 void
144 BasicTextureImage::GetUpdateRegion(nsIntRegion& aForRegion)
146 // if the texture hasn't been initialized yet, or something important
147 // changed, we need to recreate our backing surface and force the
148 // client to paint everything
149 if (mTextureState != Valid)
150 aForRegion = nsIntRect(nsIntPoint(0, 0), gfx::ThebesIntSize(mSize));
153 void
154 BasicTextureImage::EndUpdate()
156 NS_ASSERTION(!!mUpdateDrawTarget, "EndUpdate() without BeginUpdate()?");
158 // FIXME: this is the slow boat. Make me fast (with GLXPixmap?).
160 RefPtr<gfx::SourceSurface> updateSnapshot = mUpdateDrawTarget->Snapshot();
161 RefPtr<gfx::DataSourceSurface> updateData = updateSnapshot->GetDataSurface();
163 bool relative = FinishedSurfaceUpdate();
165 mTextureFormat =
166 UploadSurfaceToTexture(mGLContext,
167 updateData,
168 mUpdateRegion,
169 mTexture,
170 mTextureState == Created,
171 mUpdateOffset,
172 relative);
173 FinishedSurfaceUpload();
175 mUpdateDrawTarget = nullptr;
176 mTextureState = Valid;
179 void
180 BasicTextureImage::BindTexture(GLenum aTextureUnit)
182 mGLContext->fActiveTexture(aTextureUnit);
183 mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
184 mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0);
187 TemporaryRef<gfx::DrawTarget>
188 BasicTextureImage::GetDrawTargetForUpdate(const gfx::IntSize& aSize, gfx::SurfaceFormat aFmt)
190 return gfx::Factory::CreateDrawTarget(gfx::BackendType::CAIRO, aSize, aFmt);
193 bool
194 BasicTextureImage::FinishedSurfaceUpdate()
196 return false;
199 void
200 BasicTextureImage::FinishedSurfaceUpload()
204 bool
205 BasicTextureImage::DirectUpdate(gfx::DataSourceSurface* aSurf, const nsIntRegion& aRegion, const gfx::IntPoint& aFrom /* = gfx::IntPoint(0, 0) */)
207 nsIntRect bounds = aRegion.GetBounds();
208 nsIntRegion region;
209 if (mTextureState != Valid) {
210 bounds = nsIntRect(0, 0, mSize.width, mSize.height);
211 region = nsIntRegion(bounds);
212 } else {
213 region = aRegion;
216 mTextureFormat =
217 UploadSurfaceToTexture(mGLContext,
218 aSurf,
219 region,
220 mTexture,
221 mTextureState == Created,
222 bounds.TopLeft() + nsIntPoint(aFrom.x, aFrom.y),
223 false);
224 mTextureState = Valid;
225 return true;
228 void
229 BasicTextureImage::Resize(const gfx::IntSize& aSize)
231 NS_ASSERTION(!mUpdateDrawTarget, "Resize() while in update?");
233 mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
235 // This matches the logic in UploadImageDataToTexture so that
236 // we avoid mixing formats.
237 GLenum format;
238 GLenum type;
239 if (mGLContext->GetPreferredARGB32Format() == LOCAL_GL_BGRA) {
240 MOZ_ASSERT(!mGLContext->IsGLES());
241 format = LOCAL_GL_BGRA;
242 type = LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV;
243 } else {
244 format = LOCAL_GL_RGBA;
245 type = LOCAL_GL_UNSIGNED_BYTE;
248 mGLContext->fTexImage2D(LOCAL_GL_TEXTURE_2D,
250 LOCAL_GL_RGBA,
251 aSize.width,
252 aSize.height,
254 format,
255 type,
256 nullptr);
258 mTextureState = Allocated;
259 mSize = aSize;
262 gfx::IntSize TextureImage::GetSize() const {
263 return mSize;
266 TextureImage::TextureImage(const gfx::IntSize& aSize,
267 GLenum aWrapMode, ContentType aContentType,
268 Flags aFlags)
269 : mSize(aSize)
270 , mWrapMode(aWrapMode)
271 , mContentType(aContentType)
272 , mFilter(GraphicsFilter::FILTER_GOOD)
273 , mFlags(aFlags)
276 BasicTextureImage::BasicTextureImage(GLuint aTexture,
277 const nsIntSize& aSize,
278 GLenum aWrapMode,
279 ContentType aContentType,
280 GLContext* aContext,
281 TextureImage::Flags aFlags /* = TextureImage::NoFlags */,
282 TextureImage::ImageFormat aImageFormat /* = gfxImageFormat::Unknown */)
283 : TextureImage(aSize, aWrapMode, aContentType, aFlags, aImageFormat)
284 , mTexture(aTexture)
285 , mTextureState(Created)
286 , mGLContext(aContext)
287 , mUpdateOffset(0, 0)
291 BasicTextureImage::BasicTextureImage(GLuint aTexture,
292 const gfx::IntSize& aSize,
293 GLenum aWrapMode,
294 ContentType aContentType,
295 GLContext* aContext,
296 TextureImage::Flags aFlags,
297 TextureImage::ImageFormat aImageFormat)
298 : TextureImage(ThebesIntSize(aSize), aWrapMode, aContentType, aFlags, aImageFormat)
299 , mTexture(aTexture)
300 , mTextureState(Created)
301 , mGLContext(aContext)
302 , mUpdateOffset(0, 0)
305 static bool
306 WantsSmallTiles(GLContext* gl)
308 // We must use small tiles for good performance if we can't use
309 // glTexSubImage2D() for some reason.
310 if (!CanUploadSubTextures(gl))
311 return true;
313 // We can't use small tiles on the SGX 540, because of races in texture upload.
314 if (gl->WorkAroundDriverBugs() &&
315 gl->Renderer() == GLRenderer::SGX540)
316 return false;
318 // Don't use small tiles otherwise. (If we implement incremental texture upload,
319 // then we will want to revisit this.)
320 return false;
323 TiledTextureImage::TiledTextureImage(GLContext* aGL,
324 gfx::IntSize aSize,
325 TextureImage::ContentType aContentType,
326 TextureImage::Flags aFlags,
327 TextureImage::ImageFormat aImageFormat)
328 : TextureImage(aSize, LOCAL_GL_CLAMP_TO_EDGE, aContentType, aFlags)
329 , mCurrentImage(0)
330 , mIterationCallback(nullptr)
331 , mInUpdate(false)
332 , mRows(0)
333 , mColumns(0)
334 , mGL(aGL)
335 , mTextureState(Created)
336 , mImageFormat(aImageFormat)
338 if (!(aFlags & TextureImage::DisallowBigImage) && WantsSmallTiles(mGL)) {
339 mTileSize = 256;
340 } else {
341 mGL->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, (GLint*) &mTileSize);
343 if (aSize.width != 0 && aSize.height != 0) {
344 Resize(aSize);
348 TiledTextureImage::~TiledTextureImage()
352 bool
353 TiledTextureImage::DirectUpdate(gfx::DataSourceSurface* aSurf, const nsIntRegion& aRegion, const gfx::IntPoint& aFrom /* = gfx::IntPoint(0, 0) */)
355 if (mSize.width == 0 || mSize.height == 0) {
356 return true;
359 nsIntRegion region;
361 if (mTextureState != Valid) {
362 nsIntRect bounds = nsIntRect(0, 0, mSize.width, mSize.height);
363 region = nsIntRegion(bounds);
364 } else {
365 region = aRegion;
368 bool result = true;
369 int oldCurrentImage = mCurrentImage;
370 BeginBigImageIteration();
371 do {
372 nsIntRect tileRect = ThebesIntRect(GetSrcTileRect());
373 int xPos = tileRect.x;
374 int yPos = tileRect.y;
376 nsIntRegion tileRegion;
377 tileRegion.And(region, tileRect); // intersect with tile
379 if (tileRegion.IsEmpty())
380 continue;
382 if (CanUploadSubTextures(mGL)) {
383 tileRegion.MoveBy(-xPos, -yPos); // translate into tile local space
384 } else {
385 // If sub-textures are unsupported, expand to tile boundaries
386 tileRect.x = tileRect.y = 0;
387 tileRegion = nsIntRegion(tileRect);
390 result &= mImages[mCurrentImage]->
391 DirectUpdate(aSurf, tileRegion, aFrom + gfx::IntPoint(xPos, yPos));
393 if (mCurrentImage == mImages.Length() - 1) {
394 // We know we're done, but we still need to ensure that the callback
395 // gets called (e.g. to update the uploaded region).
396 NextTile();
397 break;
399 // Override a callback cancelling iteration if the texture wasn't valid.
400 // We need to force the update in that situation, or we may end up
401 // showing invalid/out-of-date texture data.
402 } while (NextTile() || (mTextureState != Valid));
403 mCurrentImage = oldCurrentImage;
405 mTextureFormat = mImages[0]->GetTextureFormat();
406 mTextureState = Valid;
407 return result;
410 void
411 TiledTextureImage::GetUpdateRegion(nsIntRegion& aForRegion)
413 if (mTextureState != Valid) {
414 // if the texture hasn't been initialized yet, or something important
415 // changed, we need to recreate our backing surface and force the
416 // client to paint everything
417 aForRegion = nsIntRect(nsIntPoint(0, 0), gfx::ThebesIntSize(mSize));
418 return;
421 nsIntRegion newRegion;
423 // We need to query each texture with the region it will be drawing and
424 // set aForRegion to be the combination of all of these regions
425 for (unsigned i = 0; i < mImages.Length(); i++) {
426 int xPos = (i % mColumns) * mTileSize;
427 int yPos = (i / mColumns) * mTileSize;
428 nsIntRect imageRect = nsIntRect(nsIntPoint(xPos,yPos),
429 ThebesIntSize(mImages[i]->GetSize()));
431 if (aForRegion.Intersects(imageRect)) {
432 // Make a copy of the region
433 nsIntRegion subRegion;
434 subRegion.And(aForRegion, imageRect);
435 // Translate it into tile-space
436 subRegion.MoveBy(-xPos, -yPos);
437 // Query region
438 mImages[i]->GetUpdateRegion(subRegion);
439 // Translate back
440 subRegion.MoveBy(xPos, yPos);
441 // Add to the accumulated region
442 newRegion.Or(newRegion, subRegion);
446 aForRegion = newRegion;
449 gfx::DrawTarget*
450 TiledTextureImage::BeginUpdate(nsIntRegion& aRegion)
452 NS_ASSERTION(!mInUpdate, "nested update");
453 mInUpdate = true;
455 // Note, we don't call GetUpdateRegion here as if the updated region is
456 // fully contained in a single tile, we get to avoid iterating through
457 // the tiles again (and a little copying).
458 if (mTextureState != Valid)
460 // if the texture hasn't been initialized yet, or something important
461 // changed, we need to recreate our backing surface and force the
462 // client to paint everything
463 aRegion = nsIntRect(nsIntPoint(0, 0), gfx::ThebesIntSize(mSize));
466 nsIntRect bounds = aRegion.GetBounds();
468 for (unsigned i = 0; i < mImages.Length(); i++) {
469 int xPos = (i % mColumns) * mTileSize;
470 int yPos = (i / mColumns) * mTileSize;
471 nsIntRegion imageRegion =
472 nsIntRegion(nsIntRect(nsIntPoint(xPos,yPos),
473 ThebesIntSize(mImages[i]->GetSize())));
475 // a single Image can handle this update request
476 if (imageRegion.Contains(aRegion)) {
477 // adjust for tile offset
478 aRegion.MoveBy(-xPos, -yPos);
479 // forward the actual call
480 RefPtr<gfx::DrawTarget> drawTarget = mImages[i]->BeginUpdate(aRegion);
481 // caller expects container space
482 aRegion.MoveBy(xPos, yPos);
483 // we don't have a temp surface
484 mUpdateDrawTarget = nullptr;
485 // remember which image to EndUpdate
486 mCurrentImage = i;
487 return drawTarget.get();
491 // Get the real updated region, taking into account the capabilities of
492 // each TextureImage tile
493 GetUpdateRegion(aRegion);
494 mUpdateRegion = aRegion;
495 bounds = aRegion.GetBounds();
497 // update covers multiple Images - create a temp surface to paint in
498 gfx::SurfaceFormat format =
499 (GetContentType() == gfxContentType::COLOR) ?
500 gfx::SurfaceFormat::B8G8R8X8: gfx::SurfaceFormat::B8G8R8A8;
501 mUpdateDrawTarget = gfx::Factory::CreateDrawTarget(gfx::BackendType::CAIRO,
502 bounds.Size().ToIntSize(),
503 format);
505 return mUpdateDrawTarget;;
508 void
509 TiledTextureImage::EndUpdate()
511 NS_ASSERTION(mInUpdate, "EndUpdate not in update");
512 if (!mUpdateDrawTarget) { // update was to a single TextureImage
513 mImages[mCurrentImage]->EndUpdate();
514 mInUpdate = false;
515 mTextureState = Valid;
516 mTextureFormat = mImages[mCurrentImage]->GetTextureFormat();
517 return;
520 RefPtr<gfx::SourceSurface> updateSnapshot = mUpdateDrawTarget->Snapshot();
521 RefPtr<gfx::DataSourceSurface> updateData = updateSnapshot->GetDataSurface();
523 // upload tiles from temp surface
524 for (unsigned i = 0; i < mImages.Length(); i++) {
525 int xPos = (i % mColumns) * mTileSize;
526 int yPos = (i / mColumns) * mTileSize;
527 nsIntRect imageRect = nsIntRect(nsIntPoint(xPos,yPos),
528 ThebesIntSize(mImages[i]->GetSize()));
530 nsIntRegion subregion;
531 subregion.And(mUpdateRegion, imageRect);
532 if (subregion.IsEmpty())
533 continue;
534 subregion.MoveBy(-xPos, -yPos); // Tile-local space
535 // copy tile from temp target
536 gfx::DrawTarget* drawTarget = mImages[i]->BeginUpdate(subregion);
537 MOZ_ASSERT(drawTarget->GetBackendType() == BackendType::CAIRO,
538 "updateSnapshot should not have been converted to data");
539 gfxUtils::ClipToRegion(drawTarget, subregion);
540 Size size(updateData->GetSize().width,
541 updateData->GetSize().height);
542 drawTarget->DrawSurface(updateData,
543 Rect(Point(-xPos, -yPos), size),
544 Rect(Point(0, 0), size),
545 DrawSurfaceOptions(),
546 DrawOptions(1.0, CompositionOp::OP_SOURCE,
547 AntialiasMode::NONE));
548 drawTarget->PopClip();
549 mImages[i]->EndUpdate();
552 mUpdateDrawTarget = nullptr;
553 mInUpdate = false;
554 mTextureFormat = mImages[0]->GetTextureFormat();
555 mTextureState = Valid;
558 void TiledTextureImage::BeginBigImageIteration()
560 mCurrentImage = 0;
563 bool TiledTextureImage::NextTile()
565 bool continueIteration = true;
567 if (mIterationCallback)
568 continueIteration = mIterationCallback(this, mCurrentImage,
569 mIterationCallbackData);
571 if (mCurrentImage + 1 < mImages.Length()) {
572 mCurrentImage++;
573 return continueIteration;
575 return false;
578 void TiledTextureImage::SetIterationCallback(BigImageIterationCallback aCallback,
579 void* aCallbackData)
581 mIterationCallback = aCallback;
582 mIterationCallbackData = aCallbackData;
585 gfx::IntRect TiledTextureImage::GetTileRect()
587 if (!GetTileCount()) {
588 return gfx::IntRect();
590 gfx::IntRect rect = mImages[mCurrentImage]->GetTileRect();
591 unsigned int xPos = (mCurrentImage % mColumns) * mTileSize;
592 unsigned int yPos = (mCurrentImage / mColumns) * mTileSize;
593 rect.MoveBy(xPos, yPos);
594 return rect;
597 gfx::IntRect TiledTextureImage::GetSrcTileRect()
599 gfx::IntRect rect = GetTileRect();
600 const bool needsYFlip = mFlags & OriginBottomLeft;
601 unsigned int srcY = needsYFlip ? mSize.height - rect.height - rect.y
602 : rect.y;
603 return gfx::IntRect(rect.x, srcY, rect.width, rect.height);
606 void
607 TiledTextureImage::BindTexture(GLenum aTextureUnit)
609 if (!GetTileCount()) {
610 return;
612 mImages[mCurrentImage]->BindTexture(aTextureUnit);
616 * Resize, trying to reuse tiles. The reuse strategy is to decide on reuse per
617 * column. A tile on a column is reused if it hasn't changed size, otherwise it
618 * is discarded/replaced. Extra tiles on a column are pruned after iterating
619 * each column, and extra rows are pruned after iteration over the entire image
620 * finishes.
622 void TiledTextureImage::Resize(const gfx::IntSize& aSize)
624 if (mSize == aSize && mTextureState != Created) {
625 return;
628 // calculate rows and columns, rounding up
629 unsigned int columns = (aSize.width + mTileSize - 1) / mTileSize;
630 unsigned int rows = (aSize.height + mTileSize - 1) / mTileSize;
632 // Iterate over old tile-store and insert/remove tiles as necessary
633 int row;
634 unsigned int i = 0;
635 for (row = 0; row < (int)rows; row++) {
636 // If we've gone beyond how many rows there were before, set mColumns to
637 // zero so that we only create new tiles.
638 if (row >= (int)mRows)
639 mColumns = 0;
641 // Similarly, if we're on the last row of old tiles and the height has
642 // changed, discard all tiles in that row.
643 // This will cause the pruning of columns not to work, but we don't need
644 // to worry about that, as no more tiles will be reused past this point
645 // anyway.
646 if ((row == (int)mRows - 1) && (aSize.height != mSize.height))
647 mColumns = 0;
649 int col;
650 for (col = 0; col < (int)columns; col++) {
651 nsIntSize size( // use tilesize first, then the remainder
652 (col+1) * mTileSize > (unsigned int)aSize.width ? aSize.width % mTileSize : mTileSize,
653 (row+1) * mTileSize > (unsigned int)aSize.height ? aSize.height % mTileSize : mTileSize);
655 bool replace = false;
657 // Check if we can re-use old tiles.
658 if (col < (int)mColumns) {
659 // Reuse an existing tile. If the tile is an end-tile and the
660 // width differs, replace it instead.
661 if (mSize.width != aSize.width) {
662 if (col == (int)mColumns - 1) {
663 // Tile at the end of the old column, replace it with
664 // a new one.
665 replace = true;
666 } else if (col == (int)columns - 1) {
667 // Tile at the end of the new column, create a new one.
668 } else {
669 // Before the last column on both the old and new sizes,
670 // reuse existing tile.
671 i++;
672 continue;
674 } else {
675 // Width hasn't changed, reuse existing tile.
676 i++;
677 continue;
681 // Create a new tile.
682 nsRefPtr<TextureImage> teximg =
683 TileGenFunc(mGL, size, mContentType, mFlags, mImageFormat);
684 if (replace)
685 mImages.ReplaceElementAt(i, teximg);
686 else
687 mImages.InsertElementAt(i, teximg);
688 i++;
691 // Prune any unused tiles on the end of the column.
692 if (row < (int)mRows) {
693 for (col = (int)mColumns - col; col > 0; col--) {
694 mImages.RemoveElementAt(i);
699 // Prune any unused tiles at the end of the store.
700 unsigned int length = mImages.Length();
701 for (; i < length; i++)
702 mImages.RemoveElementAt(mImages.Length()-1);
704 // Reset tile-store properties.
705 mRows = rows;
706 mColumns = columns;
707 mSize = aSize;
708 mTextureState = Allocated;
709 mCurrentImage = 0;
712 uint32_t TiledTextureImage::GetTileCount()
714 return mImages.Length();
717 already_AddRefed<TextureImage>
718 CreateBasicTextureImage(GLContext* aGL,
719 const gfx::IntSize& aSize,
720 TextureImage::ContentType aContentType,
721 GLenum aWrapMode,
722 TextureImage::Flags aFlags,
723 TextureImage::ImageFormat aImageFormat)
725 bool useNearestFilter = aFlags & TextureImage::UseNearestFilter;
726 if (!aGL->MakeCurrent()) {
727 return nullptr;
730 GLuint texture = 0;
731 aGL->fGenTextures(1, &texture);
733 ScopedBindTexture bind(aGL, texture);
735 GLint texfilter = useNearestFilter ? LOCAL_GL_NEAREST : LOCAL_GL_LINEAR;
736 aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, texfilter);
737 aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, texfilter);
738 aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, aWrapMode);
739 aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, aWrapMode);
741 nsRefPtr<BasicTextureImage> texImage =
742 new BasicTextureImage(texture, aSize, aWrapMode, aContentType,
743 aGL, aFlags, aImageFormat);
744 return texImage.forget();
747 } // namespace
748 } // namespace