diff options
Diffstat (limited to 'Source/WebCore/platform/graphics/glx')
-rw-r--r-- | Source/WebCore/platform/graphics/glx/GLContextGLX.cpp | 312 | ||||
-rw-r--r-- | Source/WebCore/platform/graphics/glx/GLContextGLX.h | 63 |
2 files changed, 232 insertions, 143 deletions
diff --git a/Source/WebCore/platform/graphics/glx/GLContextGLX.cpp b/Source/WebCore/platform/graphics/glx/GLContextGLX.cpp index 176f7722d..451b914ba 100644 --- a/Source/WebCore/platform/graphics/glx/GLContextGLX.cpp +++ b/Source/WebCore/platform/graphics/glx/GLContextGLX.cpp @@ -22,9 +22,10 @@ #if USE(GLX) #include "GraphicsContext3D.h" #include "OpenGLShims.h" +#include "PlatformDisplayX11.h" +#include "XErrorTrapper.h" #include <GL/glx.h> #include <cairo.h> -#include <wtf/OwnPtr.h> #if ENABLE(ACCELERATED_2D_CANVAS) #include <cairo-gl.h> @@ -32,36 +33,130 @@ namespace WebCore { -PassOwnPtr<GLContextGLX> GLContextGLX::createWindowContext(XID window, GLContext* sharingContext) +#if !defined(PFNGLXSWAPINTERVALSGIPROC) +typedef int (*PFNGLXSWAPINTERVALSGIPROC) (int); +#endif +#if !defined(PFNGLXCREATECONTEXTATTRIBSARBPROC) +typedef GLXContext (*PFNGLXCREATECONTEXTATTRIBSARBPROC) (Display *dpy, GLXFBConfig config, GLXContext share_context, Bool direct, const int *attrib_list); +#endif + +static PFNGLXSWAPINTERVALSGIPROC glXSwapIntervalSGI; +static PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB; + +static bool hasSGISwapControlExtension(Display* display) { - Display* display = sharedX11Display(); + static bool initialized = false; + if (initialized) + return !!glXSwapIntervalSGI; + + initialized = true; + if (!GLContext::isExtensionSupported(glXQueryExtensionsString(display, 0), "GLX_SGI_swap_control")) + return false; + + glXSwapIntervalSGI = reinterpret_cast<PFNGLXSWAPINTERVALSGIPROC>(glXGetProcAddress(reinterpret_cast<const unsigned char*>("glXSwapIntervalSGI"))); + return !!glXSwapIntervalSGI; +} + +static bool hasGLXARBCreateContextExtension(Display* display) +{ + static bool initialized = false; + if (initialized) + return !!glXCreateContextAttribsARB; + + initialized = true; + if (!GLContext::isExtensionSupported(glXQueryExtensionsString(display, 0), "GLX_ARB_create_context")) + return false; + + glXCreateContextAttribsARB = reinterpret_cast<PFNGLXCREATECONTEXTATTRIBSARBPROC>(glXGetProcAddress(reinterpret_cast<const unsigned char*>("glXCreateContextAttribsARB"))); + return !!glXCreateContextAttribsARB; +} + +static GLXContext createGLXARBContext(Display* display, GLXFBConfig config, GLXContext sharingContext) +{ + // We want to create a context with version >= 3.2 core profile, cause that ensures that the i965 driver won't + // use the software renderer. If that doesn't work, we will use whatever version available. Unfortunately, + // there's no way to know whether glXCreateContextAttribsARB can provide an OpenGL version >= 3.2 until + // we actually call it and check the return value. To make things more fun, if a version >= 3.2 cannot be + // provided, glXCreateContextAttribsARB will throw a GLXBadFBConfig X error, causing the app to crash. + // So, the first time a context is requested, we set a X error trap to disable crashes with GLXBadFBConfig + // and then check whether the return value is a context or not. + + static bool canCreate320Context = false; + static bool canCreate320ContextInitialized = false; + + static const int contextAttributes[] = { + GLX_CONTEXT_MAJOR_VERSION_ARB, 3, + GLX_CONTEXT_MINOR_VERSION_ARB, 2, + 0 + }; + + if (!canCreate320ContextInitialized) { + canCreate320ContextInitialized = true; + + { + // Set an X error trapper that ignores errors to avoid crashing on GLXBadFBConfig. Use a scope + // here to limit the error trap to just this context creation call. + XErrorTrapper trapper(display, XErrorTrapper::Policy::Ignore); + GLXContext context = glXCreateContextAttribsARB(display, config, sharingContext, GL_TRUE, contextAttributes); + if (context) { + canCreate320Context = true; + return context; + } + } + + // Creating the 3.2 context failed, so use whatever is available. + return glXCreateContextAttribsARB(display, config, sharingContext, GL_TRUE, nullptr); + } + + if (canCreate320Context) + return glXCreateContextAttribsARB(display, config, sharingContext, GL_TRUE, contextAttributes); + + return glXCreateContextAttribsARB(display, config, sharingContext, GL_TRUE, nullptr); +} + +std::unique_ptr<GLContextGLX> GLContextGLX::createWindowContext(GLNativeWindowType window, PlatformDisplay& platformDisplay, GLXContext sharingContext) +{ + Display* display = downcast<PlatformDisplayX11>(platformDisplay).native(); XWindowAttributes attributes; - if (!XGetWindowAttributes(display, window, &attributes)) + if (!XGetWindowAttributes(display, static_cast<Window>(window), &attributes)) return nullptr; XVisualInfo visualInfo; visualInfo.visualid = XVisualIDFromVisual(attributes.visual); - int numReturned = 0; - XVisualInfo* visualInfoList = XGetVisualInfo(display, VisualIDMask, &visualInfo, &numReturned); - - GLXContext glxSharingContext = sharingContext ? static_cast<GLContextGLX*>(sharingContext)->m_context : 0; - GLXContext context = glXCreateContext(display, visualInfoList, glxSharingContext, True); - XFree(visualInfoList); + int numConfigs = 0; + GLXFBConfig config = nullptr; + XUniquePtr<GLXFBConfig> configs(glXGetFBConfigs(display, DefaultScreen(display), &numConfigs)); + for (int i = 0; i < numConfigs; i++) { + XUniquePtr<XVisualInfo> glxVisualInfo(glXGetVisualFromFBConfig(display, configs.get()[i])); + if (!glxVisualInfo) + continue; + + if (glxVisualInfo.get()->visualid == visualInfo.visualid) { + config = configs.get()[i]; + break; + } + } + ASSERT(config); + + XUniqueGLXContext context; + if (hasGLXARBCreateContextExtension(display)) + context.reset(createGLXARBContext(display, config, sharingContext)); + else { + // Legacy OpenGL version. + XUniquePtr<XVisualInfo> visualInfoList(glXGetVisualFromFBConfig(display, config)); + context.reset(glXCreateContext(display, visualInfoList.get(), sharingContext, True)); + } if (!context) return nullptr; - // GLXPbuffer and XID are both the same types underneath, so we have to share - // a constructor here with the window path. - GLContextGLX* contextWrapper = new GLContextGLX(context); - contextWrapper->m_window = window; - return adoptPtr(contextWrapper); + return std::unique_ptr<GLContextGLX>(new GLContextGLX(platformDisplay, WTFMove(context), window)); } -PassOwnPtr<GLContextGLX> GLContextGLX::createPbufferContext(GLXContext sharingContext) +std::unique_ptr<GLContextGLX> GLContextGLX::createPbufferContext(PlatformDisplay& platformDisplay, GLXContext sharingContext) { - int fbConfigAttributes[] = { + static const int fbConfigAttributes[] = { GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT, GLX_RENDER_TYPE, GLX_RGBA_BIT, GLX_RED_SIZE, 1, @@ -73,36 +168,32 @@ PassOwnPtr<GLContextGLX> GLContextGLX::createPbufferContext(GLXContext sharingCo }; int returnedElements; - Display* display = sharedX11Display(); - GLXFBConfig* configs = glXChooseFBConfig(display, 0, fbConfigAttributes, &returnedElements); - if (!returnedElements) { - XFree(configs); + Display* display = downcast<PlatformDisplayX11>(platformDisplay).native(); + XUniquePtr<GLXFBConfig> configs(glXChooseFBConfig(display, 0, fbConfigAttributes, &returnedElements)); + if (!returnedElements) return nullptr; - } // We will be rendering to a texture, so our pbuffer does not need to be large. static const int pbufferAttributes[] = { GLX_PBUFFER_WIDTH, 1, GLX_PBUFFER_HEIGHT, 1, 0 }; - GLXPbuffer pbuffer = glXCreatePbuffer(display, configs[0], pbufferAttributes); - if (!pbuffer) { - XFree(configs); + XUniqueGLXPbuffer pbuffer(glXCreatePbuffer(display, configs.get()[0], pbufferAttributes)); + if (!pbuffer) return nullptr; + + XUniqueGLXContext context; + if (hasGLXARBCreateContextExtension(display)) + context.reset(createGLXARBContext(display, configs.get()[0], sharingContext)); + else { + // Legacy OpenGL version. + context.reset(glXCreateNewContext(display, configs.get()[0], GLX_RGBA_TYPE, sharingContext, GL_TRUE)); } - GLXContext context = glXCreateNewContext(display, configs[0], GLX_RGBA_TYPE, sharingContext, GL_TRUE); - XFree(configs); - if (!context) { - glXDestroyPbuffer(display, pbuffer); + if (!context) return nullptr; - } - // GLXPbuffer and XID are both the same types underneath, so we have to share - // a constructor here with the window path. - GLContextGLX* contextWrapper = new GLContextGLX(context); - contextWrapper->m_pbuffer = pbuffer; - return adoptPtr(contextWrapper); + return std::unique_ptr<GLContextGLX>(new GLContextGLX(platformDisplay, WTFMove(context), WTFMove(pbuffer))); } -PassOwnPtr<GLContextGLX> GLContextGLX::createPixmapContext(GLXContext sharingContext) +std::unique_ptr<GLContextGLX> GLContextGLX::createPixmapContext(PlatformDisplay& platformDisplay, GLXContext sharingContext) { static int visualAttributes[] = { GLX_RGBA, @@ -113,77 +204,68 @@ PassOwnPtr<GLContextGLX> GLContextGLX::createPixmapContext(GLXContext sharingCon 0 }; - Display* display = sharedX11Display(); - XVisualInfo* visualInfo = glXChooseVisual(display, DefaultScreen(display), visualAttributes); + Display* display = downcast<PlatformDisplayX11>(platformDisplay).native(); + XUniquePtr<XVisualInfo> visualInfo(glXChooseVisual(display, DefaultScreen(display), visualAttributes)); if (!visualInfo) return nullptr; - GLXContext context = glXCreateContext(display, visualInfo, sharingContext, GL_TRUE); - if (!context) { - XFree(visualInfo); + XUniqueGLXContext context(glXCreateContext(display, visualInfo.get(), sharingContext, GL_TRUE)); + if (!context) return nullptr; - } - Pixmap pixmap = XCreatePixmap(display, DefaultRootWindow(display), 1, 1, visualInfo->depth); - if (!pixmap) { - XFree(visualInfo); + XUniquePixmap pixmap(XCreatePixmap(display, DefaultRootWindow(display), 1, 1, visualInfo->depth)); + if (!pixmap) return nullptr; - } - GLXPixmap glxPixmap = glXCreateGLXPixmap(display, visualInfo, pixmap); - if (!glxPixmap) { - XFreePixmap(display, pixmap); - XFree(visualInfo); + XUniqueGLXPixmap glxPixmap(glXCreateGLXPixmap(display, visualInfo.get(), pixmap.get())); + if (!glxPixmap) return nullptr; - } - XFree(visualInfo); - return adoptPtr(new GLContextGLX(context, pixmap, glxPixmap)); + return std::unique_ptr<GLContextGLX>(new GLContextGLX(platformDisplay, WTFMove(context), WTFMove(pixmap), WTFMove(glxPixmap))); } -PassOwnPtr<GLContextGLX> GLContextGLX::createContext(XID window, GLContext* sharingContext) +std::unique_ptr<GLContextGLX> GLContextGLX::createContext(GLNativeWindowType window, PlatformDisplay& platformDisplay) { - if (!sharedX11Display()) - return nullptr; - - static bool initialized = false; - static bool success = true; - if (!initialized) { - success = initializeOpenGLShims(); - initialized = true; - } - if (!success) - return nullptr; - - GLXContext glxSharingContext = sharingContext ? static_cast<GLContextGLX*>(sharingContext)->m_context : 0; - OwnPtr<GLContextGLX> context = window ? createWindowContext(window, sharingContext) : nullptr; + GLXContext glxSharingContext = platformDisplay.sharingGLContext() ? static_cast<GLContextGLX*>(platformDisplay.sharingGLContext())->m_context.get() : nullptr; + auto context = window ? createWindowContext(window, platformDisplay, glxSharingContext) : nullptr; if (!context) - context = createPbufferContext(glxSharingContext); + context = createPbufferContext(platformDisplay, glxSharingContext); if (!context) - context = createPixmapContext(glxSharingContext); + context = createPixmapContext(platformDisplay, glxSharingContext); + + return context; +} + +std::unique_ptr<GLContextGLX> GLContextGLX::createSharingContext(PlatformDisplay& platformDisplay) +{ + auto context = createPbufferContext(platformDisplay); if (!context) - return nullptr; + context = createPixmapContext(platformDisplay); + return context; +} - return context.release(); +GLContextGLX::GLContextGLX(PlatformDisplay& display, XUniqueGLXContext&& context, GLNativeWindowType window) + : GLContext(display) + , m_x11Display(downcast<PlatformDisplayX11>(m_display).native()) + , m_context(WTFMove(context)) + , m_window(static_cast<Window>(window)) +{ } -GLContextGLX::GLContextGLX(GLXContext context) - : m_context(context) - , m_window(0) - , m_pbuffer(0) - , m_pixmap(0) - , m_glxPixmap(0) - , m_cairoDevice(0) +GLContextGLX::GLContextGLX(PlatformDisplay& display, XUniqueGLXContext&& context, XUniqueGLXPbuffer&& pbuffer) + : GLContext(display) + , m_x11Display(downcast<PlatformDisplayX11>(m_display).native()) + , m_context(WTFMove(context)) + , m_pbuffer(WTFMove(pbuffer)) { } -GLContextGLX::GLContextGLX(GLXContext context, Pixmap pixmap, GLXPixmap glxPixmap) - : m_context(context) - , m_window(0) - , m_pbuffer(0) - , m_pixmap(pixmap) - , m_glxPixmap(glxPixmap) - , m_cairoDevice(0) +GLContextGLX::GLContextGLX(PlatformDisplay& display, XUniqueGLXContext&& context, XUniquePixmap&& pixmap, XUniqueGLXPixmap&& glxPixmap) + : GLContext(display) + , m_x11Display(downcast<PlatformDisplayX11>(m_display).native()) + , m_context(WTFMove(context)) + , m_pixmap(WTFMove(pixmap)) + , m_glxPixmap(WTFMove(glxPixmap)) { } @@ -193,24 +275,21 @@ GLContextGLX::~GLContextGLX() cairo_device_destroy(m_cairoDevice); if (m_context) { - // This may be necessary to prevent crashes with NVidia's closed source drivers. Originally - // from Mozilla's 3D canvas implementation at: http://bitbucket.org/ilmari/canvas3d/ + // Due to a bug in some nvidia drivers, we need bind the default framebuffer in a context before + // destroying it to avoid a crash. In order to do that, we need to make the context current and, + // after the bind change, we need to set the previous context again. + GLContext* previousActiveContext = GLContext::current(); + makeContextCurrent(); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); - glXMakeCurrent(sharedX11Display(), None, None); - glXDestroyContext(sharedX11Display(), m_context); - } - - if (m_pbuffer) { - glXDestroyPbuffer(sharedX11Display(), m_pbuffer); - m_pbuffer = 0; - } - if (m_glxPixmap) { - glXDestroyGLXPixmap(sharedX11Display(), m_glxPixmap); - m_glxPixmap = 0; - } - if (m_pixmap) { - XFreePixmap(sharedX11Display(), m_pixmap); - m_pixmap = 0; + if (previousActiveContext && previousActiveContext != this) { + // If there was a previous context different from this one, just make it current again. + previousActiveContext->makeContextCurrent(); + } else { + // If there was no previous context or this was the previous, set a void context as current. + // We use the GLX function here, and the destructor of GLContext will clean the pointer + // returned by GLContext::current(). + glXMakeCurrent(m_x11Display, None, None); + } } } @@ -227,7 +306,7 @@ IntSize GLContextGLX::defaultFrameBufferSize() int x, y; Window rootWindow; unsigned int width, height, borderWidth, depth; - if (!XGetGeometry(sharedX11Display(), m_window, &rootWindow, &x, &y, &width, &height, &borderWidth, &depth)) + if (!XGetGeometry(m_x11Display, m_window, &rootWindow, &x, &y, &width, &height, &borderWidth, &depth)) return IntSize(); return IntSize(width, height); @@ -238,22 +317,22 @@ bool GLContextGLX::makeContextCurrent() ASSERT(m_context && (m_window || m_pbuffer || m_glxPixmap)); GLContext::makeContextCurrent(); - if (glXGetCurrentContext() == m_context) + if (glXGetCurrentContext() == m_context.get()) return true; if (m_window) - return glXMakeCurrent(sharedX11Display(), m_window, m_context); + return glXMakeCurrent(m_x11Display, m_window, m_context.get()); if (m_pbuffer) - return glXMakeCurrent(sharedX11Display(), m_pbuffer, m_context); + return glXMakeCurrent(m_x11Display, m_pbuffer.get(), m_context.get()); - return ::glXMakeCurrent(sharedX11Display(), m_glxPixmap, m_context); + return ::glXMakeCurrent(m_x11Display, m_glxPixmap.get(), m_context.get()); } void GLContextGLX::swapBuffers() { if (m_window) - glXSwapBuffers(sharedX11Display(), m_window); + glXSwapBuffers(m_x11Display, m_window); } void GLContextGLX::waitNative() @@ -261,22 +340,29 @@ void GLContextGLX::waitNative() glXWaitX(); } +void GLContextGLX::swapInterval(int interval) +{ + if (!hasSGISwapControlExtension(m_x11Display)) + return; + glXSwapIntervalSGI(interval); +} + cairo_device_t* GLContextGLX::cairoDevice() { if (m_cairoDevice) return m_cairoDevice; -#if ENABLE(ACCELERATED_2D_CANVAS) - m_cairoDevice = cairo_glx_device_create(sharedX11Display(), m_context); +#if ENABLE(ACCELERATED_2D_CANVAS) && CAIRO_HAS_GLX_FUNCTIONS + m_cairoDevice = cairo_glx_device_create(m_x11Display, m_context.get()); #endif return m_cairoDevice; } -#if USE(3D_GRAPHICS) +#if ENABLE(GRAPHICS_CONTEXT_3D) PlatformGraphicsContext3D GLContextGLX::platformContext() { - return m_context; + return m_context.get(); } #endif diff --git a/Source/WebCore/platform/graphics/glx/GLContextGLX.h b/Source/WebCore/platform/graphics/glx/GLContextGLX.h index edefc04c2..ca24024f6 100644 --- a/Source/WebCore/platform/graphics/glx/GLContextGLX.h +++ b/Source/WebCore/platform/graphics/glx/GLContextGLX.h @@ -17,58 +17,61 @@ * Boston, MA 02110-1301 USA */ -#ifndef GLContextGLX_h -#define GLContextGLX_h +#pragma once #if USE(GLX) #include "GLContext.h" +#include "XUniquePtr.h" +#include "XUniqueResource.h" -typedef struct __GLXcontextRec* GLXContext; -typedef unsigned long GLXPbuffer; -typedef unsigned long GLXPixmap; typedef unsigned char GLubyte; -typedef unsigned long Pixmap; -typedef unsigned long XID; +typedef unsigned long Window; typedef void* ContextKeyType; +typedef struct _XDisplay Display; namespace WebCore { -class GLContextGLX : public GLContext { +class GLContextGLX final : public GLContext { WTF_MAKE_NONCOPYABLE(GLContextGLX); public: - static PassOwnPtr<GLContextGLX> createContext(XID window, GLContext* sharingContext); - static PassOwnPtr<GLContextGLX> createWindowContext(XID window, GLContext* sharingContext); + static std::unique_ptr<GLContextGLX> createContext(GLNativeWindowType, PlatformDisplay&); + static std::unique_ptr<GLContextGLX> createSharingContext(PlatformDisplay&); virtual ~GLContextGLX(); - virtual bool makeContextCurrent(); - virtual void swapBuffers(); - virtual void waitNative(); - virtual bool canRenderToDefaultFramebuffer(); - virtual IntSize defaultFrameBufferSize(); - virtual cairo_device_t* cairoDevice(); -#if USE(3D_GRAPHICS) - virtual PlatformGraphicsContext3D platformContext(); +private: + bool makeContextCurrent() override; + void swapBuffers() override; + void waitNative() override; + bool canRenderToDefaultFramebuffer() override; + IntSize defaultFrameBufferSize() override; + void swapInterval(int) override; + cairo_device_t* cairoDevice() override; + bool isEGLContext() const override { return false; } + +#if ENABLE(GRAPHICS_CONTEXT_3D) + PlatformGraphicsContext3D platformContext() override; #endif -private: - static PassOwnPtr<GLContextGLX> createPbufferContext(GLXContext sharingContext); - static PassOwnPtr<GLContextGLX> createPixmapContext(GLXContext sharingContext); + GLContextGLX(PlatformDisplay&, XUniqueGLXContext&&, GLNativeWindowType); + GLContextGLX(PlatformDisplay&, XUniqueGLXContext&&, XUniqueGLXPbuffer&&); + GLContextGLX(PlatformDisplay&, XUniqueGLXContext&&, XUniquePixmap&&, XUniqueGLXPixmap&&); - GLContextGLX(GLXContext); - GLContextGLX(GLXContext, Pixmap, GLXPixmap); + static std::unique_ptr<GLContextGLX> createWindowContext(GLNativeWindowType, PlatformDisplay&, GLXContext sharingContext = nullptr); + static std::unique_ptr<GLContextGLX> createPbufferContext(PlatformDisplay&, GLXContext sharingContext = nullptr); + static std::unique_ptr<GLContextGLX> createPixmapContext(PlatformDisplay&, GLXContext sharingContext = nullptr); - GLXContext m_context; - XID m_window; - GLXPbuffer m_pbuffer; - Pixmap m_pixmap; - GLXPixmap m_glxPixmap; - cairo_device_t* m_cairoDevice; + Display* m_x11Display { nullptr }; + XUniqueGLXContext m_context; + Window m_window { 0 }; + XUniqueGLXPbuffer m_pbuffer; + XUniquePixmap m_pixmap; + XUniqueGLXPixmap m_glxPixmap; + cairo_device_t* m_cairoDevice { nullptr }; }; } // namespace WebCore #endif // USE(GLX) -#endif // GLContextGLX_h |