| /* |
| * Copyright (C) 2011, 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" |
| |
| #if USE(OPENGL) || USE(OPENGL_ES) |
| |
| #include "GLContext.h" |
| |
| #include <wtf/ThreadSpecific.h> |
| #include <wtf/text/StringToIntegerConversion.h> |
| |
| #if USE(LIBEPOXY) |
| #include <epoxy/gl.h> |
| #elif USE(OPENGL_ES) |
| #include <GLES2/gl2.h> |
| #else |
| #include "OpenGLShims.h" |
| #endif |
| |
| #if USE(EGL) |
| #include "GLContextEGL.h" |
| #endif |
| |
| #if USE(GLX) |
| #include "GLContextGLX.h" |
| #endif |
| |
| namespace WebCore { |
| |
| class ThreadGlobalGLContext { |
| public: |
| static ThreadSpecific<ThreadGlobalGLContext>* staticGLContext; |
| |
| void setContext(GLContext* context) { m_context = context; } |
| GLContext* context() { return m_context; } |
| |
| private: |
| GLContext* m_context { nullptr }; |
| }; |
| |
| ThreadSpecific<ThreadGlobalGLContext>* ThreadGlobalGLContext::staticGLContext; |
| |
| inline ThreadGlobalGLContext* currentContext() |
| { |
| if (!ThreadGlobalGLContext::staticGLContext) |
| ThreadGlobalGLContext::staticGLContext = new ThreadSpecific<ThreadGlobalGLContext>; |
| return *ThreadGlobalGLContext::staticGLContext; |
| } |
| |
| static bool initializeOpenGLShimsIfNeeded() |
| { |
| #if USE(OPENGL_ES) || USE(LIBEPOXY) || (USE(ANGLE) && !(PLATFORM(GTK) || PLATFORM(WPE))) |
| return true; |
| #else |
| static bool initialized = false; |
| static bool success = true; |
| if (!initialized) { |
| success = initializeOpenGLShims(); |
| initialized = true; |
| } |
| return success; |
| #endif |
| } |
| |
| std::unique_ptr<GLContext> GLContext::createContextForWindow(GLNativeWindowType windowHandle, PlatformDisplay* platformDisplay) |
| { |
| if (!initializeOpenGLShimsIfNeeded()) |
| return nullptr; |
| |
| PlatformDisplay& display = platformDisplay ? *platformDisplay : PlatformDisplay::sharedDisplay(); |
| #if PLATFORM(WAYLAND) |
| if (display.type() == PlatformDisplay::Type::Wayland) { |
| if (auto eglContext = GLContextEGL::createContext(windowHandle, display)) |
| return eglContext; |
| return nullptr; |
| } |
| #endif |
| |
| #if USE(GLX) |
| if (display.type() == PlatformDisplay::Type::X11) { |
| if (auto glxContext = GLContextGLX::createContext(windowHandle, display)) |
| return glxContext; |
| } |
| #endif |
| #if USE(EGL) |
| if (auto eglContext = GLContextEGL::createContext(windowHandle, display)) |
| return eglContext; |
| #endif |
| return nullptr; |
| } |
| |
| std::unique_ptr<GLContext> GLContext::createOffscreenContext(PlatformDisplay* platformDisplay) |
| { |
| if (!initializeOpenGLShimsIfNeeded()) |
| return nullptr; |
| |
| return createContextForWindow(0, platformDisplay ? platformDisplay : &PlatformDisplay::sharedDisplay()); |
| } |
| |
| std::unique_ptr<GLContext> GLContext::createSharingContext(PlatformDisplay& display) |
| { |
| if (!initializeOpenGLShimsIfNeeded()) |
| return nullptr; |
| |
| #if USE(GLX) |
| if (display.type() == PlatformDisplay::Type::X11) { |
| if (auto glxContext = GLContextGLX::createSharingContext(display)) |
| return glxContext; |
| } |
| #endif |
| |
| #if USE(EGL) || PLATFORM(WAYLAND) || PLATFORM(WPE) |
| if (auto eglContext = GLContextEGL::createSharingContext(display)) |
| return eglContext; |
| #endif |
| |
| return nullptr; |
| } |
| |
| GLContext::GLContext(PlatformDisplay& display) |
| : m_display(display) |
| { |
| } |
| |
| GLContext::~GLContext() |
| { |
| if (this == currentContext()->context()) |
| currentContext()->setContext(nullptr); |
| } |
| |
| bool GLContext::makeContextCurrent() |
| { |
| currentContext()->setContext(this); |
| return true; |
| } |
| |
| GLContext* GLContext::current() |
| { |
| return currentContext()->context(); |
| } |
| |
| bool GLContext::isExtensionSupported(const char* extensionList, const char* extension) |
| { |
| if (!extensionList) |
| return false; |
| |
| ASSERT(extension); |
| int extensionLen = strlen(extension); |
| const char* extensionListPtr = extensionList; |
| while ((extensionListPtr = strstr(extensionListPtr, extension))) { |
| if (extensionListPtr[extensionLen] == ' ' || extensionListPtr[extensionLen] == '\0') |
| return true; |
| extensionListPtr += extensionLen; |
| } |
| return false; |
| } |
| |
| unsigned GLContext::version() |
| { |
| if (!m_version) { |
| // Version string can start with the version number (all versions except GLES 1 and 2) or with |
| // "OpenGL". Different fields inside the version string are separated by spaces. |
| auto versionString = String::fromLatin1(reinterpret_cast<const char*>(::glGetString(GL_VERSION))); |
| Vector<String> versionStringComponents = versionString.split(' '); |
| |
| Vector<String> versionDigits; |
| if (versionStringComponents[0] == "OpenGL"_s) { |
| // If the version string starts with "OpenGL" it can be GLES 1 or 2. In GLES1 version string starts |
| // with "OpenGL ES-<profile> major.minor" and in GLES2 with "OpenGL ES major.minor". Version is the |
| // third component in both cases. |
| versionDigits = versionStringComponents[2].split('.'); |
| } else { |
| // Version is the first component. The version number is always "major.minor" or |
| // "major.minor.release". Ignore the release number. |
| versionDigits = versionStringComponents[0].split('.'); |
| } |
| |
| m_version = parseIntegerAllowingTrailingJunk<unsigned>(versionDigits[0]).value_or(0) * 100 |
| + parseIntegerAllowingTrailingJunk<unsigned>(versionDigits[1]).value_or(0) * 10; |
| } |
| return m_version; |
| } |
| |
| } // namespace WebCore |
| |
| #endif |