Move GL interface code out of the OpenGL video backend.

This commit is contained in:
Scott Mansell
2015-09-19 04:40:00 +12:00
parent 3df83e5717
commit 95f3c956a8
83 changed files with 367 additions and 323 deletions

View File

@ -0,0 +1,109 @@
// Copyright 2012 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "Common/GL/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, bool core)
{
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, core ? NSOpenGLProfileVersion3_2Core : NSOpenGLProfileVersionLegacy, 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];
}

View File

@ -0,0 +1,27 @@
// Copyright 2008 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#ifdef __APPLE__
#import <AppKit/AppKit.h>
#endif
#include "Common/GL/GLInterfaceBase.h"
class cInterfaceAGL : public cInterfaceBase
{
private:
NSView *cocoaWin;
NSOpenGLContext *cocoaCtx;
public:
void Swap();
bool Create(void *window_handle, bool core);
bool MakeCurrent();
bool ClearCurrent();
void Shutdown();
void Update();
void SwapInterval(int interval);
};

View File

@ -0,0 +1,227 @@
// Copyright 2012 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "Common/GL/GLInterfaceBase.h"
#include "Common/GL/GLInterface/EGL.h"
#include "VideoCommon/DriverDetails.h"
#include "VideoCommon/RenderBase.h"
// Show the current FPS
void cInterfaceEGL::Swap()
{
eglSwapBuffers(egl_dpy, egl_surf);
}
void cInterfaceEGL::SwapInterval(int Interval)
{
if (!DriverDetails::HasBug(DriverDetails::BUG_BROKENVSYNC))
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;
bool supportsGL = false, supportsGLES2 = false, supportsGLES3 = false;
std::array<int, 3> renderable_types = {
EGL_OPENGL_BIT,
(1 << 6), /* EGL_OPENGL_ES3_BIT_KHR */
EGL_OPENGL_ES2_BIT,
};
for (auto renderable_type : renderable_types)
{
// 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_RENDERABLE_TYPE, renderable_type,
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");
continue;
}
EGLConfig* 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");
delete[] config;
continue;
}
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;
}
}
delete[] config;
}
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;
if (s_opengl_mode == GLInterfaceMode::MODE_DETECT) // Errored before we found a mode
s_opengl_mode = GLInterfaceMode::MODE_OPENGL; // Fall back to OpenGL
}
// Create rendering window.
// Call browser: Core.cpp:EmuThread() > main.cpp:Video_Initialize()
bool cInterfaceEGL::Create(void *window_handle, bool core)
{
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);
}
bool cInterfaceEGL::ClearCurrent()
{
return eglMakeCurrent(egl_dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
}
// 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;
}
}

View File

@ -0,0 +1,33 @@
// Copyright 2008 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <string>
#include <EGL/egl.h>
#include "Common/GL/GLInterfaceBase.h"
#include "Core/ConfigManager.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 core);
bool MakeCurrent();
bool ClearCurrent();
void Shutdown();
};

View File

@ -0,0 +1,29 @@
// Copyright 2014 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "Common/GL/GLInterface/EGLAndroid.h"
#include "Core/Host.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);
const int width = ANativeWindow_getWidth(host_window);
const int height = ANativeWindow_getHeight(host_window);
GLInterface->SetBackBufferDimensions(width, height);
return host_window;
}
void cInterfaceEGLAndroid::ShutdownPlatform()
{
}

View File

@ -0,0 +1,15 @@
// Copyright 2014 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include "Common/GL/GLInterface/EGL.h"
class cInterfaceEGLAndroid : public cInterfaceEGL
{
protected:
EGLDisplay OpenDisplay() override;
EGLNativeWindowType InitializePlatform(EGLNativeWindowType host_window, EGLConfig config) override;
void ShutdownPlatform() override;
};

View File

@ -0,0 +1,44 @@
// Copyright 2014 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "Common/GL/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);
}

View File

@ -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 "Common/GL/GLInterface/EGL.h"
#include "Common/GL/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;
};

View File

@ -0,0 +1,40 @@
// Copyright 2014 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "Common/GL/GLInterfaceBase.h"
#ifdef ANDROID
#include "Common/GL/GLInterface/EGLAndroid.h"
#elif defined(__APPLE__)
#include "Common/GL/GLInterface/AGL.h"
#elif defined(_WIN32)
#include "Common/GL/GLInterface/WGL.h"
#elif HAVE_X11
#if defined(USE_EGL) && USE_EGL
#include "Common/GL/GLInterface/EGLX11.h"
#else
#include "Common/GL/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
}

View File

@ -0,0 +1,199 @@
// Copyright 2012 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <string>
#include "Common/GL/GLInterface/GLX.h"
#include "VideoCommon/RenderBase.h"
#include "VideoCommon/VideoConfig.h"
#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091
#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092
typedef GLXContext (*PFNGLXCREATECONTEXTATTRIBSPROC)(Display*, GLXFBConfig, GLXContext, Bool, const int*);
typedef int ( * PFNGLXSWAPINTERVALSGIPROC) (int interval);
static PFNGLXCREATECONTEXTATTRIBSPROC glXCreateContextAttribs = nullptr;
static PFNGLXSWAPINTERVALSGIPROC glXSwapIntervalSGI = nullptr;
static bool s_glxError;
static int ctxErrorHandler(Display *dpy, XErrorEvent *ev)
{
s_glxError = true;
return 0;
}
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, bool core)
{
dpy = XOpenDisplay(nullptr);
int screen = DefaultScreen(dpy);
// checking glx version
int glxMajorVersion, glxMinorVersion;
glXQueryVersion(dpy, &glxMajorVersion, &glxMinorVersion);
if (glxMajorVersion < 1 || (glxMajorVersion == 1 && glxMinorVersion < 4))
{
ERROR_LOG(VIDEO, "glX-Version %d.%d detected, but need at least 1.4",
glxMajorVersion, glxMinorVersion);
return false;
}
// loading core context creation function
glXCreateContextAttribs = (PFNGLXCREATECONTEXTATTRIBSPROC)GetFuncAddress("glXCreateContextAttribsARB");
if (!glXCreateContextAttribs)
{
ERROR_LOG(VIDEO, "glXCreateContextAttribsARB not found, do you support GLX_ARB_create_context?");
return false;
}
// choosing framebuffer
int visual_attribs[] =
{
GLX_X_RENDERABLE , True,
GLX_DRAWABLE_TYPE , GLX_WINDOW_BIT,
GLX_X_VISUAL_TYPE , GLX_TRUE_COLOR,
GLX_RED_SIZE , 8,
GLX_GREEN_SIZE , 8,
GLX_BLUE_SIZE , 8,
GLX_DEPTH_SIZE , 0,
GLX_STENCIL_SIZE , 0,
GLX_DOUBLEBUFFER , True,
None
};
int fbcount = 0;
GLXFBConfig* fbc = glXChooseFBConfig(dpy, screen, visual_attribs, &fbcount);
if (!fbc || !fbcount)
{
ERROR_LOG(VIDEO, "Failed to retrieve a framebuffer config");
return false;
}
fbconfig = *fbc;
XFree(fbc);
// Get an appropriate visual
XVisualInfo* vi = glXGetVisualFromFBConfig(dpy, fbconfig);
s_glxError = false;
XErrorHandler oldHandler = XSetErrorHandler(&ctxErrorHandler);
// Create a GLX context.
// We try to get a 4.0 core profile, else we try 3.3, else try it with anything we get.
int context_attribs[] =
{
GLX_CONTEXT_MAJOR_VERSION_ARB, 4,
GLX_CONTEXT_MINOR_VERSION_ARB, 0,
GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
None
};
ctx = nullptr;
if (core)
{
ctx = glXCreateContextAttribs(dpy, fbconfig, 0, True, context_attribs);
XSync(dpy, False);
}
if (core && (!ctx || s_glxError))
{
int context_attribs_33[] =
{
GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
GLX_CONTEXT_MINOR_VERSION_ARB, 3,
GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
None
};
s_glxError = false;
ctx = glXCreateContextAttribs(dpy, fbconfig, 0, True, context_attribs_33);
XSync(dpy, False);
}
if (!ctx || s_glxError)
{
int context_attribs_legacy[] =
{
GLX_CONTEXT_MAJOR_VERSION_ARB, 1,
GLX_CONTEXT_MINOR_VERSION_ARB, 0,
None
};
s_glxError = false;
ctx = glXCreateContextAttribs(dpy, fbconfig, 0, True, context_attribs_legacy);
XSync(dpy, False);
}
if (!ctx || s_glxError)
{
ERROR_LOG(VIDEO, "Unable to create GL context.");
return false;
}
XSetErrorHandler(oldHandler);
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);
XFree(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;
}
}

View File

@ -0,0 +1,30 @@
// Copyright 2008 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <string>
#include <GL/glx.h>
#include "Common/GL/GLInterfaceBase.h"
#include "Common/GL/GLInterface/X11_Util.h"
class cInterfaceGLX : public cInterfaceBase
{
private:
cX11Window XWindow;
Display *dpy;
Window win;
GLXContext ctx;
GLXFBConfig fbconfig;
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 core) override;
bool MakeCurrent() override;
bool ClearCurrent() override;
void Shutdown() override;
};

View File

@ -0,0 +1,182 @@
// Copyright 2012 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <string>
#include "Common/GL/GLInterface/WGL.h"
#include "Core/Host.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, bool core)
{
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;
}
}

View File

@ -0,0 +1,25 @@
// Copyright 2008 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <string>
#include "Common/GL/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 core);
bool MakeCurrent();
bool ClearCurrent();
void Shutdown();
void Update();
bool PeekMessages();
HWND m_window_handle;
};

View File

@ -0,0 +1,77 @@
// Copyright 2012 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "Common/Thread.h"
#include "Common/GL/GLInterfaceBase.h"
#include "Common/GL/GLInterface/X11_Util.h"
#include "Core/Host.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);
}
}

View File

@ -0,0 +1,26 @@
// Copyright 2008 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;
};