diff options
Diffstat (limited to 'gfx/angle/src/libANGLE/renderer/gl/glx')
12 files changed, 2622 insertions, 0 deletions
diff --git a/gfx/angle/src/libANGLE/renderer/gl/glx/DisplayGLX.cpp b/gfx/angle/src/libANGLE/renderer/gl/glx/DisplayGLX.cpp new file mode 100755 index 000000000..e98401d0a --- /dev/null +++ b/gfx/angle/src/libANGLE/renderer/gl/glx/DisplayGLX.cpp @@ -0,0 +1,981 @@ +// +// Copyright (c) 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. +// + +// DisplayGLX.cpp: GLX implementation of egl::Display + +#include "libANGLE/renderer/gl/glx/DisplayGLX.h" + +#include <EGL/eglext.h> +#include <algorithm> +#include <cstring> +#include <fstream> + +#include "common/debug.h" +#include "libANGLE/Config.h" +#include "libANGLE/Display.h" +#include "libANGLE/Surface.h" +#include "libANGLE/renderer/gl/glx/PbufferSurfaceGLX.h" +#include "libANGLE/renderer/gl/glx/WindowSurfaceGLX.h" +#include "libANGLE/renderer/gl/RendererGL.h" +#include "libANGLE/renderer/gl/renderergl_utils.h" +#include "third_party/libXNVCtrl/NVCtrl.h" +#include "third_party/libXNVCtrl/NVCtrlLib.h" + +namespace +{ + +// Scan /etc/ati/amdpcsdb.default for "ReleaseVersion". +// Return empty string on failing. +egl::Error GetAMDDriverVersion(std::string *version) +{ + *version = ""; + + const char kAMDDriverInfoFileName[] = "/etc/ati/amdpcsdb.default"; + std::ifstream file(kAMDDriverInfoFileName); + + if (!file) + { + return egl::Error(EGL_SUCCESS); + } + + std::string line; + while (std::getline(file, line)) + { + static const char kReleaseVersion[] = "ReleaseVersion="; + if (line.compare(0, std::strlen(kReleaseVersion), kReleaseVersion) != 0) + { + continue; + } + + const size_t begin = line.find_first_of("0123456789"); + if (begin == std::string::npos) + { + continue; + } + + const size_t end = line.find_first_not_of("0123456789.", begin); + if (end == std::string::npos) + { + *version = line.substr(begin); + } + else + { + *version = line.substr(begin, end - begin); + } + return egl::Error(EGL_SUCCESS); + } + return egl::Error(EGL_SUCCESS); +} + +} // anonymous namespace + +namespace rx +{ + +static int IgnoreX11Errors(Display *, XErrorEvent *) +{ + return 0; +} + +SwapControlData::SwapControlData() + : targetSwapInterval(0), + maxSwapInterval(-1), + currentSwapInterval(-1) +{ +} + +class FunctionsGLGLX : public FunctionsGL +{ + public: + FunctionsGLGLX(PFNGETPROCPROC getProc) + : mGetProc(getProc) + { + } + + ~FunctionsGLGLX() override {} + + private: + void *loadProcAddress(const std::string &function) override + { + return reinterpret_cast<void*>(mGetProc(function.c_str())); + } + + PFNGETPROCPROC mGetProc; +}; + +DisplayGLX::DisplayGLX() + : DisplayGL(), + mFunctionsGL(nullptr), + mRequestedVisual(-1), + mContextConfig(nullptr), + mContext(nullptr), + mDummyPbuffer(0), + mUsesNewXDisplay(false), + mIsMesa(false), + mHasMultisample(false), + mHasARBCreateContext(false), + mHasARBCreateContextProfile(false), + mHasARBCreateContextRobustness(false), + mHasEXTCreateContextES2Profile(false), + mSwapControl(SwapControl::Absent), + mMinSwapInterval(0), + mMaxSwapInterval(0), + mCurrentSwapInterval(-1), + mXDisplay(nullptr), + mEGLDisplay(nullptr) +{ +} + +DisplayGLX::~DisplayGLX() +{ +} + +egl::Error DisplayGLX::initialize(egl::Display *display) +{ + mEGLDisplay = display; + mXDisplay = display->getNativeDisplayId(); + const auto &attribMap = display->getAttributeMap(); + + // ANGLE_platform_angle allows the creation of a default display + // using EGL_DEFAULT_DISPLAY (= nullptr). In this case just open + // the display specified by the DISPLAY environment variable. + if (mXDisplay == EGL_DEFAULT_DISPLAY) + { + mUsesNewXDisplay = true; + mXDisplay = XOpenDisplay(NULL); + if (!mXDisplay) + { + return egl::Error(EGL_NOT_INITIALIZED, "Could not open the default X display."); + } + } + + std::string glxInitError; + if (!mGLX.initialize(mXDisplay, DefaultScreen(mXDisplay), &glxInitError)) + { + return egl::Error(EGL_NOT_INITIALIZED, glxInitError.c_str()); + } + + mHasMultisample = mGLX.minorVersion > 3 || mGLX.hasExtension("GLX_ARB_multisample"); + mHasARBCreateContext = mGLX.hasExtension("GLX_ARB_create_context"); + mHasARBCreateContextProfile = mGLX.hasExtension("GLX_ARB_create_context_profile"); + mHasARBCreateContextRobustness = mGLX.hasExtension("GLX_ARB_create_context_robustness"); + mHasEXTCreateContextES2Profile = mGLX.hasExtension("GLX_EXT_create_context_es2_profile"); + + std::string clientVendor = mGLX.getClientString(GLX_VENDOR); + mIsMesa = clientVendor.find("Mesa") != std::string::npos; + + // Choose the swap_control extension to use, if any. + // The EXT version is better as it allows glXSwapInterval to be called per + // window, while we'll potentially need to change the swap interval on each + // swap buffers when using the SGI or MESA versions. + if (mGLX.hasExtension("GLX_EXT_swap_control")) + { + mSwapControl = SwapControl::EXT; + + // In GLX_EXT_swap_control querying these is done on a GLXWindow so we just + // set default values. + mMinSwapInterval = 0; + mMaxSwapInterval = 4; + } + else if (mGLX.hasExtension("GLX_MESA_swap_control")) + { + // If we have the Mesa or SGI extension, assume that you can at least set + // a swap interval of 0 or 1. + mSwapControl = SwapControl::Mesa; + mMinSwapInterval = 0; + mMinSwapInterval = 1; + } + else if (mGLX.hasExtension("GLX_SGI_swap_control")) + { + mSwapControl = SwapControl::SGI; + mMinSwapInterval = 0; + mMinSwapInterval = 1; + } + else + { + mSwapControl = SwapControl::Absent; + mMinSwapInterval = 1; + mMinSwapInterval = 1; + } + + if (attribMap.contains(EGL_X11_VISUAL_ID_ANGLE)) + { + mRequestedVisual = static_cast<EGLint>(attribMap.get(EGL_X11_VISUAL_ID_ANGLE, -1)); + + // There is no direct way to get the GLXFBConfig matching an X11 visual ID + // so we have to iterate over all the GLXFBConfigs to find the right one. + int nConfigs; + int attribList[] = { + None, + }; + glx::FBConfig *allConfigs = mGLX.chooseFBConfig(attribList, &nConfigs); + + for (int i = 0; i < nConfigs; ++i) + { + if (getGLXFBConfigAttrib(allConfigs[i], GLX_VISUAL_ID) == mRequestedVisual) + { + mContextConfig = allConfigs[i]; + break; + } + } + XFree(allConfigs); + + if (mContextConfig == nullptr) + { + return egl::Error(EGL_NOT_INITIALIZED, "Invalid visual ID requested."); + } + } + else + { + // When glXMakeCurrent is called, the context and the surface must be + // compatible which in glX-speak means that their config have the same + // color buffer type, are both RGBA or ColorIndex, and their buffers have + // the same depth, if they exist. + // Since our whole EGL implementation is backed by only one GL context, this + // context must be compatible with all the GLXFBConfig corresponding to the + // EGLconfigs that we will be exposing. + int nConfigs; + int attribList[] = + { + // We want RGBA8 and DEPTH24_STENCIL8 + GLX_RED_SIZE, 8, + GLX_GREEN_SIZE, 8, + GLX_BLUE_SIZE, 8, + GLX_ALPHA_SIZE, 8, + GLX_DEPTH_SIZE, 24, + GLX_STENCIL_SIZE, 8, + // We want RGBA rendering (vs COLOR_INDEX) and doublebuffer + GLX_RENDER_TYPE, GLX_RGBA_BIT, + // Double buffer is not strictly required as a non-doublebuffer + // context can work with a doublebuffered surface, but it still + // flickers and all applications want doublebuffer anyway. + GLX_DOUBLEBUFFER, True, + // All of these must be supported for full EGL support + GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT | GLX_PBUFFER_BIT | GLX_PIXMAP_BIT, + // This makes sure the config have an associated visual Id + GLX_X_RENDERABLE, True, + GLX_CONFIG_CAVEAT, GLX_NONE, + None + }; + glx::FBConfig *candidates = mGLX.chooseFBConfig(attribList, &nConfigs); + if (nConfigs == 0) + { + XFree(candidates); + return egl::Error(EGL_NOT_INITIALIZED, "Could not find a decent GLX FBConfig to create the context."); + } + mContextConfig = candidates[0]; + XFree(candidates); + } + + const auto &eglAttributes = display->getAttributeMap(); + if (mHasARBCreateContext) + { + egl::Error error = initializeContext(mContextConfig, eglAttributes, &mContext); + if (error.isError()) + { + return error; + } + } + else + { + if (eglAttributes.get(EGL_PLATFORM_ANGLE_TYPE_ANGLE, + EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE) == + EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE) + { + return egl::Error(EGL_NOT_INITIALIZED, + "Cannot create an OpenGL ES platform on GLX without the " + "GLX_ARB_create_context extension."); + } + + XVisualInfo visualTemplate; + visualTemplate.visualid = getGLXFBConfigAttrib(mContextConfig, GLX_VISUAL_ID); + + int numVisuals = 0; + XVisualInfo *visuals = + XGetVisualInfo(mXDisplay, VisualIDMask, &visualTemplate, &numVisuals); + if (numVisuals <= 0) + { + return egl::Error(EGL_NOT_INITIALIZED, + "Could not get the visual info from the fb config"); + } + ASSERT(numVisuals == 1); + + mContext = mGLX.createContext(&visuals[0], nullptr, true); + XFree(visuals); + + if (!mContext) + { + return egl::Error(EGL_NOT_INITIALIZED, "Could not create GL context."); + } + } + ASSERT(mContext); + + // FunctionsGL and DisplayGL need to make a few GL calls, for example to + // query the version of the context so we need to make the context current. + // glXMakeCurrent requires a GLXDrawable so we create a temporary Pbuffer + // (of size 1, 1) for the duration of these calls. + // Ideally we would want to unset the current context and destroy the pbuffer + // before going back to the application but this is TODO + // We could use a pbuffer of size (0, 0) but it fails on the Intel Mesa driver + // as commented on https://bugs.freedesktop.org/show_bug.cgi?id=38869 so we + // use (1, 1) instead. + + int dummyPbufferAttribs[] = + { + GLX_PBUFFER_WIDTH, 1, + GLX_PBUFFER_HEIGHT, 1, + None, + }; + mDummyPbuffer = mGLX.createPbuffer(mContextConfig, dummyPbufferAttribs); + if (!mDummyPbuffer) + { + return egl::Error(EGL_NOT_INITIALIZED, "Could not create the dummy pbuffer."); + } + + if (!mGLX.makeCurrent(mDummyPbuffer, mContext)) + { + return egl::Error(EGL_NOT_INITIALIZED, "Could not make the dummy pbuffer current."); + } + + mFunctionsGL = new FunctionsGLGLX(mGLX.getProc); + mFunctionsGL->initialize(); + + // TODO(cwallez, angleproject:1303) Disable the OpenGL ES backend on Linux NVIDIA and Intel as + // it has problems on our automated testing. An OpenGL ES backend might not trigger this test if + // there is no Desktop OpenGL support, but that's not the case in our automated testing. + VendorID vendor = GetVendorID(mFunctionsGL); + bool isOpenGLES = + eglAttributes.get(EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE) == + EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE; + if (isOpenGLES && (IsIntel(vendor) || IsNvidia(vendor))) + { + return egl::Error(EGL_NOT_INITIALIZED, "Intel or NVIDIA OpenGL ES drivers are not supported."); + } + + syncXCommands(); + + return DisplayGL::initialize(display); +} + +void DisplayGLX::terminate() +{ + DisplayGL::terminate(); + + if (mDummyPbuffer) + { + mGLX.destroyPbuffer(mDummyPbuffer); + mDummyPbuffer = 0; + } + + if (mContext) + { + mGLX.destroyContext(mContext); + mContext = nullptr; + } + + mGLX.terminate(); + + SafeDelete(mFunctionsGL); +} + +SurfaceImpl *DisplayGLX::createWindowSurface(const egl::SurfaceState &state, + const egl::Config *configuration, + EGLNativeWindowType window, + const egl::AttributeMap &attribs) +{ + ASSERT(configIdToGLXConfig.count(configuration->configID) > 0); + glx::FBConfig fbConfig = configIdToGLXConfig[configuration->configID]; + + return new WindowSurfaceGLX(state, mGLX, this, getRenderer(), window, mGLX.getDisplay(), + mContext, fbConfig); +} + +SurfaceImpl *DisplayGLX::createPbufferSurface(const egl::SurfaceState &state, + const egl::Config *configuration, + const egl::AttributeMap &attribs) +{ + ASSERT(configIdToGLXConfig.count(configuration->configID) > 0); + glx::FBConfig fbConfig = configIdToGLXConfig[configuration->configID]; + + EGLint width = static_cast<EGLint>(attribs.get(EGL_WIDTH, 0)); + EGLint height = static_cast<EGLint>(attribs.get(EGL_HEIGHT, 0)); + bool largest = (attribs.get(EGL_LARGEST_PBUFFER, EGL_FALSE) == EGL_TRUE); + + return new PbufferSurfaceGLX(state, getRenderer(), width, height, largest, mGLX, mContext, + fbConfig); +} + +SurfaceImpl *DisplayGLX::createPbufferFromClientBuffer(const egl::SurfaceState &state, + const egl::Config *configuration, + EGLenum buftype, + EGLClientBuffer clientBuffer, + const egl::AttributeMap &attribs) +{ + UNIMPLEMENTED(); + return nullptr; +} + +SurfaceImpl *DisplayGLX::createPixmapSurface(const egl::SurfaceState &state, + const egl::Config *configuration, + NativePixmapType nativePixmap, + const egl::AttributeMap &attribs) +{ + UNIMPLEMENTED(); + return nullptr; +} + +egl::Error DisplayGLX::getDevice(DeviceImpl **device) +{ + UNIMPLEMENTED(); + return egl::Error(EGL_BAD_DISPLAY); +} + +egl::Error DisplayGLX::initializeContext(glx::FBConfig config, + const egl::AttributeMap &eglAttributes, + glx::Context *context) +{ + int profileMask = 0; + + EGLint requestedDisplayType = static_cast<EGLint>( + eglAttributes.get(EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE)); + if (requestedDisplayType == EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE) + { + if (!mHasEXTCreateContextES2Profile) + { + return egl::Error(EGL_NOT_INITIALIZED, + "Cannot create an OpenGL ES platform on GLX without the " + "GLX_EXT_create_context_es_profile extension."); + } + + ASSERT(mHasARBCreateContextProfile); + profileMask |= GLX_CONTEXT_ES2_PROFILE_BIT_EXT; + } + + // Create a context of the requested version, if any. + gl::Version requestedVersion(static_cast<EGLint>(eglAttributes.get( + EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, EGL_DONT_CARE)), + static_cast<EGLint>(eglAttributes.get( + EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE, EGL_DONT_CARE))); + if (static_cast<EGLint>(requestedVersion.major) != EGL_DONT_CARE && + static_cast<EGLint>(requestedVersion.minor) != EGL_DONT_CARE) + { + if (!(profileMask & GLX_CONTEXT_ES2_PROFILE_BIT_EXT) && + requestedVersion >= gl::Version(3, 2)) + { + profileMask |= GLX_CONTEXT_CORE_PROFILE_BIT_ARB; + } + return createContextAttribs(config, requestedVersion, profileMask, context); + } + + // It is commonly assumed that glXCreateContextAttrib will create a context + // of the highest version possible but it is not specified in the spec and + // is not true on the Mesa drivers. On Mesa, Instead we try to create a + // context per GL version until we succeed, starting from newer version. + // On both Mesa and other drivers we try to create a desktop context and fall + // back to ES context. + // The code could be simpler if the Mesa code path was used for all drivers, + // however the cost of failing a context creation can be high (3 milliseconds + // for the NVIDIA driver). The good thing is that failed context creation only + // takes 0.1 milliseconds on Mesa. + + struct ContextCreationInfo + { + EGLint displayType; + int profileFlag; + Optional<gl::Version> version; + }; + + // clang-format off + // For regular drivers we try to create a core, compatibility, then ES context. + // Without requiring any specific version (the Optional version is undefined). + const ContextCreationInfo contextsToTry[] = { + { EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, {} }, + { EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE, 0, {} }, + { EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE, GLX_CONTEXT_ES2_PROFILE_BIT_EXT, {} }, + }; + + // On Mesa we try to create a core context, except for versions below 3.2 + // where it is not applicable. (and fallback to ES as well) + const ContextCreationInfo mesaContextsToTry[] = { + { EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, { gl::Version(4, 5) } }, + { EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, { gl::Version(4, 4) } }, + { EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, { gl::Version(4, 3) } }, + { EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, { gl::Version(4, 2) } }, + { EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, { gl::Version(4, 1) } }, + { EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, { gl::Version(4, 0) } }, + { EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, { gl::Version(3, 3) } }, + { EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, { gl::Version(3, 2) } }, + { EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE, 0, { gl::Version(3, 1) } }, + { EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE, 0, { gl::Version(3, 0) } }, + { EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE, 0, { gl::Version(2, 0) } }, + { EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE, 0, { gl::Version(1, 5) } }, + { EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE, 0, { gl::Version(1, 4) } }, + { EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE, 0, { gl::Version(1, 3) } }, + { EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE, 0, { gl::Version(1, 2) } }, + { EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE, 0, { gl::Version(1, 1) } }, + { EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE, 0, { gl::Version(1, 0) } }, + { EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE, GLX_CONTEXT_ES2_PROFILE_BIT_EXT, { gl::Version(3, 2) } }, + { EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE, GLX_CONTEXT_ES2_PROFILE_BIT_EXT, { gl::Version(3, 1) } }, + { EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE, GLX_CONTEXT_ES2_PROFILE_BIT_EXT, { gl::Version(3, 0) } }, + { EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE, GLX_CONTEXT_ES2_PROFILE_BIT_EXT, { gl::Version(2, 0) } }, + }; + // clang-format on + + const ContextCreationInfo *toTry = contextsToTry; + size_t toTryLength = ArraySize(contextsToTry); + if (mIsMesa) + { + toTry = mesaContextsToTry; + toTryLength = ArraySize(mesaContextsToTry); + } + + // NOTE: below we return as soon as we're able to create a context so the + // "error" variable is EGL_SUCCESS when returned contrary to the common idiom + // of returning "error" when there is an actual error. + for (size_t i = 0; i < toTryLength; ++i) + { + const ContextCreationInfo &info = toTry[i]; + if (requestedDisplayType != EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE && + requestedDisplayType != info.displayType) + { + continue; + } + + egl::Error error = createContextAttribs(config, info.version, info.profileFlag, context); + if (!error.isError()) + { + return error; + } + } + + return egl::Error(EGL_NOT_INITIALIZED, "Could not create a backing OpenGL context."); +} + +egl::ConfigSet DisplayGLX::generateConfigs() +{ + egl::ConfigSet configs; + configIdToGLXConfig.clear(); + + const gl::Version &maxVersion = getMaxSupportedESVersion(); + ASSERT(maxVersion >= gl::Version(2, 0)); + bool supportsES3 = maxVersion >= gl::Version(3, 0); + + int contextRedSize = getGLXFBConfigAttrib(mContextConfig, GLX_RED_SIZE); + int contextGreenSize = getGLXFBConfigAttrib(mContextConfig, GLX_GREEN_SIZE); + int contextBlueSize = getGLXFBConfigAttrib(mContextConfig, GLX_BLUE_SIZE); + int contextAlphaSize = getGLXFBConfigAttrib(mContextConfig, GLX_ALPHA_SIZE); + + int contextDepthSize = getGLXFBConfigAttrib(mContextConfig, GLX_DEPTH_SIZE); + int contextStencilSize = getGLXFBConfigAttrib(mContextConfig, GLX_STENCIL_SIZE); + + int contextSamples = mHasMultisample ? getGLXFBConfigAttrib(mContextConfig, GLX_SAMPLES) : 0; + int contextSampleBuffers = + mHasMultisample ? getGLXFBConfigAttrib(mContextConfig, GLX_SAMPLE_BUFFERS) : 0; + + int contextAccumRedSize = getGLXFBConfigAttrib(mContextConfig, GLX_ACCUM_RED_SIZE); + int contextAccumGreenSize = getGLXFBConfigAttrib(mContextConfig, GLX_ACCUM_GREEN_SIZE); + int contextAccumBlueSize = getGLXFBConfigAttrib(mContextConfig, GLX_ACCUM_BLUE_SIZE); + int contextAccumAlphaSize = getGLXFBConfigAttrib(mContextConfig, GLX_ACCUM_ALPHA_SIZE); + + int attribList[] = + { + GLX_RENDER_TYPE, GLX_RGBA_BIT, + GLX_X_RENDERABLE, True, + GLX_DOUBLEBUFFER, True, + None, + }; + + int glxConfigCount; + glx::FBConfig *glxConfigs = mGLX.chooseFBConfig(attribList, &glxConfigCount); + + for (int i = 0; i < glxConfigCount; i++) + { + glx::FBConfig glxConfig = glxConfigs[i]; + egl::Config config; + + // Native stuff + config.nativeVisualID = getGLXFBConfigAttrib(glxConfig, GLX_VISUAL_ID); + config.nativeVisualType = getGLXFBConfigAttrib(glxConfig, GLX_X_VISUAL_TYPE); + config.nativeRenderable = EGL_TRUE; + + // When a visual ID has been specified with EGL_ANGLE_x11_visual we should + // only return configs with this visual: it will maximize performance by avoid + // blits in the driver when showing the window on the screen. + if (mRequestedVisual != -1 && config.nativeVisualID != mRequestedVisual) + { + continue; + } + + // Buffer sizes + config.redSize = getGLXFBConfigAttrib(glxConfig, GLX_RED_SIZE); + config.greenSize = getGLXFBConfigAttrib(glxConfig, GLX_GREEN_SIZE); + config.blueSize = getGLXFBConfigAttrib(glxConfig, GLX_BLUE_SIZE); + config.alphaSize = getGLXFBConfigAttrib(glxConfig, GLX_ALPHA_SIZE); + config.depthSize = getGLXFBConfigAttrib(glxConfig, GLX_DEPTH_SIZE); + config.stencilSize = getGLXFBConfigAttrib(glxConfig, GLX_STENCIL_SIZE); + + // We require RGBA8 and the D24S8 (or no DS buffer) + if (config.redSize != contextRedSize || config.greenSize != contextGreenSize || + config.blueSize != contextBlueSize || config.alphaSize != contextAlphaSize) + { + continue; + } + // The GLX spec says that it is ok for a whole buffer to not be present + // however the Mesa Intel driver (and probably on other Mesa drivers) + // fails to make current when the Depth stencil doesn't exactly match the + // configuration. + bool hasSameDepthStencil = + config.depthSize == contextDepthSize && config.stencilSize == contextStencilSize; + bool hasNoDepthStencil = config.depthSize == 0 && config.stencilSize == 0; + if (!hasSameDepthStencil && (mIsMesa || !hasNoDepthStencil)) + { + continue; + } + + config.colorBufferType = EGL_RGB_BUFFER; + config.luminanceSize = 0; + config.alphaMaskSize = 0; + + config.bufferSize = config.redSize + config.greenSize + config.blueSize + config.alphaSize; + + // Multisample and accumulation buffers + int samples = mHasMultisample ? getGLXFBConfigAttrib(glxConfig, GLX_SAMPLES) : 0; + int sampleBuffers = + mHasMultisample ? getGLXFBConfigAttrib(glxConfig, GLX_SAMPLE_BUFFERS) : 0; + + int accumRedSize = getGLXFBConfigAttrib(glxConfig, GLX_ACCUM_RED_SIZE); + int accumGreenSize = getGLXFBConfigAttrib(glxConfig, GLX_ACCUM_GREEN_SIZE); + int accumBlueSize = getGLXFBConfigAttrib(glxConfig, GLX_ACCUM_BLUE_SIZE); + int accumAlphaSize = getGLXFBConfigAttrib(glxConfig, GLX_ACCUM_ALPHA_SIZE); + + if (samples != contextSamples || + sampleBuffers != contextSampleBuffers || + accumRedSize != contextAccumRedSize || + accumGreenSize != contextAccumGreenSize || + accumBlueSize != contextAccumBlueSize || + accumAlphaSize != contextAccumAlphaSize) + { + continue; + } + + config.samples = samples; + config.sampleBuffers = sampleBuffers; + + // Transparency + if (getGLXFBConfigAttrib(glxConfig, GLX_TRANSPARENT_TYPE) == GLX_TRANSPARENT_RGB) + { + config.transparentType = EGL_TRANSPARENT_RGB; + config.transparentRedValue = getGLXFBConfigAttrib(glxConfig, GLX_TRANSPARENT_RED_VALUE); + config.transparentGreenValue = getGLXFBConfigAttrib(glxConfig, GLX_TRANSPARENT_GREEN_VALUE); + config.transparentBlueValue = getGLXFBConfigAttrib(glxConfig, GLX_TRANSPARENT_BLUE_VALUE); + } + else + { + config.transparentType = EGL_NONE; + } + + // Pbuffer + config.maxPBufferWidth = getGLXFBConfigAttrib(glxConfig, GLX_MAX_PBUFFER_WIDTH); + config.maxPBufferHeight = getGLXFBConfigAttrib(glxConfig, GLX_MAX_PBUFFER_HEIGHT); + config.maxPBufferPixels = getGLXFBConfigAttrib(glxConfig, GLX_MAX_PBUFFER_PIXELS); + + // Caveat + config.configCaveat = EGL_NONE; + + int caveat = getGLXFBConfigAttrib(glxConfig, GLX_CONFIG_CAVEAT); + if (caveat == GLX_SLOW_CONFIG) + { + config.configCaveat = EGL_SLOW_CONFIG; + } + else if (caveat == GLX_NON_CONFORMANT_CONFIG) + { + continue; + } + + // Misc + config.level = getGLXFBConfigAttrib(glxConfig, GLX_LEVEL); + + config.bindToTextureRGB = EGL_FALSE; + config.bindToTextureRGBA = EGL_FALSE; + + int glxDrawable = getGLXFBConfigAttrib(glxConfig, GLX_DRAWABLE_TYPE); + config.surfaceType = 0 | + (glxDrawable & GLX_WINDOW_BIT ? EGL_WINDOW_BIT : 0) | + (glxDrawable & GLX_PBUFFER_BIT ? EGL_PBUFFER_BIT : 0) | + (glxDrawable & GLX_PIXMAP_BIT ? EGL_PIXMAP_BIT : 0); + + config.minSwapInterval = mMinSwapInterval; + config.maxSwapInterval = mMaxSwapInterval; + + // TODO(cwallez) wildly guessing these formats, another TODO says they should be removed anyway + config.renderTargetFormat = GL_RGBA8; + config.depthStencilFormat = GL_DEPTH24_STENCIL8; + + config.conformant = EGL_OPENGL_ES2_BIT | (supportsES3 ? EGL_OPENGL_ES3_BIT_KHR : 0); + config.renderableType = config.conformant; + + // TODO(cwallez) I have no idea what this is + config.matchNativePixmap = EGL_NONE; + + int id = configs.add(config); + configIdToGLXConfig[id] = glxConfig; + } + + XFree(glxConfigs); + + return configs; +} + +bool DisplayGLX::testDeviceLost() +{ + if (mHasARBCreateContextRobustness) + { + return getRenderer()->getResetStatus() != GL_NO_ERROR; + } + + return false; +} + +egl::Error DisplayGLX::restoreLostDevice() +{ + return egl::Error(EGL_BAD_DISPLAY); +} + +bool DisplayGLX::isValidNativeWindow(EGLNativeWindowType window) const +{ + // There is no function in Xlib to check the validity of a Window directly. + // However a small number of functions used to obtain window information + // return a status code (0 meaning failure) and guarantee that they will + // fail if the window doesn't exist (the rational is that these function + // are used by window managers). Out of these function we use XQueryTree + // as it seems to be the simplest; a drawback is that it will allocate + // memory for the list of children, because we use a child window for + // WindowSurface. + Window root; + Window parent; + Window *children = nullptr; + unsigned nChildren; + int status = XQueryTree(mGLX.getDisplay(), window, &root, &parent, &children, &nChildren); + if (children) + { + XFree(children); + } + return status != 0; +} + +std::string DisplayGLX::getVendorString() const +{ + // UNIMPLEMENTED(); + return ""; +} + +egl::Error DisplayGLX::waitClient() const +{ + mGLX.waitGL(); + return egl::Error(EGL_SUCCESS); +} + +egl::Error DisplayGLX::getDriverVersion(std::string *version) const +{ + VendorID vendor = GetVendorID(mFunctionsGL); + + switch (vendor) + { + case VENDOR_ID_NVIDIA: + return getNVIDIADriverVersion(version); + case VENDOR_ID_AMD: + return GetAMDDriverVersion(version); + default: + *version = ""; + return egl::Error(EGL_SUCCESS); + } +} + +egl::Error DisplayGLX::waitNative(EGLint engine, + egl::Surface *drawSurface, + egl::Surface *readSurface) const +{ + // eglWaitNative is used to notice the driver of changes in X11 for the current surface, such as + // changes of the window size. We use this event to update the child window of WindowSurfaceGLX + // to match its parent window's size. + // Handling eglWaitNative this way helps the application control when resize happens. This is + // important because drivers have a tendency to clobber the back buffer when the windows are + // resized. See http://crbug.com/326995 + if (drawSurface != nullptr) + { + SurfaceGLX *glxDrawSurface = GetImplAs<SurfaceGLX>(drawSurface); + egl::Error error = glxDrawSurface->checkForResize(); + if (error.isError()) + { + return error; + } + } + + if (readSurface != drawSurface && readSurface != nullptr) + { + SurfaceGLX *glxReadSurface = GetImplAs<SurfaceGLX>(readSurface); + egl::Error error = glxReadSurface->checkForResize(); + if (error.isError()) + { + return error; + } + } + + // We still need to forward the resizing of the child window to the driver. + mGLX.waitX(); + return egl::Error(EGL_SUCCESS); +} + +void DisplayGLX::syncXCommands() const +{ + if (mUsesNewXDisplay) + { + XSync(mGLX.getDisplay(), False); + } +} + +void DisplayGLX::setSwapInterval(glx::Drawable drawable, SwapControlData *data) +{ + ASSERT(data != nullptr); + + // TODO(cwallez) error checking? + if (mSwapControl == SwapControl::EXT) + { + // Prefer the EXT extension, it gives per-drawable swap intervals, which will + // minimize the number of driver calls. + if (data->maxSwapInterval < 0) + { + unsigned int maxSwapInterval = 0; + mGLX.queryDrawable(drawable, GLX_MAX_SWAP_INTERVAL_EXT, &maxSwapInterval); + data->maxSwapInterval = static_cast<int>(maxSwapInterval); + } + + // When the egl configs were generated we had to guess what the max swap interval + // was because we didn't have a window to query it one (and that this max could + // depend on the monitor). This means that the target interval might be higher + // than the max interval and needs to be clamped. + const int realInterval = std::min(data->targetSwapInterval, data->maxSwapInterval); + if (data->currentSwapInterval != realInterval) + { + mGLX.swapIntervalEXT(drawable, realInterval); + data->currentSwapInterval = realInterval; + } + } + else if (mCurrentSwapInterval != data->targetSwapInterval) + { + // With the Mesa or SGI extensions we can still do per-drawable swap control + // manually but it is more expensive in number of driver calls. + if (mSwapControl == SwapControl::Mesa) + { + mGLX.swapIntervalMESA(data->targetSwapInterval); + } + else if (mSwapControl == SwapControl::SGI) + { + mGLX.swapIntervalSGI(data->targetSwapInterval); + } + mCurrentSwapInterval = data->targetSwapInterval; + } +} + +bool DisplayGLX::isValidWindowVisualId(unsigned long visualId) const +{ + return mRequestedVisual == -1 || static_cast<unsigned long>(mRequestedVisual) == visualId; +} + +const FunctionsGL *DisplayGLX::getFunctionsGL() const +{ + return mFunctionsGL; +} + +void DisplayGLX::generateExtensions(egl::DisplayExtensions *outExtensions) const +{ + outExtensions->createContextRobustness = mHasARBCreateContextRobustness; +} + +void DisplayGLX::generateCaps(egl::Caps *outCaps) const +{ + outCaps->textureNPOT = true; +} + +int DisplayGLX::getGLXFBConfigAttrib(glx::FBConfig config, int attrib) const +{ + int result; + mGLX.getFBConfigAttrib(config, attrib, &result); + return result; +} + +egl::Error DisplayGLX::createContextAttribs(glx::FBConfig, + const Optional<gl::Version> &version, + int profileMask, + glx::Context *context) const +{ + std::vector<int> attribs; + + if (mHasARBCreateContextRobustness) + { + attribs.push_back(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB); + attribs.push_back(GLX_LOSE_CONTEXT_ON_RESET_ARB); + } + + if (version.valid()) + { + attribs.push_back(GLX_CONTEXT_MAJOR_VERSION_ARB); + attribs.push_back(version.value().major); + + attribs.push_back(GLX_CONTEXT_MINOR_VERSION_ARB); + attribs.push_back(version.value().minor); + } + + if (profileMask != 0 && mHasARBCreateContextProfile) + { + attribs.push_back(GLX_CONTEXT_PROFILE_MASK_ARB); + attribs.push_back(profileMask); + } + + attribs.push_back(None); + + // When creating a context with glXCreateContextAttribsARB, a variety of X11 errors can + // be generated. To prevent these errors from crashing our process, we simply ignore + // them and only look if GLXContext was created. + // Process all events before setting the error handler to avoid desynchronizing XCB instances + // (the error handler is NOT per-display). + XSync(mXDisplay, False); + auto oldErrorHandler = XSetErrorHandler(IgnoreX11Errors); + *context = mGLX.createContextAttribsARB(mContextConfig, nullptr, True, attribs.data()); + XSetErrorHandler(oldErrorHandler); + + if (!*context) + { + return egl::Error(EGL_NOT_INITIALIZED, "Could not create GL context."); + } + return egl::Error(EGL_SUCCESS); +} + +egl::Error DisplayGLX::getNVIDIADriverVersion(std::string *version) const +{ + *version = ""; + + int eventBase = 0; + int errorBase = 0; + if (XNVCTRLQueryExtension(mXDisplay, &eventBase, &errorBase)) + { + int screenCount = ScreenCount(mXDisplay); + for (int screen = 0; screen < screenCount; ++screen) + { + char *buffer = nullptr; + if (XNVCTRLIsNvScreen(mXDisplay, screen) && + XNVCTRLQueryStringAttribute(mXDisplay, screen, 0, + NV_CTRL_STRING_NVIDIA_DRIVER_VERSION, &buffer)) + { + *version = buffer; + XFree(buffer); + } + } + } + + return egl::Error(EGL_SUCCESS); +} +} diff --git a/gfx/angle/src/libANGLE/renderer/gl/glx/DisplayGLX.h b/gfx/angle/src/libANGLE/renderer/gl/glx/DisplayGLX.h new file mode 100755 index 000000000..7e870c2f3 --- /dev/null +++ b/gfx/angle/src/libANGLE/renderer/gl/glx/DisplayGLX.h @@ -0,0 +1,151 @@ +// +// Copyright (c) 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. +// + +// DisplayGLX.h: GLX implementation of egl::Display + +#ifndef LIBANGLE_RENDERER_GL_GLX_DISPLAYGLX_H_ +#define LIBANGLE_RENDERER_GL_GLX_DISPLAYGLX_H_ + +#include <string> +#include <vector> + +#include "common/Optional.h" +#include "libANGLE/renderer/gl/DisplayGL.h" +#include "libANGLE/renderer/gl/glx/FunctionsGLX.h" + +namespace rx +{ + +class FunctionsGLX; + +// State-tracking data for the swap control to allow DisplayGLX to remember per +// drawable information for swap control. +struct SwapControlData +{ + SwapControlData(); + + // Set by the drawable + int targetSwapInterval; + + // DisplayGLX-side state-tracking + int maxSwapInterval; + int currentSwapInterval; +}; + +class DisplayGLX : public DisplayGL +{ + public: + DisplayGLX(); + ~DisplayGLX() override; + + egl::Error initialize(egl::Display *display) override; + void terminate() override; + + SurfaceImpl *createWindowSurface(const egl::SurfaceState &state, + const egl::Config *configuration, + EGLNativeWindowType window, + const egl::AttributeMap &attribs) override; + SurfaceImpl *createPbufferSurface(const egl::SurfaceState &state, + const egl::Config *configuration, + const egl::AttributeMap &attribs) override; + SurfaceImpl *createPbufferFromClientBuffer(const egl::SurfaceState &state, + const egl::Config *configuration, + EGLenum buftype, + EGLClientBuffer clientBuffer, + const egl::AttributeMap &attribs) override; + SurfaceImpl *createPixmapSurface(const egl::SurfaceState &state, + const egl::Config *configuration, + NativePixmapType nativePixmap, + const egl::AttributeMap &attribs) override; + + egl::ConfigSet generateConfigs() override; + + bool testDeviceLost() override; + egl::Error restoreLostDevice() override; + + bool isValidNativeWindow(EGLNativeWindowType window) const override; + + egl::Error getDevice(DeviceImpl **device) override; + + std::string getVendorString() const override; + + egl::Error waitClient() const override; + egl::Error waitNative(EGLint engine, + egl::Surface *drawSurface, + egl::Surface *readSurface) const override; + + egl::Error getDriverVersion(std::string *version) const override; + + // Synchronizes with the X server, if the display has been opened by ANGLE. + // Calling this is required at the end of every functions that does buffered + // X calls (not for glX calls) otherwise there might be race conditions + // between the application's display and ANGLE's one. + void syncXCommands() const; + + // Depending on the supported GLX extension, swap interval can be set + // globally or per drawable. This function will make sure the drawable's + // swap interval is the one required so that the subsequent swapBuffers + // acts as expected. + void setSwapInterval(glx::Drawable drawable, SwapControlData *data); + + bool isValidWindowVisualId(unsigned long visualId) const; + + private: + const FunctionsGL *getFunctionsGL() const override; + + egl::Error initializeContext(glx::FBConfig config, + const egl::AttributeMap &eglAttributes, + glx::Context *context); + + void generateExtensions(egl::DisplayExtensions *outExtensions) const override; + void generateCaps(egl::Caps *outCaps) const override; + + int getGLXFBConfigAttrib(glx::FBConfig config, int attrib) const; + egl::Error createContextAttribs(glx::FBConfig, + const Optional<gl::Version> &version, + int profileMask, + glx::Context *context) const; + + egl::Error getNVIDIADriverVersion(std::string *version) const; + + FunctionsGL *mFunctionsGL; + + std::map<int, glx::FBConfig> configIdToGLXConfig; + + EGLint mRequestedVisual; + glx::FBConfig mContextConfig; + glx::Context mContext; + // A pbuffer the context is current on during ANGLE initialization + glx::Pbuffer mDummyPbuffer; + + bool mUsesNewXDisplay; + bool mIsMesa; + bool mHasMultisample; + bool mHasARBCreateContext; + bool mHasARBCreateContextProfile; + bool mHasARBCreateContextRobustness; + bool mHasEXTCreateContextES2Profile; + + enum class SwapControl + { + Absent, + EXT, + Mesa, + SGI, + }; + SwapControl mSwapControl; + int mMinSwapInterval; + int mMaxSwapInterval; + int mCurrentSwapInterval; + + FunctionsGLX mGLX; + Display *mXDisplay; + egl::Display *mEGLDisplay; +}; + +} + +#endif // LIBANGLE_RENDERER_GL_GLX_DISPLAYGLX_H_ diff --git a/gfx/angle/src/libANGLE/renderer/gl/glx/FBConfigCompatibility.md b/gfx/angle/src/libANGLE/renderer/gl/glx/FBConfigCompatibility.md new file mode 100755 index 000000000..2343ad086 --- /dev/null +++ b/gfx/angle/src/libANGLE/renderer/gl/glx/FBConfigCompatibility.md @@ -0,0 +1,204 @@ +GLX Framebuffer Compatibility investigation +=========================================== + +In GLX and EGL, contexts are created with respect to a config that +describes the type of surfaces they will be used to render to. +Likewise surfaces are created with respect to a config and for +a context to be able to render to a surface, both their configs +must be compatible. Compatibility is losely described in both +the GLX and EGL specs but the following is clear: + * In GLX the config's color buffer must have the same type, including +RGBA vs. ColorIndex and the buffers must have the same depth, if they +exist. + * In EGL the config's color buffer must have the same type and the +buffers must have the same depth (not clear if it is only if they exist) + +Obviously the EGLconfig we will expose will have a one-to-one +correspondance with GLXFBConfigs. + +Our EGL implementation uses a single OpenGL context to back all +the EGLcontexts created by the application. Since our GL context +and GLXContext are the same object but in two APIs, we will make +the confusion and call the GLX context our backing context. + +The problem we have is that the the GLX context is created before +the application can choose what type of context it wants to use, +that means we have to expose EGLconfigs whose respective GLXFBConfigs +are compatible with the GLXFBConfig of our GLX context; we also need +to choose the GLXFBConfig of our GLX context so that it matches the +most common needs of application. + +Choice of the GLX context GLXFBConfig +------------------------------------- + +We decided that our GLX context's configuration must satisfy the following: + * Have a RGBA8 color buffer and D24S8 depth-stencil buffer which is what +the vast majority of applications use. + * It must render in direct colors, i.e. not in a color indexed format. + * It must be double-buffered (see later) + * It must support rendering to all the types of GLX surfaces so that we can +use it for all types of EGL surfaces + * It must have an associated visual ID so that we can use it with X, it seems +like this would be strongly tied to it having the ```WINDOW_BIT``` set. + * We would like a conformant context. + +Study of compatible GLXFBConfigs +-------------------------------- + +When using the condition of compatibility defined in the GLX spec and filtering +out the non-conformant GLXFBConfig we got the following list (see function +```print_visual_attribs_short``` in [glxinfo's source code](http://cgit.freedesktop.org/mesa/demos/tree/src/xdemos/glxinfo.c) +to understand how to read the table): + +``` + visual x bf lv rg d st colorbuffer sr ax dp st accumbuffer ms cav + id dep cl sp sz l ci b ro r g b a F gb bf th cl r g b a ns b eat Result +---------------------------------------------------------------------------- +0x02e 24 tc 0 32 0 r . . 8 8 8 8 . s 4 0 0 16 16 16 16 0 0 None Fail +0x0e4 32 tc 0 32 0 r . . 8 8 8 8 . s 4 0 0 16 16 16 16 0 0 None BadMatch +0x02c 24 tc 0 32 0 r y . 8 8 8 8 . s 4 0 0 16 16 16 16 0 0 None Pass +0x0e2 32 tc 0 32 0 r y . 8 8 8 8 . s 4 0 0 16 16 16 16 0 0 None BadMatch +0x089 24 dc 0 32 0 r . . 8 8 8 8 . s 4 0 0 16 16 16 16 0 0 None Fail +0x087 24 dc 0 32 0 r y . 8 8 8 8 . s 4 0 0 16 16 16 16 0 0 None Pass +0x026 24 tc 0 32 0 r . . 8 8 8 8 . s 4 24 8 16 16 16 16 0 0 None Fail +0x0dc 32 tc 0 32 0 r . . 8 8 8 8 . s 4 24 8 16 16 16 16 0 0 None BadMatch +0x024 24 tc 0 32 0 r y . 8 8 8 8 . s 4 24 8 16 16 16 16 0 0 None Pass +0x0da 32 tc 0 32 0 r y . 8 8 8 8 . s 4 24 8 16 16 16 16 0 0 None BadMatch +0x081 24 dc 0 32 0 r . . 8 8 8 8 . s 4 24 8 16 16 16 16 0 0 None Fail +0x07f 24 dc 0 32 0 r y . 8 8 8 8 . s 4 24 8 16 16 16 16 0 0 None Pass +``` + +The last column shows the result of trying to render on a window using the config, +with a GLX context using config 0x024. The first thing we see is that BadMatch is +thrown by the X server when creating the subwindow for rendering. This was because +we didn't set the border pixel of the subwindow *shake fist at X11* (see this [StackOverflow question](http://stackoverflow.com/questions/3645632/how-to-create-a-window-with-a-bit-depth-of-32)). +The result updated with this fix give: + +``` + visual x bf lv rg d st colorbuffer sr ax dp st accumbuffer ms cav + id dep cl sp sz l ci b ro r g b a F gb bf th cl r g b a ns b eat +---------------------------------------------------------------------------- +0x02e 24 tc 0 32 0 r . . 8 8 8 8 . s 4 0 0 16 16 16 16 0 0 None Fail +0x0e4 32 tc 0 32 0 r . . 8 8 8 8 . s 4 0 0 16 16 16 16 0 0 None Fail +0x02c 24 tc 0 32 0 r y . 8 8 8 8 . s 4 0 0 16 16 16 16 0 0 None Pass +0x0e2 32 tc 0 32 0 r y . 8 8 8 8 . s 4 0 0 16 16 16 16 0 0 None Pass +0x089 24 dc 0 32 0 r . . 8 8 8 8 . s 4 0 0 16 16 16 16 0 0 None Fail +0x087 24 dc 0 32 0 r y . 8 8 8 8 . s 4 0 0 16 16 16 16 0 0 None Pass +0x026 24 tc 0 32 0 r . . 8 8 8 8 . s 4 24 8 16 16 16 16 0 0 None Fail +0x0dc 32 tc 0 32 0 r . . 8 8 8 8 . s 4 24 8 16 16 16 16 0 0 None Fail +0x024 24 tc 0 32 0 r y . 8 8 8 8 . s 4 24 8 16 16 16 16 0 0 None Pass +0x0da 32 tc 0 32 0 r y . 8 8 8 8 . s 4 24 8 16 16 16 16 0 0 None Pass +0x081 24 dc 0 32 0 r . . 8 8 8 8 . s 4 24 8 16 16 16 16 0 0 None Fail +0x07f 24 dc 0 32 0 r y . 8 8 8 8 . s 4 24 8 16 16 16 16 0 0 None Pass +``` + +From this we see that our rendering test passed if and only if the config was double +buffered like 0x024 which is our GLX context config. The compatible configs are then: + +``` + visual x bf lv rg d st colorbuffer sr ax dp st accumbuffer ms cav + id dep cl sp sz l ci b ro r g b a F gb bf th cl r g b a ns b eat +---------------------------------------------------------------------------- +0x02c 24 tc 0 32 0 r y . 8 8 8 8 . s 4 0 0 16 16 16 16 0 0 None +0x0e2 32 tc 0 32 0 r y . 8 8 8 8 . s 4 0 0 16 16 16 16 0 0 None +0x087 24 dc 0 32 0 r y . 8 8 8 8 . s 4 0 0 16 16 16 16 0 0 None +0x024 24 tc 0 32 0 r y . 8 8 8 8 . s 4 24 8 16 16 16 16 0 0 None +0x0da 32 tc 0 32 0 r y . 8 8 8 8 . s 4 24 8 16 16 16 16 0 0 None +0x07f 24 dc 0 32 0 r y . 8 8 8 8 . s 4 24 8 16 16 16 16 0 0 None +``` + +We can see two dimensions, with our without a depth-stencil buffer and with TrueColor +or DirectColor. The depth-stencil will be useful to expose to application. + +More on double buffering +------------------------ +The tests above show that double-buffered contexts are not compatible with single- +buffered surfaces; however other tests show that single-buffered contexts are +compatible with both single and double-buffered surfaces. The problem is that in +that case, we can see some flickering even with double-buffered surfaces. If we +can find a trick to avoid that flicker, then we would be able to expose single +and double-buffered surfaces at the EGL level. Not exposing them isn't too much +of a problem though as the vast majority of application want double-buffering. + +AMD and extra buffers +--------------------- +As can be seen above, NVIDIA does not expose conformant context with multisampled +buffers or non RGBA16 accumulation buffers. The behavior is different on AMD that +exposes them as conformant, which gives the following list after filtering as +explained above: + +``` + visual x bf lv rg d st colorbuffer sr ax dp st accumbuffer ms cav + id dep cl sp sz l ci b ro r g b a F gb bf th cl r g b a ns b eat +---------------------------------------------------------------------------- +0x023 24 tc 0 32 0 r y . 8 8 8 8 . . 0 24 8 16 16 16 16 0 0 None +0x027 24 tc 0 32 0 r y . 8 8 8 8 . . 0 24 8 0 0 0 0 0 0 None +0x02b 24 tc 0 32 0 r y . 8 8 8 8 . . 0 24 8 0 0 0 0 2 1 None +0x02f 24 tc 0 32 0 r y . 8 8 8 8 . . 0 24 8 0 0 0 0 4 1 None +0x03b 24 dc 0 32 0 r y . 8 8 8 8 . . 0 24 8 16 16 16 16 0 0 None +0x03f 24 dc 0 32 0 r y . 8 8 8 8 . . 0 24 8 0 0 0 0 0 0 None +0x043 24 dc 0 32 0 r y . 8 8 8 8 . . 0 24 8 0 0 0 0 2 1 None +0x047 24 dc 0 32 0 r y . 8 8 8 8 . . 0 24 8 0 0 0 0 4 1 None +``` + +ANGLE's context is created using 0x027 and experimentation shows it is only compatible +with 0x03f which is the only other config lacking both an accumulation buffer and a +multisample buffer. The GLX spec seems to hint it should still work ("should have the +same size, if they exist") but it doesn't work in this case. Filtering the configs to +have the same multisample and accumulation buffers gives the following: + +``` + visual x bf lv rg d st colorbuffer sr ax dp st accumbuffer ms cav + id dep cl sp sz l ci b ro r g b a F gb bf th cl r g b a ns b eat +---------------------------------------------------------------------------- +0x027 24 tc 0 32 0 r y . 8 8 8 8 . . 0 24 8 0 0 0 0 0 0 None +0x03f 24 dc 0 32 0 r y . 8 8 8 8 . . 0 24 8 0 0 0 0 0 0 None +``` + +Mesa Intel driver +----------------- +In GLX, a criterium for context and surface compatibility is that buffers +should have the same depth, if they exist at all in the surface. This means +that it should be possible to make a context with a D24S8 depth-stencil +buffer to a surface without a depth-stencil buffer. This doesn't work on the +Mesa Intel driver. The list before the workaround was the following, with +0x020 being the fbconfig chosen for the context: + +``` + visual x bf lv rg d st colorbuffer sr ax dp st accumbuffer ms cav + id dep cl sp sz l ci b ro r g b a F gb bf th cl r g b a ns b eat +---------------------------------------------------------------------------- +0x020 24 tc 0 32 0 r y . 8 8 8 8 . . 0 24 8 0 0 0 0 0 0 None +0x021 24 dc 0 32 0 r y . 8 8 8 8 . . 0 24 8 0 0 0 0 0 0 None +0x08f 32 tc 0 32 0 r y . 8 8 8 8 . . 0 24 8 0 0 0 0 0 0 None +0x0d0 24 tc 0 32 0 r y . 8 8 8 8 . . 0 0 0 0 0 0 0 0 0 None +0x0e2 24 dc 0 32 0 r y . 8 8 8 8 . . 0 0 0 0 0 0 0 0 0 None +0x0e9 24 dc 0 32 0 r y . 8 8 8 8 . . 0 24 8 0 0 0 0 0 0 None +``` + +After the workaround that list becomes the following: + +``` + visual x bf lv rg d st colorbuffer sr ax dp st accumbuffer ms cav + id dep cl sp sz l ci b ro r g b a F gb bf th cl r g b a ns b eat +---------------------------------------------------------------------------- +0x020 24 tc 0 32 0 r y . 8 8 8 8 . . 0 24 8 0 0 0 0 0 0 None +0x021 24 dc 0 32 0 r y . 8 8 8 8 . . 0 24 8 0 0 0 0 0 0 None +0x08f 32 tc 0 32 0 r y . 8 8 8 8 . . 0 24 8 0 0 0 0 0 0 None +0x0e9 24 dc 0 32 0 r y . 8 8 8 8 . . 0 24 8 0 0 0 0 0 0 None +``` + +Future investigation +-------------------- +All the non-conformant configs have a multisampled buffer, so it could be interesting +to see if we can use them to expose another EGL extension. + +Finally this document is written with respect to a small number of drivers, before +using the GLX EGL implementation in the wild it would be good to test it on other +drivers and hardware. + +The drivers tested were: + + - the proprietary NVIDIA driver + - the proprietary AMD driver + - the open source Intel (Broadwell) Mesa driver diff --git a/gfx/angle/src/libANGLE/renderer/gl/glx/FunctionsGLX.cpp b/gfx/angle/src/libANGLE/renderer/gl/glx/FunctionsGLX.cpp new file mode 100755 index 000000000..4ec38dd81 --- /dev/null +++ b/gfx/angle/src/libANGLE/renderer/gl/glx/FunctionsGLX.cpp @@ -0,0 +1,398 @@ +// +// Copyright (c) 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) + { + } + + // 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; +}; + +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) \ + if (!GetProc(getProc, MEMBER, #NAME)) \ + { \ + *errorString = "Could not load GLX entry point " #NAME; \ + return false; \ + } +#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); + } + +#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); +} + +} diff --git a/gfx/angle/src/libANGLE/renderer/gl/glx/FunctionsGLX.h b/gfx/angle/src/libANGLE/renderer/gl/glx/FunctionsGLX.h new file mode 100755 index 000000000..98c2fef46 --- /dev/null +++ b/gfx/angle/src/libANGLE/renderer/gl/glx/FunctionsGLX.h @@ -0,0 +1,96 @@ +// +// Copyright (c) 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.h: Defines the FunctionsGLX class to load functions and data from GLX + +#ifndef LIBANGLE_RENDERER_GL_GLX_FUNCTIONSGLX_H_ +#define LIBANGLE_RENDERER_GL_GLX_FUNCTIONSGLX_H_ + +#include <string> +#include <vector> + +#include "libANGLE/renderer/gl/glx/platform_glx.h" + +namespace rx +{ + +class FunctionsGLX +{ + public: + FunctionsGLX(); + ~FunctionsGLX(); + + // Load data from GLX, can be called multiple times + bool initialize(Display *xDisplay, int screen, std::string *errorString); + void terminate(); + + bool hasExtension(const char *extension) const; + int majorVersion; + int minorVersion; + + Display *getDisplay() const; + int getScreen() const; + + PFNGETPROCPROC getProc; + + // GLX 1.0 + glx::Context createContext(XVisualInfo *visual, glx::Context share, bool direct) const; + void destroyContext(glx::Context context) const; + Bool makeCurrent(glx::Drawable drawable, glx::Context context) const; + void swapBuffers(glx::Drawable drawable) const; + Bool queryExtension(int *errorBase, int *event) const; + Bool queryVersion(int *major, int *minor) const; + glx::Context getCurrentContext() const; + glx::Drawable getCurrentDrawable() const; + void waitX() const; + void waitGL() const; + + // GLX 1.1 + const char *getClientString(int name) const; + const char *queryExtensionsString() const; + + // GLX 1.3 + glx::FBConfig *getFBConfigs(int *nElements) const; + glx::FBConfig *chooseFBConfig(const int *attribList, int *nElements) const; + int getFBConfigAttrib(glx::FBConfig config, int attribute, int *value) const; + XVisualInfo *getVisualFromFBConfig(glx::FBConfig config) const; + glx::Window createWindow(glx::FBConfig config, Window window, const int *attribList) const; + void destroyWindow(glx::Window window) const; + glx::Pbuffer createPbuffer(glx::FBConfig config, const int *attribList) const; + void destroyPbuffer(glx::Pbuffer pbuffer) const; + void queryDrawable(glx::Drawable drawable, int attribute, unsigned int *value) const; + + // GLX_ARB_create_context + glx::Context createContextAttribsARB(glx::FBConfig config, glx::Context shareContext, Bool direct, const int *attribList) const; + + // GLX_EXT_swap_control + void swapIntervalEXT(glx::Drawable drawable, int interval) const; + + // GLX_MESA_swap_control + int swapIntervalMESA(int interval) const; + + // GLX_SGI_swap_control + int swapIntervalSGI(int interval) const; + + private: + // So as to isolate GLX from angle we do not include angleutils.h and cannot + // use angle::NonCopyable so we replicated it here instead. + FunctionsGLX(const FunctionsGLX&) = delete; + void operator=(const FunctionsGLX&) = delete; + + struct GLXFunctionTable; + + static void *sLibHandle; + Display *mXDisplay; + int mXScreen; + + GLXFunctionTable *mFnPtrs; + std::vector<std::string> mExtensions; +}; + +} + +#endif // LIBANGLE_RENDERER_GL_GLX_FUNCTIONSGLX_H_ diff --git a/gfx/angle/src/libANGLE/renderer/gl/glx/PbufferSurfaceGLX.cpp b/gfx/angle/src/libANGLE/renderer/gl/glx/PbufferSurfaceGLX.cpp new file mode 100755 index 000000000..a97021b40 --- /dev/null +++ b/gfx/angle/src/libANGLE/renderer/gl/glx/PbufferSurfaceGLX.cpp @@ -0,0 +1,143 @@ +// +// Copyright (c) 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. +// + +// PbufferSurfaceGLX.cpp: GLX implementation of egl::Surface for PBuffers + +#include "libANGLE/renderer/gl/glx/PbufferSurfaceGLX.h" + +#include "common/debug.h" +#include "libANGLE/renderer/gl/glx/DisplayGLX.h" +#include "libANGLE/renderer/gl/glx/FunctionsGLX.h" + +namespace rx +{ + +PbufferSurfaceGLX::PbufferSurfaceGLX(const egl::SurfaceState &state, + RendererGL *renderer, + EGLint width, + EGLint height, + bool largest, + const FunctionsGLX &glx, + glx::Context context, + glx::FBConfig fbConfig) + : SurfaceGLX(state, renderer), + mWidth(width), + mHeight(height), + mLargest(largest), + mGLX(glx), + mContext(context), + mFBConfig(fbConfig), + mPbuffer(0) +{ +} + +PbufferSurfaceGLX::~PbufferSurfaceGLX() +{ + if (mPbuffer) + { + mGLX.destroyPbuffer(mPbuffer); + } +} + +egl::Error PbufferSurfaceGLX::initialize() +{ + // Avoid creating 0-sized PBuffers as it fails on the Intel Mesa driver + // as commented on https://bugs.freedesktop.org/show_bug.cgi?id=38869 so we + // use (w, 1) or (1, h) instead. + int width = std::max(1, static_cast<int>(mWidth)); + int height = std::max(1, static_cast<int>(mHeight)); + + const int attribs[] = + { + GLX_PBUFFER_WIDTH, width, + GLX_PBUFFER_HEIGHT, height, + GLX_LARGEST_PBUFFER, mLargest, + None + }; + + mPbuffer = mGLX.createPbuffer(mFBConfig, attribs); + if (!mPbuffer) + { + return egl::Error(EGL_BAD_ALLOC, "Failed to create a native GLX pbuffer."); + } + + if (mLargest) + { + mGLX.queryDrawable(mPbuffer, GLX_WIDTH, &mWidth); + mGLX.queryDrawable(mPbuffer, GLX_HEIGHT, &mHeight); + } + + return egl::Error(EGL_SUCCESS); +} + +egl::Error PbufferSurfaceGLX::makeCurrent() +{ + if (mGLX.makeCurrent(mPbuffer, mContext) != True) + { + return egl::Error(EGL_BAD_DISPLAY); + } + return egl::Error(EGL_SUCCESS); +} + +egl::Error PbufferSurfaceGLX::swap() +{ + return egl::Error(EGL_SUCCESS); +} + +egl::Error PbufferSurfaceGLX::postSubBuffer(EGLint x, EGLint y, EGLint width, EGLint height) +{ + return egl::Error(EGL_SUCCESS); +} + +egl::Error PbufferSurfaceGLX::querySurfacePointerANGLE(EGLint attribute, void **value) +{ + UNIMPLEMENTED(); + return egl::Error(EGL_SUCCESS); +} + +egl::Error PbufferSurfaceGLX::bindTexImage(gl::Texture *texture, EGLint buffer) +{ + UNIMPLEMENTED(); + return egl::Error(EGL_SUCCESS); +} + +egl::Error PbufferSurfaceGLX::releaseTexImage(EGLint buffer) +{ + UNIMPLEMENTED(); + return egl::Error(EGL_SUCCESS); +} + +void PbufferSurfaceGLX::setSwapInterval(EGLint interval) +{ +} + +EGLint PbufferSurfaceGLX::getWidth() const +{ + return mWidth; +} + +EGLint PbufferSurfaceGLX::getHeight() const +{ + return mHeight; +} + +EGLint PbufferSurfaceGLX::isPostSubBufferSupported() const +{ + UNIMPLEMENTED(); + return EGL_FALSE; +} + +EGLint PbufferSurfaceGLX::getSwapBehavior() const +{ + return EGL_BUFFER_PRESERVED; +} + +egl::Error PbufferSurfaceGLX::checkForResize() +{ + // The size of pbuffers never change + return egl::Error(EGL_SUCCESS); +} +} diff --git a/gfx/angle/src/libANGLE/renderer/gl/glx/PbufferSurfaceGLX.h b/gfx/angle/src/libANGLE/renderer/gl/glx/PbufferSurfaceGLX.h new file mode 100755 index 000000000..d346634b2 --- /dev/null +++ b/gfx/angle/src/libANGLE/renderer/gl/glx/PbufferSurfaceGLX.h @@ -0,0 +1,64 @@ +// +// Copyright (c) 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. +// + +// PBufferSurfaceGLX.h: GLX implementation of egl::Surface for PBuffers + +#ifndef LIBANGLE_RENDERER_GL_GLX_PBUFFERSURFACEGLX_H_ +#define LIBANGLE_RENDERER_GL_GLX_PBUFFERSURFACEGLX_H_ + +#include "libANGLE/renderer/gl/glx/platform_glx.h" +#include "libANGLE/renderer/gl/glx/SurfaceGLX.h" + +namespace rx +{ + +class FunctionsGLX; + +class PbufferSurfaceGLX : public SurfaceGLX +{ + public: + PbufferSurfaceGLX(const egl::SurfaceState &state, + RendererGL *renderer, + EGLint width, + EGLint height, + bool largest, + const FunctionsGLX &glx, + glx::Context context, + glx::FBConfig fbConfig); + ~PbufferSurfaceGLX() override; + + egl::Error initialize() override; + egl::Error makeCurrent() override; + + egl::Error swap() override; + egl::Error postSubBuffer(EGLint x, EGLint y, EGLint width, EGLint height) override; + egl::Error querySurfacePointerANGLE(EGLint attribute, void **value) override; + egl::Error bindTexImage(gl::Texture *texture, EGLint buffer) override; + egl::Error releaseTexImage(EGLint buffer) override; + void setSwapInterval(EGLint interval) override; + + EGLint getWidth() const override; + EGLint getHeight() const override; + + EGLint isPostSubBufferSupported() const override; + EGLint getSwapBehavior() const override; + + egl::Error checkForResize() override; + + private: + unsigned mWidth; + unsigned mHeight; + bool mLargest; + + const FunctionsGLX &mGLX; + glx::Context mContext; + glx::FBConfig mFBConfig; + glx::Pbuffer mPbuffer; +}; + +} + +#endif // LIBANGLE_RENDERER_GL_GLX_PBUFFERSURFACEGLX_H_ diff --git a/gfx/angle/src/libANGLE/renderer/gl/glx/SurfaceGLX.h b/gfx/angle/src/libANGLE/renderer/gl/glx/SurfaceGLX.h new file mode 100755 index 000000000..813516e80 --- /dev/null +++ b/gfx/angle/src/libANGLE/renderer/gl/glx/SurfaceGLX.h @@ -0,0 +1,26 @@ +// +// Copyright (c) 2016 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. +// + +// SurfaceGLX.h: common interface for GLX surfaces + +#ifndef LIBANGLE_RENDERER_GL_GLX_SURFACEGLX_H_ +#define LIBANGLE_RENDERER_GL_GLX_SURFACEGLX_H_ + +#include "libANGLE/renderer/gl/SurfaceGL.h" + +namespace rx +{ + +class SurfaceGLX : public SurfaceGL +{ + public: + SurfaceGLX(const egl::SurfaceState &state, RendererGL *renderer) : SurfaceGL(state, renderer) {} + + virtual egl::Error checkForResize() = 0; +}; +} + +#endif // LIBANGLE_RENDERER_GL_GLX_SURFACEGLX_H_ diff --git a/gfx/angle/src/libANGLE/renderer/gl/glx/WindowSurfaceGLX.cpp b/gfx/angle/src/libANGLE/renderer/gl/glx/WindowSurfaceGLX.cpp new file mode 100755 index 000000000..21b1b316f --- /dev/null +++ b/gfx/angle/src/libANGLE/renderer/gl/glx/WindowSurfaceGLX.cpp @@ -0,0 +1,244 @@ +// +// Copyright (c) 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. +// + +// WindowSurfaceGLX.cpp: GLX implementation of egl::Surface for windows + +#include "libANGLE/renderer/gl/glx/WindowSurfaceGLX.h" + +#include "common/debug.h" + +#include "libANGLE/renderer/gl/glx/DisplayGLX.h" +#include "libANGLE/renderer/gl/glx/FunctionsGLX.h" + +namespace rx +{ + +static int IgnoreX11Errors(Display *, XErrorEvent *) +{ + return 0; +} + +WindowSurfaceGLX::WindowSurfaceGLX(const egl::SurfaceState &state, + const FunctionsGLX &glx, + DisplayGLX *glxDisplay, + RendererGL *renderer, + Window window, + Display *display, + glx::Context context, + glx::FBConfig fbConfig) + : SurfaceGLX(state, renderer), + mParent(window), + mWindow(0), + mDisplay(display), + mGLX(glx), + mGLXDisplay(glxDisplay), + mContext(context), + mFBConfig(fbConfig), + mGLXWindow(0) +{ +} + +WindowSurfaceGLX::~WindowSurfaceGLX() +{ + if (mGLXWindow) + { + mGLX.destroyWindow(mGLXWindow); + } + + if (mWindow) + { + // When destroying the window, it may happen that the window has already been + // destroyed by the application (this happens in Chromium). There is no way to + // atomically check that a window exists and to destroy it so instead we call + // XDestroyWindow, ignoring any errors. + auto oldErrorHandler = XSetErrorHandler(IgnoreX11Errors); + XDestroyWindow(mDisplay, mWindow); + XSync(mDisplay, False); + XSetErrorHandler(oldErrorHandler); + } + + mGLXDisplay->syncXCommands(); +} + +egl::Error WindowSurfaceGLX::initialize() +{ + // Check that the window's visual ID is valid, as part of the AMGLE_x11_visual + // extension. + { + XWindowAttributes windowAttributes; + XGetWindowAttributes(mDisplay, mParent, &windowAttributes); + unsigned long visualId = windowAttributes.visual->visualid; + + if (!mGLXDisplay->isValidWindowVisualId(visualId)) + { + return egl::Error(EGL_BAD_MATCH, + "The visual of native_window doesn't match the visual given with " + "ANGLE_X11_VISUAL_ID"); + } + } + + // The visual of the X window, GLX window and GLX context must match, + // however we received a user-created window that can have any visual + // and wouldn't work with our GLX context. To work in all cases, we + // create a child window with the right visual that covers all of its + // parent. + XVisualInfo *visualInfo = mGLX.getVisualFromFBConfig(mFBConfig); + if (!visualInfo) + { + return egl::Error(EGL_BAD_NATIVE_WINDOW, "Failed to get the XVisualInfo for the child window."); + } + Visual* visual = visualInfo->visual; + + if (!getWindowDimensions(mParent, &mParentWidth, &mParentHeight)) + { + return egl::Error(EGL_BAD_NATIVE_WINDOW, "Failed to get the parent window's dimensions."); + } + + // The depth, colormap and visual must match otherwise we get a X error + // so we specify the colormap attribute. Also we do not want the window + // to be taken into account for input so we specify the event and + // do-not-propagate masks to 0 (the defaults). Finally we specify the + // border pixel attribute so that we can use a different visual depth + // than our parent (seems like X uses that as a condition to render + // the subwindow in a different buffer) + XSetWindowAttributes attributes; + unsigned long attributeMask = CWColormap | CWBorderPixel; + + Colormap colormap = XCreateColormap(mDisplay, mParent, visual, AllocNone); + if(!colormap) + { + XFree(visualInfo); + return egl::Error(EGL_BAD_NATIVE_WINDOW, "Failed to create the Colormap for the child window."); + } + attributes.colormap = colormap; + attributes.border_pixel = 0; + + //TODO(cwallez) set up our own error handler to see if the call failed + mWindow = XCreateWindow(mDisplay, mParent, 0, 0, mParentWidth, mParentHeight, + 0, visualInfo->depth, InputOutput, visual, attributeMask, &attributes); + mGLXWindow = mGLX.createWindow(mFBConfig, mWindow, nullptr); + + XMapWindow(mDisplay, mWindow); + XFlush(mDisplay); + + XFree(visualInfo); + XFreeColormap(mDisplay, colormap); + + mGLXDisplay->syncXCommands(); + + return egl::Error(EGL_SUCCESS); +} + +egl::Error WindowSurfaceGLX::makeCurrent() +{ + if (mGLX.makeCurrent(mGLXWindow, mContext) != True) + { + return egl::Error(EGL_BAD_DISPLAY); + } + return egl::Error(EGL_SUCCESS); +} + +egl::Error WindowSurfaceGLX::swap() +{ + // We need to swap before resizing as some drivers clobber the back buffer + // when the window is resized. + mGLXDisplay->setSwapInterval(mGLXWindow, &mSwapControl); + mGLX.swapBuffers(mGLXWindow); + + egl::Error error = checkForResize(); + if (error.isError()) + { + return error; + } + + return egl::Error(EGL_SUCCESS); +} + +egl::Error WindowSurfaceGLX::postSubBuffer(EGLint x, EGLint y, EGLint width, EGLint height) +{ + UNIMPLEMENTED(); + return egl::Error(EGL_SUCCESS); +} + +egl::Error WindowSurfaceGLX::querySurfacePointerANGLE(EGLint attribute, void **value) +{ + UNIMPLEMENTED(); + return egl::Error(EGL_SUCCESS); +} + +egl::Error WindowSurfaceGLX::bindTexImage(gl::Texture *texture, EGLint buffer) +{ + UNIMPLEMENTED(); + return egl::Error(EGL_SUCCESS); +} + +egl::Error WindowSurfaceGLX::releaseTexImage(EGLint buffer) +{ + UNIMPLEMENTED(); + return egl::Error(EGL_SUCCESS); +} + +void WindowSurfaceGLX::setSwapInterval(EGLint interval) +{ + mSwapControl.targetSwapInterval = interval; +} + +EGLint WindowSurfaceGLX::getWidth() const +{ + // The size of the window is always the same as the cached size of its parent. + return mParentWidth; +} + +EGLint WindowSurfaceGLX::getHeight() const +{ + // The size of the window is always the same as the cached size of its parent. + return mParentHeight; +} + +EGLint WindowSurfaceGLX::isPostSubBufferSupported() const +{ + UNIMPLEMENTED(); + return EGL_FALSE; +} + +EGLint WindowSurfaceGLX::getSwapBehavior() const +{ + return EGL_BUFFER_PRESERVED; +} + +egl::Error WindowSurfaceGLX::checkForResize() +{ + // TODO(cwallez) set up our own error handler to see if the call failed + unsigned int newParentWidth, newParentHeight; + if (!getWindowDimensions(mParent, &newParentWidth, &newParentHeight)) + { + return egl::Error(EGL_BAD_CURRENT_SURFACE, + "Failed to retrieve the size of the parent window."); + } + + if (mParentWidth != newParentWidth || mParentHeight != newParentHeight) + { + mParentWidth = newParentWidth; + mParentHeight = newParentHeight; + + mGLX.waitGL(); + XResizeWindow(mDisplay, mWindow, mParentWidth, mParentHeight); + mGLX.waitX(); + XSync(mDisplay, False); + } + + return egl::Error(EGL_SUCCESS); +} + +bool WindowSurfaceGLX::getWindowDimensions(Window window, unsigned int *width, unsigned int *height) const +{ + Window root; + int x, y; + unsigned int border, depth; + return XGetGeometry(mDisplay, window, &root, &x, &y, width, height, &border, &depth) != 0; +} + +} diff --git a/gfx/angle/src/libANGLE/renderer/gl/glx/WindowSurfaceGLX.h b/gfx/angle/src/libANGLE/renderer/gl/glx/WindowSurfaceGLX.h new file mode 100755 index 000000000..0cdda96e6 --- /dev/null +++ b/gfx/angle/src/libANGLE/renderer/gl/glx/WindowSurfaceGLX.h @@ -0,0 +1,73 @@ +// +// Copyright (c) 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. +// + +// WindowSurfaceGLX.h: GLX implementation of egl::Surface for windows + +#ifndef LIBANGLE_RENDERER_GL_GLX_WINDOWSURFACEGLX_H_ +#define LIBANGLE_RENDERER_GL_GLX_WINDOWSURFACEGLX_H_ + +#include "libANGLE/renderer/gl/glx/DisplayGLX.h" +#include "libANGLE/renderer/gl/glx/platform_glx.h" +#include "libANGLE/renderer/gl/glx/SurfaceGLX.h" + +namespace rx +{ + +class DisplayGLX; +class FunctionsGLX; + +class WindowSurfaceGLX : public SurfaceGLX +{ + public: + WindowSurfaceGLX(const egl::SurfaceState &state, + const FunctionsGLX &glx, + DisplayGLX *glxDisplay, + RendererGL *renderer, + Window window, + Display *display, + glx::Context context, + glx::FBConfig fbConfig); + ~WindowSurfaceGLX() override; + + egl::Error initialize() override; + egl::Error makeCurrent() override; + + egl::Error swap() override; + egl::Error postSubBuffer(EGLint x, EGLint y, EGLint width, EGLint height) override; + egl::Error querySurfacePointerANGLE(EGLint attribute, void **value) override; + egl::Error bindTexImage(gl::Texture *texture, EGLint buffer) override; + egl::Error releaseTexImage(EGLint buffer) override; + void setSwapInterval(EGLint interval) override; + + EGLint getWidth() const override; + EGLint getHeight() const override; + + EGLint isPostSubBufferSupported() const override; + EGLint getSwapBehavior() const override; + + egl::Error checkForResize() override; + + private: + bool getWindowDimensions(Window window, unsigned int *width, unsigned int *height) const; + + Window mParent; + unsigned int mParentWidth, mParentHeight; + Window mWindow; + Display *mDisplay; + + const FunctionsGLX &mGLX; + DisplayGLX *mGLXDisplay; + + glx::Context mContext; + glx::FBConfig mFBConfig; + glx::Window mGLXWindow; + + SwapControlData mSwapControl; +}; + +} + +#endif // LIBANGLE_RENDERER_GL_GLX_WINDOWSURFACEGLX_H_ diff --git a/gfx/angle/src/libANGLE/renderer/gl/glx/functionsglx_typedefs.h b/gfx/angle/src/libANGLE/renderer/gl/glx/functionsglx_typedefs.h new file mode 100755 index 000000000..b0ba033c7 --- /dev/null +++ b/gfx/angle/src/libANGLE/renderer/gl/glx/functionsglx_typedefs.h @@ -0,0 +1,52 @@ +// +// Copyright (c) 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_typedefs.h: Typedefs of GLX functions. + +#ifndef LIBANGLE_RENDERER_GL_GLX_FUNCTIONSGLXTYPEDEFS_H_ +#define LIBANGLE_RENDERER_GL_GLX_FUNCTIONSGLXTYPEDEFS_H_ + +#include "libANGLE/renderer/gl/glx/platform_glx.h" + +namespace rx +{ + +// Only the functions of GLX 1.2 and earlier need to be typdefed; the other +// functions are already typedefed in glx.h + +// GLX 1.0 +typedef XVisualInfo *(*PFNGLXCHOOSEVISUALPROC) (Display *dpy, int screen, int *attribList); +typedef GLXContext (*PFNGLXCREATECONTEXTPROC) (Display *dpy, XVisualInfo *vis, GLXContext shareList, Bool direct); +typedef void (*PFNGLXDESTROYCONTEXTPROC) (Display *dpy, GLXContext ctx); +typedef Bool (*PFNGLXMAKECURRENTPROC) (Display *dpy, GLXDrawable drawable, GLXContext ctx); +typedef void (*PFNGLXCOPYCONTEXTPROC) (Display *dpy, GLXContext src, GLXContext dst, unsigned long mask); +typedef void (*PFNGLXSWAPBUFFERSPROC) (Display *dpy, GLXDrawable drawable); +typedef GLXPixmap (*PFNGLXCREATEGLXPIXMAPPROC) (Display *dpy, XVisualInfo *visual, Pixmap pixmap); +typedef void (*PFNGLXDESTROYGLXPIXMAPPROC) (Display *dpy, GLXPixmap pixmap); +typedef Bool (*PFNGLXQUERYEXTENSIONPROC) (Display *dpy, int *errorb, int *event); +typedef Bool (*PFNGLXQUERYVERSIONPROC) (Display *dpy, int *maj, int *min); +typedef Bool (*PFNGLXISDIRECTPROC) (Display *dpy, GLXContext ctx); +typedef int (*PFNGLXGETCONFIGPROC) (Display *dpy, XVisualInfo *visual, int attrib, int *value); +typedef GLXContext (*PFNGLXGETCURRENTCONTEXTPROC) (); +typedef GLXDrawable (*PFNGLXGETCURRENTDRAWABLEPROC) (); +typedef GLXContext (*PFNGLXGETCURRENTCONTEXTPROC) (); +typedef GLXDrawable (*PFNGLXGETCURRENTDRAWABLEPROC) (); +typedef void (*PFNGLXWAITGLPROC) (); +typedef void (*PFNGLXWAITXPROC) (); +typedef void (*PFNGLXUSEXFONT) (Font font, int first, int count, int list); + +// GLX 1.1 +typedef const char *(*PFNGLXQUERYEXTENSIONSSTRINGPROC) (Display *dpy, int screen); +typedef const char *(*PFNGLXQUERYSERVERSTRINGPROC) (Display *dpy, int screen, int name); +typedef const char *(*PFNGLXGETCLIENTSTRINGPROC) (Display *dpy, int name); + + +// GLX 1.2 +typedef Display *(*PFNGLXGETCURRENTDISPLAYPROC) (); + +} + +#endif // LIBANGLE_RENDERER_GL_GLX_FUNCTIONSGLXTYPEDEFS_H_ diff --git a/gfx/angle/src/libANGLE/renderer/gl/glx/platform_glx.h b/gfx/angle/src/libANGLE/renderer/gl/glx/platform_glx.h new file mode 100755 index 000000000..3ffb609d5 --- /dev/null +++ b/gfx/angle/src/libANGLE/renderer/gl/glx/platform_glx.h @@ -0,0 +1,190 @@ +// +// Copyright (c) 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. +// + +// platform_glx.h: Includes specific to GLX. + +#ifndef LIBANGLE_RENDERER_GL_GLX_PLATFORMGLX_H_ +#define LIBANGLE_RENDERER_GL_GLX_PLATFORMGLX_H_ + +#if !defined(ANGLE_SKIP_GLX_DEFINES) +// GLX 1.0 +#define GLX_USE_GL 1 +#define GLX_BUFFER_SIZE 2 +#define GLX_LEVEL 3 +#define GLX_RGBA 4 +#define GLX_DOUBLEBUFFER 5 +#define GLX_STEREO 6 +#define GLX_AUX_BUFFERS 7 +#define GLX_RED_SIZE 8 +#define GLX_GREEN_SIZE 9 +#define GLX_BLUE_SIZE 10 +#define GLX_ALPHA_SIZE 11 +#define GLX_DEPTH_SIZE 12 +#define GLX_STENCIL_SIZE 13 +#define GLX_ACCUM_RED_SIZE 14 +#define GLX_ACCUM_GREEN_SIZE 15 +#define GLX_ACCUM_BLUE_SIZE 16 +#define GLX_ACCUM_ALPHA_SIZE 17 + +#define GLX_BAD_SCREEN 1 +#define GLX_BAD_ATTRIBUTE 2 +#define GLX_NO_EXTENSION 3 +#define GLX_BAD_VISUAL 4 +#define GLX_BAD_CONTEXT 5 +#define GLX_BAD_VALUE 6 +#define GLX_BAD_ENUM 7 + +// GLX 1.1 +#define GLX_VENDOR 1 +#define GLX_VERSION 2 +#define GLX_EXTENSIONS 3 + +// GLX 1.3 +#define GLX_CONFIG_CAVEAT 0x20 +#define GLX_DONT_CARE 0xFFFFFFFF +#define GLX_X_VISUAL_TYPE 0x22 +#define GLX_TRANSPARENT_TYPE 0x23 +#define GLX_TRANSPARENT_INDEX_VALUE 0x24 +#define GLX_TRANSPARENT_RED_VALUE 0x25 +#define GLX_TRANSPARENT_GREEN_VALUE 0x26 +#define GLX_TRANSPARENT_BLUE_VALUE 0x27 +#define GLX_TRANSPARENT_ALPHA_VALUE 0x28 +#define GLX_WINDOW_BIT 0x00000001 +#define GLX_PIXMAP_BIT 0x00000002 +#define GLX_PBUFFER_BIT 0x00000004 +#define GLX_AUX_BUFFERS_BIT 0x00000010 +#define GLX_FRONT_LEFT_BUFFER_BIT 0x00000001 +#define GLX_FRONT_RIGHT_BUFFER_BIT 0x00000002 +#define GLX_BACK_LEFT_BUFFER_BIT 0x00000004 +#define GLX_BACK_RIGHT_BUFFER_BIT 0x00000008 +#define GLX_DEPTH_BUFFER_BIT 0x00000020 +#define GLX_STENCIL_BUFFER_BIT 0x00000040 +#define GLX_ACCUM_BUFFER_BIT 0x00000080 +#define GLX_NONE 0x8000 +#define GLX_SLOW_CONFIG 0x8001 +#define GLX_TRUE_COLOR 0x8002 +#define GLX_DIRECT_COLOR 0x8003 +#define GLX_PSEUDO_COLOR 0x8004 +#define GLX_STATIC_COLOR 0x8005 +#define GLX_GRAY_SCALE 0x8006 +#define GLX_STATIC_GRAY 0x8007 +#define GLX_TRANSPARENT_RGB 0x8008 +#define GLX_TRANSPARENT_INDEX 0x8009 +#define GLX_VISUAL_ID 0x800B +#define GLX_SCREEN 0x800C +#define GLX_NON_CONFORMANT_CONFIG 0x800D +#define GLX_DRAWABLE_TYPE 0x8010 +#define GLX_RENDER_TYPE 0x8011 +#define GLX_X_RENDERABLE 0x8012 +#define GLX_FBCONFIG_ID 0x8013 +#define GLX_RGBA_TYPE 0x8014 +#define GLX_COLOR_INDEX_TYPE 0x8015 +#define GLX_MAX_PBUFFER_WIDTH 0x8016 +#define GLX_MAX_PBUFFER_HEIGHT 0x8017 +#define GLX_MAX_PBUFFER_PIXELS 0x8018 +#define GLX_PRESERVED_CONTENTS 0x801B +#define GLX_LARGEST_PBUFFER 0x801C +#define GLX_WIDTH 0x801D +#define GLX_HEIGHT 0x801E +#define GLX_EVENT_MASK 0x801F +#define GLX_DAMAGED 0x8020 +#define GLX_SAVED 0x8021 +#define GLX_WINDOW 0x8022 +#define GLX_PBUFFER 0x8023 +#define GLX_PBUFFER_HEIGHT 0x8040 +#define GLX_PBUFFER_WIDTH 0x8041 +#define GLX_RGBA_BIT 0x00000001 +#define GLX_COLOR_INDEX_BIT 0x00000002 +#define GLX_PBUFFER_CLOBBER_MASK 0x08000000 + +// GLX 1.4 +#define GLX_SAMPLE_BUFFERS 0x186a0 +#define GLX_SAMPLES 0x186a1 + +// GLX_ARB_create_context +#define GLX_CONTEXT_DEBUG_BIT_ARB 0x00000001 +#define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002 +#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091 +#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092 +#define GLX_CONTEXT_FLAGS_ARB 0x2094 + +// GLX_ARB_create_context_profile +#define GLX_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 +#define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 +#define GLX_CONTEXT_PROFILE_MASK_ARB 0x9126 + +// GLX_ARB_create_context_robustness +#define GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004 +#define GLX_LOSE_CONTEXT_ON_RESET_ARB 0x8252 +#define GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 +#define GLX_NO_RESET_NOTIFICATION_ARB 0x8261 + +// GLX_EXT_create_context_es2_profile +#define GLX_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004 + +// GLX_EXT_texture_from_pixmap +#define GLX_TEXTURE_1D_BIT_EXT 0x00000001 +#define GLX_TEXTURE_2D_BIT_EXT 0x00000002 +#define GLX_TEXTURE_RECTANGLE_BIT_EXT 0x00000004 +#define GLX_BIND_TO_TEXTURE_RGB_EXT 0x20D0 +#define GLX_BIND_TO_TEXTURE_RGBA_EXT 0x20D1 +#define GLX_BIND_TO_MIPMAP_TEXTURE_EXT 0x20D2 +#define GLX_BIND_TO_TEXTURE_TARGETS_EXT 0x20D3 +#define GLX_Y_INVERTED_EXT 0x20D4 +#define GLX_TEXTURE_FORMAT_EXT 0x20D5 +#define GLX_TEXTURE_TARGET_EXT 0x20D6 +#define GLX_MIPMAP_TEXTURE_EXT 0x20D7 +#define GLX_TEXTURE_FORMAT_NONE_EXT 0x20D8 +#define GLX_TEXTURE_FORMAT_RGB_EXT 0x20D9 +#define GLX_TEXTURE_FORMAT_RGBA_EXT 0x20DA +#define GLX_TEXTURE_1D_EXT 0x20DB +#define GLX_TEXTURE_2D_EXT 0x20DC +#define GLX_TEXTURE_RECTANGLE_EXT 0x20DD +#define GLX_FRONT_LEFT_EXT 0x20DE +#define GLX_FRONT_RIGHT_EXT 0x20DF +#define GLX_BACK_LEFT_EXT 0x20E0 +#define GLX_BACK_RIGHT_EXT 0x20E1 +#define GLX_FRONT_EXT 0x20DE +#define GLX_BACK_EXT 0x20E0 +#define GLX_AUX0_EXT 0x20E2 +#define GLX_AUX1_EXT 0x20E3 +#define GLX_AUX2_EXT 0x20E4 +#define GLX_AUX3_EXT 0x20E5 +#define GLX_AUX4_EXT 0x20E6 +#define GLX_AUX5_EXT 0x20E7 +#define GLX_AUX6_EXT 0x20E8 +#define GLX_AUX7_EXT 0x20E9 +#define GLX_AUX8_EXT 0x20EA +#define GLX_AUX9_EXT 0x20EB + +// GLX_EXT_swap_control +#define GLX_SWAP_INTERVAL_EXT 0x20F1 +#define GLX_MAX_SWAP_INTERVAL_EXT 0x20F2 +#endif // !defined(ANGLE_SKIP_GLX_DEFINES) + +// GLX typedefs depend on the X headers +#include <X11/Xlib.h> +#include <X11/Xresource.h> +#include <X11/Xutil.h> + +// GLX typedefs +namespace glx +{ + +typedef void *Context; +typedef void *FBConfig; +typedef XID FBConfigID; +typedef XID ContextID; +typedef XID Window; +typedef XID Pbuffer; +typedef XID Pixmap; +typedef XID Drawable; + +} + +typedef void* (*PFNGETPROCPROC) (const char *name); + +#endif // LIBANGLE_RENDERER_GL_GLX_PLATFORMGLX_H_ |