This source file includes following definitions.
- fbo_
- Initialize
- Destroy
- SwapBuffers
- AddBooleanValue
- AddIntegerValue
- CreateTexture
- AllocateRenderBuffers
- SetupFrameBufferObject
- ClampToValidDimensions
- MakeCurrent
- Clear
- SetSurfaceSize
- GetSurfaceId
#include "ui/surface/accelerated_surface_mac.h"
#include "base/logging.h"
#include "base/mac/scoped_cftyperef.h"
#include "ui/gfx/rect.h"
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_context.h"
#include "ui/gl/gl_implementation.h"
#include "ui/gl/gl_surface.h"
#include "ui/gl/io_surface_support_mac.h"
#include "ui/gl/scoped_make_current.h"
AcceleratedSurface::AcceleratedSurface()
: io_surface_id_(0),
allocate_fbo_(false),
texture_(0),
fbo_(0) {
}
AcceleratedSurface::~AcceleratedSurface() {}
bool AcceleratedSurface::Initialize(
gfx::GLContext* share_context,
bool allocate_fbo,
gfx::GpuPreference gpu_preference) {
allocate_fbo_ = allocate_fbo;
DCHECK_NE(gfx::GetGLImplementation(), gfx::kGLImplementationNone);
if (gfx::GetGLImplementation() != gfx::kGLImplementationDesktopGL &&
gfx::GetGLImplementation() != gfx::kGLImplementationAppleGL)
return false;
gl_surface_ = gfx::GLSurface::CreateOffscreenGLSurface(gfx::Size(1, 1));
if (!gl_surface_.get()) {
Destroy();
return false;
}
gfx::GLShareGroup* share_group =
share_context ? share_context->share_group() : NULL;
gl_context_ = gfx::GLContext::CreateGLContext(
share_group,
gl_surface_.get(),
gpu_preference);
if (!gl_context_.get()) {
Destroy();
return false;
}
return true;
}
void AcceleratedSurface::Destroy() {
gl_context_ = NULL;
gl_surface_ = NULL;
}
void AcceleratedSurface::SwapBuffers() {
if (io_surface_.get() != NULL) {
if (allocate_fbo_) {
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo_);
glFlush();
} else {
GLint current_texture = 0;
GLenum target_binding = GL_TEXTURE_BINDING_RECTANGLE_ARB;
GLenum target = GL_TEXTURE_RECTANGLE_ARB;
glGetIntegerv(target_binding, ¤t_texture);
glBindTexture(target, texture_);
glCopyTexSubImage2D(target, 0,
0, 0,
0, 0,
real_surface_size_.width(),
real_surface_size_.height());
glBindTexture(target, current_texture);
glFlush();
}
}
}
static void AddBooleanValue(CFMutableDictionaryRef dictionary,
const CFStringRef key,
bool value) {
CFDictionaryAddValue(dictionary, key,
(value ? kCFBooleanTrue : kCFBooleanFalse));
}
static void AddIntegerValue(CFMutableDictionaryRef dictionary,
const CFStringRef key,
int32 value) {
base::ScopedCFTypeRef<CFNumberRef> number(
CFNumberCreate(NULL, kCFNumberSInt32Type, &value));
CFDictionaryAddValue(dictionary, key, number.get());
}
static GLuint CreateTexture(GLenum target) {
GLuint texture = 0;
glGenTextures(1, &texture);
glBindTexture(target, texture);
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
return texture;
}
void AcceleratedSurface::AllocateRenderBuffers(GLenum target,
const gfx::Size& size) {
if (!texture_) {
texture_ = CreateTexture(target);
glGenFramebuffersEXT(1, &fbo_);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo_);
}
glBindTexture(target, texture_);
}
bool AcceleratedSurface::SetupFrameBufferObject(GLenum target) {
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo_);
GLenum fbo_status;
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
GL_COLOR_ATTACHMENT0_EXT,
target,
texture_,
0);
fbo_status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
return fbo_status == GL_FRAMEBUFFER_COMPLETE_EXT;
}
gfx::Size AcceleratedSurface::ClampToValidDimensions(const gfx::Size& size) {
return gfx::Size(std::max(size.width(), 1), std::max(size.height(), 1));
}
bool AcceleratedSurface::MakeCurrent() {
if (!gl_context_.get())
return false;
return gl_context_->MakeCurrent(gl_surface_.get());
}
void AcceleratedSurface::Clear(const gfx::Rect& rect) {
DCHECK(gl_context_->IsCurrent(gl_surface_.get()));
glClearColor(0, 0, 0, 0);
glViewport(0, 0, rect.width(), rect.height());
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, rect.width(), 0, rect.height(), -1, 1);
glClear(GL_COLOR_BUFFER_BIT);
}
uint32 AcceleratedSurface::SetSurfaceSize(const gfx::Size& size) {
if (surface_size_ == size) {
return 0;
}
if (gfx::GetGLImplementation() != gfx::kGLImplementationDesktopGL)
return 0;
IOSurfaceSupport* io_surface_support = IOSurfaceSupport::Initialize();
if (!io_surface_support)
return 0;
ui::ScopedMakeCurrent make_current(gl_context_.get(), gl_surface_.get());
if (!make_current.Succeeded())
return 0;
gfx::Size clamped_size = ClampToValidDimensions(size);
GLenum target = GL_TEXTURE_RECTANGLE_ARB;
if (allocate_fbo_) {
AllocateRenderBuffers(target, clamped_size);
} else if (!texture_) {
texture_ = CreateTexture(target);
}
base::ScopedCFTypeRef<CFMutableDictionaryRef> properties;
properties.reset(CFDictionaryCreateMutable(kCFAllocatorDefault,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks));
AddIntegerValue(properties,
io_surface_support->GetKIOSurfaceWidth(),
clamped_size.width());
AddIntegerValue(properties,
io_surface_support->GetKIOSurfaceHeight(),
clamped_size.height());
AddIntegerValue(properties,
io_surface_support->GetKIOSurfaceBytesPerElement(), 4);
AddBooleanValue(properties,
io_surface_support->GetKIOSurfaceIsGlobal(), true);
io_surface_.reset(io_surface_support->IOSurfaceCreate(properties));
GLuint plane = 0;
CGLError error = io_surface_support->CGLTexImageIOSurface2D(
static_cast<CGLContextObj>(gl_context_->GetHandle()),
target,
GL_RGBA,
clamped_size.width(),
clamped_size.height(),
GL_BGRA,
GL_UNSIGNED_INT_8_8_8_8_REV,
io_surface_.get(),
plane);
if (error != kCGLNoError) {
DLOG(ERROR) << "CGL error " << error << " during CGLTexImageIOSurface2D";
}
if (allocate_fbo_) {
if (!SetupFrameBufferObject(target)) {
DLOG(ERROR) << "Failed to set up frame buffer object";
}
}
surface_size_ = size;
real_surface_size_ = clamped_size;
io_surface_id_ = io_surface_support->IOSurfaceGetID(io_surface_);
return io_surface_id_;
}
uint32 AcceleratedSurface::GetSurfaceId() {
return io_surface_id_;
}