LCOV - code coverage report
Current view: top level - gfx/gl - GLTextureImage.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 220 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 30 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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 "mozilla/gfx/2D.h"
      13             : #include "ScopedGLHelpers.h"
      14             : #include "GLUploadHelpers.h"
      15             : #include "GfxTexturesReporter.h"
      16             : 
      17             : #include "TextureImageEGL.h"
      18             : 
      19             : using namespace mozilla::gfx;
      20             : 
      21             : namespace mozilla {
      22             : namespace gl {
      23             : 
      24             : already_AddRefed<TextureImage>
      25           0 : CreateTextureImage(GLContext* gl,
      26             :                    const gfx::IntSize& aSize,
      27             :                    TextureImage::ContentType aContentType,
      28             :                    GLenum aWrapMode,
      29             :                    TextureImage::Flags aFlags,
      30             :                    TextureImage::ImageFormat aImageFormat)
      31             : {
      32           0 :     switch (gl->GetContextType()) {
      33             :         case GLContextType::EGL:
      34           0 :             return CreateTextureImageEGL(gl, aSize, aContentType, aWrapMode, aFlags, aImageFormat);
      35             :         default: {
      36             :             GLint maxTextureSize;
      37           0 :             gl->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, &maxTextureSize);
      38           0 :             if (aSize.width > maxTextureSize || aSize.height > maxTextureSize) {
      39           0 :               NS_ASSERTION(aWrapMode == LOCAL_GL_CLAMP_TO_EDGE, "Can't support wrapping with tiles!");
      40           0 :               return CreateTiledTextureImage(gl, aSize, aContentType, aFlags, aImageFormat);
      41             :             } else {
      42           0 :               return CreateBasicTextureImage(gl, aSize, aContentType, aWrapMode, aFlags);
      43             :             }
      44             :         }
      45             :     }
      46             : }
      47             : 
      48             : 
      49             : static already_AddRefed<TextureImage>
      50           0 : TileGenFunc(GLContext* gl,
      51             :             const IntSize& aSize,
      52             :             TextureImage::ContentType aContentType,
      53             :             TextureImage::Flags aFlags,
      54             :             TextureImage::ImageFormat aImageFormat)
      55             : {
      56           0 :     switch (gl->GetContextType()) {
      57             :         case GLContextType::EGL:
      58           0 :             return TileGenFuncEGL(gl, aSize, aContentType, aFlags, aImageFormat);
      59             :         default:
      60             :             return CreateBasicTextureImage(gl, aSize, aContentType,
      61           0 :                                            LOCAL_GL_CLAMP_TO_EDGE, aFlags);
      62             :     }
      63             : }
      64             : 
      65             : already_AddRefed<TextureImage>
      66           0 : TextureImage::Create(GLContext* gl,
      67             :                      const gfx::IntSize& size,
      68             :                      TextureImage::ContentType contentType,
      69             :                      GLenum wrapMode,
      70             :                      TextureImage::Flags flags)
      71             : {
      72           0 :     return CreateTextureImage(gl, size, contentType, wrapMode, flags);
      73             : }
      74             : 
      75             : bool
      76           0 : TextureImage::UpdateFromDataSource(gfx::DataSourceSurface* aSurface,
      77             :                                    const nsIntRegion* aDestRegion,
      78             :                                    const gfx::IntPoint* aSrcPoint)
      79             : {
      80             :     nsIntRegion destRegion = aDestRegion ? *aDestRegion
      81           0 :                                          : IntRect(0, 0,
      82           0 :                                                      aSurface->GetSize().width,
      83           0 :                                                      aSurface->GetSize().height);
      84             :     gfx::IntPoint srcPoint = aSrcPoint ? *aSrcPoint
      85           0 :                                        : gfx::IntPoint(0, 0);
      86           0 :     return DirectUpdate(aSurface, destRegion, srcPoint);
      87             : }
      88             : 
      89           0 : gfx::IntRect TextureImage::GetTileRect() {
      90           0 :     return gfx::IntRect(gfx::IntPoint(0,0), mSize);
      91             : }
      92             : 
      93           0 : gfx::IntRect TextureImage::GetSrcTileRect() {
      94           0 :     return GetTileRect();
      95             : }
      96             : 
      97             : void
      98           0 : TextureImage::UpdateUploadSize(size_t amount)
      99             : {
     100           0 :     if (mUploadSize > 0) {
     101           0 :         GfxTexturesReporter::UpdateAmount(GfxTexturesReporter::MemoryFreed, mUploadSize);
     102             :     }
     103           0 :     mUploadSize = amount;
     104           0 :     GfxTexturesReporter::UpdateAmount(GfxTexturesReporter::MemoryAllocated, mUploadSize);
     105           0 : }
     106             : 
     107           0 : BasicTextureImage::~BasicTextureImage()
     108             : {
     109           0 :     GLContext* ctx = mGLContext;
     110           0 :     if (ctx->IsDestroyed() || !ctx->IsOwningThreadCurrent()) {
     111           0 :         ctx = ctx->GetSharedContext();
     112             :     }
     113             : 
     114             :     // If we have a context, then we need to delete the texture;
     115             :     // if we don't have a context (either real or shared),
     116             :     // then they went away when the contex was deleted, because it
     117             :     // was the only one that had access to it.
     118           0 :     if (ctx && ctx->MakeCurrent()) {
     119           0 :         ctx->fDeleteTextures(1, &mTexture);
     120             :     }
     121           0 : }
     122             : 
     123             : void
     124           0 : BasicTextureImage::BindTexture(GLenum aTextureUnit)
     125             : {
     126           0 :     mGLContext->fActiveTexture(aTextureUnit);
     127           0 :     mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
     128           0 :     mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0);
     129           0 : }
     130             : 
     131             : bool
     132           0 : BasicTextureImage::DirectUpdate(gfx::DataSourceSurface* aSurf, const nsIntRegion& aRegion, const gfx::IntPoint& aFrom /* = gfx::IntPoint(0, 0) */)
     133             : {
     134           0 :     nsIntRegion region;
     135           0 :     if (mTextureState == Valid) {
     136           0 :         region = aRegion;
     137             :     } else {
     138           0 :         region = nsIntRegion(IntRect(0, 0, mSize.width, mSize.height));
     139             :     }
     140           0 :     bool needInit = mTextureState == Created;
     141             :     size_t uploadSize;
     142             : 
     143           0 :     mTextureFormat =
     144           0 :         UploadSurfaceToTexture(mGLContext,
     145             :                                aSurf,
     146             :                                region,
     147             :                                mTexture,
     148             :                                mSize,
     149             :                                &uploadSize,
     150             :                                needInit,
     151             :                                aFrom);
     152             : 
     153           0 :     if (uploadSize > 0) {
     154           0 :         UpdateUploadSize(uploadSize);
     155             :     }
     156           0 :     mTextureState = Valid;
     157           0 :     return true;
     158             : }
     159             : 
     160             : void
     161           0 : BasicTextureImage::Resize(const gfx::IntSize& aSize)
     162             : {
     163           0 :     mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
     164             : 
     165             :     // This matches the logic in UploadImageDataToTexture so that
     166             :     // we avoid mixing formats.
     167             :     GLenum format;
     168             :     GLenum type;
     169           0 :     if (mGLContext->GetPreferredARGB32Format() == LOCAL_GL_BGRA) {
     170           0 :         MOZ_ASSERT(!mGLContext->IsGLES());
     171           0 :         format = LOCAL_GL_BGRA;
     172           0 :         type = LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV;
     173             :     } else {
     174           0 :         format = LOCAL_GL_RGBA;
     175           0 :         type = LOCAL_GL_UNSIGNED_BYTE;
     176             :     }
     177             : 
     178           0 :     mGLContext->fTexImage2D(LOCAL_GL_TEXTURE_2D,
     179             :                             0,
     180             :                             LOCAL_GL_RGBA,
     181           0 :                             aSize.width,
     182           0 :                             aSize.height,
     183             :                             0,
     184             :                             format,
     185             :                             type,
     186           0 :                             nullptr);
     187             : 
     188           0 :     mTextureState = Allocated;
     189           0 :     mSize = aSize;
     190           0 : }
     191             : 
     192           0 : gfx::IntSize TextureImage::GetSize() const {
     193           0 :   return mSize;
     194             : }
     195             : 
     196           0 : TextureImage::TextureImage(const gfx::IntSize& aSize,
     197             :              GLenum aWrapMode, ContentType aContentType,
     198           0 :              Flags aFlags)
     199             :     : mSize(aSize)
     200             :     , mWrapMode(aWrapMode)
     201             :     , mContentType(aContentType)
     202             :     , mTextureFormat(gfx::SurfaceFormat::UNKNOWN)
     203             :     , mSamplingFilter(SamplingFilter::GOOD)
     204             :     , mFlags(aFlags)
     205           0 :     , mUploadSize(0)
     206           0 : {}
     207             : 
     208           0 : BasicTextureImage::BasicTextureImage(GLuint aTexture,
     209             :                   const gfx::IntSize& aSize,
     210             :                   GLenum aWrapMode,
     211             :                   ContentType aContentType,
     212             :                   GLContext* aContext,
     213           0 :                   TextureImage::Flags aFlags)
     214             :   : TextureImage(aSize, aWrapMode, aContentType, aFlags)
     215             :   , mTexture(aTexture)
     216             :   , mTextureState(Created)
     217           0 :   , mGLContext(aContext)
     218           0 : {}
     219             : 
     220             : static bool
     221           0 : WantsSmallTiles(GLContext* gl)
     222             : {
     223             :     // We can't use small tiles on the SGX 540, because of races in texture upload.
     224           0 :     if (gl->WorkAroundDriverBugs() &&
     225           0 :         gl->Renderer() == GLRenderer::SGX540)
     226           0 :         return false;
     227             : 
     228             :     // We should use small tiles for good performance if we can't use
     229             :     // glTexSubImage2D() for some reason.
     230           0 :     if (!CanUploadSubTextures(gl))
     231           0 :         return true;
     232             : 
     233             :     // Don't use small tiles otherwise. (If we implement incremental texture upload,
     234             :     // then we will want to revisit this.)
     235           0 :     return false;
     236             : }
     237             : 
     238           0 : TiledTextureImage::TiledTextureImage(GLContext* aGL,
     239             :                                      gfx::IntSize aSize,
     240             :                                      TextureImage::ContentType aContentType,
     241             :                                      TextureImage::Flags aFlags,
     242           0 :                                      TextureImage::ImageFormat aImageFormat)
     243             :     : TextureImage(aSize, LOCAL_GL_CLAMP_TO_EDGE, aContentType, aFlags)
     244             :     , mCurrentImage(0)
     245             :     , mIterationCallback(nullptr)
     246             :     , mIterationCallbackData(nullptr)
     247             :     , mRows(0)
     248             :     , mColumns(0)
     249             :     , mGL(aGL)
     250             :     , mTextureState(Created)
     251           0 :     , mImageFormat(aImageFormat)
     252             : {
     253           0 :     if (!(aFlags & TextureImage::DisallowBigImage) && WantsSmallTiles(mGL)) {
     254           0 :       mTileSize = 256;
     255             :     } else {
     256           0 :       mGL->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, (GLint*) &mTileSize);
     257             :     }
     258           0 :     if (aSize.width != 0 && aSize.height != 0) {
     259           0 :         Resize(aSize);
     260             :     }
     261           0 : }
     262             : 
     263           0 : TiledTextureImage::~TiledTextureImage()
     264             : {
     265           0 : }
     266             : 
     267             : bool
     268           0 : TiledTextureImage::DirectUpdate(gfx::DataSourceSurface* aSurf, const nsIntRegion& aRegion, const gfx::IntPoint& aFrom /* = gfx::IntPoint(0, 0) */)
     269             : {
     270           0 :     if (mSize.width == 0 || mSize.height == 0) {
     271           0 :         return true;
     272             :     }
     273             : 
     274           0 :     nsIntRegion region;
     275             : 
     276           0 :     if (mTextureState != Valid) {
     277           0 :         IntRect bounds = IntRect(0, 0, mSize.width, mSize.height);
     278           0 :         region = nsIntRegion(bounds);
     279             :     } else {
     280           0 :         region = aRegion;
     281             :     }
     282             : 
     283           0 :     bool result = true;
     284           0 :     int oldCurrentImage = mCurrentImage;
     285           0 :     BeginBigImageIteration();
     286           0 :     do {
     287           0 :         IntRect tileRect = GetSrcTileRect();
     288           0 :         int xPos = tileRect.x;
     289           0 :         int yPos = tileRect.y;
     290             : 
     291           0 :         nsIntRegion tileRegion;
     292           0 :         tileRegion.And(region, tileRect); // intersect with tile
     293             : 
     294           0 :         if (tileRegion.IsEmpty())
     295           0 :             continue;
     296             : 
     297           0 :         tileRegion.MoveBy(-xPos, -yPos); // translate into tile local space
     298             : 
     299           0 :         result &= mImages[mCurrentImage]->
     300           0 :           DirectUpdate(aSurf, tileRegion, aFrom + gfx::IntPoint(xPos, yPos));
     301             : 
     302           0 :         if (mCurrentImage == mImages.Length() - 1) {
     303             :             // We know we're done, but we still need to ensure that the callback
     304             :             // gets called (e.g. to update the uploaded region).
     305           0 :             NextTile();
     306           0 :             break;
     307             :         }
     308             :         // Override a callback cancelling iteration if the texture wasn't valid.
     309             :         // We need to force the update in that situation, or we may end up
     310             :         // showing invalid/out-of-date texture data.
     311           0 :     } while (NextTile() || (mTextureState != Valid));
     312           0 :     mCurrentImage = oldCurrentImage;
     313             : 
     314           0 :     mTextureFormat = mImages[0]->GetTextureFormat();
     315           0 :     mTextureState = Valid;
     316           0 :     return result;
     317             : }
     318             : 
     319           0 : void TiledTextureImage::BeginBigImageIteration()
     320             : {
     321           0 :     mCurrentImage = 0;
     322           0 : }
     323             : 
     324           0 : bool TiledTextureImage::NextTile()
     325             : {
     326           0 :     bool continueIteration = true;
     327             : 
     328           0 :     if (mIterationCallback)
     329           0 :         continueIteration = mIterationCallback(this, mCurrentImage,
     330           0 :                                                mIterationCallbackData);
     331             : 
     332           0 :     if (mCurrentImage + 1 < mImages.Length()) {
     333           0 :         mCurrentImage++;
     334           0 :         return continueIteration;
     335             :     }
     336           0 :     return false;
     337             : }
     338             : 
     339           0 : void TiledTextureImage::SetIterationCallback(BigImageIterationCallback aCallback,
     340             :                                              void* aCallbackData)
     341             : {
     342           0 :     mIterationCallback = aCallback;
     343           0 :     mIterationCallbackData = aCallbackData;
     344           0 : }
     345             : 
     346           0 : gfx::IntRect TiledTextureImage::GetTileRect()
     347             : {
     348           0 :     if (!GetTileCount()) {
     349           0 :         return gfx::IntRect();
     350             :     }
     351           0 :     gfx::IntRect rect = mImages[mCurrentImage]->GetTileRect();
     352           0 :     unsigned int xPos = (mCurrentImage % mColumns) * mTileSize;
     353           0 :     unsigned int yPos = (mCurrentImage / mColumns) * mTileSize;
     354           0 :     rect.MoveBy(xPos, yPos);
     355           0 :     return rect;
     356             : }
     357             : 
     358           0 : gfx::IntRect TiledTextureImage::GetSrcTileRect()
     359             : {
     360           0 :     gfx::IntRect rect = GetTileRect();
     361           0 :     const bool needsYFlip = mFlags & OriginBottomLeft;
     362           0 :     unsigned int srcY = needsYFlip ? mSize.height - rect.height - rect.y
     363           0 :                                    : rect.y;
     364           0 :     return gfx::IntRect(rect.x, srcY, rect.width, rect.height);
     365             : }
     366             : 
     367             : void
     368           0 : TiledTextureImage::BindTexture(GLenum aTextureUnit)
     369             : {
     370           0 :     if (!GetTileCount()) {
     371           0 :         return;
     372             :     }
     373           0 :     mImages[mCurrentImage]->BindTexture(aTextureUnit);
     374             : }
     375             : 
     376             : /*
     377             :  * Resize, trying to reuse tiles. The reuse strategy is to decide on reuse per
     378             :  * column. A tile on a column is reused if it hasn't changed size, otherwise it
     379             :  * is discarded/replaced. Extra tiles on a column are pruned after iterating
     380             :  * each column, and extra rows are pruned after iteration over the entire image
     381             :  * finishes.
     382             :  */
     383           0 : void TiledTextureImage::Resize(const gfx::IntSize& aSize)
     384             : {
     385           0 :     if (mSize == aSize && mTextureState != Created) {
     386           0 :         return;
     387             :     }
     388             : 
     389             :     // calculate rows and columns, rounding up
     390           0 :     unsigned int columns = (aSize.width  + mTileSize - 1) / mTileSize;
     391           0 :     unsigned int rows = (aSize.height + mTileSize - 1) / mTileSize;
     392             : 
     393             :     // Iterate over old tile-store and insert/remove tiles as necessary
     394             :     int row;
     395           0 :     unsigned int i = 0;
     396           0 :     for (row = 0; row < (int)rows; row++) {
     397             :         // If we've gone beyond how many rows there were before, set mColumns to
     398             :         // zero so that we only create new tiles.
     399           0 :         if (row >= (int)mRows)
     400           0 :             mColumns = 0;
     401             : 
     402             :         // Similarly, if we're on the last row of old tiles and the height has
     403             :         // changed, discard all tiles in that row.
     404             :         // This will cause the pruning of columns not to work, but we don't need
     405             :         // to worry about that, as no more tiles will be reused past this point
     406             :         // anyway.
     407           0 :         if ((row == (int)mRows - 1) && (aSize.height != mSize.height))
     408           0 :             mColumns = 0;
     409             : 
     410             :         int col;
     411           0 :         for (col = 0; col < (int)columns; col++) {
     412             :             IntSize size( // use tilesize first, then the remainder
     413           0 :                     (col+1) * mTileSize > (unsigned int)aSize.width  ? aSize.width  % mTileSize : mTileSize,
     414           0 :                     (row+1) * mTileSize > (unsigned int)aSize.height ? aSize.height % mTileSize : mTileSize);
     415             : 
     416           0 :             bool replace = false;
     417             : 
     418             :             // Check if we can re-use old tiles.
     419           0 :             if (col < (int)mColumns) {
     420             :                 // Reuse an existing tile. If the tile is an end-tile and the
     421             :                 // width differs, replace it instead.
     422           0 :                 if (mSize.width != aSize.width) {
     423           0 :                     if (col == (int)mColumns - 1) {
     424             :                         // Tile at the end of the old column, replace it with
     425             :                         // a new one.
     426           0 :                         replace = true;
     427           0 :                     } else if (col == (int)columns - 1) {
     428             :                         // Tile at the end of the new column, create a new one.
     429             :                     } else {
     430             :                         // Before the last column on both the old and new sizes,
     431             :                         // reuse existing tile.
     432           0 :                         i++;
     433           0 :                         continue;
     434             :                     }
     435             :                 } else {
     436             :                     // Width hasn't changed, reuse existing tile.
     437           0 :                     i++;
     438           0 :                     continue;
     439             :                 }
     440             :             }
     441             : 
     442             :             // Create a new tile.
     443             :             RefPtr<TextureImage> teximg =
     444           0 :                 TileGenFunc(mGL, size, mContentType, mFlags, mImageFormat);
     445           0 :             if (replace)
     446           0 :                 mImages.ReplaceElementAt(i, teximg);
     447             :             else
     448           0 :                 mImages.InsertElementAt(i, teximg);
     449           0 :             i++;
     450             :         }
     451             : 
     452             :         // Prune any unused tiles on the end of the column.
     453           0 :         if (row < (int)mRows) {
     454           0 :             for (col = (int)mColumns - col; col > 0; col--) {
     455           0 :                 mImages.RemoveElementAt(i);
     456             :             }
     457             :         }
     458             :     }
     459             : 
     460             :     // Prune any unused tiles at the end of the store.
     461           0 :     unsigned int length = mImages.Length();
     462           0 :     for (; i < length; i++)
     463           0 :       mImages.RemoveElementAt(mImages.Length()-1);
     464             : 
     465             :     // Reset tile-store properties.
     466           0 :     mRows = rows;
     467           0 :     mColumns = columns;
     468           0 :     mSize = aSize;
     469           0 :     mTextureState = Allocated;
     470           0 :     mCurrentImage = 0;
     471             : }
     472             : 
     473           0 : uint32_t TiledTextureImage::GetTileCount()
     474             : {
     475           0 :     return mImages.Length();
     476             : }
     477             : 
     478             : already_AddRefed<TextureImage>
     479           0 : CreateTiledTextureImage(GLContext* aGL,
     480             :                         const gfx::IntSize& aSize,
     481             :                         TextureImage::ContentType aContentType,
     482             :                         TextureImage::Flags aFlags,
     483             :                         TextureImage::ImageFormat aImageFormat)
     484             : {
     485             :   RefPtr<TextureImage> texImage = static_cast<TextureImage*>(
     486           0 :       new gl::TiledTextureImage(aGL, aSize, aContentType, aFlags, aImageFormat));
     487           0 :   return texImage.forget();
     488             : }
     489             : 
     490             : 
     491             : already_AddRefed<TextureImage>
     492           0 : CreateBasicTextureImage(GLContext* aGL,
     493             :                         const gfx::IntSize& aSize,
     494             :                         TextureImage::ContentType aContentType,
     495             :                         GLenum aWrapMode,
     496             :                         TextureImage::Flags aFlags)
     497             : {
     498           0 :     bool useNearestFilter = aFlags & TextureImage::UseNearestFilter;
     499           0 :     if (!aGL->MakeCurrent()) {
     500           0 :       return nullptr;
     501             :     }
     502             : 
     503           0 :     GLuint texture = 0;
     504           0 :     aGL->fGenTextures(1, &texture);
     505             : 
     506           0 :     ScopedBindTexture bind(aGL, texture);
     507             : 
     508           0 :     GLint texfilter = useNearestFilter ? LOCAL_GL_NEAREST : LOCAL_GL_LINEAR;
     509           0 :     aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, texfilter);
     510           0 :     aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, texfilter);
     511           0 :     aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, aWrapMode);
     512           0 :     aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, aWrapMode);
     513             : 
     514             :     RefPtr<BasicTextureImage> texImage =
     515             :         new BasicTextureImage(texture, aSize, aWrapMode, aContentType,
     516           0 :                               aGL, aFlags);
     517           0 :     return texImage.forget();
     518             : }
     519             : 
     520             : } // namespace gl
     521             : } // namespace mozilla

Generated by: LCOV version 1.13