diff options
| author | Stenzek <stenzek@users.noreply.github.com> | 2018-10-24 14:51:21 +1100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-10-24 14:51:21 +1100 |
| commit | c4d1e4adffcd380cc87b841069ce2fe8b62d7b60 (patch) | |
| tree | c61a0a07c14ccc3c1f7247bdcc82927a82c145bb /Source/Core/Common | |
| parent | 9c9d598ec006527bc47aea306e5171d03c12c5f5 (diff) | |
| parent | 2c6d96433c322b50470705d43005fd6308506d49 (diff) | |
Merge pull request #7450 from stenzek/glcontext
GLInterface refactoring/cleanup and runtime platform selection
Diffstat (limited to 'Source/Core/Common')
32 files changed, 889 insertions, 984 deletions
diff --git a/Source/Core/Common/CMakeLists.txt b/Source/Core/Common/CMakeLists.txt index 507e08662e..b75c88d013 100644 --- a/Source/Core/Common/CMakeLists.txt +++ b/Source/Core/Common/CMakeLists.txt @@ -110,17 +110,18 @@ endif() target_sources(common PRIVATE GL/GLUtil.cpp GL/GLExtensions/GLExtensions.cpp - GL/GLInterface/GLInterface.cpp + GL/GLContext.cpp ) -if(USE_EGL) +if(ENABLE_EGL AND EGL_FOUND) target_sources(common PRIVATE GL/GLInterface/EGL.cpp) if(ANDROID) target_sources(common PRIVATE GL/GLInterface/EGLAndroid.cpp) - elseif(USE_X11) + elseif(ENABLE_X11 AND X11_FOUND) target_sources(common PRIVATE GL/GLInterface/EGLX11.cpp) endif() - target_link_libraries(common PUBLIC EGL) + target_include_directories(common PRIVATE ${EGL_INCLUDE_DIRS}) + target_link_libraries(common PUBLIC ${EGL_LIBRARIES}) endif() if(WIN32) @@ -130,18 +131,14 @@ if(WIN32) ) elseif(APPLE) target_sources(common PRIVATE GL/GLInterface/AGL.mm) -elseif(HAIKU) - target_sources(common PRIVATE GL/GLInterface/BGL.cpp) - target_link_libraries(common PUBLIC be GL) -elseif(USE_X11) - if (NOT USE_EGL) - target_sources(common PRIVATE GL/GLInterface/GLX.cpp) - # GLX has a hard dependency on libGL. - # Make sure to link to it if using GLX. - target_link_libraries(common PUBLIC ${OPENGL_LIBRARIES}) - endif() - target_sources(common PRIVATE GL/GLInterface/X11_Util.cpp) - target_link_libraries(common PUBLIC ${XRANDR_LIBRARIES}) +elseif(ENABLE_X11 AND X11_FOUND) + target_sources(common PRIVATE + GL/GLX11Window.cpp + GL/GLInterface/GLX.cpp) + + # GLX has a hard dependency on libGL. + # Make sure to link to it if using GLX. + target_link_libraries(common PUBLIC ${OPENGL_LIBRARIES}) endif() if(CMAKE_SYSTEM_NAME STREQUAL "Linux") @@ -163,9 +160,6 @@ if(UNIX) if(SYSTEMD_FOUND) target_link_libraries(traversal_server PRIVATE ${SYSTEMD_LIBRARIES}) endif() - if(HAIKU) - target_link_libraries(traversal_server PRIVATE network) - endif() elseif(WIN32) target_link_libraries(common PRIVATE "-INCLUDE:enableCompatPatches") endif() diff --git a/Source/Core/Common/Common.vcxproj b/Source/Core/Common/Common.vcxproj index d0751f8c3f..23752002cf 100644 --- a/Source/Core/Common/Common.vcxproj +++ b/Source/Core/Common/Common.vcxproj @@ -121,7 +121,7 @@ <ClInclude Include="GL\GLExtensions\NV_depth_buffer_float.h" /> <ClInclude Include="GL\GLExtensions\NV_occlusion_query_samples.h" /> <ClInclude Include="GL\GLExtensions\NV_primitive_restart.h" /> - <ClInclude Include="GL\GLInterfaceBase.h" /> + <ClInclude Include="GL\GLContext.h" /> <ClInclude Include="GL\GLInterface\WGL.h" /> <ClInclude Include="GL\GLUtil.h" /> <ClInclude Include="FloatUtils.h" /> @@ -189,7 +189,7 @@ <ClCompile Include="FloatUtils.cpp" /> <ClCompile Include="GekkoDisassembler.cpp" /> <ClCompile Include="GL\GLExtensions\GLExtensions.cpp" /> - <ClCompile Include="GL\GLInterface\GLInterface.cpp" /> + <ClCompile Include="GL\GLContext.cpp" /> <ClCompile Include="GL\GLInterface\WGL.cpp" /> <ClCompile Include="GL\GLUtil.cpp" /> <ClCompile Include="Hash.cpp" /> @@ -255,4 +255,4 @@ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <ImportGroup Label="ExtensionTargets"> </ImportGroup> -</Project> +</Project>
\ No newline at end of file diff --git a/Source/Core/Common/Common.vcxproj.filters b/Source/Core/Common/Common.vcxproj.filters index 3737a5a1ff..63a131a8dc 100644 --- a/Source/Core/Common/Common.vcxproj.filters +++ b/Source/Core/Common/Common.vcxproj.filters @@ -243,9 +243,6 @@ <ClInclude Include="GL\GLInterface\WGL.h"> <Filter>GL\GLInterface</Filter> </ClInclude> - <ClInclude Include="GL\GLInterfaceBase.h"> - <Filter>GL\GLInterface</Filter> - </ClInclude> <ClInclude Include="Assert.h" /> <ClInclude Include="Analytics.h" /> <ClInclude Include="Semaphore.h" /> @@ -275,6 +272,9 @@ <ClInclude Include="Debug\MemoryPatches.h"> <Filter>Debug</Filter> </ClInclude> + <ClInclude Include="GL\GLContext.h"> + <Filter>GL\GLInterface</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ClCompile Include="CDUtils.cpp" /> @@ -339,9 +339,6 @@ <ClCompile Include="GL\GLInterface\WGL.cpp"> <Filter>GL\GLInterface</Filter> </ClCompile> - <ClCompile Include="GL\GLInterface\GLInterface.cpp"> - <Filter>GL\GLInterface</Filter> - </ClCompile> <ClCompile Include="Analytics.cpp" /> <ClCompile Include="MD5.cpp" /> <ClCompile Include="File.cpp" /> @@ -355,6 +352,9 @@ <ClCompile Include="Debug\MemoryPatches.cpp"> <Filter>Debug</Filter> </ClCompile> + <ClCompile Include="GL\GLContext.cpp"> + <Filter>GL\GLInterface</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <Text Include="CMakeLists.txt" /> @@ -362,4 +362,4 @@ <ItemGroup> <Natvis Include="BitField.natvis" /> </ItemGroup> -</Project> +</Project>
\ No newline at end of file diff --git a/Source/Core/Common/GL/GLContext.cpp b/Source/Core/Common/GL/GLContext.cpp new file mode 100644 index 0000000000..b02e27778f --- /dev/null +++ b/Source/Core/Common/GL/GLContext.cpp @@ -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; +} diff --git a/Source/Core/Common/GL/GLContext.h b/Source/Core/Common/GL/GLContext.h new file mode 100644 index 0000000000..074ea3cc6d --- /dev/null +++ b/Source/Core/Common/GL/GLContext.h @@ -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; +}; diff --git a/Source/Core/Common/GL/GLExtensions/GLExtensions.cpp b/Source/Core/Common/GL/GLExtensions/GLExtensions.cpp index 9252a7bed3..641559a29a 100644 --- a/Source/Core/Common/GL/GLExtensions/GLExtensions.cpp +++ b/Source/Core/Common/GL/GLExtensions/GLExtensions.cpp @@ -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,10 +2405,10 @@ 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; @@ -2417,7 +2416,7 @@ static void InitExtensionList() 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() { @@ -2425,14 +2424,14 @@ static void InitVersion() 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 diff --git a/Source/Core/Common/GL/GLExtensions/GLExtensions.h b/Source/Core/Common/GL/GLExtensions/GLExtensions.h index 2c0364da48..f1e258f98e 100644 --- a/Source/Core/Common/GL/GLExtensions/GLExtensions.h +++ b/Source/Core/Common/GL/GLExtensions/GLExtensions.h @@ -54,10 +54,12 @@ #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")) @@ -65,4 +67,4 @@ bool Supports(const std::string& name); // Returns OpenGL version in format 430 u32 Version(); -} +} // namespace GLExtensions diff --git a/Source/Core/Common/GL/GLInterface/AGL.h b/Source/Core/Common/GL/GLInterface/AGL.h index 8d62086954..59d0116954 100644 --- a/Source/Core/Common/GL/GLInterface/AGL.h +++ b/Source/Core/Common/GL/GLInterface/AGL.h @@ -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; diff --git a/Source/Core/Common/GL/GLInterface/AGL.mm b/Source/Core/Common/GL/GLInterface/AGL.mm index 07502475f7..7216946dae 100644 --- a/Source/Core/Common/GL/GLInterface/AGL.mm +++ b/Source/Core/Common/GL/GLInterface/AGL.mm @@ -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 @@ bool cInterfaceAGL::Create(void* window_handle, bool stereo, bool core) 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]; } diff --git a/Source/Core/Common/GL/GLInterface/BGL.cpp b/Source/Core/Common/GL/GLInterface/BGL.cpp deleted file mode 100644 index ed2670efc5..0000000000 --- a/Source/Core/Common/GL/GLInterface/BGL.cpp +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2017 Dolphin Emulator Project -// Licensed under GPLv2+ -// Refer to the license.txt file included. - -#include "Common/GL/GLInterface/BGL.h" - -#include <GLView.h> -#include <Size.h> -#include <Window.h> - -void cInterfaceBGL::Swap() -{ - m_gl->SwapBuffers(); -} - -bool cInterfaceBGL::Create(void* window_handle, bool stereo, bool core) -{ - m_window = static_cast<BWindow*>(window_handle); - - m_gl = new BGLView(m_window->Bounds(), "cInterfaceBGL", B_FOLLOW_ALL_SIDES, 0, - BGL_RGB | BGL_DOUBLE | BGL_ALPHA); - m_window->AddChild(m_gl); - - s_opengl_mode = GLInterfaceMode::MODE_OPENGL; - - // Control m_window size and picture scaling - BRect size = m_gl->Frame(); - s_backbuffer_width = size.IntegerWidth(); - s_backbuffer_height = size.IntegerHeight(); - - return true; -} - -bool cInterfaceBGL::MakeCurrent() -{ - m_gl->LockGL(); - return true; -} - -bool cInterfaceBGL::ClearCurrent() -{ - m_gl->UnlockGL(); - return true; -} - -void cInterfaceBGL::Shutdown() -{ - // We don't need to delete m_gl, it's owned by the BWindow. - m_gl = nullptr; -} - -void cInterfaceBGL::Update() -{ - BRect size = m_gl->Frame(); - - if (s_backbuffer_width == size.IntegerWidth() && s_backbuffer_height == size.IntegerHeight()) - return; - - s_backbuffer_width = size.IntegerWidth(); - s_backbuffer_height = size.IntegerHeight(); -} - -void cInterfaceBGL::SwapInterval(int interval) -{ -} - -void* cInterfaceBGL::GetFuncAddress(const std::string& name) -{ - return m_gl->GetGLProcAddress(name.c_str()); -} diff --git a/Source/Core/Common/GL/GLInterface/BGL.h b/Source/Core/Common/GL/GLInterface/BGL.h deleted file mode 100644 index b26e5e3fc8..0000000000 --- a/Source/Core/Common/GL/GLInterface/BGL.h +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2017 Dolphin Emulator Project -// Licensed under GPLv2+ -// Refer to the license.txt file included. - -#pragma once - -#include "Common/GL/GLInterfaceBase.h" - -class BWindow; -class BGLView; - -class cInterfaceBGL final : public cInterfaceBase -{ -public: - void Swap() override; - void* GetFuncAddress(const std::string& name) override; - bool Create(void* window_handle, bool stereo, bool core) override; - bool MakeCurrent() override; - bool ClearCurrent() override; - void Shutdown() override; - void Update() override; - void SwapInterval(int interval) override; - -private: - BWindow* m_window; - BGLView* m_gl; -}; diff --git a/Source/Core/Common/GL/GLInterface/EGL.cpp b/Source/Core/Common/GL/GLInterface/EGL.cpp index e71b365928..93a60ca9d8 100644 --- a/Source/Core/Common/GL/GLInterface/EGL.cpp +++ b/Source/Core/Common/GL/GLInterface/EGL.cpp @@ -9,7 +9,6 @@ #include "Common/GL/GLInterface/EGL.h" #include "Common/Logging/Log.h" -#include "Core/Config/GraphicsSettings.h" #ifndef EGL_KHR_create_context #define EGL_KHR_create_context 1 @@ -28,35 +27,37 @@ #define EGL_OPENGL_ES3_BIT_KHR 0x00000040 #endif /* EGL_KHR_create_context */ -// Show the current FPS -void cInterfaceEGL::Swap() +GLContextEGL::~GLContextEGL() { - if (egl_surf != EGL_NO_SURFACE) - eglSwapBuffers(egl_dpy, egl_surf); + DestroyWindowSurface(); + DestroyContext(); } -void cInterfaceEGL::SwapInterval(int Interval) + +bool GLContextEGL::IsHeadless() const { - eglSwapInterval(egl_dpy, Interval); + return m_host_window == nullptr; } -void* cInterfaceEGL::GetFuncAddress(const std::string& name) +void GLContextEGL::Swap() { - return (void*)eglGetProcAddress(name.c_str()); + if (m_egl_surface != EGL_NO_SURFACE) + eglSwapBuffers(m_egl_display, m_egl_surface); +} +void GLContextEGL::SwapInterval(int interval) +{ + eglSwapInterval(m_egl_display, interval); } -void cInterfaceEGL::DetectMode() +void* GLContextEGL::GetFuncAddress(const std::string& name) { - if (s_opengl_mode != GLInterfaceMode::MODE_DETECT) - return; - bool preferGLES = Config::Get(Config::GFX_PREFER_GLES); + return (void*)eglGetProcAddress(name.c_str()); +} +void GLContextEGL::DetectMode(bool has_handle) +{ 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, - }}; + bool supportsGL = false, supportsGLES3 = false; + std::array<int, 3> renderable_types{{EGL_OPENGL_BIT, EGL_OPENGL_ES3_BIT_KHR}}; for (auto renderable_type : renderable_types) { @@ -71,11 +72,11 @@ void cInterfaceEGL::DetectMode() EGL_RENDERABLE_TYPE, renderable_type, EGL_SURFACE_TYPE, - m_has_handle ? EGL_WINDOW_BIT : 0, + has_handle ? EGL_WINDOW_BIT : 0, EGL_NONE}; // Get how many configs there are - if (!eglChooseConfig(egl_dpy, attribs, nullptr, 0, &num_configs)) + if (!eglChooseConfig(m_egl_display, attribs, nullptr, 0, &num_configs)) { INFO_LOG(VIDEO, "Error: couldn't get an EGL visual config"); continue; @@ -84,7 +85,7 @@ void cInterfaceEGL::DetectMode() EGLConfig* config = new EGLConfig[num_configs]; // Get all the configurations - if (!eglChooseConfig(egl_dpy, attribs, config, num_configs, &num_configs)) + if (!eglChooseConfig(m_egl_display, attribs, config, num_configs, &num_configs)) { INFO_LOG(VIDEO, "Error: couldn't get an EGL visual config"); delete[] config; @@ -95,80 +96,68 @@ void cInterfaceEGL::DetectMode() { EGLint attribVal; bool ret; - ret = eglGetConfigAttrib(egl_dpy, config[i], EGL_RENDERABLE_TYPE, &attribVal); + ret = eglGetConfigAttrib(m_egl_display, config[i], EGL_RENDERABLE_TYPE, &attribVal); if (ret) { if (attribVal & EGL_OPENGL_BIT) supportsGL = true; - if (attribVal & (1 << 6)) /* EGL_OPENGL_ES3_BIT_KHR */ + if (attribVal & EGL_OPENGL_ES3_BIT_KHR) supportsGLES3 = true; - if (attribVal & EGL_OPENGL_ES2_BIT) - supportsGLES2 = true; } } delete[] config; } - if (preferGLES) - { - if (supportsGLES3) - s_opengl_mode = GLInterfaceMode::MODE_OPENGLES3; - else if (supportsGLES2) - s_opengl_mode = GLInterfaceMode::MODE_OPENGLES2; - else if (supportsGL) - s_opengl_mode = GLInterfaceMode::MODE_OPENGL; - } - else - { - 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_OPENGL) + if (supportsGL) { INFO_LOG(VIDEO, "Using OpenGL"); + m_opengl_mode = Mode::OpenGL; } - else if (s_opengl_mode == GLInterfaceMode::MODE_OPENGLES3) - { - INFO_LOG(VIDEO, "Using OpenGL|ES 3"); - } - else if (s_opengl_mode == GLInterfaceMode::MODE_OPENGLES2) + else if (supportsGLES3) { - INFO_LOG(VIDEO, "Using OpenGL|ES 2"); + INFO_LOG(VIDEO, "Using OpenGL|ES"); + m_opengl_mode = Mode::OpenGLES; } - else if (s_opengl_mode == GLInterfaceMode::MODE_DETECT) + else { // Errored before we found a mode ERROR_LOG(VIDEO, "Error: Failed to detect OpenGL flavour, falling back to OpenGL"); // This will fail to create a context, as it'll try to use the same attribs we just failed to // find a matching config with - s_opengl_mode = GLInterfaceMode::MODE_OPENGL; + m_opengl_mode = Mode::OpenGL; } } +EGLDisplay GLContextEGL::OpenEGLDisplay() +{ + return eglGetDisplay(EGL_DEFAULT_DISPLAY); +} + +EGLNativeWindowType GLContextEGL::GetEGLNativeWindow(EGLConfig config) +{ + return reinterpret_cast<EGLNativeWindowType>(EGL_DEFAULT_DISPLAY); +} + // Create rendering window. // Call browser: Core.cpp:EmuThread() > main.cpp:Video_Initialize() -bool cInterfaceEGL::Create(void* window_handle, bool stereo, bool core) +bool GLContextEGL::Initialize(void* display_handle, void* window_handle, bool stereo, bool core) { + const bool has_handle = !!window_handle; + EGLint egl_major, egl_minor; bool supports_core_profile = false; - egl_dpy = OpenDisplay(); - m_host_window = (EGLNativeWindowType)window_handle; - m_has_handle = !!window_handle; - m_core = core; + m_host_display = display_handle; + m_host_window = window_handle; + m_egl_display = OpenEGLDisplay(); - if (!egl_dpy) + if (!m_egl_display) { INFO_LOG(VIDEO, "Error: eglGetDisplay() failed"); return false; } - if (!eglInitialize(egl_dpy, &egl_major, &egl_minor)) + if (!eglInitialize(m_egl_display, &egl_major, &egl_minor)) { INFO_LOG(VIDEO, "Error: eglInitialize() failed"); return false; @@ -177,12 +166,13 @@ bool cInterfaceEGL::Create(void* window_handle, bool stereo, bool core) /* Detection code */ EGLint num_configs; - DetectMode(); + if (m_opengl_mode == Mode::Detect) + DetectMode(has_handle); // attributes for a visual in RGBA format with at least // 8 bits per color int attribs[] = {EGL_RENDERABLE_TYPE, - EGL_OPENGL_ES2_BIT, + 0, EGL_RED_SIZE, 8, EGL_GREEN_SIZE, @@ -190,43 +180,38 @@ bool cInterfaceEGL::Create(void* window_handle, bool stereo, bool core) EGL_BLUE_SIZE, 8, EGL_SURFACE_TYPE, - m_has_handle ? EGL_WINDOW_BIT : 0, + has_handle ? EGL_WINDOW_BIT : 0, EGL_NONE}; std::vector<EGLint> ctx_attribs; - switch (s_opengl_mode) + switch (m_opengl_mode) { - case GLInterfaceMode::MODE_OPENGL: + case Mode::OpenGL: attribs[1] = EGL_OPENGL_BIT; ctx_attribs = {EGL_NONE}; break; - case GLInterfaceMode::MODE_OPENGLES2: - attribs[1] = EGL_OPENGL_ES2_BIT; - ctx_attribs = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE}; - break; - case GLInterfaceMode::MODE_OPENGLES3: - attribs[1] = (1 << 6); /* EGL_OPENGL_ES3_BIT_KHR */ + case Mode::OpenGLES: + attribs[1] = EGL_OPENGL_ES3_BIT_KHR; ctx_attribs = {EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE}; break; default: ERROR_LOG(VIDEO, "Unknown opengl mode set"); return false; - break; } - if (!eglChooseConfig(egl_dpy, attribs, &m_config, 1, &num_configs)) + if (!eglChooseConfig(m_egl_display, attribs, &m_config, 1, &num_configs)) { INFO_LOG(VIDEO, "Error: couldn't get an EGL visual config"); return false; } - if (s_opengl_mode == GLInterfaceMode::MODE_OPENGL) + if (m_opengl_mode == Mode::OpenGL) eglBindAPI(EGL_OPENGL_API); else eglBindAPI(EGL_OPENGL_ES_API); std::string tmp; - std::istringstream buffer(eglQueryString(egl_dpy, EGL_EXTENSIONS)); + std::istringstream buffer(eglQueryString(m_egl_display, EGL_EXTENSIONS)); while (buffer >> tmp) { if (tmp == "EGL_KHR_surfaceless_context") @@ -235,19 +220,9 @@ bool cInterfaceEGL::Create(void* window_handle, bool stereo, bool core) supports_core_profile = true; } - if (supports_core_profile && core && s_opengl_mode == GLInterfaceMode::MODE_OPENGL) + if (supports_core_profile && core && m_opengl_mode == Mode::OpenGL) { - std::array<std::pair<int, int>, 7> versions_to_try = {{ - {4, 5}, - {4, 4}, - {4, 3}, - {4, 2}, - {4, 1}, - {4, 0}, - {3, 3}, - }}; - - for (const auto& version : versions_to_try) + for (const auto& version : s_desktop_opengl_versions) { std::vector<EGLint> core_attribs = {EGL_CONTEXT_MAJOR_VERSION_KHR, version.first, @@ -259,8 +234,8 @@ bool cInterfaceEGL::Create(void* window_handle, bool stereo, bool core) EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR, EGL_NONE}; - egl_ctx = eglCreateContext(egl_dpy, m_config, EGL_NO_CONTEXT, &core_attribs[0]); - if (egl_ctx) + m_egl_context = eglCreateContext(m_egl_display, m_config, EGL_NO_CONTEXT, &core_attribs[0]); + if (m_egl_context) { m_attribs = std::move(core_attribs); break; @@ -268,14 +243,13 @@ bool cInterfaceEGL::Create(void* window_handle, bool stereo, bool core) } } - if (!egl_ctx) + if (!m_egl_context) { - m_core = false; - egl_ctx = eglCreateContext(egl_dpy, m_config, EGL_NO_CONTEXT, &ctx_attribs[0]); + m_egl_context = eglCreateContext(m_egl_display, m_config, EGL_NO_CONTEXT, &ctx_attribs[0]); m_attribs = std::move(ctx_attribs); } - if (!egl_ctx) + if (!m_egl_context) { INFO_LOG(VIDEO, "Error: eglCreateContext failed"); return false; @@ -286,56 +260,45 @@ bool cInterfaceEGL::Create(void* window_handle, bool stereo, bool core) ERROR_LOG(VIDEO, "Error: CreateWindowSurface failed 0x%04x", eglGetError()); return false; } - return true; -} -std::unique_ptr<cInterfaceBase> cInterfaceEGL::CreateSharedContext() -{ - std::unique_ptr<cInterfaceBase> context = std::make_unique<cInterfaceEGL>(); - if (!context->Create(this)) - return nullptr; - return context; + return MakeCurrent(); } -bool cInterfaceEGL::Create(cInterfaceBase* main_context) +std::unique_ptr<GLContext> GLContextEGL::CreateSharedContext() { - cInterfaceEGL* egl_context = static_cast<cInterfaceEGL*>(main_context); - - egl_dpy = egl_context->egl_dpy; - m_core = egl_context->m_core; - m_config = egl_context->m_config; - m_supports_surfaceless = egl_context->m_supports_surfaceless; - m_is_shared = true; - m_has_handle = false; - - if (egl_context->GetMode() == GLInterfaceMode::MODE_OPENGL) - eglBindAPI(EGL_OPENGL_API); - else - eglBindAPI(EGL_OPENGL_ES_API); - - egl_ctx = - eglCreateContext(egl_dpy, m_config, egl_context->egl_ctx, egl_context->m_attribs.data()); - if (!egl_ctx) + eglBindAPI(m_opengl_mode == Mode::OpenGL ? EGL_OPENGL_API : EGL_OPENGL_ES_API); + EGLContext new_egl_context = + eglCreateContext(m_egl_display, m_config, m_egl_context, m_attribs.data()); + if (!new_egl_context) { INFO_LOG(VIDEO, "Error: eglCreateContext failed 0x%04x", eglGetError()); - return false; + return nullptr; } - if (!CreateWindowSurface()) + std::unique_ptr<GLContextEGL> new_context = std::make_unique<GLContextEGL>(); + new_context->m_opengl_mode = m_opengl_mode; + new_context->m_egl_context = new_egl_context; + new_context->m_host_display = m_host_display; + new_context->m_egl_display = m_egl_display; + new_context->m_config = m_config; + new_context->m_supports_surfaceless = m_supports_surfaceless; + new_context->m_is_shared = true; + if (!new_context->CreateWindowSurface()) { ERROR_LOG(VIDEO, "Error: CreateWindowSurface failed 0x%04x", eglGetError()); - return false; + return nullptr; } - return true; + + return new_context; } -bool cInterfaceEGL::CreateWindowSurface() +bool GLContextEGL::CreateWindowSurface() { - if (m_has_handle) + if (m_host_window) { - EGLNativeWindowType native_window = InitializePlatform(m_host_window, m_config); - egl_surf = eglCreateWindowSurface(egl_dpy, m_config, native_window, nullptr); - if (!egl_surf) + EGLNativeWindowType native_window = GetEGLNativeWindow(m_config); + m_egl_surface = eglCreateWindowSurface(m_egl_display, m_config, native_window, nullptr); + if (!m_egl_surface) { INFO_LOG(VIDEO, "Error: eglCreateWindowSurface failed"); return false; @@ -346,8 +309,8 @@ bool cInterfaceEGL::CreateWindowSurface() EGLint attrib_list[] = { EGL_NONE, }; - egl_surf = eglCreatePbufferSurface(egl_dpy, m_config, attrib_list); - if (!egl_surf) + m_egl_surface = eglCreatePbufferSurface(m_egl_display, m_config, attrib_list); + if (!m_egl_surface) { INFO_LOG(VIDEO, "Error: eglCreatePbufferSurface failed"); return false; @@ -355,56 +318,54 @@ bool cInterfaceEGL::CreateWindowSurface() } else { - egl_surf = EGL_NO_SURFACE; + m_egl_surface = EGL_NO_SURFACE; } return true; } -void cInterfaceEGL::DestroyWindowSurface() +void GLContextEGL::DestroyWindowSurface() { - if (egl_surf != EGL_NO_SURFACE && !eglDestroySurface(egl_dpy, egl_surf)) - NOTICE_LOG(VIDEO, "Could not destroy window surface."); - egl_surf = EGL_NO_SURFACE; -} + if (m_egl_surface == EGL_NO_SURFACE) + return; -bool cInterfaceEGL::MakeCurrent() -{ - return eglMakeCurrent(egl_dpy, egl_surf, egl_surf, egl_ctx); + if (eglGetCurrentSurface(EGL_DRAW) == m_egl_surface) + eglMakeCurrent(m_egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + if (!eglDestroySurface(m_egl_display, m_egl_surface)) + NOTICE_LOG(VIDEO, "Could not destroy window surface."); + m_egl_surface = EGL_NO_SURFACE; } -void cInterfaceEGL::UpdateHandle(void* window_handle) +bool GLContextEGL::MakeCurrent() { - m_host_window = (EGLNativeWindowType)window_handle; - m_has_handle = !!window_handle; + return eglMakeCurrent(m_egl_display, m_egl_surface, m_egl_surface, m_egl_context); } -void cInterfaceEGL::UpdateSurface() +void GLContextEGL::UpdateSurface(void* window_handle) { + m_host_window = window_handle; ClearCurrent(); DestroyWindowSurface(); CreateWindowSurface(); MakeCurrent(); } -bool cInterfaceEGL::ClearCurrent() +bool GLContextEGL::ClearCurrent() { - return eglMakeCurrent(egl_dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + return eglMakeCurrent(m_egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); } // Close backend -void cInterfaceEGL::Shutdown() +void GLContextEGL::DestroyContext() { - ShutdownPlatform(); - if (egl_ctx) - { - if (!eglMakeCurrent(egl_dpy, egl_surf, egl_surf, egl_ctx)) - NOTICE_LOG(VIDEO, "Could not release drawing context."); - 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."); - DestroyWindowSurface(); - if (!m_is_shared && !eglTerminate(egl_dpy)) - NOTICE_LOG(VIDEO, "Could not destroy display connection."); - egl_ctx = nullptr; - } + if (!m_egl_context) + return; + + if (eglGetCurrentContext() == m_egl_context) + eglMakeCurrent(m_egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + if (!eglDestroyContext(m_egl_display, m_egl_context)) + NOTICE_LOG(VIDEO, "Could not destroy drawing context."); + if (!m_is_shared && !eglTerminate(m_egl_display)) + NOTICE_LOG(VIDEO, "Could not destroy display connection."); + m_egl_context = EGL_NO_CONTEXT; + m_egl_display = EGL_NO_DISPLAY; } diff --git a/Source/Core/Common/GL/GLInterface/EGL.h b/Source/Core/Common/GL/GLInterface/EGL.h index 79c623c942..51dd3fda35 100644 --- a/Source/Core/Common/GL/GLInterface/EGL.h +++ b/Source/Core/Common/GL/GLInterface/EGL.h @@ -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; }; diff --git a/Source/Core/Common/GL/GLInterface/EGLAndroid.cpp b/Source/Core/Common/GL/GLInterface/EGLAndroid.cpp index 44fb41f1d2..2a5123b21f 100644 --- a/Source/Core/Common/GL/GLInterface/EGLAndroid.cpp +++ b/Source/Core/Common/GL/GLInterface/EGLAndroid.cpp @@ -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); } diff --git a/Source/Core/Common/GL/GLInterface/EGLAndroid.h b/Source/Core/Common/GL/GLInterface/EGLAndroid.h index 8a43f261c9..f743f2fb32 100644 --- a/Source/Core/Common/GL/GLInterface/EGLAndroid.h +++ b/Source/Core/Common/GL/GLInterface/EGLAndroid.h @@ -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; }; diff --git a/Source/Core/Common/GL/GLInterface/EGLHaiku.cpp b/Source/Core/Common/GL/GLInterface/EGLHaiku.cpp deleted file mode 100644 index 253b9c8c98..0000000000 --- a/Source/Core/Common/GL/GLInterface/EGLHaiku.cpp +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2017 Dolphin Emulator Project -// Licensed under GPLv2+ -// Refer to the license.txt file included. - -#include "Common/GL/GLInterface/EGLHaiku.h" - -#include <Window.h> - -EGLDisplay cInterfaceEGLHaiku::OpenDisplay() -{ - return eglGetDisplay(EGL_DEFAULT_DISPLAY); -} - -EGLNativeWindowType cInterfaceEGLHaiku::InitializePlatform(EGLNativeWindowType host_window, - EGLConfig config) -{ - EGLint format; - eglGetConfigAttrib(egl_dpy, config, EGL_NATIVE_VISUAL_ID, &format); - - BWindow* window = reinterpret_cast<BWindow*>(host_window); - const int width = window->Size().width; - const int height = window->Size().height; - GLInterface->SetBackBufferDimensions(width, height); - - return host_window; -} - -void cInterfaceEGLHaiku::ShutdownPlatform() -{ -} diff --git a/Source/Core/Common/GL/GLInterface/EGLHaiku.h b/Source/Core/Common/GL/GLInterface/EGLHaiku.h deleted file mode 100644 index fc755963df..0000000000 --- a/Source/Core/Common/GL/GLInterface/EGLHaiku.h +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2017 Dolphin Emulator Project -// Licensed under GPLv2+ -// Refer to the license.txt file included. - -#pragma once - -#include "Common/GL/GLInterface/EGL.h" - -class cInterfaceEGLHaiku final : public cInterfaceEGL -{ -protected: - EGLDisplay OpenDisplay() override; - EGLNativeWindowType InitializePlatform(EGLNativeWindowType host_window, - EGLConfig config) override; - void ShutdownPlatform() override; -}; diff --git a/Source/Core/Common/GL/GLInterface/EGLX11.cpp b/Source/Core/Common/GL/GLInterface/EGLX11.cpp index 432f0aa601..bd59033738 100644 --- a/Source/Core/Common/GL/GLInterface/EGLX11.cpp +++ b/Source/Core/Common/GL/GLInterface/EGLX11.cpp @@ -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()); } diff --git a/Source/Core/Common/GL/GLInterface/EGLX11.h b/Source/Core/Common/GL/GLInterface/EGLX11.h index dab5a38d8e..f4be040fae 100644 --- a/Source/Core/Common/GL/GLInterface/EGLX11.h +++ b/Source/Core/Common/GL/GLInterface/EGLX11.h @@ -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; }; diff --git a/Source/Core/Common/GL/GLInterface/GLInterface.cpp b/Source/Core/Common/GL/GLInterface/GLInterface.cpp deleted file mode 100644 index edd84cc2ab..0000000000 --- a/Source/Core/Common/GL/GLInterface/GLInterface.cpp +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2014 Dolphin Emulator Project -// Licensed under GPLv2+ -// Refer to the license.txt file included. - -#include <memory> - -#include "Common/GL/GLInterfaceBase.h" - -#if 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 -#elif defined(USE_EGL) && USE_EGL && defined(USE_HEADLESS) -#include "Common/GL/GLInterface/EGL.h" -#elif ANDROID -#include "Common/GL/GLInterface/EGLAndroid.h" -#elif defined(__HAIKU__) -#include "Common/GL/GLInterface/BGL.h" -#else -#error Platform doesnt have a GLInterface -#endif - -std::unique_ptr<cInterfaceBase> HostGL_CreateGLInterface() -{ -#if defined(__APPLE__) - return std::make_unique<cInterfaceAGL>(); -#elif defined(_WIN32) - return std::make_unique<cInterfaceWGL>(); -#elif defined(USE_EGL) && defined(USE_HEADLESS) - return std::make_unique<cInterfaceEGL>(); -#elif defined(HAVE_X11) && HAVE_X11 -#if defined(USE_EGL) && USE_EGL - return std::make_unique<cInterfaceEGLX11>(); -#else - return std::make_unique<cInterfaceGLX>(); -#endif -#elif ANDROID - return std::make_unique<cInterfaceEGLAndroid>(); -#elif defined(__HAIKU__) - return std::make_unique<cInterfaceBGL>(); -#else - return nullptr; -#endif -} diff --git a/Source/Core/Common/GL/GLInterface/GLX.cpp b/Source/Core/Common/GL/GLInterface/GLX.cpp index 28714fd20c..c2e4491ff5 100644 --- a/Source/Core/Common/GL/GLInterface/GLX.cpp +++ b/Source/Core/Common/GL/GLInterface/GLX.cpp @@ -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,7 +204,7 @@ 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); @@ -199,119 +212,95 @@ bool cInterfaceGLX::Create(void* window_handle, bool stereo, bool core) } 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(); } diff --git a/Source/Core/Common/GL/GLInterface/GLX.h b/Source/Core/Common/GL/GLInterface/GLX.h index 724dca5141..1b74e53f60 100644 --- a/Source/Core/Common/GL/GLInterface/GLX.h +++ b/Source/Core/Common/GL/GLInterface/GLX.h @@ -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(); }; diff --git a/Source/Core/Common/GL/GLInterface/WGL.cpp b/Source/Core/Common/GL/GLInterface/WGL.cpp index 48f4b8c96c..e168f94e51 100644 --- a/Source/Core/Common/GL/GLInterface/WGL.cpp +++ b/Source/Core/Common/GL/GLInterface/WGL.cpp @@ -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,7 +328,6 @@ bool cInterfaceWGL::Create(void* window_handle, bool stereo, bool core) { wglDeleteContext(m_rc); m_rc = core_context; - m_core = true; } else { @@ -314,38 +335,35 @@ bool cInterfaceWGL::Create(void* window_handle, bool stereo, bool core) } } - 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) { @@ -353,12 +371,7 @@ HGLRC cInterfaceWGL::CreateCoreContext(HDC dc, HGLRC share_context) 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; } diff --git a/Source/Core/Common/GL/GLInterface/WGL.h b/Source/Core/Common/GL/GLInterface/WGL.h index efa9655713..9e3f9d86ef 100644 --- a/Source/Core/Common/GL/GLInterface/WGL.h +++ b/Source/Core/Common/GL/GLInterface/WGL.h @@ -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); diff --git a/Source/Core/Common/GL/GLInterface/X11_Util.cpp b/Source/Core/Common/GL/GLInterface/X11_Util.cpp deleted file mode 100644 index ed884a9ffd..0000000000 --- a/Source/Core/Common/GL/GLInterface/X11_Util.cpp +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2012 Dolphin Emulator Project -// Licensed under GPLv2+ -// Refer to the license.txt file included. - -#include "Common/GL/GLInterface/X11_Util.h" -#include "Common/GL/GLInterfaceBase.h" -#include "Common/Logging/Log.h" -#include "Common/Thread.h" - -void cX11Window::Initialize(Display* _dpy) -{ - dpy = _dpy; -} - -Window cX11Window::CreateXWindow(Window parent, XVisualInfo* vi) -{ - XSetWindowAttributes attr; - - colormap = XCreateColormap(dpy, parent, vi->visual, AllocNone); - - // Setup window attributes - attr.colormap = colormap; - - XWindowAttributes attribs; - if (!XGetWindowAttributes(dpy, parent, &attribs)) - { - ERROR_LOG(VIDEO, "Window attribute retrieval failed"); - return 0; - } - - // Create the window - win = XCreateWindow(dpy, parent, 0, 0, attribs.width, attribs.height, 0, vi->depth, InputOutput, - vi->visual, CWColormap, &attr); - XSelectInput(dpy, parent, StructureNotifyMask); - XMapWindow(dpy, win); - XSync(dpy, True); - - xEventThread = std::thread(&cX11Window::XEventThread, this); - - return win; -} - -void cX11Window::DestroyXWindow(void) -{ - XUnmapWindow(dpy, win); - win = 0; - if (xEventThread.joinable()) - xEventThread.join(); - XFreeColormap(dpy, colormap); -} - -void cX11Window::XEventThread() -{ - while (win) - { - XEvent event; - for (int num_events = XPending(dpy); num_events > 0; num_events--) - { - XNextEvent(dpy, &event); - switch (event.type) - { - case ConfigureNotify: - XResizeWindow(dpy, win, event.xconfigure.width, event.xconfigure.height); - GLInterface->SetBackBufferDimensions(event.xconfigure.width, event.xconfigure.height); - break; - default: - break; - } - } - Common::SleepCurrentThread(20); - } -} diff --git a/Source/Core/Common/GL/GLInterface/X11_Util.h b/Source/Core/Common/GL/GLInterface/X11_Util.h deleted file mode 100644 index e79a6fe1df..0000000000 --- a/Source/Core/Common/GL/GLInterface/X11_Util.h +++ /dev/null @@ -1,27 +0,0 @@ -// 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 <string> -#include <thread> - -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; -}; diff --git a/Source/Core/Common/GL/GLInterfaceBase.h b/Source/Core/Common/GL/GLInterfaceBase.h deleted file mode 100644 index 4ffb7f5f53..0000000000 --- a/Source/Core/Common/GL/GLInterfaceBase.h +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2008 Dolphin Emulator Project -// Licensed under GPLv2+ -// Refer to the license.txt file included. - -#pragma once - -#include <memory> -#include <string> - -#include "Common/CommonTypes.h" - -enum class GLInterfaceMode -{ - MODE_DETECT, - MODE_OPENGL, - MODE_OPENGLES2, - MODE_OPENGLES3, -}; - -class cInterfaceBase -{ -protected: - // Window dimensions. - u32 s_backbuffer_width = 0; - u32 s_backbuffer_height = 0; - bool m_core = false; - bool m_is_shared = false; - - GLInterfaceMode s_opengl_mode = GLInterfaceMode::MODE_DETECT; - -public: - virtual ~cInterfaceBase() {} - virtual void Swap() {} - virtual void SetMode(GLInterfaceMode mode) { s_opengl_mode = GLInterfaceMode::MODE_OPENGL; } - virtual GLInterfaceMode GetMode() { return s_opengl_mode; } - virtual void* GetFuncAddress(const std::string& name) { return nullptr; } - virtual bool Create(void* window_handle, bool stereo = false, bool core = true) { return true; } - virtual bool Create(cInterfaceBase* main_context) { return true; } - virtual bool MakeCurrent() { return true; } - virtual bool ClearCurrent() { return true; } - virtual void Shutdown() {} - virtual void SwapInterval(int Interval) {} - virtual u32 GetBackBufferWidth() { return s_backbuffer_width; } - virtual u32 GetBackBufferHeight() { return s_backbuffer_height; } - virtual void SetBackBufferDimensions(u32 W, u32 H) - { - s_backbuffer_width = W; - s_backbuffer_height = H; - } - virtual void Update() {} - virtual bool PeekMessages() { return false; } - virtual void UpdateHandle(void* window_handle) {} - virtual void UpdateSurface() {} - virtual std::unique_ptr<cInterfaceBase> CreateSharedContext() { return nullptr; } -}; - -extern std::unique_ptr<cInterfaceBase> GLInterface; - -// This function has to be defined along the Host_ functions from Core/Host.h. -// Current canonical implementation: DolphinWX/GLInterface/GLInterface.cpp. -std::unique_ptr<cInterfaceBase> HostGL_CreateGLInterface(); diff --git a/Source/Core/Common/GL/GLUtil.cpp b/Source/Core/Common/GL/GLUtil.cpp index 02a38d8654..ba0f76b9b0 100644 --- a/Source/Core/Common/GL/GLUtil.cpp +++ b/Source/Core/Common/GL/GLUtil.cpp @@ -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 diff --git a/Source/Core/Common/GL/GLUtil.h b/Source/Core/Common/GL/GLUtil.h index d4714026f0..1ec63ebad0 100644 --- a/Source/Core/Common/GL/GLUtil.h +++ b/Source/Core/Common/GL/GLUtil.h @@ -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 diff --git a/Source/Core/Common/GL/GLX11Window.cpp b/Source/Core/Common/GL/GLX11Window.cpp new file mode 100644 index 0000000000..681adaa099 --- /dev/null +++ b/Source/Core/Common/GL/GLX11Window.cpp @@ -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); +} diff --git a/Source/Core/Common/GL/GLX11Window.h b/Source/Core/Common/GL/GLX11Window.h new file mode 100644 index 0000000000..fd3020d1d8 --- /dev/null +++ b/Source/Core/Common/GL/GLX11Window.h @@ -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; +}; diff --git a/Source/Core/Common/WindowSystemInfo.h b/Source/Core/Common/WindowSystemInfo.h new file mode 100644 index 0000000000..897d034c2c --- /dev/null +++ b/Source/Core/Common/WindowSystemInfo.h @@ -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; +}; |
