diff --git a/build/config/BUILD.gn b/build/config/BUILD.gn index e257b3593f4..0af90cd06d4 100644 --- a/build/config/BUILD.gn +++ b/build/config/BUILD.gn @@ -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" ] } diff --git a/build/config/ui.gni b/build/config/ui.gni index db4168689f6..c2dff4a87df 100644 --- a/build/config/ui.gni +++ b/build/config/ui.gni @@ -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 diff --git a/third_party/glfw/BUILD.gn b/third_party/glfw/BUILD.gn index 5e921de7abb..799d0fbf11f 100644 --- a/third_party/glfw/BUILD.gn +++ b/third_party/glfw/BUILD.gn @@ -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", diff --git a/ui/gfx/native_widget_types.h b/ui/gfx/native_widget_types.h index 35c6e669ada..265d6e9a05b 100644 --- a/ui/gfx/native_widget_types.h +++ b/ui/gfx/native_widget_types.h @@ -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) diff --git a/ui/gl/BUILD.gn b/ui/gl/BUILD.gn index e195f0eb282..d681dc4bfd9 100644 --- a/ui/gl/BUILD.gn +++ b/ui/gl/BUILD.gn @@ -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", diff --git a/ui/gl/gl_bindings.h b/ui/gl/gl_bindings.h index fcaaf7e7592..afcf1fea747 100644 --- a/ui/gl/gl_bindings.h +++ b/ui/gl/gl_bindings.h @@ -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 #include #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(); diff --git a/ui/gl/gl_context_glfw.cc b/ui/gl/gl_context_glfw.cc new file mode 100644 index 00000000000..5a3ea6d35b7 --- /dev/null +++ b/ui/gl/gl_context_glfw.cc @@ -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 + +#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::CreateGLContext( + GLShareGroup* share_group, + GLSurface* compatible_surface, + GpuPreference gpu_preference) { + TRACE_EVENT0("gpu", "GLContext::CreateGLContext"); + switch (GetGLImplementation()) { + case kGLImplementationDesktopGL: + case kGLImplementationEGLGLES2: { + scoped_refptr 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(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 diff --git a/ui/gl/gl_context_glfw.h b/ui/gl/gl_context_glfw.h new file mode 100644 index 00000000000..e8590894985 --- /dev/null +++ b/ui/gl/gl_context_glfw.h @@ -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 + +#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_ diff --git a/ui/gl/gl_implementation_glfw.cc b/ui/gl/gl_implementation_glfw.cc new file mode 100644 index 00000000000..bf22f8f579d --- /dev/null +++ b/ui/gl/gl_implementation_glfw.cc @@ -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 + +#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* 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( + 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(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 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 diff --git a/ui/gl/gl_implementation_osmesa.cc b/ui/gl/gl_implementation_osmesa.cc index 36d3fb3eb7a..f3c84fe10f6 100644 --- a/ui/gl/gl_implementation_osmesa.cc +++ b/ui/gl/gl_implementation_osmesa.cc @@ -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. diff --git a/ui/gl/gl_surface_glfw.cc b/ui/gl/gl_surface_glfw.cc new file mode 100644 index 00000000000..263e78094da --- /dev/null +++ b/ui/gl/gl_surface_glfw.cc @@ -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 + +#include "ui/gl/gl_context.h" +#include "ui/gl/gl_enums.h" +#include "base/logging.h" + +#define WIDGET_AS_VIEW (reinterpret_cast(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::CreateViewGLSurface( + gfx::AcceleratedWidget window, + const gfx::SurfaceConfiguration& requested_configuration) { + DCHECK(window != kNullAcceleratedWidget); + scoped_refptr surface = + new GLSurfaceGlfw(window, requested_configuration); + + if (!surface->Initialize()) + return NULL; + + return surface; +} + +} // namespace gfx diff --git a/ui/gl/gl_surface_glfw.h b/ui/gl/gl_surface_glfw.h new file mode 100644 index 00000000000..b1e77db64d8 --- /dev/null +++ b/ui/gl/gl_surface_glfw.h @@ -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_