blob: 84c050d54fb1f63a8ccaa1180a303505b7e92a5a [file] [log] [blame]
/*
* 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