فهرست منبع

Move from libX11/GLX to XCB/libX11/GLX.

Zachary Lund 11 سال پیش
والد
کامیت
de6e997264
4فایلهای تغییر یافته به همراه643 افزوده شده و 238 حذف شده
  1. 31 0
      cmake/Modules/FindX11_XCB.cmake
  2. 238 0
      cmake/Modules/FindXCB.cmake
  3. 17 2
      libobs-opengl/CMakeLists.txt
  4. 357 236
      libobs-opengl/gl-x11.c

+ 31 - 0
cmake/Modules/FindX11_XCB.cmake

@@ -0,0 +1,31 @@
+# - Try to find libX11-xcb
+# Once done this will define
+#
+# X11_XCB_FOUND - system has libX11-xcb
+# X11_XCB_LIBRARIES - Link these to use libX11-xcb
+# X11_XCB_INCLUDE_DIR - the libX11-xcb include dir
+# X11_XCB_DEFINITIONS - compiler switches required for using libX11-xcb
+
+# Copyright (c) 2011 Fredrik Höglund <[email protected]>
+# Copyright (c) 2008 Helio Chissini de Castro, <[email protected]>
+# Copyright (c) 2007 Matthias Kretz, <[email protected]>
+#
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+IF (NOT WIN32)
+  # use pkg-config to get the directories and then use these values
+  # in the FIND_PATH() and FIND_LIBRARY() calls
+  FIND_PACKAGE(PkgConfig)
+  PKG_CHECK_MODULES(PKG_X11_XCB QUIET x11-xcb)
+
+  SET(X11_XCB_DEFINITIONS ${PKG_X11_XCB_CFLAGS})
+
+  FIND_PATH(X11_XCB_INCLUDE_DIR NAMES X11/Xlib-xcb.h HINTS ${PKG_X11_XCB_INCLUDE_DIRS})
+  FIND_LIBRARY(X11_XCB_LIBRARIES NAMES X11-xcb HINTS ${PKG_X11_XCB_LIBRARY_DIRS})
+
+  include(FindPackageHandleStandardArgs)
+  FIND_PACKAGE_HANDLE_STANDARD_ARGS(X11_XCB DEFAULT_MSG X11_XCB_LIBRARIES X11_XCB_INCLUDE_DIR)
+
+  MARK_AS_ADVANCED(X11_XCB_INCLUDE_DIR X11_XCB_LIBRARIES)
+ENDIF (NOT WIN32)

+ 238 - 0
cmake/Modules/FindXCB.cmake

@@ -0,0 +1,238 @@
+# Try to find XCB on a Unix system
+#
+# This will define:
+#
+#   XCB_FOUND        - True if xcb is available
+#   XCB_LIBRARIES    - Link these to use xcb
+#   XCB_INCLUDE_DIRS - Include directory for xcb
+#   XCB_DEFINITIONS  - Compiler flags for using xcb
+#
+# In addition the following more fine grained variables will be defined:
+#
+#   XCB_XCB_FOUND        XCB_XCB_INCLUDE_DIR        XCB_XCB_LIBRARY
+#   XCB_UTIL_FOUND       XCB_UTIL_INCLUDE_DIR       XCB_UTIL_LIBRARY
+#   XCB_COMPOSITE_FOUND  XCB_COMPOSITE_INCLUDE_DIR  XCB_COMPOSITE_LIBRARY
+#   XCB_DAMAGE_FOUND     XCB_DAMAGE_INCLUDE_DIR     XCB_DAMAGE_LIBRARY
+#   XCB_XFIXES_FOUND     XCB_XFIXES_INCLUDE_DIR     XCB_XFIXES_LIBRARY
+#   XCB_RENDER_FOUND     XCB_RENDER_INCLUDE_DIR     XCB_RENDER_LIBRARY
+#   XCB_RANDR_FOUND      XCB_RANDR_INCLUDE_DIR      XCB_RANDR_LIBRARY
+#   XCB_SHAPE_FOUND      XCB_SHAPE_INCLUDE_DIR      XCB_SHAPE_LIBRARY
+#   XCB_DRI2_FOUND       XCB_DRI2_INCLUDE_DIR       XCB_DRI2_LIBRARY
+#   XCB_GLX_FOUND        XCB_GLX_INCLUDE_DIR        XCB_GLX_LIBRARY
+#   XCB_SHM_FOUND        XCB_SHM_INCLUDE_DIR        XCB_SHM_LIBRARY
+#   XCB_XV_FOUND         XCB_XV_INCLUDE_DIR         XCB_XV_LIBRARY
+#   XCB_SYNC_FOUND       XCB_SYNC_INCLUDE_DIR       XCB_SYNC_LIBRARY
+#   XCB_XTEST_FOUND      XCB_XTEST_INCLUDE_DIR      XCB_XTEST_LIBRARY
+#   XCB_ICCCM_FOUND      XCB_ICCCM_INCLUDE_DIR      XCB_ICCCM_LIBRARY
+#   XCB_EWMH_FOUND       XCB_EWMH_INCLUDE_DIR       XCB_EWMH_LIBRARY
+#   XCB_IMAGE_FOUND      XCB_IMAGE_INCLUDE_DIR      XCB_IMAGE_LIBRARY
+#   XCB_RENDERUTIL_FOUND XCB_RENDERUTIL_INCLUDE_DIR XCB_RENDERUTIL_LIBRARY
+#   XCB_KEYSYMS_FOUND    XCB_KEYSYMS_INCLUDE_DIR    XCB_KEYSYMS_LIBRARY
+#
+# Copyright (c) 2011 Fredrik Höglund <[email protected]>
+# Copyright (c) 2013 Martin Gräßlin <[email protected]>
+#
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+set(knownComponents XCB
+                    COMPOSITE
+                    DAMAGE
+                    DRI2
+                    EWMH
+                    GLX
+                    ICCCM
+                    IMAGE
+                    KEYSYMS
+                    RANDR
+                    RENDER
+                    RENDERUTIL
+                    SHAPE
+                    SHM
+                    SYNC
+                    UTIL
+                    XFIXES
+                    XTEST
+                    XV)
+
+unset(unknownComponents)
+
+set(pkgConfigModules)
+set(requiredComponents)
+
+if (XCB_FIND_COMPONENTS)
+  set(comps ${XCB_FIND_COMPONENTS})
+else()
+  set(comps ${knownComponents})
+endif()
+
+# iterate through the list of requested components, and check that we know them all.
+# If not, fail.
+foreach(comp ${comps})
+    list(FIND knownComponents ${comp} index )
+    if("${index}" STREQUAL "-1")
+        list(APPEND unknownComponents "${comp}")
+    else()
+        if("${comp}" STREQUAL "XCB")
+            list(APPEND pkgConfigModules "xcb")
+        elseif("${comp}" STREQUAL "COMPOSITE")
+            list(APPEND pkgConfigModules "xcb-composite")
+        elseif("${comp}" STREQUAL "DAMAGE")
+            list(APPEND pkgConfigModules "xcb-damage")
+        elseif("${comp}" STREQUAL "DRI2")
+            list(APPEND pkgConfigModules "xcb-dri2")
+        elseif("${comp}" STREQUAL "EWMH")
+            list(APPEND pkgConfigModules "xcb-ewmh")
+        elseif("${comp}" STREQUAL "GLX")
+            list(APPEND pkgConfigModules "xcb-glx")
+        elseif("${comp}" STREQUAL "ICCCM")
+            list(APPEND pkgConfigModules "xcb-icccm")
+        elseif("${comp}" STREQUAL "IMAGE")
+            list(APPEND pkgConfigModules "xcb-image")
+        elseif("${comp}" STREQUAL "KEYSYMS")
+            list(APPEND pkgConfigModules "xcb-keysyms")
+        elseif("${comp}" STREQUAL "RANDR")
+            list(APPEND pkgConfigModules "xcb-randr")
+        elseif("${comp}" STREQUAL "RENDER")
+            list(APPEND pkgConfigModules "xcb-render")
+        elseif("${comp}" STREQUAL "RENDERUTIL")
+            list(APPEND pkgConfigModules "xcb-renderutil")
+        elseif("${comp}" STREQUAL "SHAPE")
+            list(APPEND pkgConfigModules "xcb-shape")
+        elseif("${comp}" STREQUAL "SHM")
+            list(APPEND pkgConfigModules "xcb-shm")
+        elseif("${comp}" STREQUAL "SYNC")
+            list(APPEND pkgConfigModules "xcb-sync")
+        elseif("${comp}" STREQUAL "UTIL")
+            list(APPEND pkgConfigModules "xcb-util")
+        elseif("${comp}" STREQUAL "XFIXES")
+            list(APPEND pkgConfigModules "xcb-xfixes")
+        elseif("${comp}" STREQUAL "XTEST")
+            list(APPEND pkgConfigModules "xcb-xtest")
+        elseif("${comp}" STREQUAL "XV")
+            list(APPEND pkgConfigModules "xcb-xv")
+        endif()
+    endif()
+endforeach()
+
+
+if(DEFINED unknownComponents)
+   set(msgType STATUS)
+   if(XCB_FIND_REQUIRED)
+      set(msgType FATAL_ERROR)
+   endif()
+   if(NOT XCB_FIND_QUIETLY)
+      message(${msgType} "XCB: requested unknown components ${unknownComponents}")
+   endif()
+   return()
+endif()
+
+macro(_XCB_HANDLE_COMPONENT _comp)
+    set(_header )
+    set(_lib )
+    if("${_comp}" STREQUAL "XCB")
+        set(_header "xcb/xcb.h")
+        set(_lib "xcb")
+    elseif("${_comp}" STREQUAL "COMPOSITE")
+        set(_header "xcb/composite.h")
+        set(_lib "xcb-composite")
+    elseif("${_comp}" STREQUAL "DAMAGE")
+        set(_header "xcb/damage.h")
+        set(_lib "xcb-damage")
+    elseif("${_comp}" STREQUAL "DRI2")
+        set(_header "xcb/dri2.h")
+        set(_lib "xcb-dri2")
+    elseif("${_comp}" STREQUAL "EWMH")
+        set(_header "xcb/xcb_ewmh.h")
+        set(_lib "xcb-ewmh")
+    elseif("${_comp}" STREQUAL "GLX")
+        set(_header "xcb/glx.h")
+        set(_lib "xcb-glx")
+    elseif("${_comp}" STREQUAL "ICCCM")
+        set(_header "xcb/xcb_icccm.h")
+        set(_lib "xcb-icccm")
+    elseif("${_comp}" STREQUAL "IMAGE")
+        set(_header "xcb/xcb_image.h")
+        set(_lib "xcb-image")
+    elseif("${_comp}" STREQUAL "KEYSYMS")
+        set(_header "xcb/xcb_keysyms.h")
+        set(_lib "xcb-keysyms")
+    elseif("${_comp}" STREQUAL "RANDR")
+        set(_header "xcb/randr.h")
+        set(_lib "xcb-randr")
+    elseif("${_comp}" STREQUAL "RENDER")
+        set(_header "xcb/render.h")
+        set(_lib "xcb-render")
+    elseif("${_comp}" STREQUAL "RENDERUTIL")
+        set(_header "xcb/xcb_renderutil.h")
+        set(_lib "xcb-render-util")
+    elseif("${_comp}" STREQUAL "SHAPE")
+        set(_header "xcb/shape.h")
+        set(_lib "xcb-shape")
+    elseif("${_comp}" STREQUAL "SHM")
+        set(_header "xcb/shm.h")
+        set(_lib "xcb-shm")
+    elseif("${_comp}" STREQUAL "SYNC")
+        set(_header "xcb/sync.h")
+        set(_lib "xcb-sync")
+    elseif("${_comp}" STREQUAL "UTIL")
+        set(_header "xcb/xcb_util.h")
+        set(_lib "xcb-util")
+    elseif("${_comp}" STREQUAL "XFIXES")
+        set(_header "xcb/xfixes.h")
+        set(_lib "xcb-xfixes")
+    elseif("${_comp}" STREQUAL "XTEST")
+        set(_header "xcb/xtest.h")
+        set(_lib "xcb-xtest")
+    elseif("${_comp}" STREQUAL "XV")
+        set(_header "xcb/xv.h")
+        set(_lib "xcb-xv")
+    endif()
+
+    find_path(XCB_${_comp}_INCLUDE_DIR NAMES ${_header} HINTS ${PKG_XCB_INCLUDE_DIRS})
+    find_library(XCB_${_comp}_LIBRARY NAMES ${_lib} HINTS ${PKG_XCB_LIBRARY_DIRS})
+
+    if(XCB_${_comp}_INCLUDE_DIR AND XCB_${_comp}_LIBRARY)
+        list(APPEND XCB_INCLUDE_DIRS ${XCB_${_comp}_INCLUDE_DIR})
+        list(APPEND XCB_LIBRARIES ${XCB_${_comp}_LIBRARY})
+        if (NOT XCB_FIND_QUIETLY)
+            message(STATUS "XCB[${_comp}]: Found component ${_comp}")
+        endif()
+    endif()
+
+    if(XCB_FIND_REQUIRED_${_comp})
+        list(APPEND requiredComponents XCB_${_comp}_FOUND)
+    endif()
+
+    find_package_handle_standard_args(XCB_${_comp} DEFAULT_MSG XCB_${_comp}_LIBRARY XCB_${_comp}_INCLUDE_DIR)
+
+    mark_as_advanced(XCB_${_comp}_LIBRARY XCB_${_comp}_INCLUDE_DIR)
+
+    # compatibility for old variable naming
+    set(XCB_${_comp}_INCLUDE_DIRS ${XCB_${_comp}_INCLUDE_DIR})
+    set(XCB_${_comp}_LIBRARIES ${XCB_${_comp}_LIBRARY})
+endmacro()
+
+IF (NOT WIN32)
+    include(FindPackageHandleStandardArgs)
+    # Use pkg-config to get the directories and then use these values
+    # in the FIND_PATH() and FIND_LIBRARY() calls
+    find_package(PkgConfig)
+    pkg_check_modules(PKG_XCB QUIET ${pkgConfigModules})
+
+    set(XCB_DEFINITIONS ${PKG_XCB_CFLAGS})
+
+    foreach(comp ${comps})
+        _xcb_handle_component(${comp})
+    endforeach()
+
+    if(XCB_INCLUDE_DIRS)
+        list(REMOVE_DUPLICATES XCB_INCLUDE_DIRS)
+    endif()
+
+    find_package_handle_standard_args(XCB DEFAULT_MSG XCB_LIBRARIES XCB_INCLUDE_DIRS ${requiredComponents})
+
+    # compatibility for old variable naming
+    set(XCB_INCLUDE_DIR ${XCB_INCLUDE_DIRS})
+
+ENDIF (NOT WIN32)

+ 17 - 2
libobs-opengl/CMakeLists.txt

@@ -17,7 +17,7 @@ elseif(APPLE)
 	set_source_files_properties(${libobs-opengl_PLATFORM_SOURCES}
 	set_source_files_properties(${libobs-opengl_PLATFORM_SOURCES}
 		PROPERTIES
 		PROPERTIES
 			LANGUAGE C)
 			LANGUAGE C)
-	
+
 	find_library(COCOA Cocoa)
 	find_library(COCOA Cocoa)
 	include_directories(${COCOA})
 	include_directories(${COCOA})
 	mark_as_advanced(COCOA)
 	mark_as_advanced(COCOA)
@@ -30,7 +30,22 @@ elseif(APPLE)
 		${COCOA}
 		${COCOA}
 		${IOSURF}
 		${IOSURF}
 		${OPENGL_gl_LIBRARY})
 		${OPENGL_gl_LIBRARY})
-else()
+else() #This needs to change to be more specific to get ready for Wayland
+	find_package(XCB COMPONENTS XCB REQUIRED)
+	find_package(X11_XCB REQUIRED)
+
+	include_directories(
+		${XCB_INCLUDE_DIRS}
+		${X11_XCB_INCLUDE_DIRS})
+
+	add_definitions(
+		${XCB_DEFINITIONS}
+		${X11_XCB_DEFINITIONS})
+
+	set(libobs-opengl_PLATFORM_DEPS
+		${XCB_LIBRARIES}
+		${X11_XCB_LIBRARIES})
+
 	set(libobs-opengl_PLATFORM_SOURCES
 	set(libobs-opengl_PLATFORM_SOURCES
 		gl-x11.c)
 		gl-x11.c)
 endif()
 endif()

+ 357 - 236
libobs-opengl/gl-x11.c

@@ -15,7 +15,24 @@
     along with this program.  If not, see <http://www.gnu.org/licenses/>.
     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 ******************************************************************************/
 ******************************************************************************/
 
 
+/* Version 2 of the GLX backend...
+ * Difference from version 1 is that we use XCB to help alleviate
+ * pains in a threaded environment that is prone to error.
+ * These errors must be readable and handled for the sake of,
+ * not only the users' sanity, but my own.
+ *
+ * With that said, we have more error checking capabilities...
+ * and not all of them are used to help simplify current code.
+ *
+ * TODO: Implement more complete error checking.
+ * NOTE: GLX loading functions are placed illogically
+ * 	for the sake of convenience.
+ */
+
 #include <X11/Xlib.h>
 #include <X11/Xlib.h>
+#include <X11/Xlib-xcb.h>
+
+#include <xcb/xcb.h>
 
 
 #include <stdio.h>
 #include <stdio.h>
 
 
@@ -23,17 +40,6 @@
 
 
 #include <glad/glad_glx.h>
 #include <glad/glad_glx.h>
 
 
-static const int fb_attribs[] = {
-	/* Hardcoded for now... */
-	GLX_STENCIL_SIZE, 8,
-	GLX_DEPTH_SIZE, 24,
-	GLX_BUFFER_SIZE, 32, /* Color buffer depth */
-	GLX_DOUBLEBUFFER, true,
-	GLX_X_RENDERABLE, true,
-	GLX_RENDER_TYPE, GLX_RGBA_BIT,
-	None
-};
-
 static const int ctx_attribs[] = {
 static const int ctx_attribs[] = {
 #ifdef _DEBUG
 #ifdef _DEBUG
 	GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB,
 	GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB,
@@ -44,15 +50,26 @@ static const int ctx_attribs[] = {
 };
 };
 
 
 struct gl_windowinfo {
 struct gl_windowinfo {
-	Display *display;
-	uint32_t id;
-	uint32_t int_id;
-	uint32_t glxid;
+	/* We store this value since we can fetch a lot
+	 * of information not only concerning the config
+	 * but the visual, and various other settings
+	 * for the context.
+	 */
+	GLXFBConfig config;
+
+	/* Windows in X11 are defined with integers (XID).
+	 * xcb_window_t is a define for this... they are
+	 * compatible with Xlib as well.
+	 */
+	xcb_window_t window;
+
+	/* We can't fetch screen without a request so we cache it. */
+	int screen;
 };
 };
 
 
 struct gl_platform {
 struct gl_platform {
+	Display *display;
 	GLXContext context;
 	GLXContext context;
-	GLXFBConfig fbcfg;
 	struct gs_swap_chain swap;
 	struct gs_swap_chain swap;
 };
 };
 
 
@@ -61,32 +78,6 @@ extern struct gs_swap_chain *gl_platform_getswap(struct gl_platform *platform)
 	return &platform->swap;
 	return &platform->swap;
 }
 }
 
 
-extern struct gl_windowinfo *gl_windowinfo_create(
-		const struct gs_init_data *info)
-{
-	struct gl_windowinfo *wi = bzalloc(sizeof(struct gl_windowinfo));
-	wi->id = info->window.id;
-	wi->display = info->window.display;
-
-	return wi;
-}
-
-extern void gl_windowinfo_destroy(struct gl_windowinfo *wi)
-{
-	bfree(wi);
-}
-
-extern void gl_getclientsize(const struct gs_swap_chain *swap,
-			     uint32_t *width, uint32_t *height)
-{
-	XWindowAttributes info = { 0 };
-
-	XGetWindowAttributes(swap->wi->display, swap->wi->id, &info);
-
-	*height = info.height;
-	*width = info.width;
-}
-
 static void print_info_stuff(const struct gs_init_data *info)
 static void print_info_stuff(const struct gs_init_data *info)
 {
 {
 	blog(	LOG_INFO,
 	blog(	LOG_INFO,
@@ -101,302 +92,430 @@ static void print_info_stuff(const struct gs_init_data *info)
 		info->adapter
 		info->adapter
 	);
 	);
 }
 }
+/* The following utility functions are copied verbatim from WGL code.
+ * GLX and WGL are more similar than most people realize. */
 
 
-int wait_for_notify(Display *dpy, XEvent *e, char *arg)
+/* For now, only support basic 32bit formats for graphics output. */
+static inline int get_color_format_bits(enum gs_color_format format)
 {
 {
-	UNUSED_PARAMETER(dpy);
-	return (e->type == MapNotify) && (e->xmap.window == (Window)arg);
+	switch ((uint32_t)format) {
+	case GS_RGBA:
+		return 32;
+	default:
+		return 0;
+	}
 }
 }
 
 
-static bool got_x_error = false;
-static int err_handler(Display *disp, XErrorEvent *e)
+static inline int get_depth_format_bits(enum gs_zstencil_format zsformat)
 {
 {
-	char estr[128];
-	XGetErrorText(disp, e->error_code, estr, 128);
+	switch ((uint32_t)zsformat) {
+	case GS_Z16:
+		return 16;
+	case GS_Z24_S8:
+		return 24;
+	default:
+		return 0;
+	}
+}
 
 
-	blog(LOG_DEBUG, "Got X error: %s", estr);
+static inline int get_stencil_format_bits(enum gs_zstencil_format zsformat)
+{
+	switch ((uint32_t)zsformat) {
+	case GS_Z24_S8:
+		return 8;
+	default:
+		return 0;
+	}
+}
 
 
-	got_x_error = true;
+/*
+ * Since we cannot take advantage of the asynchronous nature of xcb,
+ * all of the helper functions are synchronous but thread-safe.
+ *
+ * They check for errors and will return 0 on problems
+ * with the exception of when 0 is a valid return value... in which case
+ * read the specific function comments.
+ */
+
+/* Returns -1 on invalid screen. */
+static int get_screen_num_from_xcb_screen(xcb_connection_t *xcb_conn,
+		xcb_screen_t *screen)
+{
+	xcb_screen_iterator_t iter =
+		xcb_setup_roots_iterator(xcb_get_setup(xcb_conn));
+	int screen_num = 0;
 
 
-	return 0;
+	for (; iter.rem; xcb_screen_next(&iter), ++screen_num)
+		if (iter.data == screen)
+			return screen_num;
+
+	return -1;
 }
 }
 
 
-static bool handle_x_error(Display *disp, const char *error_string)
+static xcb_screen_t *get_screen_from_root(xcb_connection_t *xcb_conn,
+		xcb_window_t root)
 {
 {
-	XSync(disp, 0);
+	xcb_screen_iterator_t iter =
+		xcb_setup_roots_iterator(xcb_get_setup(xcb_conn));
 
 
-	if (got_x_error) {
-		if (error_string)
-			blog(LOG_ERROR, "%s", error_string);
+	while (iter.rem) {
+		if (iter.data->root == root)
+			return iter.data;
 
 
-		got_x_error = false;
-		return true;
+		xcb_screen_next(&iter);
 	}
 	}
 
 
-	return false;
+	return 0;
 }
 }
 
 
-struct gl_platform *gl_platform_create(gs_device_t *device,
-		const struct gs_init_data *info)
+static inline int get_screen_num_from_root(xcb_connection_t *xcb_conn,
+		xcb_window_t root)
 {
 {
-	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;
+	xcb_screen_t *screen = get_screen_from_root(xcb_conn, root);
 
 
-	print_info_stuff(info);
+	if (!screen) return -1;
 
 
-	if (!display) {
-		blog(LOG_ERROR, "Unable to find display. DISPLAY variable "
-		                "may not be set correctly.");
-		goto fail0;
-	}
+	return get_screen_num_from_xcb_screen(xcb_conn, screen);
+}
 
 
-	if (!XGetWindowAttributes(display, info->window.id, &attrs)) {
-		blog(LOG_ERROR, "Failed getting window attributes");
-		goto fail0;
+static xcb_get_geometry_reply_t* get_window_geometry(
+		xcb_connection_t *xcb_conn, xcb_drawable_t drawable)
+{
+	xcb_get_geometry_cookie_t cookie;
+	xcb_generic_error_t *error;
+	xcb_get_geometry_reply_t *reply;
+
+	cookie = xcb_get_geometry(xcb_conn, drawable);
+	reply = xcb_get_geometry_reply(xcb_conn, cookie, &error);
+
+	if (error) {
+		blog(LOG_ERROR, "Failed to fetch parent window geometry!");
+		free(error);
+		free(reply);
+		return 0;
 	}
 	}
 
 
-	screen = XScreenNumberOfScreen(attrs.screen);
+	free(error);
+	return reply;
+}
 
 
-	if (!gladLoadGLX(display, screen)) {
-		blog(LOG_ERROR, "Unable to load GLX entry functions.");
-		goto fail0;
-	}
+static bool gl_context_create(struct gl_platform *plat)
+{
+	Display *display = plat->display;
+	GLXFBConfig config = plat->swap.wi->config;
+	int major, minor;
+	GLXContext context;
+
+	{
+		int error_base;
+		int event_base;
 
 
-	if (!glXQueryExtension(display, &error_base, &event_base)) {
-		blog(LOG_ERROR, "GLX not supported.");
-		goto fail0;
+		if (!glXQueryExtension(display, &error_base, &event_base)) {
+			blog(LOG_ERROR, "GLX not supported.");
+			return 0;
+		}
 	}
 	}
 
 
 	/* We require glX version 1.3 */
 	/* We require glX version 1.3 */
-
 	glXQueryVersion(display, &major, &minor);
 	glXQueryVersion(display, &major, &minor);
 	if (major < 1 || (major == 1 && minor < 3)) {
 	if (major < 1 || (major == 1 && minor < 3)) {
 		blog(LOG_ERROR, "GLX version found: %i.%i\nRequired: "
 		blog(LOG_ERROR, "GLX version found: %i.%i\nRequired: "
 				"1.3", major, minor);
 				"1.3", major, minor);
-		goto fail0;
+		return false;
 	}
 	}
 
 
 	if (!GLAD_GLX_ARB_create_context) {
 	if (!GLAD_GLX_ARB_create_context) {
 		blog(LOG_ERROR, "ARB_GLX_create_context not supported!");
 		blog(LOG_ERROR, "ARB_GLX_create_context not supported!");
-		goto fail0;
+		return false;
 	}
 	}
 
 
-	configs = glXChooseFBConfig(display, screen,
-			fb_attribs, &num_configs);
-
-	if (!configs) {
-		blog(LOG_ERROR, "Attribute list or screen is invalid.");
-		goto fail0;
+	context = glXCreateContextAttribsARB(display, config, NULL,
+			true, ctx_attribs);
+	if (!context) {
+		blog(LOG_ERROR, "Failed to create OpenGL context.");
+		return false;
 	}
 	}
 
 
-	if (num_configs == 0) {
-		XFree(configs);
-		blog(LOG_ERROR, "No framebuffer configurations found.");
-		goto fail0;
-	}
+	plat->context = context;
+	plat->display = display;
 
 
-	plat->fbcfg = configs[0];
+	return true;
+}
 
 
-	XFree(configs);
+static void gl_context_destroy(struct gl_platform *plat)
+{
+	Display *display = plat->display;
 
 
-	handle_x_error(display, NULL);
+	glXMakeCurrent(display, None, 0);
+	glXDestroyContext(display, plat->context);
+	bfree(plat);
+}
 
 
-	/* 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;
-	}
+extern struct gl_windowinfo *gl_windowinfo_create(const struct gs_init_data *info)
+{
+	UNUSED_PARAMETER(info);
+	return bmalloc(sizeof(struct gl_windowinfo));
+}
 
 
-	if (handle_x_error(display, "Failed to create OpenGL context."))
-		goto fail2;
+extern void gl_windowinfo_destroy(struct gl_windowinfo *info)
+{
+	UNUSED_PARAMETER(info);
+	bfree(info);
+}
 
 
-	device->plat = plat;
+extern struct gl_platform *gl_platform_create(gs_device_t *device,
+		const struct gs_init_data *info)
+{
+	/* There's some trickery here... we're mixing libX11, xcb, and GLX
+	   For an explanation see here: http://xcb.freedesktop.org/MixingCalls/
+	   Essentially, GLX requires Xlib. Everything else we use xcb. */
+	struct gl_windowinfo *wi = gl_windowinfo_create(info);
+	struct gl_platform * plat = bmalloc(sizeof(struct gl_platform));
+	Display * display;
 
 
-	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;
+	print_info_stuff(info);
+
+	if (!wi) {
+		blog(LOG_ERROR, "Failed to create window info!");
+		goto fail_wi_create;
 	}
 	}
 
 
-	if (!gladLoadGL()) {
-		blog(LOG_ERROR, "Failed to load OpenGL entry functions.");
-		goto fail2;
+	display = XOpenDisplay(XDisplayString(info->window.display));
+	if (!display) {
+		blog(LOG_ERROR, "Unable to open new X connection!");
+		goto fail_display_open;
 	}
 	}
 
 
-	blog(LOG_INFO, "OpenGL version: %s\n", glGetString(GL_VERSION));
+	XSetEventQueueOwner(display, XCBOwnsEventQueue);
 
 
 	/* We assume later that cur_swap is already set. */
 	/* We assume later that cur_swap is already set. */
 	device->cur_swap = &plat->swap;
 	device->cur_swap = &plat->swap;
+	device->plat = plat;
 
 
-	XSync(display, false);
+	plat->display = display;
+	plat->swap.device = device;
+	plat->swap.info = *info;
+	plat->swap.wi = wi;
 
 
-	blog(LOG_INFO, "Created new platform data");
+	if (!gl_platform_init_swapchain(&plat->swap)) {
+		blog(LOG_ERROR, "Failed to initialize swap chain!");
+		goto fail_init_swapchain;
+	}
 
 
-	return plat;
+	if (!gl_context_create(plat)) {
+		blog(LOG_ERROR, "Failed to create context!");
+		goto fail_context_create;
+	}
 
 
-fail2:
-	glXMakeCurrent(display, None, NULL);
-	glXDestroyContext(display, plat->context);
+	if (!glXMakeCurrent(plat->display, wi->window, plat->context)) {
+		blog(LOG_ERROR, "Failed to make context current.");
+		goto fail_make_current;
+	}
 
 
-	gl_platform_cleanup_swapchain(&plat->swap);
+	if (!gladLoadGL()) {
+		blog(LOG_ERROR, "Failed to load OpenGL entry functions.");
+		goto fail_load_gl;
+	}
 
 
-fail0:
-	bfree(plat);
-	device->plat = 0;
+	blog(LOG_INFO, "OpenGL version: %s\n", glGetString(GL_VERSION));
 
 
-	return NULL;
+	goto success;
+
+fail_make_current:
+	gl_context_destroy(plat);
+fail_context_create:
+fail_load_gl:
+fail_init_swapchain:
+	XCloseDisplay(display);
+fail_display_open:
+fail_wi_create:
+	gl_windowinfo_destroy(wi);
+	free(plat);
+	plat = NULL;
+success:
+	return plat;
 }
 }
 
 
-void gl_platform_destroy(struct gl_platform *platform)
+extern void gl_platform_destroy(struct gl_platform *plat)
 {
 {
-	if (!platform)
+	if (!plat) /* In what case would platform be invalid here? */
 		return;
 		return;
 
 
-	Display *dpy = platform->swap.wi->display;
+	struct gl_windowinfo *wi = plat->swap.wi;
 
 
-	glXMakeCurrent(dpy, None, NULL);
-	gl_platform_cleanup_swapchain(&platform->swap);
-	glXDestroyContext(dpy, platform->context);
-	gl_windowinfo_destroy(platform->swap.wi);
-	bfree(platform);
+	gl_context_destroy(plat);
+	gl_windowinfo_destroy(wi);
 }
 }
 
 
-bool gl_platform_init_swapchain(struct gs_swap_chain *swap)
+extern bool gl_platform_init_swapchain(struct gs_swap_chain *swap)
 {
 {
-	Display *display = swap->wi->display;
-	struct gl_windowinfo *info = swap->wi;
-	struct gl_platform *plat = swap->device->plat;
-	XVisualInfo *vi = 0;
-	Colormap cmap = 0;
-	XSetWindowAttributes swa;
-	XWindowAttributes attrs;
-
-	XErrorHandler phandler = XSetErrorHandler(err_handler);
-
-	gl_platform_cleanup_swapchain(swap);
-
-	if (!XGetWindowAttributes(display, info->id, &attrs)) {
-		blog(LOG_ERROR, "Failed getting window attributes");
-		goto fail;
+	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;
 	}
 	}
 
 
-	vi = glXGetVisualFromFBConfig(display, plat->fbcfg);
-
-	if (handle_x_error(display, "Failed to get visual from fb config."))
-		goto fail;
-
-	cmap = XCreateColormap(display, info->id, vi->visual, AllocNone);
-
-	if (handle_x_error(display, "Failed creating colormap"))
-		goto fail;
-
-	swa.colormap = cmap;
-	swa.border_pixel = 0;
-
-	info->int_id = XCreateWindow(display, info->id, 0, 0,
-	                             attrs.width, attrs.height,
-	                             0, 24, InputOutput, vi->visual,
-	                             CWBorderPixel|CWColormap, &swa);
-	XMapWindow(display, info->int_id);
+	/* 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;
+	}
 
 
-	if (handle_x_error(display, "Failed creating intermediate X window"))
-		goto fail;
+	/* 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;
+		}
+	}
 
 
-	info->glxid = glXCreateWindow(display, plat->fbcfg, info->int_id, 0);
+	/* ...then fetch matching visual info for xcb. */
+	{
+		int error = glXGetFBConfigAttrib(display, fb_config[0], GLX_VISUAL_ID, &visual);
 
 
-	if (handle_x_error(display, "Failed creating intermediate GLX window"))
-		goto fail;
+		if (error) {
+			blog(LOG_ERROR, "Bad call to GetFBConfigAttrib!");
+			goto fail_visual_id;
+		}
+	}
 
 
-	XFreeColormap(display, cmap);
-	XFree(vi);
 
 
-	return true;
+	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 };
 
 
-fail:
+	xcb_create_colormap(xcb_conn,
+		XCB_COLORMAP_ALLOC_NONE,
+		colormap,
+		parent,
+		visual
+	);
 
 
-	gl_platform_cleanup_swapchain(swap);
+	xcb_create_window(
+		xcb_conn, 24 /* Hardcoded? */,
+		wid, parent,
+		0, 0,
+		geometry->width,
+		geometry->height,
+		0, 0,
+		visual, mask, mask_values
+	);
 
 
-	if (cmap)
-		XFreeColormap(display, cmap);
+	swap->wi->config = fb_config[0];
+	swap->wi->window = wid;
 
 
-	if (vi)
-		XFree(vi);
+	xcb_map_window(xcb_conn, wid);
 
 
-	XSetErrorHandler(phandler);
+	XFree(fb_config);
+	status = true;
+	goto success;
 
 
-	return false;
+fail_visual_id:
+	XFree(fb_config);
+fail_fb_config:
+fail_load_glx:
+fail_screen:
+fail_geometry_request:
+success:
+	free(geometry);
+	return status;
 }
 }
 
 
-void gl_platform_cleanup_swapchain(struct gs_swap_chain *swap)
+extern void gl_platform_cleanup_swapchain(struct gs_swap_chain *swap)
 {
 {
-	Display *display = swap->wi->display;
-	struct gl_windowinfo *info = swap->wi;
-
-	if (!info)
-		return;
-
-	if (info->glxid)
-		glXDestroyWindow(display, info->glxid);
-
-	if (info->int_id)
-		XDestroyWindow(display, info->int_id);
-
-	info->glxid = 0;
-	info->int_id = 0;
+	UNUSED_PARAMETER(swap);
+	/* Really nothing to clean up? */
 }
 }
 
 
-void device_enter_context(gs_device_t *device)
+extern void device_enter_context(gs_device_t *device)
 {
 {
 	GLXContext context = device->plat->context;
 	GLXContext context = device->plat->context;
-	XID window = device->cur_swap->wi->glxid;
-	Display *display = device->cur_swap->wi->display;
+	XID window = device->cur_swap->wi->window;
+	Display *display = device->plat->display;
 
 
 	if (!glXMakeCurrent(display, window, context)) {
 	if (!glXMakeCurrent(display, window, context)) {
 		blog(LOG_ERROR, "Failed to make context current.");
 		blog(LOG_ERROR, "Failed to make context current.");
 	}
 	}
 }
 }
 
 
-void device_leave_context(gs_device_t *device)
+extern void device_leave_context(gs_device_t *device)
 {
 {
-	Display *display = device->cur_swap->wi->display;
+	Display *display = device->plat->display;
 
 
 	if (!glXMakeCurrent(display, None, NULL)) {
 	if (!glXMakeCurrent(display, None, NULL)) {
 		blog(LOG_ERROR, "Failed to reset current context.");
 		blog(LOG_ERROR, "Failed to reset current context.");
 	}
 	}
 }
 }
 
 
-void gl_update(gs_device_t *device)
+extern void gl_getclientsize(const struct gs_swap_chain *swap,
+			     uint32_t *width, uint32_t *height)
 {
 {
-	Display *display = device->cur_swap->wi->display;
-	XID window = device->cur_swap->wi->int_id;
+	xcb_connection_t *xcb_conn = XGetXCBConnection(swap->device->plat->display);
+	xcb_window_t window = swap->wi->window;
+
+	xcb_get_geometry_reply_t *geometry = get_window_geometry(xcb_conn, window);
+	*width = geometry->width;
+	*height = geometry->height;
 
 
-	XResizeWindow(display, window,
-			device->cur_swap->info.cx, device->cur_swap->info.cy);
+	free(geometry);
 }
 }
 
 
-void device_load_swapchain(gs_device_t *device, gs_swapchain_t *swap)
+extern void gl_update(gs_device_t *device)
+{
+	Display *display = device->plat->display;
+	xcb_window_t window = device->cur_swap->wi->window;
+
+	uint32_t values[] = {
+		device->cur_swap->info.cx,
+		device->cur_swap->info.cy
+	};
+
+	xcb_configure_window(
+		XGetXCBConnection(display), window,
+		XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT,
+		values
+	);
+}
+
+extern void device_load_swapchain(gs_device_t *device, gs_swapchain_t *swap)
 {
 {
 	if (!swap)
 	if (!swap)
 		swap = &device->plat->swap;
 		swap = &device->plat->swap;
@@ -404,8 +523,8 @@ void device_load_swapchain(gs_device_t *device, gs_swapchain_t *swap)
 	if (device->cur_swap == swap)
 	if (device->cur_swap == swap)
 		return;
 		return;
 
 
-	Display *dpy = swap->wi->display;
-	XID window = swap->wi->glxid;
+	Display *dpy = device->plat->display;
+	XID window = swap->wi->window;
 	GLXContext ctx = device->plat->context;
 	GLXContext ctx = device->plat->context;
 
 
 	device->cur_swap = swap;
 	device->cur_swap = swap;
@@ -415,10 +534,12 @@ void device_load_swapchain(gs_device_t *device, gs_swapchain_t *swap)
 	}
 	}
 }
 }
 
 
-void device_present(gs_device_t *device)
+extern void device_present(gs_device_t *device)
 {
 {
-	Display *display = device->cur_swap->wi->display;
-	XID window = device->cur_swap->wi->glxid;
+	Display *display = device->plat->display;
+	XID window = device->cur_swap->wi->window;
+
+	/* TODO: Handle XCB events. */
 
 
 	glXSwapBuffers(display, window);
 	glXSwapBuffers(display, window);
 }
 }