summaryrefslogtreecommitdiffstats
path: root/content/browser/renderer_host/compositing_iosurface_context_mac.mm
blob: ede46b49607b84b7492d636960607da80888e9fa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/browser/renderer_host/compositing_iosurface_context_mac.h"

#include <OpenGL/gl.h>
#include <OpenGL/OpenGL.h>
#include <vector>

#include "base/command_line.h"
#include "base/logging.h"
#include "content/browser/renderer_host/compositing_iosurface_shader_programs_mac.h"
#include "ui/gl/gl_switches.h"
#include "ui/gl/gpu_switching_manager.h"

namespace content {

scoped_refptr<CompositingIOSurfaceContext>
    CompositingIOSurfaceContext::Get(
        CompositingIOSurfaceMac::SurfaceOrder surface_order) {
  std::vector<NSOpenGLPixelFormatAttribute> attributes;
  attributes.push_back(NSOpenGLPFADoubleBuffer);
  // We don't need a depth buffer - try setting its size to 0...
  attributes.push_back(NSOpenGLPFADepthSize); attributes.push_back(0);
  if (ui::GpuSwitchingManager::GetInstance()->SupportsDualGpus())
    attributes.push_back(NSOpenGLPFAAllowOfflineRenderers);
  attributes.push_back(0);

  scoped_nsobject<NSOpenGLPixelFormat> glPixelFormat(
      [[NSOpenGLPixelFormat alloc] initWithAttributes:&attributes.front()]);
  if (!glPixelFormat) {
    LOG(ERROR) << "NSOpenGLPixelFormat initWithAttributes failed";
    return NULL;
  }

  scoped_nsobject<NSOpenGLContext> nsgl_context(
      [[NSOpenGLContext alloc] initWithFormat:glPixelFormat
                                 shareContext:nil]);
  if (!nsgl_context) {
    LOG(ERROR) << "NSOpenGLContext initWithFormat failed";
    return NULL;
  }

  // If requested, ask the WindowServer to render the OpenGL surface underneath
  // the window. This, combined with a hole punched in the window, will allow
  // for views to "overlap" the GL surface from the user's point of view.
  if (surface_order == CompositingIOSurfaceMac::SURFACE_ORDER_BELOW_WINDOW) {
    GLint gl_surface_order = -1;
    [nsgl_context setValues:&gl_surface_order
                  forParameter:NSOpenGLCPSurfaceOrder];
  }

  CGLContextObj cgl_context = (CGLContextObj)[nsgl_context CGLContextObj];
  if (!cgl_context) {
    LOG(ERROR) << "CGLContextObj failed";
    return NULL;
  }

  // Draw at beam vsync.
  bool is_vsync_disabled =
      CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableGpuVsync);
  GLint swapInterval = is_vsync_disabled ? 0 : 1;
  [nsgl_context setValues:&swapInterval forParameter:NSOpenGLCPSwapInterval];

  // Prepare the shader program cache.  Precompile only the shader programs
  // needed to draw the IO Surface.
  CGLSetCurrentContext(cgl_context);
  scoped_ptr<CompositingIOSurfaceShaderPrograms> shader_program_cache(
      new CompositingIOSurfaceShaderPrograms());
  const bool prepared = (
      shader_program_cache->UseBlitProgram() &&
      shader_program_cache->UseSolidWhiteProgram());
  glUseProgram(0u);
  CGLSetCurrentContext(0);
  if (!prepared) {
    LOG(ERROR) << "IOSurface failed to compile/link required shader programs.";
    return NULL;
  }

  return new CompositingIOSurfaceContext(
      surface_order,
      nsgl_context.release(),
      cgl_context,
      is_vsync_disabled,
      shader_program_cache.Pass());
}

CompositingIOSurfaceContext::CompositingIOSurfaceContext(
    CompositingIOSurfaceMac::SurfaceOrder surface_order,
    NSOpenGLContext* nsgl_context,
    CGLContextObj cgl_context,
    bool is_vsync_disabled,
    scoped_ptr<CompositingIOSurfaceShaderPrograms> shader_program_cache)
    : surface_order_(surface_order),
      nsgl_context_(nsgl_context),
      cgl_context_(cgl_context),
      shader_program_cache_(shader_program_cache.Pass()) {
}

CompositingIOSurfaceContext::~CompositingIOSurfaceContext() {
  CGLSetCurrentContext(cgl_context_);
  shader_program_cache_->Reset();
  CGLSetCurrentContext(0);
}

}  // namespace content