1 // Copyright (c) 2013 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.
5 #include "content/browser/renderer_host/compositing_iosurface_context_mac.h"
8 #include <OpenGL/OpenGL.h>
11 #include "base/command_line.h"
12 #include "base/debug/trace_event.h"
13 #include "base/logging.h"
14 #include "content/browser/renderer_host/compositing_iosurface_shader_programs_mac.h"
15 #include "ui/gl/gl_switches.h"
16 #include "ui/gl/gpu_switching_manager.h"
21 scoped_refptr<CompositingIOSurfaceContext>
22 CompositingIOSurfaceContext::Get(int window_number) {
23 TRACE_EVENT0("browser", "CompositingIOSurfaceContext::Get");
25 // Return the context for this window_number, if it exists.
26 WindowMap::iterator found = window_map()->find(window_number);
27 if (found != window_map()->end()) {
28 DCHECK(found->second->can_be_shared_);
32 std::vector<NSOpenGLPixelFormatAttribute> attributes;
33 attributes.push_back(NSOpenGLPFADoubleBuffer);
34 // We don't need a depth buffer - try setting its size to 0...
35 attributes.push_back(NSOpenGLPFADepthSize); attributes.push_back(0);
36 if (ui::GpuSwitchingManager::GetInstance()->SupportsDualGpus())
37 attributes.push_back(NSOpenGLPFAAllowOfflineRenderers);
38 attributes.push_back(0);
40 base::scoped_nsobject<NSOpenGLPixelFormat> glPixelFormat(
41 [[NSOpenGLPixelFormat alloc] initWithAttributes:&attributes.front()]);
43 LOG(ERROR) << "NSOpenGLPixelFormat initWithAttributes failed";
47 // Create all contexts in the same share group so that the textures don't
48 // need to be recreated when transitioning contexts.
49 NSOpenGLContext* share_context = nil;
50 if (!window_map()->empty())
51 share_context = window_map()->begin()->second->nsgl_context();
52 base::scoped_nsobject<NSOpenGLContext> nsgl_context(
53 [[NSOpenGLContext alloc] initWithFormat:glPixelFormat
54 shareContext:share_context]);
56 LOG(ERROR) << "NSOpenGLContext initWithFormat failed";
60 CGLContextObj cgl_context = (CGLContextObj)[nsgl_context CGLContextObj];
62 LOG(ERROR) << "CGLContextObj failed";
66 // Draw at beam vsync.
67 bool is_vsync_disabled =
68 CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableGpuVsync);
69 GLint swapInterval = is_vsync_disabled ? 0 : 1;
70 [nsgl_context setValues:&swapInterval forParameter:NSOpenGLCPSwapInterval];
72 // Prepare the shader program cache. Precompile the shader programs
73 // needed to draw the IO Surface for non-offscreen contexts.
74 CGLSetCurrentContext(cgl_context);
75 scoped_ptr<CompositingIOSurfaceShaderPrograms> shader_program_cache(
76 new CompositingIOSurfaceShaderPrograms());
77 bool prepared = false;
78 if (window_number == kOffscreenContextWindowNumber) {
82 shader_program_cache->UseBlitProgram() &&
83 shader_program_cache->UseSolidWhiteProgram());
86 CGLSetCurrentContext(0);
88 LOG(ERROR) << "IOSurface failed to compile/link required shader programs.";
92 return new CompositingIOSurfaceContext(
94 nsgl_context.release(),
97 shader_program_cache.Pass());
101 void CompositingIOSurfaceContext::MarkExistingContextsAsNotShareable() {
102 for (WindowMap::iterator it = window_map()->begin();
103 it != window_map()->end();
105 it->second->can_be_shared_ = false;
107 window_map()->clear();
110 CompositingIOSurfaceContext::CompositingIOSurfaceContext(
112 NSOpenGLContext* nsgl_context,
113 CGLContextObj cgl_context,
114 bool is_vsync_disabled,
115 scoped_ptr<CompositingIOSurfaceShaderPrograms> shader_program_cache)
116 : window_number_(window_number),
117 nsgl_context_(nsgl_context),
118 cgl_context_(cgl_context),
119 is_vsync_disabled_(is_vsync_disabled),
120 shader_program_cache_(shader_program_cache.Pass()),
121 can_be_shared_(true),
122 initialized_is_intel_(false),
125 DCHECK(window_map()->find(window_number_) == window_map()->end());
126 window_map()->insert(std::make_pair(window_number_, this));
129 CompositingIOSurfaceContext::~CompositingIOSurfaceContext() {
130 CGLSetCurrentContext(cgl_context_);
131 shader_program_cache_->Reset();
132 CGLSetCurrentContext(0);
133 if (can_be_shared_) {
134 DCHECK(window_map()->find(window_number_) != window_map()->end());
135 DCHECK(window_map()->find(window_number_)->second == this);
136 window_map()->erase(window_number_);
138 WindowMap::const_iterator found = window_map()->find(window_number_);
139 if (found != window_map()->end())
140 DCHECK(found->second != this);
144 bool CompositingIOSurfaceContext::IsVendorIntel() {
146 CGLGetVirtualScreen(cgl_context(), &screen);
147 if (screen != screen_)
148 initialized_is_intel_ = false;
150 if (!initialized_is_intel_) {
151 is_intel_ = strstr(reinterpret_cast<const char*>(glGetString(GL_VENDOR)),
153 initialized_is_intel_ = true;
159 CompositingIOSurfaceContext::WindowMap*
160 CompositingIOSurfaceContext::window_map() {
161 return window_map_.Pointer();
165 base::LazyInstance<CompositingIOSurfaceContext::WindowMap>
166 CompositingIOSurfaceContext::window_map_;
168 } // namespace content