/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- * 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 "GLContextProvider.h" #include "GLContextEAGL.h" #include "GLLibraryLoader.h" #include "nsDebug.h" #include "nsIWidget.h" #include "gfxFailure.h" #include "prenv.h" #include "mozilla/Preferences.h" #include "mozilla/ProfilerLabels.h" #include "mozilla/layers/CompositorOptions.h" #include "mozilla/widget/CompositorWidget.h" #import namespace mozilla { namespace gl { using namespace mozilla::widget; GLContextEAGL::GLContextEAGL(const GLContextDesc& desc, EAGLContext* context, GLContext* sharedContext) : GLContext(desc, sharedContext), mContext(context) {} GLContextEAGL::~GLContextEAGL() { MakeCurrent(); if (mBackbufferFB) { fDeleteFramebuffers(1, &mBackbufferFB); } if (mBackbufferRB) { fDeleteRenderbuffers(1, &mBackbufferRB); } MarkDestroyed(); if (mContext) { [EAGLContext setCurrentContext:nil]; [mContext release]; } } bool GLContextEAGL::MakeCurrentImpl() const { if (mContext) { GLContext::ResetTLSCurrentContext(); if (![EAGLContext setCurrentContext:mContext]) { return false; } } return true; } bool GLContextEAGL::IsCurrentImpl() const { return [EAGLContext currentContext] == mContext; } static PRFuncPtr GLAPIENTRY GetLoadedProcAddress(const char* const name) { PRLibrary* lib = nullptr; const auto& ret = PR_FindFunctionSymbolAndLibrary(name, &lib); if (lib) { PR_UnloadLibrary(lib); } return ret; } Maybe GLContextEAGL::GetSymbolLoader() const { return Some(SymbolLoader(&GetLoadedProcAddress)); } bool GLContextEAGL::IsDoubleBuffered() const { return true; } bool GLContextEAGL::SwapBuffers() { AUTO_PROFILER_LABEL("GLContextEAGL::SwapBuffers", GRAPHICS); [mContext presentRenderbuffer:LOCAL_GL_RENDERBUFFER]; return true; } void GLContextEAGL::GetWSIInfo(nsCString* const out) const { out->AppendLiteral("EAGL"); } static GLContextEAGL* GetGlobalContextEAGL() { return static_cast(GLContextProviderEAGL::GetGlobalContext()); } static RefPtr CreateEAGLContext(const GLContextDesc& desc, GLContextEAGL* sharedContext) { EAGLRenderingAPI apis[] = {kEAGLRenderingAPIOpenGLES3, kEAGLRenderingAPIOpenGLES2}; // Try to create a GLES3 context if we can, otherwise fall back to GLES2 EAGLContext* context = nullptr; for (EAGLRenderingAPI api : apis) { if (sharedContext) { context = [[EAGLContext alloc] initWithAPI:api sharegroup:sharedContext->GetEAGLContext().sharegroup]; } else { context = [[EAGLContext alloc] initWithAPI:api]; } if (context) { break; } } if (!context) { return nullptr; } RefPtr glContext = new GLContextEAGL(desc, context, sharedContext); if (!glContext->Init()) { glContext = nullptr; return nullptr; } return glContext; } already_AddRefed GLContextProviderEAGL::CreateForCompositorWidget( CompositorWidget* aCompositorWidget, bool aHardwareWebRender, bool aForceAccelerated) { CreateContextFlags flags = CreateContextFlags::ALLOW_OFFLINE_RENDERER; if (aForceAccelerated) { flags |= CreateContextFlags::FORBID_SOFTWARE; } nsCString failureUnused; return CreateHeadless({flags}, &failureUnused); } already_AddRefed GLContextProviderEAGL::CreateHeadless( const GLContextCreateDesc& createDesc, nsACString* const out_failureId) { auto desc = GLContextDesc{createDesc}; return CreateEAGLContext(desc, GetGlobalContextEAGL()).forget(); } static RefPtr gGlobalContext; GLContext* GLContextProviderEAGL::GetGlobalContext() { static bool triedToCreateContext = false; if (!triedToCreateContext) { triedToCreateContext = true; MOZ_RELEASE_ASSERT(!gGlobalContext, "GFX: Global GL context already initialized."); nsCString discardFailureId; RefPtr temp = CreateHeadless({}, &discardFailureId); gGlobalContext = temp; if (!gGlobalContext) { MOZ_CRASH("Failed to create global context"); } } return gGlobalContext; } void GLContextProviderEAGL::Shutdown() { gGlobalContext = nullptr; } } /* namespace gl */ } /* namespace mozilla */