Home | History | Annotate | Download | only in renderer_host
      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/gpu/gpu_data_manager_impl.h"
     15 #include "ui/base/ui_base_switches.h"
     16 #include "ui/gl/gl_switches.h"
     17 #include "ui/gl/gpu_switching_manager.h"
     18 
     19 namespace content {
     20 
     21 // static
     22 scoped_refptr<CompositingIOSurfaceContext>
     23 CompositingIOSurfaceContext::Get(int window_number) {
     24   TRACE_EVENT0("browser", "CompositingIOSurfaceContext::Get");
     25 
     26   // Return the context for this window_number, if it exists.
     27   WindowMap::iterator found = window_map()->find(window_number);
     28   if (found != window_map()->end()) {
     29     DCHECK(!found->second->poisoned_);
     30     return found->second;
     31   }
     32 
     33   base::ScopedTypeRef<CGLContextObj> cgl_context_strong;
     34   CGLContextObj cgl_context = NULL;
     35   CGLError error = kCGLNoError;
     36 
     37   // Create the pixel format object for the context.
     38   std::vector<CGLPixelFormatAttribute> attribs;
     39   attribs.push_back(kCGLPFADepthSize);
     40   attribs.push_back(static_cast<CGLPixelFormatAttribute>(0));
     41   if (ui::GpuSwitchingManager::GetInstance()->SupportsDualGpus()) {
     42     attribs.push_back(kCGLPFAAllowOfflineRenderers);
     43     attribs.push_back(static_cast<CGLPixelFormatAttribute>(1));
     44   }
     45   attribs.push_back(static_cast<CGLPixelFormatAttribute>(0));
     46   GLint number_virtual_screens = 0;
     47   base::ScopedTypeRef<CGLPixelFormatObj> pixel_format;
     48   error = CGLChoosePixelFormat(&attribs.front(),
     49                                pixel_format.InitializeInto(),
     50                                &number_virtual_screens);
     51   if (error != kCGLNoError) {
     52     LOG(ERROR) << "Failed to create pixel format object.";
     53     return NULL;
     54   }
     55 
     56   // Create all contexts in the same share group so that the textures don't
     57   // need to be recreated when transitioning contexts.
     58   CGLContextObj share_context = NULL;
     59   if (!window_map()->empty())
     60     share_context = window_map()->begin()->second->cgl_context();
     61   error = CGLCreateContext(
     62       pixel_format, share_context, cgl_context_strong.InitializeInto());
     63   if (error != kCGLNoError) {
     64     LOG(ERROR) << "Failed to create context object.";
     65     return NULL;
     66   }
     67   cgl_context = cgl_context_strong;
     68 
     69   // Note that VSync is ignored because CoreAnimation will automatically
     70   // rate limit draws.
     71 
     72   return new CompositingIOSurfaceContext(
     73       window_number,
     74       cgl_context_strong,
     75       cgl_context);
     76 }
     77 
     78 void CompositingIOSurfaceContext::PoisonContextAndSharegroup() {
     79   if (poisoned_)
     80     return;
     81 
     82   for (WindowMap::iterator it = window_map()->begin();
     83        it != window_map()->end();
     84        ++it) {
     85     it->second->poisoned_ = true;
     86   }
     87   window_map()->clear();
     88 }
     89 
     90 CompositingIOSurfaceContext::CompositingIOSurfaceContext(
     91     int window_number,
     92     base::ScopedTypeRef<CGLContextObj> cgl_context_strong,
     93     CGLContextObj cgl_context)
     94     : window_number_(window_number),
     95       cgl_context_strong_(cgl_context_strong),
     96       cgl_context_(cgl_context),
     97       poisoned_(false) {
     98   DCHECK(window_map()->find(window_number_) == window_map()->end());
     99   window_map()->insert(std::make_pair(window_number_, this));
    100 
    101   GpuDataManager::GetInstance()->AddObserver(this);
    102 }
    103 
    104 CompositingIOSurfaceContext::~CompositingIOSurfaceContext() {
    105   GpuDataManager::GetInstance()->RemoveObserver(this);
    106 
    107   if (!poisoned_) {
    108     DCHECK(window_map()->find(window_number_) != window_map()->end());
    109     DCHECK(window_map()->find(window_number_)->second == this);
    110     window_map()->erase(window_number_);
    111   } else {
    112     WindowMap::const_iterator found = window_map()->find(window_number_);
    113     if (found != window_map()->end())
    114       DCHECK(found->second != this);
    115   }
    116 }
    117 
    118 void CompositingIOSurfaceContext::OnGpuSwitching() {
    119   // Recreate all browser-side GL contexts whenever the GPU switches. If this
    120   // is not done, performance will suffer.
    121   // http://crbug.com/361493
    122   PoisonContextAndSharegroup();
    123 }
    124 
    125 // static
    126 CompositingIOSurfaceContext::WindowMap*
    127     CompositingIOSurfaceContext::window_map() {
    128   return window_map_.Pointer();
    129 }
    130 
    131 // static
    132 base::LazyInstance<CompositingIOSurfaceContext::WindowMap>
    133     CompositingIOSurfaceContext::window_map_;
    134 
    135 }  // namespace content
    136