Bug 1800456 - Add failIfNot function to reftest-wait.js, r=emilio
[gecko.git] / gfx / gl / GLContextProviderEAGL.mm
blob4aabe89df1def048206b59e6e8c436bccd4e2900
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 "nsDebug.h"
9 #include "nsIWidget.h"
10 #include "gfxFailure.h"
11 #include "prenv.h"
12 #include "mozilla/Preferences.h"
13 #include "mozilla/ProfilerLabels.h"
14 #include "mozilla/layers/CompositorOptions.h"
15 #include "mozilla/widget/CompositorWidget.h"
17 #import <UIKit/UIKit.h>
19 namespace mozilla {
20 namespace gl {
22 using namespace mozilla::widget;
24 GLContextEAGL::GLContextEAGL(const GLContextDesc& desc, EAGLContext* context,
25                              GLContext* sharedContext)
26     : GLContext(desc, sharedContext), mContext(context) {}
28 GLContextEAGL::~GLContextEAGL() {
29   MakeCurrent();
31   if (mBackbufferFB) {
32     fDeleteFramebuffers(1, &mBackbufferFB);
33   }
35   if (mBackbufferRB) {
36     fDeleteRenderbuffers(1, &mBackbufferRB);
37   }
39   MarkDestroyed();
41   if (mLayer) {
42     mLayer = nil;
43   }
45   if (mContext) {
46     [EAGLContext setCurrentContext:nil];
47     [mContext release];
48   }
51 bool GLContextEAGL::AttachToWindow(nsIWidget* aWidget) {
52   // This should only be called once
53   MOZ_ASSERT(!mBackbufferFB && !mBackbufferRB);
55   UIView* view = reinterpret_cast<UIView*>(aWidget->GetNativeData(NS_NATIVE_WIDGET));
57   if (!view) {
58     MOZ_CRASH("no view!");
59   }
61   mLayer = [view layer];
63   fGenFramebuffers(1, &mBackbufferFB);
64   return RecreateRB();
67 bool GLContextEAGL::RecreateRB() {
68   MakeCurrent();
70   CAEAGLLayer* layer = (CAEAGLLayer*)mLayer;
72   if (mBackbufferRB) {
73     // It doesn't seem to be enough to just call renderbufferStorage: below,
74     // we apparently have to recreate the RB.
75     fDeleteRenderbuffers(1, &mBackbufferRB);
76     mBackbufferRB = 0;
77   }
79   fGenRenderbuffers(1, &mBackbufferRB);
80   fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, mBackbufferRB);
82   [mContext renderbufferStorage:LOCAL_GL_RENDERBUFFER fromDrawable:layer];
84   fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mBackbufferFB);
85   fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0, LOCAL_GL_RENDERBUFFER,
86                            mBackbufferRB);
88   return LOCAL_GL_FRAMEBUFFER_COMPLETE == fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
91 bool GLContextEAGL::MakeCurrentImpl() const {
92   if (mContext) {
93     if (![EAGLContext setCurrentContext:mContext]) {
94       return false;
95     }
96   }
97   return true;
100 bool GLContextEAGL::IsCurrentImpl() const { return [EAGLContext currentContext] == mContext; }
102 static PRFuncPtr GLAPIENTRY GetLoadedProcAddress(const char* const name) {
103   PRLibrary* lib = nullptr;
104   const auto& ret = PR_FindFunctionSymbolAndLibrary(name, &leakedLibRef);
105   if (lib) {
106     PR_UnloadLibrary(lib);
107   }
108   return ret;
111 Maybe<SymbolLoader> GLContextEAGL::GetSymbolLoader() const {
112   return Some(SymbolLoader(&GetLoadedProcAddress));
115 bool GLContextEAGL::IsDoubleBuffered() const { return true; }
117 bool GLContextEAGL::SwapBuffers() {
118   AUTO_PROFILER_LABEL("GLContextEAGL::SwapBuffers", GRAPHICS);
120   [mContext presentRenderbuffer:LOCAL_GL_RENDERBUFFER];
121   return true;
124 void GLContextEAGL::GetWSIInfo(nsCString* const out) const { out->AppendLiteral("EAGL"); }
126 static GLContextEAGL* GetGlobalContextEAGL() {
127   return static_cast<GLContextEAGL*>(GLContextProviderEAGL::GetGlobalContext());
130 static RefPtr<GLContext> CreateEAGLContext(const GLContextDesc& desc,
131                                            GLContextEAGL* sharedContext) {
132   EAGLRenderingAPI apis[] = {kEAGLRenderingAPIOpenGLES3, kEAGLRenderingAPIOpenGLES2};
134   // Try to create a GLES3 context if we can, otherwise fall back to GLES2
135   EAGLContext* context = nullptr;
136   for (EAGLRenderingAPI api : apis) {
137     if (sharedContext) {
138       context = [[EAGLContext alloc] initWithAPI:api
139                                       sharegroup:sharedContext->GetEAGLContext().sharegroup];
140     } else {
141       context = [[EAGLContext alloc] initWithAPI:api];
142     }
144     if (context) {
145       break;
146     }
147   }
149   if (!context) {
150     return nullptr;
151   }
153   RefPtr<GLContextEAGL> glContext = new GLContextEAGL(desc, context, sharedContext);
154   if (!glContext->Init()) {
155     glContext = nullptr;
156     return nullptr;
157   }
159   return glContext;
162 already_AddRefed<GLContext> GLContextProviderEAGL::CreateForCompositorWidget(
163     CompositorWidget* aCompositorWidget, bool aHardwareWebRender, bool aForceAccelerated) {
164   if (!aCompositorWidget) {
165     MOZ_ASSERT(false);
166     return nullptr;
167   }
169   const GLContextDesc desc = {};
170   auto glContext = CreateEAGLContext(desc, GetGlobalContextEAGL());
171   if (!glContext) {
172     return nullptr;
173   }
175   if (!GLContextEAGL::Cast(glContext)->AttachToWindow(aCompositorWidget->RealWidget())) {
176     return nullptr;
177   }
179   return glContext.forget();
182 already_AddRefed<GLContext> GLContextProviderEAGL::CreateHeadless(
183     const GLContextCreateDesc& createDesc, nsACString* const out_failureId) {
184   auto desc = GLContextDesc{createDesc};
185   desc.isOffcreen = true;
186   return CreateEAGLContext(desc, GetGlobalContextEAGL()).forget();
189 static RefPtr<GLContext> gGlobalContext;
191 GLContext* GLContextProviderEAGL::GetGlobalContext() {
192   static bool triedToCreateContext = false;
193   if (!triedToCreateContext) {
194     triedToCreateContext = true;
196     MOZ_RELEASE_ASSERT(!gGlobalContext, "GFX: Global GL context already initialized.");
197     RefPtr<GLContext> temp = CreateHeadless(CreateContextFlags::NONE);
198     gGlobalContext = temp;
200     if (!gGlobalContext) {
201       MOZ_CRASH("Failed to create global context");
202     }
203   }
205   return gGlobalContext;
208 void GLContextProviderEAGL::Shutdown() { gGlobalContext = nullptr; }
210 } /* namespace gl */
211 } /* namespace mozilla */