blob: 28713602e6a7c255ec1defdcc3205968e705e9fb [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 "base/mac/scoped_nsautorelease_pool.h"
#include "ui/gl/gl_surface_ios.h"
#include "ui/gl/gl_context.h"
#include "ui/gl/gl_enums.h"
#include "base/logging.h"
#import <OpenGLES/ES2/gl.h>
#import <QuartzCore/CAEAGLLayer.h>
namespace gfx {
#define WIDGET_AS_LAYER (reinterpret_cast<CAEAGLLayer*>(widget_))
#define CAST_CONTEXT(c) (reinterpret_cast<EAGLContext*>((c)))
GLSurfaceIOS::GLSurfaceIOS(gfx::AcceleratedWidget widget)
: widget_(widget),
framebuffer_(GL_NONE),
colorbuffer_(GL_NONE),
last_configured_size_(),
framebuffer_setup_complete_(false) {
}
#ifndef NDEBUG
static void GLSurfaceIOS_AssertFramebufferCompleteness(void) {
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
DLOG_IF(FATAL, status != GL_FRAMEBUFFER_COMPLETE)
<< "Framebuffer incomplete on GLSurfaceIOS::MakeCurrent: "
<< GLEnums::GetStringEnum(status);
}
#else
#define GLSurfaceIOS_AssertFramebufferCompleteness(...)
#endif
bool GLSurfaceIOS::OnMakeCurrent(GLContext* context) {
Size new_size = GetSize();
if (new_size == last_configured_size_) {
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_);
GLSurfaceIOS_AssertFramebufferCompleteness();
return true;
}
base::mac::ScopedNSAutoreleasePool pool;
SetupFramebufferIfNecessary();
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_);
glBindRenderbuffer(GL_RENDERBUFFER, colorbuffer_);
DCHECK(glGetError() == GL_NO_ERROR);
auto context_handle = context->GetHandle();
DCHECK(context_handle);
BOOL res = [CAST_CONTEXT(context_handle) renderbufferStorage:GL_RENDERBUFFER
fromDrawable:WIDGET_AS_LAYER];
if (!res) {
return false;
}
last_configured_size_ = new_size;
GLSurfaceIOS_AssertFramebufferCompleteness();
return true;
}
void GLSurfaceIOS::SetupFramebufferIfNecessary() {
if (framebuffer_setup_complete_) {
return;
}
DCHECK(framebuffer_ == GL_NONE);
DCHECK(colorbuffer_ == GL_NONE);
DCHECK(widget_ != kNullAcceleratedWidget);
DCHECK(glGetError() == GL_NO_ERROR);
glGenFramebuffers(1, &framebuffer_);
DCHECK(framebuffer_ != GL_NONE);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_);
DCHECK(glGetError() == GL_NO_ERROR);
glGenRenderbuffers(1, &colorbuffer_);
DCHECK(colorbuffer_ != GL_NONE);
glBindRenderbuffer(GL_RENDERBUFFER, colorbuffer_);
DCHECK(glGetError() == GL_NO_ERROR);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_RENDERBUFFER, colorbuffer_);
DCHECK(glGetError() == GL_NO_ERROR);
WIDGET_AS_LAYER.drawableProperties = @{
kEAGLDrawablePropertyColorFormat : kEAGLColorFormatRGBA8,
kEAGLDrawablePropertyRetainedBacking : @(NO),
};
framebuffer_setup_complete_ = true;
}
bool GLSurfaceIOS::SwapBuffers() {
glBindRenderbuffer(GL_RENDERBUFFER, colorbuffer_);
return [[EAGLContext currentContext] presentRenderbuffer:GL_RENDERBUFFER];
}
void GLSurfaceIOS::Destroy() {
DCHECK(glGetError() == GL_NO_ERROR);
glDeleteFramebuffers(1, &framebuffer_);
glDeleteRenderbuffers(1, &colorbuffer_);
DCHECK(glGetError() == GL_NO_ERROR);
}
bool GLSurfaceIOS::IsOffscreen() {
return widget_ == kNullAcceleratedWidget;
}
gfx::Size GLSurfaceIOS::GetSize() {
CGSize layer_size = WIDGET_AS_LAYER.bounds.size;
return Size(layer_size.width, layer_size.height);
}
void* GLSurfaceIOS::GetHandle() {
return (void*)widget_;
}
bool GLSurface::InitializeOneOffInternal() {
// On EGL, this method is used to perfom one-time initialization tasks like
// initializing the display, setting up config lists, etc. There is no such
// setup on iOS.
return true;
}
// static
scoped_refptr<GLSurface> GLSurface::CreateViewGLSurface(
gfx::AcceleratedWidget window) {
DCHECK(window != kNullAcceleratedWidget);
scoped_refptr<GLSurfaceIOS> surface = new GLSurfaceIOS(window);
if (!surface->Initialize())
return NULL;
return surface;
}
} // namespace gfx