Merge pull request #2547 from abarth/glfw

Add GLFW support to //ui/gl
This commit is contained in:
Adam Barth 2016-03-24 16:02:48 -07:00
commit 76dfd240be
12 changed files with 525 additions and 9 deletions

View File

@ -103,6 +103,9 @@ config("feature_flags") {
if (use_aura) {
defines += [ "USE_AURA=1" ]
}
if (use_glfw) {
defines += [ "USE_GLFW=1" ]
}
if (use_pango) {
defines += [ "USE_PANGO=1" ]
}

View File

@ -20,6 +20,12 @@ declare_args() {
# that does not require X11.
use_ozone = false
# Indicates if GLFW is enabled. GLFW is an abstraction layer for the
# windowing system and OpenGL rendering, providing cross-platform support
# for creating windows and OpenGL surfaces and contexts, and handling
# window system events and input.
use_glfw = false
# Support ChromeOS touchpad gestures with ozone.
use_evdev_gestures = false
@ -51,7 +57,7 @@ ui_compositor_image_transport = use_aura && is_linux
use_default_render_theme = use_aura || is_linux
# Indicates if the UI toolkit depends on X11.
use_x11 = is_linux && !use_ozone
use_x11 = is_linux && !use_ozone && !use_glfw
use_ozone_evdev = use_ozone

View File

@ -2,6 +2,10 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
config("glfw_config") {
include_dirs = [ "//third_party/glfw/include" ]
}
source_set("glfw") {
sources = [
"src/context.c",
@ -26,10 +30,6 @@ source_set("glfw") {
"src/xkb_unicode.h",
]
include_dirs = [
"include",
]
configs -= [ "//build/config/compiler:chromium_code" ]
configs += [ "//build/config/compiler:no_chromium_code" ]
@ -39,6 +39,8 @@ source_set("glfw") {
"//build/config/linux:xinerama",
]
public_configs = [ ":glfw_config" ]
defines = [
"_GLFW_USE_OPENGL",
"_GLFW_X11",

View File

@ -61,6 +61,10 @@ class ViewAndroid;
#endif
class SkBitmap;
#if defined(USE_GLFW)
struct GLFWwindow;
#endif
namespace gfx {
#if defined(OS_LINUX)
@ -148,7 +152,10 @@ struct GLSurfaceHandle {
};
// AcceleratedWidget provides a surface to compositors to paint pixels.
#if defined(USE_X11)
#if defined(USE_GLFW)
typedef GLFWwindow* AcceleratedWidget;
const AcceleratedWidget kNullAcceleratedWidget = 0;
#elif defined(USE_X11)
typedef unsigned long AcceleratedWidget;
const AcceleratedWidget kNullAcceleratedWidget = 0;
#elif defined(OS_ANDROID)

View File

@ -81,6 +81,17 @@ source_set("gl") {
if (is_linux) {
deps += [ "//third_party/libevent" ]
}
if (use_glfw) {
sources += [
"gl_context_glfw.cc",
"gl_context_glfw.h",
"gl_implementation_glfw.cc",
"gl_surface_glfw.cc",
"gl_surface_glfw.h",
]
deps += [ "//third_party/glfw" ]
}
if (use_x11) {
sources += [
"gl_context_osmesa_x11.cc",

View File

@ -15,7 +15,7 @@
#include "build/build_config.h"
#if defined(OS_ANDROID) || defined(USE_X11)
#if defined(OS_ANDROID) || defined(USE_X11) || defined(USE_GLFW)
#include <EGL/egl.h>
#include <EGL/eglext.h>
#endif
@ -340,7 +340,10 @@ struct GL_EXPORT DriverOSMESA {
static std::string GetPlatformExtensions();
};
#if !defined(OS_MACOSX)
// TODO(dalyj): Clean up the conditionals here (there should be a generic
// "USE_EGL"-type define for this, particularly since GLFW is happy to use
// EGL in some configurations).
#if !defined(OS_MACOSX) && !defined(USE_GLFW)
struct GL_EXPORT DriverEGL {
void InitializeStaticBindings();
void InitializeDebugBindings();

175
ui/gl/gl_context_glfw.cc Normal file
View File

@ -0,0 +1,175 @@
// Copyright 2016 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_context_glfw.h"
#include <GLFW/glfw3.h>
#include "base/command_line.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_context_stub.h"
#include "ui/gl/gl_surface_glfw.h"
namespace gfx {
GLContextGlfw::GLContextGlfw(GLShareGroup* share_group)
: GLContextReal(share_group),
surface_(NULL),
context_(NULL),
unbind_fbo_on_makecurrent_(false),
swap_interval_(1) {
}
scoped_refptr<GLContext> GLContext::CreateGLContext(
GLShareGroup* share_group,
GLSurface* compatible_surface,
GpuPreference gpu_preference) {
TRACE_EVENT0("gpu", "GLContext::CreateGLContext");
switch (GetGLImplementation()) {
case kGLImplementationDesktopGL:
case kGLImplementationEGLGLES2: {
scoped_refptr<GLContext> context;
context = new GLContextGlfw(share_group);
if (!context->Initialize(compatible_surface, gpu_preference))
return NULL;
return context;
}
case kGLImplementationMockGL:
return new GLContextStub;
default:
NOTREACHED();
return NULL;
}
}
bool GLContextGlfw::Initialize(
GLSurface* compatible_surface, GpuPreference gpu_preference) {
DCHECK(compatible_surface);
DCHECK(!surface_);
DCHECK(!context_);
surface_ = compatible_surface;
context_ = reinterpret_cast<gfx::AcceleratedWidget>(surface_->GetHandle());
return true;
}
void GLContextGlfw::Destroy() {
if (surface_) {
surface_ = NULL;
}
if (context_) {
context_ = NULL;
}
}
bool GLContextGlfw::MakeCurrent(GLSurface* surface) {
DCHECK(surface_);
if (IsCurrent(surface))
return true;
ScopedReleaseCurrent release_current;
TRACE_EVENT2("gpu", "GLContextEGL::MakeCurrent",
"context", surface_,
"surface", surface);
if (unbind_fbo_on_makecurrent_ && glfwGetCurrentContext() != NULL) {
glBindFramebufferEXT(GL_FRAMEBUFFER, 0);
}
// Make the surface's context current.
glfwMakeContextCurrent(context_);
// Set this as soon as the context is current, since we might call into GL.
SetRealGLApi();
SetCurrent(surface);
if (!InitializeDynamicBindings()) {
return false;
}
if (!surface->OnMakeCurrent(this)) {
LOG(ERROR) << "Could not make current.";
return false;
}
surface->OnSetSwapInterval(swap_interval_);
release_current.Cancel();
return true;
}
void GLContextGlfw::SetUnbindFboOnMakeCurrent() {
unbind_fbo_on_makecurrent_ = true;
}
void GLContextGlfw::ReleaseCurrent(GLSurface* surface) {
if (!IsCurrent(surface))
return;
if (unbind_fbo_on_makecurrent_)
glBindFramebufferEXT(GL_FRAMEBUFFER, 0);
SetCurrent(NULL);
glfwMakeContextCurrent(NULL);
}
bool GLContextGlfw::IsCurrent(GLSurface* surface) {
DCHECK(surface_);
DCHECK(context_);
bool native_context_is_current = context_ == glfwGetCurrentContext();
// If our context is current then our notion of which GLContext is
// current must be correct. On the other hand, third-party code
// using OpenGL might change the current context.
DCHECK(!native_context_is_current || (GetRealCurrent() == this));
if (!native_context_is_current)
return false;
return true;
}
void* GLContextGlfw::GetHandle() {
return (void *)context_;
}
void GLContextGlfw::OnSetSwapInterval(int interval) {
DCHECK(IsCurrent(NULL) && GLSurface::GetCurrent());
glfwSwapInterval(interval);
swap_interval_ = interval;
GLSurface::GetCurrent()->OnSetSwapInterval(interval);
}
std::string GLContextGlfw::GetExtensions() {
return GLContext::GetExtensions();
}
bool GLContextGlfw::WasAllocatedUsingRobustnessExtension() {
int robust = glfwGetWindowAttrib(context_, GLFW_CONTEXT_ROBUSTNESS);
return (robust != GLFW_NO_ROBUSTNESS);
}
GLContextGlfw::~GLContextGlfw() {
Destroy();
}
#if !defined(OS_ANDROID)
bool GLContextGlfw::GetTotalGpuMemory(size_t* bytes) {
// TODO(dalyj): Unimplemented.
DCHECK(bytes);
*bytes = 0;
return false;
}
#endif
} // namespace gfx

56
ui/gl/gl_context_glfw.h Normal file
View File

@ -0,0 +1,56 @@
// Copyright 2016 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.
#ifndef UI_GL_GL_CONTEXT_GLFW_H_
#define UI_GL_GL_CONTEXT_GLFW_H_
#include <string>
#include "base/compiler_specific.h"
#include "ui/gl/gl_context.h"
#include "ui/gfx/native_widget_types.h"
typedef void* EGLContext;
typedef void* EGLDisplay;
typedef void* EGLConfig;
namespace gfx {
class GLSurface;
// Presents a GLFW window as a GLContext.
class GLContextGlfw : public GLContextReal {
public:
explicit GLContextGlfw(GLShareGroup* share_group);
// Implement GLContext.
bool Initialize(GLSurface* compatible_surface,
GpuPreference gpu_preference) override;
void Destroy() override;
bool MakeCurrent(GLSurface* surface) override;
void ReleaseCurrent(GLSurface* surface) override;
bool IsCurrent(GLSurface* surface) override;
void* GetHandle() override;
void OnSetSwapInterval(int interval) override;
std::string GetExtensions() override;
bool WasAllocatedUsingRobustnessExtension() override;
bool GetTotalGpuMemory(size_t* bytes) override;
void SetUnbindFboOnMakeCurrent() override;
protected:
~GLContextGlfw() override;
private:
GLSurface* surface_;
gfx::AcceleratedWidget context_;
bool unbind_fbo_on_makecurrent_;
int swap_interval_;
DISALLOW_COPY_AND_ASSIGN(GLContextGlfw);
};
} // namespace gfx
#endif // UI_GL_GL_CONTEXT_EGL_H_

View File

@ -0,0 +1,126 @@
// Copyright 2016 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 <GLFW/glfw3.h>
#include "base/base_paths.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/native_library.h"
#include "base/path_service.h"
#include "base/threading/thread_restrictions.h"
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_context_stub_with_extensions.h"
#include "ui/gl/gl_gl_api_implementation.h"
#include "ui/gl/gl_implementation.h"
#include "ui/gl/gl_implementation_osmesa.h"
#include "ui/gl/gl_osmesa_api_implementation.h"
namespace gfx {
void GetAllowedGLImplementations(std::vector<GLImplementation>* impls) {
impls->push_back(kGLImplementationDesktopGL);
impls->push_back(kGLImplementationEGLGLES2);
impls->push_back(kGLImplementationOSMesaGL);
}
bool InitializeStaticGLBindings(GLImplementation implementation) {
// Prevent reinitialization with a different implementation. Once the gpu
// unit tests have initialized with kGLImplementationMock, we don't want to
// later switch to another GL implementation.
DCHECK_EQ(kGLImplementationNone, GetGLImplementation());
switch (implementation) {
case kGLImplementationOSMesaGL: {
base::FilePath module_path;
if (!PathService::Get(base::DIR_MODULE, &module_path)) {
LOG(ERROR) << "PathService::Get failed.";
return false;
}
base::FilePath library_path = module_path.Append("libosmesa.so");
base::NativeLibrary library = LoadLibraryAndPrintError(library_path);
if (!library)
return false;
GLGetProcAddressProc get_proc_address =
reinterpret_cast<GLGetProcAddressProc>(
base::GetFunctionPointerFromNativeLibrary(library,
"OSMesaGetProcAddress"));
if (!get_proc_address) {
LOG(ERROR) << "OSMesaGetProcAddress not found.";
base::UnloadNativeLibrary(library);
return false;
}
SetGLGetProcAddressProc(get_proc_address);
AddGLNativeLibrary(library);
SetGLImplementation(kGLImplementationOSMesaGL);
InitializeStaticGLBindingsGL();
InitializeStaticGLBindingsOSMESA();
break;
}
case kGLImplementationDesktopGL:
case kGLImplementationEGLGLES2: {
SetGLGetProcAddressProc(
reinterpret_cast<GLGetProcAddressProc>(glfwGetProcAddress));
SetGLImplementation(implementation);
InitializeStaticGLBindingsGL();
break;
}
case kGLImplementationMockGL: {
SetGLImplementation(kGLImplementationMockGL);
InitializeStaticGLBindingsGL();
break;
}
default:
return false;
}
return true;
}
bool InitializeDynamicGLBindings(GLImplementation implementation,
GLContext* context) {
switch (implementation) {
case kGLImplementationOSMesaGL:
case kGLImplementationDesktopGL:
case kGLImplementationEGLGLES2:
InitializeDynamicGLBindingsGL(context);
break;
case kGLImplementationMockGL:
if (!context) {
scoped_refptr<GLContextStubWithExtensions> mock_context(
new GLContextStubWithExtensions());
mock_context->SetGLVersionString("3.0");
InitializeDynamicGLBindingsGL(mock_context.get());
} else
InitializeDynamicGLBindingsGL(context);
break;
default:
return false;
}
return true;
}
void InitializeDebugGLBindings() {
InitializeDebugGLBindingsGL();
}
void ClearGLBindings() {
ClearGLBindingsGL();
SetGLImplementation(kGLImplementationNone);
UnloadGLNativeLibraries();
}
bool GetGLWindowSystemBindingInfo(GLWindowSystemBindingInfo* info) {
return false;
}
} // namespace gfx

View File

@ -15,7 +15,7 @@
namespace gfx {
#if defined(OS_LINUX)
#if defined(OS_LINUX) && !defined(USE_GLFW)
// On Linux, we always use the OSMesa implementation of GL so we hardcode these
// functions here.

87
ui/gl/gl_surface_glfw.cc Normal file
View File

@ -0,0 +1,87 @@
// Copyright 2016 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_surface_glfw.h"
#include <GLFW/glfw3.h>
#include "ui/gl/gl_context.h"
#include "ui/gl/gl_enums.h"
#include "base/logging.h"
#define WIDGET_AS_VIEW (reinterpret_cast<NSOpenGLView*>(widget_))
namespace gfx {
GLSurfaceGlfw::GLSurfaceGlfw(gfx::AcceleratedWidget widget,
const gfx::SurfaceConfiguration requested_configuration)
: GLSurface(requested_configuration),
widget_(widget) {
}
GLSurfaceGlfw::~GLSurfaceGlfw() {
Destroy();
}
bool GLSurfaceGlfw::OnMakeCurrent(GLContext* context) {
// The actual "make current" is done in the context.
return true;
}
bool GLSurfaceGlfw::SwapBuffers() {
glfwSwapBuffers(widget_);
return true;
}
void GLSurfaceGlfw::Destroy() {
DCHECK(false);
}
bool GLSurfaceGlfw::IsOffscreen() {
return false;
}
gfx::Size GLSurfaceGlfw::GetSize() {
int width;
int height;
glfwGetWindowSize(widget_, &width, &height);
return Size(width, height);
}
void* GLSurfaceGlfw::GetHandle() {
return (void*)widget_;
}
bool GLSurfaceGlfw::Resize(const gfx::Size& size) {
return true;
}
bool GLSurface::InitializeOneOffInternal() {
if (!GLSurfaceGlfw::InitializeOneOff()) {
LOG(ERROR) << "GLSurfaceGlfw::InitializeOneOff failed.";
return false;
}
return true;
}
// static
bool GLSurfaceGlfw::InitializeOneOff() {
return true;
}
// static
scoped_refptr<GLSurface> GLSurface::CreateViewGLSurface(
gfx::AcceleratedWidget window,
const gfx::SurfaceConfiguration& requested_configuration) {
DCHECK(window != kNullAcceleratedWidget);
scoped_refptr<GLSurfaceGlfw> surface =
new GLSurfaceGlfw(window, requested_configuration);
if (!surface->Initialize())
return NULL;
return surface;
}
} // namespace gfx

40
ui/gl/gl_surface_glfw.h Normal file
View File

@ -0,0 +1,40 @@
// Copyright 2016 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.
#ifndef UI_GL_GL_SURFACE_GLFW_H_
#define UI_GL_GL_SURFACE_GLFW_H_
#include "ui/gl/gl_surface.h"
namespace gfx {
class GL_EXPORT GLSurfaceGlfw : public GLSurface {
public:
GLSurfaceGlfw(gfx::AcceleratedWidget widget,
const gfx::SurfaceConfiguration requested_configuration);
static bool InitializeOneOff();
static bool HasExtension(const char* name);
static bool IsCreateContextRobustnessSupported();
bool SwapBuffers() override;
void Destroy() override;
bool IsOffscreen() override;
gfx::Size GetSize() override;
void* GetHandle() override;
bool Resize(const gfx::Size& size) override;
bool OnMakeCurrent(GLContext* context) override;
private:
~GLSurfaceGlfw() override;
gfx::AcceleratedWidget widget_;
DISALLOW_COPY_AND_ASSIGN(GLSurfaceGlfw);
};
} // namespace gfx
#endif // UI_GL_GL_SURFACE_GLFW_H_