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"
10 #include "nsIWidget.h"
11 #include <OpenGL/gl.h>
13 #include "gfxFailure.h"
15 #include "mozilla/Preferences.h"
16 #include "GeckoProfiler.h"
17 #include "mozilla/gfx/MacIOSurface.h"
22 using namespace mozilla::gfx;
24 static bool gUseDoubleBufferedWindows = true;
30 : mInitialized(false),
35 bool EnsureInitialized()
41 mOGLLibrary = PR_LoadLibrary("/System/Library/Frameworks/OpenGL.framework/OpenGL");
43 NS_WARNING("Couldn't load OpenGL Framework.");
48 const char* db = PR_GetEnv("MOZ_CGL_DB");
49 gUseDoubleBufferedWindows = (!db || *db != '0');
55 NSOpenGLPixelFormat *PixelFormat()
57 if (mPixelFormat == nullptr) {
58 NSOpenGLPixelFormatAttribute attribs[] = {
59 NSOpenGLPFAAccelerated,
60 NSOpenGLPFAAllowOfflineRenderers,
61 NSOpenGLPFADoubleBuffer,
65 if (!gUseDoubleBufferedWindows) {
69 mPixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];
76 PRLibrary *mOGLLibrary;
77 NSOpenGLPixelFormat *mPixelFormat;
80 CGLLibrary sCGLLibrary;
82 GLContextCGL::GLContextCGL(
83 const SurfaceCaps& caps,
84 GLContext *shareContext,
85 NSOpenGLContext *context,
87 : GLContext(caps, shareContext, isOffscreen),
90 SetProfileVersion(ContextProfile::OpenGLCompatibility, 210);
93 GLContextCGL::~GLContextCGL()
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];
112 if (!InitWithPrefix("gl", true))
119 GLContextCGL::GetCGLContext() const
121 return static_cast<CGLContextObj>([mContext CGLContextObj]);
125 GLContextCGL::MakeCurrentImpl(bool aForce)
127 if (!aForce && [NSOpenGLContext currentContext] == 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];
146 GLContextCGL::IsCurrent() {
147 return [NSOpenGLContext currentContext] == mContext;
151 GLContextCGL::GetPreferredARGB32Format() const
153 return LOCAL_GL_BGRA;
157 GLContextCGL::SetupLookupFunction()
163 GLContextCGL::IsDoubleBuffered() const
165 return gUseDoubleBufferedWindows;
169 GLContextCGL::SupportsRobustness() const
175 GLContextCGL::SwapBuffers()
177 PROFILER_LABEL("GLContextCGL", "SwapBuffers",
178 js::ProfileEntry::Category::GRAPHICS);
180 [mContext flushBuffer];
185 static GLContextCGL *
186 GetGlobalContextCGL()
188 return static_cast<GLContextCGL*>(GLContextProviderCGL::GetGlobalContext());
191 already_AddRefed<GLContext>
192 GLContextProviderCGL::CreateWrappingExisting(void*, void*)
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)];
209 // make the context transparent
211 [context setValues:&opaque forParameter:NSOpenGLCPSurfaceOpacity];
213 SurfaceCaps caps = SurfaceCaps::ForRGBA();
214 nsRefPtr<GLContextCGL> glContext = new GLContextCGL(caps,
217 if (!glContext->Init()) {
221 return glContext.forget();
224 static already_AddRefed<GLContextCGL>
225 CreateOffscreenFBOContext(bool aShare = true)
227 if (!sCGLLibrary.EnsureInitialized()) {
231 GLContextCGL *shareContext = aShare ? GetGlobalContextCGL() : nullptr;
232 if (aShare && !shareContext) {
233 // if there is no share context, then we can't use FBOs.
237 NSOpenGLContext *context = [[NSOpenGLContext alloc]
238 initWithFormat:sCGLLibrary.PixelFormat()
239 shareContext:shareContext ? shareContext->GetNSOpenGLContext() : NULL];
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();
257 if (!glContext->Init())
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))
271 return glContext.forget();
274 static nsRefPtr<GLContext> gGlobalContext;
277 GLContextProviderCGL::GetGlobalContext()
279 if (!sCGLLibrary.EnsureInitialized()) {
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;
296 return gGlobalContext;
300 GLContextProviderCGL::Shutdown()
302 gGlobalContext = nullptr;
306 } /* namespace mozilla */