1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "GLContextProvider.h"
7 #include "GLContextEAGL.h"
8 #include "GLLibraryLoader.h"
10 #include "nsIWidget.h"
11 #include "gfxFailure.h"
13 #include "mozilla/Preferences.h"
14 #include "mozilla/ProfilerLabels.h"
15 #include "mozilla/layers/CompositorOptions.h"
16 #include "mozilla/widget/CompositorWidget.h"
18 #import <UIKit/UIKit.h>
23 using namespace mozilla::widget;
25 GLContextEAGL::GLContextEAGL(const GLContextDesc& desc, EAGLContext* context,
26 GLContext* sharedContext)
27 : GLContext(desc, sharedContext), mContext(context) {}
29 GLContextEAGL::~GLContextEAGL() {
33 fDeleteFramebuffers(1, &mBackbufferFB);
37 fDeleteRenderbuffers(1, &mBackbufferRB);
47 [EAGLContext setCurrentContext:nil];
52 bool GLContextEAGL::AttachToWindow(nsIWidget* aWidget) {
53 // This should only be called once
54 MOZ_ASSERT(!mBackbufferFB && !mBackbufferRB);
57 reinterpret_cast<UIView*>(aWidget->GetNativeData(NS_NATIVE_WIDGET));
60 MOZ_CRASH("no view!");
63 mLayer = [view layer];
65 fGenFramebuffers(1, &mBackbufferFB);
69 bool GLContextEAGL::RecreateRB() {
72 CAEAGLLayer* layer = (CAEAGLLayer*)mLayer;
75 // It doesn't seem to be enough to just call renderbufferStorage: below,
76 // we apparently have to recreate the RB.
77 fDeleteRenderbuffers(1, &mBackbufferRB);
81 fGenRenderbuffers(1, &mBackbufferRB);
82 fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, mBackbufferRB);
84 [mContext renderbufferStorage:LOCAL_GL_RENDERBUFFER fromDrawable:layer];
86 fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mBackbufferFB);
87 fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0,
88 LOCAL_GL_RENDERBUFFER, mBackbufferRB);
90 return LOCAL_GL_FRAMEBUFFER_COMPLETE ==
91 fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
94 bool GLContextEAGL::MakeCurrentImpl() const {
96 GLContext::ResetTLSCurrentContext();
98 if (![EAGLContext setCurrentContext:mContext]) {
105 bool GLContextEAGL::IsCurrentImpl() const {
106 return [EAGLContext currentContext] == mContext;
109 static PRFuncPtr GLAPIENTRY GetLoadedProcAddress(const char* const name) {
110 PRLibrary* lib = nullptr;
111 const auto& ret = PR_FindFunctionSymbolAndLibrary(name, &lib);
113 PR_UnloadLibrary(lib);
118 Maybe<SymbolLoader> GLContextEAGL::GetSymbolLoader() const {
119 return Some(SymbolLoader(&GetLoadedProcAddress));
122 bool GLContextEAGL::IsDoubleBuffered() const { return true; }
124 bool GLContextEAGL::SwapBuffers() {
125 AUTO_PROFILER_LABEL("GLContextEAGL::SwapBuffers", GRAPHICS);
127 [mContext presentRenderbuffer:LOCAL_GL_RENDERBUFFER];
131 void GLContextEAGL::GetWSIInfo(nsCString* const out) const {
132 out->AppendLiteral("EAGL");
135 static GLContextEAGL* GetGlobalContextEAGL() {
136 return static_cast<GLContextEAGL*>(GLContextProviderEAGL::GetGlobalContext());
139 static RefPtr<GLContext> CreateEAGLContext(const GLContextDesc& desc,
140 GLContextEAGL* sharedContext) {
141 EAGLRenderingAPI apis[] = {kEAGLRenderingAPIOpenGLES3,
142 kEAGLRenderingAPIOpenGLES2};
144 // Try to create a GLES3 context if we can, otherwise fall back to GLES2
145 EAGLContext* context = nullptr;
146 for (EAGLRenderingAPI api : apis) {
148 context = [[EAGLContext alloc]
150 sharegroup:sharedContext->GetEAGLContext().sharegroup];
152 context = [[EAGLContext alloc] initWithAPI:api];
164 RefPtr<GLContextEAGL> glContext =
165 new GLContextEAGL(desc, context, sharedContext);
166 if (!glContext->Init()) {
174 already_AddRefed<GLContext> GLContextProviderEAGL::CreateForCompositorWidget(
175 CompositorWidget* aCompositorWidget, bool aHardwareWebRender,
176 bool aForceAccelerated) {
177 if (!aCompositorWidget) {
182 const GLContextDesc desc = {};
183 auto glContext = CreateEAGLContext(desc, GetGlobalContextEAGL());
188 if (!GLContextEAGL::Cast(glContext)->AttachToWindow(
189 aCompositorWidget->RealWidget())) {
193 return glContext.forget();
196 already_AddRefed<GLContext> GLContextProviderEAGL::CreateHeadless(
197 const GLContextCreateDesc& createDesc, nsACString* const out_failureId) {
198 auto desc = GLContextDesc{createDesc};
199 desc.isOffscreen = true;
200 return CreateEAGLContext(desc, GetGlobalContextEAGL()).forget();
203 static RefPtr<GLContext> gGlobalContext;
205 GLContext* GLContextProviderEAGL::GetGlobalContext() {
206 static bool triedToCreateContext = false;
207 if (!triedToCreateContext) {
208 triedToCreateContext = true;
210 MOZ_RELEASE_ASSERT(!gGlobalContext,
211 "GFX: Global GL context already initialized.");
212 nsCString discardFailureId;
213 RefPtr<GLContext> temp = CreateHeadless({}, &discardFailureId);
214 gGlobalContext = temp;
216 if (!gGlobalContext) {
217 MOZ_CRASH("Failed to create global context");
221 return gGlobalContext;
224 void GLContextProviderEAGL::Shutdown() { gGlobalContext = nullptr; }
227 } /* namespace mozilla */