blob: 2b61810884f4a1eea7472a57f59504f7f5db41ce [file] [log] [blame]
// Copyright 2014 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/common/gpu/image_transport_surface_iosurface_mac.h"
#include "content/common/gpu/gpu_messages.h"
#include "ui/accelerated_widget_mac/surface_handle_types.h"
namespace content {
namespace {
// IOSurface dimensions will be rounded up to a multiple of this value in order
// to reduce memory thrashing during resize. This must be a power of 2.
const uint32 kIOSurfaceDimensionRoundup = 64;
int RoundUpSurfaceDimension(int number) {
DCHECK(number >= 0);
// Cast into unsigned space for portable bitwise ops.
uint32 unsigned_number = static_cast<uint32>(number);
uint32 roundup_sub_1 = kIOSurfaceDimensionRoundup - 1;
unsigned_number = (unsigned_number + roundup_sub_1) & ~roundup_sub_1;
return static_cast<int>(unsigned_number);
}
void AddBooleanValue(CFMutableDictionaryRef dictionary,
const CFStringRef key,
bool value) {
CFDictionaryAddValue(dictionary, key,
(value ? kCFBooleanTrue : kCFBooleanFalse));
}
void AddIntegerValue(CFMutableDictionaryRef dictionary,
const CFStringRef key,
int32 value) {
base::ScopedCFTypeRef<CFNumberRef> number(
CFNumberCreate(NULL, kCFNumberSInt32Type, &value));
CFDictionaryAddValue(dictionary, key, number.get());
}
} // namespace
IOSurfaceStorageProvider::IOSurfaceStorageProvider(
ImageTransportSurfaceFBO* transport_surface)
: transport_surface_(transport_surface),
frame_scale_factor_(1) {}
IOSurfaceStorageProvider::~IOSurfaceStorageProvider() {
DCHECK(!io_surface_);
}
gfx::Size IOSurfaceStorageProvider::GetRoundedSize(gfx::Size size) {
return gfx::Size(RoundUpSurfaceDimension(size.width()),
RoundUpSurfaceDimension(size.height()));
}
bool IOSurfaceStorageProvider::AllocateColorBufferStorage(
CGLContextObj context, const base::Closure& context_dirtied_callback,
GLuint texture, gfx::Size pixel_size, float scale_factor) {
// Allocate a new IOSurface, which is the GPU resource that can be
// shared across processes.
base::ScopedCFTypeRef<CFMutableDictionaryRef> properties;
properties.reset(CFDictionaryCreateMutable(kCFAllocatorDefault,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks));
AddIntegerValue(properties,
kIOSurfaceWidth,
pixel_size.width());
AddIntegerValue(properties,
kIOSurfaceHeight,
pixel_size.height());
AddIntegerValue(properties,
kIOSurfaceBytesPerElement, 4);
AddBooleanValue(properties,
kIOSurfaceIsGlobal, true);
// I believe we should be able to unreference the IOSurfaces without
// synchronizing with the browser process because they are
// ultimately reference counted by the operating system.
io_surface_.reset(IOSurfaceCreate(properties));
io_surface_id_ = IOSurfaceGetID(io_surface_);
// Don't think we need to identify a plane.
GLuint plane = 0;
CGLError cglerror = CGLTexImageIOSurface2D(
context,
GL_TEXTURE_RECTANGLE_ARB,
GL_RGBA,
pixel_size.width(),
pixel_size.height(),
GL_BGRA,
GL_UNSIGNED_INT_8_8_8_8_REV,
io_surface_.get(),
plane);
if (cglerror != kCGLNoError) {
DLOG(ERROR) << "CGLTexImageIOSurface2D failed with CGL error: " << cglerror;
return false;
}
glFlush();
return true;
}
void IOSurfaceStorageProvider::FreeColorBufferStorage() {
io_surface_.reset();
io_surface_id_ = 0;
}
void IOSurfaceStorageProvider::FrameSizeChanged(const gfx::Size& pixel_size,
float scale_factor) {
frame_pixel_size_ = pixel_size;
frame_scale_factor_ = scale_factor;
}
void IOSurfaceStorageProvider::SwapBuffers() {
// The browser compositor will throttle itself, so we are free to unblock the
// context immediately. Make sure that the browser is doing its throttling
// appropriately by ensuring that the previous swap was acknowledged before
// we get another swap.
DCHECK(pending_swapped_surfaces_.empty());
pending_swapped_surfaces_.push_back(io_surface_);
transport_surface_->SendSwapBuffers(
ui::SurfaceHandleFromIOSurfaceID(io_surface_id_),
frame_pixel_size_,
frame_scale_factor_);
}
void IOSurfaceStorageProvider::WillWriteToBackbuffer() {
}
void IOSurfaceStorageProvider::DiscardBackbuffer() {
}
void IOSurfaceStorageProvider::SwapBuffersAckedByBrowser(
bool disable_throttling) {
DCHECK(!pending_swapped_surfaces_.empty());
pending_swapped_surfaces_.pop_front();
}
} // namespace content