summaryrefslogtreecommitdiff
path: root/Source/Core/VideoBackends/OGL/GLInterface
diff options
context:
space:
mode:
authorAugustin Cavalier <waddlesplash@gmail.com>2014-11-01 10:33:02 -0400
committerAugustin Cavalier <waddlesplash@gmail.com>2014-11-02 12:16:33 -0500
commit29593d403b7e0b2311241de868426ed285c7d97a (patch)
tree858bd8dbf27a6f1a0f88f79ee1b2430f8952e6e2 /Source/Core/VideoBackends/OGL/GLInterface
parent089e32ba7d7f48993fa0706f7b9f69a12bf7192a (diff)
Move GLInterface to the OGL VideoBackend's directory.
Diffstat (limited to 'Source/Core/VideoBackends/OGL/GLInterface')
-rw-r--r--Source/Core/VideoBackends/OGL/GLInterface/AGL.cpp109
-rw-r--r--Source/Core/VideoBackends/OGL/GLInterface/AGL.h27
-rw-r--r--Source/Core/VideoBackends/OGL/GLInterface/EGL.cpp209
-rw-r--r--Source/Core/VideoBackends/OGL/GLInterface/EGL.h32
-rw-r--r--Source/Core/VideoBackends/OGL/GLInterface/EGLAndroid.cpp29
-rw-r--r--Source/Core/VideoBackends/OGL/GLInterface/EGLAndroid.h15
-rw-r--r--Source/Core/VideoBackends/OGL/GLInterface/EGLX11.cpp44
-rw-r--r--Source/Core/VideoBackends/OGL/GLInterface/EGLX11.h21
-rw-r--r--Source/Core/VideoBackends/OGL/GLInterface/GLInterface.cpp40
-rw-r--r--Source/Core/VideoBackends/OGL/GLInterface/GLX.cpp145
-rw-r--r--Source/Core/VideoBackends/OGL/GLInterface/GLX.h30
-rw-r--r--Source/Core/VideoBackends/OGL/GLInterface/WGL.cpp182
-rw-r--r--Source/Core/VideoBackends/OGL/GLInterface/WGL.h25
-rw-r--r--Source/Core/VideoBackends/OGL/GLInterface/X11Utils.cpp278
-rw-r--r--Source/Core/VideoBackends/OGL/GLInterface/X11Utils.h71
-rw-r--r--Source/Core/VideoBackends/OGL/GLInterface/X11_Util.cpp75
-rw-r--r--Source/Core/VideoBackends/OGL/GLInterface/X11_Util.h26
17 files changed, 1358 insertions, 0 deletions
diff --git a/Source/Core/VideoBackends/OGL/GLInterface/AGL.cpp b/Source/Core/VideoBackends/OGL/GLInterface/AGL.cpp
new file mode 100644
index 0000000000..4ab1cdd565
--- /dev/null
+++ b/Source/Core/VideoBackends/OGL/GLInterface/AGL.cpp
@@ -0,0 +1,109 @@
+// Copyright 2014 Dolphin Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#include "VideoBackends/OGL/GLInterface/AGL.h"
+
+#include "VideoCommon/RenderBase.h"
+#include "VideoCommon/VertexShaderManager.h"
+#include "VideoCommon/VideoConfig.h"
+
+void cInterfaceAGL::Swap()
+{
+ [cocoaCtx flushBuffer];
+}
+
+// Create rendering window.
+// Call browser: Core.cpp:EmuThread() > main.cpp:Video_Initialize()
+bool cInterfaceAGL::Create(void *window_handle)
+{
+ cocoaWin = reinterpret_cast<NSView*>(window_handle);
+ NSSize size = [cocoaWin frame].size;
+
+ // Enable high-resolution display support.
+ [cocoaWin setWantsBestResolutionOpenGLSurface:YES];
+
+ NSWindow *window = [cocoaWin window];
+
+ float scale = [window backingScaleFactor];
+ size.width *= scale;
+ size.height *= scale;
+
+ // Control window size and picture scaling
+ s_backbuffer_width = size.width;
+ s_backbuffer_height = size.height;
+
+ NSOpenGLPixelFormatAttribute attr[] = { NSOpenGLPFADoubleBuffer, NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core, NSOpenGLPFAAccelerated, 0 };
+ NSOpenGLPixelFormat *fmt = [[NSOpenGLPixelFormat alloc]
+ initWithAttributes: attr];
+ if (fmt == nil)
+ {
+ ERROR_LOG(VIDEO, "failed to create pixel format");
+ return false;
+ }
+
+ cocoaCtx = [[NSOpenGLContext alloc] initWithFormat: fmt shareContext: nil];
+ [fmt release];
+ if (cocoaCtx == nil)
+ {
+ ERROR_LOG(VIDEO, "failed to create context");
+ return false;
+ }
+
+ if (cocoaWin == nil)
+ {
+ ERROR_LOG(VIDEO, "failed to create window");
+ return false;
+ }
+
+ [window makeFirstResponder:cocoaWin];
+ [cocoaCtx setView: cocoaWin];
+ [window makeKeyAndOrderFront: nil];
+
+ return true;
+}
+
+bool cInterfaceAGL::MakeCurrent()
+{
+ [cocoaCtx makeCurrentContext];
+ return true;
+}
+
+bool cInterfaceAGL::ClearCurrent()
+{
+ [NSOpenGLContext clearCurrentContext];
+ return true;
+}
+
+// Close backend
+void cInterfaceAGL::Shutdown()
+{
+ [cocoaCtx clearDrawable];
+ [cocoaCtx release];
+ cocoaCtx = nil;
+}
+
+void cInterfaceAGL::Update()
+{
+ NSWindow *window = [cocoaWin window];
+ NSSize size = [cocoaWin frame].size;
+
+ float scale = [window backingScaleFactor];
+ size.width *= scale;
+ size.height *= scale;
+
+ if (s_backbuffer_width == size.width &&
+ s_backbuffer_height == size.height)
+ return;
+
+ s_backbuffer_width = size.width;
+ s_backbuffer_height = size.height;
+
+ [cocoaCtx update];
+}
+
+void cInterfaceAGL::SwapInterval(int interval)
+{
+ [cocoaCtx setValues:(GLint *)&interval forParameter:NSOpenGLCPSwapInterval];
+}
+
diff --git a/Source/Core/VideoBackends/OGL/GLInterface/AGL.h b/Source/Core/VideoBackends/OGL/GLInterface/AGL.h
new file mode 100644
index 0000000000..8ab0dedc0c
--- /dev/null
+++ b/Source/Core/VideoBackends/OGL/GLInterface/AGL.h
@@ -0,0 +1,27 @@
+// Copyright 2014 Dolphin Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#pragma once
+
+#ifdef __APPLE__
+#import <AppKit/AppKit.h>
+#endif
+
+#include "VideoBackends/OGL/GLInterfaceBase.h"
+
+class cInterfaceAGL : public cInterfaceBase
+{
+private:
+ NSView *cocoaWin;
+ NSOpenGLContext *cocoaCtx;
+public:
+ void Swap();
+ bool Create(void *window_handle);
+ bool MakeCurrent();
+ bool ClearCurrent();
+ void Shutdown();
+ void Update();
+ void SwapInterval(int interval);
+
+};
diff --git a/Source/Core/VideoBackends/OGL/GLInterface/EGL.cpp b/Source/Core/VideoBackends/OGL/GLInterface/EGL.cpp
new file mode 100644
index 0000000000..0fdec471ef
--- /dev/null
+++ b/Source/Core/VideoBackends/OGL/GLInterface/EGL.cpp
@@ -0,0 +1,209 @@
+// Copyright 2014 Dolphin Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#include "VideoBackends/OGL/GLInterfaceBase.h"
+#include "VideoBackends/OGL/GLInterface/EGL.h"
+#include "VideoCommon/RenderBase.h"
+
+// Show the current FPS
+void cInterfaceEGL::Swap()
+{
+ eglSwapBuffers(egl_dpy, egl_surf);
+}
+void cInterfaceEGL::SwapInterval(int Interval)
+{
+ eglSwapInterval(egl_dpy, Interval);
+}
+
+void* cInterfaceEGL::GetFuncAddress(const std::string& name)
+{
+ return (void*)eglGetProcAddress(name.c_str());
+}
+
+void cInterfaceEGL::DetectMode()
+{
+ if (s_opengl_mode != MODE_DETECT)
+ return;
+
+ EGLint num_configs;
+ EGLConfig *config = nullptr;
+ bool supportsGL = false, supportsGLES2 = false, supportsGLES3 = false;
+
+ // attributes for a visual in RGBA format with at least
+ // 8 bits per color
+ int attribs[] = {
+ EGL_RED_SIZE, 8,
+ EGL_GREEN_SIZE, 8,
+ EGL_BLUE_SIZE, 8,
+ EGL_NONE };
+
+ // Get how many configs there are
+ if (!eglChooseConfig( egl_dpy, attribs, nullptr, 0, &num_configs))
+ {
+ INFO_LOG(VIDEO, "Error: couldn't get an EGL visual config\n");
+ goto err_exit;
+ }
+
+ config = new EGLConfig[num_configs];
+
+ // Get all the configurations
+ if (!eglChooseConfig(egl_dpy, attribs, config, num_configs, &num_configs))
+ {
+ INFO_LOG(VIDEO, "Error: couldn't get an EGL visual config\n");
+ goto err_exit;
+ }
+
+ for (int i = 0; i < num_configs; ++i)
+ {
+ EGLint attribVal;
+ bool ret;
+ ret = eglGetConfigAttrib(egl_dpy, config[i], EGL_RENDERABLE_TYPE, &attribVal);
+ if (ret)
+ {
+ if (attribVal & EGL_OPENGL_BIT)
+ supportsGL = true;
+ if (attribVal & (1 << 6)) /* EGL_OPENGL_ES3_BIT_KHR */
+ supportsGLES3 = true;
+ if (attribVal & EGL_OPENGL_ES2_BIT)
+ supportsGLES2 = true;
+ }
+ }
+ if (supportsGL)
+ s_opengl_mode = GLInterfaceMode::MODE_OPENGL;
+ else if (supportsGLES3)
+ s_opengl_mode = GLInterfaceMode::MODE_OPENGLES3;
+ else if (supportsGLES2)
+ s_opengl_mode = GLInterfaceMode::MODE_OPENGLES2;
+err_exit:
+ if (s_opengl_mode == GLInterfaceMode::MODE_DETECT) // Errored before we found a mode
+ s_opengl_mode = GLInterfaceMode::MODE_OPENGL; // Fall back to OpenGL
+ if (config)
+ delete[] config;
+}
+
+// Create rendering window.
+// Call browser: Core.cpp:EmuThread() > main.cpp:Video_Initialize()
+bool cInterfaceEGL::Create(void *window_handle)
+{
+ const char *s;
+ EGLint egl_major, egl_minor;
+
+ egl_dpy = OpenDisplay();
+
+ if (!egl_dpy)
+ {
+ INFO_LOG(VIDEO, "Error: eglGetDisplay() failed\n");
+ return false;
+ }
+
+ if (!eglInitialize(egl_dpy, &egl_major, &egl_minor))
+ {
+ INFO_LOG(VIDEO, "Error: eglInitialize() failed\n");
+ return false;
+ }
+
+ /* Detection code */
+ EGLConfig config;
+ EGLint num_configs;
+
+ DetectMode();
+
+ // attributes for a visual in RGBA format with at least
+ // 8 bits per color
+ int attribs[] = {
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL_RED_SIZE, 8,
+ EGL_GREEN_SIZE, 8,
+ EGL_BLUE_SIZE, 8,
+ EGL_NONE };
+
+ EGLint ctx_attribs[] = {
+ EGL_CONTEXT_CLIENT_VERSION, 2,
+ EGL_NONE
+ };
+ switch (s_opengl_mode)
+ {
+ case MODE_OPENGL:
+ attribs[1] = EGL_OPENGL_BIT;
+ ctx_attribs[0] = EGL_NONE;
+ break;
+ case MODE_OPENGLES2:
+ attribs[1] = EGL_OPENGL_ES2_BIT;
+ ctx_attribs[1] = 2;
+ break;
+ case MODE_OPENGLES3:
+ attribs[1] = (1 << 6); /* EGL_OPENGL_ES3_BIT_KHR */
+ ctx_attribs[1] = 3;
+ break;
+ default:
+ ERROR_LOG(VIDEO, "Unknown opengl mode set\n");
+ return false;
+ break;
+ }
+
+ if (!eglChooseConfig( egl_dpy, attribs, &config, 1, &num_configs))
+ {
+ INFO_LOG(VIDEO, "Error: couldn't get an EGL visual config\n");
+ exit(1);
+ }
+
+ if (s_opengl_mode == MODE_OPENGL)
+ eglBindAPI(EGL_OPENGL_API);
+ else
+ eglBindAPI(EGL_OPENGL_ES_API);
+
+ EGLNativeWindowType host_window = (EGLNativeWindowType) window_handle;
+ EGLNativeWindowType native_window = InitializePlatform(host_window, config);
+
+ s = eglQueryString(egl_dpy, EGL_VERSION);
+ INFO_LOG(VIDEO, "EGL_VERSION = %s\n", s);
+
+ s = eglQueryString(egl_dpy, EGL_VENDOR);
+ INFO_LOG(VIDEO, "EGL_VENDOR = %s\n", s);
+
+ s = eglQueryString(egl_dpy, EGL_EXTENSIONS);
+ INFO_LOG(VIDEO, "EGL_EXTENSIONS = %s\n", s);
+
+ s = eglQueryString(egl_dpy, EGL_CLIENT_APIS);
+ INFO_LOG(VIDEO, "EGL_CLIENT_APIS = %s\n", s);
+
+ egl_ctx = eglCreateContext(egl_dpy, config, EGL_NO_CONTEXT, ctx_attribs );
+ if (!egl_ctx)
+ {
+ INFO_LOG(VIDEO, "Error: eglCreateContext failed\n");
+ exit(1);
+ }
+
+ egl_surf = eglCreateWindowSurface(egl_dpy, config, native_window, nullptr);
+ if (!egl_surf)
+ {
+ INFO_LOG(VIDEO, "Error: eglCreateWindowSurface failed\n");
+ exit(1);
+ }
+
+ return true;
+}
+
+bool cInterfaceEGL::MakeCurrent()
+{
+ return eglMakeCurrent(egl_dpy, egl_surf, egl_surf, egl_ctx);
+}
+// Close backend
+void cInterfaceEGL::Shutdown()
+{
+ ShutdownPlatform();
+ if (egl_ctx && !eglMakeCurrent(egl_dpy, egl_surf, egl_surf, egl_ctx))
+ NOTICE_LOG(VIDEO, "Could not release drawing context.");
+ if (egl_ctx)
+ {
+ eglMakeCurrent(egl_dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ if (!eglDestroyContext(egl_dpy, egl_ctx))
+ NOTICE_LOG(VIDEO, "Could not destroy drawing context.");
+ if (!eglDestroySurface(egl_dpy, egl_surf))
+ NOTICE_LOG(VIDEO, "Could not destroy window surface.");
+ if (!eglTerminate(egl_dpy))
+ NOTICE_LOG(VIDEO, "Could not destroy display connection.");
+ egl_ctx = nullptr;
+ }
+}
diff --git a/Source/Core/VideoBackends/OGL/GLInterface/EGL.h b/Source/Core/VideoBackends/OGL/GLInterface/EGL.h
new file mode 100644
index 0000000000..1ed8ab59a0
--- /dev/null
+++ b/Source/Core/VideoBackends/OGL/GLInterface/EGL.h
@@ -0,0 +1,32 @@
+// Copyright 2014 Dolphin Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <string>
+#include <EGL/egl.h>
+
+#include "Core/ConfigManager.h"
+#include "VideoBackends/OGL/GLInterfaceBase.h"
+
+class cInterfaceEGL : public cInterfaceBase
+{
+protected:
+ void DetectMode();
+ EGLSurface egl_surf;
+ EGLContext egl_ctx;
+ EGLDisplay egl_dpy;
+
+ virtual EGLDisplay OpenDisplay() = 0;
+ virtual EGLNativeWindowType InitializePlatform(EGLNativeWindowType host_window, EGLConfig config) = 0;
+ virtual void ShutdownPlatform() = 0;
+public:
+ void SwapInterval(int Interval);
+ void Swap();
+ void SetMode(u32 mode) { s_opengl_mode = mode; }
+ void* GetFuncAddress(const std::string& name);
+ bool Create(void *window_handle);
+ bool MakeCurrent();
+ void Shutdown();
+};
diff --git a/Source/Core/VideoBackends/OGL/GLInterface/EGLAndroid.cpp b/Source/Core/VideoBackends/OGL/GLInterface/EGLAndroid.cpp
new file mode 100644
index 0000000000..f6c567ee6c
--- /dev/null
+++ b/Source/Core/VideoBackends/OGL/GLInterface/EGLAndroid.cpp
@@ -0,0 +1,29 @@
+// Copyright 2014 Dolphin Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#include "Core/Host.h"
+#include "VideoBackends/OGL/GLInterface/EGLAndroid.h"
+
+EGLDisplay cInterfaceEGLAndroid::OpenDisplay()
+{
+ return eglGetDisplay(EGL_DEFAULT_DISPLAY);
+}
+
+EGLNativeWindowType cInterfaceEGLAndroid::InitializePlatform(EGLNativeWindowType host_window, EGLConfig config)
+{
+ EGLint format;
+ eglGetConfigAttrib(egl_dpy, config, EGL_NATIVE_VISUAL_ID, &format);
+ ANativeWindow_setBuffersGeometry(host_window, 0, 0, format);
+
+ int none, width, height;
+ Host_GetRenderWindowSize(none, none, width, height);
+ GLInterface->SetBackBufferDimensions(width, height);
+
+ return host_window;
+}
+
+void cInterfaceEGLAndroid::ShutdownPlatform()
+{
+}
+
diff --git a/Source/Core/VideoBackends/OGL/GLInterface/EGLAndroid.h b/Source/Core/VideoBackends/OGL/GLInterface/EGLAndroid.h
new file mode 100644
index 0000000000..fe0b873759
--- /dev/null
+++ b/Source/Core/VideoBackends/OGL/GLInterface/EGLAndroid.h
@@ -0,0 +1,15 @@
+// Copyright 2014 Dolphin Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "VideoBackends/OGL/GLInterface/EGL.h"
+
+class cInterfaceEGLAndroid : public cInterfaceEGL
+{
+protected:
+ EGLDisplay OpenDisplay() override;
+ EGLNativeWindowType InitializePlatform(EGLNativeWindowType host_window, EGLConfig config) override;
+ void ShutdownPlatform() override;
+};
diff --git a/Source/Core/VideoBackends/OGL/GLInterface/EGLX11.cpp b/Source/Core/VideoBackends/OGL/GLInterface/EGLX11.cpp
new file mode 100644
index 0000000000..9b89d2fba2
--- /dev/null
+++ b/Source/Core/VideoBackends/OGL/GLInterface/EGLX11.cpp
@@ -0,0 +1,44 @@
+// Copyright 2014 Dolphin Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#include "VideoBackends/OGL/GLInterface/EGLX11.h"
+
+EGLDisplay cInterfaceEGLX11::OpenDisplay()
+{
+ dpy = XOpenDisplay(nullptr);
+ XWindow.Initialize(dpy);
+ return eglGetDisplay(dpy);
+}
+
+EGLNativeWindowType cInterfaceEGLX11::InitializePlatform(EGLNativeWindowType host_window, EGLConfig config)
+{
+ EGLint vid;
+ eglGetConfigAttrib(egl_dpy, config, EGL_NATIVE_VISUAL_ID, &vid);
+
+ XVisualInfo visTemplate;
+ visTemplate.visualid = vid;
+
+ XVisualInfo *vi;
+ int nVisuals;
+ vi = XGetVisualInfo(dpy, VisualIDMask, &visTemplate, &nVisuals);
+
+ XWindowAttributes attribs;
+ if (!XGetWindowAttributes(dpy, (Window)host_window, &attribs))
+ {
+ ERROR_LOG(VIDEO, "Window attribute retrieval failed");
+ return 0;
+ }
+
+ s_backbuffer_width = attribs.width;
+ s_backbuffer_height = attribs.height;
+
+ return (EGLNativeWindowType) XWindow.CreateXWindow((Window) host_window, vi);
+}
+
+void cInterfaceEGLX11::ShutdownPlatform()
+{
+ XWindow.DestroyXWindow();
+ XCloseDisplay(dpy);
+}
+
diff --git a/Source/Core/VideoBackends/OGL/GLInterface/EGLX11.h b/Source/Core/VideoBackends/OGL/GLInterface/EGLX11.h
new file mode 100644
index 0000000000..f858046e0d
--- /dev/null
+++ b/Source/Core/VideoBackends/OGL/GLInterface/EGLX11.h
@@ -0,0 +1,21 @@
+// Copyright 2014 Dolphin Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <X11/Xlib.h>
+
+#include "VideoBackends/OGL/GLInterface/EGL.h"
+#include "VideoBackends/OGL/GLInterface/X11_Util.h"
+
+class cInterfaceEGLX11 : public cInterfaceEGL
+{
+private:
+ cX11Window XWindow;
+ Display *dpy;
+protected:
+ EGLDisplay OpenDisplay() override;
+ EGLNativeWindowType InitializePlatform(EGLNativeWindowType host_window, EGLConfig config) override;
+ void ShutdownPlatform() override;
+};
diff --git a/Source/Core/VideoBackends/OGL/GLInterface/GLInterface.cpp b/Source/Core/VideoBackends/OGL/GLInterface/GLInterface.cpp
new file mode 100644
index 0000000000..29af99fa41
--- /dev/null
+++ b/Source/Core/VideoBackends/OGL/GLInterface/GLInterface.cpp
@@ -0,0 +1,40 @@
+// Copyright 2014 Dolphin Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#include "VideoBackends/OGL/GLInterfaceBase.h"
+
+#ifdef ANDROID
+#include "VideoBackends/OGL/GLInterface/EGLAndroid.h"
+#elif defined(__APPLE__)
+#include "VideoBackends/OGL/GLInterface/AGL.h"
+#elif defined(_WIN32)
+#include "VideoBackends/OGL/GLInterface/WGL.h"
+#elif HAVE_X11
+#if defined(USE_EGL) && USE_EGL
+#include "VideoBackends/OGL/GLInterface/EGLX11.h"
+#else
+#include "VideoBackends/OGL/GLInterface/GLX.h"
+#endif
+#else
+#error Platform doesnt have a GLInterface
+#endif
+
+cInterfaceBase* HostGL_CreateGLInterface()
+{
+ #ifdef ANDROID
+ return new cInterfaceEGLAndroid;
+ #elif defined(__APPLE__)
+ return new cInterfaceAGL;
+ #elif defined(_WIN32)
+ return new cInterfaceWGL;
+ #elif defined(HAVE_X11) && HAVE_X11
+ #if defined(USE_EGL) && USE_EGL
+ return new cInterfaceEGLX11;
+ #else
+ return new cInterfaceGLX;
+ #endif
+ #else
+ return nullptr;
+ #endif
+}
diff --git a/Source/Core/VideoBackends/OGL/GLInterface/GLX.cpp b/Source/Core/VideoBackends/OGL/GLInterface/GLX.cpp
new file mode 100644
index 0000000000..12912b0f5d
--- /dev/null
+++ b/Source/Core/VideoBackends/OGL/GLInterface/GLX.cpp
@@ -0,0 +1,145 @@
+// Copyright 2014 Dolphin Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#include <string>
+
+#include "VideoBackends/OGL/GLInterface/GLX.h"
+
+#include "VideoCommon/RenderBase.h"
+#include "VideoCommon/VideoConfig.h"
+
+typedef int ( * PFNGLXSWAPINTERVALSGIPROC) (int interval);
+static PFNGLXSWAPINTERVALSGIPROC glXSwapIntervalSGI = nullptr;
+
+void cInterfaceGLX::SwapInterval(int Interval)
+{
+ if (glXSwapIntervalSGI)
+ glXSwapIntervalSGI(Interval);
+ else
+ ERROR_LOG(VIDEO, "No support for SwapInterval (framerate clamped to monitor refresh rate).");
+}
+void* cInterfaceGLX::GetFuncAddress(const std::string& name)
+{
+ return (void*)glXGetProcAddress((const GLubyte*)name.c_str());
+}
+
+void cInterfaceGLX::Swap()
+{
+ glXSwapBuffers(dpy, win);
+}
+
+// Create rendering window.
+// Call browser: Core.cpp:EmuThread() > main.cpp:Video_Initialize()
+bool cInterfaceGLX::Create(void *window_handle)
+{
+ int glxMajorVersion, glxMinorVersion;
+
+ // attributes for a single buffered visual in RGBA format with at least
+ // 8 bits per color
+ int attrListSgl[] = {GLX_RGBA, GLX_RED_SIZE, 8,
+ GLX_GREEN_SIZE, 8,
+ GLX_BLUE_SIZE, 8,
+ None};
+
+ // attributes for a double buffered visual in RGBA format with at least
+ // 8 bits per color
+ int attrListDbl[] = {GLX_RGBA, GLX_DOUBLEBUFFER,
+ GLX_RED_SIZE, 8,
+ GLX_GREEN_SIZE, 8,
+ GLX_BLUE_SIZE, 8,
+ None };
+
+ int attrListDefault[] = {
+ GLX_RGBA,
+ GLX_RED_SIZE, 1,
+ GLX_GREEN_SIZE, 1,
+ GLX_BLUE_SIZE, 1,
+ GLX_DOUBLEBUFFER,
+ None };
+
+ dpy = XOpenDisplay(nullptr);
+ int screen = DefaultScreen(dpy);
+
+ glXQueryVersion(dpy, &glxMajorVersion, &glxMinorVersion);
+ NOTICE_LOG(VIDEO, "glX-Version %d.%d", glxMajorVersion, glxMinorVersion);
+
+ // Get an appropriate visual
+ vi = glXChooseVisual(dpy, screen, attrListDbl);
+ if (vi == nullptr)
+ {
+ vi = glXChooseVisual(dpy, screen, attrListSgl);
+ if (vi != nullptr)
+ {
+ ERROR_LOG(VIDEO, "Only single buffered visual!");
+ }
+ else
+ {
+ vi = glXChooseVisual(dpy, screen, attrListDefault);
+ if (vi == nullptr)
+ {
+ ERROR_LOG(VIDEO, "Could not choose visual (glXChooseVisual)");
+ return false;
+ }
+ }
+ }
+ else
+ {
+ NOTICE_LOG(VIDEO, "Got double buffered visual!");
+ }
+
+ // Create a GLX context.
+ ctx = glXCreateContext(dpy, vi, nullptr, GL_TRUE);
+ if (!ctx)
+ {
+ PanicAlert("Unable to create GLX context.");
+ return false;
+ }
+
+ XWindow.Initialize(dpy);
+
+ Window parent = (Window)window_handle;
+
+ XWindowAttributes attribs;
+ if (!XGetWindowAttributes(dpy, parent, &attribs))
+ {
+ ERROR_LOG(VIDEO, "Window attribute retrieval failed");
+ return false;
+ }
+
+ s_backbuffer_width = attribs.width;
+ s_backbuffer_height = attribs.height;
+
+ win = XWindow.CreateXWindow(parent, vi);
+ return true;
+}
+
+bool cInterfaceGLX::MakeCurrent()
+{
+ bool success = glXMakeCurrent(dpy, win, ctx);
+ if (success)
+ {
+ // load this function based on the current bound context
+ glXSwapIntervalSGI = (PFNGLXSWAPINTERVALSGIPROC)GLInterface->GetFuncAddress("glXSwapIntervalSGI");
+ }
+ return success;
+}
+
+bool cInterfaceGLX::ClearCurrent()
+{
+ return glXMakeCurrent(dpy, None, nullptr);
+}
+
+
+// Close backend
+void cInterfaceGLX::Shutdown()
+{
+ XWindow.DestroyXWindow();
+ if (ctx)
+ {
+ glXDestroyContext(dpy, ctx);
+ XCloseDisplay(dpy);
+ ctx = nullptr;
+ }
+}
+
diff --git a/Source/Core/VideoBackends/OGL/GLInterface/GLX.h b/Source/Core/VideoBackends/OGL/GLInterface/GLX.h
new file mode 100644
index 0000000000..fa97efdabf
--- /dev/null
+++ b/Source/Core/VideoBackends/OGL/GLInterface/GLX.h
@@ -0,0 +1,30 @@
+// Copyright 2014 Dolphin Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <string>
+#include <GL/glx.h>
+
+#include "VideoBackends/OGL/GLInterfaceBase.h"
+#include "VideoBackends/OGL/GLInterface/X11_Util.h"
+
+class cInterfaceGLX : public cInterfaceBase
+{
+private:
+ cX11Window XWindow;
+ Display *dpy;
+ Window win;
+ GLXContext ctx;
+ XVisualInfo *vi;
+public:
+ friend class cX11Window;
+ void SwapInterval(int Interval) override;
+ void Swap() override;
+ void* GetFuncAddress(const std::string& name) override;
+ bool Create(void *window_handle);
+ bool MakeCurrent() override;
+ bool ClearCurrent() override;
+ void Shutdown() override;
+};
diff --git a/Source/Core/VideoBackends/OGL/GLInterface/WGL.cpp b/Source/Core/VideoBackends/OGL/GLInterface/WGL.cpp
new file mode 100644
index 0000000000..232eb7ec71
--- /dev/null
+++ b/Source/Core/VideoBackends/OGL/GLInterface/WGL.cpp
@@ -0,0 +1,182 @@
+// Copyright 2013 Dolphin Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#include <string>
+
+#include "Core/Host.h"
+
+#include "VideoBackends/OGL/GLInterface/WGL.h"
+
+#include "VideoCommon/RenderBase.h"
+#include "VideoCommon/VertexShaderManager.h"
+#include "VideoCommon/VideoConfig.h"
+
+static HDC hDC = nullptr; // Private GDI Device Context
+static HGLRC hRC = nullptr; // Permanent Rendering Context
+static HINSTANCE dllHandle = nullptr; // Handle to OpenGL32.dll
+
+// typedef from wglext.h
+typedef BOOL(WINAPI * PFNWGLSWAPINTERVALEXTPROC) (int interval);
+static PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = nullptr;
+
+void cInterfaceWGL::SwapInterval(int Interval)
+{
+ if (wglSwapIntervalEXT)
+ wglSwapIntervalEXT(Interval);
+ else
+ ERROR_LOG(VIDEO, "No support for SwapInterval (framerate clamped to monitor refresh rate).");
+}
+void cInterfaceWGL::Swap()
+{
+ SwapBuffers(hDC);
+}
+
+void* cInterfaceWGL::GetFuncAddress(const std::string& name)
+{
+ void* func = (void*)wglGetProcAddress((LPCSTR)name.c_str());
+ if (func == nullptr)
+ func = (void*)GetProcAddress(dllHandle, (LPCSTR)name.c_str());
+ return func;
+}
+
+// Draw messages on top of the screen
+bool cInterfaceWGL::PeekMessages()
+{
+ // TODO: peekmessage
+ MSG msg;
+ while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
+ {
+ if (msg.message == WM_QUIT)
+ return FALSE;
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ return TRUE;
+}
+
+// Create rendering window.
+// Call browser: Core.cpp:EmuThread() > main.cpp:Video_Initialize()
+bool cInterfaceWGL::Create(void *window_handle)
+{
+ if (window_handle == nullptr)
+ return false;
+
+ HWND window_handle_reified = reinterpret_cast<HWND>(window_handle);
+ RECT window_rect = {0};
+
+ if (!GetClientRect(window_handle_reified, &window_rect))
+ return false;
+
+ // Control window size and picture scaling
+ int twidth = (window_rect.right - window_rect.left);
+ int theight = (window_rect.bottom - window_rect.top);
+ s_backbuffer_width = twidth;
+ s_backbuffer_height = theight;
+
+ m_window_handle = window_handle_reified;
+
+#ifdef _WIN32
+ dllHandle = LoadLibrary(TEXT("OpenGL32.dll"));
+#endif
+
+ PIXELFORMATDESCRIPTOR pfd = // pfd Tells Windows How We Want Things To Be
+ {
+ sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor
+ 1, // Version Number
+ PFD_DRAW_TO_WINDOW | // Format Must Support Window
+ PFD_SUPPORT_OPENGL | // Format Must Support OpenGL
+ PFD_DOUBLEBUFFER, // Must Support Double Buffering
+ PFD_TYPE_RGBA, // Request An RGBA Format
+ 32, // Select Our Color Depth
+ 0, 0, 0, 0, 0, 0, // Color Bits Ignored
+ 0, // 8bit Alpha Buffer
+ 0, // Shift Bit Ignored
+ 0, // No Accumulation Buffer
+ 0, 0, 0, 0, // Accumulation Bits Ignored
+ 0, // 0Bit Z-Buffer (Depth Buffer)
+ 0, // 0bit Stencil Buffer
+ 0, // No Auxiliary Buffer
+ PFD_MAIN_PLANE, // Main Drawing Layer
+ 0, // Reserved
+ 0, 0, 0 // Layer Masks Ignored
+ };
+
+ int PixelFormat; // Holds The Results After Searching For A Match
+
+ if (!(hDC = GetDC(window_handle_reified)))
+ {
+ PanicAlert("(1) Can't create an OpenGL Device context. Fail.");
+ return false;
+ }
+
+ if (!(PixelFormat = ChoosePixelFormat(hDC, &pfd)))
+ {
+ PanicAlert("(2) Can't find a suitable PixelFormat.");
+ return false;
+ }
+
+ if (!SetPixelFormat(hDC, PixelFormat, &pfd))
+ {
+ PanicAlert("(3) Can't set the PixelFormat.");
+ return false;
+ }
+
+ if (!(hRC = wglCreateContext(hDC)))
+ {
+ PanicAlert("(4) Can't create an OpenGL rendering context.");
+ return false;
+ }
+
+ return true;
+}
+
+bool cInterfaceWGL::MakeCurrent()
+{
+ bool success = wglMakeCurrent(hDC, hRC) ? true : false;
+ if (success)
+ {
+ // Grab the swap interval function pointer
+ wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)GLInterface->GetFuncAddress("wglSwapIntervalEXT");
+ }
+ return success;
+}
+
+bool cInterfaceWGL::ClearCurrent()
+{
+ return wglMakeCurrent(hDC, nullptr) ? true : false;
+}
+
+// Update window width, size and etc. Called from Render.cpp
+void cInterfaceWGL::Update()
+{
+ RECT rcWindow;
+ GetClientRect(m_window_handle, &rcWindow);
+
+ // Get the new window width and height
+ s_backbuffer_width = (rcWindow.right - rcWindow.left);
+ s_backbuffer_height = (rcWindow.bottom - rcWindow.top);
+}
+
+// Close backend
+void cInterfaceWGL::Shutdown()
+{
+ if (hRC)
+ {
+ if (!wglMakeCurrent(nullptr, nullptr))
+ NOTICE_LOG(VIDEO, "Could not release drawing context.");
+
+ if (!wglDeleteContext(hRC))
+ ERROR_LOG(VIDEO, "Attempt to release rendering context failed.");
+
+ hRC = nullptr;
+ }
+
+ if (hDC && !ReleaseDC(m_window_handle, hDC))
+ {
+ ERROR_LOG(VIDEO, "Attempt to release device context failed.");
+ hDC = nullptr;
+ }
+}
+
+
diff --git a/Source/Core/VideoBackends/OGL/GLInterface/WGL.h b/Source/Core/VideoBackends/OGL/GLInterface/WGL.h
new file mode 100644
index 0000000000..ea0c22c9d1
--- /dev/null
+++ b/Source/Core/VideoBackends/OGL/GLInterface/WGL.h
@@ -0,0 +1,25 @@
+// Copyright 2013 Dolphin Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <string>
+#include "VideoBackends/OGL/GLInterfaceBase.h"
+
+class cInterfaceWGL : public cInterfaceBase
+{
+public:
+ void SwapInterval(int Interval);
+ void Swap();
+ void* GetFuncAddress(const std::string& name);
+ bool Create(void *window_handle);
+ bool MakeCurrent();
+ bool ClearCurrent();
+ void Shutdown();
+
+ void Update();
+ bool PeekMessages();
+
+ HWND m_window_handle;
+};
diff --git a/Source/Core/VideoBackends/OGL/GLInterface/X11Utils.cpp b/Source/Core/VideoBackends/OGL/GLInterface/X11Utils.cpp
new file mode 100644
index 0000000000..7832269e27
--- /dev/null
+++ b/Source/Core/VideoBackends/OGL/GLInterface/X11Utils.cpp
@@ -0,0 +1,278 @@
+// Copyright 2014 Dolphin Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#include <spawn.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+#include "Common/Logging/Log.h"
+#include "Core/ConfigManager.h"
+#include "Core/Core.h"
+#include "Core/CoreParameter.h"
+#include "VideoBackends/OGL/GLInterface/X11Utils.h"
+
+extern char **environ;
+
+#if defined(HAVE_WX) && HAVE_WX
+#include <algorithm>
+#include <string>
+
+#include "DolphinWX/WxUtils.h"
+#endif
+
+namespace X11Utils
+{
+
+void ToggleFullscreen(Display *dpy, Window win)
+{
+ // Init X event structure for _NET_WM_STATE_FULLSCREEN client message
+ XEvent event;
+ event.xclient.type = ClientMessage;
+ event.xclient.message_type = XInternAtom(dpy, "_NET_WM_STATE", False);
+ event.xclient.window = win;
+ event.xclient.format = 32;
+ event.xclient.data.l[0] = _NET_WM_STATE_TOGGLE;
+ event.xclient.data.l[1] = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
+
+ // Send the event
+ if (!XSendEvent(dpy, DefaultRootWindow(dpy), False,
+ SubstructureRedirectMask | SubstructureNotifyMask, &event))
+ ERROR_LOG(VIDEO, "Failed to switch fullscreen/windowed mode.");
+}
+
+void InhibitScreensaver(Display *dpy, Window win, bool suspend)
+{
+ char id[11];
+ snprintf(id, sizeof(id), "0x%lx", win);
+
+ // Call xdg-screensaver
+ char *argv[4] = {
+ (char *)"xdg-screensaver",
+ (char *)(suspend ? "suspend" : "resume"),
+ id,
+ nullptr};
+ pid_t pid;
+ if (!posix_spawnp(&pid, "xdg-screensaver", nullptr, nullptr, argv, environ))
+ {
+ int status;
+ while (waitpid (pid, &status, 0) == -1);
+
+ DEBUG_LOG(VIDEO, "Started xdg-screensaver (PID = %d)", (int)pid);
+ }
+}
+
+#if defined(HAVE_XRANDR) && HAVE_XRANDR
+XRRConfiguration::XRRConfiguration(Display *_dpy, Window _win)
+ : dpy(_dpy)
+ , win(_win)
+ , screenResources(nullptr), outputInfo(nullptr), crtcInfo(nullptr)
+ , fullMode(0)
+ , fs_fb_width(0), fs_fb_height(0), fs_fb_width_mm(0), fs_fb_height_mm(0)
+ , bValid(true), bIsFullscreen(false)
+{
+ int XRRMajorVersion, XRRMinorVersion;
+
+ if (!XRRQueryVersion(dpy, &XRRMajorVersion, &XRRMinorVersion) ||
+ (XRRMajorVersion < 1 || (XRRMajorVersion == 1 && XRRMinorVersion < 3)))
+ {
+ WARN_LOG(VIDEO, "XRRExtension not supported.");
+ bValid = false;
+ return;
+ }
+
+ screenResources = XRRGetScreenResourcesCurrent(dpy, win);
+
+ screen = DefaultScreen(dpy);
+ fb_width = DisplayWidth(dpy, screen);
+ fb_height = DisplayHeight(dpy, screen);
+ fb_width_mm = DisplayWidthMM(dpy, screen);
+ fb_height_mm = DisplayHeightMM(dpy, screen);
+
+ INFO_LOG(VIDEO, "XRRExtension-Version %d.%d", XRRMajorVersion, XRRMinorVersion);
+ Update();
+}
+
+XRRConfiguration::~XRRConfiguration()
+{
+ if (bValid && bIsFullscreen)
+ ToggleDisplayMode(False);
+ if (screenResources)
+ XRRFreeScreenResources(screenResources);
+ if (outputInfo)
+ XRRFreeOutputInfo(outputInfo);
+ if (crtcInfo)
+ XRRFreeCrtcInfo(crtcInfo);
+}
+
+void XRRConfiguration::Update()
+{
+ if (SConfig::GetInstance().m_LocalCoreStartupParameter.strFullscreenResolution == "Auto")
+ return;
+
+ if (!bValid)
+ return;
+
+ if (outputInfo)
+ {
+ XRRFreeOutputInfo(outputInfo);
+ outputInfo = nullptr;
+ }
+ if (crtcInfo)
+ {
+ XRRFreeCrtcInfo(crtcInfo);
+ crtcInfo = nullptr;
+ }
+ fullMode = 0;
+
+ // Get the resolution setings for fullscreen mode
+ unsigned int fullWidth, fullHeight;
+ char *output_name = nullptr;
+ if (SConfig::GetInstance().m_LocalCoreStartupParameter.strFullscreenResolution.find(':') ==
+ std::string::npos)
+ {
+ fullWidth = fb_width;
+ fullHeight = fb_height;
+ }
+ else
+ {
+ sscanf(SConfig::GetInstance().m_LocalCoreStartupParameter.strFullscreenResolution.c_str(),
+ "%m[^:]: %ux%u", &output_name, &fullWidth, &fullHeight);
+ }
+
+ for (int i = 0; i < screenResources->noutput; i++)
+ {
+ XRROutputInfo *output_info = XRRGetOutputInfo(dpy, screenResources, screenResources->outputs[i]);
+ if (output_info && output_info->crtc && output_info->connection == RR_Connected)
+ {
+ XRRCrtcInfo *crtc_info = XRRGetCrtcInfo(dpy, screenResources, output_info->crtc);
+ if (crtc_info)
+ {
+ if (!output_name || !strcmp(output_name, output_info->name))
+ {
+ // Use the first output for the default setting.
+ if (!output_name)
+ {
+ output_name = strdup(output_info->name);
+ SConfig::GetInstance().m_LocalCoreStartupParameter.strFullscreenResolution =
+ StringFromFormat("%s: %ux%u", output_info->name, fullWidth, fullHeight);
+ }
+ outputInfo = output_info;
+ crtcInfo = crtc_info;
+ for (int j = 0; j < output_info->nmode && fullMode == 0; j++)
+ {
+ for (int k = 0; k < screenResources->nmode && fullMode == 0; k++)
+ {
+ if (output_info->modes[j] == screenResources->modes[k].id)
+ {
+ if (fullWidth == screenResources->modes[k].width &&
+ fullHeight == screenResources->modes[k].height)
+ {
+ fullMode = screenResources->modes[k].id;
+ if (crtcInfo->x + (int)screenResources->modes[k].width > fs_fb_width)
+ fs_fb_width = crtcInfo->x + screenResources->modes[k].width;
+ if (crtcInfo->y + (int)screenResources->modes[k].height > fs_fb_height)
+ fs_fb_height = crtcInfo->y + screenResources->modes[k].height;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ if (crtc_info->x + (int)crtc_info->width > fs_fb_width)
+ fs_fb_width = crtc_info->x + crtc_info->width;
+ if (crtc_info->y + (int)crtc_info->height > fs_fb_height)
+ fs_fb_height = crtc_info->y + crtc_info->height;
+ }
+ }
+ if (crtc_info && crtcInfo != crtc_info)
+ XRRFreeCrtcInfo(crtc_info);
+ }
+ if (output_info && outputInfo != output_info)
+ XRRFreeOutputInfo(output_info);
+ }
+ fs_fb_width_mm = fs_fb_width * DisplayHeightMM(dpy, screen) / DisplayHeight(dpy, screen);
+ fs_fb_height_mm = fs_fb_height * DisplayHeightMM(dpy, screen) / DisplayHeight(dpy, screen);
+
+ if (output_name)
+ free(output_name);
+
+ if (outputInfo && crtcInfo && fullMode)
+ {
+ INFO_LOG(VIDEO, "Fullscreen Resolution %dx%d", fullWidth, fullHeight);
+ }
+ else
+ {
+ ERROR_LOG(VIDEO, "Failed to obtain fullscreen size.\n"
+ "Using current desktop resolution for fullscreen.");
+ }
+}
+
+void XRRConfiguration::ToggleDisplayMode(bool bFullscreen)
+{
+ if (!bValid || !screenResources || !outputInfo || !crtcInfo || !fullMode)
+ return;
+ if (bFullscreen == bIsFullscreen)
+ return;
+
+ XGrabServer(dpy);
+ if (bFullscreen)
+ {
+ XRRSetCrtcConfig(dpy, screenResources, outputInfo->crtc, CurrentTime,
+ crtcInfo->x, crtcInfo->y, fullMode, crtcInfo->rotation,
+ crtcInfo->outputs, crtcInfo->noutput);
+ XRRSetScreenSize(dpy, win, fs_fb_width, fs_fb_height, fs_fb_width_mm, fs_fb_height_mm);
+ bIsFullscreen = true;
+ }
+ else
+ {
+ XRRSetCrtcConfig(dpy, screenResources, outputInfo->crtc, CurrentTime,
+ crtcInfo->x, crtcInfo->y, crtcInfo->mode, crtcInfo->rotation,
+ crtcInfo->outputs, crtcInfo->noutput);
+ XRRSetScreenSize(dpy, win, fb_width, fb_height, fb_width_mm, fb_height_mm);
+ bIsFullscreen = false;
+ }
+ XUngrabServer(dpy);
+ XSync(dpy, false);
+}
+
+void XRRConfiguration::AddResolutions(std::vector<std::string>& resos)
+{
+ if (!bValid || !screenResources)
+ return;
+
+ //Get all full screen resolutions for the config dialog
+ for (int i = 0; i < screenResources->noutput; i++)
+ {
+ XRROutputInfo *output_info =
+ XRRGetOutputInfo(dpy, screenResources, screenResources->outputs[i]);
+
+ if (output_info && output_info->crtc && output_info->connection == RR_Connected)
+ {
+ for (int j = 0; j < output_info->nmode; j++)
+ {
+ for (int k = 0; k < screenResources->nmode; k++)
+ {
+ if (output_info->modes[j] == screenResources->modes[k].id)
+ {
+ const std::string strRes =
+ std::string(output_info->name) + ": " +
+ std::string(screenResources->modes[k].name);
+ // Only add unique resolutions
+ if (std::find(resos.begin(), resos.end(), strRes) == resos.end())
+ {
+ resos.push_back(strRes);
+ }
+ }
+ }
+ }
+ }
+ if (output_info)
+ XRRFreeOutputInfo(output_info);
+ }
+}
+
+#endif
+
+}
diff --git a/Source/Core/VideoBackends/OGL/GLInterface/X11Utils.h b/Source/Core/VideoBackends/OGL/GLInterface/X11Utils.h
new file mode 100644
index 0000000000..b68a1babe6
--- /dev/null
+++ b/Source/Core/VideoBackends/OGL/GLInterface/X11Utils.h
@@ -0,0 +1,71 @@
+// Copyright 2014 Dolphin Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#pragma once
+
+// HACK: Xlib.h (included from gtk/gdk headers and directly) uses #defines on
+// common names such as "Status", "BadRequest" or "Response", causing SFML
+// headers to be completely broken.
+//
+// We work around that issue by including SFML first before X11 headers. This
+// is terrible, but such is the life with Xlib.
+#include <SFML/Network.hpp> // NOLINT
+
+#if defined(HAVE_WX) && HAVE_WX
+#include <gtk/gtk.h>
+#include <gdk/gdkx.h>
+#include <wx/arrstr.h>
+#endif
+
+#if defined(HAVE_XRANDR) && HAVE_XRANDR
+#include <X11/extensions/Xrandr.h>
+#endif
+#include <X11/X.h>
+#include <X11/Xlib.h>
+
+
+// EWMH state actions, see
+// http://freedesktop.org/wiki/Specifications/wm-spec?action=show&redirect=Standards%2Fwm-spec
+#define _NET_WM_STATE_REMOVE 0 // remove/unset property
+#define _NET_WM_STATE_ADD 1 // add/set property
+#define _NET_WM_STATE_TOGGLE 2 // toggle property
+
+namespace X11Utils
+{
+
+void ToggleFullscreen(Display *dpy, Window win);
+#if defined(HAVE_WX) && HAVE_WX
+Window XWindowFromHandle(void *Handle);
+Display *XDisplayFromHandle(void *Handle);
+#endif
+
+void InhibitScreensaver(Display *dpy, Window win, bool suspend);
+
+#if defined(HAVE_XRANDR) && HAVE_XRANDR
+class XRRConfiguration
+{
+ public:
+ XRRConfiguration(Display *_dpy, Window _win);
+ ~XRRConfiguration();
+
+ void Update();
+ void ToggleDisplayMode(bool bFullscreen);
+ void AddResolutions(std::vector<std::string>& resos);
+
+ private:
+ Display *dpy;
+ Window win;
+ int screen;
+ XRRScreenResources *screenResources;
+ XRROutputInfo *outputInfo;
+ XRRCrtcInfo *crtcInfo;
+ RRMode fullMode;
+ int fb_width, fb_height, fb_width_mm, fb_height_mm;
+ int fs_fb_width, fs_fb_height, fs_fb_width_mm, fs_fb_height_mm;
+ bool bValid;
+ bool bIsFullscreen;
+};
+#endif
+
+}
diff --git a/Source/Core/VideoBackends/OGL/GLInterface/X11_Util.cpp b/Source/Core/VideoBackends/OGL/GLInterface/X11_Util.cpp
new file mode 100644
index 0000000000..ffc48550bb
--- /dev/null
+++ b/Source/Core/VideoBackends/OGL/GLInterface/X11_Util.cpp
@@ -0,0 +1,75 @@
+// Copyright 2014 Dolphin Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#include "Common/Thread.h"
+#include "Core/Host.h"
+#include "VideoBackends/OGL/GLInterfaceBase.h"
+#include "VideoBackends/OGL/GLInterface/X11_Util.h"
+#include "VideoCommon/VideoConfig.h"
+
+void cX11Window::Initialize(Display *_dpy)
+{
+ dpy = _dpy;
+}
+
+Window cX11Window::CreateXWindow(Window parent, XVisualInfo *vi)
+{
+ XSetWindowAttributes attr;
+
+ colormap = XCreateColormap(dpy, parent, vi->visual, AllocNone);
+
+ // Setup window attributes
+ attr.colormap = colormap;
+
+ XWindowAttributes attribs;
+ if (!XGetWindowAttributes(dpy, parent, &attribs))
+ {
+ ERROR_LOG(VIDEO, "Window attribute retrieval failed");
+ return 0;
+ }
+
+ // Create the window
+ win = XCreateWindow(dpy, parent,
+ 0, 0, attribs.width, attribs.height, 0,
+ vi->depth, InputOutput, vi->visual,
+ CWColormap, &attr);
+ XSelectInput(dpy, parent, StructureNotifyMask);
+ XMapWindow(dpy, win);
+ XSync(dpy, True);
+
+ xEventThread = std::thread(&cX11Window::XEventThread, this);
+
+ return win;
+}
+
+void cX11Window::DestroyXWindow(void)
+{
+ XUnmapWindow(dpy, win);
+ win = 0;
+ if (xEventThread.joinable())
+ xEventThread.join();
+ XFreeColormap(dpy, colormap);
+}
+
+void cX11Window::XEventThread()
+{
+ while (win)
+ {
+ XEvent event;
+ for (int num_events = XPending(dpy); num_events > 0; num_events--)
+ {
+ XNextEvent(dpy, &event);
+ switch (event.type)
+ {
+ case ConfigureNotify:
+ XResizeWindow(dpy, win, event.xconfigure.width, event.xconfigure.height);
+ GLInterface->SetBackBufferDimensions(event.xconfigure.width, event.xconfigure.height);
+ break;
+ default:
+ break;
+ }
+ }
+ Common::SleepCurrentThread(20);
+ }
+}
diff --git a/Source/Core/VideoBackends/OGL/GLInterface/X11_Util.h b/Source/Core/VideoBackends/OGL/GLInterface/X11_Util.h
new file mode 100644
index 0000000000..1facad52aa
--- /dev/null
+++ b/Source/Core/VideoBackends/OGL/GLInterface/X11_Util.h
@@ -0,0 +1,26 @@
+// Copyright 2013 Dolphin Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <string>
+#include <thread>
+#include <X11/keysym.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+class cX11Window
+{
+private:
+ void XEventThread();
+ std::thread xEventThread;
+ Colormap colormap;
+public:
+ void Initialize(Display *dpy);
+ Window CreateXWindow(Window parent, XVisualInfo *vi);
+ void DestroyXWindow();
+
+ Display *dpy;
+ Window win;
+};