gl_context_cgl.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "ui/gl/gl_context_cgl.h" 6 7#include <OpenGL/CGLRenderers.h> 8#include <OpenGL/CGLTypes.h> 9#include <vector> 10 11#include "base/debug/trace_event.h" 12#include "base/logging.h" 13#include "ui/gl/gl_bindings.h" 14#include "ui/gl/gl_implementation.h" 15#include "ui/gl/gl_surface_cgl.h" 16#include "ui/gl/gpu_switching_manager.h" 17 18namespace gfx { 19 20GLContextCGL::GLContextCGL(GLShareGroup* share_group) 21 : GLContext(share_group), 22 context_(NULL), 23 gpu_preference_(PreferIntegratedGpu), 24 discrete_pixelformat_(NULL) { 25} 26 27bool GLContextCGL::Initialize(GLSurface* compatible_surface, 28 GpuPreference gpu_preference) { 29 DCHECK(compatible_surface); 30 31 gpu_preference = ui::GpuSwitchingManager::GetInstance()->AdjustGpuPreference( 32 gpu_preference); 33 34 GLContextCGL* share_context = share_group() ? 35 static_cast<GLContextCGL*>(share_group()->GetContext()) : NULL; 36 37 std::vector<CGLPixelFormatAttribute> attribs; 38 // If the system supports dual gpus then allow offline renderers for every 39 // context, so that they can all be in the same share group. 40 if (ui::GpuSwitchingManager::GetInstance()->SupportsDualGpus()) 41 attribs.push_back(kCGLPFAAllowOfflineRenderers); 42 if (GetGLImplementation() == kGLImplementationAppleGL) { 43 attribs.push_back(kCGLPFARendererID); 44 attribs.push_back((CGLPixelFormatAttribute) kCGLRendererGenericFloatID); 45 } 46 attribs.push_back((CGLPixelFormatAttribute) 0); 47 48 CGLPixelFormatObj format; 49 GLint num_pixel_formats; 50 if (CGLChoosePixelFormat(&attribs.front(), 51 &format, 52 &num_pixel_formats) != kCGLNoError) { 53 LOG(ERROR) << "Error choosing pixel format."; 54 return false; 55 } 56 if (!format) { 57 LOG(ERROR) << "format == 0."; 58 return false; 59 } 60 DCHECK_NE(num_pixel_formats, 0); 61 62 // If using the discrete gpu, create a pixel format requiring it before we 63 // create the context. 64 if (!ui::GpuSwitchingManager::GetInstance()->SupportsDualGpus() || 65 gpu_preference == PreferDiscreteGpu) { 66 std::vector<CGLPixelFormatAttribute> discrete_attribs; 67 discrete_attribs.push_back((CGLPixelFormatAttribute) 0); 68 GLint num_pixel_formats; 69 if (CGLChoosePixelFormat(&discrete_attribs.front(), 70 &discrete_pixelformat_, 71 &num_pixel_formats) != kCGLNoError) { 72 LOG(ERROR) << "Error choosing pixel format."; 73 return false; 74 } 75 } 76 77 CGLError res = CGLCreateContext( 78 format, 79 share_context ? 80 static_cast<CGLContextObj>(share_context->GetHandle()) : NULL, 81 reinterpret_cast<CGLContextObj*>(&context_)); 82 CGLReleasePixelFormat(format); 83 if (res != kCGLNoError) { 84 LOG(ERROR) << "Error creating context."; 85 Destroy(); 86 return false; 87 } 88 89 gpu_preference_ = gpu_preference; 90 return true; 91} 92 93void GLContextCGL::Destroy() { 94 if (discrete_pixelformat_) { 95 CGLReleasePixelFormat(discrete_pixelformat_); 96 discrete_pixelformat_ = NULL; 97 } 98 if (context_) { 99 CGLDestroyContext(static_cast<CGLContextObj>(context_)); 100 context_ = NULL; 101 } 102} 103 104bool GLContextCGL::MakeCurrent(GLSurface* surface) { 105 DCHECK(context_); 106 if (IsCurrent(surface)) 107 return true; 108 109 TRACE_EVENT0("gpu", "GLContextCGL::MakeCurrent"); 110 111 if (CGLSetCurrentContext( 112 static_cast<CGLContextObj>(context_)) != kCGLNoError) { 113 LOG(ERROR) << "Unable to make gl context current."; 114 return false; 115 } 116 117 SetCurrent(this, surface); 118 if (!InitializeExtensionBindings()) { 119 ReleaseCurrent(surface); 120 return false; 121 } 122 123 if (!surface->OnMakeCurrent(this)) { 124 LOG(ERROR) << "Unable to make gl context current."; 125 return false; 126 } 127 128 SetRealGLApi(); 129 return true; 130} 131 132void GLContextCGL::ReleaseCurrent(GLSurface* surface) { 133 if (!IsCurrent(surface)) 134 return; 135 136 SetCurrent(NULL, NULL); 137 CGLSetCurrentContext(NULL); 138} 139 140bool GLContextCGL::IsCurrent(GLSurface* surface) { 141 bool native_context_is_current = CGLGetCurrentContext() == context_; 142 143 // If our context is current then our notion of which GLContext is 144 // current must be correct. On the other hand, third-party code 145 // using OpenGL might change the current context. 146 DCHECK(!native_context_is_current || (GetCurrent() == this)); 147 148 if (!native_context_is_current) 149 return false; 150 151 return true; 152} 153 154void* GLContextCGL::GetHandle() { 155 return context_; 156} 157 158void GLContextCGL::SetSwapInterval(int interval) { 159 DCHECK(IsCurrent(NULL)); 160 LOG(WARNING) << "GLContex: GLContextCGL::SetSwapInterval is ignored."; 161} 162 163 164bool GLContextCGL::GetTotalGpuMemory(size_t* bytes) { 165 DCHECK(bytes); 166 *bytes = 0; 167 168 CGLContextObj context = reinterpret_cast<CGLContextObj>(context_); 169 if (!context) 170 return false; 171 172 // Retrieve the current renderer ID 173 GLint current_renderer_id = 0; 174 if (CGLGetParameter(context, 175 kCGLCPCurrentRendererID, 176 ¤t_renderer_id) != kCGLNoError) 177 return false; 178 179 // Iterate through the list of all renderers 180 GLuint display_mask = static_cast<GLuint>(-1); 181 CGLRendererInfoObj renderer_info = NULL; 182 GLint num_renderers = 0; 183 if (CGLQueryRendererInfo(display_mask, 184 &renderer_info, 185 &num_renderers) != kCGLNoError) 186 return false; 187 188 ScopedCGLRendererInfoObj scoper(renderer_info); 189 190 for (GLint renderer_index = 0; 191 renderer_index < num_renderers; 192 ++renderer_index) { 193 // Skip this if this renderer is not the current renderer. 194 GLint renderer_id = 0; 195 if (CGLDescribeRenderer(renderer_info, 196 renderer_index, 197 kCGLRPRendererID, 198 &renderer_id) != kCGLNoError) 199 continue; 200 if (renderer_id != current_renderer_id) 201 continue; 202 // Retrieve the video memory for the renderer. 203 GLint video_memory = 0; 204 if (CGLDescribeRenderer(renderer_info, 205 renderer_index, 206 kCGLRPVideoMemory, 207 &video_memory) != kCGLNoError) 208 continue; 209 *bytes = video_memory; 210 return true; 211 } 212 213 return false; 214} 215 216GLContextCGL::~GLContextCGL() { 217 Destroy(); 218} 219 220GpuPreference GLContextCGL::GetGpuPreference() { 221 return gpu_preference_; 222} 223 224void ScopedCGLDestroyRendererInfo::operator()(CGLRendererInfoObj x) const { 225 CGLDestroyRendererInfo(x); 226} 227 228} // namespace gfx 229