LCOV - code coverage report
Current view: top level - dom/canvas - WebGLTexture.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 1 549 0.2 %
Date: 2017-07-14 16:53:18 Functions: 0 41 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       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 "WebGLTexture.h"
       7             : 
       8             : #include <algorithm>
       9             : #include "GLContext.h"
      10             : #include "mozilla/dom/WebGLRenderingContextBinding.h"
      11             : #include "mozilla/gfx/Logging.h"
      12             : #include "mozilla/MathAlgorithms.h"
      13             : #include "mozilla/Scoped.h"
      14             : #include "mozilla/Unused.h"
      15             : #include "ScopedGLHelpers.h"
      16             : #include "WebGLContext.h"
      17             : #include "WebGLContextUtils.h"
      18             : #include "WebGLFramebuffer.h"
      19             : #include "WebGLSampler.h"
      20             : #include "WebGLTexelConversions.h"
      21             : 
      22             : namespace mozilla {
      23             : 
      24           3 : /*static*/ const WebGLTexture::ImageInfo WebGLTexture::ImageInfo::kUndefined;
      25             : 
      26             : ////////////////////////////////////////
      27             : 
      28             : template <typename T>
      29             : static inline T&
      30           0 : Mutable(const T& x)
      31             : {
      32           0 :     return const_cast<T&>(x);
      33             : }
      34             : 
      35             : void
      36           0 : WebGLTexture::ImageInfo::Clear(const char* funcName)
      37             : {
      38           0 :     if (!IsDefined())
      39           0 :         return;
      40             : 
      41           0 :     OnRespecify(funcName);
      42             : 
      43           0 :     Mutable(mFormat) = LOCAL_GL_NONE;
      44           0 :     Mutable(mWidth) = 0;
      45           0 :     Mutable(mHeight) = 0;
      46           0 :     Mutable(mDepth) = 0;
      47             : 
      48           0 :     MOZ_ASSERT(!IsDefined());
      49             : }
      50             : 
      51             : void
      52           0 : WebGLTexture::ImageInfo::Set(const char* funcName, const ImageInfo& a)
      53             : {
      54           0 :     MOZ_ASSERT(a.IsDefined());
      55             : 
      56           0 :     Mutable(mFormat) = a.mFormat;
      57           0 :     Mutable(mWidth) = a.mWidth;
      58           0 :     Mutable(mHeight) = a.mHeight;
      59           0 :     Mutable(mDepth) = a.mDepth;
      60             : 
      61           0 :     mIsDataInitialized = a.mIsDataInitialized;
      62             : 
      63             :     // But *don't* transfer mAttachPoints!
      64           0 :     MOZ_ASSERT(a.mAttachPoints.empty());
      65           0 :     OnRespecify(funcName);
      66           0 : }
      67             : 
      68             : bool
      69           0 : WebGLTexture::ImageInfo::IsPowerOfTwo() const
      70             : {
      71           0 :     return mozilla::IsPowerOfTwo(mWidth) &&
      72           0 :            mozilla::IsPowerOfTwo(mHeight) &&
      73           0 :            mozilla::IsPowerOfTwo(mDepth);
      74             : }
      75             : 
      76             : void
      77           0 : WebGLTexture::ImageInfo::AddAttachPoint(WebGLFBAttachPoint* attachPoint)
      78             : {
      79           0 :     const auto pair = mAttachPoints.insert(attachPoint);
      80           0 :     DebugOnly<bool> didInsert = pair.second;
      81           0 :     MOZ_ASSERT(didInsert);
      82           0 : }
      83             : 
      84             : void
      85           0 : WebGLTexture::ImageInfo::RemoveAttachPoint(WebGLFBAttachPoint* attachPoint)
      86             : {
      87           0 :     DebugOnly<size_t> numElemsErased = mAttachPoints.erase(attachPoint);
      88           0 :     MOZ_ASSERT_IF(IsDefined(), numElemsErased == 1);
      89           0 : }
      90             : 
      91             : void
      92           0 : WebGLTexture::ImageInfo::OnRespecify(const char* funcName) const
      93             : {
      94           0 :     for (auto cur : mAttachPoints) {
      95           0 :         cur->OnBackingStoreRespecified(funcName);
      96             :     }
      97           0 : }
      98             : 
      99             : size_t
     100           0 : WebGLTexture::ImageInfo::MemoryUsage() const
     101             : {
     102           0 :     if (!IsDefined())
     103           0 :         return 0;
     104             : 
     105           0 :     const auto bytesPerTexel = mFormat->format->estimatedBytesPerPixel;
     106           0 :     return size_t(mWidth) * size_t(mHeight) * size_t(mDepth) * bytesPerTexel;
     107             : }
     108             : 
     109             : void
     110           0 : WebGLTexture::ImageInfo::SetIsDataInitialized(bool isDataInitialized, WebGLTexture* tex)
     111             : {
     112           0 :     MOZ_ASSERT(tex);
     113           0 :     MOZ_ASSERT(this >= &tex->mImageInfoArr[0]);
     114           0 :     MOZ_ASSERT(this < &tex->mImageInfoArr[kMaxLevelCount * kMaxFaceCount]);
     115             : 
     116           0 :     mIsDataInitialized = isDataInitialized;
     117           0 :     tex->InvalidateResolveCache();
     118           0 : }
     119             : 
     120             : ////////////////////////////////////////
     121             : 
     122             : JSObject*
     123           0 : WebGLTexture::WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto) {
     124           0 :     return dom::WebGLTextureBinding::Wrap(cx, this, givenProto);
     125             : }
     126             : 
     127           0 : WebGLTexture::WebGLTexture(WebGLContext* webgl, GLuint tex)
     128             :     : WebGLRefCountedObject(webgl)
     129             :     , mGLName(tex)
     130             :     , mTarget(LOCAL_GL_NONE)
     131             :     , mFaceCount(0)
     132             :     , mMinFilter(LOCAL_GL_NEAREST_MIPMAP_LINEAR)
     133             :     , mMagFilter(LOCAL_GL_LINEAR)
     134             :     , mWrapS(LOCAL_GL_REPEAT)
     135             :     , mWrapT(LOCAL_GL_REPEAT)
     136             :     , mImmutable(false)
     137             :     , mImmutableLevelCount(0)
     138             :     , mBaseMipmapLevel(0)
     139             :     , mMaxMipmapLevel(1000)
     140             :     , mTexCompareMode(LOCAL_GL_NONE)
     141             :     , mIsResolved(false)
     142           0 :     , mResolved_Swizzle(nullptr)
     143             : {
     144           0 :     mContext->mTextures.insertBack(this);
     145           0 : }
     146             : 
     147             : void
     148           0 : WebGLTexture::Delete()
     149             : {
     150           0 :     const char funcName[] = "WebGLTexture::Delete";
     151           0 :     for (auto& cur : mImageInfoArr) {
     152           0 :         cur.Clear(funcName);
     153             :     }
     154             : 
     155           0 :     mContext->MakeContextCurrent();
     156           0 :     mContext->gl->fDeleteTextures(1, &mGLName);
     157             : 
     158           0 :     LinkedListElement<WebGLTexture>::removeFrom(mContext->mTextures);
     159           0 : }
     160             : 
     161             : size_t
     162           0 : WebGLTexture::MemoryUsage() const
     163             : {
     164           0 :     if (IsDeleted())
     165           0 :         return 0;
     166             : 
     167           0 :     size_t accum = 0;
     168           0 :     for (const auto& cur : mImageInfoArr) {
     169           0 :         accum += cur.MemoryUsage();
     170             :     }
     171           0 :     return accum;
     172             : }
     173             : 
     174             : void
     175           0 : WebGLTexture::SetImageInfo(const char* funcName, ImageInfo* target,
     176             :                            const ImageInfo& newInfo)
     177             : {
     178           0 :     target->Set(funcName, newInfo);
     179             : 
     180           0 :     InvalidateResolveCache();
     181           0 : }
     182             : 
     183             : void
     184           0 : WebGLTexture::SetImageInfosAtLevel(const char* funcName, uint32_t level,
     185             :                                    const ImageInfo& newInfo)
     186             : {
     187           0 :     for (uint8_t i = 0; i < mFaceCount; i++) {
     188           0 :         ImageInfoAtFace(i, level).Set(funcName, newInfo);
     189             :     }
     190             : 
     191           0 :     InvalidateResolveCache();
     192           0 : }
     193             : 
     194             : bool
     195           0 : WebGLTexture::IsMipmapComplete(const char* funcName, uint32_t texUnit,
     196             :                                bool* const out_initFailed)
     197             : {
     198           0 :     *out_initFailed = false;
     199           0 :     MOZ_ASSERT(DoesMinFilterRequireMipmap());
     200             :     // GLES 3.0.4, p161
     201             : 
     202             :     uint32_t maxLevel;
     203           0 :     if (!MaxEffectiveMipmapLevel(texUnit, &maxLevel))
     204           0 :         return false;
     205             : 
     206             :     // "* `level_base <= level_max`"
     207           0 :     if (mBaseMipmapLevel > maxLevel)
     208           0 :         return false;
     209             : 
     210             :     // Make a copy so we can modify it.
     211           0 :     const ImageInfo& baseImageInfo = BaseImageInfo();
     212             : 
     213             :     // Reference dimensions based on the current level.
     214           0 :     uint32_t refWidth = baseImageInfo.mWidth;
     215           0 :     uint32_t refHeight = baseImageInfo.mHeight;
     216           0 :     uint32_t refDepth = baseImageInfo.mDepth;
     217           0 :     MOZ_ASSERT(refWidth && refHeight && refDepth);
     218             : 
     219           0 :     for (uint32_t level = mBaseMipmapLevel; level <= maxLevel; level++) {
     220           0 :         if (!EnsureLevelInitialized(funcName, level)) {
     221           0 :             *out_initFailed = true;
     222           0 :             return false;
     223             :         }
     224             : 
     225             :         // "A cube map texture is mipmap complete if each of the six texture images,
     226             :         //  considered individually, is mipmap complete."
     227             : 
     228           0 :         for (uint8_t face = 0; face < mFaceCount; face++) {
     229           0 :             const ImageInfo& cur = ImageInfoAtFace(face, level);
     230             : 
     231             :             // "* The set of mipmap arrays `level_base` through `q` (where `q` is defined
     232             :             //    the "Mipmapping" discussion of section 3.8.10) were each specified with
     233             :             //    the same effective internal format."
     234             : 
     235             :             // "* The dimensions of the arrays follow the sequence described in the
     236             :             //    "Mipmapping" discussion of section 3.8.10."
     237             : 
     238           0 :             if (cur.mWidth != refWidth ||
     239           0 :                 cur.mHeight != refHeight ||
     240           0 :                 cur.mDepth != refDepth ||
     241           0 :                 cur.mFormat != baseImageInfo.mFormat)
     242             :             {
     243           0 :                 return false;
     244             :             }
     245             :         }
     246             : 
     247             :         // GLES 3.0.4, p158:
     248             :         // "[...] until the last array is reached with dimension 1 x 1 x 1."
     249           0 :         if (mTarget == LOCAL_GL_TEXTURE_3D) {
     250           0 :             if (refWidth == 1 &&
     251           0 :                 refHeight == 1 &&
     252             :                 refDepth == 1)
     253             :             {
     254           0 :                 break;
     255             :             }
     256             : 
     257           0 :             refDepth = std::max(uint32_t(1), refDepth / 2);
     258             :         } else {
     259             :             // TEXTURE_2D_ARRAY may have depth != 1, but that's normal.
     260           0 :             if (refWidth == 1 &&
     261             :                 refHeight == 1)
     262             :             {
     263           0 :                 break;
     264             :             }
     265             :         }
     266             : 
     267           0 :         refWidth  = std::max(uint32_t(1), refWidth  / 2);
     268           0 :         refHeight = std::max(uint32_t(1), refHeight / 2);
     269             :     }
     270             : 
     271           0 :     return true;
     272             : }
     273             : 
     274             : bool
     275           0 : WebGLTexture::IsCubeComplete() const
     276             : {
     277             :     // GLES 3.0.4, p161
     278             :     // "[...] a cube map texture is cube complete if the following conditions all hold
     279             :     //  true:
     280             :     //  * The `level_base` arrays of each of the six texture images making up the cube map
     281             :     //    have identical, positive, and square dimensions.
     282             :     //  * The `level_base` arrays were each specified with the same effective internal
     283             :     //    format."
     284             : 
     285             :     // Note that "cube complete" does not imply "mipmap complete".
     286             : 
     287           0 :     const ImageInfo& reference = BaseImageInfo();
     288           0 :     if (!reference.IsDefined())
     289           0 :         return false;
     290             : 
     291           0 :     auto refWidth = reference.mWidth;
     292           0 :     auto refFormat = reference.mFormat;
     293             : 
     294           0 :     for (uint8_t face = 0; face < mFaceCount; face++) {
     295           0 :         const ImageInfo& cur = ImageInfoAtFace(face, mBaseMipmapLevel);
     296           0 :         if (!cur.IsDefined())
     297           0 :             return false;
     298             : 
     299           0 :         MOZ_ASSERT(cur.mDepth == 1);
     300           0 :         if (cur.mFormat != refFormat || // Check effective formats.
     301           0 :             cur.mWidth != refWidth ||   // Check both width and height against refWidth to
     302           0 :             cur.mHeight != refWidth)    // to enforce positive and square dimensions.
     303             :         {
     304           0 :             return false;
     305             :         }
     306             :     }
     307             : 
     308           0 :     return true;
     309             : }
     310             : 
     311             : bool
     312           0 : WebGLTexture::IsComplete(const char* funcName, uint32_t texUnit,
     313             :                          const char** const out_reason, bool* const out_initFailed)
     314             : {
     315           0 :     *out_initFailed = false;
     316             : 
     317           0 :     const auto maxLevel = kMaxLevelCount - 1;
     318           0 :     if (mBaseMipmapLevel > maxLevel) {
     319           0 :         *out_reason = "`level_base` too high.";
     320           0 :         return false;
     321             :     }
     322             : 
     323             :     // Texture completeness is established at GLES 3.0.4, p160-161.
     324             :     // "[A] texture is complete unless any of the following conditions hold true:"
     325             : 
     326             :     // "* Any dimension of the `level_base` array is not positive."
     327           0 :     const ImageInfo& baseImageInfo = BaseImageInfo();
     328           0 :     if (!baseImageInfo.IsDefined()) {
     329             :         // In case of undefined texture image, we don't print any message because this is
     330             :         // a very common and often legitimate case (asynchronous texture loading).
     331           0 :         *out_reason = nullptr;
     332           0 :         return false;
     333             :     }
     334             : 
     335           0 :     if (!baseImageInfo.mWidth || !baseImageInfo.mHeight || !baseImageInfo.mDepth) {
     336           0 :         *out_reason = "The dimensions of `level_base` are not all positive.";
     337           0 :         return false;
     338             :     }
     339             : 
     340             :     // "* The texture is a cube map texture, and is not cube complete."
     341           0 :     if (IsCubeMap() && !IsCubeComplete()) {
     342           0 :         *out_reason = "Cubemaps must be \"cube complete\".";
     343           0 :         return false;
     344             :     }
     345             : 
     346           0 :     WebGLSampler* sampler = mContext->mBoundSamplers[texUnit];
     347           0 :     TexMinFilter minFilter = sampler ? sampler->mMinFilter : mMinFilter;
     348           0 :     TexMagFilter magFilter = sampler ? sampler->mMagFilter : mMagFilter;
     349             : 
     350             :     // "* The minification filter requires a mipmap (is neither NEAREST nor LINEAR) and
     351             :     //    the texture is not mipmap complete."
     352           0 :     const bool requiresMipmap = (minFilter != LOCAL_GL_NEAREST &&
     353           0 :                                  minFilter != LOCAL_GL_LINEAR);
     354           0 :     if (requiresMipmap && !IsMipmapComplete(funcName, texUnit, out_initFailed)) {
     355           0 :         if (*out_initFailed)
     356           0 :             return false;
     357             : 
     358           0 :         *out_reason = "Because the minification filter requires mipmapping, the texture"
     359             :                       " must be \"mipmap complete\".";
     360           0 :         return false;
     361             :     }
     362             : 
     363           0 :     const bool isMinFilteringNearest = (minFilter == LOCAL_GL_NEAREST ||
     364           0 :                                         minFilter == LOCAL_GL_NEAREST_MIPMAP_NEAREST);
     365           0 :     const bool isMagFilteringNearest = (magFilter == LOCAL_GL_NEAREST);
     366           0 :     const bool isFilteringNearestOnly = (isMinFilteringNearest && isMagFilteringNearest);
     367           0 :     if (!isFilteringNearestOnly) {
     368           0 :         auto formatUsage = baseImageInfo.mFormat;
     369           0 :         auto format = formatUsage->format;
     370             : 
     371           0 :         bool isFilterable = formatUsage->isFilterable;
     372             : 
     373             :         // "* The effective internal format specified for the texture arrays is a sized
     374             :         //    internal depth or depth and stencil format, the value of
     375             :         //    TEXTURE_COMPARE_MODE is NONE[1], and either the magnification filter is not
     376             :         //    NEAREST, or the minification filter is neither NEAREST nor
     377             :         //    NEAREST_MIPMAP_NEAREST."
     378             :         // [1]: This sounds suspect, but is explicitly noted in the change log for GLES
     379             :         //      3.0.1:
     380             :         //      "* Clarify that a texture is incomplete if it has a depth component, no
     381             :         //         shadow comparison, and linear filtering (also Bug 9481)."
     382           0 :         if (format->d && mTexCompareMode != LOCAL_GL_NONE) {
     383           0 :             isFilterable = true;
     384             :         }
     385             : 
     386             :         // "* The effective internal format specified for the texture arrays is a sized
     387             :         //    internal color format that is not texture-filterable, and either the
     388             :         //    magnification filter is not NEAREST or the minification filter is neither
     389             :         //    NEAREST nor NEAREST_MIPMAP_NEAREST."
     390             :         // Since all (GLES3) unsized color formats are filterable just like their sized
     391             :         // equivalents, we don't have to care whether its sized or not.
     392           0 :         if (!isFilterable) {
     393           0 :             *out_reason = "Because minification or magnification filtering is not NEAREST"
     394             :                           " or NEAREST_MIPMAP_NEAREST, and the texture's format must be"
     395             :                           " \"texture-filterable\".";
     396           0 :             return false;
     397             :         }
     398             :     }
     399             : 
     400             :     // Texture completeness is effectively (though not explicitly) amended for GLES2 by
     401             :     // the "Texture Access" section under $3.8 "Fragment Shaders". This also applies to
     402             :     // vertex shaders, as noted on GLES 2.0.25, p41.
     403           0 :     if (!mContext->IsWebGL2()) {
     404             :         // GLES 2.0.25, p87-88:
     405             :         // "Calling a sampler from a fragment shader will return (R,G,B,A)=(0,0,0,1) if
     406             :         //  any of the following conditions are true:"
     407             : 
     408             :         // "* A two-dimensional sampler is called, the minification filter is one that
     409             :         //    requires a mipmap[...], and the sampler's associated texture object is not
     410             :         //    complete[.]"
     411             :         // (already covered)
     412             : 
     413             :         // "* A two-dimensional sampler is called, the minification filter is not one that
     414             :         //    requires a mipmap (either NEAREST nor[sic] LINEAR), and either dimension of
     415             :         //    the level zero array of the associated texture object is not positive."
     416             :         // (already covered)
     417             : 
     418             :         // "* A two-dimensional sampler is called, the corresponding texture image is a
     419             :         //    non-power-of-two image[...], and either the texture wrap mode is not
     420             :         //    CLAMP_TO_EDGE, or the minification filter is neither NEAREST nor LINEAR."
     421             : 
     422             :         // "* A cube map sampler is called, any of the corresponding texture images are
     423             :         //    non-power-of-two images, and either the texture wrap mode is not
     424             :         //    CLAMP_TO_EDGE, or the minification filter is neither NEAREST nor LINEAR."
     425           0 :         if (!baseImageInfo.IsPowerOfTwo()) {
     426           0 :             TexWrap wrapS = sampler ? sampler->mWrapS : mWrapS;
     427           0 :             TexWrap wrapT = sampler ? sampler->mWrapT : mWrapT;
     428             :             // "either the texture wrap mode is not CLAMP_TO_EDGE"
     429           0 :             if (wrapS != LOCAL_GL_CLAMP_TO_EDGE ||
     430           0 :                 wrapT != LOCAL_GL_CLAMP_TO_EDGE)
     431             :             {
     432           0 :                 *out_reason = "Non-power-of-two textures must have a wrap mode of"
     433             :                               " CLAMP_TO_EDGE.";
     434           0 :                 return false;
     435             :             }
     436             : 
     437             :             // "or the minification filter is neither NEAREST nor LINEAR"
     438           0 :             if (requiresMipmap) {
     439           0 :                 *out_reason = "Mipmapping requires power-of-two textures.";
     440           0 :                 return false;
     441             :             }
     442             :         }
     443             : 
     444             :         // "* A cube map sampler is called, and either the corresponding cube map texture
     445             :         //    image is not cube complete, or TEXTURE_MIN_FILTER is one that requires a
     446             :         //    mipmap and the texture is not mipmap cube complete."
     447             :         // (already covered)
     448             :     }
     449             : 
     450           0 :     if (!EnsureLevelInitialized(funcName, mBaseMipmapLevel)) {
     451           0 :         *out_initFailed = true;
     452           0 :         return false;
     453             :     }
     454             : 
     455           0 :     return true;
     456             : }
     457             : 
     458             : bool
     459           0 : WebGLTexture::MaxEffectiveMipmapLevel(uint32_t texUnit, uint32_t* const out) const
     460             : {
     461           0 :     WebGLSampler* sampler = mContext->mBoundSamplers[texUnit];
     462           0 :     TexMinFilter minFilter = sampler ? sampler->mMinFilter : mMinFilter;
     463           0 :     if (minFilter == LOCAL_GL_NEAREST ||
     464           0 :         minFilter == LOCAL_GL_LINEAR)
     465             :     {
     466             :         // No extra mips used.
     467           0 :         *out = mBaseMipmapLevel;
     468           0 :         return true;
     469             :     }
     470             : 
     471           0 :     const auto& imageInfo = BaseImageInfo();
     472           0 :     if (!imageInfo.IsDefined())
     473           0 :         return false;
     474             : 
     475           0 :     uint32_t maxLevelBySize = mBaseMipmapLevel + imageInfo.PossibleMipmapLevels() - 1;
     476           0 :     *out = std::min<uint32_t>(maxLevelBySize, mMaxMipmapLevel);
     477           0 :     return true;
     478             : }
     479             : 
     480             : bool
     481           0 : WebGLTexture::GetFakeBlackType(const char* funcName, uint32_t texUnit,
     482             :                                FakeBlackType* const out_fakeBlack)
     483             : {
     484             :     const char* incompleteReason;
     485           0 :     bool initFailed = false;
     486           0 :     if (!IsComplete(funcName, texUnit, &incompleteReason, &initFailed)) {
     487           0 :         if (initFailed) {
     488           0 :             mContext->ErrorOutOfMemory("%s: Failed to initialize texture data.",
     489           0 :                                        funcName);
     490           0 :             return false; // The world just exploded.
     491             :         }
     492             : 
     493           0 :         if (incompleteReason) {
     494           0 :             mContext->GenerateWarning("%s: Active texture %u for target 0x%04x is"
     495             :                                       " 'incomplete', and will be rendered as"
     496             :                                       " RGBA(0,0,0,1), as per the GLES 2.0.24 $3.8.2: %s",
     497             :                                       funcName, texUnit, mTarget.get(),
     498           0 :                                       incompleteReason);
     499             :         }
     500           0 :         *out_fakeBlack = FakeBlackType::RGBA0001;
     501           0 :         return true;
     502             :     }
     503             : 
     504             : 
     505           0 :     *out_fakeBlack = FakeBlackType::None;
     506           0 :     return true;
     507             : }
     508             : 
     509             : static void
     510           0 : SetSwizzle(gl::GLContext* gl, TexTarget target, const GLint* swizzle)
     511             : {
     512             :     static const GLint kNoSwizzle[4] = { LOCAL_GL_RED, LOCAL_GL_GREEN, LOCAL_GL_BLUE,
     513             :                                          LOCAL_GL_ALPHA };
     514           0 :     if (!swizzle) {
     515           0 :         swizzle = kNoSwizzle;
     516           0 :     } else if (!gl->IsSupported(gl::GLFeature::texture_swizzle)) {
     517           0 :         MOZ_CRASH("GFX: Needs swizzle feature to swizzle!");
     518             :     }
     519             : 
     520           0 :     gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_SWIZZLE_R, swizzle[0]);
     521           0 :     gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_SWIZZLE_G, swizzle[1]);
     522           0 :     gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_SWIZZLE_B, swizzle[2]);
     523           0 :     gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_SWIZZLE_A, swizzle[3]);
     524           0 : }
     525             : 
     526             : bool
     527           0 : WebGLTexture::ResolveForDraw(const char* funcName, uint32_t texUnit,
     528             :                              FakeBlackType* const out_fakeBlack)
     529             : {
     530           0 :     if (!mIsResolved) {
     531           0 :         if (!GetFakeBlackType(funcName, texUnit, &mResolved_FakeBlack))
     532           0 :             return false;
     533             : 
     534             :         // Check which swizzle we should use. Since the texture must be complete at this
     535             :         // point, just grab the format off any valid image.
     536           0 :         const GLint* newSwizzle = nullptr;
     537           0 :         if (mResolved_FakeBlack == FakeBlackType::None) {
     538           0 :             const auto& cur = ImageInfoAtFace(0, mBaseMipmapLevel);
     539           0 :             newSwizzle = cur.mFormat->textureSwizzleRGBA;
     540             :         }
     541             : 
     542             :         // Only set the swizzle if it changed since last time we did it.
     543           0 :         if (newSwizzle != mResolved_Swizzle) {
     544           0 :             mResolved_Swizzle = newSwizzle;
     545             : 
     546             :             // Set the new swizzle!
     547           0 :             mContext->gl->fActiveTexture(LOCAL_GL_TEXTURE0 + texUnit);
     548           0 :             SetSwizzle(mContext->gl, mTarget, mResolved_Swizzle);
     549           0 :             mContext->gl->fActiveTexture(LOCAL_GL_TEXTURE0 + mContext->mActiveTexture);
     550             :         }
     551             : 
     552           0 :         mIsResolved = true;
     553             :     }
     554             : 
     555           0 :     *out_fakeBlack = mResolved_FakeBlack;
     556           0 :     return true;
     557             : }
     558             : 
     559             : bool
     560           0 : WebGLTexture::EnsureImageDataInitialized(const char* funcName, TexImageTarget target,
     561             :                                          uint32_t level)
     562             : {
     563           0 :     auto& imageInfo = ImageInfoAt(target, level);
     564           0 :     if (!imageInfo.IsDefined())
     565           0 :         return true;
     566             : 
     567           0 :     if (imageInfo.IsDataInitialized())
     568           0 :         return true;
     569             : 
     570           0 :     return InitializeImageData(funcName, target, level);
     571             : }
     572             : 
     573             : bool
     574           0 : WebGLTexture::EnsureLevelInitialized(const char* funcName, uint32_t level)
     575             : {
     576           0 :     if (mTarget != LOCAL_GL_TEXTURE_CUBE_MAP)
     577           0 :         return EnsureImageDataInitialized(funcName, mTarget.get(), level);
     578             : 
     579           0 :     for (GLenum texImageTarget = LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X;
     580           0 :          texImageTarget <= LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
     581             :          ++texImageTarget)
     582             :     {
     583           0 :         if (!EnsureImageDataInitialized(funcName, texImageTarget, level))
     584           0 :             return false;
     585             :     }
     586           0 :     return true;
     587             : }
     588             : 
     589             : static void
     590           0 : ZeroANGLEDepthTexture(WebGLContext* webgl, GLuint tex,
     591             :                       const webgl::FormatUsageInfo* usage, uint32_t width,
     592             :                       uint32_t height)
     593             : {
     594           0 :     const auto& format = usage->format;
     595           0 :     GLenum attachPoint = 0;
     596           0 :     GLbitfield clearBits = 0;
     597             : 
     598           0 :     if (format->d) {
     599           0 :         attachPoint = LOCAL_GL_DEPTH_ATTACHMENT;
     600           0 :         clearBits |= LOCAL_GL_DEPTH_BUFFER_BIT;
     601             :     }
     602             : 
     603           0 :     if (format->s) {
     604           0 :         attachPoint = (format->d ? LOCAL_GL_DEPTH_STENCIL_ATTACHMENT
     605             :                                  : LOCAL_GL_STENCIL_ATTACHMENT);
     606           0 :         clearBits |= LOCAL_GL_STENCIL_BUFFER_BIT;
     607             :     }
     608             : 
     609           0 :     MOZ_RELEASE_ASSERT(attachPoint && clearBits, "GFX: No bits cleared.");
     610             : 
     611             :     ////
     612           0 :     const auto& gl = webgl->gl;
     613           0 :     MOZ_ASSERT(gl->IsCurrent());
     614             : 
     615           0 :     gl::ScopedFramebuffer scopedFB(gl);
     616           0 :     const gl::ScopedBindFramebuffer scopedBindFB(gl, scopedFB.FB());
     617             : 
     618           0 :     gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, attachPoint, LOCAL_GL_TEXTURE_2D,
     619           0 :                               tex, 0);
     620             : 
     621           0 :     const auto& status = gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
     622           0 :     MOZ_RELEASE_ASSERT(status == LOCAL_GL_FRAMEBUFFER_COMPLETE);
     623             : 
     624             :     ////
     625             : 
     626           0 :     const bool fakeNoAlpha = false;
     627           0 :     webgl->ForceClearFramebufferWithDefaultValues(clearBits, fakeNoAlpha);
     628           0 : }
     629             : 
     630             : static bool
     631           0 : ZeroTextureData(WebGLContext* webgl, const char* funcName, GLuint tex,
     632             :                 TexImageTarget target, uint32_t level,
     633             :                 const webgl::FormatUsageInfo* usage, uint32_t width, uint32_t height,
     634             :                 uint32_t depth)
     635             : {
     636             :     // This has two usecases:
     637             :     // 1. Lazy zeroing of uninitialized textures:
     638             :     //    a. Before draw, when FakeBlack isn't viable. (TexStorage + Draw*)
     639             :     //    b. Before partial upload. (TexStorage + TexSubImage)
     640             :     // 2. Zero subrects from out-of-bounds blits. (CopyTex(Sub)Image)
     641             : 
     642             :     // We have no sympathy for any of these cases.
     643             : 
     644             :     // "Doctor, it hurts when I do this!" "Well don't do that!"
     645             :     webgl->GenerateWarning("%s: This operation requires zeroing texture data. This is"
     646             :                            " slow.",
     647           0 :                            funcName);
     648             : 
     649           0 :     gl::GLContext* gl = webgl->GL();
     650           0 :     gl->MakeCurrent();
     651             : 
     652             :     GLenum scopeBindTarget;
     653           0 :     switch (target.get()) {
     654             :     case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X:
     655             :     case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
     656             :     case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
     657             :     case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
     658             :     case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
     659             :     case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
     660           0 :         scopeBindTarget = LOCAL_GL_TEXTURE_CUBE_MAP;
     661           0 :         break;
     662             :     default:
     663           0 :         scopeBindTarget = target.get();
     664           0 :         break;
     665             :     }
     666           0 :     const gl::ScopedBindTexture scopeBindTexture(gl, tex, scopeBindTarget);
     667           0 :     auto compression = usage->format->compression;
     668           0 :     if (compression) {
     669           0 :         auto sizedFormat = usage->format->sizedFormat;
     670           0 :         MOZ_RELEASE_ASSERT(sizedFormat, "GFX: texture sized format not set");
     671             : 
     672           0 :         const auto fnSizeInBlocks = [](CheckedUint32 pixels, uint8_t pixelsPerBlock) {
     673           0 :             return RoundUpToMultipleOf(pixels, pixelsPerBlock) / pixelsPerBlock;
     674           0 :         };
     675             : 
     676           0 :         const auto widthBlocks = fnSizeInBlocks(width, compression->blockWidth);
     677           0 :         const auto heightBlocks = fnSizeInBlocks(height, compression->blockHeight);
     678             : 
     679           0 :         CheckedUint32 checkedByteCount = compression->bytesPerBlock;
     680           0 :         checkedByteCount *= widthBlocks;
     681           0 :         checkedByteCount *= heightBlocks;
     682           0 :         checkedByteCount *= depth;
     683             : 
     684           0 :         if (!checkedByteCount.isValid())
     685           0 :             return false;
     686             : 
     687           0 :         const size_t byteCount = checkedByteCount.value();
     688             : 
     689           0 :         UniqueBuffer zeros = calloc(1, byteCount);
     690           0 :         if (!zeros)
     691           0 :             return false;
     692             : 
     693           0 :         ScopedUnpackReset scopedReset(webgl);
     694           0 :         gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 1); // Don't bother with striding it
     695             :                                                         // well.
     696             : 
     697           0 :         const auto error = DoCompressedTexSubImage(gl, target.get(), level, 0, 0, 0,
     698             :                                                    width, height, depth, sizedFormat,
     699           0 :                                                    byteCount, zeros.get());
     700           0 :         return !error;
     701             :     }
     702             : 
     703           0 :     const auto driverUnpackInfo = usage->idealUnpack;
     704           0 :     MOZ_RELEASE_ASSERT(driverUnpackInfo, "GFX: ideal unpack info not set.");
     705             : 
     706           0 :     if (webgl->IsExtensionEnabled(WebGLExtensionID::WEBGL_depth_texture) &&
     707           0 :         gl->IsANGLE() &&
     708           0 :         usage->format->d)
     709             :     {
     710             :         // ANGLE_depth_texture does not allow uploads, so we have to clear.
     711             :         // (Restriction because of D3D9)
     712           0 :         MOZ_ASSERT(target == LOCAL_GL_TEXTURE_2D);
     713           0 :         MOZ_ASSERT(level == 0);
     714           0 :         ZeroANGLEDepthTexture(webgl, tex, usage, width, height);
     715           0 :         return true;
     716             :     }
     717             : 
     718           0 :     const webgl::PackingInfo packing = driverUnpackInfo->ToPacking();
     719             : 
     720           0 :     const auto bytesPerPixel = webgl::BytesPerPixel(packing);
     721             : 
     722           0 :     CheckedUint32 checkedByteCount = bytesPerPixel;
     723           0 :     checkedByteCount *= width;
     724           0 :     checkedByteCount *= height;
     725           0 :     checkedByteCount *= depth;
     726             : 
     727           0 :     if (!checkedByteCount.isValid())
     728           0 :         return false;
     729             : 
     730           0 :     const size_t byteCount = checkedByteCount.value();
     731             : 
     732           0 :     UniqueBuffer zeros = calloc(1, byteCount);
     733           0 :     if (!zeros)
     734           0 :         return false;
     735             : 
     736           0 :     ScopedUnpackReset scopedReset(webgl);
     737           0 :     gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 1); // Don't bother with striding it well.
     738           0 :     const auto error = DoTexSubImage(gl, target, level, 0, 0, 0, width, height, depth,
     739           0 :                                      packing, zeros.get());
     740           0 :     return !error;
     741             : }
     742             : 
     743             : bool
     744           0 : WebGLTexture::InitializeImageData(const char* funcName, TexImageTarget target,
     745             :                                   uint32_t level)
     746             : {
     747           0 :     auto& imageInfo = ImageInfoAt(target, level);
     748           0 :     MOZ_ASSERT(imageInfo.IsDefined());
     749           0 :     MOZ_ASSERT(!imageInfo.IsDataInitialized());
     750             : 
     751           0 :     const auto& usage = imageInfo.mFormat;
     752           0 :     const auto& width = imageInfo.mWidth;
     753           0 :     const auto& height = imageInfo.mHeight;
     754           0 :     const auto& depth = imageInfo.mDepth;
     755             : 
     756           0 :     if (!ZeroTextureData(mContext, funcName, mGLName, target, level, usage, width, height,
     757             :                          depth))
     758             :     {
     759           0 :         return false;
     760             :     }
     761             : 
     762           0 :     imageInfo.SetIsDataInitialized(true, this);
     763           0 :     return true;
     764             : }
     765             : 
     766             : void
     767           0 : WebGLTexture::ClampLevelBaseAndMax()
     768             : {
     769           0 :     if (!mImmutable)
     770           0 :         return;
     771             : 
     772             :     // GLES 3.0.4, p158:
     773             :     // "For immutable-format textures, `level_base` is clamped to the range
     774             :     //  `[0, levels-1]`, `level_max` is then clamped to the range `
     775             :     //  `[level_base, levels-1]`, where `levels` is the parameter passed to
     776             :     //   TexStorage* for the texture object."
     777           0 :     mBaseMipmapLevel = Clamp<uint32_t>(mBaseMipmapLevel, 0, mImmutableLevelCount - 1);
     778           0 :     mMaxMipmapLevel = Clamp<uint32_t>(mMaxMipmapLevel, mBaseMipmapLevel,
     779           0 :                                       mImmutableLevelCount - 1);
     780             : }
     781             : 
     782             : void
     783           0 : WebGLTexture::PopulateMipChain(const char* funcName, uint32_t firstLevel,
     784             :                                uint32_t lastLevel)
     785             : {
     786           0 :     const ImageInfo& baseImageInfo = ImageInfoAtFace(0, firstLevel);
     787           0 :     MOZ_ASSERT(baseImageInfo.IsDefined());
     788             : 
     789           0 :     uint32_t refWidth = baseImageInfo.mWidth;
     790           0 :     uint32_t refHeight = baseImageInfo.mHeight;
     791           0 :     uint32_t refDepth = baseImageInfo.mDepth;
     792           0 :     if (!refWidth || !refHeight || !refDepth)
     793           0 :         return;
     794             : 
     795           0 :     for (uint32_t level = firstLevel + 1; level <= lastLevel; level++) {
     796           0 :         bool isMinimal = (refWidth == 1 &&
     797           0 :                           refHeight == 1);
     798           0 :         if (mTarget == LOCAL_GL_TEXTURE_3D) {
     799           0 :             isMinimal &= (refDepth == 1);
     800             :         }
     801             : 
     802             :         // Higher levels are unaffected.
     803           0 :         if (isMinimal)
     804           0 :             break;
     805             : 
     806           0 :         refWidth = std::max(uint32_t(1), refWidth / 2);
     807           0 :         refHeight = std::max(uint32_t(1), refHeight / 2);
     808           0 :         if (mTarget == LOCAL_GL_TEXTURE_3D) { // But not TEXTURE_2D_ARRAY!
     809           0 :             refDepth = std::max(uint32_t(1), refDepth / 2);
     810             :         }
     811             : 
     812           0 :         const ImageInfo cur(baseImageInfo.mFormat, refWidth, refHeight, refDepth,
     813           0 :                             baseImageInfo.IsDataInitialized());
     814             : 
     815           0 :         SetImageInfosAtLevel(funcName, level, cur);
     816             :     }
     817             : }
     818             : 
     819             : //////////////////////////////////////////////////////////////////////////////////////////
     820             : // GL calls
     821             : 
     822             : bool
     823           0 : WebGLTexture::BindTexture(TexTarget texTarget)
     824             : {
     825           0 :     if (IsDeleted()) {
     826           0 :         mContext->ErrorInvalidOperation("bindTexture: Cannot bind a deleted object.");
     827           0 :         return false;
     828             :     }
     829             : 
     830           0 :     const bool isFirstBinding = !HasEverBeenBound();
     831           0 :     if (!isFirstBinding && mTarget != texTarget) {
     832           0 :         mContext->ErrorInvalidOperation("bindTexture: This texture has already been bound"
     833           0 :                                         " to a different target.");
     834           0 :         return false;
     835             :     }
     836             : 
     837           0 :     mTarget = texTarget;
     838             : 
     839           0 :     mContext->gl->fBindTexture(mTarget.get(), mGLName);
     840             : 
     841           0 :     if (isFirstBinding) {
     842           0 :         mFaceCount = IsCubeMap() ? 6 : 1;
     843             : 
     844           0 :         gl::GLContext* gl = mContext->gl;
     845             : 
     846             :         // Thanks to the WebKit people for finding this out: GL_TEXTURE_WRAP_R
     847             :         // is not present in GLES 2, but is present in GL and it seems as if for
     848             :         // cube maps we need to set it to GL_CLAMP_TO_EDGE to get the expected
     849             :         // GLES behavior.
     850             :         // If we are WebGL 2 though, we'll want to leave it as REPEAT.
     851           0 :         const bool hasWrapR = gl->IsSupported(gl::GLFeature::texture_3D);
     852           0 :         if (IsCubeMap() && hasWrapR && !mContext->IsWebGL2()) {
     853           0 :             gl->fTexParameteri(texTarget.get(), LOCAL_GL_TEXTURE_WRAP_R,
     854           0 :                                LOCAL_GL_CLAMP_TO_EDGE);
     855             :         }
     856             :     }
     857             : 
     858           0 :     return true;
     859             : }
     860             : 
     861             : 
     862             : void
     863           0 : WebGLTexture::GenerateMipmap(TexTarget texTarget)
     864             : {
     865           0 :     const char funcName[] = "generateMipmap";
     866             :     // GLES 3.0.4 p160:
     867             :     // "Mipmap generation replaces texel array levels level base + 1 through q with arrays
     868             :     //  derived from the level base array, regardless of their previous contents. All
     869             :     //  other mipmap arrays, including the level base array, are left unchanged by this
     870             :     //  computation."
     871           0 :     const ImageInfo& baseImageInfo = BaseImageInfo();
     872           0 :     if (!baseImageInfo.IsDefined()) {
     873           0 :         mContext->ErrorInvalidOperation("%s: The base level of the texture is not"
     874             :                                         " defined.",
     875           0 :                                         funcName);
     876           0 :         return;
     877             :     }
     878             : 
     879           0 :     if (IsCubeMap() && !IsCubeComplete()) {
     880           0 :       mContext->ErrorInvalidOperation("%s: Cube maps must be \"cube complete\".",
     881           0 :                                       funcName);
     882           0 :       return;
     883             :     }
     884             : 
     885           0 :     if (!mContext->IsWebGL2() && !baseImageInfo.IsPowerOfTwo()) {
     886           0 :         mContext->ErrorInvalidOperation("%s: The base level of the texture does not have"
     887             :                                         " power-of-two dimensions.",
     888           0 :                                         funcName);
     889           0 :         return;
     890             :     }
     891             : 
     892           0 :     auto format = baseImageInfo.mFormat->format;
     893           0 :     if (format->compression) {
     894           0 :         mContext->ErrorInvalidOperation("%s: Texture data at base level is compressed.",
     895           0 :                                         funcName);
     896           0 :         return;
     897             :     }
     898             : 
     899           0 :     if (format->d) {
     900           0 :         mContext->ErrorInvalidOperation("%s: Depth textures are not supported.",
     901           0 :                                         funcName);
     902           0 :         return;
     903             :     }
     904             : 
     905             :     // OpenGL ES 3.0.4 p160:
     906             :     // If the level base array was not specified with an unsized internal format from
     907             :     // table 3.3 or a sized internal format that is both color-renderable and
     908             :     // texture-filterable according to table 3.13, an INVALID_OPERATION error
     909             :     // is generated.
     910           0 :     const auto usage = baseImageInfo.mFormat;
     911           0 :     bool canGenerateMipmap = (usage->IsRenderable() && usage->isFilterable);
     912           0 :     switch (usage->format->effectiveFormat) {
     913             :     case webgl::EffectiveFormat::Luminance8:
     914             :     case webgl::EffectiveFormat::Alpha8:
     915             :     case webgl::EffectiveFormat::Luminance8Alpha8:
     916             :         // Non-color-renderable formats from Table 3.3.
     917           0 :         canGenerateMipmap = true;
     918           0 :         break;
     919             :     default:
     920           0 :         break;
     921             :     }
     922             : 
     923           0 :     if (!canGenerateMipmap) {
     924           0 :         mContext->ErrorInvalidOperation("%s: Texture at base level is not unsized"
     925             :                                         " internal format or is not"
     926             :                                         " color-renderable or texture-filterable.",
     927           0 :                                         funcName);
     928           0 :         return;
     929             :     }
     930             : 
     931             :     // Done with validation. Do the operation.
     932             : 
     933           0 :     mContext->MakeContextCurrent();
     934           0 :     gl::GLContext* gl = mContext->gl;
     935             : 
     936           0 :     if (gl->WorkAroundDriverBugs()) {
     937             :         // bug 696495 - to work around failures in the texture-mips.html test on various drivers, we
     938             :         // set the minification filter before calling glGenerateMipmap. This should not carry a significant performance
     939             :         // overhead so we do it unconditionally.
     940             :         //
     941             :         // note that the choice of GL_NEAREST_MIPMAP_NEAREST really matters. See Chromium bug 101105.
     942           0 :         gl->fTexParameteri(texTarget.get(), LOCAL_GL_TEXTURE_MIN_FILTER,
     943           0 :                            LOCAL_GL_NEAREST_MIPMAP_NEAREST);
     944           0 :         gl->fGenerateMipmap(texTarget.get());
     945           0 :         gl->fTexParameteri(texTarget.get(), LOCAL_GL_TEXTURE_MIN_FILTER,
     946           0 :                            mMinFilter.get());
     947             :     } else {
     948           0 :         gl->fGenerateMipmap(texTarget.get());
     949             :     }
     950             : 
     951             :     // Record the results.
     952             :     // Note that we don't use MaxEffectiveMipmapLevel() here, since that returns
     953             :     // mBaseMipmapLevel if the min filter doesn't require mipmaps.
     954           0 :     const uint32_t maxLevel = mBaseMipmapLevel + baseImageInfo.PossibleMipmapLevels() - 1;
     955           0 :     PopulateMipChain(funcName, mBaseMipmapLevel, maxLevel);
     956             : }
     957             : 
     958             : JS::Value
     959           0 : WebGLTexture::GetTexParameter(TexTarget texTarget, GLenum pname)
     960             : {
     961           0 :     mContext->MakeContextCurrent();
     962             : 
     963           0 :     GLint i = 0;
     964           0 :     GLfloat f = 0.0f;
     965             : 
     966           0 :     switch (pname) {
     967             :     case LOCAL_GL_TEXTURE_MIN_FILTER:
     968           0 :         return JS::NumberValue(uint32_t(mMinFilter.get()));
     969             : 
     970             :     case LOCAL_GL_TEXTURE_MAG_FILTER:
     971           0 :         return JS::NumberValue(uint32_t(mMagFilter.get()));
     972             : 
     973             :     case LOCAL_GL_TEXTURE_WRAP_S:
     974           0 :         return JS::NumberValue(uint32_t(mWrapS.get()));
     975             : 
     976             :     case LOCAL_GL_TEXTURE_WRAP_T:
     977           0 :         return JS::NumberValue(uint32_t(mWrapT.get()));
     978             : 
     979             :     case LOCAL_GL_TEXTURE_BASE_LEVEL:
     980           0 :         return JS::NumberValue(mBaseMipmapLevel);
     981             : 
     982             :     case LOCAL_GL_TEXTURE_COMPARE_MODE:
     983           0 :         return JS::NumberValue(uint32_t(mTexCompareMode));
     984             : 
     985             :     case LOCAL_GL_TEXTURE_MAX_LEVEL:
     986           0 :         return JS::NumberValue(mMaxMipmapLevel);
     987             : 
     988             :     case LOCAL_GL_TEXTURE_IMMUTABLE_FORMAT:
     989           0 :         return JS::BooleanValue(mImmutable);
     990             : 
     991             :     case LOCAL_GL_TEXTURE_IMMUTABLE_LEVELS:
     992           0 :         return JS::NumberValue(uint32_t(mImmutableLevelCount));
     993             : 
     994             :     case LOCAL_GL_TEXTURE_COMPARE_FUNC:
     995             :     case LOCAL_GL_TEXTURE_WRAP_R:
     996           0 :         mContext->gl->fGetTexParameteriv(texTarget.get(), pname, &i);
     997           0 :         return JS::NumberValue(uint32_t(i));
     998             : 
     999             :     case LOCAL_GL_TEXTURE_MAX_ANISOTROPY_EXT:
    1000             :     case LOCAL_GL_TEXTURE_MAX_LOD:
    1001             :     case LOCAL_GL_TEXTURE_MIN_LOD:
    1002           0 :         mContext->gl->fGetTexParameterfv(texTarget.get(), pname, &f);
    1003           0 :         return JS::NumberValue(float(f));
    1004             : 
    1005             :     default:
    1006           0 :         MOZ_CRASH("GFX: Unhandled pname.");
    1007             :     }
    1008             : }
    1009             : 
    1010             : bool
    1011           0 : WebGLTexture::IsTexture() const
    1012             : {
    1013           0 :     return HasEverBeenBound() && !IsDeleted();
    1014             : }
    1015             : 
    1016             : // Here we have to support all pnames with both int and float params.
    1017             : // See this discussion:
    1018             : //   https://www.khronos.org/webgl/public-mailing-list/archives/1008/msg00014.html
    1019             : void
    1020           0 : WebGLTexture::TexParameter(TexTarget texTarget, GLenum pname, const FloatOrInt& param)
    1021             : {
    1022           0 :     bool isPNameValid = false;
    1023           0 :     switch (pname) {
    1024             :     // GLES 2.0.25 p76:
    1025             :     case LOCAL_GL_TEXTURE_WRAP_S:
    1026             :     case LOCAL_GL_TEXTURE_WRAP_T:
    1027             :     case LOCAL_GL_TEXTURE_MIN_FILTER:
    1028             :     case LOCAL_GL_TEXTURE_MAG_FILTER:
    1029           0 :         isPNameValid = true;
    1030           0 :         break;
    1031             : 
    1032             :     // GLES 3.0.4 p149-150:
    1033             :     case LOCAL_GL_TEXTURE_BASE_LEVEL:
    1034             :     case LOCAL_GL_TEXTURE_COMPARE_MODE:
    1035             :     case LOCAL_GL_TEXTURE_COMPARE_FUNC:
    1036             :     case LOCAL_GL_TEXTURE_MAX_LEVEL:
    1037             :     case LOCAL_GL_TEXTURE_MAX_LOD:
    1038             :     case LOCAL_GL_TEXTURE_MIN_LOD:
    1039             :     case LOCAL_GL_TEXTURE_WRAP_R:
    1040           0 :         if (mContext->IsWebGL2())
    1041           0 :             isPNameValid = true;
    1042           0 :         break;
    1043             : 
    1044             :     case LOCAL_GL_TEXTURE_MAX_ANISOTROPY_EXT:
    1045           0 :         if (mContext->IsExtensionEnabled(WebGLExtensionID::EXT_texture_filter_anisotropic))
    1046           0 :             isPNameValid = true;
    1047           0 :         break;
    1048             :     }
    1049             : 
    1050           0 :     if (!isPNameValid) {
    1051           0 :         mContext->ErrorInvalidEnumInfo("texParameter: pname", pname);
    1052           0 :         return;
    1053             :     }
    1054             : 
    1055             :     ////////////////
    1056             :     // Validate params and invalidate if needed.
    1057             : 
    1058           0 :     bool paramBadEnum = false;
    1059           0 :     bool paramBadValue = false;
    1060             : 
    1061           0 :     switch (pname) {
    1062             :     case LOCAL_GL_TEXTURE_BASE_LEVEL:
    1063             :     case LOCAL_GL_TEXTURE_MAX_LEVEL:
    1064           0 :         paramBadValue = (param.i < 0);
    1065           0 :         break;
    1066             : 
    1067             :     case LOCAL_GL_TEXTURE_COMPARE_MODE:
    1068           0 :         paramBadValue = (param.i != LOCAL_GL_NONE &&
    1069           0 :                          param.i != LOCAL_GL_COMPARE_REF_TO_TEXTURE);
    1070           0 :         break;
    1071             : 
    1072             :     case LOCAL_GL_TEXTURE_COMPARE_FUNC:
    1073           0 :         switch (param.i) {
    1074             :         case LOCAL_GL_LEQUAL:
    1075             :         case LOCAL_GL_GEQUAL:
    1076             :         case LOCAL_GL_LESS:
    1077             :         case LOCAL_GL_GREATER:
    1078             :         case LOCAL_GL_EQUAL:
    1079             :         case LOCAL_GL_NOTEQUAL:
    1080             :         case LOCAL_GL_ALWAYS:
    1081             :         case LOCAL_GL_NEVER:
    1082           0 :             break;
    1083             : 
    1084             :         default:
    1085           0 :             paramBadValue = true;
    1086           0 :             break;
    1087             :         }
    1088           0 :         break;
    1089             : 
    1090             :     case LOCAL_GL_TEXTURE_MIN_FILTER:
    1091           0 :         switch (param.i) {
    1092             :         case LOCAL_GL_NEAREST:
    1093             :         case LOCAL_GL_LINEAR:
    1094             :         case LOCAL_GL_NEAREST_MIPMAP_NEAREST:
    1095             :         case LOCAL_GL_LINEAR_MIPMAP_NEAREST:
    1096             :         case LOCAL_GL_NEAREST_MIPMAP_LINEAR:
    1097             :         case LOCAL_GL_LINEAR_MIPMAP_LINEAR:
    1098           0 :             break;
    1099             : 
    1100             :         default:
    1101           0 :             paramBadEnum = true;
    1102           0 :             break;
    1103             :         }
    1104           0 :         break;
    1105             : 
    1106             :     case LOCAL_GL_TEXTURE_MAG_FILTER:
    1107           0 :         switch (param.i) {
    1108             :         case LOCAL_GL_NEAREST:
    1109             :         case LOCAL_GL_LINEAR:
    1110           0 :             break;
    1111             : 
    1112             :         default:
    1113           0 :             paramBadEnum = true;
    1114           0 :             break;
    1115             :         }
    1116           0 :         break;
    1117             : 
    1118             :     case LOCAL_GL_TEXTURE_WRAP_S:
    1119             :     case LOCAL_GL_TEXTURE_WRAP_T:
    1120             :     case LOCAL_GL_TEXTURE_WRAP_R:
    1121           0 :         switch (param.i) {
    1122             :         case LOCAL_GL_CLAMP_TO_EDGE:
    1123             :         case LOCAL_GL_MIRRORED_REPEAT:
    1124             :         case LOCAL_GL_REPEAT:
    1125           0 :             break;
    1126             : 
    1127             :         default:
    1128           0 :             paramBadEnum = true;
    1129           0 :             break;
    1130             :         }
    1131           0 :         break;
    1132             : 
    1133             :     case LOCAL_GL_TEXTURE_MAX_ANISOTROPY_EXT:
    1134           0 :         if (param.f < 1.0f)
    1135           0 :             paramBadValue = true;
    1136             : 
    1137           0 :         break;
    1138             :     }
    1139             : 
    1140           0 :     if (paramBadEnum) {
    1141           0 :         if (!param.isFloat) {
    1142           0 :             mContext->ErrorInvalidEnum("texParameteri: pname 0x%04x: Invalid param"
    1143             :                                        " 0x%04x.",
    1144           0 :                                        pname, param.i);
    1145             :         } else {
    1146           0 :             mContext->ErrorInvalidEnum("texParameterf: pname 0x%04x: Invalid param %g.",
    1147           0 :                                        pname, param.f);
    1148             :         }
    1149           0 :         return;
    1150             :     }
    1151             : 
    1152           0 :     if (paramBadValue) {
    1153           0 :         if (!param.isFloat) {
    1154           0 :             mContext->ErrorInvalidValue("texParameteri: pname 0x%04x: Invalid param %i"
    1155             :                                         " (0x%x).",
    1156           0 :                                         pname, param.i, param.i);
    1157             :         } else {
    1158           0 :             mContext->ErrorInvalidValue("texParameterf: pname 0x%04x: Invalid param %g.",
    1159           0 :                                         pname, param.f);
    1160             :         }
    1161           0 :         return;
    1162             :     }
    1163             : 
    1164             :     ////////////////
    1165             :     // Store any needed values
    1166             : 
    1167           0 :     FloatOrInt clamped = param;
    1168           0 :     switch (pname) {
    1169             :     case LOCAL_GL_TEXTURE_BASE_LEVEL:
    1170           0 :         mBaseMipmapLevel = clamped.i;
    1171           0 :         ClampLevelBaseAndMax();
    1172           0 :         clamped = FloatOrInt(GLint(mBaseMipmapLevel));
    1173           0 :         break;
    1174             : 
    1175             :     case LOCAL_GL_TEXTURE_MAX_LEVEL:
    1176           0 :         mMaxMipmapLevel = clamped.i;
    1177           0 :         ClampLevelBaseAndMax();
    1178           0 :         clamped = FloatOrInt(GLint(mMaxMipmapLevel));
    1179           0 :         break;
    1180             : 
    1181             :     case LOCAL_GL_TEXTURE_MIN_FILTER:
    1182           0 :         mMinFilter = clamped.i;
    1183           0 :         break;
    1184             : 
    1185             :     case LOCAL_GL_TEXTURE_MAG_FILTER:
    1186           0 :         mMagFilter = clamped.i;
    1187           0 :         break;
    1188             : 
    1189             :     case LOCAL_GL_TEXTURE_WRAP_S:
    1190           0 :         mWrapS = clamped.i;
    1191           0 :         break;
    1192             : 
    1193             :     case LOCAL_GL_TEXTURE_WRAP_T:
    1194           0 :         mWrapT = clamped.i;
    1195           0 :         break;
    1196             : 
    1197             :     case LOCAL_GL_TEXTURE_COMPARE_MODE:
    1198           0 :         mTexCompareMode = clamped.i;
    1199           0 :         break;
    1200             : 
    1201             :     // We don't actually need to store the WRAP_R, since it doesn't change texture
    1202             :     // completeness rules.
    1203             :     }
    1204             : 
    1205             :     // Only a couple of pnames don't need to invalidate our resolve status cache.
    1206           0 :     switch (pname) {
    1207             :     case LOCAL_GL_TEXTURE_MAX_ANISOTROPY_EXT:
    1208             :     case LOCAL_GL_TEXTURE_WRAP_R:
    1209           0 :         break;
    1210             : 
    1211             :     default:
    1212           0 :         InvalidateResolveCache();
    1213           0 :         break;
    1214             :     }
    1215             : 
    1216             :     ////////////////
    1217             : 
    1218           0 :     mContext->MakeContextCurrent();
    1219           0 :     if (!clamped.isFloat)
    1220           0 :         mContext->gl->fTexParameteri(texTarget.get(), pname, clamped.i);
    1221             :     else
    1222           0 :         mContext->gl->fTexParameterf(texTarget.get(), pname, clamped.f);
    1223             : }
    1224             : 
    1225             : ////////////////////////////////////////////////////////////////////////////////
    1226             : 
    1227           0 : NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLTexture)
    1228             : 
    1229           0 : NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLTexture, AddRef)
    1230           0 : NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLTexture, Release)
    1231             : 
    1232             : } // namespace mozilla

Generated by: LCOV version 1.13