15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gl/gl_context_cgl.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <OpenGL/CGLRenderers.h>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <OpenGL/CGLTypes.h>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/debug/trace_event.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
1390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/memory/scoped_ptr.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gl/gl_bindings.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gl/gl_implementation.h"
16f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "ui/gl/gl_surface.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gl/gpu_switching_manager.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace gfx {
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)namespace {
2290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool g_support_renderer_switching;
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)struct CGLRendererInfoObjDeleter {
2690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  void operator()(CGLRendererInfoObj* x) {
2790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (x)
2890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      CGLDestroyRendererInfo(*x);
2990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
3090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)};
3190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
3290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}  // namespace
3390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static CGLPixelFormatObj GetPixelFormat() {
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static CGLPixelFormatObj format;
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (format)
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return format;
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<CGLPixelFormatAttribute> attribs;
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the system supports dual gpus then allow offline renderers for every
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // context, so that they can all be in the same share group.
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (ui::GpuSwitchingManager::GetInstance()->SupportsDualGpus()) {
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    attribs.push_back(kCGLPFAAllowOfflineRenderers);
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    g_support_renderer_switching = true;
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (GetGLImplementation() == kGLImplementationAppleGL) {
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    attribs.push_back(kCGLPFARendererID);
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    attribs.push_back((CGLPixelFormatAttribute) kCGLRendererGenericFloatID);
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    g_support_renderer_switching = false;
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  attribs.push_back((CGLPixelFormatAttribute) 0);
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  GLint num_virtual_screens;
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (CGLChoosePixelFormat(&attribs.front(),
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           &format,
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                           &num_virtual_screens) != kCGLNoError) {
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Error choosing pixel format.";
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return NULL;
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!format) {
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "format == 0.";
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return NULL;
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_NE(num_virtual_screens, 0);
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return format;
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)GLContextCGL::GLContextCGL(GLShareGroup* share_group)
68868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  : GLContextReal(share_group),
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    context_(NULL),
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    gpu_preference_(PreferIntegratedGpu),
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    discrete_pixelformat_(NULL),
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    screen_(-1),
73c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    renderer_id_(-1),
74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    safe_to_force_gpu_switch_(false) {
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool GLContextCGL::Initialize(GLSurface* compatible_surface,
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                              GpuPreference gpu_preference) {
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(compatible_surface);
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  gpu_preference = ui::GpuSwitchingManager::GetInstance()->AdjustGpuPreference(
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      gpu_preference);
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  GLContextCGL* share_context = share_group() ?
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      static_cast<GLContextCGL*>(share_group()->GetContext()) : NULL;
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CGLPixelFormatObj format = GetPixelFormat();
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!format)
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If using the discrete gpu, create a pixel format requiring it before we
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // create the context.
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ui::GpuSwitchingManager::GetInstance()->SupportsDualGpus() ||
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gpu_preference == PreferDiscreteGpu) {
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<CGLPixelFormatAttribute> discrete_attribs;
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    discrete_attribs.push_back((CGLPixelFormatAttribute) 0);
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GLint num_pixel_formats;
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (CGLChoosePixelFormat(&discrete_attribs.front(),
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             &discrete_pixelformat_,
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             &num_pixel_formats) != kCGLNoError) {
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(ERROR) << "Error choosing pixel format.";
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // The renderer might be switched after this, so ignore the saved ID.
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    share_group()->SetRendererID(-1);
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CGLError res = CGLCreateContext(
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      format,
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      share_context ?
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          static_cast<CGLContextObj>(share_context->GetHandle()) : NULL,
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      reinterpret_cast<CGLContextObj*>(&context_));
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (res != kCGLNoError) {
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Error creating context.";
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Destroy();
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gpu_preference_ = gpu_preference;
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GLContextCGL::Destroy() {
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (discrete_pixelformat_) {
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Delay releasing the pixel format for 10 seconds to reduce the number of
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // unnecessary GPU switches.
127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    base::MessageLoop::current()->PostDelayedTask(
128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        FROM_HERE,
129c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        base::Bind(&CGLReleasePixelFormat, discrete_pixelformat_),
130c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        base::TimeDelta::FromSeconds(10));
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    discrete_pixelformat_ = NULL;
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (context_) {
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CGLDestroyContext(static_cast<CGLContextObj>(context_));
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    context_ = NULL;
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GLContextCGL::MakeCurrent(GLSurface* surface) {
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(context_);
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
142c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // The call to CGLSetVirtualScreen can hang on some AMD drivers
143c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // http://crbug.com/227228
144c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (safe_to_force_gpu_switch_) {
145c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    int renderer_id = share_group()->GetRendererID();
146c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    int screen;
147c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    CGLGetVirtualScreen(static_cast<CGLContextObj>(context_), &screen);
148c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
149c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (g_support_renderer_switching &&
150c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        !discrete_pixelformat_ && renderer_id != -1 &&
151c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        (screen != screen_ || renderer_id != renderer_id_)) {
152c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // Attempt to find a virtual screen that's using the requested renderer,
153c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // and switch the context to use that screen. Don't attempt to switch if
154c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // the context requires the discrete GPU.
155c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      CGLPixelFormatObj format = GetPixelFormat();
156c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      int virtual_screen_count;
157c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      if (CGLDescribePixelFormat(format, 0, kCGLPFAVirtualScreenCount,
158c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                 &virtual_screen_count) != kCGLNoError)
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return false;
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
161c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      for (int i = 0; i < virtual_screen_count; ++i) {
162c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        int screen_renderer_id;
163c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        if (CGLDescribePixelFormat(format, i, kCGLPFARendererID,
164c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                   &screen_renderer_id) != kCGLNoError)
165c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          return false;
166c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
167c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        screen_renderer_id &= kCGLRendererIDMatchingMask;
168c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        if (screen_renderer_id == renderer_id) {
169c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          CGLSetVirtualScreen(static_cast<CGLContextObj>(context_), i);
170c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          screen_ = i;
171c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          break;
172c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        }
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
174c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      renderer_id_ = renderer_id;
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (IsCurrent(surface))
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
181e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  ScopedReleaseCurrent release_current;
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TRACE_EVENT0("gpu", "GLContextCGL::MakeCurrent");
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (CGLSetCurrentContext(
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      static_cast<CGLContextObj>(context_)) != kCGLNoError) {
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Unable to make gl context current.";
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1907d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // Set this as soon as the context is current, since we might call into GL.
1917d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  SetRealGLApi();
1927d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
193868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  SetCurrent(surface);
1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!InitializeDynamicBindings()) {
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!surface->OnMakeCurrent(this)) {
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Unable to make gl context current.";
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
203e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  release_current.Cancel();
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GLContextCGL::ReleaseCurrent(GLSurface* surface) {
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!IsCurrent(surface))
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
211868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  SetCurrent(NULL);
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CGLSetCurrentContext(NULL);
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GLContextCGL::IsCurrent(GLSurface* surface) {
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool native_context_is_current = CGLGetCurrentContext() == context_;
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If our context is current then our notion of which GLContext is
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // current must be correct. On the other hand, third-party code
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // using OpenGL might change the current context.
221868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(!native_context_is_current || (GetRealCurrent() == this));
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!native_context_is_current)
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void* GLContextCGL::GetHandle() {
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return context_;
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GLContextCGL::SetSwapInterval(int interval) {
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(IsCurrent(NULL));
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LOG(WARNING) << "GLContex: GLContextCGL::SetSwapInterval is ignored.";
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GLContextCGL::GetTotalGpuMemory(size_t* bytes) {
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(bytes);
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *bytes = 0;
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CGLContextObj context = reinterpret_cast<CGLContextObj>(context_);
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!context)
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Retrieve the current renderer ID
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GLint current_renderer_id = 0;
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (CGLGetParameter(context,
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      kCGLCPCurrentRendererID,
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      &current_renderer_id) != kCGLNoError)
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Iterate through the list of all renderers
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GLuint display_mask = static_cast<GLuint>(-1);
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CGLRendererInfoObj renderer_info = NULL;
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GLint num_renderers = 0;
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (CGLQueryRendererInfo(display_mask,
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           &renderer_info,
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           &num_renderers) != kCGLNoError)
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  scoped_ptr<CGLRendererInfoObj,
26490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      CGLRendererInfoObjDeleter> scoper(&renderer_info);
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (GLint renderer_index = 0;
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       renderer_index < num_renderers;
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       ++renderer_index) {
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Skip this if this renderer is not the current renderer.
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GLint renderer_id = 0;
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (CGLDescribeRenderer(renderer_info,
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            renderer_index,
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            kCGLRPRendererID,
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            &renderer_id) != kCGLNoError)
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        continue;
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (renderer_id != current_renderer_id)
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        continue;
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Retrieve the video memory for the renderer.
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GLint video_memory = 0;
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (CGLDescribeRenderer(renderer_info,
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            renderer_index,
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            kCGLRPVideoMemory,
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            &video_memory) != kCGLNoError)
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        continue;
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *bytes = video_memory;
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
292c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void GLContextCGL::SetSafeToForceGpuSwitch() {
293c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  safe_to_force_gpu_switch_ = true;
294c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
295c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
296c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GLContextCGL::~GLContextCGL() {
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Destroy();
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GpuPreference GLContextCGL::GetGpuPreference() {
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return gpu_preference_;
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace gfx
306