blob: d133276fb2d140694375889a53082eacfe43efeb [file] [log] [blame]
//
// Copyright 2015 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// FunctionsGLX.cpp: Implements the FunctionsGLX class.
#define ANGLE_SKIP_GLX_DEFINES 1
#include "libANGLE/renderer/gl/glx/FunctionsGLX.h"
#undef ANGLE_SKIP_GLX_DEFINES
// We can only include glx.h in files which do not include ANGLE's GLES
// headers, to avoid doubly-defined GLenum macros, typedefs, etc.
#include <GL/glx.h>
#include <dlfcn.h>
#include <algorithm>
#include "common/string_utils.h"
#include "libANGLE/renderer/gl/glx/functionsglx_typedefs.h"
namespace rx
{
void *FunctionsGLX::sLibHandle = nullptr;
template <typename T>
static bool GetProc(PFNGETPROCPROC getProc, T *member, const char *name)
{
*member = reinterpret_cast<T>(getProc(name));
return *member != nullptr;
}
struct FunctionsGLX::GLXFunctionTable
{
GLXFunctionTable()
: createContextPtr(nullptr),
destroyContextPtr(nullptr),
makeCurrentPtr(nullptr),
swapBuffersPtr(nullptr),
queryExtensionPtr(nullptr),
queryVersionPtr(nullptr),
getCurrentContextPtr(nullptr),
getCurrentDrawablePtr(nullptr),
waitXPtr(nullptr),
waitGLPtr(nullptr),
getClientStringPtr(nullptr),
queryExtensionsStringPtr(nullptr),
getFBConfigsPtr(nullptr),
chooseFBConfigPtr(nullptr),
getFBConfigAttribPtr(nullptr),
getVisualFromFBConfigPtr(nullptr),
createWindowPtr(nullptr),
destroyWindowPtr(nullptr),
createPbufferPtr(nullptr),
destroyPbufferPtr(nullptr),
queryDrawablePtr(nullptr),
createContextAttribsARBPtr(nullptr),
swapIntervalEXTPtr(nullptr),
swapIntervalMESAPtr(nullptr),
swapIntervalSGIPtr(nullptr),
getSyncValuesOMLPtr(nullptr)
{}
// GLX 1.0
PFNGLXCREATECONTEXTPROC createContextPtr;
PFNGLXDESTROYCONTEXTPROC destroyContextPtr;
PFNGLXMAKECURRENTPROC makeCurrentPtr;
PFNGLXSWAPBUFFERSPROC swapBuffersPtr;
PFNGLXQUERYEXTENSIONPROC queryExtensionPtr;
PFNGLXQUERYVERSIONPROC queryVersionPtr;
PFNGLXGETCURRENTCONTEXTPROC getCurrentContextPtr;
PFNGLXGETCURRENTDRAWABLEPROC getCurrentDrawablePtr;
PFNGLXWAITXPROC waitXPtr;
PFNGLXWAITGLPROC waitGLPtr;
// GLX 1.1
PFNGLXGETCLIENTSTRINGPROC getClientStringPtr;
PFNGLXQUERYEXTENSIONSSTRINGPROC queryExtensionsStringPtr;
// GLX 1.3
PFNGLXGETFBCONFIGSPROC getFBConfigsPtr;
PFNGLXCHOOSEFBCONFIGPROC chooseFBConfigPtr;
PFNGLXGETFBCONFIGATTRIBPROC getFBConfigAttribPtr;
PFNGLXGETVISUALFROMFBCONFIGPROC getVisualFromFBConfigPtr;
PFNGLXCREATEWINDOWPROC createWindowPtr;
PFNGLXDESTROYWINDOWPROC destroyWindowPtr;
PFNGLXCREATEPBUFFERPROC createPbufferPtr;
PFNGLXDESTROYPBUFFERPROC destroyPbufferPtr;
PFNGLXQUERYDRAWABLEPROC queryDrawablePtr;
// GLX_ARB_create_context
PFNGLXCREATECONTEXTATTRIBSARBPROC createContextAttribsARBPtr;
// GLX_EXT_swap_control
PFNGLXSWAPINTERVALEXTPROC swapIntervalEXTPtr;
// GLX_MESA_swap_control
PFNGLXSWAPINTERVALMESAPROC swapIntervalMESAPtr;
// GLX_SGI_swap_control
PFNGLXSWAPINTERVALSGIPROC swapIntervalSGIPtr;
// GLX_OML_sync_control
PFNGLXGETSYNCVALUESOMLPROC getSyncValuesOMLPtr;
};
FunctionsGLX::FunctionsGLX()
: majorVersion(0),
minorVersion(0),
mXDisplay(nullptr),
mXScreen(-1),
mFnPtrs(new GLXFunctionTable())
{}
FunctionsGLX::~FunctionsGLX()
{
delete mFnPtrs;
terminate();
}
bool FunctionsGLX::initialize(Display *xDisplay, int screen, std::string *errorString)
{
terminate();
mXDisplay = xDisplay;
mXScreen = screen;
#if !defined(ANGLE_LINK_GLX)
// Some OpenGL implementations can't handle having this library
// handle closed while there's any X window still open against
// which a GLXWindow was ever created.
if (!sLibHandle)
{
sLibHandle = dlopen("libGL.so.1", RTLD_NOW);
if (!sLibHandle)
{
*errorString = std::string("Could not dlopen libGL.so.1: ") + dlerror();
return false;
}
}
getProc = reinterpret_cast<PFNGETPROCPROC>(dlsym(sLibHandle, "glXGetProcAddress"));
if (!getProc)
{
getProc = reinterpret_cast<PFNGETPROCPROC>(dlsym(sLibHandle, "glXGetProcAddressARB"));
}
if (!getProc)
{
*errorString = "Could not retrieve glXGetProcAddress";
return false;
}
#else
getProc = reinterpret_cast<PFNGETPROCPROC>(glXGetProcAddress);
#endif
#define GET_PROC_OR_ERROR(MEMBER, NAME) \
do \
{ \
if (!GetProc(getProc, MEMBER, #NAME)) \
{ \
*errorString = "Could not load GLX entry point " #NAME; \
return false; \
} \
} while (0)
#if !defined(ANGLE_LINK_GLX)
# define GET_FNPTR_OR_ERROR(MEMBER, NAME) GET_PROC_OR_ERROR(MEMBER, NAME)
#else
# define GET_FNPTR_OR_ERROR(MEMBER, NAME) *MEMBER = NAME
#endif
// GLX 1.0
GET_FNPTR_OR_ERROR(&mFnPtrs->createContextPtr, glXCreateContext);
GET_FNPTR_OR_ERROR(&mFnPtrs->destroyContextPtr, glXDestroyContext);
GET_FNPTR_OR_ERROR(&mFnPtrs->makeCurrentPtr, glXMakeCurrent);
GET_FNPTR_OR_ERROR(&mFnPtrs->swapBuffersPtr, glXSwapBuffers);
GET_FNPTR_OR_ERROR(&mFnPtrs->queryExtensionPtr, glXQueryExtension);
GET_FNPTR_OR_ERROR(&mFnPtrs->queryVersionPtr, glXQueryVersion);
GET_FNPTR_OR_ERROR(&mFnPtrs->getCurrentContextPtr, glXGetCurrentContext);
GET_FNPTR_OR_ERROR(&mFnPtrs->getCurrentDrawablePtr, glXGetCurrentDrawable);
GET_FNPTR_OR_ERROR(&mFnPtrs->waitXPtr, glXWaitX);
GET_FNPTR_OR_ERROR(&mFnPtrs->waitGLPtr, glXWaitGL);
// GLX 1.1
GET_FNPTR_OR_ERROR(&mFnPtrs->getClientStringPtr, glXGetClientString);
GET_FNPTR_OR_ERROR(&mFnPtrs->queryExtensionsStringPtr, glXQueryExtensionsString);
// Check we have a working GLX
{
int errorBase;
int eventBase;
if (!queryExtension(&errorBase, &eventBase))
{
*errorString = "GLX is not present.";
return false;
}
}
// Check we have a supported version of GLX
if (!queryVersion(&majorVersion, &minorVersion))
{
*errorString = "Could not query the GLX version.";
return false;
}
if (majorVersion != 1 || minorVersion < 3)
{
*errorString = "Unsupported GLX version (requires at least 1.3).";
return false;
}
const char *extensions = queryExtensionsString();
if (!extensions)
{
*errorString = "glXQueryExtensionsString returned NULL";
return false;
}
angle::SplitStringAlongWhitespace(extensions, &mExtensions);
// GLX 1.3
GET_FNPTR_OR_ERROR(&mFnPtrs->getFBConfigsPtr, glXGetFBConfigs);
GET_FNPTR_OR_ERROR(&mFnPtrs->chooseFBConfigPtr, glXChooseFBConfig);
GET_FNPTR_OR_ERROR(&mFnPtrs->getFBConfigAttribPtr, glXGetFBConfigAttrib);
GET_FNPTR_OR_ERROR(&mFnPtrs->getVisualFromFBConfigPtr, glXGetVisualFromFBConfig);
GET_FNPTR_OR_ERROR(&mFnPtrs->createWindowPtr, glXCreateWindow);
GET_FNPTR_OR_ERROR(&mFnPtrs->destroyWindowPtr, glXDestroyWindow);
GET_FNPTR_OR_ERROR(&mFnPtrs->createPbufferPtr, glXCreatePbuffer);
GET_FNPTR_OR_ERROR(&mFnPtrs->destroyPbufferPtr, glXDestroyPbuffer);
GET_FNPTR_OR_ERROR(&mFnPtrs->queryDrawablePtr, glXQueryDrawable);
// Extensions
if (hasExtension("GLX_ARB_create_context"))
{
GET_PROC_OR_ERROR(&mFnPtrs->createContextAttribsARBPtr, glXCreateContextAttribsARB);
}
if (hasExtension("GLX_EXT_swap_control"))
{
GET_PROC_OR_ERROR(&mFnPtrs->swapIntervalEXTPtr, glXSwapIntervalEXT);
}
if (hasExtension("GLX_MESA_swap_control"))
{
GET_PROC_OR_ERROR(&mFnPtrs->swapIntervalMESAPtr, glXSwapIntervalMESA);
}
if (hasExtension("GLX_SGI_swap_control"))
{
GET_PROC_OR_ERROR(&mFnPtrs->swapIntervalSGIPtr, glXSwapIntervalSGI);
}
if (hasExtension("GLX_OML_sync_control"))
{
GET_PROC_OR_ERROR(&mFnPtrs->getSyncValuesOMLPtr, glXGetSyncValuesOML);
}
#undef GET_FNPTR_OR_ERROR
#undef GET_PROC_OR_ERROR
*errorString = "";
return true;
}
void FunctionsGLX::terminate() {}
bool FunctionsGLX::hasExtension(const char *extension) const
{
return std::find(mExtensions.begin(), mExtensions.end(), extension) != mExtensions.end();
}
Display *FunctionsGLX::getDisplay() const
{
return mXDisplay;
}
int FunctionsGLX::getScreen() const
{
return mXScreen;
}
// GLX functions
// GLX 1.0
glx::Context FunctionsGLX::createContext(XVisualInfo *visual, glx::Context share, bool direct) const
{
GLXContext shareCtx = reinterpret_cast<GLXContext>(share);
GLXContext context = mFnPtrs->createContextPtr(mXDisplay, visual, shareCtx, direct);
return reinterpret_cast<glx::Context>(context);
}
void FunctionsGLX::destroyContext(glx::Context context) const
{
GLXContext ctx = reinterpret_cast<GLXContext>(context);
mFnPtrs->destroyContextPtr(mXDisplay, ctx);
}
Bool FunctionsGLX::makeCurrent(glx::Drawable drawable, glx::Context context) const
{
GLXContext ctx = reinterpret_cast<GLXContext>(context);
return mFnPtrs->makeCurrentPtr(mXDisplay, drawable, ctx);
}
void FunctionsGLX::swapBuffers(glx::Drawable drawable) const
{
mFnPtrs->swapBuffersPtr(mXDisplay, drawable);
}
Bool FunctionsGLX::queryExtension(int *errorBase, int *event) const
{
return mFnPtrs->queryExtensionPtr(mXDisplay, errorBase, event);
}
Bool FunctionsGLX::queryVersion(int *major, int *minor) const
{
return mFnPtrs->queryVersionPtr(mXDisplay, major, minor);
}
glx::Context FunctionsGLX::getCurrentContext() const
{
GLXContext context = mFnPtrs->getCurrentContextPtr();
return reinterpret_cast<glx::Context>(context);
}
glx::Drawable FunctionsGLX::getCurrentDrawable() const
{
GLXDrawable drawable = mFnPtrs->getCurrentDrawablePtr();
return reinterpret_cast<glx::Drawable>(drawable);
}
void FunctionsGLX::waitX() const
{
mFnPtrs->waitXPtr();
}
void FunctionsGLX::waitGL() const
{
mFnPtrs->waitGLPtr();
}
// GLX 1.1
const char *FunctionsGLX::getClientString(int name) const
{
return mFnPtrs->getClientStringPtr(mXDisplay, name);
}
const char *FunctionsGLX::queryExtensionsString() const
{
return mFnPtrs->queryExtensionsStringPtr(mXDisplay, mXScreen);
}
// GLX 1.4
glx::FBConfig *FunctionsGLX::getFBConfigs(int *nElements) const
{
GLXFBConfig *configs = mFnPtrs->getFBConfigsPtr(mXDisplay, mXScreen, nElements);
return reinterpret_cast<glx::FBConfig *>(configs);
}
glx::FBConfig *FunctionsGLX::chooseFBConfig(const int *attribList, int *nElements) const
{
GLXFBConfig *configs = mFnPtrs->chooseFBConfigPtr(mXDisplay, mXScreen, attribList, nElements);
return reinterpret_cast<glx::FBConfig *>(configs);
}
int FunctionsGLX::getFBConfigAttrib(glx::FBConfig config, int attribute, int *value) const
{
GLXFBConfig cfg = reinterpret_cast<GLXFBConfig>(config);
return mFnPtrs->getFBConfigAttribPtr(mXDisplay, cfg, attribute, value);
}
XVisualInfo *FunctionsGLX::getVisualFromFBConfig(glx::FBConfig config) const
{
GLXFBConfig cfg = reinterpret_cast<GLXFBConfig>(config);
return mFnPtrs->getVisualFromFBConfigPtr(mXDisplay, cfg);
}
GLXWindow FunctionsGLX::createWindow(glx::FBConfig config,
Window window,
const int *attribList) const
{
GLXFBConfig cfg = reinterpret_cast<GLXFBConfig>(config);
return mFnPtrs->createWindowPtr(mXDisplay, cfg, window, attribList);
}
void FunctionsGLX::destroyWindow(glx::Window window) const
{
mFnPtrs->destroyWindowPtr(mXDisplay, window);
}
glx::Pbuffer FunctionsGLX::createPbuffer(glx::FBConfig config, const int *attribList) const
{
GLXFBConfig cfg = reinterpret_cast<GLXFBConfig>(config);
return mFnPtrs->createPbufferPtr(mXDisplay, cfg, attribList);
}
void FunctionsGLX::destroyPbuffer(glx::Pbuffer pbuffer) const
{
mFnPtrs->destroyPbufferPtr(mXDisplay, pbuffer);
}
void FunctionsGLX::queryDrawable(glx::Drawable drawable, int attribute, unsigned int *value) const
{
mFnPtrs->queryDrawablePtr(mXDisplay, drawable, attribute, value);
}
// GLX_ARB_create_context
glx::Context FunctionsGLX::createContextAttribsARB(glx::FBConfig config,
glx::Context shareContext,
Bool direct,
const int *attribList) const
{
GLXContext shareCtx = reinterpret_cast<GLXContext>(shareContext);
GLXFBConfig cfg = reinterpret_cast<GLXFBConfig>(config);
GLXContext ctx =
mFnPtrs->createContextAttribsARBPtr(mXDisplay, cfg, shareCtx, direct, attribList);
return reinterpret_cast<glx::Context>(ctx);
}
void FunctionsGLX::swapIntervalEXT(glx::Drawable drawable, int intervals) const
{
mFnPtrs->swapIntervalEXTPtr(mXDisplay, drawable, intervals);
}
int FunctionsGLX::swapIntervalMESA(int intervals) const
{
return mFnPtrs->swapIntervalMESAPtr(intervals);
}
int FunctionsGLX::swapIntervalSGI(int intervals) const
{
return mFnPtrs->swapIntervalSGIPtr(intervals);
}
bool FunctionsGLX::getSyncValuesOML(glx::Drawable drawable,
int64_t *ust,
int64_t *msc,
int64_t *sbc) const
{
return mFnPtrs->getSyncValuesOMLPtr(mXDisplay, drawable, ust, msc, sbc);
}
} // namespace rx