mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
- Add missing dependencies caught by gn's new stricter checker - Update opentype code to use new OTS API. This code is updated from HEAD Blink. - Add base dependency to wtf to avoid redefining marcos from base/macros.h - Update callers of various base string utility functions to use base namespace.
542 lines
16 KiB
C++
542 lines
16 KiB
C++
// Copyright (c) 2012 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 "ui/gl/gl_gl_api_implementation.h"
|
|
|
|
#include <algorithm>
|
|
#include <vector>
|
|
|
|
#include "base/command_line.h"
|
|
#include "base/strings/string_split.h"
|
|
#include "base/strings/string_util.h"
|
|
#include "ui/gl/gl_context.h"
|
|
#include "ui/gl/gl_implementation.h"
|
|
#include "ui/gl/gl_state_restorer.h"
|
|
#include "ui/gl/gl_surface.h"
|
|
#include "ui/gl/gl_switches.h"
|
|
#include "ui/gl/gl_version_info.h"
|
|
|
|
namespace gfx {
|
|
|
|
// The GL Api being used. This could be g_real_gl or gl_trace_gl
|
|
static GLApi* g_gl = NULL;
|
|
// A GL Api that calls directly into the driver.
|
|
static RealGLApi* g_real_gl = NULL;
|
|
// A GL Api that does nothing but warn about illegal GL calls without a context
|
|
// current.
|
|
static NoContextGLApi* g_no_context_gl = NULL;
|
|
// A GL Api that calls TRACE and then calls another GL api.
|
|
static TraceGLApi* g_trace_gl = NULL;
|
|
// GL version used when initializing dynamic bindings.
|
|
static GLVersionInfo* g_version_info = NULL;
|
|
|
|
namespace {
|
|
|
|
static inline GLenum GetInternalFormat(GLenum internal_format) {
|
|
if (gfx::GetGLImplementation() != gfx::kGLImplementationEGLGLES2) {
|
|
if (internal_format == GL_BGRA_EXT || internal_format == GL_BGRA8_EXT)
|
|
return GL_RGBA8;
|
|
}
|
|
return internal_format;
|
|
}
|
|
|
|
// TODO(epenner): Could the above function be merged into this and removed?
|
|
static inline GLenum GetTexInternalFormat(GLenum internal_format,
|
|
GLenum format,
|
|
GLenum type) {
|
|
GLenum gl_internal_format = GetInternalFormat(internal_format);
|
|
|
|
// g_version_info must be initialized when this function is bound.
|
|
DCHECK(gfx::g_version_info);
|
|
if (gfx::g_version_info->is_es3) {
|
|
if (format == GL_RED_EXT) {
|
|
switch (type) {
|
|
case GL_UNSIGNED_BYTE:
|
|
gl_internal_format = GL_R8_EXT;
|
|
break;
|
|
case GL_HALF_FLOAT_OES:
|
|
gl_internal_format = GL_R16F_EXT;
|
|
break;
|
|
case GL_FLOAT:
|
|
gl_internal_format = GL_R32F_EXT;
|
|
break;
|
|
default:
|
|
NOTREACHED();
|
|
break;
|
|
}
|
|
return gl_internal_format;
|
|
} else if (format == GL_RG_EXT) {
|
|
switch (type) {
|
|
case GL_UNSIGNED_BYTE:
|
|
gl_internal_format = GL_RG8_EXT;
|
|
break;
|
|
case GL_HALF_FLOAT_OES:
|
|
gl_internal_format = GL_RG16F_EXT;
|
|
break;
|
|
case GL_FLOAT:
|
|
gl_internal_format = GL_RG32F_EXT;
|
|
break;
|
|
default:
|
|
NOTREACHED();
|
|
break;
|
|
}
|
|
return gl_internal_format;
|
|
}
|
|
}
|
|
|
|
if (type == GL_FLOAT && gfx::g_version_info->is_angle &&
|
|
gfx::g_version_info->is_es && gfx::g_version_info->major_version == 2) {
|
|
// It's possible that the texture is using a sized internal format, and
|
|
// ANGLE exposing GLES2 API doesn't support those.
|
|
// TODO(oetuaho@nvidia.com): Remove these conversions once ANGLE has the
|
|
// support.
|
|
// http://code.google.com/p/angleproject/issues/detail?id=556
|
|
switch (format) {
|
|
case GL_RGBA:
|
|
gl_internal_format = GL_RGBA;
|
|
break;
|
|
case GL_RGB:
|
|
gl_internal_format = GL_RGB;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (gfx::g_version_info->is_es)
|
|
return gl_internal_format;
|
|
|
|
if (type == GL_FLOAT) {
|
|
switch (format) {
|
|
case GL_RGBA:
|
|
gl_internal_format = GL_RGBA32F_ARB;
|
|
break;
|
|
case GL_RGB:
|
|
gl_internal_format = GL_RGB32F_ARB;
|
|
break;
|
|
case GL_LUMINANCE_ALPHA:
|
|
gl_internal_format = GL_LUMINANCE_ALPHA32F_ARB;
|
|
break;
|
|
case GL_LUMINANCE:
|
|
gl_internal_format = GL_LUMINANCE32F_ARB;
|
|
break;
|
|
case GL_ALPHA:
|
|
gl_internal_format = GL_ALPHA32F_ARB;
|
|
break;
|
|
default:
|
|
NOTREACHED();
|
|
break;
|
|
}
|
|
} else if (type == GL_HALF_FLOAT_OES) {
|
|
switch (format) {
|
|
case GL_RGBA:
|
|
gl_internal_format = GL_RGBA16F_ARB;
|
|
break;
|
|
case GL_RGB:
|
|
gl_internal_format = GL_RGB16F_ARB;
|
|
break;
|
|
case GL_LUMINANCE_ALPHA:
|
|
gl_internal_format = GL_LUMINANCE_ALPHA16F_ARB;
|
|
break;
|
|
case GL_LUMINANCE:
|
|
gl_internal_format = GL_LUMINANCE16F_ARB;
|
|
break;
|
|
case GL_ALPHA:
|
|
gl_internal_format = GL_ALPHA16F_ARB;
|
|
break;
|
|
default:
|
|
NOTREACHED();
|
|
break;
|
|
}
|
|
}
|
|
return gl_internal_format;
|
|
}
|
|
|
|
static inline GLenum GetTexType(GLenum type) {
|
|
if (gfx::GetGLImplementation() != gfx::kGLImplementationEGLGLES2) {
|
|
if (type == GL_HALF_FLOAT_OES)
|
|
return GL_HALF_FLOAT_ARB;
|
|
}
|
|
return type;
|
|
}
|
|
|
|
static void GL_BINDING_CALL CustomTexImage2D(
|
|
GLenum target, GLint level, GLint internalformat,
|
|
GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type,
|
|
const void* pixels) {
|
|
GLenum gl_internal_format = GetTexInternalFormat(
|
|
internalformat, format, type);
|
|
GLenum gl_type = GetTexType(type);
|
|
g_driver_gl.orig_fn.glTexImage2DFn(
|
|
target, level, gl_internal_format, width, height, border, format, gl_type,
|
|
pixels);
|
|
}
|
|
|
|
static void GL_BINDING_CALL CustomTexSubImage2D(
|
|
GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
|
|
GLsizei height, GLenum format, GLenum type, const void* pixels) {
|
|
GLenum gl_type = GetTexType(type);
|
|
g_driver_gl.orig_fn.glTexSubImage2DFn(
|
|
target, level, xoffset, yoffset, width, height, format, gl_type, pixels);
|
|
}
|
|
|
|
static void GL_BINDING_CALL CustomTexStorage2DEXT(
|
|
GLenum target, GLsizei levels, GLenum internalformat, GLsizei width,
|
|
GLsizei height) {
|
|
GLenum gl_internal_format = GetInternalFormat(internalformat);
|
|
g_driver_gl.orig_fn.glTexStorage2DEXTFn(
|
|
target, levels, gl_internal_format, width, height);
|
|
}
|
|
|
|
static void GL_BINDING_CALL CustomRenderbufferStorageEXT(
|
|
GLenum target, GLenum internalformat, GLsizei width, GLsizei height) {
|
|
GLenum gl_internal_format = GetInternalFormat(internalformat);
|
|
g_driver_gl.orig_fn.glRenderbufferStorageEXTFn(
|
|
target, gl_internal_format, width, height);
|
|
}
|
|
|
|
// The ANGLE and IMG variants of glRenderbufferStorageMultisample currently do
|
|
// not support BGRA render buffers so only the EXT one is customized. If
|
|
// GL_CHROMIUM_renderbuffer_format_BGRA8888 support is added to ANGLE then the
|
|
// ANGLE version should also be customized.
|
|
static void GL_BINDING_CALL CustomRenderbufferStorageMultisampleEXT(
|
|
GLenum target, GLsizei samples, GLenum internalformat, GLsizei width,
|
|
GLsizei height) {
|
|
GLenum gl_internal_format = GetInternalFormat(internalformat);
|
|
g_driver_gl.orig_fn.glRenderbufferStorageMultisampleEXTFn(
|
|
target, samples, gl_internal_format, width, height);
|
|
}
|
|
|
|
} // anonymous namespace
|
|
|
|
void DriverGL::InitializeCustomDynamicBindings(GLContext* context) {
|
|
InitializeDynamicBindings(context);
|
|
|
|
DCHECK(orig_fn.glTexImage2DFn == NULL);
|
|
orig_fn.glTexImage2DFn = fn.glTexImage2DFn;
|
|
fn.glTexImage2DFn =
|
|
reinterpret_cast<glTexImage2DProc>(CustomTexImage2D);
|
|
|
|
DCHECK(orig_fn.glTexSubImage2DFn == NULL);
|
|
orig_fn.glTexSubImage2DFn = fn.glTexSubImage2DFn;
|
|
fn.glTexSubImage2DFn =
|
|
reinterpret_cast<glTexSubImage2DProc>(CustomTexSubImage2D);
|
|
|
|
DCHECK(orig_fn.glTexStorage2DEXTFn == NULL);
|
|
orig_fn.glTexStorage2DEXTFn = fn.glTexStorage2DEXTFn;
|
|
fn.glTexStorage2DEXTFn =
|
|
reinterpret_cast<glTexStorage2DEXTProc>(CustomTexStorage2DEXT);
|
|
|
|
DCHECK(orig_fn.glRenderbufferStorageEXTFn == NULL);
|
|
orig_fn.glRenderbufferStorageEXTFn = fn.glRenderbufferStorageEXTFn;
|
|
fn.glRenderbufferStorageEXTFn =
|
|
reinterpret_cast<glRenderbufferStorageEXTProc>(
|
|
CustomRenderbufferStorageEXT);
|
|
|
|
DCHECK(orig_fn.glRenderbufferStorageMultisampleEXTFn == NULL);
|
|
orig_fn.glRenderbufferStorageMultisampleEXTFn =
|
|
fn.glRenderbufferStorageMultisampleEXTFn;
|
|
fn.glRenderbufferStorageMultisampleEXTFn =
|
|
reinterpret_cast<glRenderbufferStorageMultisampleEXTProc>(
|
|
CustomRenderbufferStorageMultisampleEXT);
|
|
}
|
|
|
|
static void GL_BINDING_CALL NullDrawClearFn(GLbitfield mask) {
|
|
if (!g_driver_gl.null_draw_bindings_enabled)
|
|
g_driver_gl.orig_fn.glClearFn(mask);
|
|
}
|
|
|
|
static void GL_BINDING_CALL
|
|
NullDrawDrawArraysFn(GLenum mode, GLint first, GLsizei count) {
|
|
if (!g_driver_gl.null_draw_bindings_enabled)
|
|
g_driver_gl.orig_fn.glDrawArraysFn(mode, first, count);
|
|
}
|
|
|
|
static void GL_BINDING_CALL NullDrawDrawElementsFn(GLenum mode,
|
|
GLsizei count,
|
|
GLenum type,
|
|
const void* indices) {
|
|
if (!g_driver_gl.null_draw_bindings_enabled)
|
|
g_driver_gl.orig_fn.glDrawElementsFn(mode, count, type, indices);
|
|
}
|
|
|
|
void DriverGL::InitializeNullDrawBindings() {
|
|
DCHECK(orig_fn.glClearFn == NULL);
|
|
orig_fn.glClearFn = fn.glClearFn;
|
|
fn.glClearFn = NullDrawClearFn;
|
|
|
|
DCHECK(orig_fn.glDrawArraysFn == NULL);
|
|
orig_fn.glDrawArraysFn = fn.glDrawArraysFn;
|
|
fn.glDrawArraysFn = NullDrawDrawArraysFn;
|
|
|
|
DCHECK(orig_fn.glDrawElementsFn == NULL);
|
|
orig_fn.glDrawElementsFn = fn.glDrawElementsFn;
|
|
fn.glDrawElementsFn = NullDrawDrawElementsFn;
|
|
|
|
null_draw_bindings_enabled = true;
|
|
}
|
|
|
|
bool DriverGL::HasInitializedNullDrawBindings() {
|
|
return orig_fn.glClearFn != NULL && orig_fn.glDrawArraysFn != NULL &&
|
|
orig_fn.glDrawElementsFn != NULL;
|
|
}
|
|
|
|
bool DriverGL::SetNullDrawBindingsEnabled(bool enabled) {
|
|
DCHECK(orig_fn.glClearFn != NULL);
|
|
DCHECK(orig_fn.glDrawArraysFn != NULL);
|
|
DCHECK(orig_fn.glDrawElementsFn != NULL);
|
|
|
|
bool before = null_draw_bindings_enabled;
|
|
null_draw_bindings_enabled = enabled;
|
|
return before;
|
|
}
|
|
|
|
void InitializeStaticGLBindingsGL() {
|
|
g_current_gl_context_tls = new base::ThreadLocalPointer<GLApi>;
|
|
g_driver_gl.InitializeStaticBindings();
|
|
if (!g_real_gl) {
|
|
g_real_gl = new RealGLApi();
|
|
g_trace_gl = new TraceGLApi(g_real_gl);
|
|
g_no_context_gl = new NoContextGLApi();
|
|
}
|
|
g_real_gl->Initialize(&g_driver_gl);
|
|
g_gl = g_real_gl;
|
|
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
|
|
switches::kEnableGPUServiceTracing)) {
|
|
g_gl = g_trace_gl;
|
|
}
|
|
SetGLToRealGLApi();
|
|
}
|
|
|
|
GLApi* GetCurrentGLApi() {
|
|
return g_current_gl_context_tls->Get();
|
|
}
|
|
|
|
void SetGLApi(GLApi* api) {
|
|
g_current_gl_context_tls->Set(api);
|
|
}
|
|
|
|
void SetGLToRealGLApi() {
|
|
SetGLApi(g_gl);
|
|
}
|
|
|
|
void SetGLApiToNoContext() {
|
|
SetGLApi(g_no_context_gl);
|
|
}
|
|
|
|
const GLVersionInfo* GetGLVersionInfo() {
|
|
return g_version_info;
|
|
}
|
|
|
|
void InitializeDynamicGLBindingsGL(GLContext* context) {
|
|
g_driver_gl.InitializeCustomDynamicBindings(context);
|
|
DCHECK(context && context->IsCurrent(NULL) && !g_version_info);
|
|
g_version_info = new GLVersionInfo(context->GetGLVersion().c_str(),
|
|
context->GetGLRenderer().c_str());
|
|
}
|
|
|
|
void InitializeDebugGLBindingsGL() {
|
|
g_driver_gl.InitializeDebugBindings();
|
|
}
|
|
|
|
void InitializeNullDrawGLBindingsGL() {
|
|
g_driver_gl.InitializeNullDrawBindings();
|
|
}
|
|
|
|
bool HasInitializedNullDrawGLBindingsGL() {
|
|
return g_driver_gl.HasInitializedNullDrawBindings();
|
|
}
|
|
|
|
bool SetNullDrawGLBindingsEnabledGL(bool enabled) {
|
|
return g_driver_gl.SetNullDrawBindingsEnabled(enabled);
|
|
}
|
|
|
|
void ClearGLBindingsGL() {
|
|
if (g_real_gl) {
|
|
delete g_real_gl;
|
|
g_real_gl = NULL;
|
|
}
|
|
if (g_trace_gl) {
|
|
delete g_trace_gl;
|
|
g_trace_gl = NULL;
|
|
}
|
|
if (g_no_context_gl) {
|
|
delete g_no_context_gl;
|
|
g_no_context_gl = NULL;
|
|
}
|
|
g_gl = NULL;
|
|
g_driver_gl.ClearBindings();
|
|
if (g_current_gl_context_tls) {
|
|
delete g_current_gl_context_tls;
|
|
g_current_gl_context_tls = NULL;
|
|
}
|
|
if (g_version_info) {
|
|
delete g_version_info;
|
|
g_version_info = NULL;
|
|
}
|
|
}
|
|
|
|
GLApi::GLApi() {
|
|
}
|
|
|
|
GLApi::~GLApi() {
|
|
if (GetCurrentGLApi() == this)
|
|
SetGLApi(NULL);
|
|
}
|
|
|
|
GLApiBase::GLApiBase()
|
|
: driver_(NULL) {
|
|
}
|
|
|
|
GLApiBase::~GLApiBase() {
|
|
}
|
|
|
|
void GLApiBase::InitializeBase(DriverGL* driver) {
|
|
driver_ = driver;
|
|
}
|
|
|
|
RealGLApi::RealGLApi() {
|
|
}
|
|
|
|
RealGLApi::~RealGLApi() {
|
|
}
|
|
|
|
void RealGLApi::Initialize(DriverGL* driver) {
|
|
InitializeBase(driver);
|
|
}
|
|
|
|
void RealGLApi::glFlushFn() {
|
|
GLApiBase::glFlushFn();
|
|
}
|
|
|
|
void RealGLApi::glFinishFn() {
|
|
GLApiBase::glFinishFn();
|
|
}
|
|
|
|
TraceGLApi::~TraceGLApi() {
|
|
}
|
|
|
|
NoContextGLApi::NoContextGLApi() {
|
|
}
|
|
|
|
NoContextGLApi::~NoContextGLApi() {
|
|
}
|
|
|
|
VirtualGLApi::VirtualGLApi()
|
|
: real_context_(NULL),
|
|
current_context_(NULL) {
|
|
}
|
|
|
|
VirtualGLApi::~VirtualGLApi() {
|
|
}
|
|
|
|
void VirtualGLApi::Initialize(DriverGL* driver, GLContext* real_context) {
|
|
InitializeBase(driver);
|
|
real_context_ = real_context;
|
|
|
|
DCHECK(real_context->IsCurrent(NULL));
|
|
std::string ext_string(
|
|
reinterpret_cast<const char*>(driver_->fn.glGetStringFn(GL_EXTENSIONS)));
|
|
std::vector<std::string> ext = base::SplitString(
|
|
ext_string, " ", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
|
|
|
|
std::vector<std::string>::iterator it;
|
|
// We can't support GL_EXT_occlusion_query_boolean which is
|
|
// based on GL_ARB_occlusion_query without a lot of work virtualizing
|
|
// queries.
|
|
it = std::find(ext.begin(), ext.end(), "GL_EXT_occlusion_query_boolean");
|
|
if (it != ext.end())
|
|
ext.erase(it);
|
|
|
|
extensions_ = base::JoinString(ext, " ");
|
|
}
|
|
|
|
bool VirtualGLApi::MakeCurrent(GLContext* virtual_context, GLSurface* surface) {
|
|
bool switched_contexts = g_current_gl_context_tls->Get() != this;
|
|
GLSurface* current_surface = GLSurface::GetCurrent();
|
|
if (switched_contexts || surface != current_surface) {
|
|
// MakeCurrent 'lite' path that avoids potentially expensive MakeCurrent()
|
|
// calls if the GLSurface uses the same underlying surface or renders to
|
|
// an FBO.
|
|
if (switched_contexts || !current_surface ||
|
|
!virtual_context->IsCurrent(surface)) {
|
|
if (!real_context_->MakeCurrent(surface)) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool state_dirtied_externally = real_context_->GetStateWasDirtiedExternally();
|
|
real_context_->SetStateWasDirtiedExternally(false);
|
|
|
|
DCHECK_EQ(real_context_, GLContext::GetRealCurrent());
|
|
DCHECK(real_context_->IsCurrent(NULL));
|
|
DCHECK(virtual_context->IsCurrent(surface));
|
|
|
|
if (state_dirtied_externally || switched_contexts ||
|
|
virtual_context != current_context_) {
|
|
#if DCHECK_IS_ON()
|
|
GLenum error = glGetErrorFn();
|
|
// Accepting a context loss error here enables using debug mode to work on
|
|
// context loss handling in virtual context mode.
|
|
// There should be no other errors from the previous context leaking into
|
|
// the new context.
|
|
DCHECK(error == GL_NO_ERROR || error == GL_CONTEXT_LOST_KHR);
|
|
#endif
|
|
|
|
// Set all state that is different from the real state
|
|
GLApi* temp = GetCurrentGLApi();
|
|
SetGLToRealGLApi();
|
|
if (virtual_context->GetGLStateRestorer()->IsInitialized()) {
|
|
virtual_context->GetGLStateRestorer()->RestoreState(
|
|
(current_context_ && !state_dirtied_externally && !switched_contexts)
|
|
? current_context_->GetGLStateRestorer()
|
|
: NULL);
|
|
}
|
|
SetGLApi(temp);
|
|
current_context_ = virtual_context;
|
|
}
|
|
SetGLApi(this);
|
|
|
|
virtual_context->SetCurrent(surface);
|
|
if (!surface->OnMakeCurrent(virtual_context)) {
|
|
LOG(ERROR) << "Could not make GLSurface current.";
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void VirtualGLApi::OnReleaseVirtuallyCurrent(GLContext* virtual_context) {
|
|
if (current_context_ == virtual_context)
|
|
current_context_ = NULL;
|
|
}
|
|
|
|
const GLubyte* VirtualGLApi::glGetStringFn(GLenum name) {
|
|
switch (name) {
|
|
case GL_EXTENSIONS:
|
|
return reinterpret_cast<const GLubyte*>(extensions_.c_str());
|
|
default:
|
|
return driver_->fn.glGetStringFn(name);
|
|
}
|
|
}
|
|
|
|
void VirtualGLApi::glFlushFn() {
|
|
GLApiBase::glFlushFn();
|
|
}
|
|
|
|
void VirtualGLApi::glFinishFn() {
|
|
GLApiBase::glFinishFn();
|
|
}
|
|
|
|
ScopedSetGLToRealGLApi::ScopedSetGLToRealGLApi()
|
|
: old_gl_api_(GetCurrentGLApi()) {
|
|
SetGLToRealGLApi();
|
|
}
|
|
|
|
ScopedSetGLToRealGLApi::~ScopedSetGLToRealGLApi() {
|
|
SetGLApi(old_gl_api_);
|
|
}
|
|
|
|
} // namespace gfx
|