compositing_iosurface_context_mac.mm revision f8ee788a64d60abd8f2d742a5fdedde054ecd910
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.
4
5#include "content/browser/renderer_host/compositing_iosurface_context_mac.h"
6
7#include <OpenGL/gl.h>
8#include <OpenGL/OpenGL.h>
9#include <vector>
10
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 "content/browser/gpu/gpu_data_manager_impl.h"
16#include "ui/base/ui_base_switches.h"
17#include "ui/gl/gl_switches.h"
18#include "ui/gl/gpu_switching_manager.h"
19
20namespace content {
21
22// static
23scoped_refptr<CompositingIOSurfaceContext>
24CompositingIOSurfaceContext::Get(int window_number) {
25  TRACE_EVENT0("browser", "CompositingIOSurfaceContext::Get");
26
27  // Return the context for this window_number, if it exists.
28  WindowMap::iterator found = window_map()->find(window_number);
29  if (found != window_map()->end()) {
30    DCHECK(!found->second->poisoned_);
31    return found->second;
32  }
33
34  static bool is_vsync_disabled =
35      CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableGpuVsync);
36
37  base::ScopedTypeRef<CGLContextObj> cgl_context_strong;
38  CGLContextObj cgl_context = NULL;
39  CGLError error = kCGLNoError;
40
41  // Create the pixel format object for the context.
42  std::vector<CGLPixelFormatAttribute> attribs;
43  attribs.push_back(kCGLPFADepthSize);
44  attribs.push_back(static_cast<CGLPixelFormatAttribute>(0));
45  if (ui::GpuSwitchingManager::GetInstance()->SupportsDualGpus()) {
46    attribs.push_back(kCGLPFAAllowOfflineRenderers);
47    attribs.push_back(static_cast<CGLPixelFormatAttribute>(1));
48  }
49  attribs.push_back(static_cast<CGLPixelFormatAttribute>(0));
50  GLint number_virtual_screens = 0;
51  base::ScopedTypeRef<CGLPixelFormatObj> pixel_format;
52  error = CGLChoosePixelFormat(&attribs.front(),
53                               pixel_format.InitializeInto(),
54                               &number_virtual_screens);
55  if (error != kCGLNoError) {
56    LOG(ERROR) << "Failed to create pixel format object.";
57    return NULL;
58  }
59
60  // Create all contexts in the same share group so that the textures don't
61  // need to be recreated when transitioning contexts.
62  CGLContextObj share_context = NULL;
63  if (!window_map()->empty())
64    share_context = window_map()->begin()->second->cgl_context();
65  error = CGLCreateContext(
66      pixel_format, share_context, cgl_context_strong.InitializeInto());
67  if (error != kCGLNoError) {
68    LOG(ERROR) << "Failed to create context object.";
69    return NULL;
70  }
71  cgl_context = cgl_context_strong;
72
73  // Note that VSync is ignored because CoreAnimation will automatically
74  // rate limit draws.
75
76  // Prepare the shader program cache. Precompile the shader programs
77  // needed to draw the IO Surface for non-offscreen contexts.
78  bool prepared = false;
79  scoped_ptr<CompositingIOSurfaceShaderPrograms> shader_program_cache;
80  {
81    gfx::ScopedCGLSetCurrentContext scoped_set_current_context(cgl_context);
82    shader_program_cache.reset(new CompositingIOSurfaceShaderPrograms());
83    if (window_number == kOffscreenContextWindowNumber) {
84      prepared = true;
85    } else {
86      prepared = (
87          shader_program_cache->UseBlitProgram() &&
88          shader_program_cache->UseSolidWhiteProgram());
89    }
90    glUseProgram(0u);
91  }
92  if (!prepared) {
93    LOG(ERROR) << "IOSurface failed to compile/link required shader programs.";
94    return NULL;
95  }
96
97  return new CompositingIOSurfaceContext(
98      window_number,
99      cgl_context_strong,
100      cgl_context,
101      is_vsync_disabled,
102      shader_program_cache.Pass());
103}
104
105void CompositingIOSurfaceContext::PoisonContextAndSharegroup() {
106  if (poisoned_)
107    return;
108
109  for (WindowMap::iterator it = window_map()->begin();
110       it != window_map()->end();
111       ++it) {
112    it->second->poisoned_ = true;
113  }
114  window_map()->clear();
115}
116
117CompositingIOSurfaceContext::CompositingIOSurfaceContext(
118    int window_number,
119    base::ScopedTypeRef<CGLContextObj> cgl_context_strong,
120    CGLContextObj cgl_context,
121    bool is_vsync_disabled,
122    scoped_ptr<CompositingIOSurfaceShaderPrograms> shader_program_cache)
123    : window_number_(window_number),
124      cgl_context_strong_(cgl_context_strong),
125      cgl_context_(cgl_context),
126      is_vsync_disabled_(is_vsync_disabled),
127      shader_program_cache_(shader_program_cache.Pass()),
128      poisoned_(false) {
129  DCHECK(window_map()->find(window_number_) == window_map()->end());
130  window_map()->insert(std::make_pair(window_number_, this));
131
132  GpuDataManager::GetInstance()->AddObserver(this);
133}
134
135CompositingIOSurfaceContext::~CompositingIOSurfaceContext() {
136  GpuDataManager::GetInstance()->RemoveObserver(this);
137
138  {
139    gfx::ScopedCGLSetCurrentContext scoped_set_current_context(cgl_context_);
140    shader_program_cache_->Reset();
141  }
142  if (!poisoned_) {
143    DCHECK(window_map()->find(window_number_) != window_map()->end());
144    DCHECK(window_map()->find(window_number_)->second == this);
145    window_map()->erase(window_number_);
146  } else {
147    WindowMap::const_iterator found = window_map()->find(window_number_);
148    if (found != window_map()->end())
149      DCHECK(found->second != this);
150  }
151}
152
153void CompositingIOSurfaceContext::OnGpuSwitching() {
154  // Recreate all browser-side GL contexts whenever the GPU switches. If this
155  // is not done, performance will suffer.
156  // http://crbug.com/361493
157  PoisonContextAndSharegroup();
158}
159
160// static
161CompositingIOSurfaceContext::WindowMap*
162    CompositingIOSurfaceContext::window_map() {
163  return window_map_.Pointer();
164}
165
166// static
167base::LazyInstance<CompositingIOSurfaceContext::WindowMap>
168    CompositingIOSurfaceContext::window_map_;
169
170}  // namespace content
171