LCOV - code coverage report
Current view: top level - dom/canvas - WebGLContext.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 1175 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 102 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 "WebGLContext.h"
       7             : 
       8             : #include <queue>
       9             : 
      10             : #include "AccessCheck.h"
      11             : #include "gfxContext.h"
      12             : #include "gfxCrashReporterUtils.h"
      13             : #include "gfxPattern.h"
      14             : #include "gfxPrefs.h"
      15             : #include "gfxUtils.h"
      16             : #include "GLBlitHelper.h"
      17             : #include "GLContext.h"
      18             : #include "GLContextProvider.h"
      19             : #include "GLReadTexImageHelper.h"
      20             : #include "GLScreenBuffer.h"
      21             : #include "ImageContainer.h"
      22             : #include "ImageEncoder.h"
      23             : #include "Layers.h"
      24             : #include "LayerUserData.h"
      25             : #include "mozilla/dom/BindingUtils.h"
      26             : #include "mozilla/dom/Event.h"
      27             : #include "mozilla/dom/HTMLVideoElement.h"
      28             : #include "mozilla/dom/ImageData.h"
      29             : #include "mozilla/dom/WebGLContextEvent.h"
      30             : #include "mozilla/EnumeratedArrayCycleCollection.h"
      31             : #include "mozilla/Preferences.h"
      32             : #include "mozilla/ProcessPriorityManager.h"
      33             : #include "mozilla/ScopeExit.h"
      34             : #include "mozilla/Services.h"
      35             : #include "mozilla/SizePrintfMacros.h"
      36             : #include "mozilla/Telemetry.h"
      37             : #include "nsContentUtils.h"
      38             : #include "nsDisplayList.h"
      39             : #include "nsError.h"
      40             : #include "nsIClassInfoImpl.h"
      41             : #include "nsIConsoleService.h"
      42             : #include "nsIDOMEvent.h"
      43             : #include "nsIGfxInfo.h"
      44             : #include "nsIObserverService.h"
      45             : #include "nsIVariant.h"
      46             : #include "nsIWidget.h"
      47             : #include "nsIXPConnect.h"
      48             : #include "nsServiceManagerUtils.h"
      49             : #include "nsSVGEffects.h"
      50             : #include "prenv.h"
      51             : #include "ScopedGLHelpers.h"
      52             : #include "VRManagerChild.h"
      53             : #include "mozilla/layers/TextureClientSharedSurface.h"
      54             : 
      55             : #ifdef MOZ_WIDGET_GONK
      56             : #include "mozilla/layers/ShadowLayers.h"
      57             : #endif
      58             : 
      59             : // Local
      60             : #include "CanvasUtils.h"
      61             : #include "WebGL1Context.h"
      62             : #include "WebGLActiveInfo.h"
      63             : #include "WebGLBuffer.h"
      64             : #include "WebGLContextLossHandler.h"
      65             : #include "WebGLContextUtils.h"
      66             : #include "WebGLExtensions.h"
      67             : #include "WebGLFramebuffer.h"
      68             : #include "WebGLMemoryTracker.h"
      69             : #include "WebGLObjectModel.h"
      70             : #include "WebGLProgram.h"
      71             : #include "WebGLQuery.h"
      72             : #include "WebGLSampler.h"
      73             : #include "WebGLShader.h"
      74             : #include "WebGLSync.h"
      75             : #include "WebGLTransformFeedback.h"
      76             : #include "WebGLVertexArray.h"
      77             : #include "WebGLVertexAttribData.h"
      78             : 
      79             : #ifdef MOZ_WIDGET_COCOA
      80             : #include "nsCocoaFeatures.h"
      81             : #endif
      82             : 
      83             : #ifdef XP_WIN
      84             : #include "WGLLibrary.h"
      85             : #endif
      86             : 
      87             : // Generated
      88             : #include "mozilla/dom/WebGLRenderingContextBinding.h"
      89             : 
      90             : 
      91             : namespace mozilla {
      92             : 
      93             : using namespace mozilla::dom;
      94             : using namespace mozilla::gfx;
      95             : using namespace mozilla::gl;
      96             : using namespace mozilla::layers;
      97             : 
      98           0 : WebGLContextOptions::WebGLContextOptions()
      99             :     : alpha(true)
     100             :     , depth(true)
     101             :     , stencil(false)
     102             :     , premultipliedAlpha(true)
     103             :     , antialias(true)
     104             :     , preserveDrawingBuffer(false)
     105           0 :     , failIfMajorPerformanceCaveat(false)
     106             : {
     107             :     // Set default alpha state based on preference.
     108           0 :     if (gfxPrefs::WebGLDefaultNoAlpha())
     109           0 :         alpha = false;
     110           0 : }
     111             : 
     112             : 
     113             : /*static*/ const uint32_t WebGLContext::kMinMaxColorAttachments = 4;
     114             : /*static*/ const uint32_t WebGLContext::kMinMaxDrawBuffers = 4;
     115             : 
     116           0 : WebGLContext::WebGLContext()
     117             :     : WebGLContextUnchecked(nullptr)
     118           0 :     , mMaxPerfWarnings(gfxPrefs::WebGLMaxPerfWarnings())
     119             :     , mNumPerfWarnings(0)
     120           0 :     , mMaxAcceptableFBStatusInvals(gfxPrefs::WebGLMaxAcceptableFBStatusInvals())
     121             :     , mBufferFetchingIsVerified(false)
     122             :     , mBufferFetchingHasPerVertex(false)
     123             :     , mMaxFetchedVertices(0)
     124             :     , mMaxFetchedInstances(0)
     125             :     , mLayerIsMirror(false)
     126             :     , mBypassShaderValidation(false)
     127             :     , mEmptyTFO(0)
     128             :     , mContextLossHandler(this)
     129             :     , mNeedsFakeNoAlpha(false)
     130             :     , mNeedsFakeNoDepth(false)
     131             :     , mNeedsFakeNoStencil(false)
     132             :     , mNeedsEmulatedLoneDepthStencil(false)
     133           0 :     , mAllowFBInvalidation(gfxPrefs::WebGLFBInvalidation())
     134             : {
     135           0 :     mGeneration = 0;
     136           0 :     mInvalidated = false;
     137           0 :     mCapturedFrameInvalidated = false;
     138           0 :     mShouldPresent = true;
     139           0 :     mResetLayer = true;
     140           0 :     mOptionsFrozen = false;
     141           0 :     mMinCapability = false;
     142           0 :     mDisableExtensions = false;
     143           0 :     mIsMesa = false;
     144           0 :     mEmitContextLostErrorOnce = false;
     145           0 :     mWebGLError = 0;
     146           0 :     mUnderlyingGLError = 0;
     147             : 
     148           0 :     mActiveTexture = 0;
     149             : 
     150           0 :     mStencilRefFront = 0;
     151           0 :     mStencilRefBack = 0;
     152           0 :     mStencilValueMaskFront = 0;
     153           0 :     mStencilValueMaskBack = 0;
     154           0 :     mStencilWriteMaskFront = 0;
     155           0 :     mStencilWriteMaskBack = 0;
     156           0 :     mDepthWriteMask = 0;
     157           0 :     mStencilClearValue = 0;
     158           0 :     mDepthClearValue = 0;
     159           0 :     mContextLostErrorSet = false;
     160             : 
     161           0 :     mViewportX = 0;
     162           0 :     mViewportY = 0;
     163           0 :     mViewportWidth = 0;
     164           0 :     mViewportHeight = 0;
     165             : 
     166           0 :     mDitherEnabled = 1;
     167           0 :     mRasterizerDiscardEnabled = 0; // OpenGL ES 3.0 spec p244
     168           0 :     mScissorTestEnabled = 0;
     169           0 :     mStencilTestEnabled = 0;
     170             : 
     171           0 :     if (NS_IsMainThread()) {
     172             :         // XXX mtseng: bug 709490, not thread safe
     173           0 :         WebGLMemoryTracker::AddWebGLContext(this);
     174             :     }
     175             : 
     176           0 :     mAllowContextRestore = true;
     177           0 :     mLastLossWasSimulated = false;
     178           0 :     mContextStatus = ContextNotLost;
     179           0 :     mLoseContextOnMemoryPressure = false;
     180           0 :     mCanLoseContextInForeground = true;
     181           0 :     mRestoreWhenVisible = false;
     182             : 
     183           0 :     mAlreadyGeneratedWarnings = 0;
     184           0 :     mAlreadyWarnedAboutFakeVertexAttrib0 = false;
     185           0 :     mAlreadyWarnedAboutViewportLargerThanDest = false;
     186             : 
     187           0 :     mMaxWarnings = gfxPrefs::WebGLMaxWarningsPerContext();
     188           0 :     if (mMaxWarnings < -1) {
     189           0 :         GenerateWarning("webgl.max-warnings-per-context size is too large (seems like a negative value wrapped)");
     190           0 :         mMaxWarnings = 0;
     191             :     }
     192             : 
     193           0 :     mLastUseIndex = 0;
     194             : 
     195           0 :     InvalidateBufferFetching();
     196             : 
     197           0 :     mDisableFragHighP = false;
     198             : 
     199           0 :     mDrawCallsSinceLastFlush = 0;
     200           0 : }
     201             : 
     202           0 : WebGLContext::~WebGLContext()
     203             : {
     204           0 :     RemovePostRefreshObserver();
     205             : 
     206           0 :     DestroyResourcesAndContext();
     207           0 :     if (NS_IsMainThread()) {
     208             :         // XXX mtseng: bug 709490, not thread safe
     209           0 :         WebGLMemoryTracker::RemoveWebGLContext(this);
     210             :     }
     211           0 : }
     212             : 
     213             : template<typename T>
     214             : void
     215           0 : ClearLinkedList(LinkedList<T>& list)
     216             : {
     217           0 :     while (!list.isEmpty()) {
     218           0 :         list.getLast()->DeleteOnce();
     219             :     }
     220           0 : }
     221             : 
     222             : void
     223           0 : WebGLContext::DestroyResourcesAndContext()
     224             : {
     225           0 :     if (!gl)
     226           0 :         return;
     227             : 
     228           0 :     gl->MakeCurrent();
     229             : 
     230           0 :     mBound2DTextures.Clear();
     231           0 :     mBoundCubeMapTextures.Clear();
     232           0 :     mBound3DTextures.Clear();
     233           0 :     mBound2DArrayTextures.Clear();
     234           0 :     mBoundSamplers.Clear();
     235           0 :     mBoundArrayBuffer = nullptr;
     236           0 :     mBoundCopyReadBuffer = nullptr;
     237           0 :     mBoundCopyWriteBuffer = nullptr;
     238           0 :     mBoundPixelPackBuffer = nullptr;
     239           0 :     mBoundPixelUnpackBuffer = nullptr;
     240           0 :     mBoundUniformBuffer = nullptr;
     241           0 :     mCurrentProgram = nullptr;
     242           0 :     mActiveProgramLinkInfo = nullptr;
     243           0 :     mBoundDrawFramebuffer = nullptr;
     244           0 :     mBoundReadFramebuffer = nullptr;
     245           0 :     mBoundRenderbuffer = nullptr;
     246           0 :     mBoundVertexArray = nullptr;
     247           0 :     mDefaultVertexArray = nullptr;
     248           0 :     mBoundTransformFeedback = nullptr;
     249           0 :     mDefaultTransformFeedback = nullptr;
     250             : 
     251           0 :     mQuerySlot_SamplesPassed = nullptr;
     252           0 :     mQuerySlot_TFPrimsWritten = nullptr;
     253           0 :     mQuerySlot_TimeElapsed = nullptr;
     254             : 
     255           0 :     mIndexedUniformBufferBindings.clear();
     256             : 
     257             :     //////
     258             : 
     259           0 :     ClearLinkedList(mBuffers);
     260           0 :     ClearLinkedList(mFramebuffers);
     261           0 :     ClearLinkedList(mPrograms);
     262           0 :     ClearLinkedList(mQueries);
     263           0 :     ClearLinkedList(mRenderbuffers);
     264           0 :     ClearLinkedList(mSamplers);
     265           0 :     ClearLinkedList(mShaders);
     266           0 :     ClearLinkedList(mSyncs);
     267           0 :     ClearLinkedList(mTextures);
     268           0 :     ClearLinkedList(mTransformFeedbacks);
     269           0 :     ClearLinkedList(mVertexArrays);
     270             : 
     271             :     //////
     272             : 
     273           0 :     if (mEmptyTFO) {
     274           0 :         gl->fDeleteTransformFeedbacks(1, &mEmptyTFO);
     275           0 :         mEmptyTFO = 0;
     276             :     }
     277             : 
     278             :     //////
     279             : 
     280           0 :     mFakeBlack_2D_0000       = nullptr;
     281           0 :     mFakeBlack_2D_0001       = nullptr;
     282           0 :     mFakeBlack_CubeMap_0000  = nullptr;
     283           0 :     mFakeBlack_CubeMap_0001  = nullptr;
     284           0 :     mFakeBlack_3D_0000       = nullptr;
     285           0 :     mFakeBlack_3D_0001       = nullptr;
     286           0 :     mFakeBlack_2D_Array_0000 = nullptr;
     287           0 :     mFakeBlack_2D_Array_0001 = nullptr;
     288             : 
     289           0 :     if (mFakeVertexAttrib0BufferObject) {
     290           0 :         gl->fDeleteBuffers(1, &mFakeVertexAttrib0BufferObject);
     291           0 :         mFakeVertexAttrib0BufferObject = 0;
     292             :     }
     293             : 
     294             :     // disable all extensions except "WEBGL_lose_context". see bug #927969
     295             :     // spec: http://www.khronos.org/registry/webgl/specs/latest/1.0/#5.15.2
     296           0 :     for (size_t i = 0; i < size_t(WebGLExtensionID::Max); ++i) {
     297           0 :         WebGLExtensionID extension = WebGLExtensionID(i);
     298             : 
     299           0 :         if (!IsExtensionEnabled(extension) || (extension == WebGLExtensionID::WEBGL_lose_context))
     300           0 :             continue;
     301             : 
     302           0 :         mExtensions[extension]->MarkLost();
     303           0 :         mExtensions[extension] = nullptr;
     304             :     }
     305             : 
     306             :     // We just got rid of everything, so the context had better
     307             :     // have been going away.
     308           0 :     if (GLContext::ShouldSpew()) {
     309           0 :         printf_stderr("--- WebGL context destroyed: %p\n", gl.get());
     310             :     }
     311             : 
     312           0 :     MOZ_ASSERT(gl);
     313           0 :     mGL_OnlyClearInDestroyResourcesAndContext = nullptr;
     314           0 :     MOZ_ASSERT(!gl);
     315             : }
     316             : 
     317             : void
     318           0 : WebGLContext::Invalidate()
     319             : {
     320           0 :     if (!mCanvasElement)
     321           0 :         return;
     322             : 
     323           0 :     mCapturedFrameInvalidated = true;
     324             : 
     325           0 :     if (mInvalidated)
     326           0 :         return;
     327             : 
     328           0 :     nsSVGEffects::InvalidateDirectRenderingObservers(mCanvasElement);
     329             : 
     330           0 :     mInvalidated = true;
     331           0 :     mCanvasElement->InvalidateCanvasContent(nullptr);
     332             : }
     333             : 
     334             : void
     335           0 : WebGLContext::OnVisibilityChange()
     336             : {
     337           0 :     if (!IsContextLost()) {
     338           0 :         return;
     339             :     }
     340             : 
     341           0 :     if (!mRestoreWhenVisible || mLastLossWasSimulated) {
     342           0 :         return;
     343             :     }
     344             : 
     345           0 :     ForceRestoreContext();
     346             : }
     347             : 
     348             : void
     349           0 : WebGLContext::OnMemoryPressure()
     350             : {
     351           0 :     bool shouldLoseContext = mLoseContextOnMemoryPressure;
     352             : 
     353           0 :     if (!mCanLoseContextInForeground &&
     354           0 :         ProcessPriorityManager::CurrentProcessIsForeground())
     355             :     {
     356           0 :         shouldLoseContext = false;
     357             :     }
     358             : 
     359           0 :     if (shouldLoseContext)
     360           0 :         ForceLoseContext();
     361           0 : }
     362             : 
     363             : //
     364             : // nsICanvasRenderingContextInternal
     365             : //
     366             : 
     367             : NS_IMETHODIMP
     368           0 : WebGLContext::SetContextOptions(JSContext* cx, JS::Handle<JS::Value> options,
     369             :                                 ErrorResult& aRvForDictionaryInit)
     370             : {
     371           0 :     if (options.isNullOrUndefined() && mOptionsFrozen)
     372           0 :         return NS_OK;
     373             : 
     374           0 :     WebGLContextAttributes attributes;
     375           0 :     if (!attributes.Init(cx, options)) {
     376           0 :       aRvForDictionaryInit.Throw(NS_ERROR_UNEXPECTED);
     377           0 :       return NS_ERROR_UNEXPECTED;
     378             :     }
     379             : 
     380           0 :     WebGLContextOptions newOpts;
     381             : 
     382           0 :     newOpts.stencil = attributes.mStencil;
     383           0 :     newOpts.depth = attributes.mDepth;
     384           0 :     newOpts.premultipliedAlpha = attributes.mPremultipliedAlpha;
     385           0 :     newOpts.antialias = attributes.mAntialias;
     386           0 :     newOpts.preserveDrawingBuffer = attributes.mPreserveDrawingBuffer;
     387           0 :     newOpts.failIfMajorPerformanceCaveat = attributes.mFailIfMajorPerformanceCaveat;
     388             : 
     389           0 :     if (attributes.mAlpha.WasPassed())
     390           0 :         newOpts.alpha = attributes.mAlpha.Value();
     391             : 
     392             :     // Don't do antialiasing if we've disabled MSAA.
     393           0 :     if (!gfxPrefs::MSAALevel())
     394           0 :       newOpts.antialias = false;
     395             : 
     396             : #if 0
     397             :     GenerateWarning("aaHint: %d stencil: %d depth: %d alpha: %d premult: %d preserve: %d\n",
     398             :                newOpts.antialias ? 1 : 0,
     399             :                newOpts.stencil ? 1 : 0,
     400             :                newOpts.depth ? 1 : 0,
     401             :                newOpts.alpha ? 1 : 0,
     402             :                newOpts.premultipliedAlpha ? 1 : 0,
     403             :                newOpts.preserveDrawingBuffer ? 1 : 0);
     404             : #endif
     405             : 
     406           0 :     if (mOptionsFrozen && newOpts != mOptions) {
     407             :         // Error if the options are already frozen, and the ones that were asked for
     408             :         // aren't the same as what they were originally.
     409           0 :         return NS_ERROR_FAILURE;
     410             :     }
     411             : 
     412           0 :     mOptions = newOpts;
     413           0 :     return NS_OK;
     414             : }
     415             : 
     416             : int32_t
     417           0 : WebGLContext::GetWidth() const
     418             : {
     419           0 :     return mWidth;
     420             : }
     421             : 
     422             : int32_t
     423           0 : WebGLContext::GetHeight() const
     424             : {
     425           0 :     return mHeight;
     426             : }
     427             : 
     428             : /* So there are a number of points of failure here. We might fail based
     429             :  * on EGL vs. WGL, or we might fail to alloc a too-large size, or we
     430             :  * might not be able to create a context with a certain combo of context
     431             :  * creation attribs.
     432             :  *
     433             :  * We don't want to test the complete fallback matrix. (for now, at
     434             :  * least) Instead, attempt creation in this order:
     435             :  * 1. By platform API. (e.g. EGL vs. WGL)
     436             :  * 2. By context creation attribs.
     437             :  * 3. By size.
     438             :  *
     439             :  * That is, try to create headless contexts based on the platform API.
     440             :  * Next, create dummy-sized backbuffers for the contexts with the right
     441             :  * caps. Finally, resize the backbuffer to an acceptable size given the
     442             :  * requested size.
     443             :  */
     444             : 
     445             : static bool
     446           0 : IsFeatureInBlacklist(const nsCOMPtr<nsIGfxInfo>& gfxInfo, int32_t feature,
     447             :                      nsCString* const out_blacklistId)
     448             : {
     449             :     int32_t status;
     450           0 :     if (!NS_SUCCEEDED(gfxUtils::ThreadSafeGetFeatureStatus(gfxInfo, feature,
     451             :                                                            *out_blacklistId, &status)))
     452             :     {
     453           0 :         return false;
     454             :     }
     455             : 
     456           0 :     return status != nsIGfxInfo::FEATURE_STATUS_OK;
     457             : }
     458             : 
     459             : static bool
     460           0 : HasAcceleratedLayers(const nsCOMPtr<nsIGfxInfo>& gfxInfo)
     461             : {
     462             :     int32_t status;
     463             : 
     464           0 :     nsCString discardFailureId;
     465             :     gfxUtils::ThreadSafeGetFeatureStatus(gfxInfo,
     466             :                                          nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS,
     467             :                                          discardFailureId,
     468           0 :                                          &status);
     469           0 :     if (status)
     470           0 :         return true;
     471             :     gfxUtils::ThreadSafeGetFeatureStatus(gfxInfo,
     472             :                                          nsIGfxInfo::FEATURE_DIRECT3D_10_LAYERS,
     473             :                                          discardFailureId,
     474           0 :                                          &status);
     475           0 :     if (status)
     476           0 :         return true;
     477             :     gfxUtils::ThreadSafeGetFeatureStatus(gfxInfo,
     478             :                                          nsIGfxInfo::FEATURE_DIRECT3D_10_1_LAYERS,
     479             :                                          discardFailureId,
     480           0 :                                          &status);
     481           0 :     if (status)
     482           0 :         return true;
     483             :     gfxUtils::ThreadSafeGetFeatureStatus(gfxInfo,
     484             :                                          nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS,
     485             :                                          discardFailureId,
     486           0 :                                          &status);
     487           0 :     if (status)
     488           0 :         return true;
     489             :     gfxUtils::ThreadSafeGetFeatureStatus(gfxInfo,
     490             :                                          nsIGfxInfo::FEATURE_OPENGL_LAYERS,
     491             :                                          discardFailureId,
     492           0 :                                          &status);
     493           0 :     if (status)
     494           0 :         return true;
     495             : 
     496           0 :     return false;
     497             : }
     498             : 
     499             : static void
     500           0 : PopulateCapFallbackQueue(const gl::SurfaceCaps& baseCaps,
     501             :                          std::queue<gl::SurfaceCaps>* out_fallbackCaps)
     502             : {
     503           0 :     out_fallbackCaps->push(baseCaps);
     504             : 
     505             :     // Dropping antialias drops our quality, but not our correctness.
     506             :     // The user basically doesn't have to handle if this fails, they
     507             :     // just get reduced quality.
     508           0 :     if (baseCaps.antialias) {
     509           0 :         gl::SurfaceCaps nextCaps(baseCaps);
     510           0 :         nextCaps.antialias = false;
     511           0 :         PopulateCapFallbackQueue(nextCaps, out_fallbackCaps);
     512             :     }
     513             : 
     514             :     // If we have to drop one of depth or stencil, we'd prefer to keep
     515             :     // depth. However, the client app will need to handle if this
     516             :     // doesn't work.
     517           0 :     if (baseCaps.stencil) {
     518           0 :         gl::SurfaceCaps nextCaps(baseCaps);
     519           0 :         nextCaps.stencil = false;
     520           0 :         PopulateCapFallbackQueue(nextCaps, out_fallbackCaps);
     521             :     }
     522             : 
     523           0 :     if (baseCaps.depth) {
     524           0 :         gl::SurfaceCaps nextCaps(baseCaps);
     525           0 :         nextCaps.depth = false;
     526           0 :         PopulateCapFallbackQueue(nextCaps, out_fallbackCaps);
     527             :     }
     528           0 : }
     529             : 
     530             : static gl::SurfaceCaps
     531           0 : BaseCaps(const WebGLContextOptions& options, WebGLContext* webgl)
     532             : {
     533           0 :     gl::SurfaceCaps baseCaps;
     534             : 
     535           0 :     baseCaps.color = true;
     536           0 :     baseCaps.alpha = options.alpha;
     537           0 :     baseCaps.antialias = options.antialias;
     538           0 :     baseCaps.depth = options.depth;
     539           0 :     baseCaps.premultAlpha = options.premultipliedAlpha;
     540           0 :     baseCaps.preserve = options.preserveDrawingBuffer;
     541           0 :     baseCaps.stencil = options.stencil;
     542             : 
     543           0 :     if (!baseCaps.alpha)
     544           0 :         baseCaps.premultAlpha = true;
     545             : 
     546             :     // we should really have this behind a
     547             :     // |gfxPlatform::GetPlatform()->GetScreenDepth() == 16| check, but
     548             :     // for now it's just behind a pref for testing/evaluation.
     549           0 :     baseCaps.bpp16 = gfxPrefs::WebGLPrefer16bpp();
     550             : 
     551             : #ifdef MOZ_WIDGET_GONK
     552             :     do {
     553             :         auto canvasElement = webgl->GetCanvas();
     554             :         if (!canvasElement)
     555             :             break;
     556             : 
     557             :         auto ownerDoc = canvasElement->OwnerDoc();
     558             :         nsIWidget* docWidget = nsContentUtils::WidgetForDocument(ownerDoc);
     559             :         if (!docWidget)
     560             :             break;
     561             : 
     562             :         layers::LayerManager* layerManager = docWidget->GetLayerManager();
     563             :         if (!layerManager)
     564             :             break;
     565             : 
     566             :         // XXX we really want "AsSurfaceAllocator" here for generality
     567             :         layers::ShadowLayerForwarder* forwarder = layerManager->AsShadowForwarder();
     568             :         if (!forwarder)
     569             :             break;
     570             : 
     571             :         baseCaps.surfaceAllocator = forwarder->GetTextureForwarder();
     572             :     } while (false);
     573             : #endif
     574             : 
     575             :     // Done with baseCaps construction.
     576             : 
     577           0 :     if (!gfxPrefs::WebGLForceMSAA()) {
     578           0 :         const nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
     579             : 
     580           0 :         nsCString blocklistId;
     581           0 :         if (IsFeatureInBlacklist(gfxInfo, nsIGfxInfo::FEATURE_WEBGL_MSAA, &blocklistId)) {
     582             :             webgl->GenerateWarning("Disallowing antialiased backbuffers due"
     583           0 :                                    " to blacklisting.");
     584           0 :             baseCaps.antialias = false;
     585             :         }
     586             :     }
     587             : 
     588           0 :     return baseCaps;
     589             : }
     590             : 
     591             : ////////////////////////////////////////
     592             : 
     593             : static already_AddRefed<gl::GLContext>
     594           0 : CreateGLWithEGL(const gl::SurfaceCaps& caps, gl::CreateContextFlags flags,
     595             :                 WebGLContext* webgl,
     596             :                 std::vector<WebGLContext::FailureReason>* const out_failReasons)
     597             : {
     598           0 :     const gfx::IntSize dummySize(16, 16);
     599           0 :     nsCString failureId;
     600           0 :     RefPtr<GLContext> gl = gl::GLContextProviderEGL::CreateOffscreen(dummySize, caps,
     601           0 :                                                                      flags, &failureId);
     602           0 :     if (gl && gl->IsANGLE()) {
     603           0 :         gl = nullptr;
     604             :     }
     605             : 
     606           0 :     if (!gl) {
     607           0 :         out_failReasons->push_back(WebGLContext::FailureReason(
     608             :             failureId,
     609             :             "Error during EGL OpenGL init."
     610           0 :         ));
     611           0 :         return nullptr;
     612             :     }
     613             : 
     614           0 :     return gl.forget();
     615             : }
     616             : 
     617             : static already_AddRefed<GLContext>
     618           0 : CreateGLWithANGLE(const gl::SurfaceCaps& caps, gl::CreateContextFlags flags,
     619             :                   WebGLContext* webgl,
     620             :                   std::vector<WebGLContext::FailureReason>* const out_failReasons)
     621             : {
     622           0 :     const gfx::IntSize dummySize(16, 16);
     623           0 :     nsCString failureId;
     624           0 :     RefPtr<GLContext> gl = gl::GLContextProviderEGL::CreateOffscreen(dummySize, caps,
     625           0 :                                                                      flags, &failureId);
     626           0 :     if (gl && !gl->IsANGLE()) {
     627           0 :         gl = nullptr;
     628             :     }
     629             : 
     630           0 :     if (!gl) {
     631           0 :         out_failReasons->push_back(WebGLContext::FailureReason(
     632             :             failureId,
     633             :             "Error during ANGLE OpenGL init."
     634           0 :         ));
     635           0 :         return nullptr;
     636             :     }
     637             : 
     638           0 :     return gl.forget();
     639             : }
     640             : 
     641             : static already_AddRefed<gl::GLContext>
     642           0 : CreateGLWithDefault(const gl::SurfaceCaps& caps, gl::CreateContextFlags flags,
     643             :                     WebGLContext* webgl,
     644             :                     std::vector<WebGLContext::FailureReason>* const out_failReasons)
     645             : {
     646           0 :     const gfx::IntSize dummySize(16, 16);
     647           0 :     nsCString failureId;
     648           0 :     RefPtr<GLContext> gl = gl::GLContextProvider::CreateOffscreen(dummySize, caps,
     649           0 :                                                                   flags, &failureId);
     650           0 :     if (gl && gl->IsANGLE()) {
     651           0 :         gl = nullptr;
     652             :     }
     653             : 
     654           0 :     if (!gl) {
     655           0 :         out_failReasons->push_back(WebGLContext::FailureReason(
     656             :             failureId,
     657             :             "Error during native OpenGL init."
     658           0 :         ));
     659           0 :         return nullptr;
     660             :     }
     661             : 
     662           0 :     return gl.forget();
     663             : }
     664             : 
     665             : ////////////////////////////////////////
     666             : 
     667             : bool
     668           0 : WebGLContext::CreateAndInitGLWith(FnCreateGL_T fnCreateGL,
     669             :                                   const gl::SurfaceCaps& baseCaps,
     670             :                                   gl::CreateContextFlags flags,
     671             :                                   std::vector<FailureReason>* const out_failReasons)
     672             : {
     673           0 :     std::queue<gl::SurfaceCaps> fallbackCaps;
     674           0 :     PopulateCapFallbackQueue(baseCaps, &fallbackCaps);
     675             : 
     676           0 :     MOZ_RELEASE_ASSERT(!gl, "GFX: Already have a context.");
     677           0 :     RefPtr<gl::GLContext> potentialGL;
     678           0 :     while (!fallbackCaps.empty()) {
     679           0 :         const gl::SurfaceCaps& caps = fallbackCaps.front();
     680           0 :         potentialGL = fnCreateGL(caps, flags, this, out_failReasons);
     681           0 :         if (potentialGL)
     682           0 :             break;
     683             : 
     684           0 :         fallbackCaps.pop();
     685             :     }
     686           0 :     if (!potentialGL) {
     687           0 :         out_failReasons->push_back(FailureReason("FEATURE_FAILURE_WEBGL_EXHAUSTED_CAPS",
     688           0 :                                                  "Exhausted GL driver caps."));
     689           0 :         return false;
     690             :     }
     691             : 
     692           0 :     FailureReason reason;
     693             : 
     694           0 :     mGL_OnlyClearInDestroyResourcesAndContext = potentialGL;
     695           0 :     MOZ_RELEASE_ASSERT(gl);
     696           0 :     if (!InitAndValidateGL(&reason)) {
     697           0 :         DestroyResourcesAndContext();
     698           0 :         MOZ_RELEASE_ASSERT(!gl);
     699             : 
     700             :         // The fail reason here should be specific enough for now.
     701           0 :         out_failReasons->push_back(reason);
     702           0 :         return false;
     703             :     }
     704             : 
     705           0 :     return true;
     706             : }
     707             : 
     708             : bool
     709           0 : WebGLContext::CreateAndInitGL(bool forceEnabled,
     710             :                               std::vector<FailureReason>* const out_failReasons)
     711             : {
     712             :     // WebGL2 is separately blocked:
     713           0 :     if (IsWebGL2()) {
     714           0 :         const nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
     715           0 :         const auto feature = nsIGfxInfo::FEATURE_WEBGL2;
     716             : 
     717           0 :         FailureReason reason;
     718           0 :         if (IsFeatureInBlacklist(gfxInfo, feature, &reason.key)) {
     719             :             reason.info = "Refused to create WebGL2 context because of blacklist"
     720           0 :                           " entry: ";
     721           0 :             reason.info.Append(reason.key);
     722           0 :             out_failReasons->push_back(reason);
     723           0 :             GenerateWarning("%s", reason.info.BeginReading());
     724           0 :             return false;
     725             :         }
     726             :     }
     727             : 
     728           0 :     const gl::SurfaceCaps baseCaps = BaseCaps(mOptions, this);
     729           0 :     gl::CreateContextFlags flags = (gl::CreateContextFlags::NO_VALIDATION |
     730           0 :                                     gl::CreateContextFlags::PREFER_ROBUSTNESS);
     731           0 :     bool tryNativeGL = true;
     732           0 :     bool tryANGLE = false;
     733             : 
     734           0 :     if (forceEnabled) {
     735           0 :         flags |= gl::CreateContextFlags::FORCE_ENABLE_HARDWARE;
     736             :     }
     737             : 
     738           0 :     if (IsWebGL2()) {
     739           0 :         flags |= gl::CreateContextFlags::PREFER_ES3;
     740             :     } else {
     741           0 :         flags |= gl::CreateContextFlags::REQUIRE_COMPAT_PROFILE;
     742             :     }
     743             : 
     744             :     //////
     745             : 
     746           0 :     const bool useEGL = PR_GetEnv("MOZ_WEBGL_FORCE_EGL");
     747             : 
     748             : #ifdef XP_WIN
     749             :     tryNativeGL = false;
     750             :     tryANGLE = true;
     751             : 
     752             :     if (gfxPrefs::WebGLDisableWGL()) {
     753             :         tryNativeGL = false;
     754             :     }
     755             : 
     756             :     if (gfxPrefs::WebGLDisableANGLE() || PR_GetEnv("MOZ_WEBGL_FORCE_OPENGL") || useEGL) {
     757             :         tryNativeGL = true;
     758             :         tryANGLE = false;
     759             :     }
     760             : #endif
     761             : 
     762           0 :     if (tryNativeGL && !forceEnabled) {
     763           0 :         const nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
     764           0 :         const auto feature = nsIGfxInfo::FEATURE_WEBGL_OPENGL;
     765             : 
     766           0 :         FailureReason reason;
     767           0 :         if (IsFeatureInBlacklist(gfxInfo, feature, &reason.key)) {
     768             :             reason.info = "Refused to create native OpenGL context because of blacklist"
     769           0 :                           " entry: ";
     770           0 :             reason.info.Append(reason.key);
     771             : 
     772           0 :             out_failReasons->push_back(reason);
     773             : 
     774           0 :             GenerateWarning("%s", reason.info.BeginReading());
     775           0 :             tryNativeGL = false;
     776             :         }
     777             :     }
     778             : 
     779             :     //////
     780             : 
     781           0 :     if (tryNativeGL) {
     782           0 :         if (useEGL)
     783           0 :             return CreateAndInitGLWith(CreateGLWithEGL, baseCaps, flags, out_failReasons);
     784             : 
     785           0 :         if (CreateAndInitGLWith(CreateGLWithDefault, baseCaps, flags, out_failReasons))
     786           0 :             return true;
     787             :     }
     788             : 
     789             :     //////
     790             : 
     791           0 :     if (tryANGLE)
     792           0 :         return CreateAndInitGLWith(CreateGLWithANGLE, baseCaps, flags, out_failReasons);
     793             : 
     794             :     //////
     795             : 
     796           0 :     out_failReasons->push_back(FailureReason("FEATURE_FAILURE_WEBGL_EXHAUSTED_DRIVERS",
     797           0 :                                              "Exhausted GL driver options."));
     798           0 :     return false;
     799             : }
     800             : 
     801             : // Fallback for resizes:
     802             : bool
     803           0 : WebGLContext::ResizeBackbuffer(uint32_t requestedWidth,
     804             :                                uint32_t requestedHeight)
     805             : {
     806           0 :     uint32_t width = requestedWidth;
     807           0 :     uint32_t height = requestedHeight;
     808             : 
     809           0 :     bool resized = false;
     810           0 :     while (width || height) {
     811           0 :       width = width ? width : 1;
     812           0 :       height = height ? height : 1;
     813             : 
     814           0 :       gfx::IntSize curSize(width, height);
     815           0 :       if (gl->ResizeOffscreen(curSize)) {
     816           0 :           resized = true;
     817           0 :           break;
     818             :       }
     819             : 
     820           0 :       width /= 2;
     821           0 :       height /= 2;
     822             :     }
     823             : 
     824           0 :     if (!resized)
     825           0 :         return false;
     826             : 
     827           0 :     mWidth = gl->OffscreenSize().width;
     828           0 :     mHeight = gl->OffscreenSize().height;
     829           0 :     MOZ_ASSERT((uint32_t)mWidth == width);
     830           0 :     MOZ_ASSERT((uint32_t)mHeight == height);
     831             : 
     832           0 :     if (width != requestedWidth ||
     833             :         height != requestedHeight)
     834             :     {
     835             :         GenerateWarning("Requested size %dx%d was too large, but resize"
     836             :                           " to %dx%d succeeded.",
     837             :                         requestedWidth, requestedHeight,
     838           0 :                         width, height);
     839             :     }
     840           0 :     return true;
     841             : }
     842             : 
     843             : void
     844           0 : WebGLContext::ThrowEvent_WebGLContextCreationError(const nsACString& text)
     845             : {
     846           0 :     RefPtr<EventTarget> target = mCanvasElement;
     847           0 :     if (!target && mOffscreenCanvas) {
     848           0 :         target = mOffscreenCanvas;
     849           0 :     } else if (!target) {
     850           0 :         GenerateWarning("Failed to create WebGL context: %s", text.BeginReading());
     851           0 :         return;
     852             :     }
     853             : 
     854           0 :     const auto kEventName = NS_LITERAL_STRING("webglcontextcreationerror");
     855             : 
     856           0 :     WebGLContextEventInit eventInit;
     857             :     // eventInit.mCancelable = true; // The spec says this, but it's silly.
     858           0 :     eventInit.mStatusMessage = NS_ConvertASCIItoUTF16(text);
     859             : 
     860           0 :     const RefPtr<WebGLContextEvent> event = WebGLContextEvent::Constructor(target,
     861             :                                                                            kEventName,
     862           0 :                                                                            eventInit);
     863           0 :     event->SetTrusted(true);
     864             : 
     865             :     bool didPreventDefault;
     866           0 :     target->DispatchEvent(event, &didPreventDefault);
     867             : 
     868             :     //////
     869             : 
     870           0 :     GenerateWarning("Failed to create WebGL context: %s", text.BeginReading());
     871             : }
     872             : 
     873             : NS_IMETHODIMP
     874           0 : WebGLContext::SetDimensions(int32_t signedWidth, int32_t signedHeight)
     875             : {
     876           0 :     if (signedWidth < 0 || signedHeight < 0) {
     877           0 :         if (!gl) {
     878           0 :             Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_FAILURE_ID,
     879           0 :                                   NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBGL_SIZE"));
     880             :         }
     881           0 :         GenerateWarning("Canvas size is too large (seems like a negative value wrapped)");
     882           0 :         return NS_ERROR_OUT_OF_MEMORY;
     883             :     }
     884             : 
     885           0 :     uint32_t width = signedWidth;
     886           0 :     uint32_t height = signedHeight;
     887             : 
     888             :     // Early success return cases
     889             : 
     890             :     // May have a OffscreenCanvas instead of an HTMLCanvasElement
     891           0 :     if (GetCanvas())
     892           0 :         GetCanvas()->InvalidateCanvas();
     893             : 
     894             :     // Zero-sized surfaces can cause problems.
     895           0 :     if (width == 0)
     896           0 :         width = 1;
     897             : 
     898           0 :     if (height == 0)
     899           0 :         height = 1;
     900             : 
     901             :     // If we already have a gl context, then we just need to resize it
     902           0 :     if (gl) {
     903           0 :         if ((uint32_t)mWidth == width &&
     904           0 :             (uint32_t)mHeight == height)
     905             :         {
     906           0 :             return NS_OK;
     907             :         }
     908             : 
     909           0 :         if (IsContextLost())
     910           0 :             return NS_OK;
     911             : 
     912           0 :         MakeContextCurrent();
     913             : 
     914             :         // If we've already drawn, we should commit the current buffer.
     915           0 :         PresentScreenBuffer();
     916             : 
     917           0 :         if (IsContextLost()) {
     918           0 :             GenerateWarning("WebGL context was lost due to swap failure.");
     919           0 :             return NS_OK;
     920             :         }
     921             : 
     922             :         // ResizeOffscreen scraps the current prod buffer before making a new one.
     923           0 :         if (!ResizeBackbuffer(width, height)) {
     924           0 :             GenerateWarning("WebGL context failed to resize.");
     925           0 :             ForceLoseContext();
     926           0 :             return NS_OK;
     927             :         }
     928             : 
     929             :         // everything's good, we're done here
     930           0 :         mResetLayer = true;
     931           0 :         mBackbufferNeedsClear = true;
     932             : 
     933           0 :         return NS_OK;
     934             :     }
     935             : 
     936           0 :     nsCString failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBGL_UNKOWN");
     937           0 :     auto autoTelemetry = mozilla::MakeScopeExit([&] {
     938             :         Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_FAILURE_ID,
     939           0 :                               failureId);
     940           0 :     });
     941             : 
     942             :     // End of early return cases.
     943             :     // At this point we know that we're not just resizing an existing context,
     944             :     // we are initializing a new context.
     945             : 
     946             :     // if we exceeded either the global or the per-principal limit for WebGL contexts,
     947             :     // lose the oldest-used context now to free resources. Note that we can't do that
     948             :     // in the WebGLContext constructor as we don't have a canvas element yet there.
     949             :     // Here is the right place to do so, as we are about to create the OpenGL context
     950             :     // and that is what can fail if we already have too many.
     951           0 :     LoseOldestWebGLContextIfLimitExceeded();
     952             : 
     953             :     // We're going to create an entirely new context.  If our
     954             :     // generation is not 0 right now (that is, if this isn't the first
     955             :     // context we're creating), we may have to dispatch a context lost
     956             :     // event.
     957             : 
     958             :     // If incrementing the generation would cause overflow,
     959             :     // don't allow it.  Allowing this would allow us to use
     960             :     // resource handles created from older context generations.
     961           0 :     if (!(mGeneration + 1).isValid()) {
     962             :         // exit without changing the value of mGeneration
     963           0 :         failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBGL_TOO_MANY");
     964           0 :         const nsLiteralCString text("Too many WebGL contexts created this run.");
     965           0 :         ThrowEvent_WebGLContextCreationError(text);
     966           0 :         return NS_ERROR_FAILURE;
     967             :     }
     968             : 
     969             :     // increment the generation number - Do this early because later
     970             :     // in CreateOffscreenGL(), "default" objects are created that will
     971             :     // pick up the old generation.
     972           0 :     ++mGeneration;
     973             : 
     974           0 :     bool disabled = gfxPrefs::WebGLDisabled();
     975             : 
     976             :     // TODO: When we have software webgl support we should use that instead.
     977           0 :     disabled |= gfxPlatform::InSafeMode();
     978             : 
     979           0 :     if (disabled) {
     980           0 :         if (gfxPlatform::InSafeMode()) {
     981           0 :             failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBGL_SAFEMODE");
     982             :         } else {
     983           0 :             failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBGL_DISABLED");
     984             :         }
     985           0 :         const nsLiteralCString text("WebGL is currently disabled.");
     986           0 :         ThrowEvent_WebGLContextCreationError(text);
     987           0 :         return NS_ERROR_FAILURE;
     988             :     }
     989             : 
     990           0 :     if (gfxPrefs::WebGLDisableFailIfMajorPerformanceCaveat()) {
     991           0 :         mOptions.failIfMajorPerformanceCaveat = false;
     992             :     }
     993             : 
     994           0 :     if (mOptions.failIfMajorPerformanceCaveat) {
     995           0 :         nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
     996           0 :         if (!HasAcceleratedLayers(gfxInfo)) {
     997           0 :             failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBGL_PERF_CAVEAT");
     998             :             const nsLiteralCString text("failIfMajorPerformanceCaveat: Compositor is not"
     999           0 :                                         " hardware-accelerated.");
    1000           0 :             ThrowEvent_WebGLContextCreationError(text);
    1001           0 :             return NS_ERROR_FAILURE;
    1002             :         }
    1003             :     }
    1004             : 
    1005             :     // Alright, now let's start trying.
    1006           0 :     bool forceEnabled = gfxPrefs::WebGLForceEnabled();
    1007           0 :     ScopedGfxFeatureReporter reporter("WebGL", forceEnabled);
    1008             : 
    1009           0 :     MOZ_ASSERT(!gl);
    1010           0 :     std::vector<FailureReason> failReasons;
    1011           0 :     if (!CreateAndInitGL(forceEnabled, &failReasons)) {
    1012           0 :         nsCString text("WebGL creation failed: ");
    1013           0 :         for (const auto& cur : failReasons) {
    1014             :             // Don't try to accumulate using an empty key if |cur.key| is empty.
    1015           0 :             if (cur.key.IsEmpty()) {
    1016           0 :                 Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_FAILURE_ID,
    1017           0 :                                       NS_LITERAL_CSTRING("FEATURE_FAILURE_REASON_UNKNOWN"));
    1018             :             } else {
    1019           0 :                 Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_FAILURE_ID, cur.key);
    1020             :             }
    1021             : 
    1022           0 :             text.AppendASCII("\n* ");
    1023           0 :             text.Append(cur.info);
    1024             :         }
    1025           0 :         failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_REASON");
    1026           0 :         ThrowEvent_WebGLContextCreationError(text);
    1027           0 :         return NS_ERROR_FAILURE;
    1028             :     }
    1029           0 :     MOZ_ASSERT(gl);
    1030           0 :     MOZ_ASSERT_IF(mOptions.alpha, gl->Caps().alpha);
    1031             : 
    1032           0 :     if (mOptions.failIfMajorPerformanceCaveat) {
    1033           0 :         if (gl->IsWARP()) {
    1034           0 :             DestroyResourcesAndContext();
    1035           0 :             MOZ_ASSERT(!gl);
    1036             : 
    1037           0 :             failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBGL_PERF_WARP");
    1038             :             const nsLiteralCString text("failIfMajorPerformanceCaveat: Driver is not"
    1039           0 :                                         " hardware-accelerated.");
    1040           0 :             ThrowEvent_WebGLContextCreationError(text);
    1041           0 :             return NS_ERROR_FAILURE;
    1042             :         }
    1043             : 
    1044             : #ifdef XP_WIN
    1045             :         if (gl->GetContextType() == gl::GLContextType::WGL &&
    1046             :             !gl::sWGLLib.HasDXInterop2())
    1047             :         {
    1048             :             DestroyResourcesAndContext();
    1049             :             MOZ_ASSERT(!gl);
    1050             : 
    1051             :             failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBGL_DXGL_INTEROP2");
    1052             :             const nsLiteralCString text("Caveat: WGL without DXGLInterop2.");
    1053             :             ThrowEvent_WebGLContextCreationError(text);
    1054             :             return NS_ERROR_FAILURE;
    1055             :         }
    1056             : #endif
    1057             :     }
    1058             : 
    1059           0 :     if (!ResizeBackbuffer(width, height)) {
    1060           0 :         failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBGL_BACKBUFFER");
    1061           0 :         const nsLiteralCString text("Initializing WebGL backbuffer failed.");
    1062           0 :         ThrowEvent_WebGLContextCreationError(text);
    1063           0 :         return NS_ERROR_FAILURE;
    1064             :     }
    1065             : 
    1066           0 :     if (GLContext::ShouldSpew()) {
    1067           0 :         printf_stderr("--- WebGL context created: %p\n", gl.get());
    1068             :     }
    1069             : 
    1070           0 :     mResetLayer = true;
    1071           0 :     mOptionsFrozen = true;
    1072             : 
    1073             :     // Update our internal stuff:
    1074           0 :     if (gl->WorkAroundDriverBugs()) {
    1075           0 :         if (!mOptions.alpha && gl->Caps().alpha)
    1076           0 :             mNeedsFakeNoAlpha = true;
    1077             : 
    1078           0 :         if (!mOptions.depth && gl->Caps().depth)
    1079           0 :             mNeedsFakeNoDepth = true;
    1080             : 
    1081           0 :         if (!mOptions.stencil && gl->Caps().stencil)
    1082           0 :             mNeedsFakeNoStencil = true;
    1083             : 
    1084             : #ifdef MOZ_WIDGET_COCOA
    1085             :         if (!nsCocoaFeatures::IsAtLeastVersion(10, 12) &&
    1086             :             gl->Vendor() == GLVendor::Intel)
    1087             :         {
    1088             :             mNeedsEmulatedLoneDepthStencil = true;
    1089             :         }
    1090             : #endif
    1091             :     }
    1092             : 
    1093             :     // Update mOptions.
    1094           0 :     if (!gl->Caps().depth)
    1095           0 :         mOptions.depth = false;
    1096             : 
    1097           0 :     if (!gl->Caps().stencil)
    1098           0 :         mOptions.stencil = false;
    1099             : 
    1100           0 :     mOptions.antialias = gl->Caps().antialias;
    1101             : 
    1102             :     //////
    1103             :     // Initial setup.
    1104             : 
    1105           0 :     MakeContextCurrent();
    1106             : 
    1107           0 :     gl->fViewport(0, 0, mWidth, mHeight);
    1108           0 :     mViewportX = mViewportY = 0;
    1109           0 :     mViewportWidth = mWidth;
    1110           0 :     mViewportHeight = mHeight;
    1111             : 
    1112           0 :     gl->fScissor(0, 0, mWidth, mHeight);
    1113           0 :     gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
    1114             : 
    1115             :     //////
    1116             :     // Check everything
    1117             : 
    1118           0 :     AssertCachedBindings();
    1119           0 :     AssertCachedGlobalState();
    1120             : 
    1121           0 :     MOZ_ASSERT(gl->Caps().color);
    1122             : 
    1123           0 :     MOZ_ASSERT_IF(!mNeedsFakeNoAlpha, gl->Caps().alpha == mOptions.alpha);
    1124           0 :     MOZ_ASSERT_IF(mNeedsFakeNoAlpha, !mOptions.alpha && gl->Caps().alpha);
    1125             : 
    1126           0 :     MOZ_ASSERT_IF(!mNeedsFakeNoDepth, gl->Caps().depth == mOptions.depth);
    1127           0 :     MOZ_ASSERT_IF(mNeedsFakeNoDepth, !mOptions.depth && gl->Caps().depth);
    1128             : 
    1129           0 :     MOZ_ASSERT_IF(!mNeedsFakeNoStencil, gl->Caps().stencil == mOptions.stencil);
    1130           0 :     MOZ_ASSERT_IF(mNeedsFakeNoStencil, !mOptions.stencil && gl->Caps().stencil);
    1131             : 
    1132           0 :     MOZ_ASSERT(gl->Caps().antialias == mOptions.antialias);
    1133           0 :     MOZ_ASSERT(gl->Caps().preserve == mOptions.preserveDrawingBuffer);
    1134             : 
    1135             :     //////
    1136             :     // Clear immediately, because we need to present the cleared initial buffer
    1137           0 :     mBackbufferNeedsClear = true;
    1138           0 :     ClearBackbufferIfNeeded();
    1139             : 
    1140           0 :     mShouldPresent = true;
    1141             : 
    1142             :     //////
    1143             : 
    1144           0 :     reporter.SetSuccessful();
    1145             : 
    1146           0 :     failureId = NS_LITERAL_CSTRING("SUCCESS");
    1147           0 :     return NS_OK;
    1148             : }
    1149             : 
    1150             : void
    1151           0 : WebGLContext::ClearBackbufferIfNeeded()
    1152             : {
    1153           0 :     if (!mBackbufferNeedsClear)
    1154           0 :         return;
    1155             : 
    1156           0 :     ClearScreen();
    1157             : 
    1158           0 :     mBackbufferNeedsClear = false;
    1159             : }
    1160             : 
    1161             : void
    1162           0 : WebGLContext::LoseOldestWebGLContextIfLimitExceeded()
    1163             : {
    1164             : #ifdef MOZ_GFX_OPTIMIZE_MOBILE
    1165             :     // some mobile devices can't have more than 8 GL contexts overall
    1166             :     const size_t kMaxWebGLContextsPerPrincipal = 2;
    1167             :     const size_t kMaxWebGLContexts             = 4;
    1168             : #else
    1169           0 :     const size_t kMaxWebGLContextsPerPrincipal = 16;
    1170           0 :     const size_t kMaxWebGLContexts             = 32;
    1171             : #endif
    1172             :     MOZ_ASSERT(kMaxWebGLContextsPerPrincipal < kMaxWebGLContexts);
    1173             : 
    1174           0 :     if (!NS_IsMainThread()) {
    1175             :         // XXX mtseng: bug 709490, WebGLMemoryTracker is not thread safe.
    1176           0 :         return;
    1177             :     }
    1178             : 
    1179             :     // it's important to update the index on a new context before losing old contexts,
    1180             :     // otherwise new unused contexts would all have index 0 and we couldn't distinguish older ones
    1181             :     // when choosing which one to lose first.
    1182           0 :     UpdateLastUseIndex();
    1183             : 
    1184           0 :     WebGLMemoryTracker::ContextsArrayType& contexts = WebGLMemoryTracker::Contexts();
    1185             : 
    1186             :     // quick exit path, should cover a majority of cases
    1187           0 :     if (contexts.Length() <= kMaxWebGLContextsPerPrincipal)
    1188           0 :         return;
    1189             : 
    1190             :     // note that here by "context" we mean "non-lost context". See the check for
    1191             :     // IsContextLost() below. Indeed, the point of this function is to maybe lose
    1192             :     // some currently non-lost context.
    1193             : 
    1194           0 :     uint64_t oldestIndex = UINT64_MAX;
    1195           0 :     uint64_t oldestIndexThisPrincipal = UINT64_MAX;
    1196           0 :     const WebGLContext* oldestContext = nullptr;
    1197           0 :     const WebGLContext* oldestContextThisPrincipal = nullptr;
    1198           0 :     size_t numContexts = 0;
    1199           0 :     size_t numContextsThisPrincipal = 0;
    1200             : 
    1201           0 :     for(size_t i = 0; i < contexts.Length(); ++i) {
    1202             :         // don't want to lose ourselves.
    1203           0 :         if (contexts[i] == this)
    1204           0 :             continue;
    1205             : 
    1206           0 :         if (contexts[i]->IsContextLost())
    1207           0 :             continue;
    1208             : 
    1209           0 :         if (!contexts[i]->GetCanvas()) {
    1210             :             // Zombie context: the canvas is already destroyed, but something else
    1211             :             // (typically the compositor) is still holding on to the context.
    1212             :             // Killing zombies is a no-brainer.
    1213           0 :             const_cast<WebGLContext*>(contexts[i])->LoseContext();
    1214           0 :             continue;
    1215             :         }
    1216             : 
    1217           0 :         numContexts++;
    1218           0 :         if (contexts[i]->mLastUseIndex < oldestIndex) {
    1219           0 :             oldestIndex = contexts[i]->mLastUseIndex;
    1220           0 :             oldestContext = contexts[i];
    1221             :         }
    1222             : 
    1223           0 :         nsIPrincipal* ourPrincipal = GetCanvas()->NodePrincipal();
    1224           0 :         nsIPrincipal* theirPrincipal = contexts[i]->GetCanvas()->NodePrincipal();
    1225             :         bool samePrincipal;
    1226           0 :         nsresult rv = ourPrincipal->Equals(theirPrincipal, &samePrincipal);
    1227           0 :         if (NS_SUCCEEDED(rv) && samePrincipal) {
    1228           0 :             numContextsThisPrincipal++;
    1229           0 :             if (contexts[i]->mLastUseIndex < oldestIndexThisPrincipal) {
    1230           0 :                 oldestIndexThisPrincipal = contexts[i]->mLastUseIndex;
    1231           0 :                 oldestContextThisPrincipal = contexts[i];
    1232             :             }
    1233             :         }
    1234             :     }
    1235             : 
    1236           0 :     if (numContextsThisPrincipal > kMaxWebGLContextsPerPrincipal) {
    1237             :         GenerateWarning("Exceeded %" PRIuSIZE " live WebGL contexts for this principal, losing the "
    1238           0 :                         "least recently used one.", kMaxWebGLContextsPerPrincipal);
    1239           0 :         MOZ_ASSERT(oldestContextThisPrincipal); // if we reach this point, this can't be null
    1240           0 :         const_cast<WebGLContext*>(oldestContextThisPrincipal)->LoseContext();
    1241           0 :     } else if (numContexts > kMaxWebGLContexts) {
    1242             :         GenerateWarning("Exceeded %" PRIuSIZE " live WebGL contexts, losing the least "
    1243           0 :                         "recently used one.", kMaxWebGLContexts);
    1244           0 :         MOZ_ASSERT(oldestContext); // if we reach this point, this can't be null
    1245           0 :         const_cast<WebGLContext*>(oldestContext)->LoseContext();
    1246             :     }
    1247             : }
    1248             : 
    1249             : UniquePtr<uint8_t[]>
    1250           0 : WebGLContext::GetImageBuffer(int32_t* out_format)
    1251             : {
    1252           0 :     *out_format = 0;
    1253             : 
    1254             :     // Use GetSurfaceSnapshot() to make sure that appropriate y-flip gets applied
    1255             :     gfxAlphaType any;
    1256           0 :     RefPtr<SourceSurface> snapshot = GetSurfaceSnapshot(&any);
    1257           0 :     if (!snapshot)
    1258           0 :         return nullptr;
    1259             : 
    1260           0 :     RefPtr<DataSourceSurface> dataSurface = snapshot->GetDataSurface();
    1261             : 
    1262           0 :     return gfxUtils::GetImageBuffer(dataSurface, mOptions.premultipliedAlpha,
    1263           0 :                                     out_format);
    1264             : }
    1265             : 
    1266             : NS_IMETHODIMP
    1267           0 : WebGLContext::GetInputStream(const char* mimeType,
    1268             :                              const char16_t* encoderOptions,
    1269             :                              nsIInputStream** out_stream)
    1270             : {
    1271           0 :     NS_ASSERTION(gl, "GetInputStream on invalid context?");
    1272           0 :     if (!gl)
    1273           0 :         return NS_ERROR_FAILURE;
    1274             : 
    1275             :     // Use GetSurfaceSnapshot() to make sure that appropriate y-flip gets applied
    1276             :     gfxAlphaType any;
    1277           0 :     RefPtr<SourceSurface> snapshot = GetSurfaceSnapshot(&any);
    1278           0 :     if (!snapshot)
    1279           0 :         return NS_ERROR_FAILURE;
    1280             : 
    1281           0 :     RefPtr<DataSourceSurface> dataSurface = snapshot->GetDataSurface();
    1282           0 :     return gfxUtils::GetInputStream(dataSurface, mOptions.premultipliedAlpha, mimeType,
    1283           0 :                                     encoderOptions, out_stream);
    1284             : }
    1285             : 
    1286             : void
    1287           0 : WebGLContext::UpdateLastUseIndex()
    1288             : {
    1289             :     static CheckedInt<uint64_t> sIndex = 0;
    1290             : 
    1291           0 :     sIndex++;
    1292             : 
    1293             :     // should never happen with 64-bit; trying to handle this would be riskier than
    1294             :     // not handling it as the handler code would never get exercised.
    1295           0 :     if (!sIndex.isValid())
    1296           0 :         MOZ_CRASH("Can't believe it's been 2^64 transactions already!");
    1297           0 :     mLastUseIndex = sIndex.value();
    1298           0 : }
    1299             : 
    1300             : static uint8_t gWebGLLayerUserData;
    1301             : static uint8_t gWebGLMirrorLayerUserData;
    1302             : 
    1303           0 : class WebGLContextUserData : public LayerUserData
    1304             : {
    1305             : public:
    1306           0 :     explicit WebGLContextUserData(HTMLCanvasElement* canvas)
    1307           0 :         : mCanvas(canvas)
    1308           0 :     {}
    1309             : 
    1310             :     /* PreTransactionCallback gets called by the Layers code every time the
    1311             :      * WebGL canvas is going to be composited.
    1312             :      */
    1313           0 :     static void PreTransactionCallback(void* data) {
    1314           0 :         WebGLContextUserData* userdata = static_cast<WebGLContextUserData*>(data);
    1315           0 :         HTMLCanvasElement* canvas = userdata->mCanvas;
    1316           0 :         WebGLContext* webgl = static_cast<WebGLContext*>(canvas->GetContextAtIndex(0));
    1317             : 
    1318             :         // Prepare the context for composition
    1319           0 :         webgl->BeginComposition();
    1320           0 :     }
    1321             : 
    1322             :     /** DidTransactionCallback gets called by the Layers code everytime the WebGL canvas gets composite,
    1323             :       * so it really is the right place to put actions that have to be performed upon compositing
    1324             :       */
    1325           0 :     static void DidTransactionCallback(void* data) {
    1326           0 :         WebGLContextUserData* userdata = static_cast<WebGLContextUserData*>(data);
    1327           0 :         HTMLCanvasElement* canvas = userdata->mCanvas;
    1328           0 :         WebGLContext* webgl = static_cast<WebGLContext*>(canvas->GetContextAtIndex(0));
    1329             : 
    1330             :         // Clean up the context after composition
    1331           0 :         webgl->EndComposition();
    1332           0 :     }
    1333             : 
    1334             : private:
    1335             :     RefPtr<HTMLCanvasElement> mCanvas;
    1336             : };
    1337             : 
    1338             : already_AddRefed<layers::Layer>
    1339           0 : WebGLContext::GetCanvasLayer(nsDisplayListBuilder* builder,
    1340             :                              Layer* oldLayer,
    1341             :                              LayerManager* manager,
    1342             :                              bool aMirror /*= false*/)
    1343             : {
    1344           0 :     if (IsContextLost())
    1345           0 :         return nullptr;
    1346             : 
    1347           0 :     if (!mResetLayer && oldLayer &&
    1348           0 :         oldLayer->HasUserData(aMirror ? &gWebGLMirrorLayerUserData : &gWebGLLayerUserData)) {
    1349           0 :         RefPtr<layers::Layer> ret = oldLayer;
    1350           0 :         return ret.forget();
    1351             :     }
    1352             : 
    1353           0 :     RefPtr<CanvasLayer> canvasLayer = manager->CreateCanvasLayer();
    1354           0 :     if (!canvasLayer) {
    1355           0 :         NS_WARNING("CreateCanvasLayer returned null!");
    1356           0 :         return nullptr;
    1357             :     }
    1358             : 
    1359           0 :     WebGLContextUserData* userData = nullptr;
    1360           0 :     if (builder->IsPaintingToWindow() && mCanvasElement && !aMirror) {
    1361             :         // Make the layer tell us whenever a transaction finishes (including
    1362             :         // the current transaction), so we can clear our invalidation state and
    1363             :         // start invalidating again. We need to do this for the layer that is
    1364             :         // being painted to a window (there shouldn't be more than one at a time,
    1365             :         // and if there is, flushing the invalidation state more often than
    1366             :         // necessary is harmless).
    1367             : 
    1368             :         // The layer will be destroyed when we tear down the presentation
    1369             :         // (at the latest), at which time this userData will be destroyed,
    1370             :         // releasing the reference to the element.
    1371             :         // The userData will receive DidTransactionCallbacks, which flush the
    1372             :         // the invalidation state to indicate that the canvas is up to date.
    1373           0 :         userData = new WebGLContextUserData(mCanvasElement);
    1374           0 :         canvasLayer->SetDidTransactionCallback(
    1375           0 :             WebGLContextUserData::DidTransactionCallback, userData);
    1376           0 :         canvasLayer->SetPreTransactionCallback(
    1377           0 :             WebGLContextUserData::PreTransactionCallback, userData);
    1378             :     }
    1379             : 
    1380           0 :     canvasLayer->SetUserData(aMirror ? &gWebGLMirrorLayerUserData : &gWebGLLayerUserData, userData);
    1381             : 
    1382           0 :     CanvasLayer::Data data;
    1383           0 :     data.mGLContext = gl;
    1384           0 :     data.mSize = nsIntSize(mWidth, mHeight);
    1385           0 :     data.mHasAlpha = gl->Caps().alpha;
    1386           0 :     data.mIsGLAlphaPremult = IsPremultAlpha() || !data.mHasAlpha;
    1387           0 :     data.mIsMirror = aMirror;
    1388             : 
    1389           0 :     canvasLayer->Initialize(data);
    1390           0 :     uint32_t flags = gl->Caps().alpha ? 0 : Layer::CONTENT_OPAQUE;
    1391           0 :     canvasLayer->SetContentFlags(flags);
    1392           0 :     canvasLayer->Updated();
    1393             : 
    1394           0 :     mResetLayer = false;
    1395             :     // We only wish to update mLayerIsMirror when a new layer is returned.
    1396             :     // If a cached layer is returned above, aMirror is not changing since
    1397             :     // the last cached layer was created and mLayerIsMirror is still valid.
    1398           0 :     mLayerIsMirror = aMirror;
    1399             : 
    1400           0 :     return canvasLayer.forget();
    1401             : }
    1402             : 
    1403             : layers::LayersBackend
    1404           0 : WebGLContext::GetCompositorBackendType() const
    1405             : {
    1406           0 :     if (mCanvasElement) {
    1407           0 :         return mCanvasElement->GetCompositorBackendType();
    1408           0 :     } else if (mOffscreenCanvas) {
    1409           0 :         return mOffscreenCanvas->GetCompositorBackendType();
    1410             :     }
    1411             : 
    1412           0 :     return LayersBackend::LAYERS_NONE;
    1413             : }
    1414             : 
    1415             : void
    1416           0 : WebGLContext::Commit()
    1417             : {
    1418           0 :     if (mOffscreenCanvas) {
    1419           0 :         mOffscreenCanvas->CommitFrameToCompositor();
    1420             :     }
    1421           0 : }
    1422             : 
    1423             : void
    1424           0 : WebGLContext::GetCanvas(Nullable<dom::OwningHTMLCanvasElementOrOffscreenCanvas>& retval)
    1425             : {
    1426           0 :     if (mCanvasElement) {
    1427           0 :         MOZ_RELEASE_ASSERT(!mOffscreenCanvas, "GFX: Canvas is offscreen.");
    1428             : 
    1429           0 :         if (mCanvasElement->IsInNativeAnonymousSubtree()) {
    1430           0 :           retval.SetNull();
    1431             :         } else {
    1432           0 :           retval.SetValue().SetAsHTMLCanvasElement() = mCanvasElement;
    1433             :         }
    1434           0 :     } else if (mOffscreenCanvas) {
    1435           0 :         retval.SetValue().SetAsOffscreenCanvas() = mOffscreenCanvas;
    1436             :     } else {
    1437           0 :         retval.SetNull();
    1438             :     }
    1439           0 : }
    1440             : 
    1441             : void
    1442           0 : WebGLContext::GetContextAttributes(dom::Nullable<dom::WebGLContextAttributes>& retval)
    1443             : {
    1444           0 :     retval.SetNull();
    1445           0 :     if (IsContextLost())
    1446           0 :         return;
    1447             : 
    1448           0 :     dom::WebGLContextAttributes& result = retval.SetValue();
    1449             : 
    1450           0 :     result.mAlpha.Construct(mOptions.alpha);
    1451           0 :     result.mDepth = mOptions.depth;
    1452           0 :     result.mStencil = mOptions.stencil;
    1453           0 :     result.mAntialias = mOptions.antialias;
    1454           0 :     result.mPremultipliedAlpha = mOptions.premultipliedAlpha;
    1455           0 :     result.mPreserveDrawingBuffer = mOptions.preserveDrawingBuffer;
    1456           0 :     result.mFailIfMajorPerformanceCaveat = mOptions.failIfMajorPerformanceCaveat;
    1457             : }
    1458             : 
    1459             : NS_IMETHODIMP
    1460           0 : WebGLContext::MozGetUnderlyingParamString(uint32_t pname, nsAString& retval)
    1461             : {
    1462           0 :     if (IsContextLost())
    1463           0 :         return NS_OK;
    1464             : 
    1465           0 :     retval.SetIsVoid(true);
    1466             : 
    1467           0 :     MakeContextCurrent();
    1468             : 
    1469           0 :     switch (pname) {
    1470             :     case LOCAL_GL_VENDOR:
    1471             :     case LOCAL_GL_RENDERER:
    1472             :     case LOCAL_GL_VERSION:
    1473             :     case LOCAL_GL_SHADING_LANGUAGE_VERSION:
    1474             :     case LOCAL_GL_EXTENSIONS:
    1475             :         {
    1476           0 :             const char* s = (const char*)gl->fGetString(pname);
    1477           0 :             retval.Assign(NS_ConvertASCIItoUTF16(nsDependentCString(s)));
    1478           0 :             break;
    1479             :         }
    1480             : 
    1481             :     default:
    1482           0 :         return NS_ERROR_INVALID_ARG;
    1483             :     }
    1484             : 
    1485           0 :     return NS_OK;
    1486             : }
    1487             : 
    1488             : void
    1489           0 : WebGLContext::ClearScreen()
    1490             : {
    1491           0 :     MakeContextCurrent();
    1492           0 :     ScopedBindFramebuffer autoFB(gl, 0);
    1493             : 
    1494           0 :     const bool changeDrawBuffers = (mDefaultFB_DrawBuffer0 != LOCAL_GL_BACK);
    1495           0 :     if (changeDrawBuffers) {
    1496           0 :         gl->Screen()->SetDrawBuffer(LOCAL_GL_BACK);
    1497             :     }
    1498             : 
    1499           0 :     GLbitfield bufferBits = LOCAL_GL_COLOR_BUFFER_BIT;
    1500           0 :     if (mOptions.depth)
    1501           0 :         bufferBits |= LOCAL_GL_DEPTH_BUFFER_BIT;
    1502           0 :     if (mOptions.stencil)
    1503           0 :         bufferBits |= LOCAL_GL_STENCIL_BUFFER_BIT;
    1504             : 
    1505           0 :     ForceClearFramebufferWithDefaultValues(bufferBits, mNeedsFakeNoAlpha);
    1506             : 
    1507           0 :     if (changeDrawBuffers) {
    1508           0 :         gl->Screen()->SetDrawBuffer(mDefaultFB_DrawBuffer0);
    1509             :     }
    1510           0 : }
    1511             : 
    1512             : void
    1513           0 : WebGLContext::ForceClearFramebufferWithDefaultValues(GLbitfield clearBits,
    1514             :                                                      bool fakeNoAlpha)
    1515             : {
    1516           0 :     MakeContextCurrent();
    1517             : 
    1518           0 :     const bool initializeColorBuffer = bool(clearBits & LOCAL_GL_COLOR_BUFFER_BIT);
    1519           0 :     const bool initializeDepthBuffer = bool(clearBits & LOCAL_GL_DEPTH_BUFFER_BIT);
    1520           0 :     const bool initializeStencilBuffer = bool(clearBits & LOCAL_GL_STENCIL_BUFFER_BIT);
    1521             : 
    1522             :     // Fun GL fact: No need to worry about the viewport here, glViewport is just
    1523             :     // setting up a coordinates transformation, it doesn't affect glClear at all.
    1524           0 :     AssertCachedGlobalState();
    1525             : 
    1526             :     // Prepare GL state for clearing.
    1527           0 :     gl->fDisable(LOCAL_GL_SCISSOR_TEST);
    1528             : 
    1529           0 :     if (initializeColorBuffer) {
    1530           0 :         gl->fColorMask(1, 1, 1, 1);
    1531             : 
    1532           0 :         if (fakeNoAlpha) {
    1533           0 :             gl->fClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    1534             :         } else {
    1535           0 :             gl->fClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    1536             :         }
    1537             :     }
    1538             : 
    1539           0 :     if (initializeDepthBuffer) {
    1540           0 :         gl->fDepthMask(1);
    1541           0 :         gl->fClearDepth(1.0f);
    1542             :     }
    1543             : 
    1544           0 :     if (initializeStencilBuffer) {
    1545             :         // "The clear operation always uses the front stencil write mask
    1546             :         //  when clearing the stencil buffer."
    1547           0 :         gl->fStencilMaskSeparate(LOCAL_GL_FRONT, 0xffffffff);
    1548           0 :         gl->fStencilMaskSeparate(LOCAL_GL_BACK,  0xffffffff);
    1549           0 :         gl->fClearStencil(0);
    1550             :     }
    1551             : 
    1552           0 :     if (mRasterizerDiscardEnabled) {
    1553           0 :         gl->fDisable(LOCAL_GL_RASTERIZER_DISCARD);
    1554             :     }
    1555             : 
    1556             :     // Do the clear!
    1557           0 :     gl->fClear(clearBits);
    1558             : 
    1559             :     // And reset!
    1560           0 :     if (mScissorTestEnabled)
    1561           0 :         gl->fEnable(LOCAL_GL_SCISSOR_TEST);
    1562             : 
    1563           0 :     if (mRasterizerDiscardEnabled) {
    1564           0 :         gl->fEnable(LOCAL_GL_RASTERIZER_DISCARD);
    1565             :     }
    1566             : 
    1567             :     // Restore GL state after clearing.
    1568           0 :     if (initializeColorBuffer) {
    1569           0 :         gl->fColorMask(mColorWriteMask[0],
    1570           0 :                        mColorWriteMask[1],
    1571           0 :                        mColorWriteMask[2],
    1572           0 :                        mColorWriteMask[3]);
    1573           0 :         gl->fClearColor(mColorClearValue[0],
    1574             :                         mColorClearValue[1],
    1575             :                         mColorClearValue[2],
    1576           0 :                         mColorClearValue[3]);
    1577             :     }
    1578             : 
    1579           0 :     if (initializeDepthBuffer) {
    1580           0 :         gl->fDepthMask(mDepthWriteMask);
    1581           0 :         gl->fClearDepth(mDepthClearValue);
    1582             :     }
    1583             : 
    1584           0 :     if (initializeStencilBuffer) {
    1585           0 :         gl->fStencilMaskSeparate(LOCAL_GL_FRONT, mStencilWriteMaskFront);
    1586           0 :         gl->fStencilMaskSeparate(LOCAL_GL_BACK,  mStencilWriteMaskBack);
    1587           0 :         gl->fClearStencil(mStencilClearValue);
    1588             :     }
    1589           0 : }
    1590             : 
    1591             : // For an overview of how WebGL compositing works, see:
    1592             : // https://wiki.mozilla.org/Platform/GFX/WebGL/Compositing
    1593             : bool
    1594           0 : WebGLContext::PresentScreenBuffer()
    1595             : {
    1596           0 :     if (IsContextLost()) {
    1597           0 :         return false;
    1598             :     }
    1599             : 
    1600           0 :     if (!mShouldPresent) {
    1601           0 :         return false;
    1602             :     }
    1603           0 :     MOZ_ASSERT(!mBackbufferNeedsClear);
    1604             : 
    1605           0 :     gl->MakeCurrent();
    1606             : 
    1607           0 :     GLScreenBuffer* screen = gl->Screen();
    1608           0 :     MOZ_ASSERT(screen);
    1609             : 
    1610           0 :     if (!screen->PublishFrame(screen->Size())) {
    1611           0 :         ForceLoseContext();
    1612           0 :         return false;
    1613             :     }
    1614             : 
    1615           0 :     if (!mOptions.preserveDrawingBuffer) {
    1616           0 :         mBackbufferNeedsClear = true;
    1617             :     }
    1618             : 
    1619           0 :     mShouldPresent = false;
    1620             : 
    1621           0 :     return true;
    1622             : }
    1623             : 
    1624             : // Prepare the context for capture before compositing
    1625             : void
    1626           0 : WebGLContext::BeginComposition()
    1627             : {
    1628             :     // Present our screenbuffer, if needed.
    1629           0 :     PresentScreenBuffer();
    1630           0 :     mDrawCallsSinceLastFlush = 0;
    1631           0 : }
    1632             : 
    1633             : // Clean up the context after captured for compositing
    1634             : void
    1635           0 : WebGLContext::EndComposition()
    1636             : {
    1637             :     // Mark ourselves as no longer invalidated.
    1638           0 :     MarkContextClean();
    1639           0 :     UpdateLastUseIndex();
    1640           0 : }
    1641             : 
    1642             : void
    1643           0 : WebGLContext::DummyReadFramebufferOperation(const char* funcName)
    1644             : {
    1645           0 :     if (!mBoundReadFramebuffer)
    1646           0 :         return; // Infallible.
    1647             : 
    1648           0 :     const auto status = mBoundReadFramebuffer->CheckFramebufferStatus(funcName);
    1649             : 
    1650           0 :     if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) {
    1651             :         ErrorInvalidFramebufferOperation("%s: Framebuffer must be complete.",
    1652           0 :                                          funcName);
    1653             :     }
    1654             : }
    1655             : 
    1656             : bool
    1657           0 : WebGLContext::Has64BitTimestamps() const
    1658             : {
    1659             :     // 'sync' provides glGetInteger64v either by supporting ARB_sync, GL3+, or GLES3+.
    1660           0 :     return gl->IsSupported(GLFeature::sync);
    1661             : }
    1662             : 
    1663             : static bool
    1664           0 : CheckContextLost(GLContext* gl, bool* const out_isGuilty)
    1665             : {
    1666           0 :     MOZ_ASSERT(gl);
    1667           0 :     MOZ_ASSERT(out_isGuilty);
    1668             : 
    1669           0 :     bool isEGL = gl->GetContextType() == gl::GLContextType::EGL;
    1670             : 
    1671           0 :     GLenum resetStatus = LOCAL_GL_NO_ERROR;
    1672           0 :     if (gl->IsSupported(GLFeature::robustness)) {
    1673           0 :         gl->MakeCurrent();
    1674           0 :         resetStatus = gl->fGetGraphicsResetStatus();
    1675           0 :     } else if (isEGL) {
    1676             :         // Simulate a ARB_robustness guilty context loss for when we
    1677             :         // get an EGL_CONTEXT_LOST error. It may not actually be guilty,
    1678             :         // but we can't make any distinction.
    1679           0 :         if (!gl->MakeCurrent(true) && gl->IsContextLost()) {
    1680           0 :             resetStatus = LOCAL_GL_UNKNOWN_CONTEXT_RESET_ARB;
    1681             :         }
    1682             :     }
    1683             : 
    1684           0 :     if (resetStatus == LOCAL_GL_NO_ERROR) {
    1685           0 :         *out_isGuilty = false;
    1686           0 :         return false;
    1687             :     }
    1688             : 
    1689             :     // Assume guilty unless we find otherwise!
    1690           0 :     bool isGuilty = true;
    1691           0 :     switch (resetStatus) {
    1692             :     case LOCAL_GL_INNOCENT_CONTEXT_RESET_ARB:
    1693             :         // Either nothing wrong, or not our fault.
    1694           0 :         isGuilty = false;
    1695           0 :         break;
    1696             :     case LOCAL_GL_GUILTY_CONTEXT_RESET_ARB:
    1697             :         NS_WARNING("WebGL content on the page definitely caused the graphics"
    1698           0 :                    " card to reset.");
    1699           0 :         break;
    1700             :     case LOCAL_GL_UNKNOWN_CONTEXT_RESET_ARB:
    1701             :         NS_WARNING("WebGL content on the page might have caused the graphics"
    1702           0 :                    " card to reset");
    1703             :         // If we can't tell, assume guilty.
    1704           0 :         break;
    1705             :     default:
    1706           0 :         MOZ_ASSERT(false, "Unreachable.");
    1707             :         // If we do get here, let's pretend to be guilty as an escape plan.
    1708             :         break;
    1709             :     }
    1710             : 
    1711           0 :     if (isGuilty) {
    1712             :         NS_WARNING("WebGL context on this page is considered guilty, and will"
    1713           0 :                    " not be restored.");
    1714             :     }
    1715             : 
    1716           0 :     *out_isGuilty = isGuilty;
    1717           0 :     return true;
    1718             : }
    1719             : 
    1720             : bool
    1721           0 : WebGLContext::TryToRestoreContext()
    1722             : {
    1723           0 :     if (NS_FAILED(SetDimensions(mWidth, mHeight)))
    1724           0 :         return false;
    1725             : 
    1726           0 :     return true;
    1727             : }
    1728             : 
    1729             : void
    1730           0 : WebGLContext::RunContextLossTimer()
    1731             : {
    1732           0 :     mContextLossHandler.RunTimer();
    1733           0 : }
    1734             : 
    1735           0 : class UpdateContextLossStatusTask : public CancelableRunnable
    1736             : {
    1737             :     RefPtr<WebGLContext> mWebGL;
    1738             : 
    1739             : public:
    1740           0 :   explicit UpdateContextLossStatusTask(WebGLContext* webgl)
    1741           0 :     : CancelableRunnable("UpdateContextLossStatusTask")
    1742           0 :     , mWebGL(webgl)
    1743             :   {
    1744           0 :     }
    1745             : 
    1746           0 :     NS_IMETHOD Run() override {
    1747           0 :         if (mWebGL)
    1748           0 :             mWebGL->UpdateContextLossStatus();
    1749             : 
    1750           0 :         return NS_OK;
    1751             :     }
    1752             : 
    1753           0 :     nsresult Cancel() override {
    1754           0 :         mWebGL = nullptr;
    1755           0 :         return NS_OK;
    1756             :     }
    1757             : };
    1758             : 
    1759             : void
    1760           0 : WebGLContext::EnqueueUpdateContextLossStatus()
    1761             : {
    1762           0 :     nsCOMPtr<nsIRunnable> task = new UpdateContextLossStatusTask(this);
    1763           0 :     NS_DispatchToCurrentThread(task);
    1764           0 : }
    1765             : 
    1766             : // We use this timer for many things. Here are the things that it is activated for:
    1767             : // 1) If a script is using the MOZ_WEBGL_lose_context extension.
    1768             : // 2) If we are using EGL and _NOT ANGLE_, we query periodically to see if the
    1769             : //    CONTEXT_LOST_WEBGL error has been triggered.
    1770             : // 3) If we are using ANGLE, or anything that supports ARB_robustness, query the
    1771             : //    GPU periodically to see if the reset status bit has been set.
    1772             : // In all of these situations, we use this timer to send the script context lost
    1773             : // and restored events asynchronously. For example, if it triggers a context loss,
    1774             : // the webglcontextlost event will be sent to it the next time the robustness timer
    1775             : // fires.
    1776             : // Note that this timer mechanism is not used unless one of these 3 criteria
    1777             : // are met.
    1778             : // At a bare minimum, from context lost to context restores, it would take 3
    1779             : // full timer iterations: detection, webglcontextlost, webglcontextrestored.
    1780             : void
    1781           0 : WebGLContext::UpdateContextLossStatus()
    1782             : {
    1783           0 :     if (!mCanvasElement && !mOffscreenCanvas) {
    1784             :         // the canvas is gone. That happens when the page was closed before we got
    1785             :         // this timer event. In this case, there's nothing to do here, just don't crash.
    1786           0 :         return;
    1787             :     }
    1788           0 :     if (mContextStatus == ContextNotLost) {
    1789             :         // We don't know that we're lost, but we might be, so we need to
    1790             :         // check. If we're guilty, don't allow restores, though.
    1791             : 
    1792           0 :         bool isGuilty = true;
    1793           0 :         MOZ_ASSERT(gl); // Shouldn't be missing gl if we're NotLost.
    1794           0 :         bool isContextLost = CheckContextLost(gl, &isGuilty);
    1795             : 
    1796           0 :         if (isContextLost) {
    1797           0 :             if (isGuilty)
    1798           0 :                 mAllowContextRestore = false;
    1799             : 
    1800           0 :             ForceLoseContext();
    1801             :         }
    1802             : 
    1803             :         // Fall through.
    1804             :     }
    1805             : 
    1806           0 :     if (mContextStatus == ContextLostAwaitingEvent) {
    1807             :         // The context has been lost and we haven't yet triggered the
    1808             :         // callback, so do that now.
    1809           0 :         const auto kEventName = NS_LITERAL_STRING("webglcontextlost");
    1810           0 :         const bool kCanBubble = true;
    1811           0 :         const bool kIsCancelable = true;
    1812             :         bool useDefaultHandler;
    1813             : 
    1814           0 :         if (mCanvasElement) {
    1815           0 :             nsContentUtils::DispatchTrustedEvent(
    1816           0 :                 mCanvasElement->OwnerDoc(),
    1817           0 :                 static_cast<nsIDOMHTMLCanvasElement*>(mCanvasElement),
    1818             :                 kEventName,
    1819             :                 kCanBubble,
    1820             :                 kIsCancelable,
    1821           0 :                 &useDefaultHandler);
    1822             :         } else {
    1823             :             // OffscreenCanvas case
    1824           0 :             RefPtr<Event> event = new Event(mOffscreenCanvas, nullptr, nullptr);
    1825           0 :             event->InitEvent(kEventName, kCanBubble, kIsCancelable);
    1826           0 :             event->SetTrusted(true);
    1827           0 :             mOffscreenCanvas->DispatchEvent(event, &useDefaultHandler);
    1828             :         }
    1829             : 
    1830             :         // We sent the callback, so we're just 'regular lost' now.
    1831           0 :         mContextStatus = ContextLost;
    1832             :         // If we're told to use the default handler, it means the script
    1833             :         // didn't bother to handle the event. In this case, we shouldn't
    1834             :         // auto-restore the context.
    1835           0 :         if (useDefaultHandler)
    1836           0 :             mAllowContextRestore = false;
    1837             : 
    1838             :         // Fall through.
    1839             :     }
    1840             : 
    1841           0 :     if (mContextStatus == ContextLost) {
    1842             :         // Context is lost, and we've already sent the callback. We
    1843             :         // should try to restore the context if we're both allowed to,
    1844             :         // and supposed to.
    1845             : 
    1846             :         // Are we allowed to restore the context?
    1847           0 :         if (!mAllowContextRestore)
    1848           0 :             return;
    1849             : 
    1850             :         // If we're only simulated-lost, we shouldn't auto-restore, and
    1851             :         // instead we should wait for restoreContext() to be called.
    1852           0 :         if (mLastLossWasSimulated)
    1853           0 :             return;
    1854             : 
    1855             :         // Restore when the app is visible
    1856           0 :         if (mRestoreWhenVisible)
    1857           0 :             return;
    1858             : 
    1859           0 :         ForceRestoreContext();
    1860           0 :         return;
    1861             :     }
    1862             : 
    1863           0 :     if (mContextStatus == ContextLostAwaitingRestore) {
    1864             :         // Context is lost, but we should try to restore it.
    1865             : 
    1866           0 :         if (!mAllowContextRestore) {
    1867             :             // We might decide this after thinking we'd be OK restoring
    1868             :             // the context, so downgrade.
    1869           0 :             mContextStatus = ContextLost;
    1870           0 :             return;
    1871             :         }
    1872             : 
    1873           0 :         if (!TryToRestoreContext()) {
    1874             :             // Failed to restore. Try again later.
    1875           0 :             mContextLossHandler.RunTimer();
    1876           0 :             return;
    1877             :         }
    1878             : 
    1879             :         // Revival!
    1880           0 :         mContextStatus = ContextNotLost;
    1881             : 
    1882           0 :         if (mCanvasElement) {
    1883           0 :             nsContentUtils::DispatchTrustedEvent(
    1884           0 :                 mCanvasElement->OwnerDoc(),
    1885           0 :                 static_cast<nsIDOMHTMLCanvasElement*>(mCanvasElement),
    1886           0 :                 NS_LITERAL_STRING("webglcontextrestored"),
    1887             :                 true,
    1888           0 :                 true);
    1889             :         } else {
    1890           0 :             RefPtr<Event> event = new Event(mOffscreenCanvas, nullptr, nullptr);
    1891           0 :             event->InitEvent(NS_LITERAL_STRING("webglcontextrestored"), true, true);
    1892           0 :             event->SetTrusted(true);
    1893             :             bool unused;
    1894           0 :             mOffscreenCanvas->DispatchEvent(event, &unused);
    1895             :         }
    1896             : 
    1897           0 :         mEmitContextLostErrorOnce = true;
    1898           0 :         return;
    1899             :     }
    1900             : }
    1901             : 
    1902             : void
    1903           0 : WebGLContext::ForceLoseContext(bool simulateLosing)
    1904             : {
    1905           0 :     printf_stderr("WebGL(%p)::ForceLoseContext\n", this);
    1906           0 :     MOZ_ASSERT(!IsContextLost());
    1907           0 :     mContextStatus = ContextLostAwaitingEvent;
    1908           0 :     mContextLostErrorSet = false;
    1909             : 
    1910             :     // Burn it all!
    1911           0 :     DestroyResourcesAndContext();
    1912           0 :     mLastLossWasSimulated = simulateLosing;
    1913             : 
    1914             :     // Queue up a task, since we know the status changed.
    1915           0 :     EnqueueUpdateContextLossStatus();
    1916           0 : }
    1917             : 
    1918             : void
    1919           0 : WebGLContext::ForceRestoreContext()
    1920             : {
    1921           0 :     printf_stderr("WebGL(%p)::ForceRestoreContext\n", this);
    1922           0 :     mContextStatus = ContextLostAwaitingRestore;
    1923           0 :     mAllowContextRestore = true; // Hey, you did say 'force'.
    1924             : 
    1925             :     // Queue up a task, since we know the status changed.
    1926           0 :     EnqueueUpdateContextLossStatus();
    1927           0 : }
    1928             : 
    1929             : void
    1930           0 : WebGLContext::MakeContextCurrent() const
    1931             : {
    1932           0 :     gl->MakeCurrent();
    1933           0 : }
    1934             : 
    1935             : already_AddRefed<mozilla::gfx::SourceSurface>
    1936           0 : WebGLContext::GetSurfaceSnapshot(gfxAlphaType* const out_alphaType)
    1937             : {
    1938           0 :     if (!gl)
    1939           0 :         return nullptr;
    1940             : 
    1941           0 :     const auto surfFormat = mOptions.alpha ? SurfaceFormat::B8G8R8A8
    1942           0 :                                            : SurfaceFormat::B8G8R8X8;
    1943           0 :     RefPtr<DataSourceSurface> surf;
    1944           0 :     surf = Factory::CreateDataSourceSurfaceWithStride(IntSize(mWidth, mHeight),
    1945             :                                                       surfFormat,
    1946           0 :                                                       mWidth * 4);
    1947           0 :     if (NS_WARN_IF(!surf))
    1948           0 :         return nullptr;
    1949             : 
    1950           0 :     gl->MakeCurrent();
    1951             :     {
    1952           0 :         ScopedBindFramebuffer autoFB(gl, 0);
    1953           0 :         ClearBackbufferIfNeeded();
    1954             : 
    1955             :         // Save, override, then restore glReadBuffer.
    1956           0 :         const GLenum readBufferMode = gl->Screen()->GetReadBufferMode();
    1957             : 
    1958           0 :         if (readBufferMode != LOCAL_GL_BACK) {
    1959           0 :             gl->Screen()->SetReadBuffer(LOCAL_GL_BACK);
    1960             :         }
    1961           0 :         ReadPixelsIntoDataSurface(gl, surf);
    1962             : 
    1963           0 :         if (readBufferMode != LOCAL_GL_BACK) {
    1964           0 :             gl->Screen()->SetReadBuffer(readBufferMode);
    1965             :         }
    1966             :     }
    1967             : 
    1968             :     gfxAlphaType alphaType;
    1969           0 :     if (!mOptions.alpha) {
    1970           0 :         alphaType = gfxAlphaType::Opaque;
    1971           0 :     } else if (mOptions.premultipliedAlpha) {
    1972           0 :         alphaType = gfxAlphaType::Premult;
    1973             :     } else {
    1974           0 :         alphaType = gfxAlphaType::NonPremult;
    1975             :     }
    1976             : 
    1977           0 :     if (out_alphaType) {
    1978           0 :         *out_alphaType = alphaType;
    1979             :     } else {
    1980             :         // Expects Opaque or Premult
    1981           0 :         if (alphaType == gfxAlphaType::NonPremult) {
    1982           0 :             gfxUtils::PremultiplyDataSurface(surf, surf);
    1983           0 :             alphaType = gfxAlphaType::Premult;
    1984             :         }
    1985             :     }
    1986             : 
    1987             :     RefPtr<DrawTarget> dt =
    1988           0 :         Factory::CreateDrawTarget(gfxPlatform::GetPlatform()->GetSoftwareBackend(),
    1989           0 :                                   IntSize(mWidth, mHeight),
    1990           0 :                                   SurfaceFormat::B8G8R8A8);
    1991           0 :     if (!dt)
    1992           0 :         return nullptr;
    1993             : 
    1994           0 :     dt->SetTransform(Matrix::Translation(0.0, mHeight).PreScale(1.0, -1.0));
    1995             : 
    1996           0 :     dt->DrawSurface(surf,
    1997           0 :                     Rect(0, 0, mWidth, mHeight),
    1998           0 :                     Rect(0, 0, mWidth, mHeight),
    1999           0 :                     DrawSurfaceOptions(),
    2000           0 :                     DrawOptions(1.0f, CompositionOp::OP_SOURCE));
    2001             : 
    2002           0 :     return dt->Snapshot();
    2003             : }
    2004             : 
    2005             : void
    2006           0 : WebGLContext::DidRefresh()
    2007             : {
    2008           0 :     if (gl) {
    2009           0 :         gl->FlushIfHeavyGLCallsSinceLastFlush();
    2010             :     }
    2011           0 : }
    2012             : 
    2013             : bool
    2014           0 : WebGLContext::ValidateCurFBForRead(const char* funcName,
    2015             :                                    const webgl::FormatUsageInfo** const out_format,
    2016             :                                    uint32_t* const out_width, uint32_t* const out_height)
    2017             : {
    2018           0 :     if (!mBoundReadFramebuffer) {
    2019           0 :         const GLenum readBufferMode = gl->Screen()->GetReadBufferMode();
    2020           0 :         if (readBufferMode == LOCAL_GL_NONE) {
    2021             :             ErrorInvalidOperation("%s: Can't read from backbuffer when readBuffer mode is"
    2022             :                                   " NONE.",
    2023           0 :                                   funcName);
    2024           0 :             return false;
    2025             :         }
    2026             : 
    2027           0 :         ClearBackbufferIfNeeded();
    2028             : 
    2029             :         // FIXME - here we're assuming that the default framebuffer is backed by
    2030             :         // UNSIGNED_BYTE that might not always be true, say if we had a 16bpp default
    2031             :         // framebuffer.
    2032           0 :         auto effFormat = mOptions.alpha ? webgl::EffectiveFormat::RGBA8
    2033           0 :                                         : webgl::EffectiveFormat::RGB8;
    2034             : 
    2035           0 :         *out_format = mFormatUsage->GetUsage(effFormat);
    2036           0 :         MOZ_ASSERT(*out_format);
    2037             : 
    2038           0 :         *out_width = mWidth;
    2039           0 :         *out_height = mHeight;
    2040           0 :         return true;
    2041             :     }
    2042             : 
    2043           0 :     return mBoundReadFramebuffer->ValidateForRead(funcName, out_format, out_width,
    2044           0 :                                                   out_height);
    2045             : }
    2046             : 
    2047             : ////////////////////////////////////////////////////////////////////////////////
    2048             : 
    2049           0 : WebGLContext::ScopedDrawCallWrapper::ScopedDrawCallWrapper(WebGLContext& webgl)
    2050             :     : mWebGL(webgl)
    2051           0 :     , mFakeNoAlpha(ShouldFakeNoAlpha(webgl))
    2052           0 :     , mFakeNoDepth(ShouldFakeNoDepth(webgl))
    2053           0 :     , mFakeNoStencil(ShouldFakeNoStencil(webgl))
    2054             : {
    2055           0 :     if (!mWebGL.mBoundDrawFramebuffer) {
    2056           0 :         mWebGL.ClearBackbufferIfNeeded();
    2057             :     }
    2058             : 
    2059           0 :     if (mFakeNoAlpha) {
    2060           0 :         mWebGL.gl->fColorMask(mWebGL.mColorWriteMask[0],
    2061           0 :                               mWebGL.mColorWriteMask[1],
    2062           0 :                               mWebGL.mColorWriteMask[2],
    2063           0 :                               false);
    2064             :     }
    2065           0 :     if (mFakeNoDepth) {
    2066           0 :         mWebGL.gl->fDisable(LOCAL_GL_DEPTH_TEST);
    2067             :     }
    2068           0 :     if (mFakeNoStencil) {
    2069           0 :         mWebGL.gl->fDisable(LOCAL_GL_STENCIL_TEST);
    2070             :     }
    2071           0 : }
    2072             : 
    2073           0 : WebGLContext::ScopedDrawCallWrapper::~ScopedDrawCallWrapper()
    2074             : {
    2075           0 :     if (mFakeNoAlpha) {
    2076           0 :         mWebGL.gl->fColorMask(mWebGL.mColorWriteMask[0],
    2077           0 :                               mWebGL.mColorWriteMask[1],
    2078           0 :                               mWebGL.mColorWriteMask[2],
    2079           0 :                               mWebGL.mColorWriteMask[3]);
    2080             :     }
    2081           0 :     if (mFakeNoDepth) {
    2082           0 :         mWebGL.gl->fEnable(LOCAL_GL_DEPTH_TEST);
    2083             :     }
    2084           0 :     if (mFakeNoStencil) {
    2085           0 :         MOZ_ASSERT(mWebGL.mStencilTestEnabled);
    2086           0 :         mWebGL.gl->fEnable(LOCAL_GL_STENCIL_TEST);
    2087             :     }
    2088             : 
    2089           0 :     if (!mWebGL.mBoundDrawFramebuffer) {
    2090           0 :         mWebGL.Invalidate();
    2091           0 :         mWebGL.mShouldPresent = true;
    2092             :     }
    2093           0 : }
    2094             : 
    2095             : /*static*/ bool
    2096           0 : WebGLContext::ScopedDrawCallWrapper::HasDepthButNoStencil(const WebGLFramebuffer* fb)
    2097             : {
    2098           0 :     const auto& depth = fb->DepthAttachment();
    2099           0 :     const auto& stencil = fb->StencilAttachment();
    2100           0 :     return depth.IsDefined() && !stencil.IsDefined();
    2101             : }
    2102             : 
    2103             : ////
    2104             : 
    2105             : void
    2106           0 : WebGLContext::OnBeforeReadCall()
    2107             : {
    2108           0 :     if (!mBoundReadFramebuffer) {
    2109           0 :         ClearBackbufferIfNeeded();
    2110             :     }
    2111           0 : }
    2112             : 
    2113             : ////////////////////////////////////////
    2114             : 
    2115           0 : IndexedBufferBinding::IndexedBufferBinding()
    2116             :     : mRangeStart(0)
    2117           0 :     , mRangeSize(0)
    2118           0 : { }
    2119             : 
    2120             : uint64_t
    2121           0 : IndexedBufferBinding::ByteCount() const
    2122             : {
    2123           0 :     if (!mBufferBinding)
    2124           0 :         return 0;
    2125             : 
    2126           0 :     uint64_t bufferSize = mBufferBinding->ByteLength();
    2127           0 :     if (!mRangeSize) // BindBufferBase
    2128           0 :         return bufferSize;
    2129             : 
    2130           0 :     if (mRangeStart >= bufferSize)
    2131           0 :         return 0;
    2132           0 :     bufferSize -= mRangeStart;
    2133             : 
    2134           0 :     return std::min(bufferSize, mRangeSize);
    2135             : }
    2136             : 
    2137             : ////////////////////////////////////////
    2138             : 
    2139           0 : ScopedUnpackReset::ScopedUnpackReset(WebGLContext* webgl)
    2140           0 :     : ScopedGLWrapper<ScopedUnpackReset>(webgl->gl)
    2141           0 :     , mWebGL(webgl)
    2142             : {
    2143           0 :     if (mWebGL->mPixelStore_UnpackAlignment != 4) mGL->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4);
    2144             : 
    2145           0 :     if (mWebGL->IsWebGL2()) {
    2146           0 :         if (mWebGL->mPixelStore_UnpackRowLength   != 0) mGL->fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH  , 0);
    2147           0 :         if (mWebGL->mPixelStore_UnpackImageHeight != 0) mGL->fPixelStorei(LOCAL_GL_UNPACK_IMAGE_HEIGHT, 0);
    2148           0 :         if (mWebGL->mPixelStore_UnpackSkipPixels  != 0) mGL->fPixelStorei(LOCAL_GL_UNPACK_SKIP_PIXELS , 0);
    2149           0 :         if (mWebGL->mPixelStore_UnpackSkipRows    != 0) mGL->fPixelStorei(LOCAL_GL_UNPACK_SKIP_ROWS   , 0);
    2150           0 :         if (mWebGL->mPixelStore_UnpackSkipImages  != 0) mGL->fPixelStorei(LOCAL_GL_UNPACK_SKIP_IMAGES , 0);
    2151             : 
    2152           0 :         if (mWebGL->mBoundPixelUnpackBuffer) mGL->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, 0);
    2153             :     }
    2154           0 : }
    2155             : 
    2156             : void
    2157           0 : ScopedUnpackReset::UnwrapImpl()
    2158             : {
    2159           0 :     mGL->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, mWebGL->mPixelStore_UnpackAlignment);
    2160             : 
    2161           0 :     if (mWebGL->IsWebGL2()) {
    2162           0 :         mGL->fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH  , mWebGL->mPixelStore_UnpackRowLength  );
    2163           0 :         mGL->fPixelStorei(LOCAL_GL_UNPACK_IMAGE_HEIGHT, mWebGL->mPixelStore_UnpackImageHeight);
    2164           0 :         mGL->fPixelStorei(LOCAL_GL_UNPACK_SKIP_PIXELS , mWebGL->mPixelStore_UnpackSkipPixels );
    2165           0 :         mGL->fPixelStorei(LOCAL_GL_UNPACK_SKIP_ROWS   , mWebGL->mPixelStore_UnpackSkipRows   );
    2166           0 :         mGL->fPixelStorei(LOCAL_GL_UNPACK_SKIP_IMAGES , mWebGL->mPixelStore_UnpackSkipImages );
    2167             : 
    2168           0 :         GLuint pbo = 0;
    2169           0 :         if (mWebGL->mBoundPixelUnpackBuffer) {
    2170           0 :             pbo = mWebGL->mBoundPixelUnpackBuffer->mGLName;
    2171             :         }
    2172             : 
    2173           0 :         mGL->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, pbo);
    2174             :     }
    2175           0 : }
    2176             : 
    2177             : ////////////////////
    2178             : 
    2179             : void
    2180           0 : ScopedFBRebinder::UnwrapImpl()
    2181             : {
    2182           0 :     const auto fnName = [&](WebGLFramebuffer* fb) {
    2183           0 :         return fb ? fb->mGLName : 0;
    2184           0 :     };
    2185             : 
    2186           0 :     if (mWebGL->IsWebGL2()) {
    2187           0 :         mGL->fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER, fnName(mWebGL->mBoundDrawFramebuffer));
    2188           0 :         mGL->fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER, fnName(mWebGL->mBoundReadFramebuffer));
    2189             :     } else {
    2190           0 :         MOZ_ASSERT(mWebGL->mBoundDrawFramebuffer == mWebGL->mBoundReadFramebuffer);
    2191           0 :         mGL->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, fnName(mWebGL->mBoundDrawFramebuffer));
    2192             :     }
    2193           0 : }
    2194             : 
    2195             : ////////////////////
    2196             : 
    2197             : static GLenum
    2198           0 : TargetIfLazy(GLenum target)
    2199             : {
    2200           0 :     switch (target) {
    2201             :     case LOCAL_GL_PIXEL_PACK_BUFFER:
    2202             :     case LOCAL_GL_PIXEL_UNPACK_BUFFER:
    2203           0 :         return target;
    2204             : 
    2205             :     default:
    2206           0 :         return 0;
    2207             :     }
    2208             : }
    2209             : 
    2210           0 : ScopedLazyBind::ScopedLazyBind(gl::GLContext* gl, GLenum target, const WebGLBuffer* buf)
    2211             :     : ScopedGLWrapper<ScopedLazyBind>(gl)
    2212           0 :     , mTarget(buf ? TargetIfLazy(target) : 0)
    2213           0 :     , mBuf(buf)
    2214             : {
    2215           0 :     if (mTarget) {
    2216           0 :         mGL->fBindBuffer(mTarget, mBuf->mGLName);
    2217             :     }
    2218           0 : }
    2219             : 
    2220             : void
    2221           0 : ScopedLazyBind::UnwrapImpl()
    2222             : {
    2223           0 :     if (mTarget) {
    2224           0 :         mGL->fBindBuffer(mTarget, 0);
    2225             :     }
    2226           0 : }
    2227             : 
    2228             : ////////////////////////////////////////
    2229             : 
    2230             : bool
    2231           0 : Intersect(const int32_t srcSize, const int32_t read0, const int32_t readSize,
    2232             :           int32_t* const out_intRead0, int32_t* const out_intWrite0,
    2233             :           int32_t* const out_intSize)
    2234             : {
    2235           0 :     MOZ_ASSERT(srcSize >= 0);
    2236           0 :     MOZ_ASSERT(readSize >= 0);
    2237           0 :     const auto read1 = int64_t(read0) + readSize;
    2238             : 
    2239           0 :     int32_t intRead0 = read0; // Clearly doesn't need validation.
    2240           0 :     int64_t intWrite0 = 0;
    2241           0 :     int64_t intSize = readSize;
    2242             : 
    2243           0 :     if (read1 <= 0 || read0 >= srcSize) {
    2244             :         // Disjoint ranges.
    2245           0 :         intSize = 0;
    2246             :     } else {
    2247           0 :         if (read0 < 0) {
    2248           0 :             const auto diff = int64_t(0) - read0;
    2249           0 :             MOZ_ASSERT(diff >= 0);
    2250           0 :             intRead0 = 0;
    2251           0 :             intWrite0 = diff;
    2252           0 :             intSize -= diff;
    2253             :         }
    2254           0 :         if (read1 > srcSize) {
    2255           0 :             const auto diff = int64_t(read1) - srcSize;
    2256           0 :             MOZ_ASSERT(diff >= 0);
    2257           0 :             intSize -= diff;
    2258             :         }
    2259             : 
    2260           0 :         if (!CheckedInt<int32_t>(intWrite0).isValid() ||
    2261           0 :             !CheckedInt<int32_t>(intSize).isValid())
    2262             :         {
    2263           0 :             return false;
    2264             :         }
    2265             :     }
    2266             : 
    2267           0 :     *out_intRead0 = intRead0;
    2268           0 :     *out_intWrite0 = intWrite0;
    2269           0 :     *out_intSize = intSize;
    2270           0 :     return true;
    2271             : }
    2272             : 
    2273             : ////////////////////////////////////////////////////////////////////////////////
    2274             : 
    2275             : CheckedUint32
    2276           0 : WebGLContext::GetUnpackSize(bool isFunc3D, uint32_t width, uint32_t height,
    2277             :                             uint32_t depth, uint8_t bytesPerPixel)
    2278             : {
    2279           0 :     if (!width || !height || !depth)
    2280           0 :         return 0;
    2281             : 
    2282             :     ////////////////
    2283             : 
    2284           0 :     const auto& maybeRowLength = mPixelStore_UnpackRowLength;
    2285           0 :     const auto& maybeImageHeight = mPixelStore_UnpackImageHeight;
    2286             : 
    2287           0 :     const auto usedPixelsPerRow = CheckedUint32(mPixelStore_UnpackSkipPixels) + width;
    2288           0 :     const auto stridePixelsPerRow = (maybeRowLength ? CheckedUint32(maybeRowLength)
    2289           0 :                                                     : usedPixelsPerRow);
    2290             : 
    2291           0 :     const auto usedRowsPerImage = CheckedUint32(mPixelStore_UnpackSkipRows) + height;
    2292           0 :     const auto strideRowsPerImage = (maybeImageHeight ? CheckedUint32(maybeImageHeight)
    2293           0 :                                                       : usedRowsPerImage);
    2294             : 
    2295           0 :     const uint32_t skipImages = (isFunc3D ? mPixelStore_UnpackSkipImages
    2296           0 :                                           : 0);
    2297           0 :     const CheckedUint32 usedImages = CheckedUint32(skipImages) + depth;
    2298             : 
    2299             :     ////////////////
    2300             : 
    2301           0 :     CheckedUint32 strideBytesPerRow = bytesPerPixel * stridePixelsPerRow;
    2302           0 :     strideBytesPerRow = RoundUpToMultipleOf(strideBytesPerRow,
    2303           0 :                                             mPixelStore_UnpackAlignment);
    2304             : 
    2305           0 :     const CheckedUint32 strideBytesPerImage = strideBytesPerRow * strideRowsPerImage;
    2306             : 
    2307             :     ////////////////
    2308             : 
    2309           0 :     CheckedUint32 usedBytesPerRow = bytesPerPixel * usedPixelsPerRow;
    2310             :     // Don't round this to the alignment, since alignment here is really just used for
    2311             :     // establishing stride, particularly in WebGL 1, where you can't set ROW_LENGTH.
    2312             : 
    2313           0 :     CheckedUint32 totalBytes = strideBytesPerImage * (usedImages - 1);
    2314           0 :     totalBytes += strideBytesPerRow * (usedRowsPerImage - 1);
    2315           0 :     totalBytes += usedBytesPerRow;
    2316             : 
    2317           0 :     return totalBytes;
    2318             : }
    2319             : 
    2320             : already_AddRefed<layers::SharedSurfaceTextureClient>
    2321           0 : WebGLContext::GetVRFrame()
    2322             : {
    2323           0 :     if (!mLayerIsMirror) {
    2324             :         /**
    2325             :          * Do not allow VR frame submission until a mirroring canvas layer has
    2326             :          * been returned by GetCanvasLayer
    2327             :          */
    2328           0 :         return nullptr;
    2329             :     }
    2330             : 
    2331           0 :     VRManagerChild* vrmc = VRManagerChild::Get();
    2332           0 :     if (!vrmc) {
    2333           0 :         return nullptr;
    2334             :     }
    2335             : 
    2336             :     /**
    2337             :      * Swap buffers as though composition has occurred.
    2338             :      * We will then share the resulting front buffer to be submitted to the VR
    2339             :      * compositor.
    2340             :      */
    2341           0 :     BeginComposition();
    2342           0 :     EndComposition();
    2343             : 
    2344           0 :     gl::GLScreenBuffer* screen = gl->Screen();
    2345           0 :     if (!screen) {
    2346           0 :         return nullptr;
    2347             :     }
    2348             : 
    2349           0 :     RefPtr<SharedSurfaceTextureClient> sharedSurface = screen->Front();
    2350           0 :     if (!sharedSurface) {
    2351           0 :         return nullptr;
    2352             :     }
    2353             : 
    2354           0 :     if (sharedSurface && sharedSurface->GetAllocator() != vrmc) {
    2355             :         RefPtr<SharedSurfaceTextureClient> dest =
    2356           0 :         screen->Factory()->NewTexClient(sharedSurface->GetSize(), vrmc);
    2357           0 :         if (!dest) {
    2358           0 :             return nullptr;
    2359             :         }
    2360           0 :         gl::SharedSurface* destSurf = dest->Surf();
    2361           0 :         destSurf->ProducerAcquire();
    2362           0 :         SharedSurface::ProdCopy(sharedSurface->Surf(), dest->Surf(),
    2363           0 :                                 screen->Factory());
    2364           0 :         destSurf->ProducerRelease();
    2365             : 
    2366           0 :         return dest.forget();
    2367             :     }
    2368             : 
    2369           0 :   return sharedSurface.forget();
    2370             : }
    2371             : 
    2372             : bool
    2373           0 : WebGLContext::StartVRPresentation()
    2374             : {
    2375           0 :     VRManagerChild* vrmc = VRManagerChild::Get();
    2376           0 :     if (!vrmc) {
    2377           0 :         return false;
    2378             :     }
    2379           0 :     gl::GLScreenBuffer* screen = gl->Screen();
    2380           0 :     if (!screen) {
    2381           0 :         return false;
    2382             :     }
    2383           0 :     gl::SurfaceCaps caps = screen->mCaps;
    2384             : 
    2385             :     UniquePtr<gl::SurfaceFactory> factory =
    2386           0 :         gl::GLScreenBuffer::CreateFactory(gl,
    2387             :             caps,
    2388             :             vrmc,
    2389             :             vrmc->GetBackendType(),
    2390           0 :             TextureFlags::ORIGIN_BOTTOM_LEFT);
    2391             : 
    2392           0 :     if (factory) {
    2393           0 :         screen->Morph(Move(factory));
    2394             :     }
    2395           0 :     return true;
    2396             : }
    2397             : 
    2398             : ////////////////////////////////////////////////////////////////////////////////
    2399             : 
    2400             : static inline size_t
    2401           0 : SizeOfViewElem(const dom::ArrayBufferView& view)
    2402             : {
    2403           0 :     const auto& elemType = view.Type();
    2404           0 :     if (elemType == js::Scalar::MaxTypedArrayViewType) // DataViews.
    2405           0 :         return 1;
    2406             : 
    2407           0 :     return js::Scalar::byteSize(elemType);
    2408             : }
    2409             : 
    2410             : bool
    2411           0 : WebGLContext::ValidateArrayBufferView(const char* funcName,
    2412             :                                       const dom::ArrayBufferView& view, GLuint elemOffset,
    2413             :                                       GLuint elemCountOverride, uint8_t** const out_bytes,
    2414             :                                       size_t* const out_byteLen)
    2415             : {
    2416           0 :     view.ComputeLengthAndData();
    2417           0 :     uint8_t* const bytes = view.DataAllowShared();
    2418           0 :     const size_t byteLen = view.LengthAllowShared();
    2419             : 
    2420           0 :     const auto& elemSize = SizeOfViewElem(view);
    2421             : 
    2422           0 :     size_t elemCount = byteLen / elemSize;
    2423           0 :     if (elemOffset > elemCount) {
    2424           0 :         ErrorInvalidValue("%s: Invalid offset into ArrayBufferView.", funcName);
    2425           0 :         return false;
    2426             :     }
    2427           0 :     elemCount -= elemOffset;
    2428             : 
    2429           0 :     if (elemCountOverride) {
    2430           0 :         if (elemCountOverride > elemCount) {
    2431           0 :             ErrorInvalidValue("%s: Invalid sub-length for ArrayBufferView.", funcName);
    2432           0 :             return false;
    2433             :         }
    2434           0 :         elemCount = elemCountOverride;
    2435             :     }
    2436             : 
    2437           0 :     *out_bytes = bytes + (elemOffset * elemSize);
    2438           0 :     *out_byteLen = elemCount * elemSize;
    2439           0 :     return true;
    2440             : }
    2441             : 
    2442             : ////////////////////////////////////////////////////////////////////////////////
    2443             : // XPCOM goop
    2444             : 
    2445             : void
    2446           0 : ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& callback,
    2447             :                             const std::vector<IndexedBufferBinding>& field,
    2448             :                             const char* name, uint32_t flags)
    2449             : {
    2450           0 :     for (const auto& cur : field) {
    2451           0 :         ImplCycleCollectionTraverse(callback, cur.mBufferBinding, name, flags);
    2452             :     }
    2453           0 : }
    2454             : 
    2455             : void
    2456           0 : ImplCycleCollectionUnlink(std::vector<IndexedBufferBinding>& field)
    2457             : {
    2458           0 :     field.clear();
    2459           0 : }
    2460             : 
    2461             : ////
    2462             : 
    2463           0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(WebGLContext)
    2464           0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(WebGLContext)
    2465             : 
    2466           0 : NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebGLContext,
    2467             :   mCanvasElement,
    2468             :   mOffscreenCanvas,
    2469             :   mExtensions,
    2470             :   mBound2DTextures,
    2471             :   mBoundCubeMapTextures,
    2472             :   mBound3DTextures,
    2473             :   mBound2DArrayTextures,
    2474             :   mBoundSamplers,
    2475             :   mBoundArrayBuffer,
    2476             :   mBoundCopyReadBuffer,
    2477             :   mBoundCopyWriteBuffer,
    2478             :   mBoundPixelPackBuffer,
    2479             :   mBoundPixelUnpackBuffer,
    2480             :   mBoundTransformFeedback,
    2481             :   mBoundUniformBuffer,
    2482             :   mCurrentProgram,
    2483             :   mBoundDrawFramebuffer,
    2484             :   mBoundReadFramebuffer,
    2485             :   mBoundRenderbuffer,
    2486             :   mBoundVertexArray,
    2487             :   mDefaultVertexArray,
    2488             :   mQuerySlot_SamplesPassed,
    2489             :   mQuerySlot_TFPrimsWritten,
    2490             :   mQuerySlot_TimeElapsed)
    2491             : 
    2492           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WebGLContext)
    2493           0 :     NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
    2494           0 :     NS_INTERFACE_MAP_ENTRY(nsIDOMWebGLRenderingContext)
    2495           0 :     NS_INTERFACE_MAP_ENTRY(nsICanvasRenderingContextInternal)
    2496           0 :     NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
    2497             :     // If the exact way we cast to nsISupports here ever changes, fix our
    2498             :     // ToSupports() method.
    2499           0 :     NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMWebGLRenderingContext)
    2500           0 : NS_INTERFACE_MAP_END
    2501             : 
    2502             : } // namespace mozilla

Generated by: LCOV version 1.13