1// Copyright 2014 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/common/gpu/image_transport_surface_iosurface_mac.h"
6
7#include "content/common/gpu/gpu_messages.h"
8#include "content/common/gpu/surface_handle_types_mac.h"
9
10namespace content {
11namespace {
12
13// IOSurface dimensions will be rounded up to a multiple of this value in order
14// to reduce memory thrashing during resize. This must be a power of 2.
15const uint32 kIOSurfaceDimensionRoundup = 64;
16
17int RoundUpSurfaceDimension(int number) {
18  DCHECK(number >= 0);
19  // Cast into unsigned space for portable bitwise ops.
20  uint32 unsigned_number = static_cast<uint32>(number);
21  uint32 roundup_sub_1 = kIOSurfaceDimensionRoundup - 1;
22  unsigned_number = (unsigned_number + roundup_sub_1) & ~roundup_sub_1;
23  return static_cast<int>(unsigned_number);
24}
25
26void AddBooleanValue(CFMutableDictionaryRef dictionary,
27                     const CFStringRef key,
28                     bool value) {
29  CFDictionaryAddValue(dictionary, key,
30                       (value ? kCFBooleanTrue : kCFBooleanFalse));
31}
32
33void AddIntegerValue(CFMutableDictionaryRef dictionary,
34                     const CFStringRef key,
35                     int32 value) {
36  base::ScopedCFTypeRef<CFNumberRef> number(
37      CFNumberCreate(NULL, kCFNumberSInt32Type, &value));
38  CFDictionaryAddValue(dictionary, key, number.get());
39}
40
41}  // namespace
42
43IOSurfaceStorageProvider::IOSurfaceStorageProvider(
44    ImageTransportSurfaceFBO* transport_surface)
45        : transport_surface_(transport_surface) {}
46
47IOSurfaceStorageProvider::~IOSurfaceStorageProvider() {
48  DCHECK(!io_surface_);
49}
50
51gfx::Size IOSurfaceStorageProvider::GetRoundedSize(gfx::Size size) {
52  return gfx::Size(RoundUpSurfaceDimension(size.width()),
53                   RoundUpSurfaceDimension(size.height()));
54}
55
56bool IOSurfaceStorageProvider::AllocateColorBufferStorage(
57    CGLContextObj context, GLuint texture,
58    gfx::Size pixel_size, float scale_factor) {
59  // Allocate a new IOSurface, which is the GPU resource that can be
60  // shared across processes.
61  base::ScopedCFTypeRef<CFMutableDictionaryRef> properties;
62  properties.reset(CFDictionaryCreateMutable(kCFAllocatorDefault,
63                                             0,
64                                             &kCFTypeDictionaryKeyCallBacks,
65                                             &kCFTypeDictionaryValueCallBacks));
66  AddIntegerValue(properties,
67                  kIOSurfaceWidth,
68                  pixel_size.width());
69  AddIntegerValue(properties,
70                  kIOSurfaceHeight,
71                  pixel_size.height());
72  AddIntegerValue(properties,
73                  kIOSurfaceBytesPerElement, 4);
74  AddBooleanValue(properties,
75                  kIOSurfaceIsGlobal, true);
76  // I believe we should be able to unreference the IOSurfaces without
77  // synchronizing with the browser process because they are
78  // ultimately reference counted by the operating system.
79  io_surface_.reset(IOSurfaceCreate(properties));
80  io_surface_id_ = IOSurfaceGetID(io_surface_);
81
82  // Don't think we need to identify a plane.
83  GLuint plane = 0;
84  CGLError cglerror = CGLTexImageIOSurface2D(
85      context,
86      GL_TEXTURE_RECTANGLE_ARB,
87      GL_RGBA,
88      pixel_size.width(),
89      pixel_size.height(),
90      GL_BGRA,
91      GL_UNSIGNED_INT_8_8_8_8_REV,
92      io_surface_.get(),
93      plane);
94  if (cglerror != kCGLNoError) {
95    DLOG(ERROR) << "CGLTexImageIOSurface2D failed with CGL error: " << cglerror;
96    return false;
97  }
98
99  glFlush();
100  return true;
101}
102
103void IOSurfaceStorageProvider::FreeColorBufferStorage() {
104  io_surface_.reset();
105  io_surface_id_ = 0;
106}
107
108void IOSurfaceStorageProvider::SwapBuffers(
109    const gfx::Size& size, float scale_factor) {
110  // The browser compositor will throttle itself, so we are free to unblock the
111  // context immediately. Make sure that the browser is doing its throttling
112  // appropriately by ensuring that the previous swap was acknowledged before
113  // we get another swap.
114  DCHECK(pending_swapped_surfaces_.empty());
115  pending_swapped_surfaces_.push_back(io_surface_);
116
117  transport_surface_->SendSwapBuffers(
118      SurfaceHandleFromIOSurfaceID(io_surface_id_), size, scale_factor);
119}
120
121void IOSurfaceStorageProvider::WillWriteToBackbuffer() {
122}
123
124void IOSurfaceStorageProvider::DiscardBackbuffer() {
125}
126
127void IOSurfaceStorageProvider::SwapBuffersAckedByBrowser() {
128  DCHECK(!pending_swapped_surfaces_.empty());
129  pending_swapped_surfaces_.pop_front();
130}
131
132}  //  namespace content
133