static GLint getInternalFormat(void) { switch (glctx.type) { #ifdef CONFIG_GL_WIN32 case GLTYPE_W32: { PIXELFORMATDESCRIPTOR pfd; HDC vo_hdc = vo_w32_get_dc(vo_w32_window); int pf = GetPixelFormat(vo_hdc); if (!DescribePixelFormat(vo_hdc, pf, sizeof pfd, &pfd)) { r_sz = g_sz = b_sz = a_sz = 0; } else { r_sz = pfd.cRedBits; g_sz = pfd.cGreenBits; b_sz = pfd.cBlueBits; a_sz = pfd.cAlphaBits; } vo_w32_release_dc(vo_w32_window, vo_hdc); } break; #endif #ifdef CONFIG_GL_X11 case GLTYPE_X11: if (glXGetConfig(mDisplay, glctx.vinfo.x11, GLX_RED_SIZE, &r_sz) != 0) r_sz = 0; if (glXGetConfig(mDisplay, glctx.vinfo.x11, GLX_GREEN_SIZE, &g_sz) != 0) g_sz = 0; if (glXGetConfig(mDisplay, glctx.vinfo.x11, GLX_BLUE_SIZE, &b_sz) != 0) b_sz = 0; if (glXGetConfig(mDisplay, glctx.vinfo.x11, GLX_ALPHA_SIZE, &a_sz) != 0) a_sz = 0; break; #endif } rgb_sz=r_sz+g_sz+b_sz; if(rgb_sz<=0) rgb_sz=24; #ifdef TEXTUREFORMAT_ALWAYS return TEXTUREFORMAT_ALWAYS; #else if(r_sz==3 && g_sz==3 && b_sz==2 && a_sz==0) return GL_R3_G3_B2; if(r_sz==4 && g_sz==4 && b_sz==4 && a_sz==0) return GL_RGB4; if(r_sz==5 && g_sz==5 && b_sz==5 && a_sz==0) return GL_RGB5; if(r_sz==8 && g_sz==8 && b_sz==8 && a_sz==0) return GL_RGB8; if(r_sz==10 && g_sz==10 && b_sz==10 && a_sz==0) return GL_RGB10; if(r_sz==2 && g_sz==2 && b_sz==2 && a_sz==2) return GL_RGBA2; if(r_sz==4 && g_sz==4 && b_sz==4 && a_sz==4) return GL_RGBA4; if(r_sz==5 && g_sz==5 && b_sz==5 && a_sz==1) return GL_RGB5_A1; if(r_sz==8 && g_sz==8 && b_sz==8 && a_sz==8) return GL_RGBA8; if(r_sz==10 && g_sz==10 && b_sz==10 && a_sz==2) return GL_RGB10_A2; #endif return GL_RGB; }
static int checkOverlayAcceptability( XVisualInfo *vi, unsigned int mode ) { t_winstruct *window = &C3D_win; int value; /* Must support OpenGL */ glXGetConfig( window->dpy, vi, GLX_USE_GL, &value ); if ( !value ) return 1; /* Must be color-index .*/ glXGetConfig( window->dpy, vi, GLX_RGBA, &value ); if ( value ) return 1; /* Must match single/double buffering request. */ glXGetConfig( window->dpy, vi, GLX_DOUBLEBUFFER, &value ); if ( C3D_WIND_IS_DOUBLE( window->display_mode) != ( value != 0 )) return 1; /* Must match mono/stereo request */ glXGetConfig( window->dpy, vi, GLX_STEREO, &value ); if ( C3D_WIND_IS_STEREO(mode) != (value != 0)) return 1; return 0; }
//================================================================ void* GLB_Create () { //================================================================ /// GLB_Create create opengl-window (used by GUI_gl__) GtkWidget *area; int xscreen, i1; GdkScreen *screen; GdkVisual *visual; Window root; XVisualInfo *xvisual; Colormap xcolormap; int attributes[] = { GLX_RGBA, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1, GLX_DOUBLEBUFFER, True, GLX_DEPTH_SIZE, 24, None }; GLB_x_id = 0; // reset area = gtk_drawing_area_new (); gtk_widget_set_double_buffered (area, FALSE); GLB_display = gdk_x11_get_default_xdisplay (); xscreen = DefaultScreen (GLB_display); screen = gdk_screen_get_default (); // printf(" screenNr = %d\n",gdk_screen_get_number(screen)); xvisual = glXChooseVisual (GLB_display, xscreen, attributes); // printf(" xvisualid=%d\n",xvisual->visualid); visual = gdk_x11_screen_lookup_visual (screen, xvisual->visualid); root = RootWindow (GLB_display, xscreen); xcolormap = XCreateColormap (GLB_display, root, xvisual->visual, AllocNone); glXGetConfig (GLB_display, xvisual, GLX_RED_SIZE, &i1); printf(" GLX_RED_SIZE=%d\n",i1); glXGetConfig (GLB_display, xvisual, GLX_DEPTH_SIZE, &i1); printf(" GLX_DEPTH_SIZE=%d\n",i1); // Gtk2 only: //colormap = gdk_x11_colormap_foreign_new (visual, xcolormap); //gtk_widget_set_colormap (area, colormap); GLB_x_context = glXCreateContext (GLB_display, xvisual, NULL, TRUE); // free (xvisual); glXWaitX(); glXWaitGL(); return area; }
XVisualInfo GlxContext::selectBestVisual(::Display* display, unsigned int bitsPerPixel, const ContextSettings& settings) { // Retrieve all the visuals int count; XVisualInfo* visuals = XGetVisualInfo(display, 0, NULL, &count); if (visuals) { // Evaluate all the returned visuals, and pick the best one int bestScore = 0xFFFF; XVisualInfo bestVisual; for (int i = 0; i < count; ++i) { // Check mandatory attributes int doubleBuffer; glXGetConfig(display, &visuals[i], GLX_DOUBLEBUFFER, &doubleBuffer); if (!doubleBuffer) continue; // Extract the components of the current visual int red, green, blue, alpha, depth, stencil, multiSampling, samples; glXGetConfig(display, &visuals[i], GLX_RED_SIZE, &red); glXGetConfig(display, &visuals[i], GLX_GREEN_SIZE, &green); glXGetConfig(display, &visuals[i], GLX_BLUE_SIZE, &blue); glXGetConfig(display, &visuals[i], GLX_ALPHA_SIZE, &alpha); glXGetConfig(display, &visuals[i], GLX_DEPTH_SIZE, &depth); glXGetConfig(display, &visuals[i], GLX_STENCIL_SIZE, &stencil); glXGetConfig(display, &visuals[i], GLX_SAMPLE_BUFFERS_ARB, &multiSampling); glXGetConfig(display, &visuals[i], GLX_SAMPLES_ARB, &samples); // Evaluate the visual int color = red + green + blue + alpha; int score = evaluateFormat(bitsPerPixel, settings, color, depth, stencil, multiSampling ? samples : 0); // If it's better than the current best, make it the new best if (score < bestScore) { bestScore = score; bestVisual = visuals[i]; } } // Free the array of visuals XFree(visuals); return bestVisual; } else { // Should never happen... err() << "No GLX visual found. You should check your graphics driver" << std::endl; return XVisualInfo(); } }
/* * Queries the GL context about some attributes */ static int fghGetConfig( int attribute ) { int returnValue = 0; if( fgStructure.CurrentWindow ) glXGetConfig( fgDisplay.Display, fgStructure.CurrentWindow->Window.VisualInfo, attribute, &returnValue ); return returnValue; }
QPlatformWindowFormat qglx_platformWindowFromGLXFBConfig(Display *display, GLXFBConfig config, GLXContext ctx) { QPlatformWindowFormat format; int redSize = 0; int greenSize = 0; int blueSize = 0; int alphaSize = 0; int depthSize = 0; int stencilSize = 0; int sampleBuffers = 0; int sampleCount = 0; int level = 0; int rgba = 0; int stereo = 0; int accumSizeA = 0; int accumSizeR = 0; int accumSizeG = 0; int accumSizeB = 0; XVisualInfo *vi = glXGetVisualFromFBConfig(display,config); glXGetConfig(display,vi,GLX_RGBA,&rgba); XFree(vi); glXGetFBConfigAttrib(display, config, GLX_RED_SIZE, &redSize); glXGetFBConfigAttrib(display, config, GLX_GREEN_SIZE, &greenSize); glXGetFBConfigAttrib(display, config, GLX_BLUE_SIZE, &blueSize); glXGetFBConfigAttrib(display, config, GLX_ALPHA_SIZE, &alphaSize); glXGetFBConfigAttrib(display, config, GLX_DEPTH_SIZE, &depthSize); glXGetFBConfigAttrib(display, config, GLX_STENCIL_SIZE, &stencilSize); glXGetFBConfigAttrib(display, config, GLX_SAMPLES, &sampleBuffers); glXGetFBConfigAttrib(display, config, GLX_LEVEL, &level); glXGetFBConfigAttrib(display, config, GLX_STEREO, &stereo); glXGetFBConfigAttrib(display, config, GLX_ACCUM_ALPHA_SIZE, &accumSizeA); glXGetFBConfigAttrib(display, config, GLX_ACCUM_RED_SIZE, &accumSizeR); glXGetFBConfigAttrib(display, config, GLX_ACCUM_GREEN_SIZE, &accumSizeG); glXGetFBConfigAttrib(display, config, GLX_ACCUM_BLUE_SIZE, &accumSizeB); format.setRedBufferSize(redSize); format.setGreenBufferSize(greenSize); format.setBlueBufferSize(blueSize); format.setAlphaBufferSize(alphaSize); format.setDepthBufferSize(depthSize); format.setStencilBufferSize(stencilSize); format.setSampleBuffers(sampleBuffers); if (format.sampleBuffers()) { glXGetFBConfigAttrib(display, config, GLX_SAMPLES_ARB, &sampleCount); format.setSamples(sampleCount); } format.setDirectRendering(glXIsDirect(display, ctx)); format.setRgba(rgba); format.setStereo(stereo); format.setAccumBufferSize(accumSizeB); return format; }
void GlxContext::updateSettingsFromVisualInfo(XVisualInfo* visualInfo) { // Update the creation settings from the chosen format int depth, stencil, multiSampling, samples; glXGetConfig(m_display, visualInfo, GLX_DEPTH_SIZE, &depth); glXGetConfig(m_display, visualInfo, GLX_STENCIL_SIZE, &stencil); if (sfglx_ext_ARB_multisample == sfglx_LOAD_SUCCEEDED) { glXGetConfig(m_display, visualInfo, GLX_SAMPLE_BUFFERS_ARB, &multiSampling); glXGetConfig(m_display, visualInfo, GLX_SAMPLES_ARB, &samples); } else { multiSampling = 0; samples = 0; } m_settings.depthBits = static_cast<unsigned int>(depth); m_settings.stencilBits = static_cast<unsigned int>(stencil); m_settings.antialiasingLevel = multiSampling ? samples : 0; }
static int checkOverlayAcceptability(XVisualInfo * vi, unsigned int mode) { int value; /* Must support OpenGL. */ glXGetConfig(__glutDisplay, vi, GLX_USE_GL, &value); if (!value) return 1; /* Must be color index. */ glXGetConfig(__glutDisplay, vi, GLX_RGBA, &value); if (value) return 1; /* Must match single/double buffering request. */ glXGetConfig(__glutDisplay, vi, GLX_DOUBLEBUFFER, &value); if (GLUT_WIND_IS_DOUBLE(mode) != (value != 0)) return 1; /* Must match mono/stereo request. */ glXGetConfig(__glutDisplay, vi, GLX_STEREO, &value); if (GLUT_WIND_IS_STEREO(mode) != (value != 0)) return 1; /* Alpha and accumulation buffers incompatible with color index. */ if (GLUT_WIND_HAS_ALPHA(mode) || GLUT_WIND_HAS_ACCUM(mode)) return 1; /* Look for depth buffer if requested. */ glXGetConfig(__glutDisplay, vi, GLX_DEPTH_SIZE, &value); if (GLUT_WIND_HAS_DEPTH(mode) && (value <= 0)) return 1; /* Look for stencil buffer if requested. */ glXGetConfig(__glutDisplay, vi, GLX_STENCIL_SIZE, &value); if (GLUT_WIND_HAS_STENCIL(mode) && (value <= 0)) return 1; #if defined(GLX_VERSION_1_1) && defined(GLX_SGIS_multisample) /* XXX Multisampled overlay color index?? Pretty unlikely. */ /* Look for multisampling if requested. */ if (__glutIsSupportedByGLX("GLX_SGIS_multisample")) glXGetConfig(__glutDisplay, vi, GLX_SAMPLES_SGIS, &value); else value = 0; if (GLUT_WIND_IS_MULTISAMPLE(mode) && (value <= 0)) return 1; #endif return 0; }
JNIEXPORT jint JNICALL GLX_NATIVE(glXGetConfig) (JNIEnv *env, jclass that, jint arg0, jobject arg1, jint arg2, jintArray arg3) { XVisualInfo _arg1, *lparg1=NULL; jint *lparg3=NULL; jint rc = 0; GLX_NATIVE_ENTER(env, that, glXGetConfig_FUNC); if (arg1) if ((lparg1 = getXVisualInfoFields(env, arg1, &_arg1)) == NULL) goto fail; if (arg3) if ((lparg3 = (*env)->GetIntArrayElements(env, arg3, NULL)) == NULL) goto fail; rc = (jint)glXGetConfig(arg0, lparg1, arg2, lparg3); fail: if (arg3 && lparg3) (*env)->ReleaseIntArrayElements(env, arg3, lparg3, 0); if (arg1 && lparg1) setXVisualInfoFields(env, arg1, lparg1); GLX_NATIVE_EXIT(env, that, glXGetConfig_FUNC); return rc; }
WindowSystem::WindowSystem(Options& o) { // If running in "compare" mode we never actually use the window // system, so we don't initialize it here. This allows us to run // on systems without graphics hardware/software. if (o.mode == Options::compare) { dpy = 0; GLXVersMajor = GLXVersMinor = 0; vip = 0; return; } // Open the X11 display: dpy = XOpenDisplay(o.dpyName.c_str()); if (!dpy) throw CantOpenDisplay(); // Verify that GLX is supported: int error_base, event_base; if (glXQueryExtension(dpy, &error_base, &event_base) == False) throw NoOpenGL(); // Record version numbers for later use: if (glXQueryVersion(dpy, &GLXVersMajor, &GLXVersMinor) == False) throw Error(); // this should never happen :-) // Get the list of raw XVisualInfo structures: XVisualInfo vit; vit.screen = DefaultScreen(dpy); int n; vip = XGetVisualInfo(dpy, VisualScreenMask, &vit, &n); // Construct a vector of DrawingSurfaceConfigs corresponding to the // XVisualInfo structures that indicate they support OpenGL: vector<DrawingSurfaceConfig*> glxv; for (int i = 0; i < n; ++i) { int supportsOpenGL; glXGetConfig(dpy, &vip[i], GLX_USE_GL, &supportsOpenGL); if (supportsOpenGL) glxv.push_back(new DrawingSurfaceConfig (dpy, &vip[i])); } // Filter the basic list of DrawingSurfaceConfigs according to // constraints provided by the user. (This makes it convenient // to run tests on just a subset of all available configs.) DrawingSurfaceFilter f(o.visFilter); // may throw an exception! surfConfigs = f.filter(glxv, o.maxVisuals); } // WindowSystem::WindowSystem
void XWindow::classicInit(void) { XVisualInfo *vi, visInfo; XWindowAttributes winAttr; XGetWindowAttributes(getDisplay(), getWindow(), &winAttr); // get the existing glWidget's visual-id memset(&visInfo, 0, sizeof(XVisualInfo)); visInfo.visualid = XVisualIDFromVisual(winAttr.visual); // get new display-variable if(getDisplay() == NULL) { setDisplay(XOpenDisplay(DisplayString(getDisplay()))); } // get a visual for the glx context int nvis; vi = XGetVisualInfo(getDisplay(), VisualIDMask, &visInfo, &nvis); // is the visual GL-capable ? int useGL; glXGetConfig( getDisplay(), vi, GLX_USE_GL, &useGL ); if (!useGL) { SFATAL << "Visual is not OpenGL-capable!" << std::endl; exit(0); } // create the new context this->setContext(glXCreateContext(getDisplay(), vi, None, GL_TRUE)); XFree(vi); }
bool CWinSystemX11::IsSuitableVisual(XVisualInfo *vInfo) { #if defined(HAS_GLX) int value; if (glXGetConfig(m_dpy, vInfo, GLX_RGBA, &value) || !value) return false; if (glXGetConfig(m_dpy, vInfo, GLX_DOUBLEBUFFER, &value) || !value) return false; if (glXGetConfig(m_dpy, vInfo, GLX_RED_SIZE, &value) || value < 8) return false; if (glXGetConfig(m_dpy, vInfo, GLX_GREEN_SIZE, &value) || value < 8) return false; if (glXGetConfig(m_dpy, vInfo, GLX_BLUE_SIZE, &value) || value < 8) return false; if (glXGetConfig(m_dpy, vInfo, GLX_ALPHA_SIZE, &value) || value < 8) return false; if (glXGetConfig(m_dpy, vInfo, GLX_DEPTH_SIZE, &value) || value < 8) return false; #endif #if defined(HAS_EGL) EGLConfig config = getEGLConfig(m_eglDisplay, vInfo); if (config == EGL_NO_CONFIG) { CLog::Log(LOGERROR, "Failed to determine egl config for visual info"); return false; } EGLint value; if (!eglGetConfigAttrib(m_eglDisplay, config, EGL_RED_SIZE, &value) || value < 8) return false; if (!eglGetConfigAttrib(m_eglDisplay, config, EGL_GREEN_SIZE, &value) || value < 8) return false; if (!eglGetConfigAttrib(m_eglDisplay, config, EGL_BLUE_SIZE, &value) || value < 8) return false; if (!eglGetConfigAttrib(m_eglDisplay, config, EGL_ALPHA_SIZE, &value) || value < 8) return false; if (!eglGetConfigAttrib(m_eglDisplay, config, EGL_DEPTH_SIZE, &value) || value < 24) return false; #endif return true; }
bool CGLContextGLX::IsSuitableVisual(XVisualInfo *vInfo) { int value; if (glXGetConfig(m_dpy, vInfo, GLX_RGBA, &value) || !value) return false; if (glXGetConfig(m_dpy, vInfo, GLX_DOUBLEBUFFER, &value) || !value) return false; if (glXGetConfig(m_dpy, vInfo, GLX_RED_SIZE, &value) || value < 8) return false; if (glXGetConfig(m_dpy, vInfo, GLX_GREEN_SIZE, &value) || value < 8) return false; if (glXGetConfig(m_dpy, vInfo, GLX_BLUE_SIZE, &value) || value < 8) return false; if (glXGetConfig(m_dpy, vInfo, GLX_ALPHA_SIZE, &value) || value < 8) return false; if (glXGetConfig(m_dpy, vInfo, GLX_DEPTH_SIZE, &value) || value < 8) return false; return true; }
void get_visual_attribs(Display *dpy, XVisualInfo *vInfo, struct visual_attribs *attribs) { const char *ext = glXQueryExtensionsString(dpy, vInfo->screen); memset(attribs, 0, sizeof(struct visual_attribs)); attribs->id = vInfo->visualid; #if defined(__cplusplus) || defined(c_plusplus) attribs->klass = vInfo->c_class; #else attribs->klass = vInfo->class; #endif attribs->depth = vInfo->depth; attribs->redMask = vInfo->red_mask; attribs->greenMask = vInfo->green_mask; attribs->blueMask = vInfo->blue_mask; attribs->colormapSize = vInfo->colormap_size; attribs->bitsPerRGB = vInfo->bits_per_rgb; if (glXGetConfig(dpy, vInfo, GLX_USE_GL, &attribs->supportsGL) != 0) return; glXGetConfig(dpy, vInfo, GLX_BUFFER_SIZE, &attribs->bufferSize); glXGetConfig(dpy, vInfo, GLX_LEVEL, &attribs->level); glXGetConfig(dpy, vInfo, GLX_RGBA, &attribs->rgba); glXGetConfig(dpy, vInfo, GLX_DOUBLEBUFFER, &attribs->doubleBuffer); glXGetConfig(dpy, vInfo, GLX_STEREO, &attribs->stereo); glXGetConfig(dpy, vInfo, GLX_AUX_BUFFERS, &attribs->auxBuffers); glXGetConfig(dpy, vInfo, GLX_RED_SIZE, &attribs->redSize); glXGetConfig(dpy, vInfo, GLX_GREEN_SIZE, &attribs->greenSize); glXGetConfig(dpy, vInfo, GLX_BLUE_SIZE, &attribs->blueSize); glXGetConfig(dpy, vInfo, GLX_ALPHA_SIZE, &attribs->alphaSize); glXGetConfig(dpy, vInfo, GLX_DEPTH_SIZE, &attribs->depthSize); glXGetConfig(dpy, vInfo, GLX_STENCIL_SIZE, &attribs->stencilSize); glXGetConfig(dpy, vInfo, GLX_ACCUM_RED_SIZE, &attribs->accumRedSize); glXGetConfig(dpy, vInfo, GLX_ACCUM_GREEN_SIZE, &attribs->accumGreenSize); glXGetConfig(dpy, vInfo, GLX_ACCUM_BLUE_SIZE, &attribs->accumBlueSize); glXGetConfig(dpy, vInfo, GLX_ACCUM_ALPHA_SIZE, &attribs->accumAlphaSize); /* transparent pixel value not implemented yet */ attribs->transparent = 0; /* multisample tests not implemented yet */ attribs->numSamples = 0; attribs->numMultisample = 0; #if defined(GLX_EXT_visual_rating) if (ext && strstr(ext, "GLX_EXT_visual_rating")) { glXGetConfig(dpy, vInfo, GLX_VISUAL_CAVEAT_EXT, &attribs->visualCaveat); } else { attribs->visualCaveat = GLX_NONE_EXT; } #else attribs->visualCaveat = 0; #endif }
QGLGraphicsSystem::QGLGraphicsSystem(bool useX11GL) : QGraphicsSystem(), m_useX11GL(useX11GL) { #if defined(Q_WS_X11) && !defined(QT_OPENGL_ES) // only override the system defaults if the user hasn't already // picked a visual if (X11->visual == 0 && X11->visual_id == -1 && X11->visual_class == -1) { // find a double buffered, RGBA visual that supports OpenGL // and set that as the default visual for windows in Qt int i = 0; int spec[16]; spec[i++] = GLX_RGBA; spec[i++] = GLX_DOUBLEBUFFER; if (!qgetenv("QT_GL_SWAPBUFFER_PRESERVE").isNull()) { spec[i++] = GLX_DEPTH_SIZE; spec[i++] = 8; spec[i++] = GLX_STENCIL_SIZE; spec[i++] = 8; spec[i++] = GLX_SAMPLE_BUFFERS_ARB; spec[i++] = 1; spec[i++] = GLX_SAMPLES_ARB; spec[i++] = 4; } spec[i++] = XNone; XVisualInfo *vi = glXChooseVisual(X11->display, X11->defaultScreen, spec); if (vi) { X11->visual_id = vi->visualid; X11->visual_class = vi->c_class; QGLFormat format; int res; glXGetConfig(X11->display, vi, GLX_LEVEL, &res); format.setPlane(res); glXGetConfig(X11->display, vi, GLX_DOUBLEBUFFER, &res); format.setDoubleBuffer(res); glXGetConfig(X11->display, vi, GLX_DEPTH_SIZE, &res); format.setDepth(res); if (format.depth()) format.setDepthBufferSize(res); glXGetConfig(X11->display, vi, GLX_RGBA, &res); format.setRgba(res); glXGetConfig(X11->display, vi, GLX_RED_SIZE, &res); format.setRedBufferSize(res); glXGetConfig(X11->display, vi, GLX_GREEN_SIZE, &res); format.setGreenBufferSize(res); glXGetConfig(X11->display, vi, GLX_BLUE_SIZE, &res); format.setBlueBufferSize(res); glXGetConfig(X11->display, vi, GLX_ALPHA_SIZE, &res); format.setAlpha(res); if (format.alpha()) format.setAlphaBufferSize(res); glXGetConfig(X11->display, vi, GLX_ACCUM_RED_SIZE, &res); format.setAccum(res); if (format.accum()) format.setAccumBufferSize(res); glXGetConfig(X11->display, vi, GLX_STENCIL_SIZE, &res); format.setStencil(res); if (format.stencil()) format.setStencilBufferSize(res); glXGetConfig(X11->display, vi, GLX_STEREO, &res); format.setStereo(res); glXGetConfig(X11->display, vi, GLX_SAMPLE_BUFFERS_ARB, &res); format.setSampleBuffers(res); if (format.sampleBuffers()) { glXGetConfig(X11->display, vi, GLX_SAMPLES_ARB, &res); format.setSamples(res); } QGLWindowSurface::surfaceFormat = format; XFree(vi); printf("using visual class %x, id %x\n", X11->visual_class, X11->visual_id); } } #elif defined(Q_WS_WIN) QGLWindowSurface::surfaceFormat.setDoubleBuffer(true); qt_win_owndc_required = true; #endif }
void GlxContext::createContext(GlxContext* shared, unsigned int bitsPerPixel, const ContextSettings& settings) { XVisualInfo* visualInfo = NULL; // Save the creation settings m_settings = settings; // Get the context to share display lists with GLXContext toShare = shared ? shared->m_context : NULL; // Create the OpenGL context -- first try context versions >= 3.0 if it is requested (they require special code) if (m_settings.majorVersion >= 3) { const GLubyte* name = reinterpret_cast<const GLubyte*>("glXCreateContextAttribsARB"); PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB = reinterpret_cast<PFNGLXCREATECONTEXTATTRIBSARBPROC>(glXGetProcAddress(name)); if (glXCreateContextAttribsARB) { // Select a GLXFB config that matches the requested context settings int nbConfigs = 0; int fbAttributes[] = { GLX_DEPTH_SIZE, static_cast<int>(settings.depthBits), GLX_STENCIL_SIZE, static_cast<int>(settings.stencilBits), GLX_SAMPLE_BUFFERS, settings.antialiasingLevel > 0, GLX_SAMPLES, static_cast<int>(settings.antialiasingLevel), GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8, GLX_ALPHA_SIZE, bitsPerPixel == 32 ? 8 : 0, GLX_DOUBLEBUFFER, True, GLX_X_RENDERABLE, True, GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, GLX_RENDER_TYPE, GLX_RGBA_BIT, GLX_CONFIG_CAVEAT, GLX_NONE, None }; GLXFBConfig* configs = glXChooseFBConfig(m_display, DefaultScreen(m_display), fbAttributes, &nbConfigs); if (configs && nbConfigs) { while (!m_context && (m_settings.majorVersion >= 3)) { // Create the context int attributes[] = { GLX_CONTEXT_MAJOR_VERSION_ARB, static_cast<int>(m_settings.majorVersion), GLX_CONTEXT_MINOR_VERSION_ARB, static_cast<int>(m_settings.minorVersion), GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, 0, 0 }; m_context = glXCreateContextAttribsARB(m_display, configs[0], toShare, true, attributes); if (m_context) { // Ok: retrieve the config's visual visualInfo = glXGetVisualFromFBConfig(m_display, configs[0]); } else { // If we couldn't create the context, lower the version number and try again -- stop at 3.0 // Invalid version numbers will be generated by this algorithm (like 3.9), but we really don't care if (m_settings.minorVersion > 0) { // If the minor version is not 0, we decrease it and try again m_settings.minorVersion--; } else { // If the minor version is 0, we decrease the major version m_settings.majorVersion--; m_settings.minorVersion = 9; } } } XFree(configs); } } } // If the OpenGL >= 3.0 context failed or if we don't want one, create a regular OpenGL 1.x/2.x context if (!m_context) { // set the context version to 2.0 (arbitrary) m_settings.majorVersion = 2; m_settings.minorVersion = 0; // Retrieve the attributes of the target window XWindowAttributes windowAttributes; if (XGetWindowAttributes(m_display, m_window, &windowAttributes) == 0) { err() << "Failed to get the window attributes" << std::endl; return; } // Get its visual XVisualInfo tpl; tpl.screen = DefaultScreen(m_display); tpl.visualid = XVisualIDFromVisual(windowAttributes.visual); int nbVisuals = 0; visualInfo = XGetVisualInfo(m_display, VisualIDMask | VisualScreenMask, &tpl, &nbVisuals); // Create the context, using the target window's visual m_context = glXCreateContext(m_display, visualInfo, toShare, true); if (!m_context) { err() << "Failed to create an OpenGL context for this window" << std::endl; return; } } // Update the creation settings from the chosen format int depth, stencil, multiSampling, samples; glXGetConfig(m_display, visualInfo, GLX_DEPTH_SIZE, &depth); glXGetConfig(m_display, visualInfo, GLX_STENCIL_SIZE, &stencil); glXGetConfig(m_display, visualInfo, GLX_SAMPLE_BUFFERS_ARB, &multiSampling); glXGetConfig(m_display, visualInfo, GLX_SAMPLES_ARB, &samples); m_settings.depthBits = static_cast<unsigned int>(depth); m_settings.stencilBits = static_cast<unsigned int>(stencil); m_settings.antialiasingLevel = multiSampling ? samples : 0; // Free the visual info XFree(visualInfo); }
static void get_visual_attribs(Display *dpy, XVisualInfo *vInfo, struct visual_attribs *attribs) { const char *ext = glXQueryExtensionsString(dpy, vInfo->screen); memset(attribs, 0, sizeof(struct visual_attribs)); attribs->id = vInfo->visualid; #if defined(__cplusplus) || defined(c_plusplus) attribs->klass = vInfo->c_class; #else attribs->klass = vInfo->class; #endif attribs->depth = vInfo->depth; attribs->redMask = vInfo->red_mask; attribs->greenMask = vInfo->green_mask; attribs->blueMask = vInfo->blue_mask; attribs->colormapSize = vInfo->colormap_size; attribs->bitsPerRGB = vInfo->bits_per_rgb; if (glXGetConfig(dpy, vInfo, GLX_USE_GL, &attribs->supportsGL) != 0) return; glXGetConfig(dpy, vInfo, GLX_BUFFER_SIZE, &attribs->bufferSize); glXGetConfig(dpy, vInfo, GLX_LEVEL, &attribs->level); glXGetConfig(dpy, vInfo, GLX_RGBA, &attribs->rgba); glXGetConfig(dpy, vInfo, GLX_DOUBLEBUFFER, &attribs->doubleBuffer); glXGetConfig(dpy, vInfo, GLX_STEREO, &attribs->stereo); glXGetConfig(dpy, vInfo, GLX_AUX_BUFFERS, &attribs->auxBuffers); glXGetConfig(dpy, vInfo, GLX_RED_SIZE, &attribs->redSize); glXGetConfig(dpy, vInfo, GLX_GREEN_SIZE, &attribs->greenSize); glXGetConfig(dpy, vInfo, GLX_BLUE_SIZE, &attribs->blueSize); glXGetConfig(dpy, vInfo, GLX_ALPHA_SIZE, &attribs->alphaSize); glXGetConfig(dpy, vInfo, GLX_DEPTH_SIZE, &attribs->depthSize); glXGetConfig(dpy, vInfo, GLX_STENCIL_SIZE, &attribs->stencilSize); glXGetConfig(dpy, vInfo, GLX_ACCUM_RED_SIZE, &attribs->accumRedSize); glXGetConfig(dpy, vInfo, GLX_ACCUM_GREEN_SIZE, &attribs->accumGreenSize); glXGetConfig(dpy, vInfo, GLX_ACCUM_BLUE_SIZE, &attribs->accumBlueSize); glXGetConfig(dpy, vInfo, GLX_ACCUM_ALPHA_SIZE, &attribs->accumAlphaSize); /* get transparent pixel stuff */ glXGetConfig(dpy, vInfo,GLX_TRANSPARENT_TYPE, &attribs->transparentType); if (attribs->transparentType == GLX_TRANSPARENT_RGB) { glXGetConfig(dpy, vInfo, GLX_TRANSPARENT_RED_VALUE, &attribs->transparentRedValue); glXGetConfig(dpy, vInfo, GLX_TRANSPARENT_GREEN_VALUE, &attribs->transparentGreenValue); glXGetConfig(dpy, vInfo, GLX_TRANSPARENT_BLUE_VALUE, &attribs->transparentBlueValue); glXGetConfig(dpy, vInfo, GLX_TRANSPARENT_ALPHA_VALUE, &attribs->transparentAlphaValue); } else if (attribs->transparentType == GLX_TRANSPARENT_INDEX) { glXGetConfig(dpy, vInfo, GLX_TRANSPARENT_INDEX_VALUE, &attribs->transparentIndexValue); } /* multisample attribs */ #ifdef GLX_ARB_multisample if (strstr("GLX_ARB_multisample", ext) == 0) { glXGetConfig(dpy, vInfo, GLX_SAMPLE_BUFFERS_ARB, &attribs->numMultisample); glXGetConfig(dpy, vInfo, GLX_SAMPLES_ARB, &attribs->numSamples); } #endif else { attribs->numSamples = 0; attribs->numMultisample = 0; } #if defined(GLX_EXT_visual_rating) if (ext && strstr(ext, "GLX_EXT_visual_rating")) { glXGetConfig(dpy, vInfo, GLX_VISUAL_CAVEAT_EXT, &attribs->visualCaveat); } else { attribs->visualCaveat = GLX_NONE_EXT; } #else attribs->visualCaveat = 0; #endif }
GLFWvidmode* _glfwPlatformGetVideoModes(int* found) { XVisualInfo* visuals; XVisualInfo dummy; int i, j, visualCount, sizeCount, rgbCount; int* rgbs; _GLFWvidsize* sizes; GLFWvidmode* result; visuals = XGetVisualInfo(_glfwLibrary.X11.display, 0, &dummy, &visualCount); if (visuals == NULL) { _glfwSetError(GLFW_PLATFORM_ERROR, "X11/GLX: Failed to retrieve the available visuals"); return 0; } // Build array of available RGB channel depths rgbs = (int*) malloc(sizeof(int) * visualCount); rgbCount = 0; for (i = 0; i < visualCount; i++) { int gl, rgba, rgb, r, g, b; glXGetConfig(_glfwLibrary.X11.display, &visuals[i], GLX_USE_GL, &gl); glXGetConfig(_glfwLibrary.X11.display, &visuals[i], GLX_RGBA, &rgba); if (!gl || !rgba) { // The visual lacks OpenGL or true color, so skip it continue; } // Convert to RGB channel depths and encode _glfwSplitBPP(visuals[i].depth, &r, &g, &b); rgb = (r << 16) | (g << 8) | b; for (j = 0; j < rgbCount; j++) { if (rgbs[j] == rgb) break; } if (j < rgbCount) { // This channel depth is a duplicate, so skip it continue; } rgbs[rgbCount] = rgb; rgbCount++; } XFree(visuals); // Build all permutations of channel depths and resolutions sizes = getResolutions(&sizeCount); result = (GLFWvidmode*) malloc(sizeof(GLFWvidmode) * rgbCount * sizeCount); *found = 0; for (i = 0; i < rgbCount; i++) { for (j = 0; j < sizeCount; j++) { result[*found].width = sizes[j].width; result[*found].height = sizes[j].height; result[*found].redBits = (rgbs[i] >> 16) & 255; result[*found].greenBits = (rgbs[i] >> 8) & 255; result[*found].blueBits = rgbs[i] & 255; (*found)++; } } free(sizes); free(rgbs); return result; }
static void visualAttribs( Display * dpy, XVisualInfo * vi, VisualAttribs * attribs ) { memset( attribs, 0, sizeof( VisualAttribs ) ); attribs->id = vi->visualid; attribs->c_class = vi->c_class; attribs->depth = vi->depth; attribs->redMask = vi->red_mask; attribs->greenMask = vi->green_mask; attribs->blueMask = vi->blue_mask; attribs->colormapSize = vi->colormap_size; attribs->bitsPerRGB = vi->bits_per_rgb; if ( glXGetConfig( dpy, vi, GLX_USE_GL, &attribs->supportsGL ) != 0 ) return; attribs->accumAlphaSize = 0; glXGetConfig( dpy, vi, GLX_BUFFER_SIZE, &attribs->bufferSize ); glXGetConfig( dpy, vi, GLX_LEVEL, &attribs->level ); glXGetConfig( dpy, vi, GLX_RGBA, &attribs->rgba ); glXGetConfig( dpy, vi, GLX_DOUBLEBUFFER, &attribs->doubleBuffer ); glXGetConfig( dpy, vi, GLX_STEREO, &attribs->stereo ); glXGetConfig( dpy, vi, GLX_AUX_BUFFERS, &attribs->auxBuffers ); glXGetConfig( dpy, vi, GLX_RED_SIZE, &attribs->redSize ); glXGetConfig( dpy, vi, GLX_GREEN_SIZE, &attribs->greenSize ); glXGetConfig( dpy, vi, GLX_BLUE_SIZE, &attribs->blueSize ); glXGetConfig( dpy, vi, GLX_ALPHA_SIZE, &attribs->alphaSize ); glXGetConfig( dpy, vi, GLX_DEPTH_SIZE, &attribs->depthSize ); glXGetConfig( dpy, vi, GLX_STENCIL_SIZE, &attribs->stencilSize ); glXGetConfig( dpy, vi, GLX_ACCUM_RED_SIZE, &attribs->accumRedSize ); glXGetConfig( dpy, vi, GLX_ACCUM_GREEN_SIZE, &attribs->accumGreenSize ); glXGetConfig( dpy, vi, GLX_ACCUM_BLUE_SIZE, &attribs->accumBlueSize ); glXGetConfig( dpy, vi, GLX_ACCUM_ALPHA_SIZE, &attribs->accumAlphaSize ); attribs->transparent = 0; // transparent pixel missing attribs->numSamples = 0; // multisample tests missing attribs->numMultisample = 0; #if defined(GLX_EXT_visual_rating) const char *ext = glXQueryExtensionsString( dpy, vi->screen ); if ( ext && strstr( ext, "GLX_EXT_visual_rating" ) ) glXGetConfig(dpy, vi, GLX_VISUAL_CAVEAT_EXT, &attribs->visualCaveat); else attribs->visualCaveat = GLX_NONE_EXT; #else attribs->visualCaveat = 0; #endif }
//-------------------------------------------------------------- // initialize graphics BOOL mgLinuxGL21Support::initDisplay() { mgDebug("------ try to create OpenGL 2.1 context, fullscreen=%s, multiSample=%s", m_fullscreen?"true":"false", m_multiSample?"true":"false"); mgLinuxServices* system = (mgLinuxServices*) mgPlatform; // =-= some drivers are failing this test. not clear we need it #ifdef WORKED int glxMajor, glxMinor; glXQueryVersion(system->m_display, &glxMajor, &glxMinor); mgDebug("GLX version = %d.%d", glxMajor, glxMinor); int glxVersion = glxMajor * 100 + glxMinor; if (glxVersion < 103) { mgDebug("GLX version < 1.3"); termDisplay(); return false; } #endif system->m_glrc = glXCreateContext(system->m_display, system->m_vi, NULL, true); if (system->m_glrc == NULL) { mgDebug("Could not glXCreateContext"); termDisplay(); return false; } glXMakeCurrent(system->m_display, system->m_window, system->m_glrc); m_depthBits = 16; // default glXGetConfig(system->m_display, system->m_vi, GLX_DEPTH_SIZE, &m_depthBits); mgDebug("%d depth bits", m_depthBits); // get the extension list again now that we have chosen driver GLenum err = glewInit(); if (err != GLEW_OK) { mgDebug("Cannot initialize OpenGL - glewInit failed."); termDisplay(); return false; } mgString errorMsg; if (!checkVersion(201, 102, errorMsg)) { mgDebug("%s", (const char*) errorMsg); termDisplay(); return false; } if (m_swapImmediate) { PFNGLXSWAPINTERVALMESAPROC fnSwapIntervalMESA = (PFNGLXSWAPINTERVALMESAPROC)glXGetProcAddress((const GLubyte*) "glXSwapIntervalMESA"); if (fnSwapIntervalMESA != NULL) (*fnSwapIntervalMESA) (0); else { PFNGLXSWAPINTERVALSGIPROC fnSwapIntervalSGI = (PFNGLXSWAPINTERVALSGIPROC)glXGetProcAddress((const GLubyte*) "glXSwapIntervalSGI"); if (fnSwapIntervalSGI != NULL) (*fnSwapIntervalSGI) (0); else mgDebug("Cannot find glXSwapInterval"); } } if (system->getMultiSample()) glEnable(GL_MULTISAMPLE); // compile the overlay shader mgDebug("compile overlay shader:"); const char* attrNames[] = {"vertPoint", "vertTexCoord0"}; const DWORD attrIndexes[] = {0, 1}; m_overlayShader = compileShaderPair(GL21_OVERLAY_VERTEX_SHADER, GL21_OVERLAY_FRAGMENT_SHADER, 2, attrNames, attrIndexes); return true; }
bool fxwt::init_graphics(GraphicsInitParameters *gparams) { Display *dpy; Window win; info("Initializing GLX"); if(!(dpy = XOpenDisplay(0))) { error("Could not connect to the X server"); return false; } int screen = DefaultScreen(dpy); Window root_win = RootWindow(dpy, screen); info("Trying to set video mode %dx%dx%d, d:%d s:%d %s", gparams->x, gparams->y, gparams->bpp, gparams->depth_bits, gparams->stencil_bits, gparams->fullscreen ? "fullscreen" : "windowed"); // determine color bits int color_bits = 1; if(!(gparams->dont_care_flags & DONT_CARE_BPP)) { switch(gparams->bpp) { case 32: case 24: color_bits = 8; break; case 16: case 15: color_bits = 5; break; case 12: color_bits = 4; break; default: error("%s: Tried to set unsupported pixel format: %d bpp", __func__, gparams->bpp); } } // determine stencil bits int stencil_bits = gparams->stencil_bits; if(gparams->dont_care_flags & DONT_CARE_STENCIL) { stencil_bits = 1; } // determine zbuffer bits int zbits = gparams->depth_bits == 32 ? 24 : gparams->depth_bits; if(gparams->dont_care_flags & DONT_CARE_BPP) { zbits = 1; } int glx_attrib[] = { GLX_RGBA, GLX_DOUBLEBUFFER, GLX_RED_SIZE, color_bits, GLX_GREEN_SIZE, color_bits, GLX_BLUE_SIZE, color_bits, GLX_DEPTH_SIZE, zbits, GLX_STENCIL_SIZE, stencil_bits, None }; XVisualInfo *vis_info; if(!(vis_info = glXChooseVisual(dpy, screen, glx_attrib))) { error("%s: Could not set requested video mode", __func__); XCloseDisplay(dpy); return false; } // check the video mode we got int arbits, agbits, abbits, azbits, astencilbits; glXGetConfig(dpy, vis_info, GLX_RED_SIZE, &arbits); glXGetConfig(dpy, vis_info, GLX_GREEN_SIZE, &agbits); glXGetConfig(dpy, vis_info, GLX_BLUE_SIZE, &abbits); glXGetConfig(dpy, vis_info, GLX_DEPTH_SIZE, &azbits); glXGetConfig(dpy, vis_info, GLX_STENCIL_SIZE, &astencilbits); info("Initialized video mode:"); info(" bpp: %d (%d%d%d)", arbits + agbits + abbits, arbits, agbits, abbits); info("zbuffer: %d", azbits); info("stencil: %d", astencilbits); /* if the dont_care_flags does not contain DONT_CARE_BPP and our color bits * does not match, we should return failure, however we test against * the difference allowing a +/-1 difference in order to allow for 16bpp * formats of either 565 or 555 and consider them equal. */ if(!(gparams->dont_care_flags & DONT_CARE_BPP) && abs(arbits - color_bits) > 1 && abs(agbits - color_bits) > 1 && abs(abbits - color_bits) > 1) { error("%s: Could not set requested exact bpp mode", __func__); XFree(vis_info); XCloseDisplay(dpy); return false; } // now if we don't have DONT_CARE_DEPTH in the dont_care_flags check for // exact depth buffer format, however consider 24 and 32 bit the same if(!(gparams->dont_care_flags & DONT_CARE_DEPTH) && azbits != zbits) { if(!(zbits == 32 && azbits == 24 || zbits == 24 && azbits == 32)) { error("%s: Could not set requested exact zbuffer depth", __func__); XFree(vis_info); XCloseDisplay(dpy); return false; } } // if we don't have DONT_CARE_STENCIL make sure we have the stencil format // that was asked. if(!(gparams->dont_care_flags & DONT_CARE_STENCIL) && astencilbits != gparams->stencil_bits) { error("%s: Could not set exact stencil format", __func__); XFree(vis_info); XCloseDisplay(dpy); return false; } // everything is ok, create the context if(!(glx_ctx = glXCreateContext(dpy, vis_info, 0, True))) { error("%s: Failed to create GLX context", __func__); XFree(vis_info); XCloseDisplay(dpy); return false; } XSetWindowAttributes xattr; xattr.background_pixel = xattr.border_pixel = BlackPixel(dpy, screen); xattr.colormap = XCreateColormap(dpy, root_win, vis_info->visual, AllocNone); if(gparams->fullscreen) { // TODO: also test for "XFree86-VidModeExtension" #ifdef USE_XF86VIDMODE info("Using XF86VidMode extension for fullscreen resolution switch."); XF86VidModeModeInfo **modes; XF86VidModeModeInfo *vid_mode = 0; int mode_count; XF86VidModeGetAllModeLines(dpy, screen, &mode_count, &modes); orig_mode = *modes[0]; for(int i=0; i<mode_count; i++) { if(modes[i]->hdisplay == gparams->x && modes[i]->vdisplay == gparams->y) { vid_mode = modes[i]; } } if(!vid_mode) { error("Could not set requested video mode"); XFree(modes); XFree(vis_info); XCloseDisplay(dpy); return -1; } XF86VidModeSwitchToMode(dpy, screen, vid_mode); XF86VidModeSetViewPort(dpy, screen, 0, 0); XFree(modes); xattr.override_redirect = True; win = XCreateWindow(dpy, root_win, 0, 0, gparams->x, gparams->y, 0, vis_info->depth, InputOutput, vis_info->visual, CWColormap | CWBackPixel | CWBorderPixel | CWOverrideRedirect, &xattr); XWarpPointer(dpy, None, win, 0, 0, 0, 0, 0, 0); XMapRaised(dpy, win); XGrabKeyboard(dpy, win, True, GrabModeAsync, GrabModeAsync, CurrentTime); XGrabPointer(dpy, win, True, ButtonPressMask, GrabModeAsync, GrabModeAsync, win, None, CurrentTime); #else info("Resolution switching is not compiled or not supported by the X server, using a full-screen window."); XWindowAttributes root_attr; XGetWindowAttributes(dpy, root_win, &root_attr); gparams->x = root_attr.width; gparams->y = root_attr.height; xattr.override_redirect = True; win = XCreateWindow(dpy, root_win, 0, 0, gparams->x, gparams->y, 0, vis_info->depth, InputOutput, vis_info->visual, CWColormap | CWBackPixel | CWBorderPixel | CWOverrideRedirect, &xattr); XWarpPointer(dpy, None, win, 0, 0, 0, 0, 0, 0); XMapRaised(dpy, win); XGrabKeyboard(dpy, win, True, GrabModeAsync, GrabModeAsync, CurrentTime); XGrabPointer(dpy, win, True, ButtonPressMask, GrabModeAsync, GrabModeAsync, win, None, CurrentTime); #endif // USE_XF86VIDMODE fullscreen = true; } else { win = XCreateWindow(dpy, root_win, 0, 0, gparams->x, gparams->y, 0, vis_info->depth, InputOutput, vis_info->visual, CWColormap | CWBackPixel | CWBorderPixel, &xattr); } long events = ExposureMask | StructureNotifyMask | KeyPressMask; // expose and key events events |= ButtonPressMask | ButtonReleaseMask | PointerMotionMask; // mouse events XSelectInput(dpy, win, events); // set WM cooperation settings Atom wm_delete = XInternAtom(dpy, "WM_DELETE_WINDOW", True); XSetWMProtocols(dpy, win, &wm_delete, 1); XTextProperty tp_wname; static char *win_title = "3dengfx/X"; XStringListToTextProperty(&win_title, 1, &tp_wname); XSetWMName(dpy, win, &tp_wname); XFree(tp_wname.value); XClassHint class_hint; class_hint.res_name = "3dengfx"; class_hint.res_class = "3dengfx_graphics"; XSetClassHint(dpy, win, &class_hint); XFree(vis_info); if(glXMakeCurrent(dpy, win, glx_ctx) == False) { error("%s: Failed to make the GLX context current", __func__); glXDestroyContext(dpy, glx_ctx); XDestroyWindow(dpy, win); XCloseDisplay(dpy); return false; } if(!glXIsDirect(dpy, glx_ctx)) { warning("using indirect rendering, which might be slow..."); } XMapWindow(dpy, win); XFlush(dpy); fxwt_x_dpy = dpy; fxwt_x_win = win; return true; }
const GrGLInterface* SkNativeGLContext::createGLContext() { fDisplay = XOpenDisplay(0); if (!fDisplay) { SkDebugf("Failed to open X display.\n"); this->destroyGLContext(); return NULL; } // Get a matching FB config static int visual_attribs[] = { GLX_X_RENDERABLE , True, GLX_DRAWABLE_TYPE , GLX_PIXMAP_BIT, None }; #ifdef GLX_1_3 //SkDebugf("Getting matching framebuffer configs.\n"); int fbcount; GLXFBConfig *fbc = glXChooseFBConfig(fDisplay, DefaultScreen(fDisplay), visual_attribs, &fbcount); if (!fbc) { SkDebugf("Failed to retrieve a framebuffer config.\n"); this->destroyGLContext(); return NULL; } //SkDebugf("Found %d matching FB configs.\n", fbcount); // Pick the FB config/visual with the most samples per pixel //SkDebugf("Getting XVisualInfos.\n"); int best_fbc = -1, best_num_samp = -1; int i; for (i = 0; i < fbcount; ++i) { XVisualInfo *vi = glXGetVisualFromFBConfig(fDisplay, fbc[i]); if (vi) { int samp_buf, samples; glXGetFBConfigAttrib(fDisplay, fbc[i], GLX_SAMPLE_BUFFERS, &samp_buf); glXGetFBConfigAttrib(fDisplay, fbc[i], GLX_SAMPLES, &samples); //SkDebugf(" Matching fbconfig %d, visual ID 0x%2x: SAMPLE_BUFFERS = %d," // " SAMPLES = %d\n", // i, (unsigned int)vi->visualid, samp_buf, samples); if (best_fbc < 0 || (samp_buf && samples > best_num_samp)) best_fbc = i, best_num_samp = samples; } XFree(vi); } GLXFBConfig bestFbc = fbc[best_fbc]; // Be sure to free the FBConfig list allocated by glXChooseFBConfig() XFree(fbc); // Get a visual XVisualInfo *vi = glXGetVisualFromFBConfig(fDisplay, bestFbc); //SkDebugf("Chosen visual ID = 0x%x\n", (unsigned int)vi->visualid); #else int numVisuals; XVisualInfo visTemplate, *visReturn; visReturn = XGetVisualInfo(fDisplay, VisualNoMask, &visTemplate, &numVisuals); if (NULL == visReturn) { SkDebugf("Failed to get visual information.\n"); this->destroyGLContext(); return NULL; } int best = -1, best_num_samp = -1; for (int i = 0; i < numVisuals; ++i) { int samp_buf, samples; glXGetConfig(fDisplay, &visReturn[i], GLX_SAMPLE_BUFFERS, &samp_buf); glXGetConfig(fDisplay, &visReturn[i], GLX_SAMPLES, &samples); if (best < 0 || (samp_buf && samples > best_num_samp)) best = i, best_num_samp = samples; } XVisualInfo temp = visReturn[best]; XVisualInfo *vi = &temp; XFree(visReturn); #endif fPixmap = XCreatePixmap(fDisplay, RootWindow(fDisplay, vi->screen), 10, 10, vi->depth); if (!fPixmap) { SkDebugf("Failed to create pixmap.\n"); this->destroyGLContext(); return NULL; } fGlxPixmap = glXCreateGLXPixmap(fDisplay, vi, fPixmap); #ifdef GLX_1_3 // Done with the visual info data XFree(vi); #endif // Create the context // Install an X error handler so the application won't exit if GL 3.0 // context allocation fails. // // Note this error handler is global. // All display connections in all threads of a process use the same // error handler, so be sure to guard against other threads issuing // X commands while this code is running. ctxErrorOccurred = false; int (*oldHandler)(Display*, XErrorEvent*) = XSetErrorHandler(&ctxErrorHandler); // Get the default screen's GLX extension list const char *glxExts = glXQueryExtensionsString( fDisplay, DefaultScreen(fDisplay) ); // Check for the GLX_ARB_create_context extension string and the function. // If either is not present, use GLX 1.3 context creation method. if (!gluCheckExtension( reinterpret_cast<const GLubyte*>("GLX_ARB_create_context") , reinterpret_cast<const GLubyte*>(glxExts))) { //SkDebugf("GLX_ARB_create_context not found." // " Using old-style GLX context.\n"); #ifdef GLX_1_3 fContext = glXCreateNewContext(fDisplay, bestFbc, GLX_RGBA_TYPE, 0, True); #else fContext = glXCreateContext(fDisplay, vi, 0, True); #endif } #ifdef GLX_1_3 else { //SkDebugf("Creating context.\n"); PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB = (PFNGLXCREATECONTEXTATTRIBSARBPROC) glXGetProcAddressARB((GrGLubyte*)"glXCreateContextAttribsARB"); int context_attribs[] = { GLX_CONTEXT_MAJOR_VERSION_ARB, 3, GLX_CONTEXT_MINOR_VERSION_ARB, 0, //GLX_CONTEXT_FLAGS_ARB , GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, None }; fContext = glXCreateContextAttribsARB( fDisplay, bestFbc, 0, True, context_attribs ); // Sync to ensure any errors generated are processed. XSync(fDisplay, False); if (!ctxErrorOccurred && fContext) { //SkDebugf( "Created GL 3.0 context.\n" ); } else { // Couldn't create GL 3.0 context. // Fall back to old-style 2.x context. // When a context version below 3.0 is requested, // implementations will return the newest context version compatible // with OpenGL versions less than version 3.0. // GLX_CONTEXT_MAJOR_VERSION_ARB = 1 context_attribs[1] = 1; // GLX_CONTEXT_MINOR_VERSION_ARB = 0 context_attribs[3] = 0; ctxErrorOccurred = false; //SkDebugf("Failed to create GL 3.0 context." // " Using old-style GLX context.\n"); fContext = glXCreateContextAttribsARB( fDisplay, bestFbc, 0, True, context_attribs ); } } #endif // Sync to ensure any errors generated are processed. XSync(fDisplay, False); // Restore the original error handler XSetErrorHandler(oldHandler); if (ctxErrorOccurred || !fContext) { SkDebugf("Failed to create an OpenGL context.\n"); this->destroyGLContext(); return NULL; } // Verify that context is a direct context if (!glXIsDirect(fDisplay, fContext)) { //SkDebugf("Indirect GLX rendering context obtained.\n"); } else { //SkDebugf("Direct GLX rendering context obtained.\n"); } //SkDebugf("Making context current.\n"); if (!glXMakeCurrent(fDisplay, fGlxPixmap, fContext)) { SkDebugf("Could not set the context.\n"); this->destroyGLContext(); return NULL; } const GrGLInterface* interface = GrGLCreateNativeInterface(); if (!interface) { SkDebugf("Failed to create gl interface"); this->destroyGLContext(); return NULL; } return interface; }
bool QGLContext::chooseContext( const QGLContext* shareContext ) { Display* disp = d->paintDevice->x11Display(); vi = chooseVisual(); if ( !vi ) return FALSE; if ( deviceIsPixmap() && (((XVisualInfo*)vi)->depth != d->paintDevice->x11Depth() || ((XVisualInfo*)vi)->screen != d->paintDevice->x11Screen()) ) { XFree( vi ); XVisualInfo appVisInfo; memset( &appVisInfo, 0, sizeof(XVisualInfo) ); appVisInfo.visualid = XVisualIDFromVisual( (Visual*)d->paintDevice->x11Visual() ); appVisInfo.screen = d->paintDevice->x11Screen(); int nvis; vi = XGetVisualInfo( disp, VisualIDMask | VisualScreenMask, &appVisInfo, &nvis ); if ( !vi ) return FALSE; int useGL; glXGetConfig( disp, (XVisualInfo*)vi, GLX_USE_GL, &useGL ); if ( !useGL ) return FALSE; //# Chickening out already... } int res; glXGetConfig( disp, (XVisualInfo*)vi, GLX_LEVEL, &res ); glFormat.setPlane( res ); glXGetConfig( disp, (XVisualInfo*)vi, GLX_DOUBLEBUFFER, &res ); glFormat.setDoubleBuffer( res ); glXGetConfig( disp, (XVisualInfo*)vi, GLX_DEPTH_SIZE, &res ); glFormat.setDepth( res ); glXGetConfig( disp, (XVisualInfo*)vi, GLX_RGBA, &res ); glFormat.setRgba( res ); glXGetConfig( disp, (XVisualInfo*)vi, GLX_ALPHA_SIZE, &res ); glFormat.setAlpha( res ); glXGetConfig( disp, (XVisualInfo*)vi, GLX_ACCUM_RED_SIZE, &res ); glFormat.setAccum( res ); glXGetConfig( disp, (XVisualInfo*)vi, GLX_STENCIL_SIZE, &res ); glFormat.setStencil( res ); glXGetConfig( disp, (XVisualInfo*)vi, GLX_STEREO, &res ); glFormat.setStereo( res ); Bool direct = format().directRendering() ? True : False; if ( shareContext && ( !shareContext->isValid() || !shareContext->cx ) ) { #if defined(QT_CHECK_NULL) qWarning("QGLContext::chooseContext(): Cannot share with invalid context"); #endif shareContext = 0; } // 1. Sharing between rgba and color-index will give wrong colors. // 2. Contexts cannot be shared btw. direct/non-direct renderers. // 3. Pixmaps cannot share contexts that are set up for direct rendering. if ( shareContext && (format().rgba() != shareContext->format().rgba() || (deviceIsPixmap() && glXIsDirect( disp, (GLXContext)shareContext->cx )))) shareContext = 0; cx = 0; if ( shareContext ) { cx = glXCreateContext( disp, (XVisualInfo *)vi, (GLXContext)shareContext->cx, direct ); if ( cx ) d->sharing = TRUE; } if ( !cx ) cx = glXCreateContext( disp, (XVisualInfo *)vi, None, direct ); if ( !cx ) return FALSE; glFormat.setDirectRendering( glXIsDirect( disp, (GLXContext)cx ) ); if ( deviceIsPixmap() ) { #if defined(GLX_MESA_pixmap_colormap) && defined(QGL_USE_MESA_EXT) gpm = glXCreateGLXPixmapMESA( disp, (XVisualInfo *)vi, d->paintDevice->handle(), choose_cmap( disp, (XVisualInfo *)vi ) ); #else gpm = (Q_UINT32)glXCreateGLXPixmap( disp, (XVisualInfo *)vi, d->paintDevice->handle() ); #endif if ( !gpm ) return FALSE; } return TRUE; }
void GlxContext::createContext(GlxContext* shared, unsigned int bitsPerPixel, const ContextSettings& settings) { // Save the creation settings m_settings = settings; // Get the attributes of the target window XWindowAttributes windowAttributes; if (XGetWindowAttributes(m_display, m_window, &windowAttributes) == 0) { err() << "Failed to get the window attributes" << std::endl; return; } // Setup the visual infos to match XVisualInfo tpl; tpl.depth = windowAttributes.depth; tpl.visualid = XVisualIDFromVisual(windowAttributes.visual); tpl.screen = DefaultScreen(m_display); // Get all the visuals matching the template int nbVisuals = 0; XVisualInfo* visuals = XGetVisualInfo(m_display, VisualDepthMask | VisualIDMask | VisualScreenMask, &tpl, &nbVisuals); if (!visuals || (nbVisuals == 0)) { if (visuals) XFree(visuals); err() << "There is no valid visual for the selected screen" << std::endl; return; } // Find the best visual int bestScore = 0xFFFF; XVisualInfo* bestVisual = NULL; for (int i = 0; i < nbVisuals; ++i) { // Get the current visual attributes int RGBA, doubleBuffer, red, green, blue, alpha, depth, stencil, multiSampling, samples; glXGetConfig(m_display, &visuals[i], GLX_RGBA, &RGBA); glXGetConfig(m_display, &visuals[i], GLX_DOUBLEBUFFER, &doubleBuffer); glXGetConfig(m_display, &visuals[i], GLX_RED_SIZE, &red); glXGetConfig(m_display, &visuals[i], GLX_GREEN_SIZE, &green); glXGetConfig(m_display, &visuals[i], GLX_BLUE_SIZE, &blue); glXGetConfig(m_display, &visuals[i], GLX_ALPHA_SIZE, &alpha); glXGetConfig(m_display, &visuals[i], GLX_DEPTH_SIZE, &depth); glXGetConfig(m_display, &visuals[i], GLX_STENCIL_SIZE, &stencil); glXGetConfig(m_display, &visuals[i], GLX_SAMPLE_BUFFERS_ARB, &multiSampling); glXGetConfig(m_display, &visuals[i], GLX_SAMPLES_ARB, &samples); // First check the mandatory parameters if ((RGBA == 0) || (doubleBuffer == 0)) continue; // Evaluate the current configuration int color = red + green + blue + alpha; int score = evaluateFormat(bitsPerPixel, m_settings, color, depth, stencil, multiSampling ? samples : 0); // Keep it if it's better than the current best if (score < bestScore) { bestScore = score; bestVisual = &visuals[i]; } } // Make sure that we have found a visual if (!bestVisual) { err() << "Failed to find a suitable pixel format for the window -- cannot create OpenGL context" << std::endl; return; } // Get the context to share display lists with GLXContext toShare = shared ? shared->m_context : NULL; // Create the OpenGL context -- first try context versions >= 3.0 if it is requested (they require special code) while (!m_context && (m_settings.majorVersion >= 3)) { const GLubyte* name = reinterpret_cast<const GLubyte*>("glXCreateContextAttribsARB"); PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB = reinterpret_cast<PFNGLXCREATECONTEXTATTRIBSARBPROC>(glXGetProcAddress(name)); if (glXCreateContextAttribsARB) { int nbConfigs = 0; GLXFBConfig* configs = glXChooseFBConfig(m_display, DefaultScreen(m_display), NULL, &nbConfigs); if (configs && nbConfigs) { // Create the context int attributes[] = { GLX_CONTEXT_MAJOR_VERSION_ARB, static_cast<int>(m_settings.majorVersion), GLX_CONTEXT_MINOR_VERSION_ARB, static_cast<int>(m_settings.minorVersion), GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, 0, 0 }; m_context = glXCreateContextAttribsARB(m_display, configs[0], toShare, true, attributes); } if (configs) XFree(configs); } // If we couldn't create the context, lower the version number and try again -- stop at 3.0 // Invalid version numbers will be generated by this algorithm (like 3.9), but we really don't care if (!m_context) { if (m_settings.minorVersion > 0) { // If the minor version is not 0, we decrease it and try again m_settings.minorVersion--; } else { // If the minor version is 0, we decrease the major version m_settings.majorVersion--; m_settings.minorVersion = 9; } } } // If the OpenGL >= 3.0 context failed or if we don't want one, create a regular OpenGL 1.x/2.x context if (!m_context) { // set the context version to 2.0 (arbitrary) m_settings.majorVersion = 2; m_settings.minorVersion = 0; m_context = glXCreateContext(m_display, bestVisual, toShare, true); if (!m_context) { err() << "Failed to create an OpenGL context for this window" << std::endl; return; } } // Update the creation settings from the chosen format int depth, stencil, multiSampling, samples; glXGetConfig(m_display, bestVisual, GLX_DEPTH_SIZE, &depth); glXGetConfig(m_display, bestVisual, GLX_STENCIL_SIZE, &stencil); glXGetConfig(m_display, bestVisual, GLX_SAMPLE_BUFFERS_ARB, &multiSampling); glXGetConfig(m_display, bestVisual, GLX_SAMPLES_ARB, &samples); m_settings.depthBits = static_cast<unsigned int>(depth); m_settings.stencilBits = static_cast<unsigned int>(stencil); m_settings.antialiasingLevel = multiSampling ? samples : 0; // Change the target window's colormap so that it matches the context's one ::Window root = RootWindow(m_display, DefaultScreen(m_display)); Colormap colorMap = XCreateColormap(m_display, root, bestVisual->visual, AllocNone); XSetWindowColormap(m_display, m_window, colorMap); // Free the temporary visuals array XFree(visuals); }
void SkOSWindow::initWindow(int requestedMSAASampleCount, AttachmentInfo* info) { if (fMSAASampleCount != requestedMSAASampleCount) { this->closeWindow(); } // presence of fDisplay means we already have a window if (NULL != fUnixWindow.fDisplay) { if (NULL != info) { if (NULL != fVi) { glXGetConfig(fUnixWindow.fDisplay, fVi, GLX_SAMPLES_ARB, &info->fSampleCount); glXGetConfig(fUnixWindow.fDisplay, fVi, GLX_STENCIL_SIZE, &info->fStencilBits); } else { info->fSampleCount = 0; info->fStencilBits = 0; } } return; } fUnixWindow.fDisplay = XOpenDisplay(NULL); Display* dsp = fUnixWindow.fDisplay; if (NULL == dsp) { SkDebugf("Could not open an X Display"); return; } // Attempt to create a window that supports GL GLint att[] = { GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER, GLX_STENCIL_SIZE, 8, None }; SkASSERT(NULL == fVi); if (requestedMSAASampleCount > 0) { static const GLint kAttCount = SK_ARRAY_COUNT(att); GLint msaaAtt[kAttCount + 4]; memcpy(msaaAtt, att, sizeof(att)); SkASSERT(None == msaaAtt[kAttCount - 1]); msaaAtt[kAttCount - 1] = GLX_SAMPLE_BUFFERS_ARB; msaaAtt[kAttCount + 0] = 1; msaaAtt[kAttCount + 1] = GLX_SAMPLES_ARB; msaaAtt[kAttCount + 2] = requestedMSAASampleCount; msaaAtt[kAttCount + 3] = None; fVi = glXChooseVisual(dsp, DefaultScreen(dsp), msaaAtt); fMSAASampleCount = requestedMSAASampleCount; } if (NULL == fVi) { fVi = glXChooseVisual(dsp, DefaultScreen(dsp), att); fMSAASampleCount = 0; } if (fVi) { if (NULL != info) { glXGetConfig(dsp, fVi, GLX_SAMPLES_ARB, &info->fSampleCount); glXGetConfig(dsp, fVi, GLX_STENCIL_SIZE, &info->fStencilBits); } Colormap colorMap = XCreateColormap(dsp, RootWindow(dsp, fVi->screen), fVi->visual, AllocNone); XSetWindowAttributes swa; swa.colormap = colorMap; swa.event_mask = EVENT_MASK; fUnixWindow.fWin = XCreateWindow(dsp, RootWindow(dsp, fVi->screen), 0, 0, // x, y WIDTH, HEIGHT, 0, // border width fVi->depth, InputOutput, fVi->visual, CWEventMask | CWColormap, &swa); } else { if (NULL != info) { info->fSampleCount = 0; info->fStencilBits = 0; } // Create a simple window instead. We will not be able to show GL fUnixWindow.fWin = XCreateSimpleWindow(dsp, DefaultRootWindow(dsp), 0, 0, // x, y WIDTH, HEIGHT, 0, // border width 0, // border value 0); // background value } this->mapWindowAndWait(); fUnixWindow.fGc = XCreateGC(dsp, fUnixWindow.fWin, 0, NULL); }
bool QGLContext::chooseContext(const QGLContext* shareContext) { Q_D(QGLContext); const QX11Info *xinfo = qt_x11Info(d->paintDevice); Display* disp = xinfo->display(); d->vi = chooseVisual(); if (!d->vi) return false; if (deviceIsPixmap() && (((XVisualInfo*)d->vi)->depth != xinfo->depth() || ((XVisualInfo*)d->vi)->screen != xinfo->screen())) { XFree(d->vi); XVisualInfo appVisInfo; memset(&appVisInfo, 0, sizeof(XVisualInfo)); appVisInfo.visualid = XVisualIDFromVisual((Visual *) xinfo->visual()); appVisInfo.screen = xinfo->screen(); int nvis; d->vi = XGetVisualInfo(disp, VisualIDMask | VisualScreenMask, &appVisInfo, &nvis); if (!d->vi) return false; int useGL; glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_USE_GL, &useGL); if (!useGL) return false; //# Chickening out already... } int res; glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_LEVEL, &res); d->glFormat.setPlane(res); glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_DOUBLEBUFFER, &res); d->glFormat.setDoubleBuffer(res); glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_DEPTH_SIZE, &res); d->glFormat.setDepth(res); if (d->glFormat.depth()) d->glFormat.setDepthBufferSize(res); glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_RGBA, &res); d->glFormat.setRgba(res); glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_RED_SIZE, &res); d->glFormat.setRedBufferSize(res); glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_GREEN_SIZE, &res); d->glFormat.setGreenBufferSize(res); glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_BLUE_SIZE, &res); d->glFormat.setBlueBufferSize(res); glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_ALPHA_SIZE, &res); d->glFormat.setAlpha(res); if (d->glFormat.alpha()) d->glFormat.setAlphaBufferSize(res); glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_ACCUM_RED_SIZE, &res); d->glFormat.setAccum(res); if (d->glFormat.accum()) d->glFormat.setAccumBufferSize(res); glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_STENCIL_SIZE, &res); d->glFormat.setStencil(res); if (d->glFormat.stencil()) d->glFormat.setStencilBufferSize(res); glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_STEREO, &res); d->glFormat.setStereo(res); glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_SAMPLE_BUFFERS_ARB, &res); d->glFormat.setSampleBuffers(res); if (d->glFormat.sampleBuffers()) { glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_SAMPLES_ARB, &res); d->glFormat.setSamples(res); } Bool direct = format().directRendering() ? True : False; if (shareContext && (!shareContext->isValid() || !shareContext->d_func()->cx)) { qWarning("QGLContext::chooseContext(): Cannot share with invalid context"); shareContext = 0; } // 1. Sharing between rgba and color-index will give wrong colors. // 2. Contexts cannot be shared btw. direct/non-direct renderers. // 3. Pixmaps cannot share contexts that are set up for direct rendering. // 4. If the contexts are not created on the same screen, they can't be shared if (shareContext && (format().rgba() != shareContext->format().rgba() || (deviceIsPixmap() && glXIsDirect(disp, (GLXContext)shareContext->d_func()->cx)) || (shareContext->d_func()->screen != xinfo->screen()))) { shareContext = 0; } d->cx = 0; if (shareContext) { d->cx = glXCreateContext(disp, (XVisualInfo *)d->vi, (GLXContext)shareContext->d_func()->cx, direct); d->screen = ((XVisualInfo*)d->vi)->screen; if (d->cx) { QGLContext *share = const_cast<QGLContext *>(shareContext); d->sharing = true; share->d_func()->sharing = true; } } if (!d->cx) { d->cx = glXCreateContext(disp, (XVisualInfo *)d->vi, NULL, direct); d->screen = ((XVisualInfo*)d->vi)->screen; } if (!d->cx) return false; d->glFormat.setDirectRendering(glXIsDirect(disp, (GLXContext)d->cx)); if (deviceIsPixmap()) { #if defined(GLX_MESA_pixmap_colormap) && defined(QGL_USE_MESA_EXT) d->gpm = glXCreateGLXPixmapMESA(disp, (XVisualInfo *)d->vi, qt_x11Handle(d->paintDevice), qt_gl_choose_cmap(disp, (XVisualInfo *)d->vi)); #else d->gpm = (quint32)glXCreateGLXPixmap(disp, (XVisualInfo *)d->vi, qt_x11Handle(d->paintDevice)); #endif if (!d->gpm) return false; } QString glxExt = QString(QLatin1String(glXGetClientString(QX11Info::display(), GLX_EXTENSIONS))); if (glxExt.contains(QLatin1String("GLX_SGI_video_sync"))) { if (d->glFormat.swapInterval() == -1) d->glFormat.setSwapInterval(0); } else { d->glFormat.setSwapInterval(-1); } return true; }
bool wxGLCanvas::Create( wxWindow *parent, const wxGLContext *shared, const wxGLCanvas *shared_context_of, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, const wxString& name, int *attribList, const wxPalette& palette) { XVisualInfo *vi, vi_templ; XWindowAttributes xwa; int val, n; m_sharedContext = (wxGLContext*)shared; // const_cast m_sharedContextOf = (wxGLCanvas*)shared_context_of; // const_cast m_glContext = (wxGLContext*) NULL; Display* display = (Display*) wxGetDisplay(); // Check for the presence of the GLX extension if(!glXQueryExtension(display, NULL, NULL)) { wxLogDebug(wxT("wxGLCanvas: GLX extension is missing\n")); return FALSE; } if(attribList) { int data[512], arg=0, p=0; while( (attribList[arg]!=0) && (p<512) ) { switch( attribList[arg++] ) { case WX_GL_RGBA: data[p++] = GLX_RGBA; break; case WX_GL_BUFFER_SIZE: data[p++]=GLX_BUFFER_SIZE; data[p++]=attribList[arg++]; break; case WX_GL_LEVEL: data[p++]=GLX_LEVEL; data[p++]=attribList[arg++]; break; case WX_GL_DOUBLEBUFFER: data[p++] = GLX_DOUBLEBUFFER; break; case WX_GL_STEREO: data[p++] = GLX_STEREO; break; case WX_GL_AUX_BUFFERS: data[p++]=GLX_AUX_BUFFERS; data[p++]=attribList[arg++]; break; case WX_GL_MIN_RED: data[p++]=GLX_RED_SIZE; data[p++]=attribList[arg++]; break; case WX_GL_MIN_GREEN: data[p++]=GLX_GREEN_SIZE; data[p++]=attribList[arg++]; break; case WX_GL_MIN_BLUE: data[p++]=GLX_BLUE_SIZE; data[p++]=attribList[arg++]; break; case WX_GL_MIN_ALPHA: data[p++]=GLX_ALPHA_SIZE; data[p++]=attribList[arg++]; break; case WX_GL_DEPTH_SIZE: data[p++]=GLX_DEPTH_SIZE; data[p++]=attribList[arg++]; break; case WX_GL_STENCIL_SIZE: data[p++]=GLX_STENCIL_SIZE; data[p++]=attribList[arg++]; break; case WX_GL_MIN_ACCUM_RED: data[p++]=GLX_ACCUM_RED_SIZE; data[p++]=attribList[arg++]; break; case WX_GL_MIN_ACCUM_GREEN: data[p++]=GLX_ACCUM_GREEN_SIZE; data[p++]=attribList[arg++]; break; case WX_GL_MIN_ACCUM_BLUE: data[p++]=GLX_ACCUM_BLUE_SIZE; data[p++]=attribList[arg++]; break; case WX_GL_MIN_ACCUM_ALPHA: data[p++]=GLX_ACCUM_ALPHA_SIZE; data[p++]=attribList[arg++]; break; default: break; } } data[p] = 0; attribList = (int*) data; // Get an appropriate visual vi = glXChooseVisual(display, DefaultScreen(display), attribList); if(!vi) return FALSE; // Here we should make sure that vi is the same visual as the // one used by the xwindow drawable in wxCanvas. However, // there is currently no mechanism for this in wx_canvs.cc. } else { // By default, we use the visual of xwindow // NI: is this really senseful ? opengl in e.g. color index mode ? XGetWindowAttributes(display, (Window)wxGetClientAreaWindow(this), &xwa); vi_templ.visualid = XVisualIDFromVisual(xwa.visual); vi = XGetVisualInfo(display, VisualIDMask, &vi_templ, &n); if(!vi) return FALSE; glXGetConfig(display, vi, GLX_USE_GL, &val); if(!val) return FALSE; // Basically, this is it. It should be possible to use vi // in glXCreateContext() below. But this fails with Mesa. // I notified the Mesa author about it; there may be a fix. #ifdef OLD_MESA // Construct an attribute list matching the visual int a_list[32]; n = 0; if(vi->c_class==TrueColor || vi->c_class==DirectColor) { // RGBA visual a_list[n++] = GLX_RGBA; a_list[n++] = GLX_RED_SIZE; a_list[n++] = bitcount(vi->red_mask); a_list[n++] = GLX_GREEN_SIZE; a_list[n++] = bitcount(vi->green_mask); a_list[n++] = GLX_BLUE_SIZE; a_list[n++] = bitcount(vi->blue_mask); glXGetConfig(display, vi, GLX_ALPHA_SIZE, &val); a_list[n++] = GLX_ALPHA_SIZE; a_list[n++] = val; } else { // Color index visual glXGetConfig(display, vi, GLX_BUFFER_SIZE, &val); a_list[n++] = GLX_BUFFER_SIZE; a_list[n++] = val; } a_list[n] = None; // XFree(vi); vi = glXChooseVisual(display, DefaultScreen(display), a_list); if(!vi) return FALSE; #endif /* OLD_MESA */ } m_vi = vi; // safe for later use wxCHECK_MSG( m_vi, FALSE, wxT("required visual couldn't be found") ); // Create the GLX context and make it current wxGLContext *share= m_sharedContext; if (share==NULL && m_sharedContextOf) share = m_sharedContextOf->GetContext(); m_glContext = new wxGLContext( TRUE, this, wxNullPalette, share ); #ifndef OLD_MESA // XFree(vi); #endif SetCurrent(); return TRUE; }
static bool gfx_ctx_glx_set_video_mode(void *data, unsigned width, unsigned height, bool fullscreen) { XEvent event; bool true_full = false, windowed_full; int val, x_off = 0, y_off = 0; XVisualInfo *vi = NULL; XSetWindowAttributes swa = {0}; int (*old_handler)(Display*, XErrorEvent*) = NULL; driver_t *driver = driver_get_ptr(); gfx_ctx_glx_data_t *glx = (gfx_ctx_glx_data_t*)driver->video_context_data; struct sigaction sa = {{0}}; settings_t *settings = config_get_ptr(); sa.sa_handler = glx_sighandler; sa.sa_flags = SA_RESTART; sigemptyset(&sa.sa_mask); sigaction(SIGINT, &sa, NULL); sigaction(SIGTERM, &sa, NULL); if (!glx) return false; windowed_full = settings->video.windowed_fullscreen; true_full = false; vi = glXGetVisualFromFBConfig(glx->g_dpy, glx->g_fbc); if (!vi) goto error; swa.colormap = glx->g_cmap = XCreateColormap(glx->g_dpy, RootWindow(glx->g_dpy, vi->screen), vi->visual, AllocNone); swa.event_mask = StructureNotifyMask | KeyPressMask | KeyReleaseMask | ButtonReleaseMask | ButtonPressMask; swa.override_redirect = fullscreen ? True : False; if (fullscreen && !windowed_full) { if (x11_enter_fullscreen(glx->g_dpy, width, height, &glx->g_desktop_mode)) { glx->g_should_reset_mode = true; true_full = true; } else RARCH_ERR("[GLX]: Entering true fullscreen failed. Will attempt windowed mode.\n"); } if (settings->video.monitor_index) glx->g_screen = settings->video.monitor_index - 1; #ifdef HAVE_XINERAMA if (fullscreen || glx->g_screen != 0) { unsigned new_width = width; unsigned new_height = height; if (x11_get_xinerama_coord(glx->g_dpy, glx->g_screen, &x_off, &y_off, &new_width, &new_height)) RARCH_LOG("[GLX]: Using Xinerama on screen #%u.\n", glx->g_screen); else RARCH_LOG("[GLX]: Xinerama is not active on screen.\n"); if (fullscreen) { width = new_width; height = new_height; } } #endif RARCH_LOG("[GLX]: X = %d, Y = %d, W = %u, H = %u.\n", x_off, y_off, width, height); glx->g_win = XCreateWindow(glx->g_dpy, RootWindow(glx->g_dpy, vi->screen), x_off, y_off, width, height, 0, vi->depth, InputOutput, vi->visual, CWBorderPixel | CWColormap | CWEventMask | (true_full ? CWOverrideRedirect : 0), &swa); XSetWindowBackground(glx->g_dpy, glx->g_win, 0); glx->g_glx_win = glXCreateWindow(glx->g_dpy, glx->g_fbc, glx->g_win, 0); x11_set_window_attr(glx->g_dpy, glx->g_win); if (fullscreen) x11_show_mouse(glx->g_dpy, glx->g_win, false); if (true_full) { RARCH_LOG("[GLX]: Using true fullscreen.\n"); XMapRaised(glx->g_dpy, glx->g_win); } else if (fullscreen) /* We attempted true fullscreen, but failed. Attempt using windowed fullscreen. */ { XMapRaised(glx->g_dpy, glx->g_win); RARCH_LOG("[GLX]: Using windowed fullscreen.\n"); /* We have to move the window to the screen we want to go fullscreen on first. * x_off and y_off usually get ignored in XCreateWindow(). */ x11_move_window(glx->g_dpy, glx->g_win, x_off, y_off, width, height); x11_windowed_fullscreen(glx->g_dpy, glx->g_win); } else { XMapWindow(glx->g_dpy, glx->g_win); // If we want to map the window on a different screen, we'll have to do it by force. // Otherwise, we should try to let the window manager sort it out. // x_off and y_off usually get ignored in XCreateWindow(). if (glx->g_screen) x11_move_window(glx->g_dpy, glx->g_win, x_off, y_off, width, height); } XIfEvent(glx->g_dpy, &event, glx_wait_notify, NULL); if (!glx->g_ctx) { if (glx->g_core_es || glx->g_debug) { int attribs[16]; int *aptr = attribs; if (glx->g_core_es) { *aptr++ = GLX_CONTEXT_MAJOR_VERSION_ARB; *aptr++ = g_major; *aptr++ = GLX_CONTEXT_MINOR_VERSION_ARB; *aptr++ = g_minor; if (glx->g_core_es_core) { /* Technically, we don't have core/compat until 3.2. * Version 3.1 is either compat or not depending on GL_ARB_compatibility. */ *aptr++ = GLX_CONTEXT_PROFILE_MASK_ARB; #ifdef HAVE_OPENGLES2 *aptr++ = GLX_CONTEXT_ES_PROFILE_BIT_EXT; #else *aptr++ = GLX_CONTEXT_CORE_PROFILE_BIT_ARB; #endif } } if (glx->g_debug) { *aptr++ = GLX_CONTEXT_FLAGS_ARB; *aptr++ = GLX_CONTEXT_DEBUG_BIT_ARB; } *aptr = None; glx->g_ctx = glx_create_context_attribs(glx->g_dpy, glx->g_fbc, NULL, True, attribs); if (glx->g_use_hw_ctx) { RARCH_LOG("[GLX]: Creating shared HW context.\n"); glx->g_hw_ctx = glx_create_context_attribs(glx->g_dpy, glx->g_fbc, glx->g_ctx, True, attribs); if (!glx->g_hw_ctx) RARCH_ERR("[GLX]: Failed to create new shared context.\n"); } } else { glx->g_ctx = glXCreateNewContext(glx->g_dpy, glx->g_fbc, GLX_RGBA_TYPE, 0, True); if (glx->g_use_hw_ctx) { glx->g_hw_ctx = glXCreateNewContext(glx->g_dpy, glx->g_fbc, GLX_RGBA_TYPE, glx->g_ctx, True); if (!glx->g_hw_ctx) RARCH_ERR("[GLX]: Failed to create new shared context.\n"); } } if (!glx->g_ctx) { RARCH_ERR("[GLX]: Failed to create new context.\n"); goto error; } } else { driver->video_cache_context_ack = true; RARCH_LOG("[GLX]: Using cached GL context.\n"); } glXMakeContextCurrent(glx->g_dpy, glx->g_glx_win, glx->g_glx_win, glx->g_ctx); XSync(glx->g_dpy, False); g_quit_atom = XInternAtom(glx->g_dpy, "WM_DELETE_WINDOW", False); if (g_quit_atom) XSetWMProtocols(glx->g_dpy, glx->g_win, &g_quit_atom, 1); glXGetConfig(glx->g_dpy, vi, GLX_DOUBLEBUFFER, &val); glx->g_is_double = val; if (glx->g_is_double) { const char *swap_func = NULL; g_pglSwapIntervalEXT = (void (*)(Display*, GLXDrawable, int))glXGetProcAddress((const GLubyte*)"glXSwapIntervalEXT"); g_pglSwapIntervalSGI = (int (*)(int))glXGetProcAddress((const GLubyte*)"glXSwapIntervalSGI"); g_pglSwapInterval = (int (*)(int))glXGetProcAddress((const GLubyte*)"glXSwapIntervalMESA"); if (g_pglSwapIntervalEXT) swap_func = "glXSwapIntervalEXT"; else if (g_pglSwapInterval) swap_func = "glXSwapIntervalMESA"; else if (g_pglSwapIntervalSGI) swap_func = "glXSwapIntervalSGI"; if (!g_pglSwapInterval && !g_pglSwapIntervalEXT && !g_pglSwapIntervalSGI) RARCH_WARN("[GLX]: Cannot find swap interval call.\n"); else RARCH_LOG("[GLX]: Found swap function: %s.\n", swap_func); } else RARCH_WARN("[GLX]: Context is not double buffered!.\n"); gfx_ctx_glx_swap_interval(data, glx->g_interval); /* This can blow up on some drivers. It's not fatal, so override errors for this call. */ old_handler = XSetErrorHandler(glx_nul_handler); XSetInputFocus(glx->g_dpy, glx->g_win, RevertToNone, CurrentTime); XSync(glx->g_dpy, False); XSetErrorHandler(old_handler); XFree(vi); glx->g_has_focus = true; if (!x11_create_input_context(glx->g_dpy, glx->g_win, &glx->g_xim, &glx->g_xic)) goto error; driver->display_type = RARCH_DISPLAY_X11; driver->video_display = (uintptr_t)glx->g_dpy; driver->video_window = (uintptr_t)glx->g_win; glx->g_true_full = true_full; return true; error: if (vi) XFree(vi); ctx_glx_destroy_resources(glx); if (glx) free(glx); return false; }
int CreateWindow(int display) { int err = 0; glutDisplay *glut_dpy = (glutDisplay *)display; glutWindow *glut_win = NULL; XVisualInfo *glx_visual = NULL; int glx_visual_attr[5]; int i = 0; glut_win = calloc(1, sizeof(glutWindow)); FIU_CHECK(glut_win); if (!glut_win) { printf("glut_win calloc error\n"); return 0; } memcpy(&glut_win->attribs, &glut_dpy->attribs, sizeof(struct attributes)); memset(glx_visual_attr, 0, sizeof(glx_visual_attr)); glx_visual_attr[i++] = GLX_RGBA; if (glut_win->attribs.double_buffer) { glx_visual_attr[i++] = GLX_DOUBLEBUFFER; } if (glut_win->attribs.depth_size) { glx_visual_attr[i++] = GLX_DEPTH_SIZE; glx_visual_attr[i++] = glut_win->attribs.depth_size; } glx_visual_attr[i] = None; glx_visual = glXChooseVisual(glut_dpy->x11_dpy, 0, glx_visual_attr); if (!glx_visual) { printf("glXChooseVisual error\n"); goto error; } glut_win->x11_win = create_window((int)glut_dpy->x11_dpy, glut_win->attribs.win_posx, glut_win->attribs.win_posy, glut_win->attribs.win_width, glut_win->attribs.win_height, 0, &err); if (err == -1) { goto error; } glut_win->glx_ctx = glXCreateContext(glut_dpy->x11_dpy, glx_visual, NULL, True); if (!glut_win->glx_ctx) { printf("glXCreateContext error\n"); goto error; } if (glut_win->attribs.depth_size) { err = glXGetConfig(glut_dpy->x11_dpy, glx_visual, GLX_DEPTH_SIZE, &glut_win->attribs.depth_size); if (err) { printf("glXCreateContext error\n"); goto error; } } free(glx_visual); return (int)glut_win; error: if (glut_win->glx_ctx) { glXDestroyContext(glut_dpy->x11_dpy, glut_win->glx_ctx); } if (glut_win->x11_win) { destroy_window((int)glut_dpy->x11_dpy, glut_win->x11_win); } if (glx_visual) { free(glx_visual); } free(glut_win); return 0; }
//-------------------------------------------------------------- // initialize graphics BOOL mgLinuxGL33Support::initDisplay() { mgDebug("------ try to create OpenGL 3.3 context, fullscreen=%s, multiSample=%s", m_fullscreen?"true":"false", m_multiSample?"true":"false"); mgLinuxServices* platform = (mgLinuxServices*) mgPlatform; // =-= some drivers are failing this test. not clear we need it #ifdef WORKED int glxMajor, glxMinor; glXQueryVersion(platform->m_display, &glxMajor, &glxMinor); mgDebug("GLX version = %d.%d", glxMajor, glxMinor); int glxVersion = glxMajor * 100 + glxMinor; if (glxVersion < 103) { mgDebug("GLX version < 1.3"); termDisplay(); return false; } #endif PFNGLXCREATECONTEXTATTRIBSARBPROC fnCreateContextAttribsARB = (PFNGLXCREATECONTEXTATTRIBSARBPROC)glXGetProcAddress((const GLubyte*) "glXCreateContextAttribsARB"); PFNGLGETSTRINGIPROC fnGetStringi = (PFNGLGETSTRINGIPROC)glXGetProcAddress((const GLubyte*) "glGetStringi"); if (fnCreateContextAttribsARB == NULL || fnGetStringi == NULL) { mgDebug("Could not locate OpenGL functions"); termDisplay(); return false; } platform->m_glrc = (*fnCreateContextAttribsARB) (platform->m_display, platform->m_bestFbc, NULL, true, GL33_CREATE_ATTRIBUTES); if (platform->m_glrc == NULL) { mgDebug("glXCreateContextAttribsARB 3.3 returns NULL. Trying 3.2"); platform->m_glrc = (*fnCreateContextAttribsARB) (platform->m_display, platform->m_bestFbc, NULL, true, GL32_CREATE_ATTRIBUTES); if (platform->m_glrc == NULL) { mgDebug("glXCreateContextAttribsARB 3.2 returns NULL. I give up."); termDisplay(); return false; } } glXMakeCurrent(platform->m_display, platform->m_window, platform->m_glrc); m_depthBits = 16; // default glXGetConfig(platform->m_display, platform->m_vi, GLX_DEPTH_SIZE, &m_depthBits); mgDebug("%d depth bits", m_depthBits); // build an extension list for glew with glGetStringi mgString extList; int i = 0; for (; ; i++) { const GLubyte* ext = (*fnGetStringi)(GL_EXTENSIONS, i); if (ext == NULL) break; extList += (const char*) ext; extList += " "; } mgDebug("glGetStringi returns %d extensions", i); checkError(); // clear error from requesting last extension // save extensions list for glew glExtensions = (GLubyte*) new char[1+extList.length()]; strcpy((char*) glExtensions, (const char*) extList); GLenum err = glewInit(); if (err != GLEW_OK) { mgDebug("Cannot initialize OpenGL - glewInit failed."); termDisplay(); return false; } // accept OpenGL 3.2, but need #version 330 shader mgString errorMsg; if (!checkVersion(302, 303, errorMsg)) { mgDebug("%s", (const char*) errorMsg); termDisplay(); return false; } if (m_swapImmediate) { PFNGLXSWAPINTERVALMESAPROC fnSwapIntervalMESA = (PFNGLXSWAPINTERVALMESAPROC)glXGetProcAddress((const GLubyte*) "glXSwapIntervalMESA"); if (fnSwapIntervalMESA != NULL) (*fnSwapIntervalMESA) (0); else { PFNGLXSWAPINTERVALSGIPROC fnSwapIntervalSGI = (PFNGLXSWAPINTERVALSGIPROC)glXGetProcAddress((const GLubyte*) "glXSwapIntervalSGI"); if (fnSwapIntervalSGI != NULL) (*fnSwapIntervalSGI) (0); else mgDebug("Cannot find glXSwapInterval"); } } if (m_multiSample) glEnable(GL_MULTISAMPLE); // compile the overlay shader mgDebug("compile overlay shader:"); const char* attrNames[] = {"vertPoint", "vertTexCoord0"}; const DWORD attrIndexes[] = {0, 1}; m_overlayShader = compileShaderPair(GL33_OVERLAY_VERTEX_SHADER, GL33_OVERLAY_FRAGMENT_SHADER, 2, attrNames, attrIndexes); if (m_overlayShader == 0) { mgDebug("Cannot compile overlay shader."); termDisplay(); return false; } const char* vendor = (const char*) glGetString(GL_VENDOR); if (vendor != NULL) mgDebug(":OpenGL device vendor: %s", (const char*) vendor); const char* renderer = (const char*) glGetString(GL_RENDERER); if (renderer != NULL) mgDebug(":OpenGL device renderer: %s", (const char*) renderer); const char* versionStr = (const char*) glGetString(GL_VERSION); if (versionStr != NULL) mgDebug(":OpenGL version: %s", (const char*) versionStr); const char* shaderVersionStr = (const char*) glGetString(GL_SHADING_LANGUAGE_VERSION); if (shaderVersionStr != NULL) mgDebug(":OpenGL shader version: %s", (const char*) shaderVersionStr); // report all the GL limits GLint value; #define GLREPORT(sym) value = INT_MAX; glGetIntegerv(sym, &value); if (value != INT_MAX) mgDebug(":%s: %d", #sym, value); GLREPORT(GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS); GLREPORT(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS); GLREPORT(GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS); GLREPORT(GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS); GLREPORT(GL_MAX_VARYING_COMPONENTS); GLREPORT(GL_MAX_COMBINED_UNIFORM_BLOCKS); GLREPORT(GL_MAX_CUBE_MAP_TEXTURE_SIZE); GLREPORT(GL_MAX_DRAW_BUFFERS); GLREPORT(GL_MAX_ELEMENTS_INDICES); GLREPORT(GL_MAX_ELEMENTS_VERTICES); GLREPORT(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS); GLREPORT(GL_MAX_FRAGMENT_UNIFORM_BLOCKS); GLREPORT(GL_MAX_FRAGMENT_INPUT_COMPONENTS); GLREPORT(GL_MIN_PROGRAM_TEXEL_OFFSET); GLREPORT(GL_MAX_PROGRAM_TEXEL_OFFSET); GLREPORT(GL_MAX_RECTANGLE_TEXTURE_SIZE); GLREPORT(GL_MAX_TEXTURE_IMAGE_UNITS); GLREPORT(GL_MAX_TEXTURE_LOD_BIAS); GLREPORT(GL_MAX_TEXTURE_SIZE); GLREPORT(GL_MAX_RENDERBUFFER_SIZE); GLREPORT(GL_MAX_ARRAY_TEXTURE_LAYERS); GLREPORT(GL_MAX_TEXTURE_BUFFER_SIZE); GLREPORT(GL_MAX_UNIFORM_BLOCK_SIZE); GLREPORT(GL_MAX_VARYING_FLOATS); GLREPORT(GL_MAX_VERTEX_ATTRIBS); GLREPORT(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS); GLREPORT(GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS); GLREPORT(GL_MAX_VERTEX_UNIFORM_COMPONENTS); GLREPORT(GL_MAX_VERTEX_OUTPUT_COMPONENTS); GLREPORT(GL_MAX_GEOMETRY_UNIFORM_COMPONENTS); GLREPORT(GL_MAX_SAMPLE_MASK_WORDS); GLREPORT(GL_MAX_COLOR_TEXTURE_SAMPLES); GLREPORT(GL_MAX_DEPTH_TEXTURE_SAMPLES); GLREPORT(GL_MAX_DEPTH_TEXTURE_SAMPLES); GLREPORT(GL_MAX_INTEGER_SAMPLES); GLREPORT(GL_MAX_UNIFORM_BUFFER_BINDINGS); GLREPORT(GL_MAX_UNIFORM_BLOCK_SIZE); GLREPORT(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT); GLREPORT(GL_MAX_VERTEX_UNIFORM_BLOCKS); GLREPORT(GL_MAX_GEOMETRY_UNIFORM_BLOCKS); GLREPORT(GL_MAX_GEOMETRY_INPUT_COMPONENTS); GLREPORT(GL_MAX_GEOMETRY_OUTPUT_COMPONENTS); #undef GLREPORT return true; }