1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/gl/GLContextProviderCGL.mm Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,296 @@ 1.4 +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "GLContextProvider.h" 1.10 +#include "GLContextCGL.h" 1.11 +#include "TextureImageCGL.h" 1.12 +#include "nsDebug.h" 1.13 +#include "nsIWidget.h" 1.14 +#include <OpenGL/gl.h> 1.15 +#include "gfxPrefs.h" 1.16 +#include "gfxFailure.h" 1.17 +#include "prenv.h" 1.18 +#include "mozilla/Preferences.h" 1.19 +#include "GeckoProfiler.h" 1.20 +#include "mozilla/gfx/MacIOSurface.h" 1.21 + 1.22 +using namespace mozilla::gfx; 1.23 + 1.24 +namespace mozilla { 1.25 +namespace gl { 1.26 + 1.27 +static bool gUseDoubleBufferedWindows = true; 1.28 + 1.29 +class CGLLibrary 1.30 +{ 1.31 +public: 1.32 + CGLLibrary() 1.33 + : mInitialized(false), 1.34 + mOGLLibrary(nullptr), 1.35 + mPixelFormat(nullptr) 1.36 + { } 1.37 + 1.38 + bool EnsureInitialized() 1.39 + { 1.40 + if (mInitialized) { 1.41 + return true; 1.42 + } 1.43 + if (!mOGLLibrary) { 1.44 + mOGLLibrary = PR_LoadLibrary("/System/Library/Frameworks/OpenGL.framework/OpenGL"); 1.45 + if (!mOGLLibrary) { 1.46 + NS_WARNING("Couldn't load OpenGL Framework."); 1.47 + return false; 1.48 + } 1.49 + } 1.50 + 1.51 + const char* db = PR_GetEnv("MOZ_CGL_DB"); 1.52 + gUseDoubleBufferedWindows = (!db || *db != '0'); 1.53 + 1.54 + mInitialized = true; 1.55 + return true; 1.56 + } 1.57 + 1.58 + NSOpenGLPixelFormat *PixelFormat() 1.59 + { 1.60 + if (mPixelFormat == nullptr) { 1.61 + NSOpenGLPixelFormatAttribute attribs[] = { 1.62 + NSOpenGLPFAAccelerated, 1.63 + NSOpenGLPFAAllowOfflineRenderers, 1.64 + NSOpenGLPFADoubleBuffer, 1.65 + 0 1.66 + }; 1.67 + 1.68 + if (!gUseDoubleBufferedWindows) { 1.69 + attribs[2] = 0; 1.70 + } 1.71 + 1.72 + mPixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs]; 1.73 + } 1.74 + 1.75 + return mPixelFormat; 1.76 + } 1.77 +private: 1.78 + bool mInitialized; 1.79 + PRLibrary *mOGLLibrary; 1.80 + NSOpenGLPixelFormat *mPixelFormat; 1.81 +}; 1.82 + 1.83 +CGLLibrary sCGLLibrary; 1.84 + 1.85 +GLContextCGL::GLContextCGL( 1.86 + const SurfaceCaps& caps, 1.87 + GLContext *shareContext, 1.88 + NSOpenGLContext *context, 1.89 + bool isOffscreen) 1.90 + : GLContext(caps, shareContext, isOffscreen), 1.91 + mContext(context) 1.92 +{ 1.93 + SetProfileVersion(ContextProfile::OpenGLCompatibility, 210); 1.94 +} 1.95 + 1.96 +GLContextCGL::~GLContextCGL() 1.97 +{ 1.98 + MarkDestroyed(); 1.99 + 1.100 + if (mContext) { 1.101 + if ([NSOpenGLContext currentContext] == mContext) { 1.102 + // Clear the current context before releasing. If we don't do 1.103 + // this, the next time we call [NSOpenGLContext currentContext], 1.104 + // "invalid context" will be printed to the console. 1.105 + [NSOpenGLContext clearCurrentContext]; 1.106 + } 1.107 + [mContext release]; 1.108 + } 1.109 + 1.110 +} 1.111 + 1.112 +bool 1.113 +GLContextCGL::Init() 1.114 +{ 1.115 + if (!InitWithPrefix("gl", true)) 1.116 + return false; 1.117 + 1.118 + return true; 1.119 +} 1.120 + 1.121 +CGLContextObj 1.122 +GLContextCGL::GetCGLContext() const 1.123 +{ 1.124 + return static_cast<CGLContextObj>([mContext CGLContextObj]); 1.125 +} 1.126 + 1.127 +bool 1.128 +GLContextCGL::MakeCurrentImpl(bool aForce) 1.129 +{ 1.130 + if (!aForce && [NSOpenGLContext currentContext] == mContext) { 1.131 + return true; 1.132 + } 1.133 + 1.134 + if (mContext) { 1.135 + [mContext makeCurrentContext]; 1.136 + // Use non-blocking swap in "ASAP mode". 1.137 + // ASAP mode means that rendering is iterated as fast as possible. 1.138 + // ASAP mode is entered when layout.frame_rate=0 (requires restart). 1.139 + // If swapInt is 1, then glSwapBuffers will block and wait for a vblank signal. 1.140 + // When we're iterating as fast as possible, however, we want a non-blocking 1.141 + // glSwapBuffers, which will happen when swapInt==0. 1.142 + GLint swapInt = gfxPrefs::LayoutFrameRate() == 0 ? 0 : 1; 1.143 + [mContext setValues:&swapInt forParameter:NSOpenGLCPSwapInterval]; 1.144 + } 1.145 + return true; 1.146 +} 1.147 + 1.148 +bool 1.149 +GLContextCGL::IsCurrent() { 1.150 + return [NSOpenGLContext currentContext] == mContext; 1.151 +} 1.152 + 1.153 +GLenum 1.154 +GLContextCGL::GetPreferredARGB32Format() const 1.155 +{ 1.156 + return LOCAL_GL_BGRA; 1.157 +} 1.158 + 1.159 +bool 1.160 +GLContextCGL::SetupLookupFunction() 1.161 +{ 1.162 + return false; 1.163 +} 1.164 + 1.165 +bool 1.166 +GLContextCGL::IsDoubleBuffered() const 1.167 +{ 1.168 + return gUseDoubleBufferedWindows; 1.169 +} 1.170 + 1.171 +bool 1.172 +GLContextCGL::SupportsRobustness() const 1.173 +{ 1.174 + return false; 1.175 +} 1.176 + 1.177 +bool 1.178 +GLContextCGL::SwapBuffers() 1.179 +{ 1.180 + PROFILER_LABEL("GLContext", "SwapBuffers"); 1.181 + [mContext flushBuffer]; 1.182 + return true; 1.183 +} 1.184 + 1.185 + 1.186 +static GLContextCGL * 1.187 +GetGlobalContextCGL() 1.188 +{ 1.189 + return static_cast<GLContextCGL*>(GLContextProviderCGL::GetGlobalContext()); 1.190 +} 1.191 + 1.192 +already_AddRefed<GLContext> 1.193 +GLContextProviderCGL::CreateWrappingExisting(void*, void*) 1.194 +{ 1.195 + return nullptr; 1.196 +} 1.197 + 1.198 +already_AddRefed<GLContext> 1.199 +GLContextProviderCGL::CreateForWindow(nsIWidget *aWidget) 1.200 +{ 1.201 + GLContextCGL *shareContext = GetGlobalContextCGL(); 1.202 + 1.203 + NSOpenGLContext *context = [[NSOpenGLContext alloc] 1.204 + initWithFormat:sCGLLibrary.PixelFormat() 1.205 + shareContext:(shareContext ? shareContext->mContext : NULL)]; 1.206 + if (!context) { 1.207 + return nullptr; 1.208 + } 1.209 + 1.210 + // make the context transparent 1.211 + GLint opaque = 0; 1.212 + [context setValues:&opaque forParameter:NSOpenGLCPSurfaceOpacity]; 1.213 + 1.214 + SurfaceCaps caps = SurfaceCaps::ForRGBA(); 1.215 + nsRefPtr<GLContextCGL> glContext = new GLContextCGL(caps, 1.216 + shareContext, 1.217 + context); 1.218 + if (!glContext->Init()) { 1.219 + return nullptr; 1.220 + } 1.221 + 1.222 + return glContext.forget(); 1.223 +} 1.224 + 1.225 +static already_AddRefed<GLContextCGL> 1.226 +CreateOffscreenFBOContext(bool aShare = true) 1.227 +{ 1.228 + if (!sCGLLibrary.EnsureInitialized()) { 1.229 + return nullptr; 1.230 + } 1.231 + 1.232 + GLContextCGL *shareContext = aShare ? GetGlobalContextCGL() : nullptr; 1.233 + if (aShare && !shareContext) { 1.234 + // if there is no share context, then we can't use FBOs. 1.235 + return nullptr; 1.236 + } 1.237 + 1.238 + NSOpenGLContext *context = [[NSOpenGLContext alloc] 1.239 + initWithFormat:sCGLLibrary.PixelFormat() 1.240 + shareContext:shareContext ? shareContext->GetNSOpenGLContext() : NULL]; 1.241 + if (!context) { 1.242 + return nullptr; 1.243 + } 1.244 + 1.245 + SurfaceCaps dummyCaps = SurfaceCaps::Any(); 1.246 + nsRefPtr<GLContextCGL> glContext = new GLContextCGL(dummyCaps, shareContext, context, true); 1.247 + 1.248 + return glContext.forget(); 1.249 +} 1.250 + 1.251 +already_AddRefed<GLContext> 1.252 +GLContextProviderCGL::CreateOffscreen(const gfxIntSize& size, 1.253 + const SurfaceCaps& caps) 1.254 +{ 1.255 + nsRefPtr<GLContextCGL> glContext = CreateOffscreenFBOContext(); 1.256 + if (glContext && 1.257 + glContext->Init() && 1.258 + glContext->InitOffscreen(ToIntSize(size), caps)) 1.259 + { 1.260 + return glContext.forget(); 1.261 + } 1.262 + 1.263 + // everything failed 1.264 + return nullptr; 1.265 +} 1.266 + 1.267 +static nsRefPtr<GLContext> gGlobalContext; 1.268 + 1.269 +GLContext * 1.270 +GLContextProviderCGL::GetGlobalContext() 1.271 +{ 1.272 + if (!sCGLLibrary.EnsureInitialized()) { 1.273 + return nullptr; 1.274 + } 1.275 + 1.276 + if (!gGlobalContext) { 1.277 + // There are bugs in some older drivers with pbuffers less 1.278 + // than 16x16 in size; also 16x16 is POT so that we can do 1.279 + // a FBO with it on older video cards. A FBO context for 1.280 + // sharing is preferred since it has no associated target. 1.281 + gGlobalContext = CreateOffscreenFBOContext(false); 1.282 + if (!gGlobalContext || !static_cast<GLContextCGL*>(gGlobalContext.get())->Init()) { 1.283 + NS_WARNING("Couldn't init gGlobalContext."); 1.284 + gGlobalContext = nullptr; 1.285 + return nullptr; 1.286 + } 1.287 + } 1.288 + 1.289 + return gGlobalContext; 1.290 +} 1.291 + 1.292 +void 1.293 +GLContextProviderCGL::Shutdown() 1.294 +{ 1.295 + gGlobalContext = nullptr; 1.296 +} 1.297 + 1.298 +} /* namespace gl */ 1.299 +} /* namespace mozilla */