GraphicsContext3DInternal.cpp [plain text]
#include "config.h"
#include <wtf/PassOwnPtr.h>
#include "GraphicsContext3DInternal.h"
#if ENABLE(WEBGL)
#include "GraphicsContext3D.h"
#include "OpenGLShims.h"
#include <GL/glx.h>
#include <dlfcn.h>
static Display* gSharedDisplay = 0;
static Display* sharedDisplay()
{
if (!gSharedDisplay)
gSharedDisplay = XOpenDisplay(0);
return gSharedDisplay;
}
namespace WebCore {
static bool cleaningUpAtExit = false;
static Vector<GraphicsContext3D*>& activeGraphicsContexts()
{
DEFINE_STATIC_LOCAL(Vector<GraphicsContext3D*>, contexts, ());
return contexts;
}
void GraphicsContext3DInternal::addActiveGraphicsContext(GraphicsContext3D* context)
{
static bool addedAtExitHandler = false;
if (!addedAtExitHandler) {
atexit(&GraphicsContext3DInternal::cleanupActiveContextsAtExit);
addedAtExitHandler = true;
}
activeGraphicsContexts().append(context);
}
void GraphicsContext3DInternal::removeActiveGraphicsContext(GraphicsContext3D* context)
{
if (cleaningUpAtExit)
return;
Vector<GraphicsContext3D*>& contexts = activeGraphicsContexts();
size_t location = contexts.find(context);
if (location != WTF::notFound)
contexts.remove(location);
}
void GraphicsContext3DInternal::cleanupActiveContextsAtExit()
{
cleaningUpAtExit = true;
Vector<GraphicsContext3D*>& contexts = activeGraphicsContexts();
for (size_t i = 0; i < contexts.size(); i++)
contexts[i]->~GraphicsContext3D();
if (!gSharedDisplay)
return;
XCloseDisplay(gSharedDisplay);
gSharedDisplay = 0;
}
PassOwnPtr<GraphicsContext3DInternal> GraphicsContext3DInternal::create()
{
if (!sharedDisplay())
return nullptr;
static bool initialized = false;
static bool success = true;
if (!initialized) {
success = initializeOpenGLShims();
initialized = true;
}
if (!success)
return nullptr;
GraphicsContext3DInternal* internal = createPbufferContext();
if (!internal)
internal = createPixmapContext();
if (!internal)
return nullptr;
internal->makeContextCurrent();
return adoptPtr(internal);
}
GraphicsContext3DInternal* GraphicsContext3DInternal::createPbufferContext()
{
int fbConfigAttributes[] = {
GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT,
GLX_RENDER_TYPE, GLX_RGBA_BIT,
GLX_RED_SIZE, 1,
GLX_GREEN_SIZE, 1,
GLX_BLUE_SIZE, 1,
GLX_ALPHA_SIZE, 1,
GLX_DEPTH_SIZE, 1,
GLX_STENCIL_SIZE, 1,
GLX_SAMPLE_BUFFERS, 1,
GLX_DOUBLEBUFFER, GL_FALSE,
GLX_SAMPLES, 4,
0
};
int returnedElements;
GLXFBConfig* configs = glXChooseFBConfig(sharedDisplay(), 0, fbConfigAttributes, &returnedElements);
if (!configs) {
fbConfigAttributes[20] = 0; configs = glXChooseFBConfig(sharedDisplay(), 0, fbConfigAttributes, &returnedElements);
}
if (!returnedElements) {
XFree(configs);
return 0;
}
static const int pbufferAttributes[] = { GLX_PBUFFER_WIDTH, 1, GLX_PBUFFER_HEIGHT, 1, 0 };
GLXPbuffer pbuffer = glXCreatePbuffer(sharedDisplay(), configs[0], pbufferAttributes);
if (!pbuffer) {
XFree(configs);
return 0;
}
GLXContext context = glXCreateNewContext(sharedDisplay(), configs[0], GLX_RGBA_TYPE, 0, GL_TRUE);
XFree(configs);
if (!context)
return 0;
return new GraphicsContext3DInternal(context, pbuffer);
}
GraphicsContext3DInternal* GraphicsContext3DInternal::createPixmapContext()
{
static int visualAttributes[] = {
GLX_RGBA,
GLX_RED_SIZE, 1,
GLX_GREEN_SIZE, 1,
GLX_BLUE_SIZE, 1,
GLX_ALPHA_SIZE, 1,
GLX_DOUBLEBUFFER,
0
};
XVisualInfo* visualInfo = glXChooseVisual(sharedDisplay(), DefaultScreen(sharedDisplay()), visualAttributes);
if (!visualInfo)
return 0;
GLXContext context = glXCreateContext(sharedDisplay(), visualInfo, 0, GL_TRUE);
if (!context) {
XFree(visualInfo);
return 0;
}
Pixmap pixmap = XCreatePixmap(sharedDisplay(), DefaultRootWindow(sharedDisplay()), 1, 1, visualInfo->depth);
if (!pixmap) {
XFree(visualInfo);
return 0;
}
GLXPixmap glxPixmap = glXCreateGLXPixmap(sharedDisplay(), visualInfo, pixmap);
if (!glxPixmap) {
XFreePixmap(sharedDisplay(), pixmap);
XFree(visualInfo);
return 0;
}
return new GraphicsContext3DInternal(context, pixmap, glxPixmap);
}
GraphicsContext3DInternal::GraphicsContext3DInternal(GLXContext context, GLXPbuffer pbuffer)
: m_context(context)
, m_pbuffer(pbuffer)
, m_pixmap(0)
, m_glxPixmap(0)
{
}
GraphicsContext3DInternal::GraphicsContext3DInternal(GLXContext context, Pixmap pixmap, GLXPixmap glxPixmap)
: m_context(context)
, m_pbuffer(0)
, m_pixmap(pixmap)
, m_glxPixmap(glxPixmap)
{
}
GraphicsContext3DInternal::~GraphicsContext3DInternal()
{
if (m_context) {
::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
::glXMakeContextCurrent(sharedDisplay(), 0, 0, 0);
::glXDestroyContext(sharedDisplay(), m_context);
m_context = 0;
}
if (m_pbuffer) {
::glXDestroyPbuffer(sharedDisplay(), m_pbuffer);
m_pbuffer = 0;
}
if (m_glxPixmap) {
glXDestroyGLXPixmap(sharedDisplay(), m_glxPixmap);
m_glxPixmap = 0;
}
if (m_pixmap) {
XFreePixmap(sharedDisplay(), m_pixmap);
m_pixmap = 0;
}
}
void GraphicsContext3DInternal::makeContextCurrent()
{
if (::glXGetCurrentContext() == m_context)
return;
if (!m_context)
return;
if (m_pbuffer) {
::glXMakeCurrent(sharedDisplay(), m_pbuffer, m_context);
return;
}
ASSERT(m_glxPixmap);
::glXMakeCurrent(sharedDisplay(), m_glxPixmap, m_context);
}
}
#endif // ENABLE_WEBGL