Bug 1883287 - Don't wait for the hidden window to be created on Linux to load the...
[gecko.git] / gfx / gl / GLContextProviderEAGL.mm
blobcfba0300002fa3c378a6708e266a031ee9e6ac56
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"
9 #include "nsDebug.h"
10 #include "nsIWidget.h"
11 #include "gfxFailure.h"
12 #include "prenv.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>
20 namespace mozilla {
21 namespace gl {
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() {
30   MakeCurrent();
32   if (mBackbufferFB) {
33     fDeleteFramebuffers(1, &mBackbufferFB);
34   }
36   if (mBackbufferRB) {
37     fDeleteRenderbuffers(1, &mBackbufferRB);
38   }
40   MarkDestroyed();
42   if (mLayer) {
43     mLayer = nil;
44   }
46   if (mContext) {
47     [EAGLContext setCurrentContext:nil];
48     [mContext release];
49   }
52 bool GLContextEAGL::AttachToWindow(nsIWidget* aWidget) {
53   // This should only be called once
54   MOZ_ASSERT(!mBackbufferFB && !mBackbufferRB);
56   UIView* view =
57       reinterpret_cast<UIView*>(aWidget->GetNativeData(NS_NATIVE_WIDGET));
59   if (!view) {
60     MOZ_CRASH("no view!");
61   }
63   mLayer = [view layer];
65   fGenFramebuffers(1, &mBackbufferFB);
66   return RecreateRB();
69 bool GLContextEAGL::RecreateRB() {
70   MakeCurrent();
72   CAEAGLLayer* layer = (CAEAGLLayer*)mLayer;
74   if (mBackbufferRB) {
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);
78     mBackbufferRB = 0;
79   }
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 {
95   if (mContext) {
96     GLContext::ResetTLSCurrentContext();
98     if (![EAGLContext setCurrentContext:mContext]) {
99       return false;
100     }
101   }
102   return true;
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);
112   if (lib) {
113     PR_UnloadLibrary(lib);
114   }
115   return ret;
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];
128   return true;
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) {
147     if (sharedContext) {
148       context = [[EAGLContext alloc]
149           initWithAPI:api
150            sharegroup:sharedContext->GetEAGLContext().sharegroup];
151     } else {
152       context = [[EAGLContext alloc] initWithAPI:api];
153     }
155     if (context) {
156       break;
157     }
158   }
160   if (!context) {
161     return nullptr;
162   }
164   RefPtr<GLContextEAGL> glContext =
165       new GLContextEAGL(desc, context, sharedContext);
166   if (!glContext->Init()) {
167     glContext = nullptr;
168     return nullptr;
169   }
171   return glContext;
174 already_AddRefed<GLContext> GLContextProviderEAGL::CreateForCompositorWidget(
175     CompositorWidget* aCompositorWidget, bool aHardwareWebRender,
176     bool aForceAccelerated) {
177   if (!aCompositorWidget) {
178     MOZ_ASSERT(false);
179     return nullptr;
180   }
182   const GLContextDesc desc = {};
183   auto glContext = CreateEAGLContext(desc, GetGlobalContextEAGL());
184   if (!glContext) {
185     return nullptr;
186   }
188   if (!GLContextEAGL::Cast(glContext)->AttachToWindow(
189           aCompositorWidget->RealWidget())) {
190     return nullptr;
191   }
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");
218     }
219   }
221   return gGlobalContext;
224 void GLContextProviderEAGL::Shutdown() { gGlobalContext = nullptr; }
226 } /* namespace gl */
227 } /* namespace mozilla */