| /* |
| * Copyright (C) 2012 Igalia, S.L. |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
| */ |
| |
| #include "config.h" |
| #include "GLContextEGL.h" |
| |
| #if USE(EGL) |
| |
| #include "GraphicsContext3D.h" |
| #include <wtf/OwnPtr.h> |
| |
| #if USE(OPENGL_ES_2) |
| #include <GLES2/gl2.h> |
| #include <GLES2/gl2ext.h> |
| #else |
| #include "OpenGLShims.h" |
| #endif |
| |
| namespace WebCore { |
| |
| static EGLDisplay gSharedEGLDisplay = EGL_NO_DISPLAY; |
| |
| #if USE(OPENGL_ES_2) |
| static const EGLenum gGLAPI = EGL_OPENGL_ES_API; |
| #else |
| static const EGLenum gGLAPI = EGL_OPENGL_API; |
| #endif |
| |
| static EGLDisplay sharedEGLDisplay() |
| { |
| static bool initialized = false; |
| if (!initialized) { |
| initialized = true; |
| #if PLATFORM(X11) |
| gSharedEGLDisplay = eglGetDisplay(GLContext::sharedX11Display()); |
| #else |
| gSharedEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); |
| #endif |
| if (gSharedEGLDisplay != EGL_NO_DISPLAY && (!eglInitialize(gSharedEGLDisplay, 0, 0) || !eglBindAPI(gGLAPI))) |
| gSharedEGLDisplay = EGL_NO_DISPLAY; |
| } |
| return gSharedEGLDisplay; |
| } |
| |
| static const EGLint gContextAttributes[] = { |
| #if USE(OPENGL_ES_2) |
| EGL_CONTEXT_CLIENT_VERSION, 2, |
| #endif |
| EGL_NONE |
| }; |
| |
| static bool getEGLConfig(EGLConfig* config, GLContextEGL::EGLSurfaceType surfaceType) |
| { |
| EGLint attributeList[] = { |
| #if USE(OPENGL_ES_2) |
| EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, |
| #else |
| EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, |
| #endif |
| EGL_RED_SIZE, 8, |
| EGL_GREEN_SIZE, 8, |
| EGL_BLUE_SIZE, 8, |
| EGL_STENCIL_SIZE, 8, |
| EGL_ALPHA_SIZE, 8, |
| EGL_SURFACE_TYPE, EGL_NONE, |
| EGL_NONE |
| }; |
| |
| switch (surfaceType) { |
| case GLContextEGL::PbufferSurface: |
| attributeList[13] = EGL_PBUFFER_BIT; |
| break; |
| case GLContextEGL::PixmapSurface: |
| attributeList[13] = EGL_PIXMAP_BIT; |
| break; |
| case GLContextEGL::WindowSurface: |
| attributeList[13] = EGL_WINDOW_BIT; |
| break; |
| } |
| |
| EGLint numberConfigsReturned; |
| return eglChooseConfig(sharedEGLDisplay(), attributeList, config, 1, &numberConfigsReturned) && numberConfigsReturned; |
| } |
| |
| PassOwnPtr<GLContextEGL> GLContextEGL::createWindowContext(EGLNativeWindowType window, GLContext* sharingContext) |
| { |
| EGLContext eglSharingContext = sharingContext ? static_cast<GLContextEGL*>(sharingContext)->m_context : 0; |
| |
| EGLDisplay display = sharedEGLDisplay(); |
| if (display == EGL_NO_DISPLAY) |
| return nullptr; |
| |
| EGLConfig config; |
| if (!getEGLConfig(&config, WindowSurface)) |
| return nullptr; |
| |
| EGLContext context = eglCreateContext(display, config, eglSharingContext, gContextAttributes); |
| if (context == EGL_NO_CONTEXT) |
| return nullptr; |
| |
| EGLSurface surface = eglCreateWindowSurface(display, config, window, 0); |
| if (surface == EGL_NO_SURFACE) |
| return nullptr; |
| |
| return adoptPtr(new GLContextEGL(context, surface, WindowSurface)); |
| } |
| |
| PassOwnPtr<GLContextEGL> GLContextEGL::createPbufferContext(EGLContext sharingContext) |
| { |
| EGLDisplay display = sharedEGLDisplay(); |
| if (display == EGL_NO_DISPLAY) |
| return nullptr; |
| |
| EGLConfig config; |
| if (!getEGLConfig(&config, PbufferSurface)) |
| return nullptr; |
| |
| EGLContext context = eglCreateContext(display, config, sharingContext, gContextAttributes); |
| if (context == EGL_NO_CONTEXT) |
| return nullptr; |
| |
| static const int pbufferAttributes[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE }; |
| EGLSurface surface = eglCreatePbufferSurface(display, config, pbufferAttributes); |
| if (surface == EGL_NO_SURFACE) { |
| eglDestroyContext(display, context); |
| return nullptr; |
| } |
| |
| return adoptPtr(new GLContextEGL(context, surface, PbufferSurface)); |
| } |
| |
| PassOwnPtr<GLContextEGL> GLContextEGL::createPixmapContext(EGLContext sharingContext) |
| { |
| #if PLATFORM(X11) |
| EGLDisplay display = sharedEGLDisplay(); |
| if (display == EGL_NO_DISPLAY) |
| return nullptr; |
| |
| EGLConfig config; |
| if (!getEGLConfig(&config, PixmapSurface)) |
| return nullptr; |
| |
| EGLContext context = eglCreateContext(display, config, sharingContext, gContextAttributes); |
| if (context == EGL_NO_CONTEXT) |
| return nullptr; |
| |
| EGLint depth; |
| if (!eglGetConfigAttrib(display, config, EGL_DEPTH_SIZE, &depth)) |
| return nullptr; |
| |
| Pixmap pixmap = XCreatePixmap(sharedX11Display(), DefaultRootWindow(sharedX11Display()), 1, 1, depth); |
| if (!pixmap) |
| return nullptr; |
| |
| EGLSurface surface = eglCreatePixmapSurface(display, config, pixmap, 0); |
| #else |
| EGLSurface surface = EGL_NO_SURFACE; |
| #endif |
| if (surface == EGL_NO_SURFACE) |
| return nullptr; |
| |
| return adoptPtr(new GLContextEGL(context, surface, PixmapSurface)); |
| } |
| |
| PassOwnPtr<GLContextEGL> GLContextEGL::createContext(EGLNativeWindowType window, GLContext* sharingContext) |
| { |
| if (!sharedEGLDisplay()) |
| return nullptr; |
| |
| static bool initialized = false; |
| static bool success = true; |
| if (!initialized) { |
| #if !USE(OPENGL_ES_2) |
| success = initializeOpenGLShims(); |
| #endif |
| initialized = true; |
| } |
| if (!success) |
| return nullptr; |
| |
| EGLContext eglSharingContext = sharingContext ? static_cast<GLContextEGL*>(sharingContext)->m_context : 0; |
| OwnPtr<GLContextEGL> context = window ? createWindowContext(window, sharingContext) : nullptr; |
| if (!context) |
| context = createPixmapContext(eglSharingContext); |
| |
| if (!context) |
| context = createPbufferContext(eglSharingContext); |
| |
| return context.release(); |
| } |
| |
| GLContextEGL::GLContextEGL(EGLContext context, EGLSurface surface, EGLSurfaceType type) |
| : m_context(context) |
| , m_surface(surface) |
| , m_type(type) |
| { |
| } |
| |
| GLContextEGL::~GLContextEGL() |
| { |
| EGLDisplay display = sharedEGLDisplay(); |
| if (m_context) { |
| glBindFramebuffer(GL_FRAMEBUFFER, 0); |
| eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); |
| eglDestroyContext(display, m_context); |
| } |
| |
| if (m_surface) |
| eglDestroySurface(display, m_surface); |
| } |
| |
| bool GLContextEGL::canRenderToDefaultFramebuffer() |
| { |
| return m_type == WindowSurface; |
| } |
| |
| IntSize GLContextEGL::defaultFrameBufferSize() |
| { |
| if (!canRenderToDefaultFramebuffer()) |
| return IntSize(); |
| |
| EGLint width, height; |
| if (!eglQuerySurface(sharedEGLDisplay(), m_surface, EGL_WIDTH, &width) |
| || !eglQuerySurface(sharedEGLDisplay(), m_surface, EGL_HEIGHT, &height)) |
| return IntSize(); |
| |
| return IntSize(width, height); |
| } |
| |
| bool GLContextEGL::makeContextCurrent() |
| { |
| ASSERT(m_context && m_surface); |
| |
| GLContext::makeContextCurrent(); |
| if (eglGetCurrentContext() == m_context) |
| return true; |
| |
| return eglMakeCurrent(sharedEGLDisplay(), m_surface, m_surface, m_context); |
| } |
| |
| void GLContextEGL::swapBuffers() |
| { |
| ASSERT(m_surface); |
| eglSwapBuffers(sharedEGLDisplay(), m_surface); |
| } |
| |
| void GLContextEGL::waitNative() |
| { |
| eglWaitNative(EGL_CORE_NATIVE_ENGINE); |
| } |
| |
| #if ENABLE(WEBGL) |
| PlatformGraphicsContext3D GLContextEGL::platformContext() |
| { |
| return m_context; |
| } |
| #endif |
| |
| } // namespace WebCore |
| |
| #endif // USE(EGL) |