// Return the GLXFBConfig most closely matching the specified hints // static GLFWbool chooseGLXFBConfig(const _GLFWfbconfig* desired, GLXFBConfig* result) { GLXFBConfig* nativeConfigs; _GLFWfbconfig* usableConfigs; const _GLFWfbconfig* closest; int i, nativeCount, usableCount; const char* vendor; GLFWbool trustWindowBit = GLFW_TRUE; // HACK: This is a (hopefully temporary) workaround for Chromium // (VirtualBox GL) not setting the window bit on any GLXFBConfigs vendor = glXGetClientString(_glfw.x11.display, GLX_VENDOR); if (strcmp(vendor, "Chromium") == 0) trustWindowBit = GLFW_FALSE; nativeConfigs = glXGetFBConfigs(_glfw.x11.display, _glfw.x11.screen, &nativeCount); if (!nativeCount) { _glfwInputError(GLFW_API_UNAVAILABLE, "GLX: No GLXFBConfigs returned"); return GLFW_FALSE; } usableConfigs = calloc(nativeCount, sizeof(_GLFWfbconfig)); usableCount = 0; for (i = 0; i < nativeCount; i++) { const GLXFBConfig n = nativeConfigs[i]; _GLFWfbconfig* u = usableConfigs + usableCount; // Only consider RGBA GLXFBConfigs if (!(getGLXFBConfigAttrib(n, GLX_RENDER_TYPE) & GLX_RGBA_BIT)) continue; // Only consider window GLXFBConfigs if (!(getGLXFBConfigAttrib(n, GLX_DRAWABLE_TYPE) & GLX_WINDOW_BIT)) { if (trustWindowBit) continue; } u->redBits = getGLXFBConfigAttrib(n, GLX_RED_SIZE); u->greenBits = getGLXFBConfigAttrib(n, GLX_GREEN_SIZE); u->blueBits = getGLXFBConfigAttrib(n, GLX_BLUE_SIZE); u->alphaBits = getGLXFBConfigAttrib(n, GLX_ALPHA_SIZE); u->depthBits = getGLXFBConfigAttrib(n, GLX_DEPTH_SIZE); u->stencilBits = getGLXFBConfigAttrib(n, GLX_STENCIL_SIZE); u->accumRedBits = getGLXFBConfigAttrib(n, GLX_ACCUM_RED_SIZE); u->accumGreenBits = getGLXFBConfigAttrib(n, GLX_ACCUM_GREEN_SIZE); u->accumBlueBits = getGLXFBConfigAttrib(n, GLX_ACCUM_BLUE_SIZE); u->accumAlphaBits = getGLXFBConfigAttrib(n, GLX_ACCUM_ALPHA_SIZE); u->auxBuffers = getGLXFBConfigAttrib(n, GLX_AUX_BUFFERS); if (getGLXFBConfigAttrib(n, GLX_STEREO)) u->stereo = GLFW_TRUE; if (getGLXFBConfigAttrib(n, GLX_DOUBLEBUFFER)) u->doublebuffer = GLFW_TRUE; if (_glfw.glx.ARB_multisample) u->samples = getGLXFBConfigAttrib(n, GLX_SAMPLES); if (_glfw.glx.ARB_framebuffer_sRGB || _glfw.glx.EXT_framebuffer_sRGB) u->sRGB = getGLXFBConfigAttrib(n, GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB); u->handle = (uintptr_t) n; usableCount++; } closest = _glfwChooseFBConfig(desired, usableConfigs, usableCount); if (closest) *result = (GLXFBConfig) closest->handle; XFree(nativeConfigs); free(usableConfigs); return closest != NULL; }
egl::Error DisplayGLX::initialize(egl::Display *display) { mEGLDisplay = display; Display *xDisplay = 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 (xDisplay == EGL_DEFAULT_DISPLAY) { mUsesNewXDisplay = true; xDisplay = XOpenDisplay(NULL); if (!xDisplay) { return egl::Error(EGL_NOT_INITIALIZED, "Could not open the default X display."); } } std::string glxInitError; if (!mGLX.initialize(xDisplay, DefaultScreen(xDisplay), &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"); mHasEXTCreateContextES2Profile = mGLX.hasExtension("GLX_EXT_create_context_es2_profile"); // 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 = 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(xDisplay, 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 && (vendor == VENDOR_ID_INTEL || vendor == VENDOR_ID_NVIDIA)) { return egl::Error(EGL_NOT_INITIALIZED, "Intel or NVIDIA OpenGL ES drivers are not supported."); } syncXCommands(); std::string rendererString = reinterpret_cast<const char*>(mFunctionsGL->getString(GL_RENDERER)); mIsMesa = rendererString.find("Mesa") != std::string::npos; return DisplayGL::initialize(display); }
egl::ConfigSet DisplayGLX::generateConfigs() const { 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; }
egl::Error DisplayGLX::initialize(egl::Display *display) { mEGLDisplay = display; mXDisplay = display->getNativeDisplayId(); // 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) { mXDisplay = XOpenDisplay(NULL); if (!mXDisplay) { return egl::Error(EGL_NOT_INITIALIZED, "Could not open the default X display."); } } egl::Error glxInitResult = mGLX.initialize(mXDisplay); if (glxInitResult.isError()) { return glxInitResult; } // Check we have the needed extensions { if (mGLX.minorVersion == 3 && !mGLX.hasExtension("GLX_ARB_multisample")) { return egl::Error(EGL_NOT_INITIALIZED, "GLX doesn't support ARB_multisample."); } // Require ARB_create_context which has been supported since Mesa 9 unconditionnaly // and is present in Mesa 8 in an almost always on compile flag. Also assume proprietary // drivers have it. if (!mGLX.hasExtension("GLX_ARB_create_context")) { return egl::Error(EGL_NOT_INITIALIZED, "GLX doesn't support ARB_create_context."); } } GLXFBConfig contextConfig; // When glXMakeCurrent is called the visual of the context FBConfig and of // the drawable must match. This means that when generating the list of EGL // configs, they must all have the same visual id as our unique GL context. // Here we find a GLX framebuffer config we like to create our GL context // so that we are sure there is a decent config given back to the application // when it queries EGL. { int nConfigs; int attribList[] = { // We want at least 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, 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 }; GLXFBConfig* candidates = mGLX.chooseFBConfig(mXDisplay, DefaultScreen(mXDisplay), attribList, &nConfigs); if (nConfigs == 0) { XFree(candidates); return egl::Error(EGL_NOT_INITIALIZED, "Could not find a decent GLX FBConfig to create the context."); } contextConfig = candidates[0]; XFree(candidates); } mContextVisualId = getGLXFBConfigAttrib(contextConfig, GLX_VISUAL_ID); mContext = mGLX.createContextAttribsARB(mXDisplay, contextConfig, nullptr, True, nullptr); if (!mContext) { return egl::Error(EGL_NOT_INITIALIZED, "Could not create GL context."); } // 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 0, 0) for the duration of these calls. // TODO(cwallez) error checking here // TODO(cwallez) during the initialization of ANGLE we need a gl context current // to query things like limits. Ideally we would want to unset the current context // and destroy the pbuffer before going back to the application but this is TODO mDummyPbuffer = mGLX.createPbuffer(mXDisplay, contextConfig, nullptr); mGLX.makeCurrent(mXDisplay, mDummyPbuffer, mContext); mFunctionsGL = new FunctionsGLGLX(mGLX.getProc); mFunctionsGL->initialize(); return DisplayGL::initialize(display); }
egl::ConfigSet DisplayGLX::generateConfigs() const { egl::ConfigSet configs; configIdToGLXConfig.clear(); // GLX_EXT_texture_from_pixmap is required for the "bind to rgb(a)" attributes bool hasTextureFromPixmap = mGLX.hasExtension("GLX_EXT_texture_from_pixmap"); int glxConfigCount; GLXFBConfig *glxConfigs = mGLX.getFBConfigs(mXDisplay, DefaultScreen(mXDisplay), &glxConfigCount); for (int i = 0; i < glxConfigCount; i++) { GLXFBConfig glxConfig = glxConfigs[i]; egl::Config config; // Native stuff int visualId = getGLXFBConfigAttrib(glxConfig, GLX_VISUAL_ID); if (visualId != mContextVisualId) { // Filter out the configs that are incompatible with our GL context continue; } config.nativeVisualID = visualId; config.nativeVisualType = getGLXFBConfigAttrib(glxConfig, GLX_X_VISUAL_TYPE); config.nativeRenderable = EGL_TRUE; // 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); config.colorBufferType = EGL_RGB_BUFFER; config.luminanceSize = 0; config.alphaMaskSize = 0; config.bufferSize = config.redSize + config.greenSize + config.blueSize + config.alphaSize; // 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.sampleBuffers = getGLXFBConfigAttrib(glxConfig, GLX_SAMPLE_BUFFERS); config.samples = getGLXFBConfigAttrib(glxConfig, GLX_SAMPLES); config.level = getGLXFBConfigAttrib(glxConfig, GLX_LEVEL); config.bindToTextureRGB = EGL_FALSE; config.bindToTextureRGBA = EGL_FALSE; if (hasTextureFromPixmap) { config.bindToTextureRGB = getGLXFBConfigAttrib(glxConfig, GLX_BIND_TO_TEXTURE_RGB_EXT); config.bindToTextureRGBA = getGLXFBConfigAttrib(glxConfig, GLX_BIND_TO_TEXTURE_RGBA_EXT); } 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); // In GLX_EXT_swap_control querying these is done on a GLXWindow so we just set a default value. config.maxSwapInterval = 1; config.minSwapInterval = 1; // TODO(cwallez) wildly guessing these formats, another TODO says they should be removed anyway config.renderTargetFormat = GL_RGBA8; config.depthStencilFormat = GL_DEPTH24_STENCIL8; // TODO(cwallez) Fill after determining the GL version we are using and what ES version it supports config.conformant = EGL_OPENGL_ES2_BIT | EGL_OPENGL_ES3_BIT_KHR; config.renderableType = EGL_OPENGL_ES2_BIT | EGL_OPENGL_ES3_BIT_KHR; // TODO(cwallez) I have no idea what this is config.matchNativePixmap = EGL_NONE; int id = configs.add(config); configIdToGLXConfig[id] = glxConfig; } return configs; }
egl::ConfigSet DisplayGLX::generateConfigs() const { egl::ConfigSet configs; configIdToGLXConfig.clear(); bool hasSwapControl = mGLX.hasExtension("GLX_EXT_swap_control"); int contextSamples = getGLXFBConfigAttrib(mContextConfig, GLX_SAMPLES); int contextSampleBuffers = getGLXFBConfigAttrib(mContextConfig, GLX_SAMPLE_BUFFERS); 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; // 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 != 8 || config.greenSize != 8 || config.blueSize != 8 || config.alphaSize != 8) { continue; } if (!(config.depthSize == 24 && config.stencilSize == 8) && !(config.depthSize == 0 && config.stencilSize == 0)) { 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 = getGLXFBConfigAttrib(glxConfig, GLX_SAMPLES); int sampleBuffers = getGLXFBConfigAttrib(glxConfig, GLX_SAMPLE_BUFFERS); 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; } // 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.sampleBuffers = getGLXFBConfigAttrib(glxConfig, GLX_SAMPLE_BUFFERS); config.samples = getGLXFBConfigAttrib(glxConfig, GLX_SAMPLES); 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); if (hasSwapControl) { // In GLX_EXT_swap_control querying these is done on a GLXWindow so we just set a default value. config.minSwapInterval = 0; config.maxSwapInterval = 4; } else { config.minSwapInterval = 1; config.maxSwapInterval = 1; } // TODO(cwallez) wildly guessing these formats, another TODO says they should be removed anyway config.renderTargetFormat = GL_RGBA8; config.depthStencilFormat = GL_DEPTH24_STENCIL8; // TODO(cwallez) Fill after determining the GL version we are using and what ES version it supports config.conformant = EGL_OPENGL_ES2_BIT | EGL_OPENGL_ES3_BIT_KHR; config.renderableType = EGL_OPENGL_ES2_BIT | EGL_OPENGL_ES3_BIT_KHR; // TODO(cwallez) I have no idea what this is config.matchNativePixmap = EGL_NONE; int id = configs.add(config); configIdToGLXConfig[id] = glxConfig; } return configs; }