Manually load X11 and resolve its symbols when needed.

This removes the static dependency on X11 on Linux, allowing for
headless rendering on systems without it.

Bug 20104157

Change-Id: I463c8b3340c3ad16cd0f0d1d0f8804ee31012dd0
Reviewed-on: https://swiftshader-review.googlesource.com/2832
Reviewed-by: Nicolas Capens <capn@google.com>
Tested-by: Nicolas Capens <capn@google.com>
diff --git a/src/Main/FrameBufferX11.cpp b/src/Main/FrameBufferX11.cpp
index 7fb97e4..f0d3c50 100644
--- a/src/Main/FrameBufferX11.cpp
+++ b/src/Main/FrameBufferX11.cpp
@@ -15,9 +15,11 @@
 

 #include "FrameBufferX11.hpp"

 

+#include "libX11.hpp"

+

 #include <sys/ipc.h>

 #include <sys/shm.h>

-#include <string.h>
+#include <string.h>

 #include <assert.h>

 

 namespace sw

@@ -43,31 +45,31 @@
 	{

 		if(!x_display)

 		{

-			x_display = XOpenDisplay(0);

+			x_display = libX11->XOpenDisplay(0);

 		}

 

 		int screen = DefaultScreen(x_display);

-		x_gc = XDefaultGC(x_display, screen);

-		int depth = XDefaultDepth(x_display, screen);
-
-		Status status = XMatchVisualInfo(x_display, screen, 32, TrueColor, &x_visual);
-		bool match = (status != 0 && x_visual.blue_mask == 0xFF);   // Prefer X8R8G8B8
-		Visual *visual = match ? x_visual.visual : XDefaultVisual(x_display, screen);

+		x_gc = libX11->XDefaultGC(x_display, screen);

+		int depth = libX11->XDefaultDepth(x_display, screen);

 

-		mit_shm = (XShmQueryExtension(x_display) == True);

+		Status status = libX11->XMatchVisualInfo(x_display, screen, 32, TrueColor, &x_visual);

+		bool match = (status != 0 && x_visual.blue_mask == 0xFF);   // Prefer X8R8G8B8

+		Visual *visual = match ? x_visual.visual : libX11->XDefaultVisual(x_display, screen);

+

+		mit_shm = (libX11->XShmQueryExtension && libX11->XShmQueryExtension(x_display) == True);

 

 		if(mit_shm)

 		{

-			x_image = XShmCreateImage(x_display, visual, depth, ZPixmap, 0, &shminfo, width, height);

+			x_image = libX11->XShmCreateImage(x_display, visual, depth, ZPixmap, 0, &shminfo, width, height);

 

 			shminfo.shmid = shmget(IPC_PRIVATE, x_image->bytes_per_line * x_image->height, IPC_CREAT | SHM_R | SHM_W);

 			shminfo.shmaddr = x_image->data = buffer = (char*)shmat(shminfo.shmid, 0, 0);

 			shminfo.readOnly = False;

 

-			PreviousXErrorHandler = XSetErrorHandler(XShmErrorHandler);

-			XShmAttach(x_display, &shminfo);   // May produce a BadAccess error

-			XSync(x_display, False);

-			XSetErrorHandler(PreviousXErrorHandler);

+			PreviousXErrorHandler = libX11->XSetErrorHandler(XShmErrorHandler);

+			libX11->XShmAttach(x_display, &shminfo);   // May produce a BadAccess error

+			libX11->XSync(x_display, False);

+			libX11->XSetErrorHandler(PreviousXErrorHandler);

 

 			if(shmBadAccess)

 			{

@@ -84,7 +86,7 @@
 		if(!mit_shm)

 		{

 			buffer = new char[width * height * 4];

-			x_image = XCreateImage(x_display, visual, depth, ZPixmap, 0, buffer, width, height, 32, width * 4);

+			x_image = libX11->XCreateImage(x_display, visual, depth, ZPixmap, 0, buffer, width, height, 32, width * 4);

 		}

 	}

 

@@ -100,7 +102,7 @@
 		}

 		else

 		{

-			XShmDetach(x_display, &shminfo);

+			libX11->XShmDetach(x_display, &shminfo);

 			XDestroyImage(x_image);

 			shmdt(shminfo.shmaddr);

 			shmctl(shminfo.shmid, IPC_RMID, 0);

@@ -108,7 +110,7 @@
 

 		if(ownX11)

 		{

-			XCloseDisplay(x_display);

+			libX11->XCloseDisplay(x_display);

 		}

 	}

 

@@ -131,14 +133,14 @@
 

 		if(!mit_shm)

 		{

-			XPutImage(x_display, x_window, x_gc, x_image, 0, 0, 0, 0, width, height);

+			libX11->XPutImage(x_display, x_window, x_gc, x_image, 0, 0, 0, 0, width, height);

 		}

 		else

 		{

-			XShmPutImage(x_display, x_window, x_gc, x_image, 0, 0, 0, 0, width, height, False);

+			libX11->XShmPutImage(x_display, x_window, x_gc, x_image, 0, 0, 0, 0, width, height, False);

 		}

 

-		XSync(x_display, False);

+		libX11->XSync(x_display, False);

 	}

 }

 

diff --git a/src/Main/libX11.cpp b/src/Main/libX11.cpp
new file mode 100644
index 0000000..ebd76ff
--- /dev/null
+++ b/src/Main/libX11.cpp
@@ -0,0 +1,48 @@
+#include "libX11.hpp"
+
+#include "Common/SharedLibrary.hpp"
+
+#define Bool int
+
+LibX11exports::LibX11exports(void *libX11, void *libXext)
+{
+    XOpenDisplay = (Display *(*)(char*))getProcAddress(libX11, "XOpenDisplay");
+    XGetWindowAttributes = (Status (*)(Display*, Window, XWindowAttributes*))getProcAddress(libX11, "XGetWindowAttributes");
+    XDefaultScreenOfDisplay = (Screen *(*)(Display*))getProcAddress(libX11, "XDefaultScreenOfDisplay");
+    XWidthOfScreen = (int (*)(Screen*))getProcAddress(libX11, "XWidthOfScreen");
+    XHeightOfScreen = (int (*)(Screen*))getProcAddress(libX11, "XHeightOfScreen");
+    XPlanesOfScreen = (int (*)(Screen*))getProcAddress(libX11, "XPlanesOfScreen");
+    XDefaultGC = (GC (*)(Display*, int))getProcAddress(libX11, "XDefaultGC");
+    XDefaultDepth = (int (*)(Display*, int))getProcAddress(libX11, "XDefaultDepth");
+    XMatchVisualInfo = (Status (*)(Display*, int, int, int, XVisualInfo*))getProcAddress(libX11, "XMatchVisualInfo");
+    XDefaultVisual = (Visual *(*)(Display*, int screen_number))getProcAddress(libX11, "XDefaultVisual");
+    XSetErrorHandler = (int (*(*)(int (*)(Display*, XErrorEvent*)))(Display*, XErrorEvent*))getProcAddress(libX11, "XSetErrorHandler");
+    XSync = (int (*)(Display*, Bool))getProcAddress(libX11, "XSync");
+    XCreateImage = (XImage *(*)(Display*, Visual*, unsigned int, int, int, char*, unsigned int, unsigned int, int, int))getProcAddress(libX11, "XCreateImage");
+    XCloseDisplay = (int (*)(Display*))getProcAddress(libX11, "XCloseDisplay");
+    XPutImage = (int (*)(Display*, Drawable, GC, XImage*, int, int, int, int, unsigned int, unsigned int))getProcAddress(libX11, "XPutImage");
+
+    XShmQueryExtension = (Bool (*)(Display*))getProcAddress(libXext, "XShmQueryExtension");
+    XShmCreateImage = (XImage *(*)(Display*, Visual*, unsigned int, int, char*, XShmSegmentInfo*, unsigned int, unsigned int))getProcAddress(libXext, "XShmCreateImage");
+    XShmAttach = (Bool (*)(Display*, XShmSegmentInfo*))getProcAddress(libXext, "XShmAttach");
+    XShmDetach = (Bool (*)(Display*, XShmSegmentInfo*))getProcAddress(libXext, "XShmDetach");
+    XShmPutImage = (int (*)(Display*, Drawable, GC, XImage*, int, int, int, int, unsigned int, unsigned int, bool))getProcAddress(libXext, "XShmPutImage");
+}
+
+LibX11exports *LibX11::operator->()
+{
+    static void *libX11 = nullptr;
+    static void *libXext = nullptr;
+    static LibX11exports *libX11exports = nullptr;
+
+    if(!libX11)
+    {
+        libX11 = loadLibrary("libX11.so");
+        libXext = loadLibrary("libXext.so");
+        libX11exports = new LibX11exports(libX11, libXext);
+    }
+
+    return libX11exports;
+}
+
+LibX11 libX11;
diff --git a/src/Main/libX11.hpp b/src/Main/libX11.hpp
new file mode 100644
index 0000000..eb5f6fc
--- /dev/null
+++ b/src/Main/libX11.hpp
@@ -0,0 +1,46 @@
+#ifndef libX11_hpp
+#define libX11_hpp
+
+#define Bool int
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/extensions/XShm.h>
+
+struct LibX11exports
+{
+    LibX11exports(void *libX11, void *libXext);
+
+    Display *(*XOpenDisplay)(char *display_name);
+    Status (*XGetWindowAttributes)(Display *display, Window w, XWindowAttributes *window_attributes_return);
+    Screen *(*XDefaultScreenOfDisplay)(Display *display);
+    int (*XWidthOfScreen)(Screen *screen);
+    int (*XHeightOfScreen)(Screen *screen);
+    int (*XPlanesOfScreen)(Screen *screen);
+    GC (*XDefaultGC)(Display *display, int screen_number);
+    int (*XDefaultDepth)(Display *display, int screen_number);
+    Status (*XMatchVisualInfo)(Display *display, int screen, int depth, int screen_class, XVisualInfo *vinfo_return);
+    Visual *(*XDefaultVisual)(Display *display, int screen_number);
+    int (*(*XSetErrorHandler)(int (*handler)(Display*, XErrorEvent*)))(Display*, XErrorEvent*);
+    int (*XSync)(Display *display, Bool discard);
+    XImage *(*XCreateImage)(Display *display, Visual *visual, unsigned int depth, int format, int offset, char *data, unsigned int width, unsigned int height, int bitmap_pad, int bytes_per_line);
+    int (*XCloseDisplay)(Display *display);
+    int (*XPutImage)(Display *display, Drawable d, GC gc, XImage *image, int src_x, int src_y, int dest_x, int dest_y, unsigned int width, unsigned int height);
+
+    Bool (*XShmQueryExtension)(Display *display);
+    XImage *(*XShmCreateImage)(Display *display, Visual *visual, unsigned int depth, int format, char *data, XShmSegmentInfo *shminfo, unsigned int width, unsigned int height);
+    Bool (*XShmAttach)(Display *display, XShmSegmentInfo *shminfo);
+    Bool (*XShmDetach)(Display *display, XShmSegmentInfo *shminfo);
+    int (*XShmPutImage)(Display *display, Drawable d, GC gc, XImage *image, int src_x, int src_y, int dest_x, int dest_y, unsigned int width, unsigned int height, bool send_event);
+};
+
+#undef Bool
+
+class LibX11
+{
+public:
+    LibX11exports *operator->();
+};
+
+extern LibX11 libX11;
+
+#endif   // libX11_hpp
diff --git a/src/OpenGL/libEGL/Display.cpp b/src/OpenGL/libEGL/Display.cpp
index cbd4d27..8d99bc7 100644
--- a/src/OpenGL/libEGL/Display.cpp
+++ b/src/OpenGL/libEGL/Display.cpp
@@ -20,6 +20,10 @@
 #include "libEGL/Context.hpp"
 #include "common/debug.h"
 
+#if defined(__unix__) && !defined(__ANDROID__)
+#include "Main/libX11.hpp"
+#endif
+
 #ifdef __ANDROID__
 #include <system/window.h>
 #include <GceFrameBufferConfig.h>
@@ -49,7 +53,14 @@
             if(platform == EGL_PLATFORM_X11_EXT)
             {
                 #if defined(__unix__)
-                    displayId = XOpenDisplay(NULL);
+					if(libX11->XOpenDisplay)
+					{
+						displayId = libX11->XOpenDisplay(NULL);
+					}
+					else
+					{
+						return error(EGL_BAD_PARAMETER, (egl::Display*)EGL_NO_DISPLAY);
+					}
                 #else
                     return error(EGL_BAD_PARAMETER, (egl::Display*)EGL_NO_DISPLAY);
                 #endif
@@ -507,7 +518,7 @@
         if(platform == EGL_PLATFORM_X11_EXT)
         {
             XWindowAttributes windowAttributes;
-            Status status = XGetWindowAttributes(displayId, window, &windowAttributes);
+            Status status = libX11->XGetWindowAttributes(displayId, window, &windowAttributes);
 
             return status == True;
         }
@@ -573,10 +584,10 @@
     #else
         if(platform == EGL_PLATFORM_X11_EXT)
         {
-            Screen *screen = XDefaultScreenOfDisplay(displayId);
-            displayMode.width = XWidthOfScreen(screen);
-            displayMode.height = XHeightOfScreen(screen);
-            unsigned int bpp = XPlanesOfScreen(screen);
+            Screen *screen = libX11->XDefaultScreenOfDisplay(displayId);
+            displayMode.width = libX11->XWidthOfScreen(screen);
+            displayMode.height = libX11->XHeightOfScreen(screen);
+            unsigned int bpp = libX11->XPlanesOfScreen(screen);
 
             switch(bpp)
             {
diff --git a/src/OpenGL/libEGL/Surface.cpp b/src/OpenGL/libEGL/Surface.cpp
index 0770848..1a36a93 100644
--- a/src/OpenGL/libEGL/Surface.cpp
+++ b/src/OpenGL/libEGL/Surface.cpp
@@ -23,6 +23,10 @@
 #include "common/debug.h"

 #include "Main/FrameBuffer.hpp"

 

+#if defined(__unix__) && !defined(__ANDROID__)

+#include "Main/libX11.hpp"

+#endif

+

 #if defined(_WIN32)

 #include <tchar.h>

 #endif

@@ -82,7 +86,7 @@
 }

 

 void Surface::deleteResources()

-{	

+{

     if(mDepthStencil)

     {

         mDepthStencil->release();

@@ -122,8 +126,8 @@
 		return reset(ANativeWindow_getWidth(mWindow), ANativeWindow_getHeight(mWindow));

 	#else

 		XWindowAttributes windowAttributes;

-		XGetWindowAttributes(mDisplay->getNativeDisplay(), mWindow, &windowAttributes);

-		

+		libX11->XGetWindowAttributes(mDisplay->getNativeDisplay(), mWindow, &windowAttributes);

+

 		return reset(windowAttributes.width, windowAttributes.height);

 	#endif

 }

@@ -219,7 +223,7 @@
     {

         return;

     }

-    

+

     mSwapInterval = interval;

     mSwapInterval = std::max(mSwapInterval, mDisplay->getMinSwapInterval());

     mSwapInterval = std::min(mSwapInterval, mDisplay->getMaxSwapInterval());

@@ -302,7 +306,7 @@
 		int clientHeight = ANativeWindow_getHeight(mWindow);

 	#else

 		XWindowAttributes windowAttributes;

-		XGetWindowAttributes(mDisplay->getNativeDisplay(), mWindow, &windowAttributes);

+		libX11->XGetWindowAttributes(mDisplay->getNativeDisplay(), mWindow, &windowAttributes);

 

 		int clientWidth = windowAttributes.width;

 		int clientHeight = windowAttributes.height;

diff --git a/src/OpenGL/libEGL/libEGL.cbp b/src/OpenGL/libEGL/libEGL.cbp
index 92a43c1..ee5fa97 100644
--- a/src/OpenGL/libEGL/libEGL.cbp
+++ b/src/OpenGL/libEGL/libEGL.cbp
@@ -107,10 +107,13 @@
 		<Linker>
 			<Add option="-Wl,--version-script=./exports.map" />
 			<Add option="-Wl,--hash-style=both" />
+			<Add option="-Wl,--no-undefined" />
 			<Add library="pthread" />
-			<Add library="X11" />
+			<Add library="dl" />
 		</Linker>
 		<Unit filename="../../Common/SharedLibrary.hpp" />
+		<Unit filename="../../Main/libX11.cpp" />
+		<Unit filename="../../Main/libX11.hpp" />
 		<Unit filename="../common/Object.cpp" />
 		<Unit filename="../common/Object.hpp" />
 		<Unit filename="../common/debug.cpp" />
diff --git a/src/OpenGL/libGLES_CM/libGLES_CM.cbp b/src/OpenGL/libGLES_CM/libGLES_CM.cbp
index ce1178b..7041a83 100644
--- a/src/OpenGL/libGLES_CM/libGLES_CM.cbp
+++ b/src/OpenGL/libGLES_CM/libGLES_CM.cbp
@@ -131,9 +131,9 @@
 		<Linker>
 			<Add option="-Wl,--version-script=./exports.map" />
 			<Add option="-Wl,--hash-style=both" />
+			<Add option="-Wl,--no-undefined" />
 			<Add library="pthread" />
-			<Add library="X11" />
-			<Add library="Xext" />
+			<Add library="dl" />
 		</Linker>
 		<Unit filename="../../Common/CPUID.cpp" />
 		<Unit filename="../../Common/CPUID.hpp" />
@@ -174,6 +174,8 @@
 		<Unit filename="../../Main/SwiftConfig.hpp" />
 		<Unit filename="../../Main/crc.cpp" />
 		<Unit filename="../../Main/crc.h" />
+		<Unit filename="../../Main/libX11.cpp" />
+		<Unit filename="../../Main/libX11.hpp" />
 		<Unit filename="../../Main/serialcommon.h" />
 		<Unit filename="../../Main/serialvalid.cpp" />
 		<Unit filename="../../Main/serialvalid.h" />
@@ -247,6 +249,8 @@
 		<Unit filename="../../Shader/VertexRoutine.hpp" />
 		<Unit filename="../../Shader/VertexShader.cpp" />
 		<Unit filename="../../Shader/VertexShader.hpp" />
+		<Unit filename="../common/MatrixStack.cpp" />
+		<Unit filename="../common/MatrixStack.hpp" />
 		<Unit filename="../common/NameSpace.cpp" />
 		<Unit filename="../common/NameSpace.hpp" />
 		<Unit filename="../common/Object.cpp" />
@@ -272,8 +276,6 @@
 		<Unit filename="Image.hpp" />
 		<Unit filename="IndexDataManager.cpp" />
 		<Unit filename="IndexDataManager.h" />
-		<Unit filename="../common/MatrixStack.cpp" />
-		<Unit filename="../common/MatrixStack.hpp" />
 		<Unit filename="Renderbuffer.cpp" />
 		<Unit filename="Renderbuffer.h" />
 		<Unit filename="ResourceManager.cpp" />
diff --git a/src/OpenGL/libGLESv2/libGLESv2.cbp b/src/OpenGL/libGLESv2/libGLESv2.cbp
index 6f08551..4615472 100644
--- a/src/OpenGL/libGLESv2/libGLESv2.cbp
+++ b/src/OpenGL/libGLESv2/libGLESv2.cbp
@@ -131,9 +131,9 @@
 		<Linker>
 			<Add option="-Wl,--version-script=./exports.map" />
 			<Add option="-Wl,--hash-style=both" />
+			<Add option="-Wl,--no-undefined" />
 			<Add library="pthread" />
-			<Add library="X11" />
-			<Add library="Xext" />
+			<Add library="dl" />
 		</Linker>
 		<Unit filename="../../Common/CPUID.cpp" />
 		<Unit filename="../../Common/CPUID.hpp" />
@@ -174,6 +174,8 @@
 		<Unit filename="../../Main/SwiftConfig.hpp" />
 		<Unit filename="../../Main/crc.cpp" />
 		<Unit filename="../../Main/crc.h" />
+		<Unit filename="../../Main/libX11.cpp" />
+		<Unit filename="../../Main/libX11.hpp" />
 		<Unit filename="../../Main/serialcommon.h" />
 		<Unit filename="../../Main/serialvalid.cpp" />
 		<Unit filename="../../Main/serialvalid.h" />
diff --git a/src/Radiance/libRAD/libRAD.cbp b/src/Radiance/libRAD/libRAD.cbp
index 47be418..4017d4e 100644
--- a/src/Radiance/libRAD/libRAD.cbp
+++ b/src/Radiance/libRAD/libRAD.cbp
@@ -153,6 +153,8 @@
 		<Unit filename="../../Main/SwiftConfig.hpp" />
 		<Unit filename="../../Main/crc.cpp" />
 		<Unit filename="../../Main/crc.h" />
+		<Unit filename="../../Main/libX11.cpp" />
+		<Unit filename="../../Main/libX11.hpp" />
 		<Unit filename="../../Main/serialcommon.h" />
 		<Unit filename="../../Main/serialvalid.cpp" />
 		<Unit filename="../../Main/serialvalid.h" />