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

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; 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 "WebGLContext.h"
       7             : 
       8             : #include "GLContext.h"
       9             : #include "mozilla/CheckedInt.h"
      10             : #include "mozilla/UniquePtrExtensions.h"
      11             : #include "nsPrintfCString.h"
      12             : #include "WebGLBuffer.h"
      13             : #include "WebGLContextUtils.h"
      14             : #include "WebGLFramebuffer.h"
      15             : #include "WebGLProgram.h"
      16             : #include "WebGLRenderbuffer.h"
      17             : #include "WebGLShader.h"
      18             : #include "WebGLTexture.h"
      19             : #include "WebGLTransformFeedback.h"
      20             : #include "WebGLVertexArray.h"
      21             : #include "WebGLVertexAttribData.h"
      22             : 
      23             : #include <algorithm>
      24             : 
      25             : namespace mozilla {
      26             : 
      27             : // For a Tegra workaround.
      28             : static const int MAX_DRAW_CALLS_SINCE_FLUSH = 100;
      29             : 
      30             : ////////////////////////////////////////
      31             : 
      32             : class ScopedResolveTexturesForDraw
      33             : {
      34             :     struct TexRebindRequest
      35             :     {
      36             :         uint32_t texUnit;
      37             :         WebGLTexture* tex;
      38             :     };
      39             : 
      40             :     WebGLContext* const mWebGL;
      41             :     std::vector<TexRebindRequest> mRebindRequests;
      42             : 
      43             : public:
      44             :     ScopedResolveTexturesForDraw(WebGLContext* webgl, const char* funcName,
      45             :                                  bool* const out_error);
      46             :     ~ScopedResolveTexturesForDraw();
      47             : };
      48             : 
      49             : bool
      50           0 : WebGLTexture::IsFeedback(WebGLContext* webgl, const char* funcName, uint32_t texUnit,
      51             :                          const std::vector<const WebGLFBAttachPoint*>& fbAttachments) const
      52             : {
      53           0 :     auto itr = fbAttachments.cbegin();
      54           0 :     for (; itr != fbAttachments.cend(); ++itr) {
      55           0 :         const auto& attach = *itr;
      56           0 :         if (attach->Texture() == this)
      57           0 :             break;
      58             :     }
      59             : 
      60           0 :     if (itr == fbAttachments.cend())
      61           0 :         return false;
      62             : 
      63             :     ////
      64             : 
      65           0 :     const auto minLevel = mBaseMipmapLevel;
      66             :     uint32_t maxLevel;
      67           0 :     if (!MaxEffectiveMipmapLevel(texUnit, &maxLevel)) {
      68             :         // No valid mips. Will need fake-black.
      69           0 :         return false;
      70             :     }
      71             : 
      72             :     ////
      73             : 
      74           0 :     for (; itr != fbAttachments.cend(); ++itr) {
      75           0 :         const auto& attach = *itr;
      76           0 :         if (attach->Texture() != this)
      77           0 :             continue;
      78             : 
      79           0 :         const auto dstLevel = attach->MipLevel();
      80             : 
      81           0 :         if (minLevel <= dstLevel && dstLevel <= maxLevel) {
      82           0 :             webgl->ErrorInvalidOperation("%s: Feedback loop detected between tex target"
      83             :                                          " 0x%04x, tex unit %u, levels %u-%u; and"
      84             :                                          " framebuffer attachment 0x%04x, level %u.",
      85             :                                          funcName, mTarget.get(), texUnit, minLevel,
      86           0 :                                          maxLevel, attach->mAttachmentPoint, dstLevel);
      87           0 :             return true;
      88             :         }
      89             :     }
      90             : 
      91           0 :     return false;
      92             : }
      93             : 
      94           0 : ScopedResolveTexturesForDraw::ScopedResolveTexturesForDraw(WebGLContext* webgl,
      95             :                                                            const char* funcName,
      96           0 :                                                            bool* const out_error)
      97           0 :     : mWebGL(webgl)
      98             : {
      99           0 :     MOZ_ASSERT(mWebGL->gl->IsCurrent());
     100             : 
     101           0 :     if (!mWebGL->mActiveProgramLinkInfo) {
     102           0 :         mWebGL->ErrorInvalidOperation("%s: The current program is not linked.", funcName);
     103           0 :         *out_error = true;
     104           0 :         return;
     105             :     }
     106             : 
     107           0 :     const std::vector<const WebGLFBAttachPoint*>* attachList = nullptr;
     108           0 :     const auto& fb = mWebGL->mBoundDrawFramebuffer;
     109           0 :     if (fb) {
     110           0 :         if (!fb->ValidateAndInitAttachments(funcName)) {
     111           0 :             *out_error = true;
     112           0 :             return;
     113             :         }
     114             : 
     115           0 :         attachList = &(fb->ResolvedCompleteData()->texDrawBuffers);
     116             :     } else {
     117           0 :         webgl->ClearBackbufferIfNeeded();
     118             :     }
     119             : 
     120           0 :     MOZ_ASSERT(mWebGL->mActiveProgramLinkInfo);
     121           0 :     const auto& uniformSamplers = mWebGL->mActiveProgramLinkInfo->uniformSamplers;
     122           0 :     for (const auto& uniform : uniformSamplers) {
     123           0 :         const auto& texList = *(uniform->mSamplerTexList);
     124             : 
     125           0 :         for (const auto& texUnit : uniform->mSamplerValues) {
     126           0 :             if (texUnit >= texList.Length())
     127           0 :                 continue;
     128             : 
     129           0 :             const auto& tex = texList[texUnit];
     130           0 :             if (!tex)
     131           0 :                 continue;
     132             : 
     133           0 :             if (attachList &&
     134           0 :                 tex->IsFeedback(mWebGL, funcName, texUnit, *attachList))
     135             :             {
     136           0 :                 *out_error = true;
     137           0 :                 return;
     138             :             }
     139             : 
     140             :             FakeBlackType fakeBlack;
     141           0 :             if (!tex->ResolveForDraw(funcName, texUnit, &fakeBlack)) {
     142           0 :                 mWebGL->ErrorOutOfMemory("%s: Failed to resolve textures for draw.",
     143           0 :                                          funcName);
     144           0 :                 *out_error = true;
     145           0 :                 return;
     146             :             }
     147             : 
     148           0 :             if (fakeBlack == FakeBlackType::None)
     149           0 :                 continue;
     150             : 
     151           0 :             if (!mWebGL->BindFakeBlack(texUnit, tex->Target(), fakeBlack)) {
     152           0 :                 mWebGL->ErrorOutOfMemory("%s: Failed to create fake black texture.",
     153           0 :                                          funcName);
     154           0 :                 *out_error = true;
     155           0 :                 return;
     156             :             }
     157             : 
     158           0 :             mRebindRequests.push_back({texUnit, tex});
     159             :         }
     160             :     }
     161             : 
     162           0 :     *out_error = false;
     163             : }
     164             : 
     165           0 : ScopedResolveTexturesForDraw::~ScopedResolveTexturesForDraw()
     166             : {
     167           0 :     if (!mRebindRequests.size())
     168           0 :         return;
     169             : 
     170           0 :     gl::GLContext* gl = mWebGL->gl;
     171             : 
     172           0 :     for (const auto& itr : mRebindRequests) {
     173           0 :         gl->fActiveTexture(LOCAL_GL_TEXTURE0 + itr.texUnit);
     174           0 :         gl->fBindTexture(itr.tex->Target().get(), itr.tex->mGLName);
     175             :     }
     176             : 
     177           0 :     gl->fActiveTexture(LOCAL_GL_TEXTURE0 + mWebGL->mActiveTexture);
     178           0 : }
     179             : 
     180             : bool
     181           0 : WebGLContext::BindFakeBlack(uint32_t texUnit, TexTarget target, FakeBlackType fakeBlack)
     182             : {
     183           0 :     MOZ_ASSERT(fakeBlack == FakeBlackType::RGBA0000 ||
     184             :                fakeBlack == FakeBlackType::RGBA0001);
     185             : 
     186           0 :     const auto fnGetSlot = [this, target, fakeBlack]() -> UniquePtr<FakeBlackTexture>*
     187           0 :     {
     188           0 :         switch (fakeBlack) {
     189             :         case FakeBlackType::RGBA0000:
     190           0 :             switch (target.get()) {
     191           0 :             case LOCAL_GL_TEXTURE_2D      : return &mFakeBlack_2D_0000;
     192           0 :             case LOCAL_GL_TEXTURE_CUBE_MAP: return &mFakeBlack_CubeMap_0000;
     193           0 :             case LOCAL_GL_TEXTURE_3D      : return &mFakeBlack_3D_0000;
     194           0 :             case LOCAL_GL_TEXTURE_2D_ARRAY: return &mFakeBlack_2D_Array_0000;
     195           0 :             default: return nullptr;
     196             :             }
     197             : 
     198             :         case FakeBlackType::RGBA0001:
     199           0 :             switch (target.get()) {
     200           0 :             case LOCAL_GL_TEXTURE_2D      : return &mFakeBlack_2D_0001;
     201           0 :             case LOCAL_GL_TEXTURE_CUBE_MAP: return &mFakeBlack_CubeMap_0001;
     202           0 :             case LOCAL_GL_TEXTURE_3D      : return &mFakeBlack_3D_0001;
     203           0 :             case LOCAL_GL_TEXTURE_2D_ARRAY: return &mFakeBlack_2D_Array_0001;
     204           0 :             default: return nullptr;
     205             :             }
     206             : 
     207             :         default:
     208           0 :             return nullptr;
     209             :         }
     210           0 :     };
     211             : 
     212           0 :     UniquePtr<FakeBlackTexture>* slot = fnGetSlot();
     213           0 :     if (!slot) {
     214           0 :         MOZ_CRASH("GFX: fnGetSlot failed.");
     215             :     }
     216           0 :     UniquePtr<FakeBlackTexture>& fakeBlackTex = *slot;
     217             : 
     218           0 :     if (!fakeBlackTex) {
     219           0 :         fakeBlackTex = FakeBlackTexture::Create(gl, target, fakeBlack);
     220           0 :         if (!fakeBlackTex) {
     221           0 :             return false;
     222             :         }
     223             :     }
     224             : 
     225           0 :     gl->fActiveTexture(LOCAL_GL_TEXTURE0 + texUnit);
     226           0 :     gl->fBindTexture(target.get(), fakeBlackTex->mGLName);
     227           0 :     gl->fActiveTexture(LOCAL_GL_TEXTURE0 + mActiveTexture);
     228           0 :     return true;
     229             : }
     230             : 
     231             : ////////////////////////////////////////
     232             : 
     233             : bool
     234           0 : WebGLContext::DrawInstanced_check(const char* info)
     235             : {
     236           0 :     MOZ_ASSERT(IsWebGL2() ||
     237             :                IsExtensionEnabled(WebGLExtensionID::ANGLE_instanced_arrays));
     238           0 :     if (!mBufferFetchingHasPerVertex) {
     239             :         /* http://www.khronos.org/registry/gles/extensions/ANGLE/ANGLE_instanced_arrays.txt
     240             :          *  If all of the enabled vertex attribute arrays that are bound to active
     241             :          *  generic attributes in the program have a non-zero divisor, the draw
     242             :          *  call should return INVALID_OPERATION.
     243             :          *
     244             :          * NB: This also appears to apply to NV_instanced_arrays, though the
     245             :          * INVALID_OPERATION emission is not explicitly stated.
     246             :          * ARB_instanced_arrays does not have this restriction.
     247             :          */
     248           0 :         ErrorInvalidOperation("%s: at least one vertex attribute divisor should be 0", info);
     249           0 :         return false;
     250             :     }
     251             : 
     252           0 :     return true;
     253             : }
     254             : 
     255             : bool
     256           0 : WebGLContext::DrawArrays_check(const char* funcName, GLenum mode, GLint first,
     257             :                                GLsizei vertCount, GLsizei instanceCount)
     258             : {
     259           0 :     if (!ValidateDrawModeEnum(mode, funcName))
     260           0 :         return false;
     261             : 
     262           0 :     if (!ValidateNonNegative(funcName, "first", first) ||
     263           0 :         !ValidateNonNegative(funcName, "vertCount", vertCount) ||
     264           0 :         !ValidateNonNegative(funcName, "instanceCount", instanceCount))
     265             :     {
     266           0 :         return false;
     267             :     }
     268             : 
     269           0 :     if (!ValidateStencilParamsForDrawCall())
     270           0 :         return false;
     271             : 
     272           0 :     if (IsWebGL2() && !gl->IsSupported(gl::GLFeature::prim_restart_fixed)) {
     273           0 :         MOZ_ASSERT(gl->IsSupported(gl::GLFeature::prim_restart));
     274           0 :         if (mPrimRestartTypeBytes != 0) {
     275           0 :             mPrimRestartTypeBytes = 0;
     276             : 
     277             :             // OSX appears to have severe perf issues with leaving this enabled.
     278           0 :             gl->fDisable(LOCAL_GL_PRIMITIVE_RESTART);
     279             :         }
     280             :     }
     281             : 
     282           0 :     if (!vertCount || !instanceCount)
     283           0 :         return false; // No error, just early out.
     284             : 
     285           0 :     if (!ValidateBufferFetching(funcName))
     286           0 :         return false;
     287             : 
     288           0 :     const auto checked_firstPlusCount = CheckedInt<GLsizei>(first) + vertCount;
     289           0 :     if (!checked_firstPlusCount.isValid()) {
     290           0 :         ErrorInvalidOperation("%s: overflow in first+vertCount", funcName);
     291           0 :         return false;
     292             :     }
     293             : 
     294           0 :     if (uint32_t(checked_firstPlusCount.value()) > mMaxFetchedVertices) {
     295             :         ErrorInvalidOperation("%s: Bound vertex attribute buffers do not have sufficient"
     296             :                               " size for given first and count.",
     297           0 :                               funcName);
     298           0 :         return false;
     299             :     }
     300             : 
     301           0 :     return true;
     302             : }
     303             : 
     304             : ////////////////////////////////////////
     305             : 
     306             : template<typename T>
     307             : static bool
     308             : DoSetsIntersect(const std::set<T>& a, const std::set<T>& b)
     309             : {
     310             :     std::vector<T> intersection;
     311             :     std::set_intersection(a.begin(), a.end(), b.begin(), b.end(),
     312             :                           std::back_inserter(intersection));
     313             :     return bool(intersection.size());
     314             : }
     315             : 
     316             : class ScopedDrawHelper final
     317             : {
     318             :     WebGLContext* const mWebGL;
     319             :     bool mDidFake;
     320             : 
     321             : public:
     322           0 :     ScopedDrawHelper(WebGLContext* webgl, const char* funcName, uint32_t firstVertex,
     323             :                      uint32_t vertCount, uint32_t instanceCount, bool* const out_error)
     324           0 :         : mWebGL(webgl)
     325           0 :         , mDidFake(false)
     326             :     {
     327           0 :         if (instanceCount > mWebGL->mMaxFetchedInstances) {
     328           0 :             mWebGL->ErrorInvalidOperation("%s: Bound instance attribute buffers do not"
     329             :                                           " have sufficient size for given"
     330             :                                           " `instanceCount`.",
     331           0 :                                           funcName);
     332           0 :             *out_error = true;
     333           0 :             return;
     334             :         }
     335             : 
     336           0 :         MOZ_ASSERT(mWebGL->gl->IsCurrent());
     337             : 
     338           0 :         if (mWebGL->mBoundDrawFramebuffer) {
     339           0 :             if (!mWebGL->mBoundDrawFramebuffer->ValidateAndInitAttachments(funcName)) {
     340           0 :                 *out_error = true;
     341           0 :                 return;
     342             :             }
     343             :         } else {
     344           0 :             mWebGL->ClearBackbufferIfNeeded();
     345             :         }
     346             : 
     347             :         ////
     348             : 
     349           0 :         const size_t requiredVerts = firstVertex + vertCount;
     350           0 :         if (!mWebGL->DoFakeVertexAttrib0(funcName, requiredVerts)) {
     351           0 :             *out_error = true;
     352           0 :             return;
     353             :         }
     354           0 :         mDidFake = true;
     355             : 
     356             :         ////
     357             :         // Check UBO sizes.
     358             : 
     359           0 :         const auto& linkInfo = mWebGL->mActiveProgramLinkInfo;
     360             : 
     361           0 :         for (const auto& cur : linkInfo->uniformBlocks) {
     362           0 :             const auto& dataSize = cur->mDataSize;
     363           0 :             const auto& binding = cur->mBinding;
     364           0 :             if (!binding) {
     365           0 :                 mWebGL->ErrorInvalidOperation("%s: Buffer for uniform block is null.",
     366           0 :                                               funcName);
     367           0 :                 *out_error = true;
     368           0 :                 return;
     369             :             }
     370             : 
     371           0 :             const auto availByteCount = binding->ByteCount();
     372           0 :             if (dataSize > availByteCount) {
     373           0 :                 mWebGL->ErrorInvalidOperation("%s: Buffer for uniform block is smaller"
     374             :                                               " than UNIFORM_BLOCK_DATA_SIZE.",
     375           0 :                                               funcName);
     376           0 :                 *out_error = true;
     377           0 :                 return;
     378             :             }
     379             : 
     380           0 :             if (binding->mBufferBinding->IsBoundForTF()) {
     381           0 :                 mWebGL->ErrorInvalidOperation("%s: Buffer for uniform block is bound or"
     382             :                                               " in use for transform feedback.",
     383           0 :                                               funcName);
     384           0 :                 *out_error = true;
     385           0 :                 return;
     386             :             }
     387             :         }
     388             : 
     389             :         ////
     390             : 
     391           0 :         const auto& tfo = mWebGL->mBoundTransformFeedback;
     392           0 :         if (tfo && tfo->IsActiveAndNotPaused()) {
     393             :             uint32_t numUsed;
     394           0 :             switch (linkInfo->transformFeedbackBufferMode) {
     395             :             case LOCAL_GL_INTERLEAVED_ATTRIBS:
     396           0 :                 numUsed = 1;
     397           0 :                 break;
     398             : 
     399             :             case LOCAL_GL_SEPARATE_ATTRIBS:
     400           0 :                 numUsed = linkInfo->transformFeedbackVaryings.size();
     401           0 :                 break;
     402             : 
     403             :             default:
     404           0 :                 MOZ_CRASH();
     405             :             }
     406             : 
     407           0 :             for (uint32_t i = 0; i < numUsed; ++i) {
     408           0 :                 const auto& buffer = tfo->mIndexedBindings[i].mBufferBinding;
     409           0 :                 if (buffer->IsBoundForNonTF()) {
     410           0 :                     mWebGL->ErrorInvalidOperation("%s: Transform feedback varying %u's"
     411             :                                                   " buffer is bound for"
     412             :                                                   " non-transform-feedback.",
     413           0 :                                                   funcName, i);
     414           0 :                     *out_error = true;
     415           0 :                     return;
     416             :                 }
     417             :             }
     418             :         }
     419             : 
     420             :         ////
     421             : 
     422           0 :         for (const auto& progAttrib : linkInfo->attribs) {
     423           0 :             const auto& loc = progAttrib.mLoc;
     424           0 :             if (loc == -1)
     425           0 :                 continue;
     426             : 
     427           0 :             const auto& attribData = mWebGL->mBoundVertexArray->mAttribs[loc];
     428             : 
     429             :             GLenum attribDataBaseType;
     430           0 :             if (attribData.mEnabled) {
     431           0 :                 attribDataBaseType = attribData.BaseType();
     432             : 
     433           0 :                 if (attribData.mBuf->IsBoundForTF()) {
     434           0 :                     mWebGL->ErrorInvalidOperation("%s: Vertex attrib %u's buffer is bound"
     435             :                                                   " or in use for transform feedback.",
     436           0 :                                                   funcName, loc);
     437           0 :                     *out_error = true;
     438           0 :                     return;
     439             :                 }
     440             :             } else {
     441           0 :                 attribDataBaseType = mWebGL->mGenericVertexAttribTypes[loc];
     442             :             }
     443             : 
     444           0 :             if (attribDataBaseType != progAttrib.mBaseType) {
     445           0 :                 nsCString progType, dataType;
     446           0 :                 WebGLContext::EnumName(progAttrib.mBaseType, &progType);
     447           0 :                 WebGLContext::EnumName(attribDataBaseType, &dataType);
     448           0 :                 mWebGL->ErrorInvalidOperation("%s: Vertex attrib %u requires data of type"
     449             :                                               " %s, but is being supplied with type %s.",
     450             :                                               funcName, loc, progType.BeginReading(),
     451           0 :                                               dataType.BeginReading());
     452           0 :                 *out_error = true;
     453           0 :                 return;
     454             :             }
     455             :         }
     456             : 
     457             :         ////
     458             : 
     459           0 :         mWebGL->RunContextLossTimer();
     460             :     }
     461             : 
     462           0 :     ~ScopedDrawHelper() {
     463           0 :         if (mDidFake) {
     464           0 :             mWebGL->UndoFakeVertexAttrib0();
     465             :         }
     466           0 :     }
     467             : };
     468             : 
     469             : ////////////////////////////////////////
     470             : 
     471             : static uint32_t
     472           0 : UsedVertsForTFDraw(GLenum mode, uint32_t vertCount)
     473             : {
     474             :     uint8_t vertsPerPrim;
     475             : 
     476           0 :     switch (mode) {
     477             :     case LOCAL_GL_POINTS:
     478           0 :         vertsPerPrim = 1;
     479           0 :         break;
     480             :     case LOCAL_GL_LINES:
     481           0 :         vertsPerPrim = 2;
     482           0 :         break;
     483             :     case LOCAL_GL_TRIANGLES:
     484           0 :         vertsPerPrim = 3;
     485           0 :         break;
     486             :     default:
     487           0 :         MOZ_CRASH("`mode`");
     488             :     }
     489             : 
     490           0 :     return vertCount / vertsPerPrim * vertsPerPrim;
     491             : }
     492             : 
     493             : class ScopedDrawWithTransformFeedback final
     494             : {
     495             :     WebGLContext* const mWebGL;
     496             :     WebGLTransformFeedback* const mTFO;
     497             :     const bool mWithTF;
     498             :     uint32_t mUsedVerts;
     499             : 
     500             : public:
     501           0 :     ScopedDrawWithTransformFeedback(WebGLContext* webgl, const char* funcName,
     502             :                                     GLenum mode, uint32_t vertCount,
     503             :                                     uint32_t instanceCount, bool* const out_error)
     504           0 :         : mWebGL(webgl)
     505           0 :         , mTFO(mWebGL->mBoundTransformFeedback)
     506           0 :         , mWithTF(mTFO &&
     507           0 :                   mTFO->mIsActive &&
     508           0 :                   !mTFO->mIsPaused)
     509           0 :         , mUsedVerts(0)
     510             :     {
     511           0 :         *out_error = false;
     512           0 :         if (!mWithTF)
     513           0 :             return;
     514             : 
     515           0 :         if (mode != mTFO->mActive_PrimMode) {
     516           0 :             mWebGL->ErrorInvalidOperation("%s: Drawing with transform feedback requires"
     517             :                                           " `mode` to match BeginTransformFeedback's"
     518             :                                           " `primitiveMode`.",
     519           0 :                                           funcName);
     520           0 :             *out_error = true;
     521           0 :             return;
     522             :         }
     523             : 
     524           0 :         const auto usedVertsPerInstance = UsedVertsForTFDraw(mode, vertCount);
     525           0 :         const auto usedVerts = CheckedInt<uint32_t>(usedVertsPerInstance) * instanceCount;
     526             : 
     527           0 :         const auto remainingCapacity = mTFO->mActive_VertCapacity - mTFO->mActive_VertPosition;
     528           0 :         if (!usedVerts.isValid() ||
     529           0 :             usedVerts.value() > remainingCapacity)
     530             :         {
     531           0 :             mWebGL->ErrorInvalidOperation("%s: Insufficient buffer capacity remaining for"
     532             :                                           " transform feedback.",
     533           0 :                                           funcName);
     534           0 :             *out_error = true;
     535           0 :             return;
     536             :         }
     537             : 
     538           0 :         mUsedVerts = usedVerts.value();
     539             :     }
     540             : 
     541           0 :     void Advance() const {
     542           0 :         if (!mWithTF)
     543           0 :             return;
     544             : 
     545           0 :         mTFO->mActive_VertPosition += mUsedVerts;
     546             :     }
     547             : };
     548             : 
     549             : ////////////////////////////////////////
     550             : 
     551             : void
     552           0 : WebGLContext::DrawArrays(GLenum mode, GLint first, GLsizei vertCount)
     553             : {
     554           0 :     const char funcName[] = "drawArrays";
     555           0 :     if (IsContextLost())
     556           0 :         return;
     557             : 
     558           0 :     MakeContextCurrent();
     559             : 
     560           0 :     bool error = false;
     561           0 :     ScopedResolveTexturesForDraw scopedResolve(this, funcName, &error);
     562           0 :     if (error)
     563           0 :         return;
     564             : 
     565           0 :     const GLsizei instanceCount = 1;
     566           0 :     if (!DrawArrays_check(funcName, mode, first, vertCount, instanceCount))
     567           0 :         return;
     568             : 
     569           0 :     const ScopedDrawHelper scopedHelper(this, funcName, first, vertCount, instanceCount, &error);
     570           0 :     if (error)
     571           0 :         return;
     572             : 
     573             :     const ScopedDrawWithTransformFeedback scopedTF(this, funcName, mode, vertCount,
     574           0 :                                                    instanceCount, &error);
     575           0 :     if (error)
     576           0 :         return;
     577             : 
     578             :     {
     579           0 :         ScopedDrawCallWrapper wrapper(*this);
     580           0 :         gl->fDrawArrays(mode, first, vertCount);
     581             :     }
     582             : 
     583           0 :     Draw_cleanup(funcName);
     584           0 :     scopedTF.Advance();
     585             : }
     586             : 
     587             : void
     588           0 : WebGLContext::DrawArraysInstanced(GLenum mode, GLint first, GLsizei vertCount,
     589             :                                   GLsizei instanceCount)
     590             : {
     591           0 :     const char funcName[] = "drawArraysInstanced";
     592           0 :     if (IsContextLost())
     593           0 :         return;
     594             : 
     595           0 :     MakeContextCurrent();
     596             : 
     597           0 :     bool error = false;
     598           0 :     ScopedResolveTexturesForDraw scopedResolve(this, funcName, &error);
     599           0 :     if (error)
     600           0 :         return;
     601             : 
     602           0 :     if (!DrawArrays_check(funcName, mode, first, vertCount, instanceCount))
     603           0 :         return;
     604             : 
     605           0 :     if (!DrawInstanced_check(funcName))
     606           0 :         return;
     607             : 
     608           0 :     const ScopedDrawHelper scopedHelper(this, funcName, first, vertCount, instanceCount, &error);
     609           0 :     if (error)
     610           0 :         return;
     611             : 
     612             :     const ScopedDrawWithTransformFeedback scopedTF(this, funcName, mode, vertCount,
     613           0 :                                                    instanceCount, &error);
     614           0 :     if (error)
     615           0 :         return;
     616             : 
     617             :     {
     618           0 :         ScopedDrawCallWrapper wrapper(*this);
     619           0 :         gl->fDrawArraysInstanced(mode, first, vertCount, instanceCount);
     620             :     }
     621             : 
     622           0 :     Draw_cleanup(funcName);
     623           0 :     scopedTF.Advance();
     624             : }
     625             : 
     626             : ////////////////////////////////////////
     627             : 
     628             : bool
     629           0 : WebGLContext::DrawElements_check(const char* funcName, GLenum mode, GLsizei vertCount,
     630             :                                  GLenum type, WebGLintptr byteOffset,
     631             :                                  GLsizei instanceCount)
     632             : {
     633           0 :     if (!ValidateDrawModeEnum(mode, funcName))
     634           0 :         return false;
     635             : 
     636           0 :     if (mBoundTransformFeedback &&
     637           0 :         mBoundTransformFeedback->mIsActive &&
     638           0 :         !mBoundTransformFeedback->mIsPaused)
     639             :     {
     640             :         ErrorInvalidOperation("%s: DrawElements* functions are incompatible with"
     641             :                               " transform feedback.",
     642           0 :                               funcName);
     643           0 :         return false;
     644             :     }
     645             : 
     646           0 :     if (!ValidateNonNegative(funcName, "vertCount", vertCount) ||
     647           0 :         !ValidateNonNegative(funcName, "byteOffset", byteOffset) ||
     648           0 :         !ValidateNonNegative(funcName, "instanceCount", instanceCount))
     649             :     {
     650           0 :         return false;
     651             :     }
     652             : 
     653           0 :     if (!ValidateStencilParamsForDrawCall())
     654           0 :         return false;
     655             : 
     656           0 :     if (!vertCount || !instanceCount)
     657           0 :         return false; // No error, just early out.
     658             : 
     659           0 :     uint8_t bytesPerElem = 0;
     660           0 :     switch (type) {
     661             :     case LOCAL_GL_UNSIGNED_BYTE:
     662           0 :         bytesPerElem = 1;
     663           0 :         break;
     664             : 
     665             :     case LOCAL_GL_UNSIGNED_SHORT:
     666           0 :         bytesPerElem = 2;
     667           0 :         break;
     668             : 
     669             :     case LOCAL_GL_UNSIGNED_INT:
     670           0 :         if (IsWebGL2() || IsExtensionEnabled(WebGLExtensionID::OES_element_index_uint)) {
     671           0 :             bytesPerElem = 4;
     672             :         }
     673           0 :         break;
     674             :     }
     675             : 
     676           0 :     if (!bytesPerElem) {
     677           0 :         ErrorInvalidEnum("%s: Invalid `type`: 0x%04x", funcName, type);
     678           0 :         return false;
     679             :     }
     680             : 
     681           0 :     if (byteOffset % bytesPerElem != 0) {
     682             :         ErrorInvalidOperation("%s: `byteOffset` must be a multiple of the size of `type`",
     683           0 :                               funcName);
     684           0 :         return false;
     685             :     }
     686             : 
     687             :     ////
     688             : 
     689           0 :     if (IsWebGL2() && !gl->IsSupported(gl::GLFeature::prim_restart_fixed)) {
     690           0 :         MOZ_ASSERT(gl->IsSupported(gl::GLFeature::prim_restart));
     691           0 :         if (mPrimRestartTypeBytes != bytesPerElem) {
     692           0 :             mPrimRestartTypeBytes = bytesPerElem;
     693             : 
     694           0 :             const uint32_t ones = UINT32_MAX >> (32 - 8*mPrimRestartTypeBytes);
     695           0 :             gl->fEnable(LOCAL_GL_PRIMITIVE_RESTART);
     696           0 :             gl->fPrimitiveRestartIndex(ones);
     697             :         }
     698             :     }
     699             : 
     700             :     ////
     701             : 
     702           0 :     const GLsizei first = byteOffset / bytesPerElem;
     703           0 :     const CheckedUint32 checked_byteCount = bytesPerElem * CheckedUint32(vertCount);
     704             : 
     705           0 :     if (!checked_byteCount.isValid()) {
     706           0 :         ErrorInvalidValue("%s: Overflow in byteCount.", funcName);
     707           0 :         return false;
     708             :     }
     709             : 
     710           0 :     if (!mBoundVertexArray->mElementArrayBuffer) {
     711           0 :         ErrorInvalidOperation("%s: Must have element array buffer binding.", funcName);
     712           0 :         return false;
     713             :     }
     714             : 
     715           0 :     WebGLBuffer& elemArrayBuffer = *mBoundVertexArray->mElementArrayBuffer;
     716             : 
     717           0 :     if (!elemArrayBuffer.ByteLength()) {
     718             :         ErrorInvalidOperation("%s: Bound element array buffer doesn't have any data.",
     719           0 :                               funcName);
     720           0 :         return false;
     721             :     }
     722             : 
     723           0 :     CheckedInt<GLsizei> checked_neededByteCount = checked_byteCount.toChecked<GLsizei>() + byteOffset;
     724             : 
     725           0 :     if (!checked_neededByteCount.isValid()) {
     726           0 :         ErrorInvalidOperation("%s: Overflow in byteOffset+byteCount.", funcName);
     727           0 :         return false;
     728             :     }
     729             : 
     730           0 :     if (uint32_t(checked_neededByteCount.value()) > elemArrayBuffer.ByteLength()) {
     731             :         ErrorInvalidOperation("%s: Bound element array buffer is too small for given"
     732             :                               " count and offset.",
     733           0 :                               funcName);
     734           0 :         return false;
     735             :     }
     736             : 
     737           0 :     if (!ValidateBufferFetching(funcName))
     738           0 :         return false;
     739             : 
     740           0 :     if (!mMaxFetchedVertices ||
     741           0 :         !elemArrayBuffer.ValidateIndexedFetch(type, mMaxFetchedVertices, first, vertCount))
     742             :     {
     743             :         ErrorInvalidOperation("%s: bound vertex attribute buffers do not have sufficient "
     744             :                               "size for given indices from the bound element array",
     745           0 :                               funcName);
     746           0 :         return false;
     747             :     }
     748             : 
     749           0 :     return true;
     750             : }
     751             : 
     752             : static void
     753           0 : HandleDrawElementsErrors(WebGLContext* webgl, const char* funcName,
     754             :                          gl::GLContext::LocalErrorScope& errorScope)
     755             : {
     756           0 :     const auto err = errorScope.GetError();
     757           0 :     if (err == LOCAL_GL_INVALID_OPERATION) {
     758             :         webgl->ErrorInvalidOperation("%s: Driver rejected indexed draw call, possibly"
     759           0 :                                      " due to out-of-bounds indices.", funcName);
     760           0 :         return;
     761             :     }
     762             : 
     763           0 :     MOZ_ASSERT(!err);
     764           0 :     if (err) {
     765             :         webgl->ErrorImplementationBug("%s: Unexpected driver error during indexed draw"
     766             :                                       " call. Please file a bug.",
     767           0 :                                       funcName);
     768           0 :         return;
     769             :     }
     770             : }
     771             : 
     772             : void
     773           0 : WebGLContext::DrawElements(GLenum mode, GLsizei vertCount, GLenum type,
     774             :                            WebGLintptr byteOffset, const char* funcName)
     775             : {
     776           0 :     if (!funcName) {
     777           0 :         funcName = "drawElements";
     778             :     }
     779             : 
     780           0 :     if (IsContextLost())
     781           0 :         return;
     782             : 
     783           0 :     MakeContextCurrent();
     784             : 
     785           0 :     bool error = false;
     786           0 :     ScopedResolveTexturesForDraw scopedResolve(this, funcName, &error);
     787           0 :     if (error)
     788           0 :         return;
     789             : 
     790           0 :     const GLsizei instanceCount = 1;
     791           0 :     if (!DrawElements_check(funcName, mode, vertCount, type, byteOffset, instanceCount))
     792           0 :         return;
     793             : 
     794             :     const ScopedDrawHelper scopedHelper(this, funcName, 0, mMaxFetchedVertices, instanceCount,
     795           0 :                                         &error);
     796           0 :     if (error)
     797           0 :         return;
     798             : 
     799             :     {
     800           0 :         ScopedDrawCallWrapper wrapper(*this);
     801             :         {
     802           0 :             UniquePtr<gl::GLContext::LocalErrorScope> errorScope;
     803             : 
     804           0 :             if (gl->IsANGLE()) {
     805           0 :                 errorScope.reset(new gl::GLContext::LocalErrorScope(*gl));
     806             :             }
     807             : 
     808           0 :             gl->fDrawElements(mode, vertCount, type,
     809           0 :                               reinterpret_cast<GLvoid*>(byteOffset));
     810             : 
     811           0 :             if (errorScope) {
     812           0 :                 HandleDrawElementsErrors(this, funcName, *errorScope);
     813             :             }
     814             :         }
     815             :     }
     816             : 
     817           0 :     Draw_cleanup(funcName);
     818             : }
     819             : 
     820             : void
     821           0 : WebGLContext::DrawElementsInstanced(GLenum mode, GLsizei vertCount, GLenum type,
     822             :                                     WebGLintptr byteOffset, GLsizei instanceCount)
     823             : {
     824           0 :     const char funcName[] = "drawElementsInstanced";
     825           0 :     if (IsContextLost())
     826           0 :         return;
     827             : 
     828           0 :     MakeContextCurrent();
     829             : 
     830           0 :     bool error = false;
     831           0 :     ScopedResolveTexturesForDraw scopedResolve(this, funcName, &error);
     832           0 :     if (error)
     833           0 :         return;
     834             : 
     835           0 :     if (!DrawElements_check(funcName, mode, vertCount, type, byteOffset, instanceCount))
     836           0 :         return;
     837             : 
     838           0 :     if (!DrawInstanced_check(funcName))
     839           0 :         return;
     840             : 
     841             :     const ScopedDrawHelper scopedHelper(this, funcName, 0, mMaxFetchedVertices, instanceCount,
     842           0 :                                         &error);
     843           0 :     if (error)
     844           0 :         return;
     845             : 
     846             :     {
     847           0 :         ScopedDrawCallWrapper wrapper(*this);
     848             :         {
     849           0 :             UniquePtr<gl::GLContext::LocalErrorScope> errorScope;
     850             : 
     851           0 :             if (gl->IsANGLE()) {
     852           0 :                 errorScope.reset(new gl::GLContext::LocalErrorScope(*gl));
     853             :             }
     854             : 
     855           0 :             gl->fDrawElementsInstanced(mode, vertCount, type,
     856             :                                        reinterpret_cast<GLvoid*>(byteOffset),
     857           0 :                                        instanceCount);
     858           0 :             if (errorScope) {
     859           0 :                 HandleDrawElementsErrors(this, funcName, *errorScope);
     860             :             }
     861             :         }
     862             :     }
     863             : 
     864           0 :     Draw_cleanup(funcName);
     865             : }
     866             : 
     867             : ////////////////////////////////////////
     868             : 
     869             : void
     870           0 : WebGLContext::Draw_cleanup(const char* funcName)
     871             : {
     872           0 :     if (gl->WorkAroundDriverBugs()) {
     873           0 :         if (gl->Renderer() == gl::GLRenderer::Tegra) {
     874           0 :             mDrawCallsSinceLastFlush++;
     875             : 
     876           0 :             if (mDrawCallsSinceLastFlush >= MAX_DRAW_CALLS_SINCE_FLUSH) {
     877           0 :                 gl->fFlush();
     878           0 :                 mDrawCallsSinceLastFlush = 0;
     879             :             }
     880             :         }
     881             :     }
     882             : 
     883             :     // Let's check for a really common error: Viewport is larger than the actual
     884             :     // destination framebuffer.
     885           0 :     uint32_t destWidth = mViewportWidth;
     886           0 :     uint32_t destHeight = mViewportHeight;
     887             : 
     888           0 :     if (mBoundDrawFramebuffer) {
     889           0 :         const auto& drawBuffers = mBoundDrawFramebuffer->ColorDrawBuffers();
     890           0 :         for (const auto& cur : drawBuffers) {
     891           0 :             if (!cur->IsDefined())
     892           0 :                 continue;
     893           0 :             cur->Size(&destWidth, &destHeight);
     894           0 :             break;
     895             :         }
     896             :     } else {
     897           0 :         destWidth = mWidth;
     898           0 :         destHeight = mHeight;
     899             :     }
     900             : 
     901           0 :     if (mViewportWidth > int32_t(destWidth) ||
     902           0 :         mViewportHeight > int32_t(destHeight))
     903             :     {
     904           0 :         if (!mAlreadyWarnedAboutViewportLargerThanDest) {
     905             :             GenerateWarning("%s: Drawing to a destination rect smaller than the viewport"
     906             :                             " rect. (This warning will only be given once)",
     907           0 :                             funcName);
     908           0 :             mAlreadyWarnedAboutViewportLargerThanDest = true;
     909             :         }
     910             :     }
     911           0 : }
     912             : 
     913             : /*
     914             :  * Verify that state is consistent for drawing, and compute max number of elements (maxAllowedCount)
     915             :  * that will be legal to be read from bound VBOs.
     916             :  */
     917             : 
     918             : bool
     919           0 : WebGLContext::ValidateBufferFetching(const char* info)
     920             : {
     921           0 :     MOZ_ASSERT(mCurrentProgram);
     922             :     // Note that mCurrentProgram->IsLinked() is NOT GUARANTEED.
     923           0 :     MOZ_ASSERT(mActiveProgramLinkInfo);
     924             : 
     925             : #ifdef DEBUG
     926           0 :     GLint currentProgram = 0;
     927           0 :     MakeContextCurrent();
     928           0 :     gl->fGetIntegerv(LOCAL_GL_CURRENT_PROGRAM, &currentProgram);
     929           0 :     MOZ_ASSERT(GLuint(currentProgram) == mCurrentProgram->mGLName,
     930             :                "WebGL: current program doesn't agree with GL state");
     931             : #endif
     932             : 
     933           0 :     if (mBufferFetchingIsVerified)
     934           0 :         return true;
     935             : 
     936           0 :     bool hasPerVertex = false;
     937           0 :     uint32_t maxVertices = UINT32_MAX;
     938           0 :     uint32_t maxInstances = UINT32_MAX;
     939           0 :     const uint32_t attribCount = mBoundVertexArray->mAttribs.Length();
     940             : 
     941           0 :     uint32_t i = 0;
     942           0 :     for (const auto& vd : mBoundVertexArray->mAttribs) {
     943             :         // If the attrib array isn't enabled, there's nothing to check;
     944             :         // it's a static value.
     945           0 :         if (!vd.mEnabled)
     946           0 :             continue;
     947             : 
     948           0 :         if (!vd.mBuf) {
     949             :             ErrorInvalidOperation("%s: no VBO bound to enabled vertex attrib index %du!",
     950           0 :                                   info, i);
     951           0 :             return false;
     952             :         }
     953             : 
     954           0 :         ++i;
     955             :     }
     956             : 
     957           0 :     mBufferFetch_IsAttrib0Active = false;
     958             : 
     959           0 :     for (const auto& attrib : mActiveProgramLinkInfo->attribs) {
     960           0 :         if (attrib.mLoc == -1)
     961           0 :             continue;
     962             : 
     963           0 :         const uint32_t attribLoc(attrib.mLoc);
     964           0 :         if (attribLoc >= attribCount)
     965           0 :             continue;
     966             : 
     967           0 :         if (attribLoc == 0) {
     968           0 :             mBufferFetch_IsAttrib0Active = true;
     969             :         }
     970             : 
     971           0 :         const auto& vd = mBoundVertexArray->mAttribs[attribLoc];
     972           0 :         if (!vd.mEnabled)
     973           0 :             continue;
     974             : 
     975           0 :         const auto& bufByteLen = vd.mBuf->ByteLength();
     976           0 :         if (vd.ByteOffset() > bufByteLen) {
     977           0 :             maxVertices = 0;
     978           0 :             maxInstances = 0;
     979           0 :             break;
     980             :         }
     981             : 
     982           0 :         size_t availBytes = bufByteLen - vd.ByteOffset();
     983           0 :         if (vd.BytesPerVertex() > availBytes) {
     984           0 :             maxVertices = 0;
     985           0 :             maxInstances = 0;
     986           0 :             break;
     987             :         }
     988           0 :         availBytes -= vd.BytesPerVertex(); // Snip off the tail.
     989           0 :         const size_t vertCapacity = availBytes / vd.ExplicitStride() + 1; // Add +1 for the snipped tail.
     990             : 
     991           0 :         if (vd.mDivisor == 0) {
     992           0 :             if (vertCapacity < maxVertices) {
     993           0 :                 maxVertices = vertCapacity;
     994             :             }
     995           0 :             hasPerVertex = true;
     996             :         } else {
     997           0 :             const auto curMaxInstances = CheckedInt<size_t>(vertCapacity) * vd.mDivisor;
     998             :             // If this isn't valid, it's because we overflowed, which means we can support
     999             :             // *too much*. Don't update maxInstances in this case.
    1000           0 :             if (curMaxInstances.isValid() &&
    1001           0 :                 curMaxInstances.value() < maxInstances)
    1002             :             {
    1003           0 :                 maxInstances = curMaxInstances.value();
    1004             :             }
    1005             :         }
    1006             :     }
    1007             : 
    1008           0 :     mBufferFetchingIsVerified = true;
    1009           0 :     mBufferFetchingHasPerVertex = hasPerVertex;
    1010           0 :     mMaxFetchedVertices = maxVertices;
    1011           0 :     mMaxFetchedInstances = maxInstances;
    1012             : 
    1013           0 :     return true;
    1014             : }
    1015             : 
    1016             : WebGLVertexAttrib0Status
    1017           0 : WebGLContext::WhatDoesVertexAttrib0Need() const
    1018             : {
    1019           0 :     MOZ_ASSERT(mCurrentProgram);
    1020           0 :     MOZ_ASSERT(mActiveProgramLinkInfo);
    1021             : 
    1022           0 :     const auto& isAttribArray0Enabled = mBoundVertexArray->mAttribs[0].mEnabled;
    1023             : 
    1024           0 :     bool legacyAttrib0 = gl->IsCompatibilityProfile();
    1025             : #ifdef XP_MACOSX
    1026             :     if (gl->WorkAroundDriverBugs()) {
    1027             :         // Failures in conformance/attribs/gl-disabled-vertex-attrib.
    1028             :         // Even in Core profiles on NV. Sigh.
    1029             :         legacyAttrib0 |= (gl->Vendor() == gl::GLVendor::NVIDIA);
    1030             :     }
    1031             : #endif
    1032             : 
    1033           0 :     if (!legacyAttrib0)
    1034           0 :         return WebGLVertexAttrib0Status::Default;
    1035             : 
    1036           0 :     if (isAttribArray0Enabled && mBufferFetch_IsAttrib0Active)
    1037           0 :         return WebGLVertexAttrib0Status::Default;
    1038             : 
    1039           0 :     if (mBufferFetch_IsAttrib0Active)
    1040           0 :         return WebGLVertexAttrib0Status::EmulatedInitializedArray;
    1041             : 
    1042             :     // Ensure that the legacy code has enough buffer.
    1043           0 :     return WebGLVertexAttrib0Status::EmulatedUninitializedArray;
    1044             : }
    1045             : 
    1046             : bool
    1047           0 : WebGLContext::DoFakeVertexAttrib0(const char* funcName, GLuint vertexCount)
    1048             : {
    1049           0 :     if (!vertexCount) {
    1050           0 :         vertexCount = 1;
    1051             :     }
    1052             : 
    1053           0 :     const auto whatDoesAttrib0Need = WhatDoesVertexAttrib0Need();
    1054           0 :     if (MOZ_LIKELY(whatDoesAttrib0Need == WebGLVertexAttrib0Status::Default))
    1055           0 :         return true;
    1056             : 
    1057           0 :     if (!mAlreadyWarnedAboutFakeVertexAttrib0) {
    1058             :         GenerateWarning("Drawing without vertex attrib 0 array enabled forces the browser "
    1059             :                         "to do expensive emulation work when running on desktop OpenGL "
    1060             :                         "platforms, for example on Mac. It is preferable to always draw "
    1061             :                         "with vertex attrib 0 array enabled, by using bindAttribLocation "
    1062           0 :                         "to bind some always-used attribute to location 0.");
    1063           0 :         mAlreadyWarnedAboutFakeVertexAttrib0 = true;
    1064             :     }
    1065             : 
    1066           0 :     gl->fEnableVertexAttribArray(0);
    1067             : 
    1068           0 :     if (!mFakeVertexAttrib0BufferObject) {
    1069           0 :         gl->fGenBuffers(1, &mFakeVertexAttrib0BufferObject);
    1070           0 :         mFakeVertexAttrib0BufferObjectSize = 0;
    1071             :     }
    1072           0 :     gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mFakeVertexAttrib0BufferObject);
    1073             : 
    1074             :     ////
    1075             : 
    1076           0 :     switch (mGenericVertexAttribTypes[0]) {
    1077             :     case LOCAL_GL_FLOAT:
    1078           0 :         gl->fVertexAttribPointer(0, 4, LOCAL_GL_FLOAT, false, 0, 0);
    1079           0 :         break;
    1080             : 
    1081             :     case LOCAL_GL_INT:
    1082           0 :         gl->fVertexAttribIPointer(0, 4, LOCAL_GL_INT, 0, 0);
    1083           0 :         break;
    1084             : 
    1085             :     case LOCAL_GL_UNSIGNED_INT:
    1086           0 :         gl->fVertexAttribIPointer(0, 4, LOCAL_GL_UNSIGNED_INT, 0, 0);
    1087           0 :         break;
    1088             : 
    1089             :     default:
    1090           0 :         MOZ_CRASH();
    1091             :     }
    1092             : 
    1093             :     ////
    1094             : 
    1095           0 :     const auto bytesPerVert = sizeof(mFakeVertexAttrib0Data);
    1096           0 :     const auto checked_dataSize = CheckedUint32(vertexCount) * bytesPerVert;
    1097           0 :     if (!checked_dataSize.isValid()) {
    1098             :         ErrorOutOfMemory("Integer overflow trying to construct a fake vertex attrib 0 array for a draw-operation "
    1099           0 :                          "with %d vertices. Try reducing the number of vertices.", vertexCount);
    1100           0 :         return false;
    1101             :     }
    1102           0 :     const auto dataSize = checked_dataSize.value();
    1103             : 
    1104           0 :     if (mFakeVertexAttrib0BufferObjectSize < dataSize) {
    1105           0 :         gl->fBufferData(LOCAL_GL_ARRAY_BUFFER, dataSize, nullptr, LOCAL_GL_DYNAMIC_DRAW);
    1106           0 :         mFakeVertexAttrib0BufferObjectSize = dataSize;
    1107           0 :         mFakeVertexAttrib0DataDefined = false;
    1108             :     }
    1109             : 
    1110           0 :     if (whatDoesAttrib0Need == WebGLVertexAttrib0Status::EmulatedUninitializedArray)
    1111           0 :         return true;
    1112             : 
    1113             :     ////
    1114             : 
    1115           0 :     if (mFakeVertexAttrib0DataDefined &&
    1116           0 :         memcmp(mFakeVertexAttrib0Data, mGenericVertexAttrib0Data, bytesPerVert) == 0)
    1117             :     {
    1118           0 :         return true;
    1119             :     }
    1120             : 
    1121             :     ////
    1122             : 
    1123           0 :     const UniqueBuffer data(malloc(dataSize));
    1124           0 :     if (!data) {
    1125             :         ErrorOutOfMemory("%s: Failed to allocate fake vertex attrib 0 array.",
    1126           0 :                          funcName);
    1127           0 :         return false;
    1128             :     }
    1129           0 :     auto itr = (uint8_t*)data.get();
    1130           0 :     const auto itrEnd = itr + dataSize;
    1131           0 :     while (itr != itrEnd) {
    1132           0 :         memcpy(itr, mGenericVertexAttrib0Data, bytesPerVert);
    1133           0 :         itr += bytesPerVert;
    1134             :     }
    1135             : 
    1136             :     {
    1137           0 :         gl::GLContext::LocalErrorScope errorScope(*gl);
    1138             : 
    1139           0 :         gl->fBufferSubData(LOCAL_GL_ARRAY_BUFFER, 0, dataSize, data.get());
    1140             : 
    1141           0 :         const auto err = errorScope.GetError();
    1142           0 :         if (err) {
    1143           0 :             ErrorOutOfMemory("%s: Failed to upload fake vertex attrib 0 data.", funcName);
    1144           0 :             return false;
    1145             :         }
    1146             :     }
    1147             : 
    1148             :     ////
    1149             : 
    1150           0 :     memcpy(mFakeVertexAttrib0Data, mGenericVertexAttrib0Data, bytesPerVert);
    1151           0 :     mFakeVertexAttrib0DataDefined = true;
    1152           0 :     return true;
    1153             : }
    1154             : 
    1155             : void
    1156           0 : WebGLContext::UndoFakeVertexAttrib0()
    1157             : {
    1158           0 :     const auto whatDoesAttrib0Need = WhatDoesVertexAttrib0Need();
    1159           0 :     if (MOZ_LIKELY(whatDoesAttrib0Need == WebGLVertexAttrib0Status::Default))
    1160           0 :         return;
    1161             : 
    1162           0 :     if (mBoundVertexArray->mAttribs[0].mBuf) {
    1163           0 :         const WebGLVertexAttribData& attrib0 = mBoundVertexArray->mAttribs[0];
    1164           0 :         gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, attrib0.mBuf->mGLName);
    1165           0 :         attrib0.DoVertexAttribPointer(gl, 0);
    1166             :     } else {
    1167           0 :         gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
    1168             :     }
    1169             : 
    1170           0 :     gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mBoundArrayBuffer ? mBoundArrayBuffer->mGLName : 0);
    1171             : }
    1172             : 
    1173             : static GLuint
    1174           0 : CreateGLTexture(gl::GLContext* gl)
    1175             : {
    1176           0 :     MOZ_ASSERT(gl->IsCurrent());
    1177           0 :     GLuint ret = 0;
    1178           0 :     gl->fGenTextures(1, &ret);
    1179           0 :     return ret;
    1180             : }
    1181             : 
    1182             : UniquePtr<WebGLContext::FakeBlackTexture>
    1183           0 : WebGLContext::FakeBlackTexture::Create(gl::GLContext* gl, TexTarget target,
    1184             :                                        FakeBlackType type)
    1185             : {
    1186             :     GLenum texFormat;
    1187           0 :     switch (type) {
    1188             :     case FakeBlackType::RGBA0000:
    1189           0 :         texFormat = LOCAL_GL_RGBA;
    1190           0 :         break;
    1191             : 
    1192             :     case FakeBlackType::RGBA0001:
    1193           0 :         texFormat = LOCAL_GL_RGB;
    1194           0 :         break;
    1195             : 
    1196             :     default:
    1197           0 :         MOZ_CRASH("GFX: bad type");
    1198             :     }
    1199             : 
    1200           0 :     UniquePtr<FakeBlackTexture> result(new FakeBlackTexture(gl));
    1201           0 :     gl::ScopedBindTexture scopedBind(gl, result->mGLName, target.get());
    1202             : 
    1203           0 :     gl->fTexParameteri(target.get(), LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_NEAREST);
    1204           0 :     gl->fTexParameteri(target.get(), LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_NEAREST);
    1205             : 
    1206             :     // We allocate our zeros on the heap, and we overallocate (16 bytes instead of 4) to
    1207             :     // minimize the risk of running into a driver bug in texImage2D, as it is a bit
    1208             :     // unusual maybe to create 1x1 textures, and the stack may not have the alignment that
    1209             :     // TexImage2D expects.
    1210             : 
    1211           0 :     const webgl::DriverUnpackInfo dui = {texFormat, texFormat, LOCAL_GL_UNSIGNED_BYTE};
    1212           0 :     UniqueBuffer zeros = moz_xcalloc(1, 16); // Infallible allocation.
    1213             : 
    1214           0 :     MOZ_ASSERT(gl->IsCurrent());
    1215             : 
    1216           0 :     if (target == LOCAL_GL_TEXTURE_CUBE_MAP) {
    1217           0 :         for (int i = 0; i < 6; ++i) {
    1218           0 :             const TexImageTarget curTarget = LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X + i;
    1219           0 :             const GLenum error = DoTexImage(gl, curTarget.get(), 0, &dui, 1, 1, 1,
    1220           0 :                                             zeros.get());
    1221           0 :             if (error) {
    1222           0 :                 return nullptr;
    1223             :             }
    1224             :         }
    1225             :     } else {
    1226           0 :         const GLenum error = DoTexImage(gl, target.get(), 0, &dui, 1, 1, 1,
    1227           0 :                                         zeros.get());
    1228           0 :         if (error) {
    1229           0 :             return nullptr;
    1230             :         }
    1231             :     }
    1232             : 
    1233           0 :     return result;
    1234             : }
    1235             : 
    1236           0 : WebGLContext::FakeBlackTexture::FakeBlackTexture(gl::GLContext* gl)
    1237             :     : mGL(gl)
    1238           0 :     , mGLName(CreateGLTexture(gl))
    1239             : {
    1240           0 : }
    1241             : 
    1242           0 : WebGLContext::FakeBlackTexture::~FakeBlackTexture()
    1243             : {
    1244           0 :     mGL->MakeCurrent();
    1245           0 :     mGL->fDeleteTextures(1, &mGLName);
    1246           0 : }
    1247             : 
    1248             : } // namespace mozilla

Generated by: LCOV version 1.13