static Display *open_windowless_display(void) { Display *display = XOpenDisplay(NULL); xcb_connection_t *xcb_conn; xcb_screen_iterator_t screen_iterator; xcb_screen_t *screen; int screen_num; if (!display) { blog(LOG_ERROR, "Unable to open new X connection!"); return NULL; } xcb_conn = XGetXCBConnection(display); if (!xcb_conn) { blog(LOG_ERROR, "Unable to get XCB connection to main display"); goto error; } screen_iterator = xcb_setup_roots_iterator(xcb_get_setup(xcb_conn)); screen = screen_iterator.data; if (!screen) { blog(LOG_ERROR, "Unable to get screen root"); goto error; } screen_num = get_screen_num_from_root(xcb_conn, screen->root); if (screen_num == -1) { blog(LOG_ERROR, "Unable to get screen number from root"); goto error; } if (!gladLoadGLX(display, screen_num)) { blog(LOG_ERROR, "Unable to load GLX entry functions."); goto error; } return display; error: if (display) XCloseDisplay(display); return NULL; }
struct gl_platform *gl_platform_create(device_t device, struct gs_init_data *info) { int num_configs = 0; int error_base = 0, event_base = 0; Display *display = info->window.display; struct gl_platform *plat = bzalloc(sizeof(struct gl_platform)); GLXFBConfig* configs; XWindowAttributes attrs; int screen; int major = 0, minor = 0; print_info_stuff(info); if (!display) { blog(LOG_ERROR, "Unable to find display. DISPLAY variable " "may not be set correctly."); goto fail0; } if (!XGetWindowAttributes(display, info->window.id, &attrs)) { blog(LOG_ERROR, "Failed getting window attributes"); goto fail0; } screen = XScreenNumberOfScreen(attrs.screen); if (!gladLoadGLX(display, screen)) { blog(LOG_ERROR, "Unable to load GLX entry functions."); goto fail0; } if (!glXQueryExtension(display, &error_base, &event_base)) { blog(LOG_ERROR, "GLX not supported."); goto fail0; } /* We require glX version 1.3 */ glXQueryVersion(display, &major, &minor); if (major < 1 || (major == 1 && minor < 3)) { blog(LOG_ERROR, "GLX version found: %i.%i\nRequired: " "1.3", major, minor); goto fail0; } if (!GLAD_GLX_ARB_create_context) { blog(LOG_ERROR, "ARB_GLX_create_context not supported!"); goto fail0; } configs = glXChooseFBConfig(display, screen, fb_attribs, &num_configs); if (!configs) { blog(LOG_ERROR, "Attribute list or screen is invalid."); goto fail0; } if (num_configs == 0) { XFree(configs); blog(LOG_ERROR, "No framebuffer configurations found."); goto fail0; } plat->fbcfg = configs[0]; XFree(configs); handle_x_error(display, NULL); /* We just use the first configuration found... as it does everything * we want at the very least. */ plat->context = glXCreateContextAttribsARB(display, plat->fbcfg, NULL, true, ctx_attribs); if (!plat->context) { blog(LOG_ERROR, "Failed to create OpenGL context."); goto fail0; } if (handle_x_error(display, "Failed to create OpenGL context.")) goto fail2; device->plat = plat; plat->swap.device = device; plat->swap.info.window.id = info->window.id; plat->swap.info.window.display = display; plat->swap.info.format = GS_RGBA; plat->swap.info.zsformat = GS_Z24_S8; plat->swap.info.num_backbuffers = 1; plat->swap.info.adapter = info->adapter; plat->swap.info.cx = attrs.width; plat->swap.info.cy = attrs.height; plat->swap.wi = gl_windowinfo_create(info); if (!gl_platform_init_swapchain(&plat->swap)) goto fail2; if (!glXMakeCurrent(display, plat->swap.wi->glxid, plat->context)) { blog(LOG_ERROR, "Failed to make context current."); goto fail2; } if (!gladLoadGL()) { blog(LOG_ERROR, "Failed to load OpenGL entry functions."); goto fail2; } blog(LOG_INFO, "OpenGL version: %s\n", glGetString(GL_VERSION)); /* We assume later that cur_swap is already set. */ device->cur_swap = &plat->swap; XSync(display, false); blog(LOG_INFO, "Created new platform data"); return plat; fail2: glXMakeCurrent(display, None, NULL); glXDestroyContext(display, plat->context); gl_platform_cleanup_swapchain(&plat->swap); fail0: bfree(plat); device->plat = 0; return NULL; }
extern bool gl_platform_init_swapchain(struct gs_swap_chain *swap) { Display *display = swap->device->plat->display; struct gs_init_data *info = &swap->info; xcb_connection_t *xcb_conn = XGetXCBConnection(display); xcb_window_t wid = xcb_generate_id(xcb_conn); xcb_window_t parent = swap->info.window.id; xcb_get_geometry_reply_t *geometry = get_window_geometry(xcb_conn, parent); bool status = false; int screen_num; int visual; GLXFBConfig *fb_config; if (!geometry) goto fail_geometry_request; screen_num = get_screen_num_from_root(xcb_conn, geometry->root); if (screen_num == -1) { goto fail_screen; } /* NOTE: * So GLX is odd. You can have different extensions per screen, * not just per video card or visual. * * Because of this, it makes sense to call LoadGLX everytime * we open a frackin' window. In Windows, entry points can change * so it makes more sense there. Here, despite it virtually never * having the possibility of changing unless the user is intentionally * being an asshole to cause this behavior, we still have to give it * the correct screen num just out of good practice. *sigh* */ if (!gladLoadGLX(display, screen_num)) { blog(LOG_ERROR, "Unable to load GLX entry functions."); goto fail_load_glx; } /* Define our FBConfig hints for GLX... */ const int fb_attribs[] = { GLX_STENCIL_SIZE, get_stencil_format_bits(info->zsformat), GLX_DEPTH_SIZE, get_depth_format_bits(info->zsformat), GLX_BUFFER_SIZE, get_color_format_bits(info->format), GLX_DOUBLEBUFFER, true, GLX_X_RENDERABLE, true, None }; /* ...fetch the best match... */ { int num_configs; fb_config = glXChooseFBConfig(display, screen_num, fb_attribs, &num_configs); if (!fb_config || !num_configs) { blog(LOG_ERROR, "Failed to find FBConfig!"); goto fail_fb_config; } } /* ...then fetch matching visual info for xcb. */ { int error = glXGetFBConfigAttrib(display, fb_config[0], GLX_VISUAL_ID, &visual); if (error) { blog(LOG_ERROR, "Bad call to GetFBConfigAttrib!"); goto fail_visual_id; } } xcb_colormap_t colormap = xcb_generate_id(xcb_conn); uint32_t mask = XCB_CW_BORDER_PIXEL | XCB_CW_COLORMAP; uint32_t mask_values[] = { 0, colormap, 0 }; xcb_create_colormap(xcb_conn, XCB_COLORMAP_ALLOC_NONE, colormap, parent, visual ); xcb_create_window( xcb_conn, 24 /* Hardcoded? */, wid, parent, 0, 0, geometry->width, geometry->height, 0, 0, visual, mask, mask_values ); swap->wi->config = fb_config[0]; swap->wi->window = wid; xcb_map_window(xcb_conn, wid); XFree(fb_config); status = true; goto success; fail_visual_id: XFree(fb_config); fail_fb_config: fail_load_glx: fail_screen: fail_geometry_request: success: free(geometry); return status; }
void X11OpenGLWindow::createWindow(const b3gWindowConstructionInfo& ci) { m_data->m_dpy = MyXOpenDisplay(NULL); m_data->m_glWidth = ci.m_width; m_data->m_glHeight = ci.m_height; if(m_data->m_dpy == NULL) { fprintf(stderr, "\n\tcannot connect to X server\n\n"); exit(EXIT_FAILURE); } m_data->m_root = DefaultRootWindow(m_data->m_dpy); #ifdef GLEW_DYNAMIC_LOAD_ALL_GLX_FUNCTIONS int res=gladLoadGLX(m_data->m_dpy,DefaultScreen(m_data->m_dpy)); if (!res) { printf("Error in gladLoadGLX\n"); exit(0); } #endif if (ci.m_openglVersion < 3) { forceOpenGL3 = false; } if (forceOpenGL3) { int glxMinor, glxMajor; if (!glXQueryVersion(m_data->m_dpy,&glxMajor,&glxMinor) || (((glxMajor==1)&&(glxMinor<3)) || (glxMajor<1))) { fprintf(stderr, "Invalid GLX version: major %d, minor %d\n",glxMajor,glxMinor); exit(EXIT_FAILURE); } static int visual_attribs[] = { GLX_X_RENDERABLE , True, GLX_DRAWABLE_TYPE , GLX_WINDOW_BIT, GLX_RENDER_TYPE , GLX_RGBA_BIT, GLX_X_VISUAL_TYPE , GLX_TRUE_COLOR, GLX_RED_SIZE , 8, GLX_GREEN_SIZE , 8, GLX_BLUE_SIZE , 8, GLX_ALPHA_SIZE , 8, GLX_DEPTH_SIZE , 24, GLX_STENCIL_SIZE , 8, GLX_DOUBLEBUFFER , True, None }; int fbcount; GLXFBConfig* fbc = glXChooseFBConfig(m_data->m_dpy, DefaultScreen(m_data->m_dpy), visual_attribs, &fbcount); if (!fbc) { fprintf(stderr, "Failed to retrieve a framebuffer config\n" ); exit(1); } ///don't use highest samples, it is really slow on some NVIDIA Quadro cards #ifdef USE_HIGHEST_SAMPLES int best_fbc = -1, worst_fbc = -1, best_num_samp = -1, worst_num_samp = 999; int i; for (i=0; i<fbcount; ++i) { XVisualInfo *vi = glXGetVisualFromFBConfig( m_data->m_dpy, fbc[i] ); if ( vi ) { int samp_buf, samples; glXGetFBConfigAttrib( m_data->m_dpy, fbc[i], GLX_SAMPLE_BUFFERS, &samp_buf ); glXGetFBConfigAttrib( m_data->m_dpy, fbc[i], GLX_SAMPLES , &samples ); //printf( " Matching fbconfig %d, visual ID 0x%2x: SAMPLE_BUFFERS = %d," // " SAMPLES = %d\n", // i, vi -> visualid, samp_buf, samples ); if ( best_fbc < 0 || (samp_buf && (samples > best_num_samp)) ) best_fbc = i, best_num_samp = samples; if ( worst_fbc < 0 || (!samp_buf || (samples < worst_num_samp)) ) worst_fbc = i, worst_num_samp = samples; } MyXFree( vi ); } m_data->m_bestFbc = fbc[ best_fbc ]; #else m_data->m_bestFbc = *fbc; #endif // Be sure to free the FBConfig list allocated by glXChooseFBConfig() MyXFree( fbc ); m_data->m_vi = glXGetVisualFromFBConfig( m_data->m_dpy, m_data->m_bestFbc ); m_data->m_swa.colormap = m_data->m_cmap = MyXCreateColormap( m_data->m_dpy, RootWindow( m_data->m_dpy, m_data->m_vi->screen ), m_data->m_vi->visual, AllocNone ); m_data->m_swa.background_pixmap = None ; m_data->m_swa.border_pixel = 0; m_data->m_swa.event_mask = ExposureMask | KeyReleaseMask | KeyPressMask |ButtonPressMask | ButtonReleaseMask |PointerMotionMask|StructureNotifyMask; ; m_data->m_root = RootWindow( m_data->m_dpy, m_data->m_vi->screen ); m_data->m_win = MyXCreateWindow( m_data->m_dpy, m_data->m_root, 0, 0, ci.m_width, ci.m_height, 0, m_data->m_vi->depth, InputOutput, m_data->m_vi->visual, CWBorderPixel|CWColormap|CWEventMask, &m_data->m_swa ); //m_data->m_win = m_data->m_x11_XCreateWindow(m_data->m_dpy, m_data->m_root, 0, 0, ci.m_width, ci.m_height, 0, m_data->m_vi->depth, InputOutput, m_data->m_vi->visual, CWColormap | CWEventMask, &m_data->m_swa); if (!m_data->m_win) { fprintf(stderr, "Cannot create window\n"); exit(EXIT_FAILURE); } MyXMapWindow(m_data->m_dpy, m_data->m_win); MyXStoreName(m_data->m_dpy, m_data->m_win, "OpenGL3 Window"); } else { m_data->m_vi = glXChooseVisual(m_data->m_dpy, 0, att); printf("4\n"); if(m_data->m_vi == NULL) { fprintf(stderr, "\n\tno appropriate visual found\n\n"); exit(EXIT_FAILURE); } else { printf("\n\tvisual %p selected\n", (void *)m_data->m_vi->visualid); /* %p creates hexadecimal output like in glxinfo */ } m_data->m_cmap = MyXCreateColormap(m_data->m_dpy, m_data->m_root, m_data->m_vi->visual, AllocNone); m_data->m_swa.colormap = m_data->m_cmap; m_data->m_swa.event_mask = ExposureMask | KeyReleaseMask | KeyPressMask |ButtonPressMask | ButtonReleaseMask |PointerMotionMask|StructureNotifyMask; m_data->m_win = MyXCreateWindow(m_data->m_dpy, m_data->m_root, 0, 0, ci.m_width, ci.m_height, 0, m_data->m_vi->depth, InputOutput, m_data->m_vi->visual, CWColormap | CWEventMask, &m_data->m_swa); MyXMapWindow(m_data->m_dpy, m_data->m_win); MyXStoreName(m_data->m_dpy, m_data->m_win, "OpenGL2 Window"); } enableOpenGL(); }
bool LinuxWindowImpl::RunThread() { Thread::RunThread(); // Lock our use of the display connection.. XLockDisplay(GetDisplay()); int screenId = DefaultScreen(GetDisplay()); // Make sure we have glx extensions loaded. gladLoadGLX(GetDisplay(), screenId); // Make sure we've got a good version of GLX int majorGLX, minorGLX = 0; glXQueryVersion(GetDisplay(), &majorGLX, &minorGLX); if (majorGLX <= 1 && minorGLX < 3) { LOG(Log::CRITICAL) << "GLX 1.3 or greater is required.\n"; return false; } else { LOG(Log::DEFAULT) << "GLX version: " << majorGLX << "." << minorGLX << '\n'; } // Pick a visual info based on the context display settings. ::XVisualInfo* vi = GetVisualInfoFromSettings(GetDisplay(), screenId, settings); if (!vi) { LOG(Log::CRITICAL) << "Couldn't find an XVisualInfo that matches Context Settings!"; return false; } // Open the actual window. XSetWindowAttributes windowAttribs; windowAttribs.border_pixel = BlackPixel(GetDisplay(), screenId); windowAttribs.background_pixel = WhitePixel(GetDisplay(), screenId); windowAttribs.override_redirect = True; windowAttribs.colormap = XCreateColormap(GetDisplay(), RootWindow(GetDisplay(), screenId), vi->visual, AllocNone); windowAttribs.event_mask = ExposureMask | FocusChangeMask; window = XCreateWindow(GetDisplay(), RootWindow(GetDisplay(), screenId), 0, 0, width, height, 0, vi->depth, InputOutput, vi->visual, CWBackPixel | CWColormap | CWBorderPixel | CWEventMask, &windowAttribs); XClearWindow(GetDisplay(), window); XMapRaised(GetDisplay(), window); // Finished with the display XUnlockDisplay(GetDisplay()); Wait(); XLockDisplay(GetDisplay()); // Have to do this ridiculousness just to capture when the window is closed... Atom wmDeleteMessage = XInternAtom(GetDisplay(), "WM_DELETE_WINDOW", False); XSetWMProtocols(GetDisplay(), window, &wmDeleteMessage, 1); XUnlockDisplay(GetDisplay()); // Loop through the events dealing with them. running = true; while (running) { xcb_generic_event_t* event = xcb_wait_for_event(GetXCBConnection()); switch(event->response_type & ~0x80) { case XCB_EXPOSE: break; case XCB_CLIENT_MESSAGE: { xcb_client_message_event_t* clientMessage = (xcb_client_message_event_t*)event; if (clientMessage->data.data32[0] == wmDeleteMessage) running = false; break; } default: break; } free(event); } XFree(vi); XLockDisplay(GetDisplay()); XFreeColormap(LinuxWindowImpl::GetDisplay(), windowAttribs.colormap); XDestroyWindow(LinuxWindowImpl::GetDisplay(), window); XUnlockDisplay(GetDisplay()); return true; }