| author | Jeff Gilbert <jgilbert@mozilla.com> |
| Thu, 24 Sep 2015 12:21:05 -0700 | |
| changeset 264310 | 0cecdec0f6e144c874e203744dc84c213ec057a5 |
| parent 264309 | b0d7f0fd067c181f0d7e51e59c9caadfa8664513 |
| child 264311 | b9b74d5bd4230bab9f761a32711ae28555645e28 |
| push id | 29436 |
| push user | cbook@mozilla.com |
| push date | Fri, 25 Sep 2015 12:39:56 +0000 |
| treeherder | mozilla-central@543e1b3a2588 [default view] [failures only] |
| perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
| reviewers | jrmuizel |
| bugs | 1191042 |
| milestone | 44.0a1 |
| first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
| last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/dom/canvas/WebGLContext.cpp +++ b/dom/canvas/WebGLContext.cpp @@ -212,16 +212,17 @@ WebGLContextOptions::WebGLContextOptions alpha = false; } WebGLContext::WebGLContext() : WebGLContextUnchecked(nullptr) , mBypassShaderValidation(false) , mGLMaxSamples(1) , mNeedsFakeNoAlpha(false) + , mNeedsFakeNoDepth(false) , mNeedsFakeNoStencil(false) { mGeneration = 0; mInvalidated = false; mCapturedFrameInvalidated = false; mShouldPresent = true; mResetLayer = true; mOptionsFrozen = false; @@ -248,16 +249,17 @@ WebGLContext::WebGLContext() mViewportX = 0; mViewportY = 0; mViewportWidth = 0; mViewportHeight = 0; mDitherEnabled = 1; mRasterizerDiscardEnabled = 0; // OpenGL ES 3.0 spec p244 mScissorTestEnabled = 0; + mDepthTestEnabled = 0; mStencilTestEnabled = 0; // initialize some GL values: we're going to get them from the GL and use them as the sizes of arrays, // so in case glGetIntegerv leaves them uninitialized because of a GL bug, we would have very weird crashes. mGLMaxVertexAttribs = 0; mGLMaxTextureUnits = 0; mGLMaxTextureSize = 0; mGLMaxTextureSizeLog2 = 0; @@ -538,251 +540,244 @@ HasAcceleratedLayers(const nsCOMPtr<nsIG return true; gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_OPENGL_LAYERS, &status); if (status) return true; return false; } -static already_AddRefed<GLContext> -CreateHeadlessNativeGL(CreateContextFlags flags, const nsCOMPtr<nsIGfxInfo>& gfxInfo, - WebGLContext* webgl) -{ - if (!(flags & CreateContextFlags::FORCE_ENABLE_HARDWARE) && - IsFeatureInBlacklist(gfxInfo, nsIGfxInfo::FEATURE_WEBGL_OPENGL)) - { - webgl->GenerateWarning("Refused to create native OpenGL context" - " because of blacklisting."); - return nullptr; - } - - nsRefPtr<GLContext> gl = gl::GLContextProvider::CreateHeadless(flags); - if (!gl) { - webgl->GenerateWarning("Error during native OpenGL init."); - return nullptr; - } - MOZ_ASSERT(!gl->IsANGLE()); - - return gl.forget(); -} - -// Note that we have a separate call for ANGLE and EGL, even though -// right now, we get ANGLE implicitly by using EGL on Windows. -// Eventually, we want to be able to pick ANGLE-EGL or native EGL. -static already_AddRefed<GLContext> -CreateHeadlessANGLE(CreateContextFlags flags, const nsCOMPtr<nsIGfxInfo>& gfxInfo, - WebGLContext* webgl) -{ - nsRefPtr<GLContext> gl; - -#ifdef XP_WIN - gl = gl::GLContextProviderEGL::CreateHeadless(flags); - if (!gl) { - webgl->GenerateWarning("Error during ANGLE OpenGL init."); - return nullptr; - } - MOZ_ASSERT(gl->IsANGLE()); -#endif - - return gl.forget(); -} - -static already_AddRefed<GLContext> -CreateHeadlessEGL(CreateContextFlags flags, WebGLContext* webgl) -{ - nsRefPtr<GLContext> gl; - -#ifdef ANDROID - gl = gl::GLContextProviderEGL::CreateHeadless(flags); - if (!gl) { - webgl->GenerateWarning("Error during EGL OpenGL init."); - return nullptr; - } - MOZ_ASSERT(!gl->IsANGLE()); -#endif - - return gl.forget(); -} - -static already_AddRefed<GLContext> -CreateHeadlessGL(CreateContextFlags flags, const nsCOMPtr<nsIGfxInfo>& gfxInfo, - WebGLContext* webgl) -{ - bool preferEGL = PR_GetEnv("MOZ_WEBGL_PREFER_EGL"); - bool disableANGLE = Preferences::GetBool("webgl.disable-angle", false); - - if (PR_GetEnv("MOZ_WEBGL_FORCE_OPENGL")) - disableANGLE = true; - - if (!webgl->IsWebGL2()) { - flags |= CreateContextFlags::REQUIRE_COMPAT_PROFILE; - } - - nsRefPtr<GLContext> gl; - - if (preferEGL) - gl = CreateHeadlessEGL(flags, webgl); - - if (!gl && !disableANGLE) { - gl = CreateHeadlessANGLE(flags, gfxInfo, webgl); - } - - if (!gl) { - gl = CreateHeadlessNativeGL(flags, gfxInfo, webgl); - } - - return gl.forget(); -} - -// Try to create a dummy offscreen with the given caps. -static bool -CreateOffscreenWithCaps(GLContext* gl, const SurfaceCaps& caps) -{ - gfx::IntSize dummySize(16, 16); - return gl->InitOffscreen(dummySize, caps); -} - static void -PopulateCapFallbackQueue(const SurfaceCaps& baseCaps, - std::queue<SurfaceCaps>* out_fallbackCaps) +PopulateCapFallbackQueue(const gl::SurfaceCaps& baseCaps, + std::queue<gl::SurfaceCaps>* out_fallbackCaps) { out_fallbackCaps->push(baseCaps); // Dropping antialias drops our quality, but not our correctness. // The user basically doesn't have to handle if this fails, they // just get reduced quality. if (baseCaps.antialias) { - SurfaceCaps nextCaps(baseCaps); + gl::SurfaceCaps nextCaps(baseCaps); nextCaps.antialias = false; PopulateCapFallbackQueue(nextCaps, out_fallbackCaps); } // If we have to drop one of depth or stencil, we'd prefer to keep // depth. However, the client app will need to handle if this // doesn't work. if (baseCaps.stencil) { - SurfaceCaps nextCaps(baseCaps); + gl::SurfaceCaps nextCaps(baseCaps); nextCaps.stencil = false; PopulateCapFallbackQueue(nextCaps, out_fallbackCaps); } if (baseCaps.depth) { - SurfaceCaps nextCaps(baseCaps); + gl::SurfaceCaps nextCaps(baseCaps); nextCaps.depth = false; PopulateCapFallbackQueue(nextCaps, out_fallbackCaps); } } -static bool -CreateOffscreen(GLContext* gl, const WebGLContextOptions& options, - const nsCOMPtr<nsIGfxInfo>& gfxInfo, WebGLContext* webgl, - layers::LayersBackend layersBackend, - layers::ISurfaceAllocator* surfAllocator) +static gl::SurfaceCaps +BaseCaps(const WebGLContextOptions& options, WebGLContext* webgl) { - SurfaceCaps baseCaps; + gl::SurfaceCaps baseCaps; baseCaps.color = true; baseCaps.alpha = options.alpha; baseCaps.antialias = options.antialias; baseCaps.depth = options.depth; baseCaps.premultAlpha = options.premultipliedAlpha; baseCaps.preserve = options.preserveDrawingBuffer; baseCaps.stencil = options.stencil; if (!baseCaps.alpha) baseCaps.premultAlpha = true; - if (gl->IsANGLE() || - (gl->GetContextType() == GLContextType::GLX && - layersBackend == LayersBackend::LAYERS_OPENGL)) - { - // We can't use no-alpha formats on ANGLE yet because of: - // https://code.google.com/p/angleproject/issues/detail?id=764 - // GLX only supports GL_RGBA pixmaps as well. Since we can't blit from - // an RGB FB to GLX's RGBA FB, force RGBA when surface sharing. - baseCaps.alpha = true; - } - // we should really have this behind a // |gfxPlatform::GetPlatform()->GetScreenDepth() == 16| check, but // for now it's just behind a pref for testing/evaluation. baseCaps.bpp16 = Preferences::GetBool("webgl.prefer-16bpp", false); #ifdef MOZ_WIDGET_GONK - baseCaps.surfaceAllocator = surfAllocator; + do { + auto canvasElement = webgl->GetCanvas(); + auto ownerDoc = canvasElement->OwnerDoc(); + nsIWidget* docWidget = nsContentUtils::WidgetForDocument(ownerDoc); + if (!docWidget) + break; + + layers::LayerManager* layerManager = docWidget->GetLayerManager(); + if (!layerManager) + break; + + // XXX we really want "AsSurfaceAllocator" here for generality + layers::ShadowLayerForwarder* forwarder = layerManager->AsShadowForwarder(); + if (!forwarder) + break; + + baseCaps.surfaceAllocator = static_cast<layers::ISurfaceAllocator*>(forwarder); + } while (false); #endif // Done with baseCaps construction. bool forceAllowAA = Preferences::GetBool("webgl.msaa-force", false); + nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo(); if (!forceAllowAA && IsFeatureInBlacklist(gfxInfo, nsIGfxInfo::FEATURE_WEBGL_MSAA)) { webgl->GenerateWarning("Disallowing antialiased backbuffers due" " to blacklisting."); baseCaps.antialias = false; } - std::queue<SurfaceCaps> fallbackCaps; + return baseCaps; +} + +//////////////////////////////////////// + +static already_AddRefed<gl::GLContext> +CreateGLWithEGL(const gl::SurfaceCaps& caps, gl::CreateContextFlags flags, + WebGLContext* webgl) +{ + RefPtr<GLContext> gl; +#ifndef XP_MACOSX // Mac doesn't have GLContextProviderEGL. + gfx::IntSize dummySize(16, 16); + gl = gl::GLContextProviderEGL::CreateOffscreen(dummySize, caps, + flags); + if (!gl) { + webgl->GenerateWarning("Error during EGL OpenGL init."); + return nullptr; + } + + if (gl->IsANGLE()) + return nullptr; +#endif // XP_MACOSX + return gl.forget(); +} + +static already_AddRefed<GLContext> +CreateGLWithANGLE(const gl::SurfaceCaps& caps, gl::CreateContextFlags flags, + WebGLContext* webgl) +{ + RefPtr<GLContext> gl; + +#ifdef XP_WIN + gfx::IntSize dummySize(16, 16); + gl = gl::GLContextProviderEGL::CreateOffscreen(dummySize, caps, flags); + if (!gl) { + webgl->GenerateWarning("Error during ANGLE OpenGL init."); + return nullptr; + } + + if (!gl->IsANGLE()) + return nullptr; +#endif + + return gl.forget(); +} + +static already_AddRefed<gl::GLContext> +CreateGLWithDefault(const gl::SurfaceCaps& caps, gl::CreateContextFlags flags, + WebGLContext* webgl) +{ + nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo(); + + if (!(flags & CreateContextFlags::FORCE_ENABLE_HARDWARE) && + IsFeatureInBlacklist(gfxInfo, nsIGfxInfo::FEATURE_WEBGL_OPENGL)) + { + webgl->GenerateWarning("Refused to create native OpenGL context because of" + " blacklisting."); + return nullptr; + } + + gfx::IntSize dummySize(16, 16); + RefPtr<GLContext> gl = gl::GLContextProvider::CreateOffscreen(dummySize, caps, flags); + if (!gl) { + webgl->GenerateWarning("Error during native OpenGL init."); + return nullptr; + } + + if (gl->IsANGLE()) + return nullptr; + + return gl.forget(); +} + +//////////////////////////////////////// + +bool +WebGLContext::CreateAndInitGLWith(FnCreateGL_T fnCreateGL, + const gl::SurfaceCaps& baseCaps, + gl::CreateContextFlags flags) +{ + MOZ_ASSERT(!gl); + + std::queue<gl::SurfaceCaps> fallbackCaps; PopulateCapFallbackQueue(baseCaps, &fallbackCaps); - bool created = false; + gl = nullptr; while (!fallbackCaps.empty()) { - SurfaceCaps& caps = fallbackCaps.front(); + gl::SurfaceCaps& caps = fallbackCaps.front(); - created = CreateOffscreenWithCaps(gl, caps); - if (created) + gl = fnCreateGL(caps, flags, this); + if (gl) break; fallbackCaps.pop(); } + if (!gl) + return false; - return created; + if (!InitAndValidateGL()) { + gl = nullptr; + return false; + } + + return true; } bool -WebGLContext::CreateOffscreenGL(bool forceEnabled) +WebGLContext::CreateAndInitGL(bool forceEnabled) { - nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo(); + bool preferEGL = PR_GetEnv("MOZ_WEBGL_PREFER_EGL"); + bool disableANGLE = Preferences::GetBool("webgl.disable-angle", false); + + if (PR_GetEnv("MOZ_WEBGL_FORCE_OPENGL")) + disableANGLE = true; - layers::ISurfaceAllocator* surfAllocator = nullptr; -#ifdef MOZ_WIDGET_GONK - nsIWidget* docWidget = nsContentUtils::WidgetForDocument(mCanvasElement->OwnerDoc()); - if (docWidget) { - layers::LayerManager* layerManager = docWidget->GetLayerManager(); - if (layerManager) { - // XXX we really want "AsSurfaceAllocator" here for generality - layers::ShadowLayerForwarder* forwarder = layerManager->AsShadowForwarder(); - if (forwarder) - surfAllocator = static_cast<layers::ISurfaceAllocator*>(forwarder); - } - } -#endif + gl::CreateContextFlags flags = gl::CreateContextFlags::NONE; + if (forceEnabled) flags |= gl::CreateContextFlags::FORCE_ENABLE_HARDWARE; + if (!IsWebGL2()) flags |= gl::CreateContextFlags::REQUIRE_COMPAT_PROFILE; + + const gl::SurfaceCaps baseCaps = BaseCaps(mOptions, this); + + MOZ_ASSERT(!gl); - CreateContextFlags flags = forceEnabled ? CreateContextFlags::FORCE_ENABLE_HARDWARE : - CreateContextFlags::NONE; + if (preferEGL) { + if (CreateAndInitGLWith(CreateGLWithEGL, baseCaps, flags)) + return true; + } - gl = CreateHeadlessGL(flags, gfxInfo, this); - - do { - if (!gl) - break; + MOZ_ASSERT(!gl); - if (!CreateOffscreen(gl, mOptions, gfxInfo, this, - GetCompositorBackendType(), surfAllocator)) - break; + if (!disableANGLE) { + if (CreateAndInitGLWith(CreateGLWithANGLE, baseCaps, flags)) + return true; + } + + MOZ_ASSERT(!gl); - if (!InitAndValidateGL()) - break; - + if (CreateAndInitGLWith(CreateGLWithDefault, baseCaps, flags)) return true; - } while (false); + MOZ_ASSERT(!gl); gl = nullptr; + return false; } // Fallback for resizes: bool WebGLContext::ResizeBackbuffer(uint32_t requestedWidth, uint32_t requestedHeight) { @@ -936,22 +931,25 @@ WebGLContext::SetDimensions(int32_t sign return NS_ERROR_FAILURE; } } // Alright, now let's start trying. bool forceEnabled = Preferences::GetBool("webgl.force-enabled", false); ScopedGfxFeatureReporter reporter("WebGL", forceEnabled); - if (!CreateOffscreenGL(forceEnabled)) { + MOZ_ASSERT(!gl); + if (!CreateAndInitGL(forceEnabled)) { GenerateWarning("WebGL creation failed."); return NS_ERROR_FAILURE; } MOZ_ASSERT(gl); + MOZ_ASSERT_IF(mOptions.alpha, gl->Caps().alpha); + if (!ResizeBackbuffer(width, height)) { GenerateWarning("Initializing WebGL backbuffer failed."); return NS_ERROR_FAILURE; } #ifdef DEBUG if (gl->DebugMode()) printf_stderr("--- WebGL context created: %p\n", gl.get()); @@ -960,24 +958,30 @@ WebGLContext::SetDimensions(int32_t sign mResetLayer = true; mOptionsFrozen = true; // Update our internal stuff: if (gl->WorkAroundDriverBugs()) { if (!mOptions.alpha && gl->Caps().alpha) mNeedsFakeNoAlpha = true; - // ANGLE doesn't quite handle this properly. - if (gl->Caps().depth && !gl->Caps().stencil && gl->IsANGLE()) + if (!mOptions.depth && gl->Caps().depth) + mNeedsFakeNoDepth = true; + + if (!mOptions.stencil && gl->Caps().stencil) mNeedsFakeNoStencil = true; } // Update mOptions. - mOptions.depth = gl->Caps().depth; - mOptions.stencil = gl->Caps().stencil; + if (!gl->Caps().depth) + mOptions.depth = false; + + if (!gl->Caps().stencil) + mOptions.stencil = false; + mOptions.antialias = gl->Caps().antialias; MakeContextCurrent(); gl->fViewport(0, 0, mWidth, mHeight); mViewportWidth = mWidth; mViewportHeight = mHeight; @@ -993,20 +997,26 @@ WebGLContext::SetDimensions(int32_t sign // Clear immediately, because we need to present the cleared initial // buffer. mBackbufferNeedsClear = true; ClearBackbufferIfNeeded(); mShouldPresent = true; MOZ_ASSERT(gl->Caps().color); + MOZ_ASSERT_IF(!mNeedsFakeNoAlpha, gl->Caps().alpha == mOptions.alpha); MOZ_ASSERT_IF(mNeedsFakeNoAlpha, !mOptions.alpha && gl->Caps().alpha); - MOZ_ASSERT(gl->Caps().depth == mOptions.depth); - MOZ_ASSERT(gl->Caps().stencil == mOptions.stencil); + + MOZ_ASSERT_IF(!mNeedsFakeNoDepth, gl->Caps().depth == mOptions.depth); + MOZ_ASSERT_IF(mNeedsFakeNoDepth, !mOptions.depth && gl->Caps().depth); + + MOZ_ASSERT_IF(!mNeedsFakeNoStencil, gl->Caps().stencil == mOptions.stencil); + MOZ_ASSERT_IF(mNeedsFakeNoStencil, !mOptions.stencil && gl->Caps().stencil); + MOZ_ASSERT(gl->Caps().antialias == mOptions.antialias); MOZ_ASSERT(gl->Caps().preserve == mOptions.preserveDrawingBuffer); AssertCachedBindings(); AssertCachedState(); reporter.SetSuccessful(); return NS_OK; @@ -1871,37 +1881,44 @@ RoundedToNextMultipleOf(CheckedUint32 x, return ((x + y - 1) / y) * y; } //////////////////////////////////////////////////////////////////////////////// WebGLContext::ScopedMaskWorkaround::ScopedMaskWorkaround(WebGLContext& webgl) : mWebGL(webgl) , mFakeNoAlpha(ShouldFakeNoAlpha(webgl)) + , mFakeNoDepth(ShouldFakeNoDepth(webgl)) , mFakeNoStencil(ShouldFakeNoStencil(webgl)) { if (mFakeNoAlpha) { mWebGL.gl->fColorMask(mWebGL.mColorWriteMask[0], mWebGL.mColorWriteMask[1], mWebGL.mColorWriteMask[2], false); } + if (mFakeNoDepth) { + mWebGL.gl->fDisable(LOCAL_GL_DEPTH_TEST); + } if (mFakeNoStencil) { mWebGL.gl->fDisable(LOCAL_GL_STENCIL_TEST); } } WebGLContext::ScopedMaskWorkaround::~ScopedMaskWorkaround() { if (mFakeNoAlpha) { mWebGL.gl->fColorMask(mWebGL.mColorWriteMask[0], mWebGL.mColorWriteMask[1], mWebGL.mColorWriteMask[2], mWebGL.mColorWriteMask[3]); } + if (mFakeNoDepth) { + mWebGL.gl->fEnable(LOCAL_GL_DEPTH_TEST); + } if (mFakeNoStencil) { mWebGL.gl->fEnable(LOCAL_GL_STENCIL_TEST); } } //////////////////////////////////////////////////////////////////////////////// // XPCOM goop
--- a/dom/canvas/WebGLContext.h +++ b/dom/canvas/WebGLContext.h @@ -3,32 +3,34 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef WEBGLCONTEXT_H_ #define WEBGLCONTEXT_H_ #include <stdarg.h> +#include "GLContextTypes.h" #include "GLDefs.h" #include "mozilla/Attributes.h" #include "mozilla/CheckedInt.h" #include "mozilla/dom/HTMLCanvasElement.h" #include "mozilla/dom/TypedArray.h" #include "mozilla/EnumeratedArray.h" #include "mozilla/ErrorResult.h" #include "mozilla/gfx/2D.h" #include "mozilla/LinkedList.h" #include "mozilla/UniquePtr.h" #include "mozilla/WeakPtr.h" #include "nsCycleCollectionNoteChild.h" #include "nsICanvasRenderingContextInternal.h" #include "nsLayoutUtils.h" #include "nsTArray.h" #include "nsWrapperCache.h" +#include "SurfaceTypes.h" #ifdef XP_MACOSX #include "ForceDiscreteGPUHelperCGL.h" #endif // Local #include "WebGLContextUnchecked.h" #include "WebGLFormats.h" @@ -807,16 +809,17 @@ public: JS::MutableHandle<JS::Value> retval); bool IsEnabled(GLenum cap); private: // State tracking slots realGLboolean mDitherEnabled; realGLboolean mRasterizerDiscardEnabled; realGLboolean mScissorTestEnabled; + realGLboolean mDepthTestEnabled; realGLboolean mStencilTestEnabled; bool ValidateCapabilityEnum(GLenum cap, const char* info); realGLboolean* GetStateTrackingSlot(GLenum cap); // ----------------------------------------------------------------------------- // Texture funcions (WebGLContextTextures.cpp) public: @@ -1148,21 +1151,29 @@ protected: // ------------------------------------------------------------------------- // WebGL 2 specifics (implemented in WebGL2Context.cpp) public: virtual bool IsWebGL2() const = 0; protected: bool InitWebGL2(); + bool CreateAndInitGL(bool forceEnabled); + bool ResizeBackbuffer(uint32_t width, uint32_t height); + + typedef already_AddRefed<gl::GLContext> FnCreateGL_T(const gl::SurfaceCaps& caps, + gl::CreateContextFlags flags, + WebGLContext* webgl); + + bool CreateAndInitGLWith(FnCreateGL_T fnCreateGL, const gl::SurfaceCaps& baseCaps, + gl::CreateContextFlags flags); + // ------------------------------------------------------------------------- // Validation functions (implemented in WebGLContextValidate.cpp) - bool CreateOffscreenGL(bool forceEnabled); bool InitAndValidateGL(); - bool ResizeBackbuffer(uint32_t width, uint32_t height); bool ValidateBlendEquationEnum(GLenum cap, const char* info); bool ValidateBlendFuncDstEnum(GLenum mode, const char* info); bool ValidateBlendFuncSrcEnum(GLenum mode, const char* info); bool ValidateBlendFuncEnumsCompatibility(GLenum sfactor, GLenum dfactor, const char* info); bool ValidateDataOffsetSize(WebGLintptr offset, WebGLsizeiptr size, WebGLsizeiptr bufferSize, const char* info); bool ValidateDataRanges(WebGLintptr readOffset, WebGLintptr writeOffset, WebGLsizeiptr size, const char* info); bool ValidateTextureTargetEnum(GLenum target, const char* info); @@ -1438,31 +1449,40 @@ protected: int mMaxWarnings; bool mAlreadyWarnedAboutFakeVertexAttrib0; bool ShouldGenerateWarnings() const; uint64_t mLastUseIndex; bool mNeedsFakeNoAlpha; + bool mNeedsFakeNoDepth; bool mNeedsFakeNoStencil; struct ScopedMaskWorkaround { WebGLContext& mWebGL; const bool mFakeNoAlpha; + const bool mFakeNoDepth; const bool mFakeNoStencil; static bool ShouldFakeNoAlpha(WebGLContext& webgl) { // We should only be doing this if we're about to draw to the backbuffer, but // the backbuffer needs to have this fake-no-alpha workaround. return !webgl.mBoundDrawFramebuffer && webgl.mNeedsFakeNoAlpha && webgl.mColorWriteMask[3] != false; } + static bool ShouldFakeNoDepth(WebGLContext& webgl) { + // We should only be doing this if we're about to draw to the backbuffer. + return !webgl.mBoundDrawFramebuffer && + webgl.mNeedsFakeNoDepth && + webgl.mDepthTestEnabled; + } + static bool ShouldFakeNoStencil(WebGLContext& webgl) { // We should only be doing this if we're about to draw to the backbuffer. return !webgl.mBoundDrawFramebuffer && webgl.mNeedsFakeNoStencil && webgl.mStencilTestEnabled; } explicit ScopedMaskWorkaround(WebGLContext& webgl);
--- a/dom/canvas/WebGLContextState.cpp +++ b/dom/canvas/WebGLContextState.cpp @@ -355,20 +355,26 @@ WebGLContext::GetParameter(JSContext* cx case LOCAL_GL_SAMPLE_BUFFERS: case LOCAL_GL_SAMPLES: case LOCAL_GL_MAX_VERTEX_ATTRIBS: case LOCAL_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: case LOCAL_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS: case LOCAL_GL_MAX_TEXTURE_IMAGE_UNITS: case LOCAL_GL_RED_BITS: case LOCAL_GL_GREEN_BITS: - case LOCAL_GL_BLUE_BITS: + case LOCAL_GL_BLUE_BITS: { + GLint i = 0; + gl->fGetIntegerv(pname, &i); + return JS::Int32Value(i); + } case LOCAL_GL_DEPTH_BITS: { GLint i = 0; - gl->fGetIntegerv(pname, &i); + if (!mNeedsFakeNoDepth) { + gl->fGetIntegerv(pname, &i); + } return JS::Int32Value(i); } case LOCAL_GL_ALPHA_BITS: { GLint i = 0; if (!mNeedsFakeNoAlpha) { gl->fGetIntegerv(pname, &i); } return JS::Int32Value(i); @@ -617,16 +623,18 @@ WebGLContext::ValidateCapabilityEnum(GLe return false; } } realGLboolean* WebGLContext::GetStateTrackingSlot(GLenum cap) { switch (cap) { + case LOCAL_GL_DEPTH_TEST: + return &mDepthTestEnabled; case LOCAL_GL_DITHER: return &mDitherEnabled; case LOCAL_GL_RASTERIZER_DISCARD: return &mRasterizerDiscardEnabled; case LOCAL_GL_SCISSOR_TEST: return &mScissorTestEnabled; case LOCAL_GL_STENCIL_TEST: return &mStencilTestEnabled;
--- a/dom/canvas/WebGLContextUtils.cpp +++ b/dom/canvas/WebGLContextUtils.cpp @@ -1170,16 +1170,17 @@ WebGLContext::AssertCachedState() // extensions if (IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers)) { AssertUintParamCorrect(gl, LOCAL_GL_MAX_COLOR_ATTACHMENTS, mGLMaxColorAttachments); AssertUintParamCorrect(gl, LOCAL_GL_MAX_DRAW_BUFFERS, mGLMaxDrawBuffers); } // Draw state + MOZ_ASSERT(gl->fIsEnabled(LOCAL_GL_DEPTH_TEST) == mDepthTestEnabled); MOZ_ASSERT(gl->fIsEnabled(LOCAL_GL_DITHER) == mDitherEnabled); MOZ_ASSERT_IF(IsWebGL2(), gl->fIsEnabled(LOCAL_GL_RASTERIZER_DISCARD) == mRasterizerDiscardEnabled); MOZ_ASSERT(gl->fIsEnabled(LOCAL_GL_SCISSOR_TEST) == mScissorTestEnabled); MOZ_ASSERT(gl->fIsEnabled(LOCAL_GL_STENCIL_TEST) == mStencilTestEnabled); realGLboolean colorWriteMask[4] = {0, 0, 0, 0}; gl->fGetBooleanv(LOCAL_GL_COLOR_WRITEMASK, colorWriteMask);
--- a/dom/media/platforms/android/AndroidDecoderModule.cpp +++ b/dom/media/platforms/android/AndroidDecoderModule.cpp @@ -95,17 +95,17 @@ public: return nullptr; } EGLint attribs[] = { LOCAL_EGL_IMAGE_PRESERVED_KHR, LOCAL_EGL_TRUE, LOCAL_EGL_NONE, LOCAL_EGL_NONE }; - EGLContext eglContext = static_cast<GLContextEGL*>(mGLContext.get())->GetEGLContext(); + EGLContext eglContext = static_cast<GLContextEGL*>(mGLContext.get())->mContext; EGLImage eglImage = sEGLLibrary.fCreateImage(EGL_DISPLAY(), eglContext, LOCAL_EGL_GL_TEXTURE_2D_KHR, (EGLClientBuffer)tex, attribs); mGLContext->fDeleteTextures(1, &tex); return eglImage; }
--- a/dom/plugins/base/android/ANPOpenGL.cpp +++ b/dom/plugins/base/android/ANPOpenGL.cpp @@ -23,17 +23,17 @@ typedef nsNPAPIPluginInstance::TextureIn static ANPEGLContext anp_opengl_acquireContext(NPP instance) { nsNPAPIPluginInstance* pinst = static_cast<nsNPAPIPluginInstance*>(instance->ndata); GLContext* context = pinst->GLContext(); if (!context) return nullptr; context->MakeCurrent(); - return GLContextEGL::Cast(context)->GetEGLContext(); + return GLContextEGL::Cast(context)->mContext; } static ANPTextureInfo anp_opengl_lockTexture(NPP instance) { nsNPAPIPluginInstance* pinst = static_cast<nsNPAPIPluginInstance*>(instance->ndata); TextureInfo pluginInfo = pinst->LockContentTexture(); ANPTextureInfo info;
--- a/gfx/gl/EGLUtils.cpp +++ b/gfx/gl/EGLUtils.cpp @@ -18,17 +18,17 @@ DoesEGLContextSupportSharingWithEGLImage } EGLImage CreateEGLImage(GLContext* gl, GLuint tex) { MOZ_ASSERT(DoesEGLContextSupportSharingWithEGLImage(gl)); EGLClientBuffer clientBuffer = (EGLClientBuffer)((uint64_t)tex); - EGLContext eglContext = GLContextEGL::Cast(gl)->GetEGLContext(); + EGLContext eglContext = GLContextEGL::Cast(gl)->mContext; EGLImage image = sEGLLibrary.fCreateImage(EGL_DISPLAY(), eglContext, LOCAL_EGL_GL_TEXTURE_2D, clientBuffer, nullptr); return image; } @@ -37,17 +37,17 @@ CreateEGLImage(GLContext* gl, GLuint tex /*static*/ EGLImageWrapper* EGLImageWrapper::Create(GLContext* gl, GLuint tex) { MOZ_ASSERT(DoesEGLContextSupportSharingWithEGLImage(gl)); GLLibraryEGL& library = sEGLLibrary; EGLDisplay display = EGL_DISPLAY(); - EGLContext eglContext = GLContextEGL::Cast(gl)->GetEGLContext(); + EGLContext eglContext = GLContextEGL::Cast(gl)->mContext; EGLClientBuffer clientBuffer = (EGLClientBuffer)((uint64_t)tex); EGLImage image = library.fCreateImage(display, eglContext, LOCAL_EGL_GL_TEXTURE_2D, clientBuffer, nullptr); if (!image) { #ifdef DEBUG
--- a/gfx/gl/GLContext.cpp +++ b/gfx/gl/GLContext.cpp @@ -301,17 +301,16 @@ GLContext::GLContext(const SurfaceCaps& mIsOffscreen(isOffscreen), mContextLost(false), mVersion(0), mProfile(ContextProfile::Unknown), mVendor(GLVendor::Other), mRenderer(GLRenderer::Other), mHasRobustness(false), mTopError(LOCAL_GL_NO_ERROR), - mLocalErrorScope(nullptr), mSharedContext(sharedContext), mCaps(caps), mScreen(nullptr), mLockedSurface(nullptr), mMaxTextureSize(0), mMaxCubeMapTextureSize(0), mMaxTextureImageSize(0), mMaxRenderbufferSize(0),
--- a/gfx/gl/GLContext.h +++ b/gfx/gl/GLContext.h @@ -2,22 +2,23 @@ /* vim: set ts=8 sts=4 et sw=4 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef GLCONTEXT_H_ #define GLCONTEXT_H_ -#include <stdio.h> -#include <stdint.h> +#include <bitset> #include <ctype.h> +#include <stdint.h> +#include <stdio.h> #include <map> -#include <bitset> #include <queue> +#include <stack> #ifdef DEBUG #include <string.h> #endif #ifdef WIN32 #include <windows.h> #endif @@ -614,31 +615,30 @@ public: return err; } //////////////////////////////////// // Use this safer option. class LocalErrorScope; private: - LocalErrorScope* mLocalErrorScope; + std::stack<const LocalErrorScope*> mLocalErrorScopeStack; public: class LocalErrorScope { GLContext& mGL; GLenum mOldTop; bool mHasBeenChecked; public: explicit LocalErrorScope(GLContext& gl) : mGL(gl) , mHasBeenChecked(false) { - MOZ_ASSERT(!mGL.mLocalErrorScope); - mGL.mLocalErrorScope = this; + mGL.mLocalErrorScopeStack.push(this); mGL.FlushErrors(); mOldTop = mGL.mTopError; mGL.mTopError = LOCAL_GL_NO_ERROR; } GLenum GetError() { @@ -648,20 +648,20 @@ public: return mGL.fGetError(); } ~LocalErrorScope() { MOZ_ASSERT(mHasBeenChecked); MOZ_ASSERT(mGL.fGetError() == LOCAL_GL_NO_ERROR); + MOZ_ASSERT(mGL.mLocalErrorScopeStack.top() == this); + mGL.mLocalErrorScopeStack.pop(); + mGL.mTopError = mOldTop; - - MOZ_ASSERT(mGL.mLocalErrorScope == this); - mGL.mLocalErrorScope = nullptr; } }; bool GetPotentialInteger(GLenum pname, GLint* param) { LocalErrorScope localError(*this); fGetIntegerv(pname, param); @@ -733,17 +733,17 @@ private: GLenum err = FlushErrors(); if (DebugMode() & DebugTrace) { printf_stderr("[gl:%p] < %s [%s (0x%04x)]\n", this, funcName, GLErrorToString(err), err); } if (err != LOCAL_GL_NO_ERROR && - !mLocalErrorScope) + !mLocalErrorScopeStack.size()) { printf_stderr("[gl:%p] %s: Generated unexpected %s error." " (0x%04x)\n", this, funcName, GLErrorToString(err), err); if (DebugMode() & DebugAbortOnError) MOZ_CRASH("MOZ_GL_DEBUG_ABORT_ON_ERROR"); }
--- a/gfx/gl/GLContextEGL.h +++ b/gfx/gl/GLContextEGL.h @@ -87,45 +87,46 @@ public: virtual bool SetupLookupFunction() override; virtual bool SwapBuffers() override; // hold a reference to the given surface // for the lifetime of this context. void HoldSurface(gfxASurface *aSurf); - EGLContext GetEGLContext() { - return mContext; - } - - EGLSurface GetEGLSurface() { + EGLSurface GetEGLSurface() const { return mSurface; } - EGLDisplay GetEGLDisplay() { - return EGL_DISPLAY(); + EGLDisplay GetEGLDisplay() const { + return sEGLLibrary.Display(); } bool BindTex2DOffscreen(GLContext *aOffscreen); void UnbindTex2DOffscreen(GLContext *aOffscreen); void BindOffscreenFramebuffer(); static already_AddRefed<GLContextEGL> CreateEGLPixmapOffscreenContext(const gfx::IntSize& size); static already_AddRefed<GLContextEGL> - CreateEGLPBufferOffscreenContext(const gfx::IntSize& size); + CreateEGLPBufferOffscreenContext(const gfx::IntSize& size, + const SurfaceCaps& minCaps); protected: friend class GLContextProviderEGL; - EGLConfig mConfig; +public: + const EGLConfig mConfig; +protected: EGLSurface mSurface; +public: + const EGLContext mContext; +protected: EGLSurface mSurfaceOverride; - EGLContext mContext; nsRefPtr<gfxASurface> mThebesSurface; bool mBound; bool mIsPBuffer; bool mIsDoubleBuffered; bool mCanBindToTexture; bool mShareWithEGLImage; bool mOwnsContext;
--- a/gfx/gl/GLContextProvider.h +++ b/gfx/gl/GLContextProvider.h @@ -4,84 +4,71 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef GLCONTEXTPROVIDER_H_ #define GLCONTEXTPROVIDER_H_ #include "GLContextTypes.h" #include "nsAutoPtr.h" #include "SurfaceTypes.h" -#include "mozilla/TypedEnumBits.h" #include "nsSize.h" // for gfx::IntSize (needed by GLContextProviderImpl.h below) class nsIWidget; namespace mozilla { namespace gl { -enum class CreateContextFlags : int8_t { - NONE = 0, - REQUIRE_COMPAT_PROFILE = 1 << 0, - // Force the use of hardware backed GL, don't allow software implementations. - FORCE_ENABLE_HARDWARE = 1 << 1, - /* Don't force discrete GPU to be used (if applicable) */ - ALLOW_OFFLINE_RENDERER = 1 << 2, -}; -MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(CreateContextFlags) - #define IN_GL_CONTEXT_PROVIDER_H // Null is always there #define GL_CONTEXT_PROVIDER_NAME GLContextProviderNull #include "GLContextProviderImpl.h" #undef GL_CONTEXT_PROVIDER_NAME #ifdef XP_WIN -#define GL_CONTEXT_PROVIDER_NAME GLContextProviderWGL -#include "GLContextProviderImpl.h" -#undef GL_CONTEXT_PROVIDER_NAME -#define GL_CONTEXT_PROVIDER_DEFAULT GLContextProviderWGL -#define DEFAULT_IMPL WGL + #define GL_CONTEXT_PROVIDER_NAME GLContextProviderWGL + #include "GLContextProviderImpl.h" + #undef GL_CONTEXT_PROVIDER_NAME + #define GL_CONTEXT_PROVIDER_DEFAULT GLContextProviderWGL + #define DEFAULT_IMPL WGL #endif #ifdef XP_MACOSX -#define GL_CONTEXT_PROVIDER_NAME GLContextProviderCGL -#include "GLContextProviderImpl.h" -#undef GL_CONTEXT_PROVIDER_NAME -#define GL_CONTEXT_PROVIDER_DEFAULT GLContextProviderCGL + #define GL_CONTEXT_PROVIDER_NAME GLContextProviderCGL + #include "GLContextProviderImpl.h" + #undef GL_CONTEXT_PROVIDER_NAME + #define GL_CONTEXT_PROVIDER_DEFAULT GLContextProviderCGL #endif -#if defined(ANDROID) || defined(XP_WIN) +#if defined(MOZ_X11) + #define GL_CONTEXT_PROVIDER_NAME GLContextProviderGLX + #include "GLContextProviderImpl.h" + #undef GL_CONTEXT_PROVIDER_NAME + #define GL_CONTEXT_PROVIDER_DEFAULT GLContextProviderGLX +#endif + #define GL_CONTEXT_PROVIDER_NAME GLContextProviderEGL #include "GLContextProviderImpl.h" #undef GL_CONTEXT_PROVIDER_NAME #ifndef GL_CONTEXT_PROVIDER_DEFAULT -#define GL_CONTEXT_PROVIDER_DEFAULT GLContextProviderEGL -#endif + #define GL_CONTEXT_PROVIDER_DEFAULT GLContextProviderEGL #endif #ifdef MOZ_GL_PROVIDER -#define GL_CONTEXT_PROVIDER_NAME MOZ_GL_PROVIDER -#include "GLContextProviderImpl.h" -#undef GL_CONTEXT_PROVIDER_NAME -#define GL_CONTEXT_PROVIDER_DEFAULT MOZ_GL_PROVIDER -#endif - -#if defined(MOZ_X11) && !defined(GL_CONTEXT_PROVIDER_DEFAULT) -#define GL_CONTEXT_PROVIDER_NAME GLContextProviderGLX -#include "GLContextProviderImpl.h" -#undef GL_CONTEXT_PROVIDER_NAME -#define GL_CONTEXT_PROVIDER_DEFAULT GLContextProviderGLX + #define GL_CONTEXT_PROVIDER_NAME MOZ_GL_PROVIDER + #include "GLContextProviderImpl.h" + #undef GL_CONTEXT_PROVIDER_NAME + #define GL_CONTEXT_PROVIDER_DEFAULT MOZ_GL_PROVIDER #endif #ifdef GL_CONTEXT_PROVIDER_DEFAULT -typedef GL_CONTEXT_PROVIDER_DEFAULT GLContextProvider; + typedef GL_CONTEXT_PROVIDER_DEFAULT GLContextProvider; #else -typedef GLContextProviderNull GLContextProvider; + typedef GLContextProviderNull GLContextProvider; #endif #undef IN_GL_CONTEXT_PROVIDER_H } // namespace gl } // namespace mozilla #endif
--- a/gfx/gl/GLContextProviderCGL.mm +++ b/gfx/gl/GLContextProviderCGL.mm @@ -312,26 +312,27 @@ GLContextProviderCGL::CreateHeadless(Cre return nullptr; } return gl.forget(); } already_AddRefed<GLContext> GLContextProviderCGL::CreateOffscreen(const IntSize& size, - const SurfaceCaps& caps, + const SurfaceCaps& minCaps, CreateContextFlags flags) { - nsRefPtr<GLContext> glContext = CreateHeadless(flags); - if (!glContext->InitOffscreen(size, caps)) { - NS_WARNING("Failed during InitOffscreen."); + RefPtr<GLContext> gl = CreateHeadless(flags); + if (!gl) return nullptr; - } - return glContext.forget(); + if (!gl->InitOffscreen(size, minCaps)) + return nullptr; + + return gl.forget(); } static nsRefPtr<GLContext> gGlobalContext; GLContext* GLContextProviderCGL::GetGlobalContext() { if (!sCGLLibrary.EnsureInitialized()) {
--- a/gfx/gl/GLContextProviderEGL.cpp +++ b/gfx/gl/GLContextProviderEGL.cpp @@ -1,123 +1,115 @@ /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include "mozilla/ArrayUtils.h" - -#include "GLContextEGL.h" - -#if defined(XP_UNIX) - -#ifdef MOZ_WIDGET_GTK -#include <gdk/gdkx.h> -// we're using default display for now -#define GET_NATIVE_WINDOW(aWidget) (EGLNativeWindowType)GDK_WINDOW_XID((GdkWindow *) aWidget->GetNativeData(NS_NATIVE_WINDOW)) +#if defined(MOZ_WIDGET_GTK) + #include <gdk/gdkx.h> + // we're using default display for now + #define GET_NATIVE_WINDOW(aWidget) ((EGLNativeWindowType)GDK_WINDOW_XID((GdkWindow*)aWidget->GetNativeData(NS_NATIVE_WINDOW))) #elif defined(MOZ_WIDGET_QT) -#define GET_NATIVE_WINDOW(aWidget) (EGLNativeWindowType)(aWidget->GetNativeData(NS_NATIVE_SHAREABLE_WINDOW)) -#elif defined(MOZ_WIDGET_GONK) -#define GET_NATIVE_WINDOW(aWidget) ((EGLNativeWindowType)aWidget->GetNativeData(NS_NATIVE_WINDOW)) -#include "libdisplay/GonkDisplay.h" -#include "nsWindow.h" -#include "nsScreenManagerGonk.h" -#endif - -#if defined(ANDROID) -/* from widget */ -#if defined(MOZ_WIDGET_ANDROID) -#include "AndroidBridge.h" -#endif - -#include <android/log.h> -#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args) - -# if defined(MOZ_WIDGET_GONK) -# include "cutils/properties.h" -# include <ui/GraphicBuffer.h> - -using namespace android; -# endif - -#endif - -#define GLES2_LIB "libGLESv2.so" -#define GLES2_LIB2 "libGLESv2.so.2" - -#elif defined(XP_WIN) - -#include "nsIFile.h" - -#define GLES2_LIB "libGLESv2.dll" - -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN 1 + #define GET_NATIVE_WINDOW(aWidget) ((EGLNativeWindowType)aWidget->GetNativeData(NS_NATIVE_SHAREABLE_WINDOW)) +#else + #define GET_NATIVE_WINDOW(aWidget) ((EGLNativeWindowType)aWidget->GetNativeData(NS_NATIVE_WINDOW)) #endif -#include <windows.h> +#if defined(XP_UNIX) + #ifdef MOZ_WIDGET_GONK + #include "libdisplay/GonkDisplay.h" + #include "nsWindow.h" + #include "nsScreenManagerGonk.h" + #endif -// a little helper -class AutoDestroyHWND { -public: - AutoDestroyHWND(HWND aWnd = nullptr) - : mWnd(aWnd) - { - } + #ifdef ANDROID + /* from widget */ + #ifdef MOZ_WIDGET_ANDROID + #include "AndroidBridge.h" + #endif + + #include <android/log.h> + #define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args) - ~AutoDestroyHWND() { - if (mWnd) { - ::DestroyWindow(mWnd); - } - } + #ifdef MOZ_WIDGET_GONK + #include "cutils/properties.h" + #include <ui/GraphicBuffer.h> + + using namespace android; + #endif + #endif - operator HWND() { - return mWnd; - } + #define GLES2_LIB "libGLESv2.so" + #define GLES2_LIB2 "libGLESv2.so.2" + +#elif defined(XP_WIN) + #include "nsIFile.h" + + #define GLES2_LIB "libGLESv2.dll" + + #ifndef WIN32_LEAN_AND_MEAN + #define WIN32_LEAN_AND_MEAN 1 + #endif - HWND forget() { - HWND w = mWnd; - mWnd = nullptr; - return w; - } + #include <windows.h> - HWND operator=(HWND aWnd) { - if (mWnd && mWnd != aWnd) { - ::DestroyWindow(mWnd); + // a little helper + class AutoDestroyHWND { + public: + AutoDestroyHWND(HWND aWnd = nullptr) + : mWnd(aWnd) + { + } + + ~AutoDestroyHWND() { + if (mWnd) { + ::DestroyWindow(mWnd); + } + } + + operator HWND() { + return mWnd; } - mWnd = aWnd; - return mWnd; - } + + HWND forget() { + HWND w = mWnd; + mWnd = nullptr; + return w; + } - HWND mWnd; -}; + HWND operator=(HWND aWnd) { + if (mWnd && mWnd != aWnd) { + ::DestroyWindow(mWnd); + } + mWnd = aWnd; + return mWnd; + } + HWND mWnd; + }; #else - -#error "Platform not recognized" - + #error "Platform not recognized" #endif -#include "mozilla/Preferences.h" -#include "gfxUtils.h" +#include "gfxASurface.h" +#include "gfxCrashReporterUtils.h" #include "gfxFailure.h" -#include "gfxASurface.h" #include "gfxPlatform.h" +#include "gfxUtils.h" +#include "GLBlitHelper.h" +#include "GLContextEGL.h" #include "GLContextProvider.h" #include "GLLibraryEGL.h" -#include "TextureImageEGL.h" +#include "mozilla/ArrayUtils.h" +#include "mozilla/Preferences.h" #include "nsDebug.h" -#include "nsThreadUtils.h" - #include "nsIWidget.h" - -#include "gfxCrashReporterUtils.h" - +#include "nsThreadUtils.h" #include "ScopedGLHelpers.h" -#include "GLBlitHelper.h" +#include "TextureImageEGL.h" using namespace mozilla::gfx; namespace mozilla { namespace gl { #define ADD_ATTR_2(_array, _k, _v) do { \ (_array).AppendElement(_k); \ @@ -185,43 +177,41 @@ DestroySurface(EGLSurface oldSurface) { EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); sEGLLibrary.fDestroySurface(EGL_DISPLAY(), oldSurface); } } static EGLSurface CreateSurfaceForWindow(nsIWidget* widget, const EGLConfig& config) { - EGLSurface newSurface = EGL_NO_SURFACE; + EGLSurface newSurface = nullptr; - #ifdef MOZ_WIDGET_ANDROID +#ifdef MOZ_WIDGET_ANDROID mozilla::AndroidBridge::Bridge()->RegisterCompositor(); newSurface = mozilla::AndroidBridge::Bridge()->CreateEGLSurfaceForCompositor(); - if (newSurface == EGL_NO_SURFACE) { - return EGL_NO_SURFACE; - } - #else +#else MOZ_ASSERT(widget != nullptr); - newSurface = sEGLLibrary.fCreateWindowSurface(EGL_DISPLAY(), config, GET_NATIVE_WINDOW(widget), 0); - #endif + newSurface = sEGLLibrary.fCreateWindowSurface(EGL_DISPLAY(), config, + GET_NATIVE_WINDOW(widget), 0); +#endif return newSurface; } GLContextEGL::GLContextEGL( const SurfaceCaps& caps, GLContext* shareContext, bool isOffscreen, EGLConfig config, EGLSurface surface, EGLContext context) : GLContext(caps, shareContext, isOffscreen) , mConfig(config) , mSurface(surface) + , mContext(context) , mSurfaceOverride(EGL_NO_SURFACE) - , mContext(context) , mThebesSurface(nullptr) , mBound(false) , mIsPBuffer(false) , mIsDoubleBuffered(false) , mCanBindToTexture(false) , mShareWithEGLImage(false) , mOwnsContext(true) { @@ -420,17 +410,17 @@ GLContextEGL::RenewSurface() { // pass again to CreateSurfaceForWindow below. // The reason why Android doesn't need this is that it delegates EGLSurface creation to // Java code which is the only thing that knows about our actual widget. #endif // unconditionally release the surface and create a new one. Don't try to optimize this away. // If we get here, then by definition we know that we want to get a new surface. ReleaseSurface(); mSurface = mozilla::gl::CreateSurfaceForWindow(nullptr, mConfig); // the nullptr here is where we assume Android. - if (mSurface == EGL_NO_SURFACE) { + if (!mSurface) { return false; } return MakeCurrent(true); } void GLContextEGL::ReleaseSurface() { if (mOwnsContext) { @@ -485,16 +475,20 @@ GLContextEGL::CreateSurfaceForWindow(nsI EGLConfig config; if (!CreateConfig(&config, aWidget)) { MOZ_CRASH("Failed to create EGLConfig!\n"); return nullptr; } EGLSurface surface = mozilla::gl::CreateSurfaceForWindow(aWidget, config); + if (!surface) { + MOZ_CRASH("Failed to create EGLSurface for window!\n"); + return nullptr; + } return surface; } /* static */ void GLContextEGL::DestroySurface(EGLSurface aSurface) { if (aSurface != EGL_NO_SURFACE) { sEGLLibrary.fDestroySurface(EGL_DISPLAY(), aSurface); @@ -775,18 +769,17 @@ GLContextProviderEGL::CreateForWindow(ns EGLConfig config; if (!CreateConfig(&config, aWidget)) { MOZ_CRASH("Failed to create EGLConfig!\n"); return nullptr; } EGLSurface surface = mozilla::gl::CreateSurfaceForWindow(aWidget, config); - - if (surface == EGL_NO_SURFACE) { + if (!surface) { MOZ_CRASH("Failed to create EGLSurface!\n"); return nullptr; } SurfaceCaps caps = SurfaceCaps::Any(); nsRefPtr<GLContextEGL> glContext = GLContextEGL::CreateGLContext(caps, nullptr, false, @@ -834,70 +827,154 @@ GLContextProviderEGL::DestroyEGLSurface( if (!sEGLLibrary.EnsureInitialized()) { MOZ_CRASH("Failed to load EGL library!\n"); } sEGLLibrary.fDestroySurface(EGL_DISPLAY(), surface); } #endif // defined(ANDROID) -already_AddRefed<GLContextEGL> -GLContextEGL::CreateEGLPBufferOffscreenContext(const mozilla::gfx::IntSize& size) +static void +FillContextAttribs(bool alpha, bool depth, bool stencil, bool bpp16, + nsTArray<EGLint>* out) { - EGLConfig config; - EGLSurface surface; + out->AppendElement(LOCAL_EGL_SURFACE_TYPE); + out->AppendElement(LOCAL_EGL_PBUFFER_BIT); + + out->AppendElement(LOCAL_EGL_RENDERABLE_TYPE); + out->AppendElement(LOCAL_EGL_OPENGL_ES2_BIT); + + out->AppendElement(LOCAL_EGL_RED_SIZE); + if (bpp16) { + out->AppendElement(alpha ? 4 : 5); + } else { + out->AppendElement(8); + } + + out->AppendElement(LOCAL_EGL_GREEN_SIZE); + if (bpp16) { + out->AppendElement(alpha ? 4 : 6); + } else { + out->AppendElement(8); + } + + out->AppendElement(LOCAL_EGL_BLUE_SIZE); + if (bpp16) { + out->AppendElement(alpha ? 4 : 5); + } else { + out->AppendElement(8); + } + + out->AppendElement(LOCAL_EGL_ALPHA_SIZE); + if (alpha) { + out->AppendElement(bpp16 ? 4 : 8); + } else { + out->AppendElement(0); + } - const EGLint numConfigs = 1; // We only need one. - EGLConfig configs[numConfigs]; + out->AppendElement(LOCAL_EGL_DEPTH_SIZE); + out->AppendElement(depth ? 16 : 0); + + out->AppendElement(LOCAL_EGL_STENCIL_SIZE); + out->AppendElement(stencil ? 8 : 0); + + // EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS + out->AppendElement(LOCAL_EGL_NONE); + out->AppendElement(0); + + out->AppendElement(0); + out->AppendElement(0); +} + +static GLint +GetAttrib(GLLibraryEGL* egl, EGLConfig config, EGLint attrib) +{ + EGLint bits = 0; + egl->fGetConfigAttrib(egl->Display(), config, attrib, &bits); + MOZ_ASSERT(egl->fGetError() == LOCAL_EGL_SUCCESS); + + return bits; +} + +static EGLConfig +ChooseConfig(GLLibraryEGL* egl, const SurfaceCaps& minCaps, + SurfaceCaps* const out_configCaps) +{ + nsTArray<EGLint> configAttribList; + FillContextAttribs(minCaps.alpha, minCaps.depth, minCaps.stencil, minCaps.bpp16, + &configAttribList); + + const EGLint* configAttribs = configAttribList.Elements(); + + // We're guaranteed to get at least minCaps, and the sorting dictated by the spec for + // eglChooseConfig reasonably assures that a reasonable 'best' config is on top. + const EGLint kMaxConfigs = 1; + EGLConfig configs[kMaxConfigs]; EGLint foundConfigs = 0; - if (!sEGLLibrary.fChooseConfig(EGL_DISPLAY(), - kEGLConfigAttribsOffscreenPBuffer, - configs, numConfigs, - &foundConfigs) + if (!egl->fChooseConfig(egl->Display(), configAttribs, configs, kMaxConfigs, + &foundConfigs) || foundConfigs == 0) { - NS_WARNING("No EGL Config for minimal PBuffer!"); + return EGL_NO_CONFIG; + } + + EGLConfig config = configs[0]; + + *out_configCaps = minCaps; // Pick up any preserve, etc. + out_configCaps->color = true; + out_configCaps->alpha = bool(GetAttrib(egl, config, LOCAL_EGL_ALPHA_SIZE)); + out_configCaps->depth = bool(GetAttrib(egl, config, LOCAL_EGL_DEPTH_SIZE)); + out_configCaps->stencil = bool(GetAttrib(egl, config, LOCAL_EGL_STENCIL_SIZE)); + out_configCaps->bpp16 = (GetAttrib(egl, config, LOCAL_EGL_RED_SIZE) < 8); + + return config; +} + +/*static*/ already_AddRefed<GLContextEGL> +GLContextEGL::CreateEGLPBufferOffscreenContext(const mozilla::gfx::IntSize& size, + const SurfaceCaps& minCaps) +{ + SurfaceCaps configCaps; + EGLConfig config = ChooseConfig(&sEGLLibrary, minCaps, &configCaps); + if (config == EGL_NO_CONFIG) { + NS_WARNING("Failed to find a compatible config."); return nullptr; } - // We absolutely don't care, so just pick the first one. - config = configs[0]; if (GLContext::ShouldSpew()) sEGLLibrary.DumpEGLConfig(config); mozilla::gfx::IntSize pbSize(size); - surface = GLContextEGL::CreatePBufferSurfaceTryingPowerOfTwo(config, - LOCAL_EGL_NONE, - pbSize); + EGLSurface surface = GLContextEGL::CreatePBufferSurfaceTryingPowerOfTwo(config, + LOCAL_EGL_NONE, + pbSize); if (!surface) { NS_WARNING("Failed to create PBuffer for context!"); return nullptr; } - SurfaceCaps dummyCaps = SurfaceCaps::Any(); - nsRefPtr<GLContextEGL> glContext = - GLContextEGL::CreateGLContext(dummyCaps, - nullptr, true, - config, surface); - if (!glContext) { + + RefPtr<GLContextEGL> gl = GLContextEGL::CreateGLContext(configCaps, nullptr, true, + config, surface); + if (!gl) { NS_WARNING("Failed to create GLContext from PBuffer"); - sEGLLibrary.fDestroySurface(EGL_DISPLAY(), surface); + sEGLLibrary.fDestroySurface(sEGLLibrary.Display(), surface); return nullptr; } - if (!glContext->Init()) { + if (!gl->Init()) { NS_WARNING("Failed to initialize GLContext!"); // GLContextEGL::dtor will destroy |surface| for us. return nullptr; } - return glContext.forget(); + return gl.forget(); } -already_AddRefed<GLContextEGL> +/*static*/ already_AddRefed<GLContextEGL> GLContextEGL::CreateEGLPixmapOffscreenContext(const mozilla::gfx::IntSize& size) { gfxASurface *thebesSurface = nullptr; EGLNativePixmapType pixmap = 0; if (!pixmap) { return nullptr; } @@ -927,59 +1004,87 @@ GLContextEGL::CreateEGLPixmapOffscreenCo return nullptr; } glContext->HoldSurface(thebesSurface); return glContext.forget(); } -already_AddRefed<GLContext> +/*static*/ already_AddRefed<GLContext> GLContextProviderEGL::CreateHeadless(CreateContextFlags flags) { - if (!sEGLLibrary.EnsureInitialized(bool(flags & CreateContextFlags::FORCE_ENABLE_HARDWARE))) { + bool forceEnableHardware = bool(flags & CreateContextFlags::FORCE_ENABLE_HARDWARE); + if (!sEGLLibrary.EnsureInitialized(forceEnableHardware)) return nullptr; - } mozilla::gfx::IntSize dummySize = mozilla::gfx::IntSize(16, 16); - nsRefPtr<GLContext> glContext; - glContext = GLContextEGL::CreateEGLPBufferOffscreenContext(dummySize); - if (!glContext) - return nullptr; - - return glContext.forget(); + SurfaceCaps dummyCaps = SurfaceCaps::Any(); + return GLContextEGL::CreateEGLPBufferOffscreenContext(dummySize, dummyCaps); } // Under EGL, on Android, pbuffers are supported fine, though // often without the ability to texture from them directly. -already_AddRefed<GLContext> +/*static*/ already_AddRefed<GLContext> GLContextProviderEGL::CreateOffscreen(const mozilla::gfx::IntSize& size, - const SurfaceCaps& caps, + const SurfaceCaps& minCaps, CreateContextFlags flags) { - nsRefPtr<GLContext> glContext = CreateHeadless(flags); - if (!glContext) + bool forceEnableHardware = bool(flags & CreateContextFlags::FORCE_ENABLE_HARDWARE); + if (!sEGLLibrary.EnsureInitialized(forceEnableHardware)) return nullptr; - if (!glContext->InitOffscreen(size, caps)) + bool canOffscreenUseHeadless = true; + if (sEGLLibrary.IsANGLE()) { + // ANGLE needs to use PBuffers. + canOffscreenUseHeadless = false; + } + + RefPtr<GLContext> gl; + SurfaceCaps offscreenCaps = minCaps; + + if (canOffscreenUseHeadless) { + gl = CreateHeadless(flags); + if (!gl) + return nullptr; + } else { + SurfaceCaps minBackbufferCaps = minCaps; + if (minCaps.antialias) { + minBackbufferCaps.antialias = false; + minBackbufferCaps.depth = false; + minBackbufferCaps.stencil = false; + } + + gl = GLContextEGL::CreateEGLPBufferOffscreenContext(size, minBackbufferCaps); + if (!gl) + return nullptr; + + offscreenCaps = gl->Caps(); + if (minCaps.antialias) { + offscreenCaps.depth = minCaps.depth; + offscreenCaps.stencil = minCaps.stencil; + } + } + + if (!gl->InitOffscreen(size, offscreenCaps)) return nullptr; - return glContext.forget(); + return gl.forget(); } // Don't want a global context on Android as 1) share groups across 2 threads fail on many Tegra drivers (bug 759225) // and 2) some mobile devices have a very strict limit on global number of GL contexts (bug 754257) // and 3) each EGL context eats 750k on B2G (bug 813783) -GLContext* +/*static*/ GLContext* GLContextProviderEGL::GetGlobalContext() { return nullptr; } -void +/*static*/ void GLContextProviderEGL::Shutdown() { } } /* namespace gl */ } /* namespace mozilla */ #undef EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS
--- a/gfx/gl/GLContextProviderGLX.cpp +++ b/gfx/gl/GLContextProviderGLX.cpp @@ -1125,159 +1125,167 @@ GLContextProviderGLX::CreateForWindow(ns display, window, cfgs[matchIndex], false); return glContext.forget(); } -static already_AddRefed<GLContextGLX> -CreateOffscreenPixmapContext(const IntSize& size) +static bool +ChooseConfig(GLXLibrary* glx, Display* display, int screen, const SurfaceCaps& minCaps, + ScopedXFree<GLXFBConfig>* const out_scopedConfigArr, + GLXFBConfig* const out_config, int* const out_visid) { - GLXLibrary& glx = sGLXLibrary; - if (!glx.EnsureInitialized()) { - return nullptr; - } + ScopedXFree<GLXFBConfig>& scopedConfigArr = *out_scopedConfigArr; - Display *display = DefaultXDisplay(); - int xscreen = DefaultScreen(display); + if (minCaps.antialias) + return false; int attribs[] = { LOCAL_GLX_DRAWABLE_TYPE, LOCAL_GLX_PIXMAP_BIT, LOCAL_GLX_X_RENDERABLE, True, + LOCAL_GLX_RED_SIZE, 8, + LOCAL_GLX_GREEN_SIZE, 8, + LOCAL_GLX_BLUE_SIZE, 8, + LOCAL_GLX_ALPHA_SIZE, minCaps.alpha ? 8 : 0, + LOCAL_GLX_DEPTH_SIZE, minCaps.depth ? 16 : 0, + LOCAL_GLX_STENCIL_SIZE, minCaps.stencil ? 8 : 0, 0 }; + int numConfigs = 0; + scopedConfigArr = glx->xChooseFBConfig(display, screen, attribs, &numConfigs); + if (!scopedConfigArr || !numConfigs) + return false; - ScopedXFree<GLXFBConfig> cfgs; - cfgs = glx.xChooseFBConfig(display, - xscreen, - attribs, - &numConfigs); - if (!cfgs) { - return nullptr; - } + // Issues with glxChooseFBConfig selection and sorting: + // * ALPHA_SIZE is sorted as 'largest total RGBA bits first'. If we don't request + // alpha bits, we'll probably get RGBA anyways, since 32 is more than 24. + // * DEPTH_SIZE is sorted largest first, including for `0` inputs. + // * STENCIL_SIZE is smallest first, but it might return `8` even though we ask for + // `0`. - MOZ_ASSERT(numConfigs > 0, - "glXChooseFBConfig() failed to match our requested format and " - "violated its spec!"); - - int visid = None; - int chosenIndex = 0; + // For now, we don't care about these. We *will* care when we do XPixmap sharing. for (int i = 0; i < numConfigs; ++i) { - int dtype; + GLXFBConfig curConfig = scopedConfigArr[i]; - if (glx.xGetFBConfigAttrib(display, cfgs[i], LOCAL_GLX_DRAWABLE_TYPE, &dtype) != Success - || !(dtype & LOCAL_GLX_PIXMAP_BIT)) - { - continue; - } - if (glx.xGetFBConfigAttrib(display, cfgs[i], LOCAL_GLX_VISUAL_ID, &visid) != Success - || visid == 0) + int visid; + if (glx->xGetFBConfigAttrib(display, curConfig, LOCAL_GLX_VISUAL_ID, &visid) + != Success) { continue; } - chosenIndex = i; - break; + if (!visid) + continue; + + *out_config = curConfig; + *out_visid = visid; + return true; } - if (!visid) { - NS_WARNING("glXChooseFBConfig() didn't give us any configs with visuals!"); + return false; +} + +static already_AddRefed<GLContextGLX> +CreateOffscreenPixmapContext(const IntSize& size, const SurfaceCaps& minCaps) +{ + GLXLibrary* glx = &sGLXLibrary; + if (!glx->EnsureInitialized()) + return nullptr; + + Display* display = DefaultXDisplay(); + int screen = DefaultScreen(display); + + ScopedXFree<GLXFBConfig> scopedConfigArr; + GLXFBConfig config; + int visid; + if (!ChooseConfig(glx, display, screen, minCaps, &scopedConfigArr, &config, &visid)) { + NS_WARNING("Failed to find a compatible config."); return nullptr; } - Visual *visual; + Visual* visual; int depth; FindVisualAndDepth(display, visid, &visual, &depth); - ScopedXErrorHandler xErrorHandler; - GLXPixmap glxpixmap = 0; - bool error = false; - IntSize dummySize(16, 16); - nsRefPtr<gfxXlibSurface> xsurface = gfxXlibSurface::Create(DefaultScreenOfDisplay(display), - visual, - dummySize); - if (xsurface->CairoStatus() != 0) { + ScopedXErrorHandler xErrorHandler; + bool error = false; + // Must be declared before goto: + Drawable drawable; + GLXPixmap pixmap; + + gfx::IntSize dummySize(16, 16); + RefPtr<gfxXlibSurface> surface = gfxXlibSurface::Create(DefaultScreenOfDisplay(display), + visual, + dummySize); + if (surface->CairoStatus() != 0) { error = true; goto DONE_CREATING_PIXMAP; } // Handle slightly different signature between glXCreatePixmap and // its pre-GLX-1.3 extension equivalent (though given the ABI, we // might not need to). - if (glx.GLXVersionCheck(1, 3)) { - glxpixmap = glx.xCreatePixmap(display, - cfgs[chosenIndex], - xsurface->XDrawable(), - nullptr); + drawable = surface->XDrawable(); + if (glx->GLXVersionCheck(1, 3)) { + pixmap = glx->xCreatePixmap(display, config, drawable, nullptr); } else { - glxpixmap = glx.xCreateGLXPixmapWithConfig(display, - cfgs[chosenIndex], - xsurface-> - XDrawable()); + pixmap = glx->xCreateGLXPixmapWithConfig(display, config, drawable); } - if (glxpixmap == 0) { + + if (pixmap == 0) { error = true; } DONE_CREATING_PIXMAP: - nsRefPtr<GLContextGLX> glContext; bool serverError = xErrorHandler.SyncAndGetError(display); - - if (!error && // earlier recorded error - !serverError) - { - // We might have an alpha channel, but it doesn't matter. - SurfaceCaps dummyCaps = SurfaceCaps::Any(); - GLContextGLX* shareContext = GetGlobalContextGLX(); + if (error || serverError) + return nullptr; - glContext = GLContextGLX::CreateGLContext(dummyCaps, - shareContext, - true, - display, - glxpixmap, - cfgs[chosenIndex], - true, - xsurface); - } - - return glContext.forget(); + GLContextGLX* shareContext = GetGlobalContextGLX(); + return GLContextGLX::CreateGLContext(minCaps, shareContext, true, display, pixmap, + config, true, surface); } -already_AddRefed<GLContext> +/*static*/ already_AddRefed<GLContext> GLContextProviderGLX::CreateHeadless(CreateContextFlags) { IntSize dummySize = IntSize(16, 16); - nsRefPtr<GLContext> glContext = CreateOffscreenPixmapContext(dummySize); - if (!glContext) - return nullptr; - - return glContext.forget(); + SurfaceCaps dummyCaps = SurfaceCaps::Any(); + return CreateOffscreenPixmapContext(dummySize, dummyCaps); } -already_AddRefed<GLContext> +/*static*/ already_AddRefed<GLContext> GLContextProviderGLX::CreateOffscreen(const IntSize& size, - const SurfaceCaps& caps, + const SurfaceCaps& minCaps, CreateContextFlags flags) { - nsRefPtr<GLContext> glContext = CreateHeadless(flags); - if (!glContext) + SurfaceCaps minBackbufferCaps = minCaps; + if (minCaps.antialias) { + minBackbufferCaps.antialias = false; + minBackbufferCaps.depth = false; + minBackbufferCaps.stencil = false; + } + + RefPtr<GLContext> gl; + gl = CreateOffscreenPixmapContext(size, minBackbufferCaps); + if (!gl) return nullptr; - if (!glContext->InitOffscreen(size, caps)) + if (!gl->InitOffscreen(size, minCaps)) return nullptr; - return glContext.forget(); + return gl.forget(); } -GLContext* +/*static*/ GLContext* GLContextProviderGLX::GetGlobalContext() { static bool checkedContextSharing = false; static bool useContextSharing = false; if (!checkedContextSharing) { useContextSharing = getenv("MOZ_DISABLE_CONTEXT_SHARING_GLX") == 0; checkedContextSharing = true; @@ -1288,27 +1296,29 @@ GLContextProviderGLX::GetGlobalContext() return nullptr; } static bool triedToCreateContext = false; if (!triedToCreateContext && !gGlobalContext) { triedToCreateContext = true; IntSize dummySize = IntSize(16, 16); + SurfaceCaps dummyCaps = SurfaceCaps::Any(); // StaticPtr doesn't support assignments from already_AddRefed, // so use a temporary nsRefPtr to make the reference counting // fall out correctly. - nsRefPtr<GLContext> holder = CreateOffscreenPixmapContext(dummySize); + RefPtr<GLContext> holder; + holder = CreateOffscreenPixmapContext(dummySize, dummyCaps); gGlobalContext = holder; } return gGlobalContext; } -void +/*static*/ void GLContextProviderGLX::Shutdown() { gGlobalContext = nullptr; } } /* namespace gl */ } /* namespace mozilla */
--- a/gfx/gl/GLContextProviderImpl.h +++ b/gfx/gl/GLContextProviderImpl.h @@ -49,26 +49,28 @@ public: * * The offscreen context returned by this method will always have * the ability to be rendered into a context created by a window. * It might or might not share resources with the global context; * query GetSharedContext() for a non-null result to check. If * resource sharing can be avoided on the target platform, it will * be, in order to isolate the offscreen context. * - * @param size The initial size of this offscreen context. - * @param caps The SurfaceCaps for this offscreen context. - * @param flags The set of CreateContextFlags to be used for this - * offscreen context. + * @param size The initial size of this offscreen context. + * @param minCaps The required SurfaceCaps for this offscreen context. The resulting + * context *may* have more/better caps than requested, but it cannot + * have fewer/worse caps than requested. + * @param flags The set of CreateContextFlags to be used for this + * offscreen context. * * @return Context to use for offscreen rendering */ static already_AddRefed<GLContext> CreateOffscreen(const mozilla::gfx::IntSize& size, - const SurfaceCaps& caps, + const SurfaceCaps& minCaps, CreateContextFlags flags); // Just create a context. We'll add offscreen stuff ourselves. static already_AddRefed<GLContext> CreateHeadless(CreateContextFlags flags); /** * Create wrapping Gecko GLContext for external gl context.
--- a/gfx/gl/GLContextProviderWGL.cpp +++ b/gfx/gl/GLContextProviderWGL.cpp @@ -601,17 +601,17 @@ CreateWindowOffscreenContext() SurfaceCaps caps = SurfaceCaps::ForRGBA(); nsRefPtr<GLContextWGL> glContext = new GLContextWGL(caps, shareContext, true, dc, context, win); return glContext.forget(); } -already_AddRefed<GLContext> +/*static*/ already_AddRefed<GLContext> GLContextProviderWGL::CreateHeadless(CreateContextFlags) { if (!sWGLLib.EnsureInitialized()) { return nullptr; } nsRefPtr<GLContextWGL> glContext; @@ -634,34 +634,34 @@ GLContextProviderWGL::CreateHeadless(Cre { return nullptr; } nsRefPtr<GLContext> retGL = glContext.get(); return retGL.forget(); } -already_AddRefed<GLContext> +/*static*/ already_AddRefed<GLContext> GLContextProviderWGL::CreateOffscreen(const IntSize& size, - const SurfaceCaps& caps, + const SurfaceCaps& minCaps, CreateContextFlags flags) { - nsRefPtr<GLContext> glContext = CreateHeadless(flags); - if (!glContext) + RefPtr<GLContext> gl = CreateHeadless(flags); + if (!gl) return nullptr; - if (!glContext->InitOffscreen(size, caps)) + if (!gl->InitOffscreen(size, minCaps)) return nullptr; - return glContext.forget(); + return gl.forget(); } static nsRefPtr<GLContextWGL> gGlobalContext; -GLContext * +/*static*/ GLContext* GLContextProviderWGL::GetGlobalContext() { if (!sWGLLib.EnsureInitialized()) { return nullptr; } static bool triedToCreateContext = false; @@ -679,16 +679,16 @@ GLContextProviderWGL::GetGlobalContext() gGlobalContext = nullptr; return nullptr; } } return static_cast<GLContext*>(gGlobalContext); } -void +/*static*/ void GLContextProviderWGL::Shutdown() { gGlobalContext = nullptr; } } /* namespace gl */ } /* namespace mozilla */
--- a/gfx/gl/GLContextTypes.h +++ b/gfx/gl/GLContextTypes.h @@ -2,16 +2,17 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef GLCONTEXT_TYPES_H_ #define GLCONTEXT_TYPES_H_ #include "GLTypes.h" +#include "mozilla/TypedEnumBits.h" namespace mozilla { namespace gl { class GLContext; enum class GLContextType { Unknown, @@ -38,12 +39,22 @@ struct GLFormats GLenum depthStencil; GLenum depth; GLenum stencil; GLsizei samples; }; +enum class CreateContextFlags : int8_t { + NONE = 0, + REQUIRE_COMPAT_PROFILE = 1 << 0, + // Force the use of hardware backed GL, don't allow software implementations. + FORCE_ENABLE_HARDWARE = 1 << 1, + /* Don't force discrete GPU to be used (if applicable) */ + ALLOW_OFFLINE_RENDERER = 1 << 2, +}; +MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(CreateContextFlags) + } /* namespace gl */ } /* namespace mozilla */ #endif /* GLCONTEXT_TYPES_H_ */
--- a/gfx/gl/GLLibraryEGL.h +++ b/gfx/gl/GLLibraryEGL.h @@ -12,50 +12,42 @@ #include "GLLibraryLoader.h" #include "mozilla/ThreadLocal.h" #include "nsIFile.h" #include "GeckoProfiler.h" #include <bitset> #include <vector> -#if defined(XP_WIN) - -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN 1 -#endif +#ifdef XP_WIN + #ifndef WIN32_LEAN_AND_MEAN + #define WIN32_LEAN_AND_MEAN 1 + #endif -#include <windows.h> + #include <windows.h> -typedef HDC EGLNativeDisplayType; -typedef HBITMAP EGLNativePixmapType; -typedef HWND EGLNativeWindowType; - -#define GET_NATIVE_WINDOW(aWidget) ((EGLNativeWindowType)aWidget->GetNativeData(NS_NATIVE_WINDOW)) - + typedef HDC EGLNativeDisplayType; + typedef HBITMAP EGLNativePixmapType; + typedef HWND EGLNativeWindowType; #else -typedef void *EGLNativeDisplayType; -typedef void *EGLNativePixmapType; -typedef void *EGLNativeWindowType; + typedef void* EGLNativeDisplayType; + typedef void* EGLNativePixmapType; + typedef void* EGLNativeWindowType; -#ifdef ANDROID -// We only need to explicitly dlopen egltrace -// on android as we can use LD_PRELOAD or other tricks -// on other platforms. We look for it in /data/local -// as that's writeable by all users -// -// This should really go in GLLibraryEGL.cpp but we currently reference -// APITRACE_LIB in GLContextProviderEGL.cpp. Further refactoring -// will come in subsequent patches on Bug 732865 -#define APITRACE_LIB "/data/local/tmp/egltrace.so" - -#ifdef MOZ_WIDGET_ANDROID - -#endif // MOZ_WIDGET_ANDROID -#endif // ANDROID + #ifdef ANDROID + // We only need to explicitly dlopen egltrace + // on android as we can use LD_PRELOAD or other tricks + // on other platforms. We look for it in /data/local + // as that's writeable by all users + // + // This should really go in GLLibraryEGL.cpp but we currently reference + // APITRACE_LIB in GLContextProviderEGL.cpp. Further refactoring + // will come in subsequent patches on Bug 732865 + #define APITRACE_LIB "/data/local/tmp/egltrace.so" + #endif #endif #if defined(MOZ_X11) #define EGL_DEFAULT_DISPLAY ((EGLNativeDisplayType)mozilla::DefaultXDisplay()) #else #define EGL_DEFAULT_DISPLAY ((EGLNativeDisplayType)0) #endif
--- a/gfx/gl/GLScreenBuffer.cpp +++ b/gfx/gl/GLScreenBuffer.cpp @@ -481,19 +481,26 @@ GLScreenBuffer::Swap(const gfx::IntSize& !mDraw) { auto src = mFront->Surf(); auto dest = mBack->Surf(); //uint32_t srcPixel = ReadPixel(src); //uint32_t destPixel = ReadPixel(dest); //printf_stderr("Before: src: 0x%08x, dest: 0x%08x\n", srcPixel, destPixel); +#ifdef DEBUG + GLContext::LocalErrorScope errorScope(*mGL); +#endif SharedSurface::ProdCopy(src, dest, mFactory.get()); +#ifdef DEBUG + MOZ_ASSERT(!errorScope.GetError()); +#endif + //srcPixel = ReadPixel(src); //destPixel = ReadPixel(dest); //printf_stderr("After: src: 0x%08x, dest: 0x%08x\n", srcPixel, destPixel); } // XXX: We would prefer to fence earlier on platforms that don't need // the full ProducerAcquire/ProducerRelease semantics, so that the fence // doesn't include the copy operation. Unfortunately, the current API
--- a/gfx/gl/SharedSurfaceANGLE.cpp +++ b/gfx/gl/SharedSurfaceANGLE.cpp @@ -36,27 +36,24 @@ CreatePBufferSurface(GLLibraryEGL* egl, EGLint err = egl->fGetError(); if (err != LOCAL_EGL_SUCCESS) return 0; return surface; } /*static*/ UniquePtr<SharedSurface_ANGLEShareHandle> -SharedSurface_ANGLEShareHandle::Create(GLContext* gl, - EGLContext context, EGLConfig config, +SharedSurface_ANGLEShareHandle::Create(GLContext* gl, EGLConfig config, const gfx::IntSize& size, bool hasAlpha) { GLLibraryEGL* egl = &sEGLLibrary; MOZ_ASSERT(egl); MOZ_ASSERT(egl->IsExtensionSupported( GLLibraryEGL::ANGLE_surface_d3d_texture_2d_share_handle)); - - if (!context || !config) - return nullptr; + MOZ_ASSERT(config); EGLDisplay display = egl->Display(); EGLSurface pbuffer = CreatePBufferSurface(egl, display, config, size); if (!pbuffer) return nullptr; // Declare everything before 'goto's. HANDLE shareHandle = nullptr; @@ -77,44 +74,42 @@ SharedSurface_ANGLEShareHandle::Create(G GLuint fence = 0; if (gl->IsExtensionSupported(GLContext::NV_fence)) { gl->MakeCurrent(); gl->fGenFences(1, &fence); } typedef SharedSurface_ANGLEShareHandle ptrT; - UniquePtr<ptrT> ret( new ptrT(gl, egl, size, hasAlpha, context, - pbuffer, shareHandle, keyedMutex, fence) ); + UniquePtr<ptrT> ret( new ptrT(gl, egl, size, hasAlpha, pbuffer, shareHandle, + keyedMutex, fence) ); return Move(ret); } EGLDisplay SharedSurface_ANGLEShareHandle::Display() { return mEGL->Display(); } SharedSurface_ANGLEShareHandle::SharedSurface_ANGLEShareHandle(GLContext* gl, GLLibraryEGL* egl, const gfx::IntSize& size, bool hasAlpha, - EGLContext context, EGLSurface pbuffer, HANDLE shareHandle, const RefPtr<IDXGIKeyedMutex>& keyedMutex, GLuint fence) : SharedSurface(SharedSurfaceType::EGLSurfaceANGLE, AttachmentType::Screen, gl, size, hasAlpha, true) , mEGL(egl) - , mContext(context) , mPBuffer(pbuffer) , mShareHandle(shareHandle) , mKeyedMutex(keyedMutex) , mFence(fence) { } @@ -276,186 +271,42 @@ SharedSurface_ANGLEShareHandle::ToSurfac *out_descriptor = layers::SurfaceDescriptorD3D10((WindowsHandle)mShareHandle, format, mSize); return true; } //////////////////////////////////////////////////////////////////////////////// // Factory -static void -FillPBufferAttribs_ByBits(nsTArray<EGLint>& aAttrs, - int redBits, int greenBits, - int blueBits, int alphaBits, - int depthBits, int stencilBits) -{ - aAttrs.Clear(); - -#if defined(A1) || defined(A2) -#error The temp-macro names we want are already defined. -#endif - -#define A1(_x) do { aAttrs.AppendElement(_x); } while (0) -#define A2(_x,_y) do { A1(_x); A1(_y); } while (0) - - A2(LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT); - A2(LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_PBUFFER_BIT); - - A2(LOCAL_EGL_RED_SIZE, redBits); - A2(LOCAL_EGL_GREEN_SIZE, greenBits); - A2(LOCAL_EGL_BLUE_SIZE, blueBits); - A2(LOCAL_EGL_ALPHA_SIZE, alphaBits); - - A2(LOCAL_EGL_DEPTH_SIZE, depthBits); - A2(LOCAL_EGL_STENCIL_SIZE, stencilBits); - - A1(LOCAL_EGL_NONE); -#undef A1 -#undef A2 -} - -static void -FillPBufferAttribs_BySizes(nsTArray<EGLint>& attribs, - bool bpp16, bool hasAlpha, - int depthBits, int stencilBits) -{ - int red = 0; - int green = 0; - int blue = 0; - int alpha = 0; - - if (bpp16) { - if (hasAlpha) { - red = green = blue = alpha = 4; - } else { - red = 5; - green = 6; - blue = 5; - } - } else { - red = green = blue = 8; - if (hasAlpha) - alpha = 8; - } - - FillPBufferAttribs_ByBits(attribs, red, green, blue, alpha, depthBits, - stencilBits); -} - -static bool -DoesAttribBitsMatchCapBool(GLLibraryEGL* egl, EGLConfig config, EGLint attrib, - bool capBool) -{ - EGLint bits = 0; - egl->fGetConfigAttrib(egl->Display(), config, attrib, &bits); - MOZ_ASSERT(egl->fGetError() == LOCAL_EGL_SUCCESS); - - bool hasBits = !!bits; - - return hasBits == capBool; -} - -static EGLConfig -ChooseConfig(GLContext* gl, GLLibraryEGL* egl, const SurfaceCaps& caps) -{ - MOZ_ASSERT(egl); - MOZ_ASSERT(caps.color); - - // We might want 24-bit depth, but we're only (fairly) sure to get 16-bit. - int depthBits = caps.depth ? 16 : 0; - int stencilBits = caps.stencil ? 8 : 0; - - // Ok, now we have everything. - nsTArray<EGLint> attribs(32); - FillPBufferAttribs_BySizes(attribs, caps.bpp16, caps.alpha, depthBits, - stencilBits); - - // Time to try to get this config: - EGLConfig configs[64]; - int numConfigs = sizeof(configs)/sizeof(EGLConfig); - int foundConfigs = 0; - - if (!egl->fChooseConfig(egl->Display(), attribs.Elements(), configs, - numConfigs, &foundConfigs) || - !foundConfigs) - { - NS_WARNING("No configs found for the requested formats."); - return EGL_NO_CONFIG; - } - - // The requests passed to ChooseConfig are treated as minimums. If you ask - // for 0 bits of alpha, we might still get 8 bits. - EGLConfig config = EGL_NO_CONFIG; - for (int i = 0; i < foundConfigs; i++) { - EGLConfig cur = configs[i]; - if (!DoesAttribBitsMatchCapBool(egl, cur, LOCAL_EGL_ALPHA_SIZE, - caps.alpha) || - !DoesAttribBitsMatchCapBool(egl, cur, LOCAL_EGL_DEPTH_SIZE, - caps.depth) || - !DoesAttribBitsMatchCapBool(egl, cur, LOCAL_EGL_STENCIL_SIZE, - caps.stencil)) - { - continue; - } - - config = cur; - break; - } - - if (config == EGL_NO_CONFIG) { - NS_WARNING("No acceptable EGLConfig found."); - return EGL_NO_CONFIG; - } - - if (gl->DebugMode()) { - egl->DumpEGLConfig(config); - } - - return config; -} - /*static*/ UniquePtr<SurfaceFactory_ANGLEShareHandle> SurfaceFactory_ANGLEShareHandle::Create(GLContext* gl, const SurfaceCaps& caps, const RefPtr<layers::ISurfaceAllocator>& allocator, const layers::TextureFlags& flags) { GLLibraryEGL* egl = &sEGLLibrary; if (!egl) return nullptr; auto ext = GLLibraryEGL::ANGLE_surface_d3d_texture_2d_share_handle; if (!egl->IsExtensionSupported(ext)) return nullptr; - bool success; - typedef SurfaceFactory_ANGLEShareHandle ptrT; - UniquePtr<ptrT> ret( new ptrT(gl, caps, allocator, flags, egl, &success) ); + EGLConfig config = GLContextEGL::Cast(gl)->mConfig; - if (!success) - return nullptr; - + typedef SurfaceFactory_ANGLEShareHandle ptrT; + UniquePtr<ptrT> ret( new ptrT(gl, caps, allocator, flags, egl, config) ); return Move(ret); } SurfaceFactory_ANGLEShareHandle::SurfaceFactory_ANGLEShareHandle(GLContext* gl, const SurfaceCaps& caps, const RefPtr<layers::ISurfaceAllocator>& allocator, const layers::TextureFlags& flags, GLLibraryEGL* egl, - bool* const out_success) + EGLConfig config) : SurfaceFactory(SharedSurfaceType::EGLSurfaceANGLE, gl, caps, allocator, flags) , mProdGL(gl) , mEGL(egl) -{ - MOZ_ASSERT(out_success); - *out_success = false; - - mContext = GLContextEGL::Cast(mProdGL)->GetEGLContext(); - mConfig = ChooseConfig(mProdGL, mEGL, mReadCaps); - if (mConfig == EGL_NO_CONFIG) - return; - - MOZ_ASSERT(mConfig && mContext); - *out_success = true; -} + , mConfig(config) +{ } } /* namespace gl */ } /* namespace mozilla */
--- a/gfx/gl/SharedSurfaceANGLE.h +++ b/gfx/gl/SharedSurfaceANGLE.h @@ -18,45 +18,42 @@ namespace gl { class GLContext; class GLLibraryEGL; class SharedSurface_ANGLEShareHandle : public SharedSurface { public: static UniquePtr<SharedSurface_ANGLEShareHandle> Create(GLContext* gl, - EGLContext context, EGLConfig config, const gfx::IntSize& size, bool hasAlpha); static SharedSurface_ANGLEShareHandle* Cast(SharedSurface* surf) { MOZ_ASSERT(surf->mType == SharedSurfaceType::EGLSurfaceANGLE); return (SharedSurface_ANGLEShareHandle*)surf; } protected: GLLibraryEGL* const mEGL; - const EGLContext mContext; const EGLSurface mPBuffer; public: const HANDLE mShareHandle; protected: RefPtr<IDXGIKeyedMutex> mKeyedMutex; RefPtr<IDXGIKeyedMutex> mConsumerKeyedMutex; RefPtr<ID3D11Texture2D> mConsumerTexture; const GLuint mFence; SharedSurface_ANGLEShareHandle(GLContext* gl, GLLibraryEGL* egl, const gfx::IntSize& size, bool hasAlpha, - EGLContext context, EGLSurface pbuffer, HANDLE shareHandle, const RefPtr<IDXGIKeyedMutex>& keyedMutex, GLuint fence); EGLDisplay Display(); public: @@ -89,35 +86,32 @@ public: class SurfaceFactory_ANGLEShareHandle : public SurfaceFactory { protected: GLContext* const mProdGL; GLLibraryEGL* const mEGL; - EGLContext mContext; - EGLConfig mConfig; + const EGLConfig mConfig; public: static UniquePtr<SurfaceFactory_ANGLEShareHandle> Create(GLContext* gl, const SurfaceCaps& caps, const RefPtr<layers::ISurfaceAllocator>& allocator, const layers::TextureFlags& flags); protected: SurfaceFactory_ANGLEShareHandle(GLContext* gl, const SurfaceCaps& caps, const RefPtr<layers::ISurfaceAllocator>& allocator, const layers::TextureFlags& flags, GLLibraryEGL* egl, - bool* const out_success); + EGLConfig config); virtual UniquePtr<SharedSurface> CreateShared(const gfx::IntSize& size) override { bool hasAlpha = mReadCaps.alpha; - return SharedSurface_ANGLEShareHandle::Create(mProdGL, - mContext, mConfig, - size, hasAlpha); + return SharedSurface_ANGLEShareHandle::Create(mProdGL, mConfig, size, hasAlpha); } }; } /* namespace gfx */ } /* namespace mozilla */ #endif /* SHARED_SURFACE_ANGLE_H_ */
--- a/gfx/gl/SharedSurfaceEGL.cpp +++ b/gfx/gl/SharedSurfaceEGL.cpp @@ -215,17 +215,17 @@ SharedSurface_EGLImage::ToSurfaceDescrip //////////////////////////////////////////////////////////////////////// /*static*/ UniquePtr<SurfaceFactory_EGLImage> SurfaceFactory_EGLImage::Create(GLContext* prodGL, const SurfaceCaps& caps, const RefPtr<layers::ISurfaceAllocator>& allocator, const layers::TextureFlags& flags) { - EGLContext context = GLContextEGL::Cast(prodGL)->GetEGLContext(); + EGLContext context = GLContextEGL::Cast(prodGL)->mContext; typedef SurfaceFactory_EGLImage ptrT; UniquePtr<ptrT> ret; GLLibraryEGL* egl = &sEGLLibrary; if (SharedSurface_EGLImage::HasExtensions(egl, prodGL)) { ret.reset( new ptrT(prodGL, caps, allocator, flags, context) ); }
--- a/gfx/gl/moz.build +++ b/gfx/gl/moz.build @@ -66,17 +66,17 @@ if CONFIG['MOZ_X11']: # Win32 is a special snowflake, for ANGLE if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': EXPORTS += [ 'GLContextWGL.h', 'SharedSurfaceANGLE.h', # Needs <windows.h> for `HANDLE`. 'WGLLibrary.h', ] UNIFIED_SOURCES += [ - 'GLContextProviderEGL.cpp', + 'GLContextProviderWGL.cpp', 'SharedSurfaceANGLE.cpp', ] if CONFIG['MOZ_ENABLE_SKIA_GPU']: EXPORTS += ['SkiaGLGlue.h'] UNIFIED_SOURCES += [ 'SkiaGLGlue.cpp', ] @@ -108,30 +108,27 @@ elif gl_provider == 'GLX': # as it includes X11 headers which cause conflicts. SOURCES += [ 'GLContextProviderGLX.cpp', 'SharedSurfaceGLX.cpp' ] EXPORTS += [ 'SharedSurfaceGLX.h' ] -else: - UNIFIED_SOURCES += [ - 'GLContextProvider%s.cpp' % gl_provider, - ] UNIFIED_SOURCES += [ 'AndroidNativeWindow.cpp', 'AndroidSurfaceTexture.cpp', 'DecomposeIntoNoRepeatTriangles.cpp', 'EGLUtils.cpp', 'GfxTexturesReporter.cpp', 'GLBlitHelper.cpp', 'GLContext.cpp', 'GLContextFeatures.cpp', + 'GLContextProviderEGL.cpp', 'GLContextTypes.cpp', 'GLDebugUtils.cpp', 'GLLibraryEGL.cpp', 'GLLibraryLoader.cpp', 'GLReadTexImageHelper.cpp', 'GLScreenBuffer.cpp', 'GLTextureImage.cpp', 'GLUploadHelpers.cpp',