@@ -0,0 +1,126 @@
// Copyright 2014 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.

#include <memory>

#include "Common/GL/GLContext.h"

#if defined(__APPLE__)
#include "Common/GL/GLInterface/AGL.h"
#endif
#if defined(WIN32)
#include "Common/GL/GLInterface/WGL.h"
#endif
#if HAVE_X11
#include "Common/GL/GLInterface/GLX.h"
#endif
#if HAVE_EGL
#include "Common/GL/GLInterface/EGL.h"
#if HAVE_X11
#include "Common/GL/GLInterface/EGLX11.h"
#endif
#if defined(ANDROID)
#include "Common/GL/GLInterface/EGLAndroid.h"
#endif
#endif

const std::array<std::pair<int, int>, 9> GLContext::s_desktop_opengl_versions = {
{{4, 6}, {4, 5}, {4, 4}, {4, 3}, {4, 2}, {4, 1}, {4, 0}, {3, 3}, {3, 2}}};

GLContext::~GLContext() = default;

bool GLContext::Initialize(void* display_handle, void* window_handle, bool stereo, bool core)
{
return false;
}

bool GLContext::IsHeadless() const
{
return true;
}

std::unique_ptr<GLContext> GLContext::CreateSharedContext()
{
return nullptr;
}

bool GLContext::MakeCurrent()
{
return false;
}

bool GLContext::ClearCurrent()
{
return false;
}

void GLContext::Update()
{
}

void GLContext::UpdateSurface(void* window_handle)
{
}

void GLContext::Swap()
{
}

void GLContext::SwapInterval(int interval)
{
}

void* GLContext::GetFuncAddress(const std::string& name)
{
return nullptr;
}

std::unique_ptr<GLContext> GLContext::Create(const WindowSystemInfo& wsi, bool stereo, bool core,
bool prefer_egl, bool prefer_gles)
{
std::unique_ptr<GLContext> context;
#if defined(__APPLE__)
if (wsi.type == WindowSystemType::MacOS || wsi.type == WindowSystemType::Headless)
context = std::make_unique<GLContextAGL>();
#endif
#if defined(_WIN32)
if (wsi.type == WindowSystemType::Windows)
context = std::make_unique<GLContextWGL>();
#endif
#if defined(ANDROID)
if (wsi.type == WindowSystemType::Android)
context = std::make_unique<GLContextEGLAndroid>();
#endif
#if HAVE_X11
if (wsi.type == WindowSystemType::X11)
{
// GLES 3 is not supported via GLX.
const bool use_egl = prefer_egl || prefer_gles;
#if defined(HAVE_EGL)
if (use_egl)
context = std::make_unique<GLContextEGLX11>();
else
context = std::make_unique<GLContextGLX>();
#else
context = std::make_unique<GLContextGLX>();
#endif
}
#endif
#if HAVE_EGL
if (wsi.type == WindowSystemType::Headless)
context = std::make_unique<GLContextEGL>();
#endif

if (!context)
return nullptr;

// Option to prefer GLES on desktop platforms, useful for testing.
if (prefer_gles)
context->m_opengl_mode = Mode::OpenGLES;

if (!context->Initialize(wsi.display_connection, wsi.render_surface, stereo, core))
return nullptr;

return context;
}
@@ -0,0 +1,67 @@
// Copyright 2008 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.

#pragma once

#include <array>
#include <memory>
#include <string>
#include <utility>

#include "Common/CommonTypes.h"
#include "Common/WindowSystemInfo.h"

class GLContext
{
public:
enum class Mode
{
Detect,
OpenGL,
OpenGLES
};

virtual ~GLContext();

Mode GetMode() { return m_opengl_mode; }
bool IsGLES() const { return m_opengl_mode == Mode::OpenGLES; }

u32 GetBackBufferWidth() { return m_backbuffer_width; }
u32 GetBackBufferHeight() { return m_backbuffer_height; }

virtual bool IsHeadless() const;

virtual std::unique_ptr<GLContext> CreateSharedContext();

virtual bool MakeCurrent();
virtual bool ClearCurrent();

virtual void Update();
virtual void UpdateSurface(void* window_handle);

virtual void Swap();
virtual void SwapInterval(int interval);

virtual void* GetFuncAddress(const std::string& name);

// Creates an instance of GLContext specific to the platform we are running on.
// If successful, the context is made current on the calling thread.
static std::unique_ptr<GLContext> Create(const WindowSystemInfo& wsi, bool stereo = false,
bool core = true, bool prefer_egl = false,
bool prefer_gles = false);

protected:
virtual bool Initialize(void* display_handle, void* window_handle, bool stereo, bool core);

Mode m_opengl_mode = Mode::Detect;

// Window dimensions.
u32 m_backbuffer_width = 0;
u32 m_backbuffer_height = 0;
bool m_is_shared = false;

// A list of desktop OpenGL versions to attempt to create a context for.
// (4.6-3.2, geometry shaders is a minimum requirement since we're using core profile).
static const std::array<std::pair<int, int>, 9> s_desktop_opengl_versions;
};
@@ -5,8 +5,8 @@
#include <sstream>
#include <unordered_map>

#include "Common/GL/GLContext.h"
#include "Common/GL/GLExtensions/GLExtensions.h"
#include "Common/GL/GLInterfaceBase.h"
#include "Common/Logging/Log.h"

#if defined(__linux__) || defined(__APPLE__)
@@ -2148,12 +2148,11 @@ const GLFunc gl_function_array[] = {
namespace GLExtensions
{
// Private members and functions
static bool _isES;
static u32 _GLVersion;
static std::unordered_map<std::string, bool> m_extension_list;
static u32 s_gl_version;
static std::unordered_map<std::string, bool> s_extension_list;

// Private initialization functions
bool InitFunctionPointers();
bool InitFunctionPointers(GLContext* context);

// Initializes the extension list the old way
static void InitExtensionList21()
@@ -2163,28 +2162,28 @@ static void InitExtensionList21()
std::istringstream buffer(tmp);

while (buffer >> tmp)
m_extension_list[tmp] = true;
s_extension_list[tmp] = true;
}

static void InitExtensionList()
static void InitExtensionList(GLContext* context)
{
m_extension_list.clear();
if (_isES)
s_extension_list.clear();
if (context->IsGLES())
{
switch (_GLVersion)
switch (s_gl_version)
{
default:
case 320:
m_extension_list["VERSION_GLES_3_2"] = true;
s_extension_list["VERSION_GLES_3_2"] = true;
case 310:
m_extension_list["VERSION_GLES_3_1"] = true;
s_extension_list["VERSION_GLES_3_1"] = true;
case 300:
m_extension_list["VERSION_GLES_3"] = true;
s_extension_list["VERSION_GLES_3"] = true;
break;
}

// We always have ES 2.0
m_extension_list["VERSION_GLES_2"] = true;
s_extension_list["VERSION_GLES_2"] = true;
}
else
{
@@ -2194,7 +2193,7 @@ static void InitExtensionList()
// When an extension got merged in to core, the naming may have changed

// This has intentional fall through
switch (_GLVersion)
switch (s_gl_version)
{
default:
case 450:
@@ -2213,7 +2212,7 @@ static void InitExtensionList()
"VERSION_4_5",
};
for (auto it : gl450exts)
m_extension_list[it] = true;
s_extension_list[it] = true;
}
case 440:
{
@@ -2229,7 +2228,7 @@ static void InitExtensionList()
"VERSION_4_4",
};
for (auto it : gl440exts)
m_extension_list[it] = true;
s_extension_list[it] = true;
}
case 430:
{
@@ -2257,7 +2256,7 @@ static void InitExtensionList()
"VERSION_4_3",
};
for (auto it : gl430exts)
m_extension_list[it] = true;
s_extension_list[it] = true;
}
case 420:
{
@@ -2277,7 +2276,7 @@ static void InitExtensionList()
"VERSION_4_2",
};
for (auto it : gl420exts)
m_extension_list[it] = true;
s_extension_list[it] = true;
}
case 410:
{
@@ -2291,7 +2290,7 @@ static void InitExtensionList()
"VERSION_4_1",
};
for (auto it : gl410exts)
m_extension_list[it] = true;
s_extension_list[it] = true;
}
case 400:
{
@@ -2311,7 +2310,7 @@ static void InitExtensionList()
"VERSION_4_0",
};
for (auto it : gl400exts)
m_extension_list[it] = true;
s_extension_list[it] = true;
}
case 330:
{
@@ -2329,7 +2328,7 @@ static void InitExtensionList()
"VERSION_3_3",
};
for (auto it : gl330exts)
m_extension_list[it] = true;
s_extension_list[it] = true;
}
case 320:
{
@@ -2346,7 +2345,7 @@ static void InitExtensionList()
"VERSION_3_2",
};
for (auto it : gl320exts)
m_extension_list[it] = true;
s_extension_list[it] = true;
}
case 310:
{
@@ -2361,7 +2360,7 @@ static void InitExtensionList()
"VERSION_3_1",
};
for (auto it : gl310exts)
m_extension_list[it] = true;
s_extension_list[it] = true;
}
case 300:
{
@@ -2392,7 +2391,7 @@ static void InitExtensionList()
"VERSION_3_0",
};
for (auto it : gl300exts)
m_extension_list[it] = true;
s_extension_list[it] = true;
}
case 210:
case 200:
@@ -2406,33 +2405,33 @@ static void InitExtensionList()
break;
}
// So we can easily determine if we are running dekstop GL
m_extension_list["VERSION_GL"] = true;
s_extension_list["VERSION_GL"] = true;
}

if (_GLVersion < 300)
if (s_gl_version < 300)
{
InitExtensionList21();
return;
}
GLint NumExtension = 0;
glGetIntegerv(GL_NUM_EXTENSIONS, &NumExtension);
for (GLint i = 0; i < NumExtension; ++i)
m_extension_list[std::string((const char*)glGetStringi(GL_EXTENSIONS, i))] = true;
s_extension_list[std::string((const char*)glGetStringi(GL_EXTENSIONS, i))] = true;
}
static void InitVersion()
{
GLint major, minor;
glGetIntegerv(GL_MAJOR_VERSION, &major);
glGetIntegerv(GL_MINOR_VERSION, &minor);
if (glGetError() == GL_NO_ERROR)
_GLVersion = major * 100 + minor * 10;
s_gl_version = major * 100 + minor * 10;
else
_GLVersion = 210;
s_gl_version = 210;
}

static void* GetFuncAddress(const std::string& name, void** func)
static void* GetFuncAddress(GLContext* context, const std::string& name, void** func)
{
*func = GLInterface->GetFuncAddress(name);
*func = context->GetFuncAddress(name);
if (*func == nullptr)
{
#if defined(__linux__) || defined(__APPLE__)
@@ -2448,37 +2447,36 @@ static void* GetFuncAddress(const std::string& name, void** func)
// Public members
u32 Version()
{
return _GLVersion;
return s_gl_version;
}
bool Supports(const std::string& name)
{
return m_extension_list[name];
return s_extension_list[name];
}

bool Init()
bool Init(GLContext* context)
{
_isES = GLInterface->GetMode() != GLInterfaceMode::MODE_OPENGL;

// Grab a few functions for initial checking
// We need them to grab the extension list
// Also to check if there is an error grabbing the version
if (GetFuncAddress("glGetIntegerv", (void**)&glGetIntegerv) == nullptr)
if (GetFuncAddress(context, "glGetIntegerv", (void**)&glGetIntegerv) == nullptr)
return false;
if (GetFuncAddress("glGetString", (void**)&glGetString) == nullptr)
if (GetFuncAddress(context, "glGetString", (void**)&glGetString) == nullptr)
return false;
if (GetFuncAddress("glGetError", (void**)&glGetError) == nullptr)
if (GetFuncAddress(context, "glGetError", (void**)&glGetError) == nullptr)
return false;

InitVersion();

// We need to use glGetStringi to get the extension list
// if we are using GLES3 or a GL version greater than 2.1
if (_GLVersion > 210 && GetFuncAddress("glGetStringi", (void**)&glGetStringi) == nullptr)
if (s_gl_version > 210 &&
GetFuncAddress(context, "glGetStringi", (void**)&glGetStringi) == nullptr)
return false;

InitExtensionList();
InitExtensionList(context);

return InitFunctionPointers();
return InitFunctionPointers(context);
}

// Private initialization functions
@@ -2491,20 +2489,20 @@ static bool HasFeatures(const std::string& extensions)
while (buffer >> tmp)
{
if (tmp[0] == '!')
result &= !m_extension_list[tmp.erase(0, 1)];
result &= !s_extension_list[tmp.erase(0, 1)];
else if (tmp[0] == '|')
result |= m_extension_list[tmp.erase(0, 1)];
result |= s_extension_list[tmp.erase(0, 1)];
else
result &= m_extension_list[tmp];
result &= s_extension_list[tmp];
}
return result;
}
bool InitFunctionPointers()
bool InitFunctionPointers(GLContext* context)
{
bool result = true;
for (const auto& it : gl_function_array)
if (HasFeatures(it.requirements))
result &= !!GetFuncAddress(it.function_name, it.function_ptr);
result &= !!GetFuncAddress(context, it.function_name, it.function_ptr);
return result;
}
}
} // namespace GLExtensions
@@ -54,15 +54,17 @@
#include "Common/GL/GLExtensions/gl_4_4.h"
#include "Common/GL/GLExtensions/gl_4_5.h"

class GLContext;

namespace GLExtensions
{
// Initializes the interface
bool Init();
bool Init(GLContext* context);

// Function for checking if the hardware supports an extension
// example: if (GLExtensions::Supports("GL_ARB_multi_map"))
bool Supports(const std::string& name);

// Returns OpenGL version in format 430
u32 Version();
}
} // namespace GLExtensions
@@ -12,22 +12,28 @@ struct NSOpenGLPixelFormat;
struct NSView;
#endif

#include "Common/GL/GLInterfaceBase.h"
#include "Common/GL/GLContext.h"

class cInterfaceAGL : public cInterfaceBase
class GLContextAGL final : public GLContext
{
public:
void Swap() override;
bool Create(void* window_handle, bool stereo, bool core) override;
bool Create(cInterfaceBase* main_context) override;
~GLContextAGL() override;

bool IsHeadless() const override;

std::unique_ptr<GLContext> CreateSharedContext() override;

bool MakeCurrent() override;
bool ClearCurrent() override;
void Shutdown() override;

void Update() override;

void Swap() override;
void SwapInterval(int interval) override;
std::unique_ptr<cInterfaceBase> CreateSharedContext() override;

private:
protected:
bool Initialize(void* display_handle, void* window_handle, bool stereo, bool core) override;

NSView* m_view = nullptr;
NSOpenGLContext* m_context = nullptr;
NSOpenGLPixelFormat* m_pixel_format = nullptr;
@@ -10,16 +10,15 @@ static bool UpdateCachedDimensions(NSView* view, u32* width, u32* height)
NSWindow* window = [view window];
NSSize size = [view frame].size;

float scale = [window backingScaleFactor];
size.width *= scale;
size.height *= scale;
const CGFloat scale = [window backingScaleFactor];
u32 new_width = static_cast<u32>(size.width * scale);
u32 new_height = static_cast<u32>(size.height * scale);

if (*width == size.width && *height == size.height)
if (*width == new_width && *height == new_height)
return false;

*width = size.width;
*height = size.height;

*width = new_width;
*height = new_height;
return true;
}

@@ -44,14 +43,33 @@ static bool AttachContextToView(NSOpenGLContext* context, NSView* view, u32* wid
return true;
}

void cInterfaceAGL::Swap()
GLContextAGL::~GLContextAGL()
{
if ([NSOpenGLContext currentContext] == m_context)
[NSOpenGLContext clearCurrentContext];

if (m_context)
{
[m_context clearDrawable];
[m_context release];
}
if (m_pixel_format)
[m_pixel_format release];
}

bool GLContextAGL::IsHeadless() const
{
return !m_view;
}

void GLContextAGL::Swap()
{
[m_context flushBuffer];
}

// Create rendering window.
// Call browser: Core.cpp:EmuThread() > main.cpp:Video_Initialize()
bool cInterfaceAGL::Create(void* window_handle, bool stereo, bool core)
bool GLContextAGL::Initialize(void* display_handle, void* window_handle, bool stereo, bool core)
{
NSOpenGLPixelFormatAttribute attr[] = {
NSOpenGLPFADoubleBuffer,
@@ -78,65 +96,54 @@ static bool AttachContextToView(NSOpenGLContext* context, NSView* view, u32* wid
return true;

m_view = static_cast<NSView*>(window_handle);
return AttachContextToView(m_context, m_view, &s_backbuffer_width, &s_backbuffer_height);
}

bool cInterfaceAGL::Create(cInterfaceBase* main_context)
{
cInterfaceAGL* agl_context = static_cast<cInterfaceAGL*>(main_context);
NSOpenGLPixelFormat* pixel_format = agl_context->m_pixel_format;
NSOpenGLContext* share_context = agl_context->m_context;

m_context = [[NSOpenGLContext alloc] initWithFormat:pixel_format shareContext:share_context];
if (m_context == nil)
{
ERROR_LOG(VIDEO, "failed to create shared context");
m_opengl_mode = Mode::OpenGL;
if (!AttachContextToView(m_context, m_view, &m_backbuffer_width, &m_backbuffer_height))
return false;
}

[m_context makeCurrentContext];
return true;
}

std::unique_ptr<cInterfaceBase> cInterfaceAGL::CreateSharedContext()
std::unique_ptr<GLContext> GLContextAGL::CreateSharedContext()
{
std::unique_ptr<cInterfaceBase> context = std::make_unique<cInterfaceAGL>();
if (!context->Create(this))
NSOpenGLContext* new_agl_context =
[[NSOpenGLContext alloc] initWithFormat:m_pixel_format shareContext:m_context];
if (new_agl_context == nil)
{
ERROR_LOG(VIDEO, "failed to create shared context");
return nullptr;
return context;
}

std::unique_ptr<GLContextAGL> new_context = std::make_unique<GLContextAGL>();
new_context->m_context = new_agl_context;
new_context->m_pixel_format = m_pixel_format;
[new_context->m_pixel_format retain];
new_context->m_is_shared = true;
return new_context;
}

bool cInterfaceAGL::MakeCurrent()
bool GLContextAGL::MakeCurrent()
{
[m_context makeCurrentContext];
return true;
}

bool cInterfaceAGL::ClearCurrent()
bool GLContextAGL::ClearCurrent()
{
[NSOpenGLContext clearCurrentContext];
return true;
}

// Close backend
void cInterfaceAGL::Shutdown()
{
[m_context clearDrawable];
[m_context release];
m_context = nil;
[m_pixel_format release];
m_pixel_format = nil;
}

void cInterfaceAGL::Update()
void GLContextAGL::Update()
{
if (!m_view)
return;

if (UpdateCachedDimensions(m_view, &s_backbuffer_width, &s_backbuffer_height))
if (UpdateCachedDimensions(m_view, &m_backbuffer_width, &m_backbuffer_height))
[m_context update];
}

void cInterfaceAGL::SwapInterval(int interval)
void GLContextAGL::SwapInterval(int interval)
{
[m_context setValues:static_cast<GLint*>(&interval) forParameter:NSOpenGLCPSwapInterval];
}

This file was deleted.

This file was deleted.

Large diffs are not rendered by default.

@@ -9,44 +9,46 @@
#include <string>
#include <vector>

#include "Common/GL/GLInterfaceBase.h"
#include "Common/GL/GLContext.h"

class cInterfaceEGL : public cInterfaceBase
class GLContextEGL : public GLContext
{
private:
EGLConfig m_config;
bool m_has_handle;
EGLNativeWindowType m_host_window;
bool m_supports_surfaceless = false;
std::vector<int> m_attribs;
public:
virtual ~GLContextEGL() override;

bool CreateWindowSurface();
void DestroyWindowSurface();
bool IsHeadless() const override;

protected:
void DetectMode();
EGLSurface egl_surf;
EGLContext egl_ctx;
EGLDisplay egl_dpy;

virtual EGLDisplay OpenDisplay() { return eglGetDisplay(EGL_DEFAULT_DISPLAY); }
virtual EGLNativeWindowType InitializePlatform(EGLNativeWindowType host_window, EGLConfig config)
{
return (EGLNativeWindowType)EGL_DEFAULT_DISPLAY;
}
virtual void ShutdownPlatform() {}
std::unique_ptr<GLContext> CreateSharedContext() override;

bool MakeCurrent() override;
bool ClearCurrent() override;

void UpdateSurface(void* window_handle) override;

public:
void Swap() override;
void SwapInterval(int interval) override;
void SetMode(GLInterfaceMode mode) override { s_opengl_mode = mode; }

void* GetFuncAddress(const std::string& name) override;
bool Create(void* window_handle, bool stereo, bool core) override;
bool Create(cInterfaceBase* main_context) override;
bool MakeCurrent() override;
bool ClearCurrent() override;
void Shutdown() override;
void UpdateHandle(void* window_handle) override;
void UpdateSurface() override;
std::unique_ptr<cInterfaceBase> CreateSharedContext() override;

protected:
virtual EGLDisplay OpenEGLDisplay();
virtual EGLNativeWindowType GetEGLNativeWindow(EGLConfig config);

bool Initialize(void* display_handle, void* window_handle, bool stereo, bool core) override;

bool CreateWindowSurface();
void DestroyWindowSurface();
void DetectMode(bool has_handle);
void DestroyContext();

void* m_host_display = nullptr;
void* m_host_window = nullptr;

EGLConfig m_config;
bool m_supports_surfaceless = false;
std::vector<int> m_attribs;

EGLSurface m_egl_surface = EGL_NO_SURFACE;
EGLContext m_egl_context = EGL_NO_CONTEXT;
EGLDisplay m_egl_display = EGL_NO_DISPLAY;
};
@@ -3,26 +3,19 @@
// Refer to the license.txt file included.

#include "Common/GL/GLInterface/EGLAndroid.h"
#include <android/native_window.h>

EGLDisplay cInterfaceEGLAndroid::OpenDisplay()
EGLDisplay GLContextEGLAndroid::OpenEGLDisplay()
{
return eglGetDisplay(EGL_DEFAULT_DISPLAY);
}

EGLNativeWindowType cInterfaceEGLAndroid::InitializePlatform(EGLNativeWindowType host_window,
EGLConfig config)
EGLNativeWindowType GLContextEGLAndroid::GetEGLNativeWindow(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()
{
eglGetConfigAttrib(m_egl_display, config, EGL_NATIVE_VISUAL_ID, &format);
ANativeWindow_setBuffersGeometry(static_cast<ANativeWindow*>(m_host_window), 0, 0, format);
m_backbuffer_width = ANativeWindow_getWidth(static_cast<ANativeWindow*>(m_host_window));
m_backbuffer_height = ANativeWindow_getHeight(static_cast<ANativeWindow*>(m_host_window));
return static_cast<EGLNativeWindowType>(m_host_window);
}
@@ -4,14 +4,11 @@

#pragma once

#include <android/native_window.h>
#include "Common/GL/GLInterface/EGL.h"

class cInterfaceEGLAndroid : public cInterfaceEGL
class GLContextEGLAndroid final : public GLContextEGL
{
protected:
EGLDisplay OpenDisplay() override;
EGLNativeWindowType InitializePlatform(EGLNativeWindowType host_window,
EGLConfig config) override;
void ShutdownPlatform() override;
EGLDisplay OpenEGLDisplay() override;
EGLNativeWindowType GetEGLNativeWindow(EGLConfig config) override;
};

This file was deleted.

This file was deleted.

@@ -3,43 +3,48 @@
// Refer to the license.txt file included.

#include "Common/GL/GLInterface/EGLX11.h"
#include "Common/Logging/Log.h"

EGLDisplay cInterfaceEGLX11::OpenDisplay()
GLContextEGLX11::~GLContextEGLX11()
{
dpy = XOpenDisplay(nullptr);
XWindow.Initialize(dpy);
return eglGetDisplay(dpy);
// The context must be destroyed before the window.
DestroyWindowSurface();
DestroyContext();
m_render_window.reset();
}

EGLNativeWindowType cInterfaceEGLX11::InitializePlatform(EGLNativeWindowType host_window,
EGLConfig config)
void GLContextEGLX11::Update()
{
m_render_window->UpdateDimensions();
m_backbuffer_width = m_render_window->GetWidth();
m_backbuffer_height = m_render_window->GetHeight();
}

EGLDisplay GLContextEGLX11::OpenEGLDisplay()
{
return eglGetDisplay(static_cast<Display*>(m_host_display));
}

EGLNativeWindowType GLContextEGLX11::GetEGLNativeWindow(EGLConfig config)
{
EGLint vid;
eglGetConfigAttrib(egl_dpy, config, EGL_NATIVE_VISUAL_ID, &vid);
eglGetConfigAttrib(m_egl_display, config, EGL_NATIVE_VISUAL_ID, &vid);

XVisualInfo visTemplate;
XVisualInfo visTemplate = {};
visTemplate.visualid = vid;

XVisualInfo* vi;
int nVisuals;
vi = XGetVisualInfo(dpy, VisualIDMask, &visTemplate, &nVisuals);
XVisualInfo* vi =
XGetVisualInfo(static_cast<Display*>(m_host_display), VisualIDMask, &visTemplate, &nVisuals);

XWindowAttributes attribs;
if (!XGetWindowAttributes(dpy, (Window)host_window, &attribs))
{
ERROR_LOG(VIDEO, "Window attribute retrieval failed");
return 0;
}
if (m_render_window)
m_render_window.reset();

s_backbuffer_width = attribs.width;
s_backbuffer_height = attribs.height;
m_render_window = GLX11Window::Create(static_cast<Display*>(m_host_display),
reinterpret_cast<Window>(m_host_window), vi);
m_backbuffer_width = m_render_window->GetWidth();
m_backbuffer_height = m_render_window->GetHeight();

return (EGLNativeWindowType)XWindow.CreateXWindow((Window)host_window, vi);
}
XFree(vi);

void cInterfaceEGLX11::ShutdownPlatform()
{
XWindow.DestroyXWindow();
XCloseDisplay(dpy);
return reinterpret_cast<EGLNativeWindowType>(m_render_window->GetWindow());
}
@@ -7,17 +7,18 @@
#include <X11/Xlib.h>

#include "Common/GL/GLInterface/EGL.h"
#include "Common/GL/GLInterface/X11_Util.h"
#include "Common/GL/GLX11Window.h"

class cInterfaceEGLX11 : public cInterfaceEGL
class GLContextEGLX11 final : public GLContextEGL
{
private:
cX11Window XWindow;
Display* dpy;
public:
~GLContextEGLX11() override;

void Update() override;

protected:
EGLDisplay OpenDisplay() override;
EGLNativeWindowType InitializePlatform(EGLNativeWindowType host_window,
EGLConfig config) override;
void ShutdownPlatform() override;
EGLDisplay OpenEGLDisplay() override;
EGLNativeWindowType GetEGLNativeWindow(EGLConfig config) override;

std::unique_ptr<GLX11Window> m_render_window;
};

This file was deleted.

@@ -30,43 +30,57 @@ static int ctxErrorHandler(Display* dpy, XErrorEvent* ev)
return 0;
}

void cInterfaceGLX::SwapInterval(int Interval)
GLContextGLX::~GLContextGLX()
{
if (!m_has_handle)
DestroyWindowSurface();
if (m_context)
{
if (glXGetCurrentContext() == m_context)
glXMakeCurrent(m_display, None, nullptr);

glXDestroyContext(m_display, m_context);
}
}

bool GLContextGLX::IsHeadless() const
{
return !m_render_window;
}

void GLContextGLX::SwapInterval(int Interval)
{
if (!m_drawable)
return;

// Try EXT_swap_control, then MESA_swap_control.
if (glXSwapIntervalEXTPtr)
glXSwapIntervalEXTPtr(dpy, win, Interval);
glXSwapIntervalEXTPtr(m_display, m_drawable, Interval);
else if (glXSwapIntervalMESAPtr)
glXSwapIntervalMESAPtr(static_cast<unsigned int>(Interval));
else
ERROR_LOG(VIDEO, "No support for SwapInterval (framerate clamped to monitor refresh rate).");
}

void* cInterfaceGLX::GetFuncAddress(const std::string& name)
void* GLContextGLX::GetFuncAddress(const std::string& name)
{
return (void*)glXGetProcAddress((const GLubyte*)name.c_str());
return reinterpret_cast<void*>(glXGetProcAddress(reinterpret_cast<const GLubyte*>(name.c_str())));
}

void cInterfaceGLX::Swap()
void GLContextGLX::Swap()
{
glXSwapBuffers(dpy, win);
glXSwapBuffers(m_display, m_drawable);
}

// Create rendering window.
// Call browser: Core.cpp:EmuThread() > main.cpp:Video_Initialize()
bool cInterfaceGLX::Create(void* window_handle, bool stereo, bool core)
bool GLContextGLX::Initialize(void* display_handle, void* window_handle, bool stereo, bool core)
{
m_has_handle = !!window_handle;
m_host_window = (Window)window_handle;

dpy = XOpenDisplay(nullptr);
int screen = DefaultScreen(dpy);
m_display = static_cast<Display*>(display_handle);
int screen = DefaultScreen(m_display);

// checking glx version
int glxMajorVersion, glxMinorVersion;
glXQueryVersion(dpy, &glxMajorVersion, &glxMinorVersion);
glXQueryVersion(m_display, &glxMajorVersion, &glxMinorVersion);
if (glxMajorVersion < 1 || (glxMajorVersion == 1 && glxMinorVersion < 4))
{
ERROR_LOG(VIDEO, "glX-Version %d.%d detected, but need at least 1.4", glxMajorVersion,
@@ -107,54 +121,53 @@ bool cInterfaceGLX::Create(void* window_handle, bool stereo, bool core)
stereo ? True : False,
None};
int fbcount = 0;
GLXFBConfig* fbc = glXChooseFBConfig(dpy, screen, visual_attribs, &fbcount);
GLXFBConfig* fbc = glXChooseFBConfig(m_display, screen, visual_attribs, &fbcount);
if (!fbc || !fbcount)
{
ERROR_LOG(VIDEO, "Failed to retrieve a framebuffer config");
return false;
}
fbconfig = *fbc;
m_fbconfig = *fbc;
XFree(fbc);

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.
std::array<int, 9> 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[0]);
XSync(dpy, False);
m_attribs.insert(m_attribs.end(), context_attribs.begin(), context_attribs.end());
}
if (core && (!ctx || s_glxError))
{
std::array<int, 9> 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[0]);
XSync(dpy, False);
m_attribs.clear();
m_attribs.insert(m_attribs.end(), context_attribs_33.begin(), context_attribs_33.end());
for (const auto& version : s_desktop_opengl_versions)
{
std::array<int, 9> context_attribs = {
{GLX_CONTEXT_MAJOR_VERSION_ARB, version.first, GLX_CONTEXT_MINOR_VERSION_ARB,
version.second, 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;
m_context = glXCreateContextAttribs(m_display, m_fbconfig, 0, True, &context_attribs[0]);
XSync(m_display, False);
m_attribs.insert(m_attribs.end(), context_attribs.begin(), context_attribs.end());
if (!m_context || s_glxError)
continue;

// Got a context.
INFO_LOG(VIDEO, "Created a GLX context with version %d.%d", version.first, version.second);
break;
}
}
if (!ctx || s_glxError)

// Failed to create any core contexts, try for anything.
if (!m_context || s_glxError)
{
std::array<int, 5> 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[0]);
XSync(dpy, False);
m_context = glXCreateContextAttribs(m_display, m_fbconfig, 0, True, &context_attribs_legacy[0]);
XSync(m_display, False);
m_attribs.clear();
m_attribs.insert(m_attribs.end(), context_attribs_legacy.begin(), context_attribs_legacy.end());
}
if (!ctx || s_glxError)
if (!m_context || s_glxError)
{
ERROR_LOG(VIDEO, "Unable to create GL context.");
XSetErrorHandler(oldHandler);
@@ -168,7 +181,7 @@ bool cInterfaceGLX::Create(void* window_handle, bool stereo, bool core)
m_supports_pbuffer = false;

std::string tmp;
std::istringstream buffer(glXQueryExtensionsString(dpy, screen));
std::istringstream buffer(glXQueryExtensionsString(m_display, screen));
while (buffer >> tmp)
{
if (tmp == "GLX_SGIX_pbuffer")
@@ -191,127 +204,103 @@ bool cInterfaceGLX::Create(void* window_handle, bool stereo, bool core)
}
}

if (!CreateWindowSurface())
if (!CreateWindowSurface(reinterpret_cast<Window>(window_handle)))
{
ERROR_LOG(VIDEO, "Error: CreateWindowSurface failed\n");
XSetErrorHandler(oldHandler);
return false;
}

XSetErrorHandler(oldHandler);
return true;
m_opengl_mode = Mode::OpenGL;
return MakeCurrent();
}

bool cInterfaceGLX::Create(cInterfaceBase* main_context)
std::unique_ptr<GLContext> GLContextGLX::CreateSharedContext()
{
cInterfaceGLX* glx_context = static_cast<cInterfaceGLX*>(main_context);

m_has_handle = false;
m_supports_pbuffer = glx_context->m_supports_pbuffer;
dpy = glx_context->dpy;
fbconfig = glx_context->fbconfig;
s_glxError = false;
XErrorHandler oldHandler = XSetErrorHandler(&ctxErrorHandler);

ctx = glXCreateContextAttribs(dpy, fbconfig, glx_context->ctx, True, &glx_context->m_attribs[0]);
XSync(dpy, False);
GLXContext new_glx_context =
glXCreateContextAttribs(m_display, m_fbconfig, m_context, True, &m_attribs[0]);
XSync(m_display, False);

if (!ctx || s_glxError)
if (!new_glx_context || s_glxError)
{
ERROR_LOG(VIDEO, "Unable to create GL context.");
XSetErrorHandler(oldHandler);
return false;
return nullptr;
}

if (m_supports_pbuffer && !CreateWindowSurface())
std::unique_ptr<GLContextGLX> new_context = std::make_unique<GLContextGLX>();
new_context->m_context = new_glx_context;
new_context->m_opengl_mode = m_opengl_mode;
new_context->m_supports_pbuffer = m_supports_pbuffer;
new_context->m_display = m_display;
new_context->m_fbconfig = m_fbconfig;
new_context->m_is_shared = true;

if (m_supports_pbuffer && !new_context->CreateWindowSurface(None))
{
ERROR_LOG(VIDEO, "Error: CreateWindowSurface failed\n");
ERROR_LOG(VIDEO, "Error: CreateWindowSurface failed");
XSetErrorHandler(oldHandler);
return false;
return nullptr;
}

XSetErrorHandler(oldHandler);
return true;
return new_context;
}

std::unique_ptr<cInterfaceBase> cInterfaceGLX::CreateSharedContext()
bool GLContextGLX::CreateWindowSurface(Window window_handle)
{
std::unique_ptr<cInterfaceBase> context = std::make_unique<cInterfaceGLX>();
if (!context->Create(this))
return nullptr;
return context;
}

bool cInterfaceGLX::CreateWindowSurface()
{
if (m_has_handle)
if (window_handle)
{
// Get an appropriate visual
XVisualInfo* vi = glXGetVisualFromFBConfig(dpy, fbconfig);

XWindow.Initialize(dpy);

XWindowAttributes attribs;
if (!XGetWindowAttributes(dpy, m_host_window, &attribs))
{
ERROR_LOG(VIDEO, "Window attribute retrieval failed");
XVisualInfo* vi = glXGetVisualFromFBConfig(m_display, m_fbconfig);
m_render_window = GLX11Window::Create(m_display, window_handle, vi);
if (!m_render_window)
return false;
}

s_backbuffer_width = attribs.width;
s_backbuffer_height = attribs.height;

win = XWindow.CreateXWindow(m_host_window, vi);
m_backbuffer_width = m_render_window->GetWidth();
m_backbuffer_height = m_render_window->GetHeight();
m_drawable = static_cast<GLXDrawable>(m_render_window->GetWindow());
XFree(vi);
}
else if (m_supports_pbuffer)
{
win = m_pbuffer = glXCreateGLXPbufferSGIX(dpy, fbconfig, 1, 1, nullptr);
m_pbuffer = glXCreateGLXPbufferSGIX(m_display, m_fbconfig, 1, 1, nullptr);
if (!m_pbuffer)
return false;

m_drawable = static_cast<GLXDrawable>(m_pbuffer);
}

return true;
}

void cInterfaceGLX::DestroyWindowSurface()
void GLContextGLX::DestroyWindowSurface()
{
if (m_has_handle)
m_render_window.reset();
if (m_supports_pbuffer && m_pbuffer)
{
XWindow.DestroyXWindow();
}
else if (m_supports_pbuffer && m_pbuffer)
{
glXDestroyGLXPbufferSGIX(dpy, m_pbuffer);
glXDestroyGLXPbufferSGIX(m_display, m_pbuffer);
m_pbuffer = 0;
}
}

bool cInterfaceGLX::MakeCurrent()
bool GLContextGLX::MakeCurrent()
{
return glXMakeCurrent(dpy, win, ctx);
return glXMakeCurrent(m_display, m_drawable, m_context);
}

bool cInterfaceGLX::ClearCurrent()
bool GLContextGLX::ClearCurrent()
{
return glXMakeCurrent(dpy, None, nullptr);
return glXMakeCurrent(m_display, None, nullptr);
}

// Close backend
void cInterfaceGLX::Shutdown()
void GLContextGLX::Update()
{
DestroyWindowSurface();
if (ctx)
{
glXDestroyContext(dpy, ctx);

// Don't close the display connection if we are a shared context.
// Saves doing reference counting on this object, and the main context will always
// be shut down last anyway.
if (m_has_handle)
{
XCloseDisplay(dpy);
ctx = nullptr;
}
}
m_render_window->UpdateDimensions();
m_backbuffer_width = m_render_window->GetWidth();
m_backbuffer_height = m_render_window->GetHeight();
}
@@ -10,35 +10,41 @@
#include <string>
#include <vector>

#include "Common/GL/GLInterface/X11_Util.h"
#include "Common/GL/GLInterfaceBase.h"
#include "Common/GL/GLContext.h"
#include "Common/GL/GLX11Window.h"

class cInterfaceGLX : public cInterfaceBase
class GLContextGLX final : public GLContext
{
private:
Window m_host_window;
cX11Window XWindow;
Display* dpy;
Window win;
GLXContext ctx;
GLXFBConfig fbconfig;
bool m_has_handle;
bool m_supports_pbuffer = false;
GLXPbufferSGIX m_pbuffer = 0;
std::vector<int> m_attribs;
public:
~GLContextGLX() override;

bool CreateWindowSurface();
void DestroyWindowSurface();
bool IsHeadless() const override;

std::unique_ptr<GLContext> CreateSharedContext() override;

bool MakeCurrent() override;
bool ClearCurrent() override;

void Update() override;

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 stereo, bool core) override;
bool Create(cInterfaceBase* main_context) override;
bool MakeCurrent() override;
bool ClearCurrent() override;
void Shutdown() override;
std::unique_ptr<cInterfaceBase> CreateSharedContext() override;

protected:
bool Initialize(void* display_handle, void* window_handle, bool stereo, bool core) override;

Display* m_display = nullptr;
std::unique_ptr<GLX11Window> m_render_window;

GLXDrawable m_drawable = {};
GLXContext m_context = nullptr;
GLXFBConfig m_fbconfig = {};
bool m_supports_pbuffer = false;
GLXPbufferSGIX m_pbuffer = 0;
std::vector<int> m_attribs;

bool CreateWindowSurface(Window window_handle);
void DestroyWindowSurface();
};
@@ -130,8 +130,8 @@ static PFNWGLDESTROYPBUFFERARBPROC wglDestroyPbufferARB = nullptr;

static void LoadWGLExtensions()
{
wglSwapIntervalEXT = reinterpret_cast<PFNWGLSWAPINTERVALEXTPROC>(
GLInterface->GetFuncAddress("wglSwapIntervalEXT"));
wglSwapIntervalEXT =
reinterpret_cast<PFNWGLSWAPINTERVALEXTPROC>(wglGetProcAddress("wglSwapIntervalEXT"));
wglCreateContextAttribsARB = reinterpret_cast<PFNWGLCREATECONTEXTATTRIBSARBPROC>(
wglGetProcAddress("wglCreateContextAttribsARB"));
wglChoosePixelFormatARB = reinterpret_cast<PFNWGLCHOOSEPIXELFORMATARBPROC>(
@@ -157,19 +157,57 @@ static void ClearWGLExtensionPointers()
wglDestroyPbufferARB = nullptr;
}

void cInterfaceWGL::SwapInterval(int Interval)
GLContextWGL::~GLContextWGL()
{
if (m_rc)
{
if (wglGetCurrentContext() == m_rc && !wglMakeCurrent(m_dc, nullptr))
NOTICE_LOG(VIDEO, "Could not release drawing context.");

if (!wglDeleteContext(m_rc))
ERROR_LOG(VIDEO, "Attempt to release rendering context failed.");

m_rc = nullptr;
}

if (m_dc)
{
if (m_pbuffer_handle)
{
wglReleasePbufferDCARB(static_cast<HPBUFFERARB>(m_pbuffer_handle), m_dc);
m_dc = nullptr;

wglDestroyPbufferARB(static_cast<HPBUFFERARB>(m_pbuffer_handle));
m_pbuffer_handle = nullptr;
}
else
{
if (!ReleaseDC(m_window_handle, m_dc))
ERROR_LOG(VIDEO, "Attempt to release device context failed.");

m_dc = nullptr;
}
}
}

bool GLContextWGL::IsHeadless() const
{
return !m_window_handle;
}

void GLContextWGL::SwapInterval(int interval)
{
if (wglSwapIntervalEXT)
wglSwapIntervalEXT(Interval);
wglSwapIntervalEXT(interval);
else
ERROR_LOG(VIDEO, "No support for SwapInterval (framerate clamped to monitor refresh rate).");
}
void cInterfaceWGL::Swap()
void GLContextWGL::Swap()
{
SwapBuffers(m_dc);
}

void* cInterfaceWGL::GetFuncAddress(const std::string& name)
void* GLContextWGL::GetFuncAddress(const std::string& name)
{
FARPROC func = wglGetProcAddress(name.c_str());
if (func == nullptr)
@@ -183,24 +221,9 @@ void* cInterfaceWGL::GetFuncAddress(const std::string& name)
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 stereo, bool core)
bool GLContextWGL::Initialize(void* display_handle, void* window_handle, bool stereo, bool core)
{
if (!window_handle)
return false;
@@ -216,8 +239,8 @@ bool cInterfaceWGL::Create(void* window_handle, bool stereo, bool core)
// 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_backbuffer_width = twidth;
m_backbuffer_height = theight;

const DWORD stereo_flag = stereo ? PFD_STEREO : 0;

@@ -274,8 +297,7 @@ bool cInterfaceWGL::Create(void* window_handle, bool stereo, bool core)
}

// WGL only supports desktop GL, for now.
if (s_opengl_mode == GLInterfaceMode::MODE_DETECT)
s_opengl_mode = GLInterfaceMode::MODE_OPENGL;
m_opengl_mode = Mode::OpenGL;

if (core)
{
@@ -306,59 +328,50 @@ bool cInterfaceWGL::Create(void* window_handle, bool stereo, bool core)
{
wglDeleteContext(m_rc);
m_rc = core_context;
m_core = true;
}
else
{
WARN_LOG(VIDEO, "Failed to create a core OpenGL context. Using fallback context.");
}
}

return true;
return MakeCurrent();
}

bool cInterfaceWGL::Create(cInterfaceBase* main_context)
std::unique_ptr<GLContext> GLContextWGL::CreateSharedContext()
{
cInterfaceWGL* wgl_main_context = static_cast<cInterfaceWGL*>(main_context);

// WGL does not support surfaceless contexts, so we use a 1x1 pbuffer instead.
if (!CreatePBuffer(wgl_main_context->m_dc, 1, 1, &m_pbuffer_handle, &m_dc))
return false;

m_rc = CreateCoreContext(m_dc, wgl_main_context->m_rc);
if (!m_rc)
return false;

m_core = true;
return true;
}
HANDLE pbuffer;
HDC dc;
if (!CreatePBuffer(m_dc, 1, 1, &pbuffer, &dc))
return nullptr;

std::unique_ptr<cInterfaceBase> cInterfaceWGL::CreateSharedContext()
{
std::unique_ptr<cInterfaceWGL> context = std::make_unique<cInterfaceWGL>();
if (!context->Create(this))
HGLRC rc = CreateCoreContext(dc, m_rc);
if (!rc)
{
context->Shutdown();
wglReleasePbufferDCARB(static_cast<HPBUFFERARB>(pbuffer), dc);
wglDestroyPbufferARB(static_cast<HPBUFFERARB>(pbuffer));
return nullptr;
}

return std::move(context);
std::unique_ptr<GLContextWGL> context = std::make_unique<GLContextWGL>();
context->m_pbuffer_handle = pbuffer;
context->m_dc = dc;
context->m_rc = rc;
context->m_opengl_mode = m_opengl_mode;
context->m_is_shared = true;
return context;
}

HGLRC cInterfaceWGL::CreateCoreContext(HDC dc, HGLRC share_context)
HGLRC GLContextWGL::CreateCoreContext(HDC dc, HGLRC share_context)
{
if (!wglCreateContextAttribsARB)
{
WARN_LOG(VIDEO, "Missing WGL_ARB_create_context extension");
return nullptr;
}

// List of versions to attempt context creation for. (4.5-3.2, geometry shaders is a minimum
// requirement since we're using core profile)
static constexpr std::array<std::pair<int, int>, 8> try_versions = {
{{4, 5}, {4, 4}, {4, 3}, {4, 2}, {4, 1}, {4, 0}, {3, 3}, {3, 2}}};

for (const auto& version : try_versions)
for (const auto& version : s_desktop_opengl_versions)
{
// Construct list of attributes. Prefer a forward-compatible, core context.
std::array<int, 5 * 2> attribs = {WGL_CONTEXT_PROFILE_MASK_ARB,
@@ -402,8 +415,8 @@ HGLRC cInterfaceWGL::CreateCoreContext(HDC dc, HGLRC share_context)
return nullptr;
}

bool cInterfaceWGL::CreatePBuffer(HDC onscreen_dc, int width, int height, HANDLE* pbuffer_handle,
HDC* pbuffer_dc)
bool GLContextWGL::CreatePBuffer(HDC onscreen_dc, int width, int height, HANDLE* pbuffer_handle,
HDC* pbuffer_dc)
{
if (!wglChoosePixelFormatARB || !wglCreatePbufferARB || !wglGetPbufferDCARB ||
!wglReleasePbufferDCARB || !wglDestroyPbufferARB)
@@ -462,57 +475,23 @@ bool cInterfaceWGL::CreatePBuffer(HDC onscreen_dc, int width, int height, HANDLE
return true;
}

bool cInterfaceWGL::MakeCurrent()
bool GLContextWGL::MakeCurrent()
{
return wglMakeCurrent(m_dc, m_rc) == TRUE;
}

bool cInterfaceWGL::ClearCurrent()
bool GLContextWGL::ClearCurrent()
{
return wglMakeCurrent(m_dc, nullptr) == TRUE;
}

// Update window width, size and etc. Called from Render.cpp
void cInterfaceWGL::Update()
void GLContextWGL::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 (m_rc)
{
if (!wglMakeCurrent(m_dc, nullptr))
NOTICE_LOG(VIDEO, "Could not release drawing context.");

if (!wglDeleteContext(m_rc))
ERROR_LOG(VIDEO, "Attempt to release rendering context failed.");

m_rc = nullptr;
}

if (m_dc)
{
if (m_pbuffer_handle)
{
wglReleasePbufferDCARB(static_cast<HPBUFFERARB>(m_pbuffer_handle), m_dc);
m_dc = nullptr;

wglDestroyPbufferARB(static_cast<HPBUFFERARB>(m_pbuffer_handle));
m_pbuffer_handle = nullptr;
}
else
{
if (!ReleaseDC(m_window_handle, m_dc))
ERROR_LOG(VIDEO, "Attempt to release device context failed.");

m_dc = nullptr;
}
}
m_backbuffer_width = rcWindow.right - rcWindow.left;
m_backbuffer_height = rcWindow.bottom - rcWindow.top;
}
@@ -6,26 +6,30 @@

#include <windows.h>
#include <string>
#include "Common/GL/GLInterfaceBase.h"
#include "Common/GL/GLContext.h"

class cInterfaceWGL : public cInterfaceBase
class GLContextWGL final : public GLContext
{
public:
void SwapInterval(int interval) override;
void Swap() override;
void* GetFuncAddress(const std::string& name) override;
bool Create(void* window_handle, bool stereo, bool core) override;
bool Create(cInterfaceBase* main_context) override;
~GLContextWGL();

bool IsHeadless() const;

std::unique_ptr<GLContext> CreateSharedContext() override;

bool MakeCurrent() override;
bool ClearCurrent() override;
void Shutdown() override;

void Update() override;
bool PeekMessages() override;

std::unique_ptr<cInterfaceBase> CreateSharedContext() override;
void Swap() override;
void SwapInterval(int interval) override;

void* GetFuncAddress(const std::string& name) override;

protected:
bool Initialize(void* display_handle, void* window_handle, bool stereo, bool core) override;

private:
static HGLRC CreateCoreContext(HDC dc, HGLRC share_context);
static bool CreatePBuffer(HDC onscreen_dc, int width, int height, HANDLE* pbuffer_handle,
HDC* pbuffer_dc);

This file was deleted.

This file was deleted.

This file was deleted.

@@ -5,19 +5,12 @@
#include <memory>

#include "Common/Assert.h"
#include "Common/GL/GLInterfaceBase.h"
#include "Common/GL/GLContext.h"
#include "Common/GL/GLUtil.h"
#include "Common/Logging/Log.h"

std::unique_ptr<cInterfaceBase> GLInterface;

namespace GLUtil
{
void InitInterface()
{
GLInterface = HostGL_CreateGLInterface();
}

GLuint CompileProgram(const std::string& vertexShader, const std::string& fragmentShader)
{
// generate objects
@@ -103,11 +96,11 @@ GLuint CompileProgram(const std::string& vertexShader, const std::string& fragme
return programID;
}

void EnablePrimitiveRestart()
void EnablePrimitiveRestart(const GLContext* context)
{
constexpr GLuint PRIMITIVE_RESTART_INDEX = 65535;

if (GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGLES3)
if (context->IsGLES())
{
glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
}
@@ -125,4 +118,4 @@ void EnablePrimitiveRestart()
}
}
}
}
} // namespace GLUtil
@@ -8,9 +8,10 @@

#include "Common/GL/GLExtensions/GLExtensions.h"

class GLContext;

namespace GLUtil
{
void InitInterface();
GLuint CompileProgram(const std::string& vertexShader, const std::string& fragmentShader);
void EnablePrimitiveRestart();
}
void EnablePrimitiveRestart(const GLContext* context);
} // namespace GLUtil
@@ -0,0 +1,53 @@
// Copyright 2012 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.

#include "Common/GL/GLX11Window.h"
#include "Common/GL/GLContext.h"

GLX11Window::GLX11Window(Display* display, Window parent_window, Colormap color_map, Window window,
int width, int height)
: m_display(display), m_parent_window(parent_window), m_color_map(color_map), m_window(window),
m_width(width), m_height(height)
{
}

GLX11Window::~GLX11Window()
{
XUnmapWindow(m_display, m_window);
XDestroyWindow(m_display, m_window);
XFreeColormap(m_display, m_color_map);
}

void GLX11Window::UpdateDimensions()
{
XWindowAttributes attribs;
XGetWindowAttributes(m_display, m_parent_window, &attribs);
XResizeWindow(m_display, m_window, attribs.width, attribs.height);
m_width = attribs.width;
m_height = attribs.height;
}

std::unique_ptr<GLX11Window> GLX11Window::Create(Display* display, Window parent_window,
XVisualInfo* vi)
{
// Set color map for the new window based on the visual.
Colormap color_map = XCreateColormap(display, parent_window, vi->visual, AllocNone);
XSetWindowAttributes attribs = {};
attribs.colormap = color_map;

// Get the dimensions from the parent window.
XWindowAttributes parent_attribs = {};
XGetWindowAttributes(display, parent_window, &parent_attribs);

// Create the window
Window window =
XCreateWindow(display, parent_window, 0, 0, parent_attribs.width, parent_attribs.height, 0,
vi->depth, InputOutput, vi->visual, CWColormap, &attribs);
XSelectInput(display, parent_window, StructureNotifyMask);
XMapWindow(display, window);
XSync(display, True);

return std::make_unique<GLX11Window>(display, parent_window, color_map, window,
parent_attribs.width, parent_attribs.height);
}
@@ -0,0 +1,39 @@
// Copyright 2008 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.

#pragma once

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>
#include <memory>
#include <thread>

class GLX11Window
{
public:
GLX11Window(Display* display, Window parent_window, Colormap color_map, Window window, int width,
int height);
~GLX11Window();

Display* GetDisplay() const { return m_display; }
Window GetParentWindow() const { return m_parent_window; }
Window GetWindow() const { return m_window; }
int GetWidth() const { return m_width; }
int GetHeight() const { return m_height; }

void UpdateDimensions();

static std::unique_ptr<GLX11Window> Create(Display* display, Window parent_window,
XVisualInfo* vi);

private:
Display* m_display;
Window m_parent_window;
Colormap m_color_map;
Window m_window;

int m_width;
int m_height;
};
@@ -0,0 +1,35 @@
// Copyright 2018 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.

#pragma once

enum class WindowSystemType
{
Headless,
Windows,
MacOS,
Android,
X11,
Wayland
};

struct WindowSystemInfo
{
WindowSystemInfo() = default;
WindowSystemInfo(WindowSystemType type_, void* display_connection_, void* render_surface_)
: type(type_), display_connection(display_connection_), render_surface(render_surface_)
{
}

// Window system type. Determines which GL context or Vulkan WSI is used.
WindowSystemType type = WindowSystemType::Headless;

// Connection to a display server. This is used on X11 and Wayland platforms.
void* display_connection = nullptr;

// Render surface. This is a pointer to the native window handle, which depends
// on the platform. e.g. HWND for Windows, Window for X11. If the surface is
// set to nullptr, the video backend will run in headless mode.
void* render_surface = nullptr;
};
@@ -222,7 +222,7 @@ static GPUDeterminismMode ParseGPUDeterminismMode(const std::string& mode)
}

// Boot the ISO or file
bool BootCore(std::unique_ptr<BootParameters> boot)
bool BootCore(std::unique_ptr<BootParameters> boot, const WindowSystemInfo& wsi)
{
if (!boot)
return false;
@@ -403,12 +403,14 @@ bool BootCore(std::unique_ptr<BootParameters> boot)
std::holds_alternative<BootParameters::Disc>(boot->parameters);
if (load_ipl)
{
return Core::Init(std::make_unique<BootParameters>(
BootParameters::IPL{StartUp.m_region,
std::move(std::get<BootParameters::Disc>(boot->parameters))},
boot->savestate_path));
return Core::Init(
std::make_unique<BootParameters>(
BootParameters::IPL{StartUp.m_region,
std::move(std::get<BootParameters::Disc>(boot->parameters))},
boot->savestate_path),
wsi);
}
return Core::Init(std::move(boot));
return Core::Init(std::move(boot), wsi);
}

// SYSCONF can be modified during emulation by the user and internally, which makes it
@@ -7,12 +7,13 @@
#include <memory>

struct BootParameters;
struct WindowSystemInfo;

namespace BootManager
{
bool BootCore(std::unique_ptr<BootParameters> parameters);
bool BootCore(std::unique_ptr<BootParameters> parameters, const WindowSystemInfo& wsi);

// Synchronise Dolphin's configuration with the SYSCONF (which may have changed during emulation),
// and restore settings that were overriden by per-game INIs or for some other reason.
void RestoreConfig();
}
} // namespace BootManager
@@ -89,7 +89,6 @@ static bool s_is_stopping = false;
static bool s_hardware_initialized = false;
static bool s_is_started = false;
static Common::Flag s_is_booting;
static void* s_window_handle = nullptr;
static std::thread s_emu_thread;
static StateChangedCallbackFunc s_on_state_changed_callback;

@@ -108,7 +107,7 @@ static std::queue<HostJob> s_host_jobs_queue;

static thread_local bool tls_is_cpu_thread = false;

static void EmuThread(std::unique_ptr<BootParameters> boot);
static void EmuThread(std::unique_ptr<BootParameters> boot, WindowSystemInfo wsi);

bool GetIsThrottlerTempDisabled()
{
@@ -191,7 +190,7 @@ bool WantsDeterminism()

// This is called from the GUI thread. See the booting call schedule in
// BootManager.cpp
bool Init(std::unique_ptr<BootParameters> boot)
bool Init(std::unique_ptr<BootParameters> boot, const WindowSystemInfo& wsi)
{
if (s_emu_thread.joinable())
{
@@ -215,10 +214,8 @@ bool Init(std::unique_ptr<BootParameters> boot)

Host_UpdateMainFrame(); // Disable any menus or buttons at boot

s_window_handle = Host_GetRenderHandle();

// Start the emu thread
s_emu_thread = std::thread(EmuThread, std::move(boot));
s_emu_thread = std::thread(EmuThread, std::move(boot), wsi);
return true;
}

@@ -389,7 +386,7 @@ static void FifoPlayerThread(const std::optional<std::string>& savestate_path,
// Initialize and create emulation thread
// Call browser: Init():s_emu_thread().
// See the BootManager.cpp file description for a complete call schedule.
static void EmuThread(std::unique_ptr<BootParameters> boot)
static void EmuThread(std::unique_ptr<BootParameters> boot, WindowSystemInfo wsi)
{
const SConfig& core_parameter = SConfig::GetInstance();
s_is_booting.Set();
@@ -441,7 +438,7 @@ static void EmuThread(std::unique_ptr<BootParameters> boot)
g_video_backend->InitBackendInfo();
g_Config.Refresh();

if (!g_video_backend->Initialize(s_window_handle))
if (!g_video_backend->Initialize(wsi))
{
PanicAlert("Failed to initialize video backend!");
return;
@@ -462,7 +459,7 @@ static void EmuThread(std::unique_ptr<BootParameters> boot)
bool init_controllers = false;
if (!g_controller_interface.IsInit())
{
g_controller_interface.Initialize(s_window_handle);
g_controller_interface.Initialize(wsi.display_connection);
Pad::Initialize();
Keyboard::Initialize();
init_controllers = true;
@@ -958,4 +955,4 @@ void DoFrameStep()
}
}

} // Core
} // namespace Core
@@ -18,6 +18,7 @@
#include "Common/CommonTypes.h"

struct BootParameters;
struct WindowSystemInfo;

namespace Core
{
@@ -35,7 +36,7 @@ enum class State
Starting,
};

bool Init(std::unique_ptr<BootParameters> boot);
bool Init(std::unique_ptr<BootParameters> boot, const WindowSystemInfo& wsi);
void Stop();
void Shutdown();

@@ -104,4 +105,4 @@ void HostDispatchJobs();

void DoFrameStep();

} // namespace
} // namespace Core
@@ -44,6 +44,3 @@ void Host_UpdateMainFrame();
void Host_UpdateTitle(const std::string& title);
void Host_YieldToUI();
void Host_UpdateProgressDialog(const char* caption, int position, int total);

// TODO (neobrain): Remove this from host!
void* Host_GetRenderHandle();
@@ -71,6 +71,10 @@ class Platform
}
virtual void Shutdown() {}
virtual ~Platform() {}

virtual WindowSystemType GetWindowSystem() const { return WindowSystemType::Headless; }
virtual void* GetDisplayHandle() const { return nullptr; }
virtual void* GetWindowHandle() const { return nullptr; }
};

static Platform* platform;
@@ -91,12 +95,6 @@ void Host_Message(HostMessageID id)
updateMainFrameEvent.Set();
}

static void* s_window_handle = nullptr;
void* Host_GetRenderHandle()
{
return s_window_handle;
}

void Host_UpdateTitle(const std::string& title)
{
platform->SetTitle(title);
@@ -187,7 +185,6 @@ class PlatformX11 : public Platform
}
XMapRaised(dpy, win);
XFlush(dpy);
s_window_handle = (void*)win;

if (SConfig::GetInstance().bDisableScreenSaver)
X11Utils::InhibitScreensaver(win, true);
@@ -213,9 +210,6 @@ class PlatformX11 : public Platform
void MainLoop() override
{
bool fullscreen = SConfig::GetInstance().bFullscreen;
int last_window_width = SConfig::GetInstance().iRenderWindowWidth;
int last_window_height = SConfig::GetInstance().iRenderWindowHeight;

if (fullscreen)
{
rendererIsFullscreen = X11Utils::ToggleFullscreen(dpy, win);
@@ -315,14 +309,8 @@ class PlatformX11 : public Platform
break;
case ConfigureNotify:
{
if (last_window_width != event.xconfigure.width ||
last_window_height != event.xconfigure.height)
{
last_window_width = event.xconfigure.width;
last_window_height = event.xconfigure.height;
if (g_renderer)
g_renderer->ResizeSurface(last_window_width, last_window_height);
}
if (g_renderer)
g_renderer->ResizeSurface();
}
break;
}
@@ -354,6 +342,10 @@ class PlatformX11 : public Platform

XCloseDisplay(dpy);
}

WindowSystemType GetWindowSystem() const override { return WindowSystemType::X11; }
void* GetDisplayHandle() const override { return static_cast<void*>(dpy); }
void* GetWindowHandle() const override { return reinterpret_cast<void*>(win); }
};
#endif

@@ -433,7 +425,10 @@ int main(int argc, char* argv[])

DolphinAnalytics::Instance()->ReportDolphinStart("nogui");

if (!BootManager::BootCore(std::move(boot)))
WindowSystemInfo wsi(platform->GetWindowSystem(), platform->GetDisplayHandle(),
platform->GetWindowHandle());

if (!BootManager::BootCore(std::move(boot), wsi))
{
fprintf(stderr, "Could not boot the specified file\n");
return 1;
@@ -30,14 +30,10 @@ Host* Host::GetInstance()
return s_instance;
}

void* Host::GetRenderHandle()
{
return m_render_handle;
}

void Host::SetRenderHandle(void* handle)
{
m_render_handle = handle;
if (g_renderer)
g_renderer->ChangeSurface(handle);
}

bool Host::GetRenderFocus()
@@ -72,7 +68,7 @@ void Host::SetRenderFullscreen(bool fullscreen)
void Host::ResizeSurface(int new_width, int new_height)
{
if (g_renderer)
g_renderer->ResizeSurface(new_width, new_height);
g_renderer->ResizeSurface();
}

void Host_Message(HostMessageID id)
@@ -94,11 +90,6 @@ void Host_UpdateTitle(const std::string& title)
emit Host::GetInstance()->RequestTitle(QString::fromStdString(title));
}

void* Host_GetRenderHandle()
{
return Host::GetInstance()->GetRenderHandle();
}

bool Host_RendererHasFocus()
{
return Host::GetInstance()->GetRenderFocus();
@@ -20,7 +20,6 @@ class Host final : public QObject
public:
static Host* GetInstance();

void* GetRenderHandle();
bool GetRenderFocus();
bool GetRenderFullscreen();

@@ -16,6 +16,7 @@
#include <QProgressDialog>
#include <QStackedWidget>
#include <QVBoxLayout>
#include <QWindow>

#include <future>
#include <optional>
@@ -26,7 +27,12 @@
#include "QtUtils/SignalDaemon.h"
#endif

#ifndef WIN32
#include <qpa/qplatformnativeinterface.h>
#endif

#include "Common/Version.h"
#include "Common/WindowSystemInfo.h"

#include "Core/Boot/Boot.h"
#include "Core/BootManager.h"
@@ -98,7 +104,6 @@
#include "VideoCommon/VideoConfig.h"

#if defined(HAVE_XRANDR) && HAVE_XRANDR
#include <qpa/qplatformnativeinterface.h>
#include "UICommon/X11Utils.h"
#endif

@@ -119,6 +124,45 @@ static void InstallSignalHandler()
}
#endif

static WindowSystemType GetWindowSystemType()
{
// Determine WSI type based on Qt platform.
QString platform_name = QGuiApplication::platformName();
if (platform_name == QStringLiteral("windows"))
return WindowSystemType::Windows;
else if (platform_name == QStringLiteral("cocoa"))
return WindowSystemType::MacOS;
else if (platform_name == QStringLiteral("xcb"))
return WindowSystemType::X11;
else if (platform_name == QStringLiteral("wayland"))
return WindowSystemType::Wayland;

QMessageBox::critical(
nullptr, QStringLiteral("Error"),
QString::asprintf("Unknown Qt platform: %s", platform_name.toStdString().c_str()));
return WindowSystemType::Headless;
}

static WindowSystemInfo GetWindowSystemInfo(QWindow* window)
{
WindowSystemInfo wsi;
wsi.type = GetWindowSystemType();

// Our Win32 Qt external doesn't have the private API.
#if defined(WIN32) || defined(__APPLE__)
wsi.render_surface = window ? reinterpret_cast<void*>(window->winId()) : nullptr;
#else
QPlatformNativeInterface* pni = QGuiApplication::platformNativeInterface();
wsi.display_connection = pni->nativeResourceForWindow("display", window);
if (wsi.type == WindowSystemType::Wayland)
wsi.render_surface = window ? pni->nativeResourceForWindow("surface", window) : nullptr;
else
wsi.render_surface = window ? reinterpret_cast<void*>(window->winId()) : nullptr;
#endif

return wsi;
}

MainWindow::MainWindow(std::unique_ptr<BootParameters> boot_parameters) : QMainWindow(nullptr)
{
setWindowTitle(QString::fromStdString(Common::scm_rev_str));
@@ -797,14 +841,19 @@ void MainWindow::StartGame(std::unique_ptr<BootParameters>&& parameters)
m_pending_boot = std::move(parameters);
return;
}

// We need the render widget before booting.
ShowRenderWidget();

// Boot up, show an error if it fails to load the game.
if (!BootManager::BootCore(std::move(parameters)))
if (!BootManager::BootCore(std::move(parameters),
GetWindowSystemInfo(m_render_widget->windowHandle())))
{
QMessageBox::critical(this, tr("Error"), tr("Failed to init core"), QMessageBox::Ok);
HideRenderWidget();
return;
}

ShowRenderWidget();
#ifdef USE_DISCORD_PRESENCE
if (!NetPlay::IsNetPlayRunning())
Discord::UpdateDiscordPresence();
@@ -55,8 +55,6 @@ RenderWidget::RenderWidget(QWidget* parent) : QWidget(parent)
connect(this, &RenderWidget::FocusChanged, Host::GetInstance(), &Host::SetRenderFocus,
Qt::DirectConnection);

emit HandleChanged((void*)winId());

m_mouse_timer = new QTimer(this);
connect(m_mouse_timer, &QTimer::timeout, this, &RenderWidget::HandleCursorTimer);
m_mouse_timer->setSingleShot(true);
@@ -70,6 +68,9 @@ RenderWidget::RenderWidget(QWidget* parent) : QWidget(parent)
OnKeepOnTopChanged(Settings::Instance().IsKeepWindowOnTopEnabled());
m_mouse_timer->start(MOUSE_HIDE_DELAY);

// We need a native window to render into.
setAttribute(Qt::WA_NativeWindow);

SetFillBackground(true);
}

@@ -144,7 +145,7 @@ bool RenderWidget::event(QEvent* event)
}
break;
case QEvent::WinIdChange:
emit HandleChanged((void*)winId());
emit HandleChanged(reinterpret_cast<void*>(winId()));
break;
case QEvent::WindowActivate:
if (SConfig::GetInstance().m_PauseOnFocusLost && Core::GetState() == Core::State::Paused)
@@ -24,8 +24,10 @@ if ((DEFINED CMAKE_ANDROID_ARCH_ABI AND CMAKE_ANDROID_ARCH_ABI MATCHES "x86|x86_
target_link_libraries(uicommon PRIVATE bdisasm)
endif()

if(USE_X11)
if(ENABLE_X11 AND X11_FOUND)
target_include_directories(uicommon PRIVATE ${X11_INCLUDE_DIR})
target_sources(uicommon PRIVATE X11Utils.cpp)
target_link_libraries(uicommon PUBLIC ${XRANDR_LIBRARIES})
endif()

if(LIBUSB_FOUND)
@@ -429,10 +429,13 @@ HRESULT Create(HWND wnd)
// prevent DXGI from responding to Alt+Enter, unfortunately DXGI_MWA_NO_ALT_ENTER
// does not work so we disable all monitoring of window messages. However this
// may make it more difficult for DXGI to handle display mode changes.
hr = s_dxgi_factory->MakeWindowAssociation(wnd, DXGI_MWA_NO_WINDOW_CHANGES);
if (FAILED(hr))
MessageBox(wnd, _T("Failed to associate the window"), _T("Dolphin Direct3D 11 backend"),
MB_OK | MB_ICONERROR);
if (wnd)
{
hr = s_dxgi_factory->MakeWindowAssociation(wnd, DXGI_MWA_NO_WINDOW_CHANGES);
if (FAILED(hr))
MessageBox(wnd, _T("Failed to associate the window"), _T("Dolphin Direct3D 11 backend"),
MB_OK | MB_ICONERROR);
}

SetDebugObjectName(context, "device context");

@@ -225,6 +225,11 @@ void Renderer::Create3DVisionTexture(int width, int height)
DXGI_FORMAT_R8G8B8A8_UNORM, 1, 1, &sys_data);
}

bool Renderer::IsHeadless() const
{
return D3D::swapchain == nullptr;
}

std::unique_ptr<AbstractTexture> Renderer::CreateTexture(const TextureConfig& config)
{
return std::make_unique<DXTexture>(config);
@@ -698,12 +703,12 @@ void Renderer::CheckForSurfaceChange()
if (!m_surface_changed.TestAndClear())
return;

m_surface_handle = m_new_surface_handle;
m_new_surface_handle = nullptr;

SAFE_RELEASE(m_screenshot_texture);
SAFE_RELEASE(m_3d_vision_texture);

D3D::Reset(reinterpret_cast<HWND>(m_new_surface_handle));
m_new_surface_handle = nullptr;

UpdateBackbufferSize();
}

@@ -714,9 +719,6 @@ void Renderer::CheckForSurfaceResize()
if (!m_surface_resized.TestAndClear() && !exclusive_fullscreen_changed)
return;

m_backbuffer_width = m_new_backbuffer_width;
m_backbuffer_height = m_new_backbuffer_height;

SAFE_RELEASE(m_screenshot_texture);
SAFE_RELEASE(m_3d_vision_texture);
m_last_fullscreen_state = fullscreen_state;
@@ -22,6 +22,9 @@ class Renderer : public ::Renderer
~Renderer() override;

StateCache& GetStateCache() { return m_state_cache; }

bool IsHeadless() const override;

std::unique_ptr<AbstractTexture> CreateTexture(const TextureConfig& config) override;
std::unique_ptr<AbstractStagingTexture>
CreateStagingTexture(StagingTextureType type, const TextureConfig& config) override;
@@ -11,12 +11,12 @@ namespace DX11
{
class VideoBackend : public VideoBackendBase
{
bool Initialize(void*) override;
bool Initialize(const WindowSystemInfo& wsi) override;
void Shutdown() override;

std::string GetName() const override;
std::string GetDisplayName() const override;

void InitBackendInfo() override;
};
}
} // namespace DX11
@@ -127,14 +127,11 @@ void VideoBackend::InitBackendInfo()
DX11::D3D::UnloadD3D();
}

bool VideoBackend::Initialize(void* window_handle)
bool VideoBackend::Initialize(const WindowSystemInfo& wsi)
{
if (window_handle == nullptr)
return false;

InitializeShared();

if (FAILED(D3D::Create(reinterpret_cast<HWND>(window_handle))))
if (FAILED(D3D::Create(reinterpret_cast<HWND>(wsi.render_surface))))
{
PanicAlert("Failed to create D3D device.");
return false;
@@ -188,4 +185,4 @@ void VideoBackend::Shutdown()

D3D::Close();
}
}
} // namespace DX11
@@ -54,7 +54,7 @@ void VideoBackend::InitBackendInfo()
g_Config.backend_info.AAModes = {1};
}

bool VideoBackend::Initialize(void* window_handle)
bool VideoBackend::Initialize(const WindowSystemInfo& wsi)
{
InitializeShared();

@@ -80,4 +80,4 @@ void VideoBackend::Shutdown()

ShutdownShared();
}
}
} // namespace Null
@@ -24,6 +24,11 @@ Renderer::~Renderer()
UpdateActiveConfig();
}

bool Renderer::IsHeadless() const
{
return true;
}

std::unique_ptr<AbstractTexture> Renderer::CreateTexture(const TextureConfig& config)
{
return std::make_unique<NullTexture>(config);
@@ -14,6 +14,8 @@ class Renderer : public ::Renderer
Renderer();
~Renderer() override;

bool IsHeadless() const override;

std::unique_ptr<AbstractTexture> CreateTexture(const TextureConfig& config) override;
std::unique_ptr<AbstractStagingTexture>
CreateStagingTexture(StagingTextureType type, const TextureConfig& config) override;
@@ -11,7 +11,7 @@ namespace Null
{
class VideoBackend : public VideoBackendBase
{
bool Initialize(void* window_handle) override;
bool Initialize(const WindowSystemInfo& wsi) override;
void Shutdown() override;

std::string GetName() const override { return "Null"; }
@@ -22,4 +22,4 @@ class VideoBackend : public VideoBackendBase
}
void InitBackendInfo() override;
};
}
} // namespace Null
@@ -9,7 +9,6 @@

#include "Common/Common.h"
#include "Common/CommonTypes.h"
#include "Common/GL/GLInterfaceBase.h"
#include "Common/Logging/Log.h"
#include "Common/MsgHandler.h"

@@ -414,7 +413,7 @@ FramebufferManager::FramebufferManager(int targetWidth, int targetHeight, int ms
glBindBuffer(GL_ARRAY_BUFFER,
static_cast<VertexManager*>(g_vertex_manager.get())->GetVertexBufferHandle());

if (GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGL)
if (!static_cast<Renderer*>(g_renderer.get())->IsGLES())
glEnable(GL_PROGRAM_POINT_SIZE);
}

@@ -4,7 +4,6 @@

#include "Common/Assert.h"
#include "Common/CommonTypes.h"
#include "Common/GL/GLInterfaceBase.h"
#include "Common/MsgHandler.h"

#include "VideoBackends/OGL/FramebufferManager.h"
@@ -6,25 +6,23 @@

#include "Common/CommonFuncs.h"
#include "Common/CommonTypes.h"
#include "Common/GL/GLInterfaceBase.h"
#include "Common/GL/GLUtil.h"
#include "Common/GL/GLExtensions/GLExtensions.h"

#include "VideoBackends/OGL/PerfQuery.h"
#include "VideoCommon/RenderBase.h"
#include "VideoBackends/OGL/Render.h"
#include "VideoCommon/VideoConfig.h"

namespace OGL
{
std::unique_ptr<PerfQueryBase> GetPerfQuery()
{
if (GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGLES3 &&
GLExtensions::Supports("GL_NV_occlusion_query_samples"))
const bool is_gles = static_cast<Renderer*>(g_renderer.get())->IsGLES();
if (is_gles && GLExtensions::Supports("GL_NV_occlusion_query_samples"))
return std::make_unique<PerfQueryGLESNV>();

if (GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGLES3)
else if (is_gles)
return std::make_unique<PerfQueryGL>(GL_ANY_SAMPLES_PASSED);

return std::make_unique<PerfQueryGL>(GL_SAMPLES_PASSED);
else
return std::make_unique<PerfQueryGL>(GL_SAMPLES_PASSED);
}

PerfQuery::PerfQuery() : m_query_read_pos()
@@ -266,4 +264,4 @@ void PerfQueryGLESNV::FlushResults()
FlushOne();
}

} // namespace
} // namespace OGL
@@ -12,7 +12,7 @@
#include "Common/Assert.h"
#include "Common/CommonTypes.h"
#include "Common/FileUtil.h"
#include "Common/GL/GLInterfaceBase.h"
#include "Common/GL/GLContext.h"
#include "Common/Logging/Log.h"
#include "Common/MsgHandler.h"
#include "Common/StringUtil.h"
@@ -805,7 +805,8 @@ void ProgramShaderCache::CreateHeader()

bool SharedContextAsyncShaderCompiler::WorkerThreadInitMainThread(void** param)
{
std::unique_ptr<cInterfaceBase> context = GLInterface->CreateSharedContext();
std::unique_ptr<GLContext> context =
static_cast<Renderer*>(g_renderer.get())->GetMainGLContext()->CreateSharedContext();
if (!context)
{
PanicAlert("Failed to create shared context for shader compiling.");
@@ -818,20 +819,20 @@ bool SharedContextAsyncShaderCompiler::WorkerThreadInitMainThread(void** param)

bool SharedContextAsyncShaderCompiler::WorkerThreadInitWorkerThread(void* param)
{
cInterfaceBase* context = static_cast<cInterfaceBase*>(param);
GLContext* context = static_cast<GLContext*>(param);
if (!context->MakeCurrent())
return false;

s_is_shared_context = true;
if (g_ActiveConfig.backend_info.bSupportsPrimitiveRestart)
GLUtil::EnablePrimitiveRestart();
GLUtil::EnablePrimitiveRestart(context);

return true;
}

void SharedContextAsyncShaderCompiler::WorkerThreadExit(void* param)
{
cInterfaceBase* context = static_cast<cInterfaceBase*>(param);
GLContext* context = static_cast<GLContext*>(param);
context->ClearCurrent();
delete context;
}