diff options
Diffstat (limited to 'app')
-rw-r--r-- | app/app_base.gypi | 8 | ||||
-rw-r--r-- | app/gfx/gl/generate_bindings.py | 8 | ||||
-rw-r--r-- | app/gfx/gl/gl_bindings.h | 15 | ||||
-rw-r--r-- | app/gfx/gl/gl_context_egl.cc | 86 | ||||
-rw-r--r-- | app/gfx/gl/gl_context_egl.h | 1 | ||||
-rw-r--r-- | app/gfx/gl/gl_context_linux.cc | 25 | ||||
-rw-r--r-- | app/gfx/gl/gl_implementation_linux.cc | 93 |
7 files changed, 204 insertions, 32 deletions
diff --git a/app/app_base.gypi b/app/app_base.gypi index 247118a..5cd97ee 100644 --- a/app/app_base.gypi +++ b/app/app_base.gypi @@ -300,9 +300,17 @@ }], ['OS=="linux"', { 'sources': [ + 'gfx/gl/gl_context_egl.cc', + 'gfx/gl/gl_context_egl.h', + '<(gl_binding_output_dir)/gl_bindings_autogen_egl.cc', + '<(gl_binding_output_dir)/gl_bindings_autogen_egl.h', '<(gl_binding_output_dir)/gl_bindings_autogen_glx.cc', '<(gl_binding_output_dir)/gl_bindings_autogen_glx.h', ], + 'include_dirs': [ + # We don't use angle, but pull the EGL/GLES headers from there. + '../third_party/angle/include', + ], 'all_dependent_settings': { 'defines': [ 'GL_GLEXT_PROTOTYPES', diff --git a/app/gfx/gl/generate_bindings.py b/app/gfx/gl/generate_bindings.py index 7aaf6d4..0adf603 100644 --- a/app/gfx/gl/generate_bindings.py +++ b/app/gfx/gl/generate_bindings.py @@ -246,7 +246,7 @@ OSMESA_FUNCTIONS = [ EGL_FUNCTIONS = [ ['EGLint', ['eglGetError'], 'void'], -['EGLDisplay', ['eglGetDisplay'], 'void* display_id'], +['EGLDisplay', ['eglGetDisplay'], 'EGLNativeDisplayType display_id'], ['EGLBoolean', ['eglInitialize'], 'EGLDisplay dpy, EGLint* major, EGLint* minor'], ['EGLBoolean', ['eglTerminate'], 'EGLDisplay dpy'], @@ -260,11 +260,11 @@ EGL_FUNCTIONS = [ ['EGLBoolean', ['eglGetConfigAttrib'], 'EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint* value'], ['EGLSurface', ['eglCreateWindowSurface'], - 'EGLDisplay dpy, EGLConfig config, void* win, const EGLint* attrib_list'], + 'EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint* attrib_list'], ['EGLSurface', ['eglCreatePbufferSurface'], 'EGLDisplay dpy, EGLConfig config, const EGLint* attrib_list'], ['EGLSurface', ['eglCreatePixmapSurface'], - 'EGLDisplay dpy, EGLConfig config, void* pixmap, ' + 'EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, ' 'const EGLint* attrib_list'], ['EGLBoolean', ['eglDestroySurface'], 'EGLDisplay dpy, EGLSurface surface'], ['EGLBoolean', ['eglQuerySurface'], @@ -298,7 +298,7 @@ EGL_FUNCTIONS = [ ['EGLBoolean', ['eglWaitNative'], 'EGLint engine'], ['EGLBoolean', ['eglSwapBuffers'], 'EGLDisplay dpy, EGLSurface surface'], ['EGLBoolean', ['eglCopyBuffers'], - 'EGLDisplay dpy, EGLSurface surface, void* target'], + 'EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target'], ['__eglMustCastToProperFunctionPointerType', ['eglGetProcAddress'], 'const char* procname'], ] diff --git a/app/gfx/gl/gl_bindings.h b/app/gfx/gl/gl_bindings.h index c9dbbee..e384bfd 100644 --- a/app/gfx/gl/gl_bindings.h +++ b/app/gfx/gl/gl_bindings.h @@ -42,7 +42,7 @@ typedef struct osmesa_context *OSMesaContext; typedef void (*OSMESAproc)(); -#if defined(OS_WIN) +#if defined(OS_WIN) || defined(OS_LINUX) // Forward declare EGL types. typedef unsigned int EGLBoolean; @@ -55,7 +55,17 @@ typedef void *EGLSurface; typedef void *EGLClientBuffer; typedef void (*__eglMustCastToProperFunctionPointerType)(void); -#endif // OS_WIN +#if defined(OS_WIN) +typedef HDC EGLNativeDisplayType; +typedef HBITMAP EGLNativePixmapType; +typedef HWND EGLNativeWindowType; +#else +typedef Display *EGLNativeDisplayType; +typedef Pixmap EGLNativePixmapType; +typedef Window EGLNativeWindowType; +#endif + +#endif // OS_WIN || OS_LINUX #include "gl_bindings_autogen_gl.h" #include "gl_bindings_autogen_osmesa.h" @@ -64,6 +74,7 @@ typedef void (*__eglMustCastToProperFunctionPointerType)(void); #include "gl_bindings_autogen_egl.h" #include "gl_bindings_autogen_wgl.h" #elif defined(OS_LINUX) +#include "gl_bindings_autogen_egl.h" #include "gl_bindings_autogen_glx.h" #endif diff --git a/app/gfx/gl/gl_context_egl.cc b/app/gfx/gl/gl_context_egl.cc index ec64ae91..4bea175 100644 --- a/app/gfx/gl/gl_context_egl.cc +++ b/app/gfx/gl/gl_context_egl.cc @@ -4,6 +4,11 @@ #include <EGL/egl.h> +#include "build/build_config.h" +#if defined(OS_LINUX) +#include "app/x11_util.h" +#define EGL_HAS_PBUFFERS 1 +#endif #include "base/scoped_ptr.h" #include "app/gfx/gl/gl_bindings.h" #include "app/gfx/gl/gl_context_egl.h" @@ -21,7 +26,12 @@ bool InitializeOneOff() { if (initialized) return true; - g_display = eglGetDisplay(EGL_DEFAULT_DISPLAY); +#ifdef OS_LINUX + EGLNativeDisplayType native_display = x11_util::GetXDisplay(); +#else + EGLNativeDisplayType native_display = EGL_DEFAULT_DISPLAY; +#endif + g_display = eglGetDisplay(native_display); if (!g_display) return false; @@ -34,9 +44,14 @@ bool InitializeOneOff() { EGL_ALPHA_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_RED_SIZE, 8, - EGL_DEPTH_SIZE, 24, + EGL_DEPTH_SIZE, 16, EGL_STENCIL_SIZE, 8, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, +#ifdef EGL_HAS_PBUFFERS + EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT, +#else + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, +#endif EGL_NONE }; @@ -85,10 +100,10 @@ bool NativeViewEGLContext::Initialize() { return NULL; // Create a surface for the native window. - surface_ = eglCreateWindowSurface(g_display, - g_config, - static_cast<EGLNativeWindowType>(window_), - NULL); + EGLNativeWindowType native_window = + reinterpret_cast<EGLNativeWindowType>(window_); + surface_ = eglCreateWindowSurface(g_display, g_config, native_window, NULL); + if (!surface_) { Destroy(); return false; @@ -152,8 +167,13 @@ gfx::Size NativeViewEGLContext::GetSize() { CHECK(GetClientRect(static_cast<HWND>(window_), &rect)); return gfx::Size(rect.right - rect.left, rect.bottom - rect.top); #else - NOTREACHED() - << "NativeViewEGLContext::GetSize not implemented on this platform."; + // TODO(piman): This doesn't work correctly on Windows yet, the size doesn't + // get updated on resize. When it does, we can share the code. + EGLint width; + EGLint height; + CHECK(eglQuerySurface(g_display, surface_, EGL_WIDTH, &width)); + CHECK(eglQuerySurface(g_display, surface_, EGL_HEIGHT, &height)); + return gfx::Size(width, height); #endif } @@ -167,6 +187,7 @@ EGLSurface NativeViewEGLContext::GetSurface() { SecondaryEGLContext::SecondaryEGLContext() : surface_(NULL), + own_surface_(false), context_(NULL) { } @@ -175,20 +196,51 @@ SecondaryEGLContext::~SecondaryEGLContext() { } bool SecondaryEGLContext::Initialize(GLContext* shared_context) { - DCHECK(shared_context); DCHECK(!context_); if (!InitializeOneOff()) return NULL; - surface_ = static_cast<BaseEGLContext*>(shared_context)->GetSurface(); + static const EGLint kContextAttributes[] = { + EGL_CONTEXT_CLIENT_VERSION, 2, + EGL_NONE + }; + + if (shared_context) { + surface_ = static_cast<BaseEGLContext*>(shared_context)->GetSurface(); + own_surface_ = false; + + // Create a context. + context_ = eglCreateContext(g_display, + g_config, + shared_context->GetHandle(), + kContextAttributes); + } else { +#ifdef EGL_HAS_PBUFFERS + static const EGLint kPbufferAttribs[] = { + EGL_WIDTH, 1, + EGL_HEIGHT, 1, + EGL_NONE + }; + + surface_ = eglCreatePbufferSurface(g_display, g_config, kPbufferAttribs); + if (!surface_) { + EGLint error = eglGetError(); + LOG(ERROR) << "Error creating Pbuffer: " << error; + return false; + } + own_surface_ = true; + + context_ = eglCreateContext(g_display, g_config, NULL, kContextAttributes); +#else + NOTIMPLEMENTED() << "Offscreen non-shared GLES context"; + return false; +#endif + } - // Create a context. - context_ = eglCreateContext(g_display, - g_config, - shared_context->GetHandle(), - NULL); if (!context_) { + EGLint error = eglGetError(); + LOG(ERROR) << "Error creating context: " << error; Destroy(); return false; } @@ -197,6 +249,10 @@ bool SecondaryEGLContext::Initialize(GLContext* shared_context) { } void SecondaryEGLContext::Destroy() { + if (own_surface_) { + eglDestroySurface(g_display, surface_); + own_surface_ = false; + } surface_ = NULL; if (context_) { diff --git a/app/gfx/gl/gl_context_egl.h b/app/gfx/gl/gl_context_egl.h index 4bfff9b..016a770 100644 --- a/app/gfx/gl/gl_context_egl.h +++ b/app/gfx/gl/gl_context_egl.h @@ -83,6 +83,7 @@ class SecondaryEGLContext : public BaseEGLContext { private: // All offscreen EGLSurface surface_; + bool own_surface_; EGLContext context_; DISALLOW_COPY_AND_ASSIGN(SecondaryEGLContext); diff --git a/app/gfx/gl/gl_context_linux.cc b/app/gfx/gl/gl_context_linux.cc index d2c5a4f..550f967 100644 --- a/app/gfx/gl/gl_context_linux.cc +++ b/app/gfx/gl/gl_context_linux.cc @@ -9,6 +9,7 @@ #include "base/scoped_ptr.h" #include "app/gfx/gl/gl_bindings.h" #include "app/gfx/gl/gl_context.h" +#include "app/gfx/gl/gl_context_egl.h" #include "app/gfx/gl/gl_context_osmesa.h" #include "app/gfx/gl/gl_context_stub.h" #include "app/gfx/gl/gl_implementation.h" @@ -120,9 +121,11 @@ static bool InitializeOneOff() { // Initialize the GL bindings if they haven't already been initialized. If // the GPU unit tests are running, the mock GL implementation will already // have been initialized. - if (!InitializeGLBindings(kGLImplementationDesktopGL)) { - LOG(ERROR) << "Could not initialize GL."; - return false; + if (!InitializeGLBindings(kGLImplementationEGLGLES2)) { + if (!InitializeGLBindings(kGLImplementationDesktopGL)) { + LOG(ERROR) << "Could not initialize GL."; + return false; + } } // Only check the GLX version if we are in fact using GLX. We might actually @@ -255,6 +258,14 @@ GLContext* GLContext::CreateViewGLContext(gfx::PluginWindowHandle window, return context.release(); } + case kGLImplementationEGLGLES2: { + scoped_ptr<NativeViewEGLContext> context( + new NativeViewEGLContext(reinterpret_cast<void *>(window))); + if (!context->Initialize()) + return NULL; + + return context.release(); + } case kGLImplementationMockGL: return new StubGLContext; default: @@ -518,6 +529,14 @@ GLContext* GLContext::CreateOffscreenGLContext(GLContext* shared_context) { return NULL; } + case kGLImplementationEGLGLES2: { + scoped_ptr<SecondaryEGLContext> context( + new SecondaryEGLContext()); + if (!context->Initialize(shared_context)) + return NULL; + + return context.release(); + } case kGLImplementationMockGL: return new StubGLContext; default: diff --git a/app/gfx/gl/gl_implementation_linux.cc b/app/gfx/gl/gl_implementation_linux.cc index e27cdae..3bad24e 100644 --- a/app/gfx/gl/gl_implementation_linux.cc +++ b/app/gfx/gl/gl_implementation_linux.cc @@ -3,7 +3,9 @@ // found in the LICENSE file. #include <dlfcn.h> +#include <vector> +#include "base/at_exit.h" #include "base/logging.h" #include "app/gfx/gl/gl_bindings.h" #include "app/gfx/gl/gl_context_stub.h" @@ -14,8 +16,32 @@ namespace { typedef void* (*GetProcAddressProc)(const char* name); GLImplementation g_gl_implementation = kGLImplementationNone; -void* g_shared_library; +typedef std::vector<void*> PointerArray; +PointerArray* g_shared_libraries = NULL; GetProcAddressProc g_get_proc_address; + +// TODO(piman): it should be Desktop GL marshalling from double to float. Today +// on native GLES, we do float->double->float. +void GL_BINDING_CALL MarshalClearDepthToClearDepthf(GLclampd depth) { + glClearDepthf(static_cast<GLclampf>(depth)); +} + +void GL_BINDING_CALL MarshalDepthRangeToDepthRangef(GLclampd z_near, + GLclampd z_far) { + glDepthRangef(static_cast<GLclampf>(z_near), static_cast<GLclampf>(z_far)); +} + +void CleanupSharedLibraries(void* unused) { + if (g_shared_libraries) { + for (PointerArray::iterator it = g_shared_libraries->begin(); + it != g_shared_libraries->end(); ++it) { + dlclose(*it); + } + delete g_shared_libraries; + g_shared_libraries = NULL; + } +} + } // namespace anonymous bool InitializeGLBindings(GLImplementation implementation) { @@ -25,22 +51,70 @@ bool InitializeGLBindings(GLImplementation implementation) { if (g_gl_implementation != kGLImplementationNone) return true; + if (!g_shared_libraries) { + g_shared_libraries = new PointerArray(); + base::AtExitManager::RegisterCallback(CleanupSharedLibraries, NULL); + } + + void* shared_library = NULL; + switch (implementation) { case kGLImplementationDesktopGL: - g_shared_library = dlopen("libGL.so.1", RTLD_LAZY | RTLD_LOCAL); - if (!g_shared_library) + DLOG(INFO) << "Initializing Desktop GL"; + shared_library = dlopen("libGL.so.1", RTLD_LAZY | RTLD_LOCAL); + if (!shared_library) { + DLOG(ERROR) << "Failed to load libGL.so.1"; return false; + } + + g_shared_libraries->push_back(shared_library); g_gl_implementation = kGLImplementationDesktopGL; g_get_proc_address = reinterpret_cast<GetProcAddressProc>( - dlsym(g_shared_library, "glXGetProcAddress")); + dlsym(shared_library, "glXGetProcAddress")); CHECK(g_get_proc_address); InitializeGLBindingsGL(); InitializeGLBindingsGLX(); break; + case kGLImplementationEGLGLES2: + DLOG(INFO) << "Initializing EGL"; + shared_library = dlopen("libEGL.so", RTLD_LAZY | RTLD_LOCAL); + if (!shared_library) { + DLOG(ERROR) << "Failed to load libEGL.so"; + return false; + } + + g_gl_implementation = kGLImplementationEGLGLES2; + + g_get_proc_address = reinterpret_cast<GetProcAddressProc>( + dlsym(shared_library, "eglGetProcAddress")); + DCHECK(g_get_proc_address); + + g_shared_libraries->push_back(shared_library); + + shared_library = dlopen("libGLESv2.so", RTLD_LAZY | RTLD_LOCAL); + if (!shared_library) { + DLOG(ERROR) << "Failed to load libGLESv2.so"; + g_shared_libraries->clear(); + return false; + } + + DCHECK(shared_library); + + g_shared_libraries->push_back(shared_library); + + InitializeGLBindingsGL(); + InitializeGLBindingsEGL(); + + // These two functions take single precision float rather than double + // precision float parameters in GLES. + ::gfx::g_glClearDepth = MarshalClearDepthToClearDepthf; + ::gfx::g_glDepthRange = MarshalDepthRangeToDepthRangef; + break; + case kGLImplementationMockGL: g_get_proc_address = GetMockGLProcAddress; g_gl_implementation = kGLImplementationMockGL; @@ -68,10 +142,13 @@ void* GetGLProcAddress(const char* name) { return proc; } - if (g_shared_library) { - void* proc = dlsym(g_shared_library, name); - if (proc) - return proc; + if (g_shared_libraries) { + for (PointerArray::iterator it = g_shared_libraries->begin(); + it != g_shared_libraries->end(); ++it) { + void* proc = dlsym(*it, name); + if (proc) + return proc; + } } return NULL; |