gfx/gl/GLContextProviderCGL.mm

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

michael@0 1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
michael@0 2 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #include "GLContextProvider.h"
michael@0 7 #include "GLContextCGL.h"
michael@0 8 #include "TextureImageCGL.h"
michael@0 9 #include "nsDebug.h"
michael@0 10 #include "nsIWidget.h"
michael@0 11 #include <OpenGL/gl.h>
michael@0 12 #include "gfxPrefs.h"
michael@0 13 #include "gfxFailure.h"
michael@0 14 #include "prenv.h"
michael@0 15 #include "mozilla/Preferences.h"
michael@0 16 #include "GeckoProfiler.h"
michael@0 17 #include "mozilla/gfx/MacIOSurface.h"
michael@0 18
michael@0 19 using namespace mozilla::gfx;
michael@0 20
michael@0 21 namespace mozilla {
michael@0 22 namespace gl {
michael@0 23
michael@0 24 static bool gUseDoubleBufferedWindows = true;
michael@0 25
michael@0 26 class CGLLibrary
michael@0 27 {
michael@0 28 public:
michael@0 29 CGLLibrary()
michael@0 30 : mInitialized(false),
michael@0 31 mOGLLibrary(nullptr),
michael@0 32 mPixelFormat(nullptr)
michael@0 33 { }
michael@0 34
michael@0 35 bool EnsureInitialized()
michael@0 36 {
michael@0 37 if (mInitialized) {
michael@0 38 return true;
michael@0 39 }
michael@0 40 if (!mOGLLibrary) {
michael@0 41 mOGLLibrary = PR_LoadLibrary("/System/Library/Frameworks/OpenGL.framework/OpenGL");
michael@0 42 if (!mOGLLibrary) {
michael@0 43 NS_WARNING("Couldn't load OpenGL Framework.");
michael@0 44 return false;
michael@0 45 }
michael@0 46 }
michael@0 47
michael@0 48 const char* db = PR_GetEnv("MOZ_CGL_DB");
michael@0 49 gUseDoubleBufferedWindows = (!db || *db != '0');
michael@0 50
michael@0 51 mInitialized = true;
michael@0 52 return true;
michael@0 53 }
michael@0 54
michael@0 55 NSOpenGLPixelFormat *PixelFormat()
michael@0 56 {
michael@0 57 if (mPixelFormat == nullptr) {
michael@0 58 NSOpenGLPixelFormatAttribute attribs[] = {
michael@0 59 NSOpenGLPFAAccelerated,
michael@0 60 NSOpenGLPFAAllowOfflineRenderers,
michael@0 61 NSOpenGLPFADoubleBuffer,
michael@0 62 0
michael@0 63 };
michael@0 64
michael@0 65 if (!gUseDoubleBufferedWindows) {
michael@0 66 attribs[2] = 0;
michael@0 67 }
michael@0 68
michael@0 69 mPixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];
michael@0 70 }
michael@0 71
michael@0 72 return mPixelFormat;
michael@0 73 }
michael@0 74 private:
michael@0 75 bool mInitialized;
michael@0 76 PRLibrary *mOGLLibrary;
michael@0 77 NSOpenGLPixelFormat *mPixelFormat;
michael@0 78 };
michael@0 79
michael@0 80 CGLLibrary sCGLLibrary;
michael@0 81
michael@0 82 GLContextCGL::GLContextCGL(
michael@0 83 const SurfaceCaps& caps,
michael@0 84 GLContext *shareContext,
michael@0 85 NSOpenGLContext *context,
michael@0 86 bool isOffscreen)
michael@0 87 : GLContext(caps, shareContext, isOffscreen),
michael@0 88 mContext(context)
michael@0 89 {
michael@0 90 SetProfileVersion(ContextProfile::OpenGLCompatibility, 210);
michael@0 91 }
michael@0 92
michael@0 93 GLContextCGL::~GLContextCGL()
michael@0 94 {
michael@0 95 MarkDestroyed();
michael@0 96
michael@0 97 if (mContext) {
michael@0 98 if ([NSOpenGLContext currentContext] == mContext) {
michael@0 99 // Clear the current context before releasing. If we don't do
michael@0 100 // this, the next time we call [NSOpenGLContext currentContext],
michael@0 101 // "invalid context" will be printed to the console.
michael@0 102 [NSOpenGLContext clearCurrentContext];
michael@0 103 }
michael@0 104 [mContext release];
michael@0 105 }
michael@0 106
michael@0 107 }
michael@0 108
michael@0 109 bool
michael@0 110 GLContextCGL::Init()
michael@0 111 {
michael@0 112 if (!InitWithPrefix("gl", true))
michael@0 113 return false;
michael@0 114
michael@0 115 return true;
michael@0 116 }
michael@0 117
michael@0 118 CGLContextObj
michael@0 119 GLContextCGL::GetCGLContext() const
michael@0 120 {
michael@0 121 return static_cast<CGLContextObj>([mContext CGLContextObj]);
michael@0 122 }
michael@0 123
michael@0 124 bool
michael@0 125 GLContextCGL::MakeCurrentImpl(bool aForce)
michael@0 126 {
michael@0 127 if (!aForce && [NSOpenGLContext currentContext] == mContext) {
michael@0 128 return true;
michael@0 129 }
michael@0 130
michael@0 131 if (mContext) {
michael@0 132 [mContext makeCurrentContext];
michael@0 133 // Use non-blocking swap in "ASAP mode".
michael@0 134 // ASAP mode means that rendering is iterated as fast as possible.
michael@0 135 // ASAP mode is entered when layout.frame_rate=0 (requires restart).
michael@0 136 // If swapInt is 1, then glSwapBuffers will block and wait for a vblank signal.
michael@0 137 // When we're iterating as fast as possible, however, we want a non-blocking
michael@0 138 // glSwapBuffers, which will happen when swapInt==0.
michael@0 139 GLint swapInt = gfxPrefs::LayoutFrameRate() == 0 ? 0 : 1;
michael@0 140 [mContext setValues:&swapInt forParameter:NSOpenGLCPSwapInterval];
michael@0 141 }
michael@0 142 return true;
michael@0 143 }
michael@0 144
michael@0 145 bool
michael@0 146 GLContextCGL::IsCurrent() {
michael@0 147 return [NSOpenGLContext currentContext] == mContext;
michael@0 148 }
michael@0 149
michael@0 150 GLenum
michael@0 151 GLContextCGL::GetPreferredARGB32Format() const
michael@0 152 {
michael@0 153 return LOCAL_GL_BGRA;
michael@0 154 }
michael@0 155
michael@0 156 bool
michael@0 157 GLContextCGL::SetupLookupFunction()
michael@0 158 {
michael@0 159 return false;
michael@0 160 }
michael@0 161
michael@0 162 bool
michael@0 163 GLContextCGL::IsDoubleBuffered() const
michael@0 164 {
michael@0 165 return gUseDoubleBufferedWindows;
michael@0 166 }
michael@0 167
michael@0 168 bool
michael@0 169 GLContextCGL::SupportsRobustness() const
michael@0 170 {
michael@0 171 return false;
michael@0 172 }
michael@0 173
michael@0 174 bool
michael@0 175 GLContextCGL::SwapBuffers()
michael@0 176 {
michael@0 177 PROFILER_LABEL("GLContext", "SwapBuffers");
michael@0 178 [mContext flushBuffer];
michael@0 179 return true;
michael@0 180 }
michael@0 181
michael@0 182
michael@0 183 static GLContextCGL *
michael@0 184 GetGlobalContextCGL()
michael@0 185 {
michael@0 186 return static_cast<GLContextCGL*>(GLContextProviderCGL::GetGlobalContext());
michael@0 187 }
michael@0 188
michael@0 189 already_AddRefed<GLContext>
michael@0 190 GLContextProviderCGL::CreateWrappingExisting(void*, void*)
michael@0 191 {
michael@0 192 return nullptr;
michael@0 193 }
michael@0 194
michael@0 195 already_AddRefed<GLContext>
michael@0 196 GLContextProviderCGL::CreateForWindow(nsIWidget *aWidget)
michael@0 197 {
michael@0 198 GLContextCGL *shareContext = GetGlobalContextCGL();
michael@0 199
michael@0 200 NSOpenGLContext *context = [[NSOpenGLContext alloc]
michael@0 201 initWithFormat:sCGLLibrary.PixelFormat()
michael@0 202 shareContext:(shareContext ? shareContext->mContext : NULL)];
michael@0 203 if (!context) {
michael@0 204 return nullptr;
michael@0 205 }
michael@0 206
michael@0 207 // make the context transparent
michael@0 208 GLint opaque = 0;
michael@0 209 [context setValues:&opaque forParameter:NSOpenGLCPSurfaceOpacity];
michael@0 210
michael@0 211 SurfaceCaps caps = SurfaceCaps::ForRGBA();
michael@0 212 nsRefPtr<GLContextCGL> glContext = new GLContextCGL(caps,
michael@0 213 shareContext,
michael@0 214 context);
michael@0 215 if (!glContext->Init()) {
michael@0 216 return nullptr;
michael@0 217 }
michael@0 218
michael@0 219 return glContext.forget();
michael@0 220 }
michael@0 221
michael@0 222 static already_AddRefed<GLContextCGL>
michael@0 223 CreateOffscreenFBOContext(bool aShare = true)
michael@0 224 {
michael@0 225 if (!sCGLLibrary.EnsureInitialized()) {
michael@0 226 return nullptr;
michael@0 227 }
michael@0 228
michael@0 229 GLContextCGL *shareContext = aShare ? GetGlobalContextCGL() : nullptr;
michael@0 230 if (aShare && !shareContext) {
michael@0 231 // if there is no share context, then we can't use FBOs.
michael@0 232 return nullptr;
michael@0 233 }
michael@0 234
michael@0 235 NSOpenGLContext *context = [[NSOpenGLContext alloc]
michael@0 236 initWithFormat:sCGLLibrary.PixelFormat()
michael@0 237 shareContext:shareContext ? shareContext->GetNSOpenGLContext() : NULL];
michael@0 238 if (!context) {
michael@0 239 return nullptr;
michael@0 240 }
michael@0 241
michael@0 242 SurfaceCaps dummyCaps = SurfaceCaps::Any();
michael@0 243 nsRefPtr<GLContextCGL> glContext = new GLContextCGL(dummyCaps, shareContext, context, true);
michael@0 244
michael@0 245 return glContext.forget();
michael@0 246 }
michael@0 247
michael@0 248 already_AddRefed<GLContext>
michael@0 249 GLContextProviderCGL::CreateOffscreen(const gfxIntSize& size,
michael@0 250 const SurfaceCaps& caps)
michael@0 251 {
michael@0 252 nsRefPtr<GLContextCGL> glContext = CreateOffscreenFBOContext();
michael@0 253 if (glContext &&
michael@0 254 glContext->Init() &&
michael@0 255 glContext->InitOffscreen(ToIntSize(size), caps))
michael@0 256 {
michael@0 257 return glContext.forget();
michael@0 258 }
michael@0 259
michael@0 260 // everything failed
michael@0 261 return nullptr;
michael@0 262 }
michael@0 263
michael@0 264 static nsRefPtr<GLContext> gGlobalContext;
michael@0 265
michael@0 266 GLContext *
michael@0 267 GLContextProviderCGL::GetGlobalContext()
michael@0 268 {
michael@0 269 if (!sCGLLibrary.EnsureInitialized()) {
michael@0 270 return nullptr;
michael@0 271 }
michael@0 272
michael@0 273 if (!gGlobalContext) {
michael@0 274 // There are bugs in some older drivers with pbuffers less
michael@0 275 // than 16x16 in size; also 16x16 is POT so that we can do
michael@0 276 // a FBO with it on older video cards. A FBO context for
michael@0 277 // sharing is preferred since it has no associated target.
michael@0 278 gGlobalContext = CreateOffscreenFBOContext(false);
michael@0 279 if (!gGlobalContext || !static_cast<GLContextCGL*>(gGlobalContext.get())->Init()) {
michael@0 280 NS_WARNING("Couldn't init gGlobalContext.");
michael@0 281 gGlobalContext = nullptr;
michael@0 282 return nullptr;
michael@0 283 }
michael@0 284 }
michael@0 285
michael@0 286 return gGlobalContext;
michael@0 287 }
michael@0 288
michael@0 289 void
michael@0 290 GLContextProviderCGL::Shutdown()
michael@0 291 {
michael@0 292 gGlobalContext = nullptr;
michael@0 293 }
michael@0 294
michael@0 295 } /* namespace gl */
michael@0 296 } /* namespace mozilla */

mercurial