diff --git a/dom/canvas/WebGLContext.cpp b/dom/canvas/WebGLContext.cpp index 749621074af9..38420ff232e2 100644 --- a/dom/canvas/WebGLContext.cpp +++ b/dom/canvas/WebGLContext.cpp @@ -505,7 +505,7 @@ IsFeatureInBlacklist(const nsCOMPtr& gfxInfo, int32_t feature) static already_AddRefed CreateHeadlessNativeGL(bool forceEnabled, const nsCOMPtr& gfxInfo, - WebGLContext* webgl) + bool requireCompatProfile, WebGLContext* webgl) { if (!forceEnabled && IsFeatureInBlacklist(gfxInfo, nsIGfxInfo::FEATURE_WEBGL_OPENGL)) @@ -515,7 +515,7 @@ CreateHeadlessNativeGL(bool forceEnabled, const nsCOMPtr& gfxInfo, return nullptr; } - nsRefPtr gl = gl::GLContextProvider::CreateHeadless(); + nsRefPtr gl = gl::GLContextProvider::CreateHeadless(requireCompatProfile); if (!gl) { webgl->GenerateWarning("Error during native OpenGL init."); return nullptr; @@ -530,7 +530,7 @@ CreateHeadlessNativeGL(bool forceEnabled, const nsCOMPtr& gfxInfo, // Eventually, we want to be able to pick ANGLE-EGL or native EGL. static already_AddRefed CreateHeadlessANGLE(bool forceEnabled, const nsCOMPtr& gfxInfo, - WebGLContext* webgl) + bool requireCompatProfile, WebGLContext* webgl) { nsRefPtr gl; @@ -543,7 +543,7 @@ CreateHeadlessANGLE(bool forceEnabled, const nsCOMPtr& gfxInfo, return nullptr; } - gl = gl::GLContextProviderEGL::CreateHeadless(); + gl = gl::GLContextProviderEGL::CreateHeadless(requireCompatProfile); if (!gl) { webgl->GenerateWarning("Error during ANGLE OpenGL init."); return nullptr; @@ -555,13 +555,13 @@ CreateHeadlessANGLE(bool forceEnabled, const nsCOMPtr& gfxInfo, } static already_AddRefed -CreateHeadlessEGL(bool forceEnabled, const nsCOMPtr& gfxInfo, +CreateHeadlessEGL(bool forceEnabled, bool requireCompatProfile, WebGLContext* webgl) { nsRefPtr gl; #ifdef ANDROID - gl = gl::GLContextProviderEGL::CreateHeadless(); + gl = gl::GLContextProviderEGL::CreateHeadless(requireCompatProfile); if (!gl) { webgl->GenerateWarning("Error during EGL OpenGL init."); return nullptr; @@ -583,16 +583,22 @@ CreateHeadlessGL(bool forceEnabled, const nsCOMPtr& gfxInfo, if (PR_GetEnv("MOZ_WEBGL_FORCE_OPENGL")) disableANGLE = true; + bool requireCompatProfile = webgl->IsWebGL2() ? false : true; + nsRefPtr gl; if (preferEGL) - gl = CreateHeadlessEGL(forceEnabled, gfxInfo, webgl); + gl = CreateHeadlessEGL(forceEnabled, requireCompatProfile, webgl); - if (!gl && !disableANGLE) - gl = CreateHeadlessANGLE(forceEnabled, gfxInfo, webgl); + if (!gl && !disableANGLE) { + gl = CreateHeadlessANGLE(forceEnabled, gfxInfo, requireCompatProfile, + webgl); + } - if (!gl) - gl = CreateHeadlessNativeGL(forceEnabled, gfxInfo, webgl); + if (!gl) { + gl = CreateHeadlessNativeGL(forceEnabled, gfxInfo, + requireCompatProfile, webgl); + } return gl.forget(); } diff --git a/dom/canvas/WebGLContext.h b/dom/canvas/WebGLContext.h index dabdd737782f..fdaada5f80b0 100644 --- a/dom/canvas/WebGLContext.h +++ b/dom/canvas/WebGLContext.h @@ -1209,9 +1209,10 @@ protected: // ------------------------------------------------------------------------- // WebGL 2 specifics (implemented in WebGL2Context.cpp) - +public: virtual bool IsWebGL2() const = 0; +protected: bool InitWebGL2(); // ------------------------------------------------------------------------- diff --git a/dom/canvas/WebGLContextGL.cpp b/dom/canvas/WebGLContextGL.cpp index 999b71b67e42..1e4d4c1b370a 100644 --- a/dom/canvas/WebGLContextGL.cpp +++ b/dom/canvas/WebGLContextGL.cpp @@ -2106,7 +2106,6 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width, // if we're reading alpha, we may need to do fixup. Note that we don't allow // GL_ALPHA to readpixels currently, but we had the code written for it already. - const bool formatHasAlpha = format == LOCAL_GL_ALPHA || format == LOCAL_GL_RGBA; if (!formatHasAlpha) diff --git a/dom/canvas/WebGLContextUtils.cpp b/dom/canvas/WebGLContextUtils.cpp index b0e02a185770..caba53cac181 100644 --- a/dom/canvas/WebGLContextUtils.cpp +++ b/dom/canvas/WebGLContextUtils.cpp @@ -1117,11 +1117,12 @@ WebGLContext::AssertCachedState() AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_CLEAR_VALUE, mStencilClearValue); GLint stencilBits = 0; - gl->fGetIntegerv(LOCAL_GL_STENCIL_BITS, &stencilBits); - const GLuint stencilRefMask = (1 << stencilBits) - 1; + if (GetStencilBits(&stencilBits)) { + const GLuint stencilRefMask = (1 << stencilBits) - 1; - AssertMaskedUintParamCorrect(gl, LOCAL_GL_STENCIL_REF, stencilRefMask, mStencilRefFront); - AssertMaskedUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_REF, stencilRefMask, mStencilRefBack); + AssertMaskedUintParamCorrect(gl, LOCAL_GL_STENCIL_REF, stencilRefMask, mStencilRefFront); + AssertMaskedUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_REF, stencilRefMask, mStencilRefBack); + } // GLES 3.0.4, $4.1.4, p177: // [...] the front and back stencil mask are both set to the value `2^s - 1`, where diff --git a/dom/canvas/WebGLContextValidate.cpp b/dom/canvas/WebGLContextValidate.cpp index 1dbc000a1416..e942610793b9 100644 --- a/dom/canvas/WebGLContextValidate.cpp +++ b/dom/canvas/WebGLContextValidate.cpp @@ -1779,8 +1779,8 @@ WebGLContext::InitAndValidateGL() MakeContextCurrent(); - // on desktop OpenGL, we always keep vertex attrib 0 array enabled - if (!gl->IsGLES()) + // For OpenGL compat. profiles, we always keep vertex attrib 0 array enabled. + if (gl->IsCompatibilityProfile()) gl->fEnableVertexAttribArray(0); if (MinCapabilityMode()) @@ -1889,7 +1889,7 @@ WebGLContext::InitAndValidateGL() // Always 1 for GLES2 mMaxFramebufferColorAttachments = 1; - if (!gl->IsGLES()) { + if (gl->IsCompatibilityProfile()) { // gl_PointSize is always available in ES2 GLSL, but has to be // specifically enabled on desktop GLSL. gl->fEnable(LOCAL_GL_VERTEX_PROGRAM_POINT_SIZE); diff --git a/dom/media/fmp4/android/AndroidDecoderModule.cpp b/dom/media/fmp4/android/AndroidDecoderModule.cpp index 84fbd4ef3f54..bd00d07faa7f 100644 --- a/dom/media/fmp4/android/AndroidDecoderModule.cpp +++ b/dom/media/fmp4/android/AndroidDecoderModule.cpp @@ -179,7 +179,7 @@ protected: return true; } - mGLContext = GLContextProvider::CreateHeadless(); + mGLContext = GLContextProvider::CreateHeadless(false); return mGLContext; } diff --git a/dom/plugins/base/nsNPAPIPluginInstance.cpp b/dom/plugins/base/nsNPAPIPluginInstance.cpp index 811b75c31bf3..9f94d76639d1 100644 --- a/dom/plugins/base/nsNPAPIPluginInstance.cpp +++ b/dom/plugins/base/nsNPAPIPluginInstance.cpp @@ -91,9 +91,8 @@ static nsRefPtr sPluginContext = nullptr; static bool EnsureGLContext() { if (!sPluginContext) { - gfxIntSize dummySize(16, 16); - sPluginContext = GLContextProvider::CreateOffscreen(dummySize, - SurfaceCaps::Any()); + bool requireCompatProfile = true; + sPluginContext = GLContextProvider::CreateHeadless(requireCompatProfile); } return sPluginContext != nullptr; diff --git a/gfx/gl/GLContext.cpp b/gfx/gl/GLContext.cpp index b300ddff6085..f84a47c54b02 100644 --- a/gfx/gl/GLContext.cpp +++ b/gfx/gl/GLContext.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include "GLContext.h" #include "GLBlitHelper.h" @@ -156,8 +157,7 @@ static const char *sExtensionNames[] = { "GL_OES_texture_half_float", "GL_OES_texture_half_float_linear", "GL_OES_texture_npot", - "GL_OES_vertex_array_object", - nullptr + "GL_OES_vertex_array_object" }; static bool @@ -501,6 +501,8 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl) mInitialized = LoadSymbols(&symbols[0], trygl, prefix); MakeCurrent(); if (mInitialized) { + MOZ_ASSERT(mProfile != ContextProfile::Unknown); + uint32_t version = 0; ParseGLVersion(this, &version); @@ -656,6 +658,15 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl) } } + if (IsFeatureProvidedByCoreSymbols(GLFeature::get_string_indexed)) { + SymLoadStruct moreSymbols[] = { + { (PRFuncPtr*) &mSymbols.fGetStringi, { "GetStringi", nullptr } }, + END_SYMBOLS + }; + + MOZ_ALWAYS_TRUE(LoadSymbols(moreSymbols, trygl, prefix)); + } + InitExtensions(); InitFeatures(); @@ -670,12 +681,6 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl) MarkUnsupported(GLFeature::standard_derivatives); } - if (Vendor() == GLVendor::Imagination && - Renderer() == GLRenderer::SGX540) { - // Bug 980048 - MarkExtensionUnsupported(OES_EGL_sync); - } - if (Renderer() == GLRenderer::MicrosoftBasicRenderDriver) { // Bug 978966: on Microsoft's "Basic Render Driver" (software renderer) // multisampling hardcodes blending with the default blendfunc, which breaks WebGL. @@ -1468,10 +1473,13 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl) // We're ready for final setup. fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0); - if (mCaps.any) - DetermineCaps(); + // TODO: Remove SurfaceCaps::any. + if (mCaps.any) { + mCaps.any = false; + mCaps.color = true; + mCaps.alpha = false; + } - UpdatePixelFormat(); UpdateGLFormats(mCaps); mTexGarbageBin = new TextureGarbageBin(this); @@ -1593,61 +1601,105 @@ GLContext::DebugCallback(GLenum source, void GLContext::InitExtensions() { - MakeCurrent(); - const char* extensions = (const char*)fGetString(LOCAL_GL_EXTENSIONS); - if (!extensions) - return; + MOZ_ASSERT(IsCurrent()); - InitializeExtensionsBitSet(mAvailableExtensions, extensions, - sExtensionNames); + std::vector driverExtensionList; - if (WorkAroundDriverBugs() && - Vendor() == GLVendor::Qualcomm) { + if (IsFeatureProvidedByCoreSymbols(GLFeature::get_string_indexed)) { + GLuint count = 0; + GetUIntegerv(LOCAL_GL_NUM_EXTENSIONS, &count); + for (GLuint i = 0; i < count; i++) { + // This is UTF-8. + const char* rawExt = (const char*)fGetStringi(LOCAL_GL_EXTENSIONS, i); - // Some Adreno drivers do not report GL_OES_EGL_sync, but they really do support it. - MarkExtensionSupported(OES_EGL_sync); + // We CANNOT use nsDependentCString here, because the spec doesn't guarantee + // that the pointers returned are different, only that their contents are. + // On Flame, each of these index string queries returns the same address. + driverExtensionList.push_back(nsCString(rawExt)); + } + } else { + MOZ_ALWAYS_TRUE(!fGetError()); + const char* rawExts = (const char*)fGetString(LOCAL_GL_EXTENSIONS); + MOZ_ALWAYS_TRUE(!fGetError()); + + if (rawExts) { + nsDependentCString exts(rawExts); + SplitByChar(exts, ' ', &driverExtensionList); + } } - if (WorkAroundDriverBugs() && - Renderer() == GLRenderer::AndroidEmulator) { - // the Android emulator, which we use to run B2G reftests on, - // doesn't expose the OES_rgb8_rgba8 extension, but it seems to - // support it (tautologically, as it only runs on desktop GL). - MarkExtensionSupported(OES_rgb8_rgba8); + const bool shouldDumpExts = ShouldDumpExts(); + if (shouldDumpExts) { + printf_stderr("%i GL driver extensions: (*: recognized)\n", + (uint32_t)driverExtensionList.size()); } - if (WorkAroundDriverBugs() && - Vendor() == GLVendor::VMware && - Renderer() == GLRenderer::GalliumLlvmpipe) - { - // The llvmpipe driver that is used on linux try servers appears to have - // buggy support for s3tc/dxt1 compressed textures. - // See Bug 975824. - MarkExtensionUnsupported(EXT_texture_compression_s3tc); - MarkExtensionUnsupported(EXT_texture_compression_dxt1); - MarkExtensionUnsupported(ANGLE_texture_compression_dxt3); - MarkExtensionUnsupported(ANGLE_texture_compression_dxt5); - } + MarkBitfieldByStrings(driverExtensionList, shouldDumpExts, sExtensionNames, + &mAvailableExtensions); + + if (WorkAroundDriverBugs()) { + if (Vendor() == GLVendor::Qualcomm) { + // Some Adreno drivers do not report GL_OES_EGL_sync, but they really do support it. + MarkExtensionSupported(OES_EGL_sync); + } + + if (Vendor() == GLVendor::Imagination && + Renderer() == GLRenderer::SGX540) + { + // Bug 980048 + MarkExtensionUnsupported(OES_EGL_sync); + } + + if (Renderer() == GLRenderer::AndroidEmulator) { + // the Android emulator, which we use to run B2G reftests on, + // doesn't expose the OES_rgb8_rgba8 extension, but it seems to + // support it (tautologically, as it only runs on desktop GL). + MarkExtensionSupported(OES_rgb8_rgba8); + } + + if (Vendor() == GLVendor::VMware && + Renderer() == GLRenderer::GalliumLlvmpipe) + { + // The llvmpipe driver that is used on linux try servers appears to have + // buggy support for s3tc/dxt1 compressed textures. + // See Bug 975824. + MarkExtensionUnsupported(EXT_texture_compression_s3tc); + MarkExtensionUnsupported(EXT_texture_compression_dxt1); + MarkExtensionUnsupported(ANGLE_texture_compression_dxt3); + MarkExtensionUnsupported(ANGLE_texture_compression_dxt5); + } #ifdef XP_MACOSX - // Bug 1009642: On OSX Mavericks (10.9), the driver for Intel HD - // 3000 appears to be buggy WRT updating sub-images of S3TC - // textures with glCompressedTexSubImage2D. Works on Intel HD 4000 - // and Intel HD 5000/Iris that I tested. - if (WorkAroundDriverBugs() && - nsCocoaFeatures::OSXVersionMajor() == 10 && - nsCocoaFeatures::OSXVersionMinor() == 9 && - Renderer() == GLRenderer::IntelHD3000) - { - MarkExtensionUnsupported(EXT_texture_compression_s3tc); - } + // Bug 1009642: On OSX Mavericks (10.9), the driver for Intel HD + // 3000 appears to be buggy WRT updating sub-images of S3TC + // textures with glCompressedTexSubImage2D. Works on Intel HD 4000 + // and Intel HD 5000/Iris that I tested. + if (nsCocoaFeatures::OSXVersionMajor() == 10 && + nsCocoaFeatures::OSXVersionMinor() == 9 && + Renderer() == GLRenderer::IntelHD3000) + { + MarkExtensionUnsupported(EXT_texture_compression_s3tc); + } #endif + } + + if (shouldDumpExts) { + printf_stderr("\nActivated extensions:\n"); + + for (size_t i = 0; i < mAvailableExtensions.size(); i++) { + if (!mAvailableExtensions[i]) + continue; + + const char* ext = sExtensionNames[i]; + printf_stderr("[%i] %s\n", (uint32_t)i, ext); + } + } } void GLContext::PlatformStartup() { - RegisterStrongMemoryReporter(new GfxTexturesReporter()); + RegisterStrongMemoryReporter(new GfxTexturesReporter()); } // Common code for checking for both GL extensions and GLX extensions. @@ -1688,66 +1740,6 @@ GLContext::ListHasExtension(const GLubyte *extensions, const char *extension) return false; } -void -GLContext::DetermineCaps() -{ - PixelBufferFormat format = QueryPixelFormat(); - - SurfaceCaps caps; - caps.color = !!format.red && !!format.green && !!format.blue; - caps.bpp16 = caps.color && format.ColorBits() == 16; - caps.alpha = !!format.alpha; - caps.depth = !!format.depth; - caps.stencil = !!format.stencil; - caps.antialias = format.samples > 1; - caps.preserve = true; - - mCaps = caps; -} - -PixelBufferFormat -GLContext::QueryPixelFormat() -{ - PixelBufferFormat format; - - ScopedBindFramebuffer autoFB(this, 0); - - fGetIntegerv(LOCAL_GL_RED_BITS , &format.red ); - fGetIntegerv(LOCAL_GL_GREEN_BITS, &format.green); - fGetIntegerv(LOCAL_GL_BLUE_BITS , &format.blue ); - fGetIntegerv(LOCAL_GL_ALPHA_BITS, &format.alpha); - - fGetIntegerv(LOCAL_GL_DEPTH_BITS, &format.depth); - fGetIntegerv(LOCAL_GL_STENCIL_BITS, &format.stencil); - - fGetIntegerv(LOCAL_GL_SAMPLES, &format.samples); - - return format; -} - -void -GLContext::UpdatePixelFormat() -{ - PixelBufferFormat format = QueryPixelFormat(); -#ifdef MOZ_GL_DEBUG - const SurfaceCaps& caps = Caps(); - MOZ_ASSERT(!caps.any, "Did you forget to DetermineCaps()?"); - - MOZ_ASSERT(caps.color == !!format.red); - MOZ_ASSERT(caps.color == !!format.green); - MOZ_ASSERT(caps.color == !!format.blue); - - // These we either must have if they're requested, or - // we can have if they're not. - MOZ_ASSERT(caps.alpha == !!format.alpha || !caps.alpha); - MOZ_ASSERT(caps.depth == !!format.depth || !caps.depth); - MOZ_ASSERT(caps.stencil == !!format.stencil || !caps.stencil); - - MOZ_ASSERT(caps.antialias == (format.samples > 1)); -#endif - mPixelFormat = new PixelBufferFormat(format); -} - GLFormats GLContext::ChooseGLFormats(const SurfaceCaps& caps) const { @@ -2417,6 +2409,13 @@ GLContext::FlushIfHeavyGLCallsSinceLastFlush() fFlush(); } +/*static*/ bool +GLContext::ShouldDumpExts() +{ + static bool ret = PR_GetEnv("MOZ_GL_DUMP_EXTS"); + return ret; +} + bool DoesStringMatch(const char* aString, const char *aWantedString) { @@ -2444,8 +2443,29 @@ DoesStringMatch(const char* aString, const char *aWantedString) /*static*/ bool GLContext::ShouldSpew() { - static bool spew = PR_GetEnv("MOZ_GL_SPEW"); - return spew; + static bool ret = PR_GetEnv("MOZ_GL_SPEW"); + return ret; +} + +void +SplitByChar(const nsACString& str, const char delim, std::vector* const out) +{ + uint32_t start = 0; + while (true) { + int32_t end = str.FindChar(' ', start); + if (end == -1) + break; + + uint32_t len = (uint32_t)end - start; + nsDependentCSubstring substr(str, start, len); + out->push_back(nsCString(substr)); + + start = end + 1; + continue; + } + + nsDependentCSubstring substr(str, start); + out->push_back(nsCString(substr)); } } /* namespace gl */ diff --git a/gfx/gl/GLContext.h b/gfx/gl/GLContext.h index 9cc3a0906344..cc6d8fcf2a42 100644 --- a/gfx/gl/GLContext.h +++ b/gfx/gl/GLContext.h @@ -104,6 +104,7 @@ enum class GLFeature { get_integer_indexed, get_integer64_indexed, get_query_object_iv, + get_string_indexed, gpu_shader4, instanced_arrays, instanced_non_arrays, @@ -308,7 +309,6 @@ public: virtual bool IsCurrent() = 0; protected: - bool mInitialized; bool mIsOffscreen; bool mIsGlobalSharedContext; @@ -325,9 +325,12 @@ protected: GLVendor mVendor; GLRenderer mRenderer; - inline void SetProfileVersion(ContextProfile profile, unsigned int version) { - MOZ_ASSERT(!mInitialized, "SetProfileVersion can only be called before initialization!"); - MOZ_ASSERT(profile != ContextProfile::Unknown && profile != ContextProfile::OpenGL, "Invalid `profile` for SetProfileVersion"); + void SetProfileVersion(ContextProfile profile, uint32_t version) { + MOZ_ASSERT(!mInitialized, "SetProfileVersion can only be called before" + " initialization!"); + MOZ_ASSERT(profile != ContextProfile::Unknown && + profile != ContextProfile::OpenGL, + "Invalid `profile` for SetProfileVersion"); MOZ_ASSERT(version >= 100, "Invalid `version` for SetProfileVersion"); mVersion = version; @@ -457,6 +460,7 @@ public: return mAvailableExtensions[aKnownExtension]; } +protected: void MarkExtensionUnsupported(GLExtensions aKnownExtension) { mAvailableExtensions[aKnownExtension] = 0; } @@ -465,42 +469,6 @@ public: mAvailableExtensions[aKnownExtension] = 1; } -public: - template - static void InitializeExtensionsBitSet(std::bitset& extensionsBitset, - const char* extStr, - const char** extList) - { - char* exts = ::strdup(extStr); - - if (ShouldSpew()) - printf_stderr("Extensions: %s\n", exts); - - char* cur = exts; - bool done = false; - while (!done) { - char* space = strchr(cur, ' '); - if (space) { - *space = '\0'; - } else { - done = true; - } - - for (int i = 0; extList[i]; ++i) { - if (PL_strcasecmp(cur, extList[i]) == 0) { - if (ShouldSpew()) - printf_stderr("Found extension %s\n", cur); - extensionsBitset[i] = true; - } - } - - cur = space + 1; - } - - free(exts); - } - -protected: std::bitset mAvailableExtensions; // ----------------------------------------------------------------------------- @@ -3180,6 +3148,17 @@ public: AFTER_GL_CALL; } +// ----------------------------------------------------------------------------- +// get_string_indexed + + const GLubyte* fGetStringi(GLenum name, GLuint index) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fGetStringi); + const GLubyte* ret = mSymbols.fGetStringi(name, index); + AFTER_GL_CALL; + return ret; + } + // ----------------------------------------------------------------------------- // Constructor protected: @@ -3448,11 +3427,9 @@ public: fViewport(0, 0, size.width, size.height); mCaps = mScreen->mCaps; - if (mCaps.any) - DetermineCaps(); + MOZ_ASSERT(!mCaps.any); UpdateGLFormats(mCaps); - UpdatePixelFormat(); return true; } @@ -3475,10 +3452,8 @@ public: protected: SurfaceCaps mCaps; nsAutoPtr mGLFormats; - nsAutoPtr mPixelFormat; public: - void DetermineCaps(); const SurfaceCaps& Caps() const { return mCaps; } @@ -3494,14 +3469,6 @@ public: return *mGLFormats; } - PixelBufferFormat QueryPixelFormat(); - void UpdatePixelFormat(); - - const PixelBufferFormat& GetPixelFormat() const { - MOZ_ASSERT(mPixelFormat); - return *mPixelFormat; - } - bool IsFramebufferComplete(GLuint fb, GLenum* status = nullptr); // Does not check completeness. @@ -3541,7 +3508,7 @@ public: } bool IsOffscreen() const { - return !!mScreen; + return mIsOffscreen; } GLScreenBuffer* Screen() const { @@ -3696,10 +3663,42 @@ protected: public: void FlushIfHeavyGLCallsSinceLastFlush(); static bool ShouldSpew(); + static bool ShouldDumpExts(); }; bool DoesStringMatch(const char* aString, const char *aWantedString); +void SplitByChar(const nsACString& str, const char delim, + std::vector* const out); + +template +bool +MarkBitfieldByString(const nsACString& str, const char* (&markStrList)[N], + std::bitset* const out_markList) +{ + for (size_t i = 0; i < N; i++) { + if (str.Equals(markStrList[i])) { + (*out_markList)[i] = 1; + return true; + } + } + return false; +} + +template +void +MarkBitfieldByStrings(const std::vector& strList, + bool dumpStrings, const char* (&markStrList)[N], + std::bitset* const out_markList) +{ + for (auto itr = strList.begin(); itr != strList.end(); ++itr) { + const nsACString& str = *itr; + const bool wasMarked = MarkBitfieldByString(str, markStrList, + out_markList); + if (dumpStrings) + printf_stderr(" %s%s\n", str.BeginReading(), wasMarked ? "(*)" : ""); + } +} } /* namespace gl */ } /* namespace mozilla */ diff --git a/gfx/gl/GLContextCGL.h b/gfx/gl/GLContextCGL.h index 9b3c52ddd8e5..5da7085450cb 100644 --- a/gfx/gl/GLContextCGL.h +++ b/gfx/gl/GLContextCGL.h @@ -28,10 +28,8 @@ class GLContextCGL : public GLContext public: MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GLContextCGL, MOZ_OVERRIDE) - GLContextCGL(const SurfaceCaps& caps, - GLContext *shareContext, - NSOpenGLContext *context, - bool isOffscreen = false); + GLContextCGL(const SurfaceCaps& caps, NSOpenGLContext* context, + bool isOffscreen, ContextProfile profile); ~GLContextCGL(); diff --git a/gfx/gl/GLContextFeatures.cpp b/gfx/gl/GLContextFeatures.cpp index 0e47ecbae087..ed2fa69ec9e2 100644 --- a/gfx/gl/GLContextFeatures.cpp +++ b/gfx/gl/GLContextFeatures.cpp @@ -274,6 +274,16 @@ static const FeatureInfo sFeatureInfoArr[] = { * ARB_occlusion_query (added by OpenGL 2.0). */ }, + { + "get_string_indexed", + GLVersion::GL3, + GLESVersion::ES3, + GLContext::Extension_None, + { + GLContext::Extensions_End + } + // glGetStringi + }, { "gpu_shader4", GLVersion::GL3, diff --git a/gfx/gl/GLContextProviderCGL.mm b/gfx/gl/GLContextProviderCGL.mm index 3492e4ab4eac..a5c3a9baf3e6 100644 --- a/gfx/gl/GLContextProviderCGL.mm +++ b/gfx/gl/GLContextProviderCGL.mm @@ -21,16 +21,14 @@ namespace gl { using namespace mozilla::gfx; -static bool gUseDoubleBufferedWindows = true; - class CGLLibrary { public: CGLLibrary() - : mInitialized(false), - mOGLLibrary(nullptr), - mPixelFormat(nullptr) - { } + : mInitialized(false) + , mUseDoubleBufferedWindows(true) + , mOGLLibrary(nullptr) + {} bool EnsureInitialized() { @@ -46,48 +44,33 @@ public: } const char* db = PR_GetEnv("MOZ_CGL_DB"); - gUseDoubleBufferedWindows = (!db || *db != '0'); + if (db) { + mUseDoubleBufferedWindows = *db != '0'; + } mInitialized = true; return true; } - NSOpenGLPixelFormat *PixelFormat() - { - if (mPixelFormat == nullptr) { - NSOpenGLPixelFormatAttribute attribs[] = { - NSOpenGLPFAAccelerated, - NSOpenGLPFAAllowOfflineRenderers, - NSOpenGLPFADoubleBuffer, - 0 - }; - - if (!gUseDoubleBufferedWindows) { - attribs[2] = 0; - } - - mPixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs]; - } - - return mPixelFormat; + bool UseDoubleBufferedWindows() const { + MOZ_ASSERT(mInitialized); + return mUseDoubleBufferedWindows; } + private: bool mInitialized; + bool mUseDoubleBufferedWindows; PRLibrary *mOGLLibrary; - NSOpenGLPixelFormat *mPixelFormat; }; CGLLibrary sCGLLibrary; -GLContextCGL::GLContextCGL( - const SurfaceCaps& caps, - GLContext *shareContext, - NSOpenGLContext *context, - bool isOffscreen) - : GLContext(caps, shareContext, isOffscreen), - mContext(context) +GLContextCGL::GLContextCGL(const SurfaceCaps& caps, NSOpenGLContext* context, + bool isOffscreen, ContextProfile profile) + : GLContext(caps, nullptr, isOffscreen) + , mContext(context) { - SetProfileVersion(ContextProfile::OpenGLCompatibility, 210); + SetProfileVersion(profile, 210); } GLContextCGL::~GLContextCGL() @@ -162,7 +145,7 @@ GLContextCGL::SetupLookupFunction() bool GLContextCGL::IsDoubleBuffered() const { - return gUseDoubleBufferedWindows; + return sCGLLibrary.UseDoubleBufferedWindows(); } bool @@ -182,26 +165,66 @@ GLContextCGL::SwapBuffers() } -static GLContextCGL * -GetGlobalContextCGL() -{ - return static_cast(GLContextProviderCGL::GetGlobalContext()); -} - already_AddRefed GLContextProviderCGL::CreateWrappingExisting(void*, void*) { return nullptr; } +static const NSOpenGLPixelFormatAttribute kAttribs_singleBuffered[] = { + NSOpenGLPFAAccelerated, + NSOpenGLPFAAllowOfflineRenderers, + 0 +}; + +static const NSOpenGLPixelFormatAttribute kAttribs_doubleBuffered[] = { + NSOpenGLPFAAccelerated, + NSOpenGLPFAAllowOfflineRenderers, + NSOpenGLPFADoubleBuffer, + 0 +}; + +static const NSOpenGLPixelFormatAttribute kAttribs_offscreen[] = { + NSOpenGLPFAPixelBuffer, + 0 +}; + +static const NSOpenGLPixelFormatAttribute kAttribs_offscreen_coreProfile[] = { + NSOpenGLPFAAccelerated, + NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core, + 0 +}; + +static NSOpenGLContext* +CreateWithFormat(const NSOpenGLPixelFormatAttribute* attribs) +{ + NSOpenGLPixelFormat* format = [[NSOpenGLPixelFormat alloc] + initWithAttributes:attribs]; + if (!format) + return nullptr; + + NSOpenGLContext* context = [[NSOpenGLContext alloc] initWithFormat:format + shareContext:nullptr]; + + [format release]; + + return context; +} + already_AddRefed GLContextProviderCGL::CreateForWindow(nsIWidget *aWidget) { - GLContextCGL *shareContext = GetGlobalContextCGL(); + if (!sCGLLibrary.EnsureInitialized()) { + return nullptr; + } - NSOpenGLContext *context = [[NSOpenGLContext alloc] - initWithFormat:sCGLLibrary.PixelFormat() - shareContext:(shareContext ? shareContext->mContext : NULL)]; + const NSOpenGLPixelFormatAttribute* attribs; + if (sCGLLibrary.UseDoubleBufferedWindows()) { + attribs = kAttribs_doubleBuffered; + } else { + attribs = kAttribs_singleBuffered; + } + NSOpenGLContext* context = CreateWithFormat(attribs); if (!context) { return nullptr; } @@ -211,10 +234,13 @@ GLContextProviderCGL::CreateForWindow(nsIWidget *aWidget) [context setValues:&opaque forParameter:NSOpenGLCPSurfaceOpacity]; SurfaceCaps caps = SurfaceCaps::ForRGBA(); - nsRefPtr glContext = new GLContextCGL(caps, - shareContext, - context); + ContextProfile profile = ContextProfile::OpenGLCompatibility; + nsRefPtr glContext = new GLContextCGL(caps, context, false, + profile); + if (!glContext->Init()) { + glContext = nullptr; + [context release]; return nullptr; } @@ -222,49 +248,54 @@ GLContextProviderCGL::CreateForWindow(nsIWidget *aWidget) } static already_AddRefed -CreateOffscreenFBOContext(bool aShare = true) +CreateOffscreenFBOContext(bool requireCompatProfile) { if (!sCGLLibrary.EnsureInitialized()) { return nullptr; } - GLContextCGL *shareContext = aShare ? GetGlobalContextCGL() : nullptr; - if (aShare && !shareContext) { - // if there is no share context, then we can't use FBOs. - return nullptr; - } + ContextProfile profile; + NSOpenGLContext* context = nullptr; - NSOpenGLContext *context = [[NSOpenGLContext alloc] - initWithFormat:sCGLLibrary.PixelFormat() - shareContext:shareContext ? shareContext->GetNSOpenGLContext() : NULL]; + if (!requireCompatProfile) { + profile = ContextProfile::OpenGLCore; + context = CreateWithFormat(kAttribs_offscreen_coreProfile); + } + if (!context) { + profile = ContextProfile::OpenGLCompatibility; + context = CreateWithFormat(kAttribs_offscreen); + } if (!context) { return nullptr; } SurfaceCaps dummyCaps = SurfaceCaps::Any(); - nsRefPtr glContext = new GLContextCGL(dummyCaps, shareContext, context, true); + nsRefPtr glContext = new GLContextCGL(dummyCaps, context, + true, profile); return glContext.forget(); } already_AddRefed -GLContextProviderCGL::CreateHeadless() +GLContextProviderCGL::CreateHeadless(bool requireCompatProfile) { - nsRefPtr glContext = CreateOffscreenFBOContext(); - if (!glContext) + nsRefPtr gl; + gl = CreateOffscreenFBOContext(requireCompatProfile); + if (!gl) return nullptr; - if (!glContext->Init()) + if (!gl->Init()) return nullptr; - return glContext.forget(); + return gl.forget(); } already_AddRefed GLContextProviderCGL::CreateOffscreen(const gfxIntSize& size, - const SurfaceCaps& caps) + const SurfaceCaps& caps, + bool requireCompatProfile) { - nsRefPtr glContext = CreateHeadless(); + nsRefPtr glContext = CreateHeadless(requireCompatProfile); if (!glContext->InitOffscreen(ToIntSize(size), caps)) return nullptr; @@ -299,7 +330,7 @@ GLContextProviderCGL::GetGlobalContext() void GLContextProviderCGL::Shutdown() { - gGlobalContext = nullptr; + gGlobalContext = nullptr; } } /* namespace gl */ diff --git a/gfx/gl/GLContextProviderEGL.cpp b/gfx/gl/GLContextProviderEGL.cpp index 12c2068091db..b946167fa66b 100644 --- a/gfx/gl/GLContextProviderEGL.cpp +++ b/gfx/gl/GLContextProviderEGL.cpp @@ -878,7 +878,7 @@ GLContextEGL::CreateEGLPixmapOffscreenContext(const gfxIntSize& size) } already_AddRefed -GLContextProviderEGL::CreateHeadless() +GLContextProviderEGL::CreateHeadless(bool) { if (!sEGLLibrary.EnsureInitialized()) { return nullptr; @@ -897,9 +897,10 @@ GLContextProviderEGL::CreateHeadless() // often without the ability to texture from them directly. already_AddRefed GLContextProviderEGL::CreateOffscreen(const gfxIntSize& size, - const SurfaceCaps& caps) + const SurfaceCaps& caps, + bool requireCompatProfile) { - nsRefPtr glContext = CreateHeadless(); + nsRefPtr glContext = CreateHeadless(requireCompatProfile); if (!glContext) return nullptr; diff --git a/gfx/gl/GLContextProviderGLX.cpp b/gfx/gl/GLContextProviderGLX.cpp index 4587b7d2e1dd..22eab4603067 100644 --- a/gfx/gl/GLContextProviderGLX.cpp +++ b/gfx/gl/GLContextProviderGLX.cpp @@ -1213,7 +1213,7 @@ DONE_CREATING_PIXMAP: } already_AddRefed -GLContextProviderGLX::CreateHeadless() +GLContextProviderGLX::CreateHeadless(bool) { gfxIntSize dummySize = gfxIntSize(16, 16); nsRefPtr glContext = CreateOffscreenPixmapContext(dummySize); @@ -1225,9 +1225,10 @@ GLContextProviderGLX::CreateHeadless() already_AddRefed GLContextProviderGLX::CreateOffscreen(const gfxIntSize& size, - const SurfaceCaps& caps) + const SurfaceCaps& caps, + bool requireCompatProfile) { - nsRefPtr glContext = CreateHeadless(); + nsRefPtr glContext = CreateHeadless(requireCompatProfile); if (!glContext) return nullptr; diff --git a/gfx/gl/GLContextProviderImpl.h b/gfx/gl/GLContextProviderImpl.h index 6efc65de064f..9e87170c8237 100644 --- a/gfx/gl/GLContextProviderImpl.h +++ b/gfx/gl/GLContextProviderImpl.h @@ -58,11 +58,12 @@ public: */ static already_AddRefed CreateOffscreen(const gfxIntSize& size, - const SurfaceCaps& caps); + const SurfaceCaps& caps, + bool requireCompatProfile); // Just create a context. We'll add offscreen stuff ourselves. static already_AddRefed - CreateHeadless(); + CreateHeadless(bool requireCompatProfile); /** * Create wrapping Gecko GLContext for external gl context. diff --git a/gfx/gl/GLContextProviderNull.cpp b/gfx/gl/GLContextProviderNull.cpp index 61732a6e6b63..231c75be5f3f 100644 --- a/gfx/gl/GLContextProviderNull.cpp +++ b/gfx/gl/GLContextProviderNull.cpp @@ -22,13 +22,14 @@ GLContextProviderNull::CreateWrappingExisting(void*, void*) already_AddRefed GLContextProviderNull::CreateOffscreen(const gfxIntSize&, - const SurfaceCaps&) + const SurfaceCaps&, + bool) { return nullptr; } already_AddRefed -GLContextProviderNull::CreateHeadless() +GLContextProviderNull::CreateHeadless(bool) { return nullptr; } diff --git a/gfx/gl/GLContextProviderWGL.cpp b/gfx/gl/GLContextProviderWGL.cpp index a8c2124d6788..bf605c057e9a 100644 --- a/gfx/gl/GLContextProviderWGL.cpp +++ b/gfx/gl/GLContextProviderWGL.cpp @@ -607,7 +607,7 @@ CreateWindowOffscreenContext() } already_AddRefed -GLContextProviderWGL::CreateHeadless() +GLContextProviderWGL::CreateHeadless(bool) { if (!sWGLLib.EnsureInitialized()) { return nullptr; @@ -641,9 +641,10 @@ GLContextProviderWGL::CreateHeadless() already_AddRefed GLContextProviderWGL::CreateOffscreen(const gfxIntSize& size, - const SurfaceCaps& caps) + const SurfaceCaps& caps, + bool requireCompatProfile) { - nsRefPtr glContext = CreateHeadless(); + nsRefPtr glContext = CreateHeadless(requireCompatProfile); if (!glContext) return nullptr; diff --git a/gfx/gl/GLContextSymbols.h b/gfx/gl/GLContextSymbols.h index 3904beac1736..91ff5ac71dc9 100644 --- a/gfx/gl/GLContextSymbols.h +++ b/gfx/gl/GLContextSymbols.h @@ -666,6 +666,10 @@ struct GLContextSymbols GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid* data); PFNGLCOMPRESSEDTEXSUBIMAGE3D fCompressedTexSubImage3D; + + // get_string_indexed + typedef const GLubyte* (GLAPIENTRY * pfnGLGetStringiT)(GLenum name, GLuint index); + pfnGLGetStringiT fGetStringi; }; } diff --git a/gfx/gl/GLContextTypes.cpp b/gfx/gl/GLContextTypes.cpp index b11c99098d28..2cca59dc96aa 100644 --- a/gfx/gl/GLContextTypes.cpp +++ b/gfx/gl/GLContextTypes.cpp @@ -12,8 +12,3 @@ GLFormats::GLFormats() { std::memset(this, 0, sizeof(GLFormats)); } - -PixelBufferFormat::PixelBufferFormat() -{ - std::memset(this, 0, sizeof(PixelBufferFormat)); -} diff --git a/gfx/gl/GLContextTypes.h b/gfx/gl/GLContextTypes.h index f21cc11cf06e..979790bb1e58 100644 --- a/gfx/gl/GLContextTypes.h +++ b/gfx/gl/GLContextTypes.h @@ -43,19 +43,6 @@ struct GLFormats GLsizei samples; }; -struct PixelBufferFormat -{ - // Constructs a zeroed object: - PixelBufferFormat(); - - int red, green, blue; - int alpha; - int depth, stencil; - int samples; - - int ColorBits() const { return red + green + blue; } -}; - } /* namespace gl */ } /* namespace mozilla */ diff --git a/gfx/gl/GLLibraryEGL.cpp b/gfx/gl/GLLibraryEGL.cpp index a07b3e79f3df..40cee8d0c98d 100644 --- a/gfx/gl/GLLibraryEGL.cpp +++ b/gfx/gl/GLLibraryEGL.cpp @@ -35,8 +35,7 @@ static const char *sEGLExtensionNames[] = { "EGL_EXT_create_context_robustness", "EGL_KHR_image", "EGL_KHR_fence_sync", - "EGL_ANDROID_native_fence_sync", - nullptr + "EGL_ANDROID_native_fence_sync" }; #if defined(ANDROID) @@ -240,8 +239,8 @@ GLLibraryEGL::EnsureInitialized() }; // Do not warn about the failure to load this - see bug 1092191 - GLLibraryLoader::LoadSymbols(mEGLLibrary, &optionalSymbols[0], - nullptr, nullptr, false); + GLLibraryLoader::LoadSymbols(mEGLLibrary, &optionalSymbols[0], nullptr, nullptr, + false); #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 18 MOZ_RELEASE_ASSERT(mSymbols.fQueryStringImplementationANDROID, @@ -421,15 +420,24 @@ GLLibraryEGL::EnsureInitialized() void GLLibraryEGL::InitExtensions() { - const char *extensions = (const char*)fQueryString(mEGLDisplay, LOCAL_EGL_EXTENSIONS); + std::vector driverExtensionList; - if (!extensions) { + const char* rawExts = (const char*)fQueryString(mEGLDisplay, LOCAL_EGL_EXTENSIONS); + if (rawExts) { + nsDependentCString exts(rawExts); + SplitByChar(exts, ' ', &driverExtensionList); + } else { NS_WARNING("Failed to load EGL extension list!"); - return; } - GLContext::InitializeExtensionsBitSet(mAvailableExtensions, extensions, - sEGLExtensionNames); + const bool shouldDumpExts = GLContext::ShouldDumpExts(); + if (shouldDumpExts) { + printf_stderr("%i EGL driver extensions: (*: recognized)\n", + (uint32_t)driverExtensionList.size()); + } + + MarkBitfieldByStrings(driverExtensionList, shouldDumpExts, sEGLExtensionNames, + &mAvailableExtensions); } void diff --git a/gfx/gl/GLLibraryEGL.h b/gfx/gl/GLLibraryEGL.h index 1d175a217efe..4e055344c8f5 100644 --- a/gfx/gl/GLLibraryEGL.h +++ b/gfx/gl/GLLibraryEGL.h @@ -15,6 +15,7 @@ #include "GeckoProfiler.h" #include +#include #if defined(XP_WIN) diff --git a/gfx/layers/GLImages.cpp b/gfx/layers/GLImages.cpp index 66fa218df961..7525eefd40fa 100644 --- a/gfx/layers/GLImages.cpp +++ b/gfx/layers/GLImages.cpp @@ -39,7 +39,7 @@ GLImage::GetAsSourceSurface() MOZ_ASSERT(NS_IsMainThread(), "Should be on the main thread"); if (!sSnapshotContext) { - sSnapshotContext = GLContextProvider::CreateHeadless(); + sSnapshotContext = GLContextProvider::CreateHeadless(false); if (!sSnapshotContext) { NS_WARNING("Failed to create snapshot GLContext"); return nullptr; diff --git a/gfx/layers/opengl/CompositorOGL.cpp b/gfx/layers/opengl/CompositorOGL.cpp index ec7a9f3325f4..4e8b7bd8c5b2 100644 --- a/gfx/layers/opengl/CompositorOGL.cpp +++ b/gfx/layers/opengl/CompositorOGL.cpp @@ -124,8 +124,11 @@ CompositorOGL::CreateContext() SurfaceCaps caps = SurfaceCaps::ForRGB(); caps.preserve = false; caps.bpp16 = gfxPlatform::GetPlatform()->GetOffscreenFormat() == gfxImageFormat::RGB16_565; + + bool requireCompatProfile = true; context = GLContextProvider::CreateOffscreen(gfxIntSize(mSurfaceSize.width, - mSurfaceSize.height), caps); + mSurfaceSize.height), + caps, requireCompatProfile); } if (!context) diff --git a/gfx/tests/gtest/TestCompositor.cpp b/gfx/tests/gtest/TestCompositor.cpp index a8cf3c2674b9..8d17c650d57e 100644 --- a/gfx/tests/gtest/TestCompositor.cpp +++ b/gfx/tests/gtest/TestCompositor.cpp @@ -45,7 +45,7 @@ public: caps.preserve = false; caps.bpp16 = false; nsRefPtr context = GLContextProvider::CreateOffscreen( - gfxIntSize(gCompWidth, gCompHeight), caps); + gfxIntSize(gCompWidth, gCompHeight), caps, true); return context.forget().take(); } return nullptr; diff --git a/gfx/thebes/gfxPlatform.cpp b/gfx/thebes/gfxPlatform.cpp index 2e271cf3f52b..1394387fceba 100644 --- a/gfx/thebes/gfxPlatform.cpp +++ b/gfx/thebes/gfxPlatform.cpp @@ -1099,8 +1099,9 @@ gfxPlatform::GetSkiaGLGlue() * FIXME: This should be stored in TLS or something, since there needs to be one for each thread using it. As it * stands, this only works on the main thread. */ - mozilla::gl::SurfaceCaps caps = mozilla::gl::SurfaceCaps::ForRGBA(); - nsRefPtr glContext = mozilla::gl::GLContextProvider::CreateOffscreen(gfxIntSize(16, 16), caps); + bool requireCompatProfile = true; + nsRefPtr glContext; + glContext = mozilla::gl::GLContextProvider::CreateHeadless(requireCompatProfile); if (!glContext) { printf_stderr("Failed to create GLContext for SkiaGL!\n"); return nullptr; diff --git a/widget/android/GfxInfo.cpp b/widget/android/GfxInfo.cpp index 4ab9da311ede..95bd0d409cd8 100644 --- a/widget/android/GfxInfo.cpp +++ b/widget/android/GfxInfo.cpp @@ -72,8 +72,8 @@ public: } nsRefPtr gl; - gl = gl::GLContextProvider::CreateOffscreen(gfxIntSize(16, 16), - gl::SurfaceCaps::ForRGB()); + bool requireCompatProfile = true; + gl = gl::GLContextProvider::CreateHeadless(requireCompatProfile); if (!gl) { // Setting mReady to true here means that we won't retry. Everything will