Bumping manifests a=b2g-bump
[gecko.git] / gfx / gl / GLContextProviderCGL.mm
blob3492e4ab4eacacee8b931062a1057726257e40e5
1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
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 "GLContextCGL.h"
8 #include "TextureImageCGL.h"
9 #include "nsDebug.h"
10 #include "nsIWidget.h"
11 #include <OpenGL/gl.h>
12 #include "gfxPrefs.h"
13 #include "gfxFailure.h"
14 #include "prenv.h"
15 #include "mozilla/Preferences.h"
16 #include "GeckoProfiler.h"
17 #include "mozilla/gfx/MacIOSurface.h"
19 namespace mozilla {
20 namespace gl {
22 using namespace mozilla::gfx;
24 static bool gUseDoubleBufferedWindows = true;
26 class CGLLibrary
28 public:
29     CGLLibrary()
30       : mInitialized(false),
31         mOGLLibrary(nullptr),
32         mPixelFormat(nullptr)
33     { }
35     bool EnsureInitialized()
36     {
37         if (mInitialized) {
38             return true;
39         }
40         if (!mOGLLibrary) {
41             mOGLLibrary = PR_LoadLibrary("/System/Library/Frameworks/OpenGL.framework/OpenGL");
42             if (!mOGLLibrary) {
43                 NS_WARNING("Couldn't load OpenGL Framework.");
44                 return false;
45             }
46         }
48         const char* db = PR_GetEnv("MOZ_CGL_DB");
49         gUseDoubleBufferedWindows = (!db || *db != '0');
51         mInitialized = true;
52         return true;
53     }
55     NSOpenGLPixelFormat *PixelFormat()
56     {
57         if (mPixelFormat == nullptr) {
58             NSOpenGLPixelFormatAttribute attribs[] = {
59                 NSOpenGLPFAAccelerated,
60                 NSOpenGLPFAAllowOfflineRenderers,
61                 NSOpenGLPFADoubleBuffer,
62                 0
63             };
65             if (!gUseDoubleBufferedWindows) {
66               attribs[2] = 0;
67             }
69             mPixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];
70         }
72         return mPixelFormat;
73     }
74 private:
75     bool mInitialized;
76     PRLibrary *mOGLLibrary;
77     NSOpenGLPixelFormat *mPixelFormat;
80 CGLLibrary sCGLLibrary;
82 GLContextCGL::GLContextCGL(
83                   const SurfaceCaps& caps,
84                   GLContext *shareContext,
85                   NSOpenGLContext *context,
86                   bool isOffscreen)
87     : GLContext(caps, shareContext, isOffscreen),
88       mContext(context)
90     SetProfileVersion(ContextProfile::OpenGLCompatibility, 210);
93 GLContextCGL::~GLContextCGL()
95     MarkDestroyed();
97     if (mContext) {
98         if ([NSOpenGLContext currentContext] == mContext) {
99             // Clear the current context before releasing. If we don't do
100             // this, the next time we call [NSOpenGLContext currentContext],
101             // "invalid context" will be printed to the console.
102             [NSOpenGLContext clearCurrentContext];
103         }
104         [mContext release];
105     }
109 bool
110 GLContextCGL::Init()
112     if (!InitWithPrefix("gl", true))
113         return false;
115     return true;
118 CGLContextObj
119 GLContextCGL::GetCGLContext() const
121     return static_cast<CGLContextObj>([mContext CGLContextObj]);
124 bool
125 GLContextCGL::MakeCurrentImpl(bool aForce)
127     if (!aForce && [NSOpenGLContext currentContext] == mContext) {
128         return true;
129     }
131     if (mContext) {
132         [mContext makeCurrentContext];
133         // Use non-blocking swap in "ASAP mode".
134         // ASAP mode means that rendering is iterated as fast as possible.
135         // ASAP mode is entered when layout.frame_rate=0 (requires restart).
136         // If swapInt is 1, then glSwapBuffers will block and wait for a vblank signal.
137         // When we're iterating as fast as possible, however, we want a non-blocking
138         // glSwapBuffers, which will happen when swapInt==0.
139         GLint swapInt = gfxPrefs::LayoutFrameRate() == 0 ? 0 : 1;
140         [mContext setValues:&swapInt forParameter:NSOpenGLCPSwapInterval];
141     }
142     return true;
145 bool
146 GLContextCGL::IsCurrent() {
147     return [NSOpenGLContext currentContext] == mContext;
150 GLenum
151 GLContextCGL::GetPreferredARGB32Format() const
153     return LOCAL_GL_BGRA;
156 bool
157 GLContextCGL::SetupLookupFunction()
159     return false;
162 bool
163 GLContextCGL::IsDoubleBuffered() const
165   return gUseDoubleBufferedWindows;
168 bool
169 GLContextCGL::SupportsRobustness() const
171     return false;
174 bool
175 GLContextCGL::SwapBuffers()
177   PROFILER_LABEL("GLContextCGL", "SwapBuffers",
178     js::ProfileEntry::Category::GRAPHICS);
180   [mContext flushBuffer];
181   return true;
185 static GLContextCGL *
186 GetGlobalContextCGL()
188     return static_cast<GLContextCGL*>(GLContextProviderCGL::GetGlobalContext());
191 already_AddRefed<GLContext>
192 GLContextProviderCGL::CreateWrappingExisting(void*, void*)
194     return nullptr;
197 already_AddRefed<GLContext>
198 GLContextProviderCGL::CreateForWindow(nsIWidget *aWidget)
200     GLContextCGL *shareContext = GetGlobalContextCGL();
202     NSOpenGLContext *context = [[NSOpenGLContext alloc]
203                                 initWithFormat:sCGLLibrary.PixelFormat()
204                                 shareContext:(shareContext ? shareContext->mContext : NULL)];
205     if (!context) {
206         return nullptr;
207     }
209     // make the context transparent
210     GLint opaque = 0;
211     [context setValues:&opaque forParameter:NSOpenGLCPSurfaceOpacity];
213     SurfaceCaps caps = SurfaceCaps::ForRGBA();
214     nsRefPtr<GLContextCGL> glContext = new GLContextCGL(caps,
215                                                         shareContext,
216                                                         context);
217     if (!glContext->Init()) {
218         return nullptr;
219     }
221     return glContext.forget();
224 static already_AddRefed<GLContextCGL>
225 CreateOffscreenFBOContext(bool aShare = true)
227     if (!sCGLLibrary.EnsureInitialized()) {
228         return nullptr;
229     }
231     GLContextCGL *shareContext = aShare ? GetGlobalContextCGL() : nullptr;
232     if (aShare && !shareContext) {
233         // if there is no share context, then we can't use FBOs.
234         return nullptr;
235     }
237     NSOpenGLContext *context = [[NSOpenGLContext alloc]
238                                 initWithFormat:sCGLLibrary.PixelFormat()
239                                 shareContext:shareContext ? shareContext->GetNSOpenGLContext() : NULL];
240     if (!context) {
241         return nullptr;
242     }
244     SurfaceCaps dummyCaps = SurfaceCaps::Any();
245     nsRefPtr<GLContextCGL> glContext = new GLContextCGL(dummyCaps, shareContext, context, true);
247     return glContext.forget();
250 already_AddRefed<GLContext>
251 GLContextProviderCGL::CreateHeadless()
253     nsRefPtr<GLContextCGL> glContext = CreateOffscreenFBOContext();
254     if (!glContext)
255         return nullptr;
257     if (!glContext->Init())
258         return nullptr;
260     return glContext.forget();
263 already_AddRefed<GLContext>
264 GLContextProviderCGL::CreateOffscreen(const gfxIntSize& size,
265                                       const SurfaceCaps& caps)
267     nsRefPtr<GLContext> glContext = CreateHeadless();
268     if (!glContext->InitOffscreen(ToIntSize(size), caps))
269         return nullptr;
271     return glContext.forget();
274 static nsRefPtr<GLContext> gGlobalContext;
276 GLContext*
277 GLContextProviderCGL::GetGlobalContext()
279     if (!sCGLLibrary.EnsureInitialized()) {
280         return nullptr;
281     }
283     if (!gGlobalContext) {
284         // There are bugs in some older drivers with pbuffers less
285         // than 16x16 in size; also 16x16 is POT so that we can do
286         // a FBO with it on older video cards.  A FBO context for
287         // sharing is preferred since it has no associated target.
288         gGlobalContext = CreateOffscreenFBOContext(false);
289         if (!gGlobalContext || !static_cast<GLContextCGL*>(gGlobalContext.get())->Init()) {
290             NS_WARNING("Couldn't init gGlobalContext.");
291             gGlobalContext = nullptr;
292             return nullptr;
293         }
294     }
296     return gGlobalContext;
299 void
300 GLContextProviderCGL::Shutdown()
302   gGlobalContext = nullptr;
305 } /* namespace gl */
306 } /* namespace mozilla */