mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 05:40:04 +00:00 
			
		
		
		
	Apply clang-format-15
This commit is contained in:
		
							parent
							
								
									3193775201
								
							
						
					
					
						commit
						99b9cec967
					
				
					 21 changed files with 1623 additions and 1779 deletions
				
			
		|  | @ -7,7 +7,7 @@ | |||
| 
 | ||||
| #define ALWAYS_INLINE __attribute__((always_inline)) inline | ||||
| 
 | ||||
| #define AssertMsg(cond, msg) assert(cond && msg) | ||||
| #define AssertMsg(cond, msg) assert(cond&& msg) | ||||
| #define Assert(cond) assert(cond) | ||||
| 
 | ||||
| #define Panic(msg) assert(false && msg) | ||||
|  |  | |||
							
								
								
									
										227
									
								
								src/citra_qt/externals/duckstation/gl/context.cpp
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										227
									
								
								src/citra_qt/externals/duckstation/gl/context.cpp
									
										
									
									
										vendored
									
									
								
							|  | @ -1,9 +1,9 @@ | |||
| #include "context.h" | ||||
| #include "../log.h" | ||||
| #include "loader.h" | ||||
| #include <cstdlib> | ||||
| #include <cstring> | ||||
| #include <stdlib.h> | ||||
| #include "../log.h" | ||||
| #include "context.h" | ||||
| #include "loader.h" | ||||
| Log_SetChannel(GL::Context); | ||||
| 
 | ||||
| #if defined(_WIN32) | ||||
|  | @ -20,16 +20,15 @@ Log_SetChannel(GL::Context); | |||
| 
 | ||||
| namespace GL { | ||||
| 
 | ||||
| static bool ShouldPreferESContext() | ||||
| { | ||||
| static bool ShouldPreferESContext() { | ||||
| #ifndef _MSC_VER | ||||
|   const char* value = std::getenv("PREFER_GLES_CONTEXT"); | ||||
|   return (value && strcmp(value, "1") == 0); | ||||
|     const char* value = std::getenv("PREFER_GLES_CONTEXT"); | ||||
|     return (value && strcmp(value, "1") == 0); | ||||
| #else | ||||
|   char buffer[2] = {}; | ||||
|   size_t buffer_size = sizeof(buffer); | ||||
|   getenv_s(&buffer_size, buffer, "PREFER_GLES_CONTEXT"); | ||||
|   return (std::strcmp(buffer, "1") == 0); | ||||
|     char buffer[2] = {}; | ||||
|     size_t buffer_size = sizeof(buffer); | ||||
|     getenv_s(&buffer_size, buffer, "PREFER_GLES_CONTEXT"); | ||||
|     return (std::strcmp(buffer, "1") == 0); | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
|  | @ -37,139 +36,131 @@ Context::Context(const WindowInfo& wi) : m_wi(wi) {} | |||
| 
 | ||||
| Context::~Context() = default; | ||||
| 
 | ||||
| std::vector<Context::FullscreenModeInfo> Context::EnumerateFullscreenModes() | ||||
| { | ||||
|   return {}; | ||||
| std::vector<Context::FullscreenModeInfo> Context::EnumerateFullscreenModes() { | ||||
|     return {}; | ||||
| } | ||||
| 
 | ||||
| std::unique_ptr<GL::Context> Context::Create(const WindowInfo& wi, const Version* versions_to_try, | ||||
|                                              size_t num_versions_to_try) | ||||
| { | ||||
|   if (ShouldPreferESContext()) | ||||
|   { | ||||
|     // move ES versions to the front
 | ||||
|     Version* new_versions_to_try = static_cast<Version*>(alloca(sizeof(Version) * num_versions_to_try)); | ||||
|     size_t count = 0; | ||||
|     for (size_t i = 0; i < num_versions_to_try; i++) | ||||
|     { | ||||
|       if (versions_to_try[i].profile == Profile::ES) | ||||
|         new_versions_to_try[count++] = versions_to_try[i]; | ||||
|                                              size_t num_versions_to_try) { | ||||
|     if (ShouldPreferESContext()) { | ||||
|         // move ES versions to the front
 | ||||
|         Version* new_versions_to_try = | ||||
|             static_cast<Version*>(alloca(sizeof(Version) * num_versions_to_try)); | ||||
|         size_t count = 0; | ||||
|         for (size_t i = 0; i < num_versions_to_try; i++) { | ||||
|             if (versions_to_try[i].profile == Profile::ES) | ||||
|                 new_versions_to_try[count++] = versions_to_try[i]; | ||||
|         } | ||||
|         for (size_t i = 0; i < num_versions_to_try; i++) { | ||||
|             if (versions_to_try[i].profile != Profile::ES) | ||||
|                 new_versions_to_try[count++] = versions_to_try[i]; | ||||
|         } | ||||
|         versions_to_try = new_versions_to_try; | ||||
|     } | ||||
|     for (size_t i = 0; i < num_versions_to_try; i++) | ||||
|     { | ||||
|       if (versions_to_try[i].profile != Profile::ES) | ||||
|         new_versions_to_try[count++] = versions_to_try[i]; | ||||
|     } | ||||
|     versions_to_try = new_versions_to_try; | ||||
|   } | ||||
| 
 | ||||
|   std::unique_ptr<Context> context; | ||||
|     std::unique_ptr<Context> context; | ||||
| #if defined(_WIN32) | ||||
|   context = ContextWGL::Create(wi, versions_to_try, num_versions_to_try); | ||||
|     context = ContextWGL::Create(wi, versions_to_try, num_versions_to_try); | ||||
| #elif defined(__APPLE__) | ||||
|   context = ContextAGL::Create(wi, versions_to_try, num_versions_to_try); | ||||
|     context = ContextAGL::Create(wi, versions_to_try, num_versions_to_try); | ||||
| #else | ||||
|   if (wi.type == WindowInfo::Type::X11) | ||||
|   { | ||||
|     const char* use_egl_x11 = std::getenv("USE_EGL_X11"); | ||||
|     if (use_egl_x11 && std::strcmp(use_egl_x11, "1") == 0) | ||||
|       context = ContextEGLX11::Create(wi, versions_to_try, num_versions_to_try); | ||||
|     else | ||||
|       context = ContextGLX::Create(wi, versions_to_try, num_versions_to_try); | ||||
|   } | ||||
|     if (wi.type == WindowInfo::Type::X11) { | ||||
|         const char* use_egl_x11 = std::getenv("USE_EGL_X11"); | ||||
|         if (use_egl_x11 && std::strcmp(use_egl_x11, "1") == 0) | ||||
|             context = ContextEGLX11::Create(wi, versions_to_try, num_versions_to_try); | ||||
|         else | ||||
|             context = ContextGLX::Create(wi, versions_to_try, num_versions_to_try); | ||||
|     } | ||||
| 
 | ||||
| #ifdef WAYLAND_ENABLED | ||||
|   if (wi.type == WindowInfo::Type::Wayland) | ||||
|     context = ContextEGLWayland::Create(wi, versions_to_try, num_versions_to_try); | ||||
|     if (wi.type == WindowInfo::Type::Wayland) | ||||
|         context = ContextEGLWayland::Create(wi, versions_to_try, num_versions_to_try); | ||||
| #endif | ||||
| #endif | ||||
| 
 | ||||
|   if (!context) | ||||
|     return nullptr; | ||||
|     if (!context) | ||||
|         return nullptr; | ||||
| 
 | ||||
|   Log_InfoPrintf("Created a %s context", context->IsGLES() ? "OpenGL ES" : "OpenGL"); | ||||
|     Log_InfoPrintf("Created a %s context", context->IsGLES() ? "OpenGL ES" : "OpenGL"); | ||||
| 
 | ||||
|   // TODO: Not thread-safe.
 | ||||
|   static Context* context_being_created; | ||||
|   context_being_created = context.get(); | ||||
|     // TODO: Not thread-safe.
 | ||||
|     static Context* context_being_created; | ||||
|     context_being_created = context.get(); | ||||
| 
 | ||||
|   if (!gladLoadGLLoader([](const char* name) { return context_being_created->GetProcAddress(name); })) | ||||
|   { | ||||
|     Log_ErrorPrintf("Failed to load GL functions for GLAD"); | ||||
|     return nullptr; | ||||
|   } | ||||
|     if (!gladLoadGLLoader( | ||||
|             [](const char* name) { return context_being_created->GetProcAddress(name); })) { | ||||
|         Log_ErrorPrintf("Failed to load GL functions for GLAD"); | ||||
|         return nullptr; | ||||
|     } | ||||
| 
 | ||||
|   const char* gl_vendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR)); | ||||
|   const char* gl_renderer = reinterpret_cast<const char*>(glGetString(GL_RENDERER)); | ||||
|   const char* gl_version = reinterpret_cast<const char*>(glGetString(GL_VERSION)); | ||||
|   const char* gl_shading_language_version = reinterpret_cast<const char*>(glGetString(GL_SHADING_LANGUAGE_VERSION)); | ||||
|   Log_InfoPrintf("GL_VENDOR: %s", gl_vendor); | ||||
|   Log_InfoPrintf("GL_RENDERER: %s", gl_renderer); | ||||
|   Log_InfoPrintf("GL_VERSION: %s", gl_version); | ||||
|   Log_InfoPrintf("GL_SHADING_LANGUAGE_VERSION: %s", gl_shading_language_version); | ||||
|     const char* gl_vendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR)); | ||||
|     const char* gl_renderer = reinterpret_cast<const char*>(glGetString(GL_RENDERER)); | ||||
|     const char* gl_version = reinterpret_cast<const char*>(glGetString(GL_VERSION)); | ||||
|     const char* gl_shading_language_version = | ||||
|         reinterpret_cast<const char*>(glGetString(GL_SHADING_LANGUAGE_VERSION)); | ||||
|     Log_InfoPrintf("GL_VENDOR: %s", gl_vendor); | ||||
|     Log_InfoPrintf("GL_RENDERER: %s", gl_renderer); | ||||
|     Log_InfoPrintf("GL_VERSION: %s", gl_version); | ||||
|     Log_InfoPrintf("GL_SHADING_LANGUAGE_VERSION: %s", gl_shading_language_version); | ||||
| 
 | ||||
|   return context; | ||||
|     return context; | ||||
| } | ||||
| 
 | ||||
| const std::array<Context::Version, 11>& Context::GetAllDesktopVersionsList() | ||||
| { | ||||
|   static constexpr std::array<Version, 11> vlist = {{{Profile::Core, 4, 6}, | ||||
|                                                      {Profile::Core, 4, 5}, | ||||
|                                                      {Profile::Core, 4, 4}, | ||||
|                                                      {Profile::Core, 4, 3}, | ||||
|                                                      {Profile::Core, 4, 2}, | ||||
|                                                      {Profile::Core, 4, 1}, | ||||
|                                                      {Profile::Core, 4, 0}, | ||||
|                                                      {Profile::Core, 3, 3}, | ||||
|                                                      {Profile::Core, 3, 2}, | ||||
|                                                      {Profile::Core, 3, 1}, | ||||
|                                                      {Profile::Core, 3, 0}}}; | ||||
|   return vlist; | ||||
| const std::array<Context::Version, 11>& Context::GetAllDesktopVersionsList() { | ||||
|     static constexpr std::array<Version, 11> vlist = {{{Profile::Core, 4, 6}, | ||||
|                                                        {Profile::Core, 4, 5}, | ||||
|                                                        {Profile::Core, 4, 4}, | ||||
|                                                        {Profile::Core, 4, 3}, | ||||
|                                                        {Profile::Core, 4, 2}, | ||||
|                                                        {Profile::Core, 4, 1}, | ||||
|                                                        {Profile::Core, 4, 0}, | ||||
|                                                        {Profile::Core, 3, 3}, | ||||
|                                                        {Profile::Core, 3, 2}, | ||||
|                                                        {Profile::Core, 3, 1}, | ||||
|                                                        {Profile::Core, 3, 0}}}; | ||||
|     return vlist; | ||||
| } | ||||
| 
 | ||||
| const std::array<Context::Version, 12>& Context::GetAllDesktopVersionsListWithFallback() | ||||
| { | ||||
|   static constexpr std::array<Version, 12> vlist = {{{Profile::Core, 4, 6}, | ||||
|                                                      {Profile::Core, 4, 5}, | ||||
|                                                      {Profile::Core, 4, 4}, | ||||
|                                                      {Profile::Core, 4, 3}, | ||||
|                                                      {Profile::Core, 4, 2}, | ||||
|                                                      {Profile::Core, 4, 1}, | ||||
|                                                      {Profile::Core, 4, 0}, | ||||
|                                                      {Profile::Core, 3, 3}, | ||||
|                                                      {Profile::Core, 3, 2}, | ||||
|                                                      {Profile::Core, 3, 1}, | ||||
|                                                      {Profile::Core, 3, 0}, | ||||
|                                                      {Profile::NoProfile, 0, 0}}}; | ||||
|   return vlist; | ||||
| const std::array<Context::Version, 12>& Context::GetAllDesktopVersionsListWithFallback() { | ||||
|     static constexpr std::array<Version, 12> vlist = {{{Profile::Core, 4, 6}, | ||||
|                                                        {Profile::Core, 4, 5}, | ||||
|                                                        {Profile::Core, 4, 4}, | ||||
|                                                        {Profile::Core, 4, 3}, | ||||
|                                                        {Profile::Core, 4, 2}, | ||||
|                                                        {Profile::Core, 4, 1}, | ||||
|                                                        {Profile::Core, 4, 0}, | ||||
|                                                        {Profile::Core, 3, 3}, | ||||
|                                                        {Profile::Core, 3, 2}, | ||||
|                                                        {Profile::Core, 3, 1}, | ||||
|                                                        {Profile::Core, 3, 0}, | ||||
|                                                        {Profile::NoProfile, 0, 0}}}; | ||||
|     return vlist; | ||||
| } | ||||
| 
 | ||||
| const std::array<Context::Version, 4>& Context::GetAllESVersionsList() | ||||
| { | ||||
|   static constexpr std::array<Version, 4> vlist = { | ||||
|     {{Profile::ES, 3, 2}, {Profile::ES, 3, 1}, {Profile::ES, 3, 0}, {Profile::ES, 2, 0}}}; | ||||
|   return vlist; | ||||
| const std::array<Context::Version, 4>& Context::GetAllESVersionsList() { | ||||
|     static constexpr std::array<Version, 4> vlist = { | ||||
|         {{Profile::ES, 3, 2}, {Profile::ES, 3, 1}, {Profile::ES, 3, 0}, {Profile::ES, 2, 0}}}; | ||||
|     return vlist; | ||||
| } | ||||
| 
 | ||||
| const std::array<Context::Version, 16>& Context::GetAllVersionsList() | ||||
| { | ||||
|   static constexpr std::array<Version, 16> vlist = {{{Profile::Core, 4, 6}, | ||||
|                                                      {Profile::Core, 4, 5}, | ||||
|                                                      {Profile::Core, 4, 4}, | ||||
|                                                      {Profile::Core, 4, 3}, | ||||
|                                                      {Profile::Core, 4, 2}, | ||||
|                                                      {Profile::Core, 4, 1}, | ||||
|                                                      {Profile::Core, 4, 0}, | ||||
|                                                      {Profile::Core, 3, 3}, | ||||
|                                                      {Profile::Core, 3, 2}, | ||||
|                                                      {Profile::Core, 3, 1}, | ||||
|                                                      {Profile::Core, 3, 0}, | ||||
|                                                      {Profile::ES, 3, 2}, | ||||
|                                                      {Profile::ES, 3, 1}, | ||||
|                                                      {Profile::ES, 3, 0}, | ||||
|                                                      {Profile::ES, 2, 0}, | ||||
|                                                      {Profile::NoProfile, 0, 0}}}; | ||||
|   return vlist; | ||||
| const std::array<Context::Version, 16>& Context::GetAllVersionsList() { | ||||
|     static constexpr std::array<Version, 16> vlist = {{{Profile::Core, 4, 6}, | ||||
|                                                        {Profile::Core, 4, 5}, | ||||
|                                                        {Profile::Core, 4, 4}, | ||||
|                                                        {Profile::Core, 4, 3}, | ||||
|                                                        {Profile::Core, 4, 2}, | ||||
|                                                        {Profile::Core, 4, 1}, | ||||
|                                                        {Profile::Core, 4, 0}, | ||||
|                                                        {Profile::Core, 3, 3}, | ||||
|                                                        {Profile::Core, 3, 2}, | ||||
|                                                        {Profile::Core, 3, 1}, | ||||
|                                                        {Profile::Core, 3, 0}, | ||||
|                                                        {Profile::ES, 3, 2}, | ||||
|                                                        {Profile::ES, 3, 1}, | ||||
|                                                        {Profile::ES, 3, 0}, | ||||
|                                                        {Profile::ES, 2, 0}, | ||||
|                                                        {Profile::NoProfile, 0, 0}}}; | ||||
|     return vlist; | ||||
| } | ||||
| 
 | ||||
| } // namespace GL
 | ||||
|  |  | |||
							
								
								
									
										108
									
								
								src/citra_qt/externals/duckstation/gl/context.h
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										108
									
								
								src/citra_qt/externals/duckstation/gl/context.h
									
										
									
									
										vendored
									
									
								
							|  | @ -1,77 +1,81 @@ | |||
| #pragma once | ||||
| #include "../duckstation_compat.h" | ||||
| #include "../window_info.h" | ||||
| #include <array> | ||||
| #include <memory> | ||||
| #include <vector> | ||||
| #include "../duckstation_compat.h" | ||||
| #include "../window_info.h" | ||||
| 
 | ||||
| namespace GL { | ||||
| using namespace citra; | ||||
| class Context | ||||
| { | ||||
| class Context { | ||||
| public: | ||||
|   Context(const WindowInfo& wi); | ||||
|   virtual ~Context(); | ||||
|     Context(const WindowInfo& wi); | ||||
|     virtual ~Context(); | ||||
| 
 | ||||
|   enum class Profile | ||||
|   { | ||||
|     NoProfile, | ||||
|     Core, | ||||
|     ES | ||||
|   }; | ||||
|     enum class Profile { NoProfile, Core, ES }; | ||||
| 
 | ||||
|   struct Version | ||||
|   { | ||||
|     Profile profile; | ||||
|     int major_version; | ||||
|     int minor_version; | ||||
|   }; | ||||
|     struct Version { | ||||
|         Profile profile; | ||||
|         int major_version; | ||||
|         int minor_version; | ||||
|     }; | ||||
| 
 | ||||
|   struct FullscreenModeInfo | ||||
|   { | ||||
|     u32 width; | ||||
|     u32 height; | ||||
|     float refresh_rate; | ||||
|   }; | ||||
|     struct FullscreenModeInfo { | ||||
|         u32 width; | ||||
|         u32 height; | ||||
|         float refresh_rate; | ||||
|     }; | ||||
| 
 | ||||
|   ALWAYS_INLINE const WindowInfo& GetWindowInfo() const { return m_wi; } | ||||
|   ALWAYS_INLINE bool IsGLES() const { return (m_version.profile == Profile::ES); } | ||||
|   ALWAYS_INLINE u32 GetSurfaceWidth() const { return m_wi.surface_width; } | ||||
|   ALWAYS_INLINE u32 GetSurfaceHeight() const { return m_wi.surface_height; } | ||||
|   ALWAYS_INLINE WindowInfo::SurfaceFormat GetSurfaceFormat() const { return m_wi.surface_format; } | ||||
|     ALWAYS_INLINE const WindowInfo& GetWindowInfo() const { | ||||
|         return m_wi; | ||||
|     } | ||||
|     ALWAYS_INLINE bool IsGLES() const { | ||||
|         return (m_version.profile == Profile::ES); | ||||
|     } | ||||
|     ALWAYS_INLINE u32 GetSurfaceWidth() const { | ||||
|         return m_wi.surface_width; | ||||
|     } | ||||
|     ALWAYS_INLINE u32 GetSurfaceHeight() const { | ||||
|         return m_wi.surface_height; | ||||
|     } | ||||
|     ALWAYS_INLINE WindowInfo::SurfaceFormat GetSurfaceFormat() const { | ||||
|         return m_wi.surface_format; | ||||
|     } | ||||
| 
 | ||||
|   virtual void* GetProcAddress(const char* name) = 0; | ||||
|   virtual bool ChangeSurface(const WindowInfo& new_wi) = 0; | ||||
|   virtual void ResizeSurface(u32 new_surface_width = 0, u32 new_surface_height = 0) = 0; | ||||
|   virtual bool SwapBuffers() = 0; | ||||
|   virtual bool MakeCurrent() = 0; | ||||
|   virtual bool DoneCurrent() = 0; | ||||
|   virtual bool SetSwapInterval(s32 interval) = 0; | ||||
|   virtual std::unique_ptr<Context> CreateSharedContext(const WindowInfo& wi) = 0; | ||||
|     virtual void* GetProcAddress(const char* name) = 0; | ||||
|     virtual bool ChangeSurface(const WindowInfo& new_wi) = 0; | ||||
|     virtual void ResizeSurface(u32 new_surface_width = 0, u32 new_surface_height = 0) = 0; | ||||
|     virtual bool SwapBuffers() = 0; | ||||
|     virtual bool MakeCurrent() = 0; | ||||
|     virtual bool DoneCurrent() = 0; | ||||
|     virtual bool SetSwapInterval(s32 interval) = 0; | ||||
|     virtual std::unique_ptr<Context> CreateSharedContext(const WindowInfo& wi) = 0; | ||||
| 
 | ||||
|   virtual std::vector<FullscreenModeInfo> EnumerateFullscreenModes(); | ||||
|     virtual std::vector<FullscreenModeInfo> EnumerateFullscreenModes(); | ||||
| 
 | ||||
|   static std::unique_ptr<Context> Create(const WindowInfo& wi, const Version* versions_to_try, | ||||
|                                          size_t num_versions_to_try); | ||||
|     static std::unique_ptr<Context> Create(const WindowInfo& wi, const Version* versions_to_try, | ||||
|                                            size_t num_versions_to_try); | ||||
| 
 | ||||
|   template<size_t N> | ||||
|   static std::unique_ptr<Context> Create(const WindowInfo& wi, const std::array<Version, N>& versions_to_try) | ||||
|   { | ||||
|     return Create(wi, versions_to_try.data(), versions_to_try.size()); | ||||
|   } | ||||
|     template <size_t N> | ||||
|     static std::unique_ptr<Context> Create(const WindowInfo& wi, | ||||
|                                            const std::array<Version, N>& versions_to_try) { | ||||
|         return Create(wi, versions_to_try.data(), versions_to_try.size()); | ||||
|     } | ||||
| 
 | ||||
|   static std::unique_ptr<Context> Create(const WindowInfo& wi) { return Create(wi, GetAllVersionsList()); } | ||||
|     static std::unique_ptr<Context> Create(const WindowInfo& wi) { | ||||
|         return Create(wi, GetAllVersionsList()); | ||||
|     } | ||||
| 
 | ||||
|   static const std::array<Version, 11>& GetAllDesktopVersionsList(); | ||||
|   static const std::array<Version, 12>& GetAllDesktopVersionsListWithFallback(); | ||||
|   static const std::array<Version, 4>& GetAllESVersionsList(); | ||||
|   static const std::array<Version, 16>& GetAllVersionsList(); | ||||
|     static const std::array<Version, 11>& GetAllDesktopVersionsList(); | ||||
|     static const std::array<Version, 12>& GetAllDesktopVersionsListWithFallback(); | ||||
|     static const std::array<Version, 4>& GetAllESVersionsList(); | ||||
|     static const std::array<Version, 16>& GetAllVersionsList(); | ||||
| 
 | ||||
| protected: | ||||
| #ifdef _WIN32 | ||||
| #endif | ||||
| 
 | ||||
|   WindowInfo m_wi; | ||||
|   Version m_version = {}; | ||||
|     WindowInfo m_wi; | ||||
|     Version m_version = {}; | ||||
| }; | ||||
| } // namespace GL
 | ||||
|  |  | |||
|  | @ -14,37 +14,38 @@ struct NSView; | |||
| namespace GL { | ||||
| 
 | ||||
| using namespace melonDS; | ||||
| class ContextAGL final : public Context | ||||
| { | ||||
| class ContextAGL final : public Context { | ||||
| public: | ||||
|   ContextAGL(const WindowInfo& wi); | ||||
|   ~ContextAGL() override; | ||||
|     ContextAGL(const WindowInfo& wi); | ||||
|     ~ContextAGL() override; | ||||
| 
 | ||||
|   static std::unique_ptr<Context> Create(const WindowInfo& wi, const Version* versions_to_try, | ||||
|                                          size_t num_versions_to_try); | ||||
|     static std::unique_ptr<Context> Create(const WindowInfo& wi, const Version* versions_to_try, | ||||
|                                            size_t num_versions_to_try); | ||||
| 
 | ||||
|   void* GetProcAddress(const char* name) override; | ||||
|   bool ChangeSurface(const WindowInfo& new_wi) override; | ||||
|   void ResizeSurface(u32 new_surface_width = 0, u32 new_surface_height = 0) override; | ||||
|   bool SwapBuffers() override; | ||||
|   bool MakeCurrent() override; | ||||
|   bool DoneCurrent() override; | ||||
|   bool SetSwapInterval(s32 interval) override; | ||||
|   std::unique_ptr<Context> CreateSharedContext(const WindowInfo& wi) override; | ||||
|     void* GetProcAddress(const char* name) override; | ||||
|     bool ChangeSurface(const WindowInfo& new_wi) override; | ||||
|     void ResizeSurface(u32 new_surface_width = 0, u32 new_surface_height = 0) override; | ||||
|     bool SwapBuffers() override; | ||||
|     bool MakeCurrent() override; | ||||
|     bool DoneCurrent() override; | ||||
|     bool SetSwapInterval(s32 interval) override; | ||||
|     std::unique_ptr<Context> CreateSharedContext(const WindowInfo& wi) override; | ||||
| 
 | ||||
| private: | ||||
|   ALWAYS_INLINE NSView* GetView() const { return static_cast<NSView*>((__bridge NSView*)m_wi.window_handle); } | ||||
|     ALWAYS_INLINE NSView* GetView() const { | ||||
|         return static_cast<NSView*>((__bridge NSView*)m_wi.window_handle); | ||||
|     } | ||||
| 
 | ||||
|   bool Initialize(const Version* versions_to_try, size_t num_versions_to_try); | ||||
|   bool CreateContext(NSOpenGLContext* share_context, int profile, bool make_current); | ||||
|   void BindContextToView(); | ||||
|     bool Initialize(const Version* versions_to_try, size_t num_versions_to_try); | ||||
|     bool CreateContext(NSOpenGLContext* share_context, int profile, bool make_current); | ||||
|     void BindContextToView(); | ||||
| 
 | ||||
|   // returns true if dimensions have changed
 | ||||
|   bool UpdateDimensions(); | ||||
|     // returns true if dimensions have changed
 | ||||
|     bool UpdateDimensions(); | ||||
| 
 | ||||
|   NSOpenGLContext* m_context = nullptr; | ||||
|   NSOpenGLPixelFormat* m_pixel_format = nullptr; | ||||
|   void* m_opengl_module_handle = nullptr; | ||||
|     NSOpenGLContext* m_context = nullptr; | ||||
|     NSOpenGLPixelFormat* m_pixel_format = nullptr; | ||||
|     void* m_opengl_module_handle = nullptr; | ||||
| }; | ||||
| 
 | ||||
| } // namespace GL
 | ||||
|  |  | |||
|  | @ -1,432 +1,386 @@ | |||
| #include "context_egl.h" | ||||
| #include "../log.h" | ||||
| #include "../duckstation_compat.h" | ||||
| #include <cstring> | ||||
| #include <optional> | ||||
| #include <vector> | ||||
| #include <cstring> | ||||
| #include "../duckstation_compat.h" | ||||
| #include "../log.h" | ||||
| #include "context_egl.h" | ||||
| Log_SetChannel(GL::ContextEGL); | ||||
| 
 | ||||
| namespace GL { | ||||
| ContextEGL::ContextEGL(const WindowInfo& wi) : Context(wi) {} | ||||
| 
 | ||||
| ContextEGL::~ContextEGL() | ||||
| { | ||||
|   DestroySurface(); | ||||
|   DestroyContext(); | ||||
| ContextEGL::~ContextEGL() { | ||||
|     DestroySurface(); | ||||
|     DestroyContext(); | ||||
| } | ||||
| 
 | ||||
| std::unique_ptr<Context> ContextEGL::Create(const WindowInfo& wi, const Version* versions_to_try, | ||||
|                                             size_t num_versions_to_try) | ||||
| { | ||||
|   std::unique_ptr<ContextEGL> context = std::make_unique<ContextEGL>(wi); | ||||
|   if (!context->Initialize(versions_to_try, num_versions_to_try)) | ||||
|     return nullptr; | ||||
|                                             size_t num_versions_to_try) { | ||||
|     std::unique_ptr<ContextEGL> context = std::make_unique<ContextEGL>(wi); | ||||
|     if (!context->Initialize(versions_to_try, num_versions_to_try)) | ||||
|         return nullptr; | ||||
| 
 | ||||
|   return context; | ||||
|     return context; | ||||
| } | ||||
| 
 | ||||
| bool ContextEGL::Initialize(const Version* versions_to_try, size_t num_versions_to_try) | ||||
| { | ||||
|   if (!gladLoadEGL()) | ||||
|   { | ||||
|     Log_ErrorPrintf("Loading GLAD EGL functions failed"); | ||||
| bool ContextEGL::Initialize(const Version* versions_to_try, size_t num_versions_to_try) { | ||||
|     if (!gladLoadEGL()) { | ||||
|         Log_ErrorPrintf("Loading GLAD EGL functions failed"); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     if (!SetDisplay()) | ||||
|         return false; | ||||
| 
 | ||||
|     int egl_major, egl_minor; | ||||
|     if (!eglInitialize(m_display, &egl_major, &egl_minor)) { | ||||
|         Log_ErrorPrintf("eglInitialize() failed: %d", eglGetError()); | ||||
|         return false; | ||||
|     } | ||||
|     Log_InfoPrintf("EGL Version: %d.%d", egl_major, egl_minor); | ||||
| 
 | ||||
|     const char* extensions = eglQueryString(m_display, EGL_EXTENSIONS); | ||||
|     if (extensions) { | ||||
|         Log_InfoPrintf("EGL Extensions: %s", extensions); | ||||
|         m_supports_surfaceless = std::strstr(extensions, "EGL_KHR_surfaceless_context") != nullptr; | ||||
|     } | ||||
|     if (!m_supports_surfaceless) | ||||
|         Log_WarningPrint( | ||||
|             "EGL implementation does not support surfaceless contexts, emulating with pbuffers"); | ||||
| 
 | ||||
|     for (size_t i = 0; i < num_versions_to_try; i++) { | ||||
|         if (CreateContextAndSurface(versions_to_try[i], nullptr, true)) | ||||
|             return true; | ||||
|     } | ||||
| 
 | ||||
|     return false; | ||||
|   } | ||||
| 
 | ||||
|   if (!SetDisplay()) | ||||
|     return false; | ||||
| 
 | ||||
|   int egl_major, egl_minor; | ||||
|   if (!eglInitialize(m_display, &egl_major, &egl_minor)) | ||||
|   { | ||||
|     Log_ErrorPrintf("eglInitialize() failed: %d", eglGetError()); | ||||
|     return false; | ||||
|   } | ||||
|   Log_InfoPrintf("EGL Version: %d.%d", egl_major, egl_minor); | ||||
| 
 | ||||
|   const char* extensions = eglQueryString(m_display, EGL_EXTENSIONS); | ||||
|   if (extensions) | ||||
|   { | ||||
|     Log_InfoPrintf("EGL Extensions: %s", extensions); | ||||
|     m_supports_surfaceless = std::strstr(extensions, "EGL_KHR_surfaceless_context") != nullptr; | ||||
|   } | ||||
|   if (!m_supports_surfaceless) | ||||
|     Log_WarningPrint("EGL implementation does not support surfaceless contexts, emulating with pbuffers"); | ||||
| 
 | ||||
|   for (size_t i = 0; i < num_versions_to_try; i++) | ||||
|   { | ||||
|     if (CreateContextAndSurface(versions_to_try[i], nullptr, true)) | ||||
|       return true; | ||||
|   } | ||||
| 
 | ||||
|   return false; | ||||
| } | ||||
| 
 | ||||
| bool ContextEGL::SetDisplay() | ||||
| { | ||||
|   m_display = eglGetDisplay(static_cast<EGLNativeDisplayType>(m_wi.display_connection)); | ||||
|   if (!m_display) | ||||
|   { | ||||
|     Log_ErrorPrintf("eglGetDisplay() failed: %d", eglGetError()); | ||||
|     return false; | ||||
|   } | ||||
| bool ContextEGL::SetDisplay() { | ||||
|     m_display = eglGetDisplay(static_cast<EGLNativeDisplayType>(m_wi.display_connection)); | ||||
|     if (!m_display) { | ||||
|         Log_ErrorPrintf("eglGetDisplay() failed: %d", eglGetError()); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|   return true; | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| void* ContextEGL::GetProcAddress(const char* name) | ||||
| { | ||||
|   return reinterpret_cast<void*>(eglGetProcAddress(name)); | ||||
| void* ContextEGL::GetProcAddress(const char* name) { | ||||
|     return reinterpret_cast<void*>(eglGetProcAddress(name)); | ||||
| } | ||||
| 
 | ||||
| bool ContextEGL::ChangeSurface(const WindowInfo& new_wi) | ||||
| { | ||||
|   const bool was_current = (eglGetCurrentContext() == m_context); | ||||
|   if (was_current) | ||||
|     eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); | ||||
| bool ContextEGL::ChangeSurface(const WindowInfo& new_wi) { | ||||
|     const bool was_current = (eglGetCurrentContext() == m_context); | ||||
|     if (was_current) | ||||
|         eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); | ||||
| 
 | ||||
|   if (m_surface != EGL_NO_SURFACE) | ||||
|   { | ||||
|     eglDestroySurface(m_display, m_surface); | ||||
|     m_surface = EGL_NO_SURFACE; | ||||
|   } | ||||
|     if (m_surface != EGL_NO_SURFACE) { | ||||
|         eglDestroySurface(m_display, m_surface); | ||||
|         m_surface = EGL_NO_SURFACE; | ||||
|     } | ||||
| 
 | ||||
|   m_wi = new_wi; | ||||
|   if (!CreateSurface()) | ||||
|     return false; | ||||
|     m_wi = new_wi; | ||||
|     if (!CreateSurface()) | ||||
|         return false; | ||||
| 
 | ||||
|   if (was_current && !eglMakeCurrent(m_display, m_surface, m_surface, m_context)) | ||||
|   { | ||||
|     Log_ErrorPrintf("Failed to make context current again after surface change"); | ||||
|     return false; | ||||
|   } | ||||
|     if (was_current && !eglMakeCurrent(m_display, m_surface, m_surface, m_context)) { | ||||
|         Log_ErrorPrintf("Failed to make context current again after surface change"); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|   return true; | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| void ContextEGL::ResizeSurface(u32 new_surface_width /*= 0*/, u32 new_surface_height /*= 0*/) | ||||
| { | ||||
|   if (new_surface_width == 0 && new_surface_height == 0) | ||||
|   { | ||||
| void ContextEGL::ResizeSurface(u32 new_surface_width /*= 0*/, u32 new_surface_height /*= 0*/) { | ||||
|     if (new_surface_width == 0 && new_surface_height == 0) { | ||||
|         EGLint surface_width, surface_height; | ||||
|         if (eglQuerySurface(m_display, m_surface, EGL_WIDTH, &surface_width) && | ||||
|             eglQuerySurface(m_display, m_surface, EGL_HEIGHT, &surface_height)) { | ||||
|             m_wi.surface_width = static_cast<u32>(surface_width); | ||||
|             m_wi.surface_height = static_cast<u32>(surface_height); | ||||
|             return; | ||||
|         } else { | ||||
|             Log_ErrorPrintf("eglQuerySurface() failed: %d", eglGetError()); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     m_wi.surface_width = new_surface_width; | ||||
|     m_wi.surface_height = new_surface_height; | ||||
| } | ||||
| 
 | ||||
| bool ContextEGL::SwapBuffers() { | ||||
|     return eglSwapBuffers(m_display, m_surface); | ||||
| } | ||||
| 
 | ||||
| bool ContextEGL::MakeCurrent() { | ||||
|     if (!eglMakeCurrent(m_display, m_surface, m_surface, m_context)) { | ||||
|         Log_ErrorPrintf("eglMakeCurrent() failed: %d", eglGetError()); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool ContextEGL::DoneCurrent() { | ||||
|     return eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); | ||||
| } | ||||
| 
 | ||||
| bool ContextEGL::SetSwapInterval(s32 interval) { | ||||
|     return eglSwapInterval(m_display, interval); | ||||
| } | ||||
| 
 | ||||
| std::unique_ptr<Context> ContextEGL::CreateSharedContext(const WindowInfo& wi) { | ||||
|     std::unique_ptr<ContextEGL> context = std::make_unique<ContextEGL>(wi); | ||||
|     context->m_display = m_display; | ||||
|     context->m_supports_surfaceless = m_supports_surfaceless; | ||||
| 
 | ||||
|     if (!context->CreateContextAndSurface(m_version, m_context, false)) | ||||
|         return nullptr; | ||||
| 
 | ||||
|     return context; | ||||
| } | ||||
| 
 | ||||
| EGLNativeWindowType ContextEGL::GetNativeWindow(EGLConfig config) { | ||||
|     return {}; | ||||
| } | ||||
| 
 | ||||
| bool ContextEGL::CreateSurface() { | ||||
|     if (m_wi.type == WindowInfo::Type::Surfaceless) { | ||||
|         if (m_supports_surfaceless) | ||||
|             return true; | ||||
|         else | ||||
|             return CreatePBufferSurface(); | ||||
|     } | ||||
| 
 | ||||
|     EGLNativeWindowType native_window = GetNativeWindow(m_config); | ||||
|     m_surface = eglCreateWindowSurface(m_display, m_config, native_window, nullptr); | ||||
|     if (!m_surface) { | ||||
|         Log_ErrorPrintf("eglCreateWindowSurface() failed: %d", eglGetError()); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     // Some implementations may require the size to be queried at runtime.
 | ||||
|     EGLint surface_width, surface_height; | ||||
|     if (eglQuerySurface(m_display, m_surface, EGL_WIDTH, &surface_width) && | ||||
|         eglQuerySurface(m_display, m_surface, EGL_HEIGHT, &surface_height)) | ||||
|     { | ||||
|       m_wi.surface_width = static_cast<u32>(surface_width); | ||||
|       m_wi.surface_height = static_cast<u32>(surface_height); | ||||
|       return; | ||||
|         eglQuerySurface(m_display, m_surface, EGL_HEIGHT, &surface_height)) { | ||||
|         m_wi.surface_width = static_cast<u32>(surface_width); | ||||
|         m_wi.surface_height = static_cast<u32>(surface_height); | ||||
|     } else { | ||||
|         Log_ErrorPrintf("eglQuerySurface() failed: %d", eglGetError()); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|       Log_ErrorPrintf("eglQuerySurface() failed: %d", eglGetError()); | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool ContextEGL::CreatePBufferSurface() { | ||||
|     const u32 width = std::max<u32>(m_wi.surface_width, 1); | ||||
|     const u32 height = std::max<u32>(m_wi.surface_height, 1); | ||||
| 
 | ||||
|     // TODO: Format
 | ||||
|     EGLint attrib_list[] = { | ||||
|         EGL_WIDTH, static_cast<EGLint>(width), EGL_HEIGHT, static_cast<EGLint>(height), EGL_NONE, | ||||
|     }; | ||||
| 
 | ||||
|     m_surface = eglCreatePbufferSurface(m_display, m_config, attrib_list); | ||||
|     if (!m_surface) { | ||||
|         Log_ErrorPrintf("eglCreatePbufferSurface() failed: %d", eglGetError()); | ||||
|         return false; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   m_wi.surface_width = new_surface_width; | ||||
|   m_wi.surface_height = new_surface_height; | ||||
|     Log_DevPrintf("Created %ux%u pbuffer surface", width, height); | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool ContextEGL::SwapBuffers() | ||||
| { | ||||
|   return eglSwapBuffers(m_display, m_surface); | ||||
| } | ||||
| bool ContextEGL::CheckConfigSurfaceFormat(EGLConfig config, | ||||
|                                           WindowInfo::SurfaceFormat format) const { | ||||
|     int red_size, green_size, blue_size, alpha_size; | ||||
|     if (!eglGetConfigAttrib(m_display, config, EGL_RED_SIZE, &red_size) || | ||||
|         !eglGetConfigAttrib(m_display, config, EGL_GREEN_SIZE, &green_size) || | ||||
|         !eglGetConfigAttrib(m_display, config, EGL_BLUE_SIZE, &blue_size) || | ||||
|         !eglGetConfigAttrib(m_display, config, EGL_ALPHA_SIZE, &alpha_size)) { | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
| bool ContextEGL::MakeCurrent() | ||||
| { | ||||
|   if (!eglMakeCurrent(m_display, m_surface, m_surface, m_context)) | ||||
|   { | ||||
|     Log_ErrorPrintf("eglMakeCurrent() failed: %d", eglGetError()); | ||||
|     return false; | ||||
|   } | ||||
| 
 | ||||
|   return true; | ||||
| } | ||||
| 
 | ||||
| bool ContextEGL::DoneCurrent() | ||||
| { | ||||
|   return eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); | ||||
| } | ||||
| 
 | ||||
| bool ContextEGL::SetSwapInterval(s32 interval) | ||||
| { | ||||
|   return eglSwapInterval(m_display, interval); | ||||
| } | ||||
| 
 | ||||
| std::unique_ptr<Context> ContextEGL::CreateSharedContext(const WindowInfo& wi) | ||||
| { | ||||
|   std::unique_ptr<ContextEGL> context = std::make_unique<ContextEGL>(wi); | ||||
|   context->m_display = m_display; | ||||
|   context->m_supports_surfaceless = m_supports_surfaceless; | ||||
| 
 | ||||
|   if (!context->CreateContextAndSurface(m_version, m_context, false)) | ||||
|     return nullptr; | ||||
| 
 | ||||
|   return context; | ||||
| } | ||||
| 
 | ||||
| EGLNativeWindowType ContextEGL::GetNativeWindow(EGLConfig config) | ||||
| { | ||||
|   return {}; | ||||
| } | ||||
| 
 | ||||
| bool ContextEGL::CreateSurface() | ||||
| { | ||||
|   if (m_wi.type == WindowInfo::Type::Surfaceless) | ||||
|   { | ||||
|     if (m_supports_surfaceless) | ||||
|       return true; | ||||
|     else | ||||
|       return CreatePBufferSurface(); | ||||
|   } | ||||
| 
 | ||||
|   EGLNativeWindowType native_window = GetNativeWindow(m_config); | ||||
|   m_surface = eglCreateWindowSurface(m_display, m_config, native_window, nullptr); | ||||
|   if (!m_surface) | ||||
|   { | ||||
|     Log_ErrorPrintf("eglCreateWindowSurface() failed: %d", eglGetError()); | ||||
|     return false; | ||||
|   } | ||||
| 
 | ||||
|   // Some implementations may require the size to be queried at runtime.
 | ||||
|   EGLint surface_width, surface_height; | ||||
|   if (eglQuerySurface(m_display, m_surface, EGL_WIDTH, &surface_width) && | ||||
|       eglQuerySurface(m_display, m_surface, EGL_HEIGHT, &surface_height)) | ||||
|   { | ||||
|     m_wi.surface_width = static_cast<u32>(surface_width); | ||||
|     m_wi.surface_height = static_cast<u32>(surface_height); | ||||
|   } | ||||
|   else | ||||
|   { | ||||
|     Log_ErrorPrintf("eglQuerySurface() failed: %d", eglGetError()); | ||||
|   } | ||||
| 
 | ||||
|   return true; | ||||
| } | ||||
| 
 | ||||
| bool ContextEGL::CreatePBufferSurface() | ||||
| { | ||||
|   const u32 width = std::max<u32>(m_wi.surface_width, 1); | ||||
|   const u32 height = std::max<u32>(m_wi.surface_height, 1); | ||||
| 
 | ||||
|   // TODO: Format
 | ||||
|   EGLint attrib_list[] = { | ||||
|     EGL_WIDTH, static_cast<EGLint>(width), EGL_HEIGHT, static_cast<EGLint>(height), EGL_NONE, | ||||
|   }; | ||||
| 
 | ||||
|   m_surface = eglCreatePbufferSurface(m_display, m_config, attrib_list); | ||||
|   if (!m_surface) | ||||
|   { | ||||
|     Log_ErrorPrintf("eglCreatePbufferSurface() failed: %d", eglGetError()); | ||||
|     return false; | ||||
|   } | ||||
| 
 | ||||
|   Log_DevPrintf("Created %ux%u pbuffer surface", width, height); | ||||
|   return true; | ||||
| } | ||||
| 
 | ||||
| bool ContextEGL::CheckConfigSurfaceFormat(EGLConfig config, WindowInfo::SurfaceFormat format) const | ||||
| { | ||||
|   int red_size, green_size, blue_size, alpha_size; | ||||
|   if (!eglGetConfigAttrib(m_display, config, EGL_RED_SIZE, &red_size) || | ||||
|       !eglGetConfigAttrib(m_display, config, EGL_GREEN_SIZE, &green_size) || | ||||
|       !eglGetConfigAttrib(m_display, config, EGL_BLUE_SIZE, &blue_size) || | ||||
|       !eglGetConfigAttrib(m_display, config, EGL_ALPHA_SIZE, &alpha_size)) | ||||
|   { | ||||
|     return false; | ||||
|   } | ||||
| 
 | ||||
|   switch (format) | ||||
|   { | ||||
|     switch (format) { | ||||
|     case WindowInfo::SurfaceFormat::Auto: | ||||
|       return true; | ||||
|         return true; | ||||
| 
 | ||||
|     case WindowInfo::SurfaceFormat::RGB8: | ||||
|       return (red_size == 8 && green_size == 8 && blue_size == 8); | ||||
|         return (red_size == 8 && green_size == 8 && blue_size == 8); | ||||
| 
 | ||||
|     case WindowInfo::SurfaceFormat::RGBA8: | ||||
|       return (red_size == 8 && green_size == 8 && blue_size == 8 && alpha_size == 8); | ||||
|         return (red_size == 8 && green_size == 8 && blue_size == 8 && alpha_size == 8); | ||||
| 
 | ||||
|     case WindowInfo::SurfaceFormat::RGB565: | ||||
|       return (red_size == 5 && green_size == 6 && blue_size == 5); | ||||
|         return (red_size == 5 && green_size == 6 && blue_size == 5); | ||||
| 
 | ||||
|     default: | ||||
|       return false; | ||||
|   } | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void ContextEGL::DestroyContext() | ||||
| { | ||||
|   if (eglGetCurrentContext() == m_context) | ||||
|     eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); | ||||
| void ContextEGL::DestroyContext() { | ||||
|     if (eglGetCurrentContext() == m_context) | ||||
|         eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); | ||||
| 
 | ||||
|   if (m_context != EGL_NO_CONTEXT) | ||||
|   { | ||||
|     eglDestroyContext(m_display, m_context); | ||||
|     m_context = EGL_NO_CONTEXT; | ||||
|   } | ||||
|     if (m_context != EGL_NO_CONTEXT) { | ||||
|         eglDestroyContext(m_display, m_context); | ||||
|         m_context = EGL_NO_CONTEXT; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void ContextEGL::DestroySurface() | ||||
| { | ||||
|   if (eglGetCurrentSurface(EGL_DRAW) == m_surface) | ||||
|     eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); | ||||
| void ContextEGL::DestroySurface() { | ||||
|     if (eglGetCurrentSurface(EGL_DRAW) == m_surface) | ||||
|         eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); | ||||
| 
 | ||||
|   if (m_surface != EGL_NO_SURFACE) | ||||
|   { | ||||
|     eglDestroySurface(m_display, m_surface); | ||||
|     m_surface = EGL_NO_SURFACE; | ||||
|   } | ||||
|     if (m_surface != EGL_NO_SURFACE) { | ||||
|         eglDestroySurface(m_display, m_surface); | ||||
|         m_surface = EGL_NO_SURFACE; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| bool ContextEGL::CreateContext(const Version& version, EGLContext share_context) | ||||
| { | ||||
|   Log_DevPrintf( | ||||
|     "Trying version %u.%u (%s)", version.major_version, version.minor_version, | ||||
|     version.profile == Context::Profile::ES ? "ES" : (version.profile == Context::Profile::Core ? "Core" : "None")); | ||||
|   int surface_attribs[16] = { | ||||
|     EGL_RENDERABLE_TYPE, | ||||
|     (version.profile == Profile::ES) ? | ||||
|       ((version.major_version >= 3) ? EGL_OPENGL_ES3_BIT : | ||||
|                                       ((version.major_version == 2) ? EGL_OPENGL_ES2_BIT : EGL_OPENGL_ES_BIT)) : | ||||
|       EGL_OPENGL_BIT, | ||||
|     EGL_SURFACE_TYPE, | ||||
|     (m_wi.type != WindowInfo::Type::Surfaceless) ? EGL_WINDOW_BIT : 0, | ||||
|   }; | ||||
|   int nsurface_attribs = 4; | ||||
| bool ContextEGL::CreateContext(const Version& version, EGLContext share_context) { | ||||
|     Log_DevPrintf("Trying version %u.%u (%s)", version.major_version, version.minor_version, | ||||
|                   version.profile == Context::Profile::ES | ||||
|                       ? "ES" | ||||
|                       : (version.profile == Context::Profile::Core ? "Core" : "None")); | ||||
|     int surface_attribs[16] = { | ||||
|         EGL_RENDERABLE_TYPE, | ||||
|         (version.profile == Profile::ES) | ||||
|             ? ((version.major_version >= 3) | ||||
|                    ? EGL_OPENGL_ES3_BIT | ||||
|                    : ((version.major_version == 2) ? EGL_OPENGL_ES2_BIT : EGL_OPENGL_ES_BIT)) | ||||
|             : EGL_OPENGL_BIT, | ||||
|         EGL_SURFACE_TYPE, | ||||
|         (m_wi.type != WindowInfo::Type::Surfaceless) ? EGL_WINDOW_BIT : 0, | ||||
|     }; | ||||
|     int nsurface_attribs = 4; | ||||
| 
 | ||||
|   switch (m_wi.surface_format) | ||||
|   { | ||||
|     switch (m_wi.surface_format) { | ||||
|     case WindowInfo::SurfaceFormat::RGB8: | ||||
|       surface_attribs[nsurface_attribs++] = EGL_RED_SIZE; | ||||
|       surface_attribs[nsurface_attribs++] = 8; | ||||
|       surface_attribs[nsurface_attribs++] = EGL_GREEN_SIZE; | ||||
|       surface_attribs[nsurface_attribs++] = 8; | ||||
|       surface_attribs[nsurface_attribs++] = EGL_BLUE_SIZE; | ||||
|       surface_attribs[nsurface_attribs++] = 8; | ||||
|       break; | ||||
|         surface_attribs[nsurface_attribs++] = EGL_RED_SIZE; | ||||
|         surface_attribs[nsurface_attribs++] = 8; | ||||
|         surface_attribs[nsurface_attribs++] = EGL_GREEN_SIZE; | ||||
|         surface_attribs[nsurface_attribs++] = 8; | ||||
|         surface_attribs[nsurface_attribs++] = EGL_BLUE_SIZE; | ||||
|         surface_attribs[nsurface_attribs++] = 8; | ||||
|         break; | ||||
| 
 | ||||
|     case WindowInfo::SurfaceFormat::RGBA8: | ||||
|       surface_attribs[nsurface_attribs++] = EGL_RED_SIZE; | ||||
|       surface_attribs[nsurface_attribs++] = 8; | ||||
|       surface_attribs[nsurface_attribs++] = EGL_GREEN_SIZE; | ||||
|       surface_attribs[nsurface_attribs++] = 8; | ||||
|       surface_attribs[nsurface_attribs++] = EGL_BLUE_SIZE; | ||||
|       surface_attribs[nsurface_attribs++] = 8; | ||||
|       surface_attribs[nsurface_attribs++] = EGL_ALPHA_SIZE; | ||||
|       surface_attribs[nsurface_attribs++] = 8; | ||||
|       break; | ||||
|         surface_attribs[nsurface_attribs++] = EGL_RED_SIZE; | ||||
|         surface_attribs[nsurface_attribs++] = 8; | ||||
|         surface_attribs[nsurface_attribs++] = EGL_GREEN_SIZE; | ||||
|         surface_attribs[nsurface_attribs++] = 8; | ||||
|         surface_attribs[nsurface_attribs++] = EGL_BLUE_SIZE; | ||||
|         surface_attribs[nsurface_attribs++] = 8; | ||||
|         surface_attribs[nsurface_attribs++] = EGL_ALPHA_SIZE; | ||||
|         surface_attribs[nsurface_attribs++] = 8; | ||||
|         break; | ||||
| 
 | ||||
|     case WindowInfo::SurfaceFormat::RGB565: | ||||
|       surface_attribs[nsurface_attribs++] = EGL_RED_SIZE; | ||||
|       surface_attribs[nsurface_attribs++] = 5; | ||||
|       surface_attribs[nsurface_attribs++] = EGL_GREEN_SIZE; | ||||
|       surface_attribs[nsurface_attribs++] = 6; | ||||
|       surface_attribs[nsurface_attribs++] = EGL_BLUE_SIZE; | ||||
|       surface_attribs[nsurface_attribs++] = 5; | ||||
|       break; | ||||
|         surface_attribs[nsurface_attribs++] = EGL_RED_SIZE; | ||||
|         surface_attribs[nsurface_attribs++] = 5; | ||||
|         surface_attribs[nsurface_attribs++] = EGL_GREEN_SIZE; | ||||
|         surface_attribs[nsurface_attribs++] = 6; | ||||
|         surface_attribs[nsurface_attribs++] = EGL_BLUE_SIZE; | ||||
|         surface_attribs[nsurface_attribs++] = 5; | ||||
|         break; | ||||
| 
 | ||||
|     case WindowInfo::SurfaceFormat::Auto: | ||||
|       break; | ||||
|         break; | ||||
| 
 | ||||
|     default: | ||||
|       UnreachableCode(); | ||||
|       break; | ||||
|   } | ||||
| 
 | ||||
|   surface_attribs[nsurface_attribs++] = EGL_NONE; | ||||
|   surface_attribs[nsurface_attribs++] = 0; | ||||
| 
 | ||||
|   EGLint num_configs; | ||||
|   if (!eglChooseConfig(m_display, surface_attribs, nullptr, 0, &num_configs) || num_configs == 0) | ||||
|   { | ||||
|     Log_ErrorPrintf("eglChooseConfig() failed: %d", eglGetError()); | ||||
|     return false; | ||||
|   } | ||||
| 
 | ||||
|   std::vector<EGLConfig> configs(static_cast<u32>(num_configs)); | ||||
|   if (!eglChooseConfig(m_display, surface_attribs, configs.data(), num_configs, &num_configs)) | ||||
|   { | ||||
|     Log_ErrorPrintf("eglChooseConfig() failed: %d", eglGetError()); | ||||
|     return false; | ||||
|   } | ||||
|   configs.resize(static_cast<u32>(num_configs)); | ||||
| 
 | ||||
|   std::optional<EGLConfig> config; | ||||
|   for (EGLConfig check_config : configs) | ||||
|   { | ||||
|     if (CheckConfigSurfaceFormat(check_config, m_wi.surface_format)) | ||||
|     { | ||||
|       config = check_config; | ||||
|       break; | ||||
|         UnreachableCode(); | ||||
|         break; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   if (!config.has_value()) | ||||
|   { | ||||
|     Log_WarningPrintf("No EGL configs matched exactly, using first."); | ||||
|     config = configs.front(); | ||||
|   } | ||||
|     surface_attribs[nsurface_attribs++] = EGL_NONE; | ||||
|     surface_attribs[nsurface_attribs++] = 0; | ||||
| 
 | ||||
|   int attribs[8]; | ||||
|   int nattribs = 0; | ||||
|   if (version.profile != Profile::NoProfile) | ||||
|   { | ||||
|     attribs[nattribs++] = EGL_CONTEXT_MAJOR_VERSION; | ||||
|     attribs[nattribs++] = version.major_version; | ||||
|     attribs[nattribs++] = EGL_CONTEXT_MINOR_VERSION; | ||||
|     attribs[nattribs++] = version.minor_version; | ||||
|   } | ||||
|   attribs[nattribs++] = EGL_NONE; | ||||
|   attribs[nattribs++] = 0; | ||||
|     EGLint num_configs; | ||||
|     if (!eglChooseConfig(m_display, surface_attribs, nullptr, 0, &num_configs) || | ||||
|         num_configs == 0) { | ||||
|         Log_ErrorPrintf("eglChooseConfig() failed: %d", eglGetError()); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|   if (!eglBindAPI((version.profile == Profile::ES) ? EGL_OPENGL_ES_API : EGL_OPENGL_API)) | ||||
|   { | ||||
|     Log_ErrorPrintf("eglBindAPI(%s) failed", (version.profile == Profile::ES) ? "EGL_OPENGL_ES_API" : "EGL_OPENGL_API"); | ||||
|     return false; | ||||
|   } | ||||
|     std::vector<EGLConfig> configs(static_cast<u32>(num_configs)); | ||||
|     if (!eglChooseConfig(m_display, surface_attribs, configs.data(), num_configs, &num_configs)) { | ||||
|         Log_ErrorPrintf("eglChooseConfig() failed: %d", eglGetError()); | ||||
|         return false; | ||||
|     } | ||||
|     configs.resize(static_cast<u32>(num_configs)); | ||||
| 
 | ||||
|   m_context = eglCreateContext(m_display, config.value(), share_context, attribs); | ||||
|   if (!m_context) | ||||
|   { | ||||
|     Log_ErrorPrintf("eglCreateContext() failed: %d", eglGetError()); | ||||
|     return false; | ||||
|   } | ||||
|     std::optional<EGLConfig> config; | ||||
|     for (EGLConfig check_config : configs) { | ||||
|         if (CheckConfigSurfaceFormat(check_config, m_wi.surface_format)) { | ||||
|             config = check_config; | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|   Log_InfoPrintf( | ||||
|     "Got version %u.%u (%s)", version.major_version, version.minor_version, | ||||
|     version.profile == Context::Profile::ES ? "ES" : (version.profile == Context::Profile::Core ? "Core" : "None")); | ||||
|     if (!config.has_value()) { | ||||
|         Log_WarningPrintf("No EGL configs matched exactly, using first."); | ||||
|         config = configs.front(); | ||||
|     } | ||||
| 
 | ||||
|   m_config = config.value(); | ||||
|   m_version = version; | ||||
|   return true; | ||||
|     int attribs[8]; | ||||
|     int nattribs = 0; | ||||
|     if (version.profile != Profile::NoProfile) { | ||||
|         attribs[nattribs++] = EGL_CONTEXT_MAJOR_VERSION; | ||||
|         attribs[nattribs++] = version.major_version; | ||||
|         attribs[nattribs++] = EGL_CONTEXT_MINOR_VERSION; | ||||
|         attribs[nattribs++] = version.minor_version; | ||||
|     } | ||||
|     attribs[nattribs++] = EGL_NONE; | ||||
|     attribs[nattribs++] = 0; | ||||
| 
 | ||||
|     if (!eglBindAPI((version.profile == Profile::ES) ? EGL_OPENGL_ES_API : EGL_OPENGL_API)) { | ||||
|         Log_ErrorPrintf("eglBindAPI(%s) failed", | ||||
|                         (version.profile == Profile::ES) ? "EGL_OPENGL_ES_API" : "EGL_OPENGL_API"); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     m_context = eglCreateContext(m_display, config.value(), share_context, attribs); | ||||
|     if (!m_context) { | ||||
|         Log_ErrorPrintf("eglCreateContext() failed: %d", eglGetError()); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     Log_InfoPrintf("Got version %u.%u (%s)", version.major_version, version.minor_version, | ||||
|                    version.profile == Context::Profile::ES | ||||
|                        ? "ES" | ||||
|                        : (version.profile == Context::Profile::Core ? "Core" : "None")); | ||||
| 
 | ||||
|     m_config = config.value(); | ||||
|     m_version = version; | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool ContextEGL::CreateContextAndSurface(const Version& version, EGLContext share_context, bool make_current) | ||||
| { | ||||
|   if (!CreateContext(version, share_context)) | ||||
|     return false; | ||||
| bool ContextEGL::CreateContextAndSurface(const Version& version, EGLContext share_context, | ||||
|                                          bool make_current) { | ||||
|     if (!CreateContext(version, share_context)) | ||||
|         return false; | ||||
| 
 | ||||
|   if (!CreateSurface()) | ||||
|   { | ||||
|     Log_ErrorPrintf("Failed to create surface for context"); | ||||
|     eglDestroyContext(m_display, m_context); | ||||
|     m_context = EGL_NO_CONTEXT; | ||||
|     return false; | ||||
|   } | ||||
| 
 | ||||
|   if (make_current && !eglMakeCurrent(m_display, m_surface, m_surface, m_context)) | ||||
|   { | ||||
|     Log_ErrorPrintf("eglMakeCurrent() failed: %d", eglGetError()); | ||||
|     if (m_surface != EGL_NO_SURFACE) | ||||
|     { | ||||
|       eglDestroySurface(m_display, m_surface); | ||||
|       m_surface = EGL_NO_SURFACE; | ||||
|     if (!CreateSurface()) { | ||||
|         Log_ErrorPrintf("Failed to create surface for context"); | ||||
|         eglDestroyContext(m_display, m_context); | ||||
|         m_context = EGL_NO_CONTEXT; | ||||
|         return false; | ||||
|     } | ||||
|     eglDestroyContext(m_display, m_context); | ||||
|     m_context = EGL_NO_CONTEXT; | ||||
|     return false; | ||||
|   } | ||||
| 
 | ||||
|   return true; | ||||
|     if (make_current && !eglMakeCurrent(m_display, m_surface, m_surface, m_context)) { | ||||
|         Log_ErrorPrintf("eglMakeCurrent() failed: %d", eglGetError()); | ||||
|         if (m_surface != EGL_NO_SURFACE) { | ||||
|             eglDestroySurface(m_display, m_surface); | ||||
|             m_surface = EGL_NO_SURFACE; | ||||
|         } | ||||
|         eglDestroyContext(m_display, m_context); | ||||
|         m_context = EGL_NO_CONTEXT; | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| } // namespace GL
 | ||||
|  |  | |||
|  | @ -1,48 +1,48 @@ | |||
| #pragma once | ||||
| #include "context.h" | ||||
| #include "../../../../../externals/glad/src/glad_egl.h" | ||||
| #include "context.h" | ||||
| 
 | ||||
| namespace GL { | ||||
| 
 | ||||
| class ContextEGL : public Context | ||||
| { | ||||
| class ContextEGL : public Context { | ||||
| public: | ||||
|   ContextEGL(const WindowInfo& wi); | ||||
|   ~ContextEGL() override; | ||||
|     ContextEGL(const WindowInfo& wi); | ||||
|     ~ContextEGL() override; | ||||
| 
 | ||||
|   static std::unique_ptr<Context> Create(const WindowInfo& wi, const Version* versions_to_try, | ||||
|                                          size_t num_versions_to_try); | ||||
|     static std::unique_ptr<Context> Create(const WindowInfo& wi, const Version* versions_to_try, | ||||
|                                            size_t num_versions_to_try); | ||||
| 
 | ||||
|   void* GetProcAddress(const char* name) override; | ||||
|   virtual bool ChangeSurface(const WindowInfo& new_wi) override; | ||||
|   virtual void ResizeSurface(u32 new_surface_width = 0, u32 new_surface_height = 0) override; | ||||
|   bool SwapBuffers() override; | ||||
|   bool MakeCurrent() override; | ||||
|   bool DoneCurrent() override; | ||||
|   bool SetSwapInterval(s32 interval) override; | ||||
|   virtual std::unique_ptr<Context> CreateSharedContext(const WindowInfo& wi) override; | ||||
|     void* GetProcAddress(const char* name) override; | ||||
|     virtual bool ChangeSurface(const WindowInfo& new_wi) override; | ||||
|     virtual void ResizeSurface(u32 new_surface_width = 0, u32 new_surface_height = 0) override; | ||||
|     bool SwapBuffers() override; | ||||
|     bool MakeCurrent() override; | ||||
|     bool DoneCurrent() override; | ||||
|     bool SetSwapInterval(s32 interval) override; | ||||
|     virtual std::unique_ptr<Context> CreateSharedContext(const WindowInfo& wi) override; | ||||
| 
 | ||||
| protected: | ||||
|   virtual bool SetDisplay(); | ||||
|   virtual EGLNativeWindowType GetNativeWindow(EGLConfig config); | ||||
|     virtual bool SetDisplay(); | ||||
|     virtual EGLNativeWindowType GetNativeWindow(EGLConfig config); | ||||
| 
 | ||||
|   bool Initialize(const Version* versions_to_try, size_t num_versions_to_try); | ||||
|   bool CreateDisplay(); | ||||
|   bool CreateContext(const Version& version, EGLContext share_context); | ||||
|   bool CreateContextAndSurface(const Version& version, EGLContext share_context, bool make_current); | ||||
|   bool CreateSurface(); | ||||
|   bool CreatePBufferSurface(); | ||||
|   bool CheckConfigSurfaceFormat(EGLConfig config, WindowInfo::SurfaceFormat format) const; | ||||
|   void DestroyContext(); | ||||
|   void DestroySurface(); | ||||
|     bool Initialize(const Version* versions_to_try, size_t num_versions_to_try); | ||||
|     bool CreateDisplay(); | ||||
|     bool CreateContext(const Version& version, EGLContext share_context); | ||||
|     bool CreateContextAndSurface(const Version& version, EGLContext share_context, | ||||
|                                  bool make_current); | ||||
|     bool CreateSurface(); | ||||
|     bool CreatePBufferSurface(); | ||||
|     bool CheckConfigSurfaceFormat(EGLConfig config, WindowInfo::SurfaceFormat format) const; | ||||
|     void DestroyContext(); | ||||
|     void DestroySurface(); | ||||
| 
 | ||||
|   EGLDisplay m_display = EGL_NO_DISPLAY; | ||||
|   EGLSurface m_surface = EGL_NO_SURFACE; | ||||
|   EGLContext m_context = EGL_NO_CONTEXT; | ||||
|     EGLDisplay m_display = EGL_NO_DISPLAY; | ||||
|     EGLSurface m_surface = EGL_NO_SURFACE; | ||||
|     EGLContext m_context = EGL_NO_CONTEXT; | ||||
| 
 | ||||
|   EGLConfig m_config = {}; | ||||
|     EGLConfig m_config = {}; | ||||
| 
 | ||||
|   bool m_supports_surfaceless = false; | ||||
|     bool m_supports_surfaceless = false; | ||||
| }; | ||||
| 
 | ||||
| } // namespace GL
 | ||||
|  |  | |||
|  | @ -1,86 +1,78 @@ | |||
| #include "context_egl_wayland.h" | ||||
| #include "../log.h" | ||||
| #include <dlfcn.h> | ||||
| #include "../log.h" | ||||
| #include "context_egl_wayland.h" | ||||
| Log_SetChannel(ContextEGLWayland); | ||||
| 
 | ||||
| namespace GL { | ||||
| static const char* WAYLAND_EGL_MODNAME = "libwayland-egl.so.1"; | ||||
| 
 | ||||
| ContextEGLWayland::ContextEGLWayland(const WindowInfo& wi) : ContextEGL(wi) {} | ||||
| ContextEGLWayland::~ContextEGLWayland() | ||||
| { | ||||
|   if (m_wl_window) | ||||
|     m_wl_egl_window_destroy(m_wl_window); | ||||
|   if (m_wl_module) | ||||
|     dlclose(m_wl_module); | ||||
| ContextEGLWayland::~ContextEGLWayland() { | ||||
|     if (m_wl_window) | ||||
|         m_wl_egl_window_destroy(m_wl_window); | ||||
|     if (m_wl_module) | ||||
|         dlclose(m_wl_module); | ||||
| } | ||||
| 
 | ||||
| std::unique_ptr<Context> ContextEGLWayland::Create(const WindowInfo& wi, const Version* versions_to_try, | ||||
|                                                    size_t num_versions_to_try) | ||||
| { | ||||
|   std::unique_ptr<ContextEGLWayland> context = std::make_unique<ContextEGLWayland>(wi); | ||||
|   if (!context->LoadModule() || !context->Initialize(versions_to_try, num_versions_to_try)) | ||||
|     return nullptr; | ||||
| std::unique_ptr<Context> ContextEGLWayland::Create(const WindowInfo& wi, | ||||
|                                                    const Version* versions_to_try, | ||||
|                                                    size_t num_versions_to_try) { | ||||
|     std::unique_ptr<ContextEGLWayland> context = std::make_unique<ContextEGLWayland>(wi); | ||||
|     if (!context->LoadModule() || !context->Initialize(versions_to_try, num_versions_to_try)) | ||||
|         return nullptr; | ||||
| 
 | ||||
|   return context; | ||||
|     return context; | ||||
| } | ||||
| 
 | ||||
| std::unique_ptr<Context> ContextEGLWayland::CreateSharedContext(const WindowInfo& wi) | ||||
| { | ||||
|   std::unique_ptr<ContextEGLWayland> context = std::make_unique<ContextEGLWayland>(wi); | ||||
|   context->m_display = m_display; | ||||
| std::unique_ptr<Context> ContextEGLWayland::CreateSharedContext(const WindowInfo& wi) { | ||||
|     std::unique_ptr<ContextEGLWayland> context = std::make_unique<ContextEGLWayland>(wi); | ||||
|     context->m_display = m_display; | ||||
| 
 | ||||
|   if (!context->LoadModule() || !context->CreateContextAndSurface(m_version, m_context, false)) | ||||
|     return nullptr; | ||||
|     if (!context->LoadModule() || !context->CreateContextAndSurface(m_version, m_context, false)) | ||||
|         return nullptr; | ||||
| 
 | ||||
|   return context; | ||||
|     return context; | ||||
| } | ||||
| 
 | ||||
| void ContextEGLWayland::ResizeSurface(u32 new_surface_width, u32 new_surface_height) | ||||
| { | ||||
|   if (m_wl_window) | ||||
|     m_wl_egl_window_resize(m_wl_window, new_surface_width, new_surface_height, 0, 0); | ||||
| void ContextEGLWayland::ResizeSurface(u32 new_surface_width, u32 new_surface_height) { | ||||
|     if (m_wl_window) | ||||
|         m_wl_egl_window_resize(m_wl_window, new_surface_width, new_surface_height, 0, 0); | ||||
| 
 | ||||
|   ContextEGL::ResizeSurface(new_surface_width, new_surface_height); | ||||
|     ContextEGL::ResizeSurface(new_surface_width, new_surface_height); | ||||
| } | ||||
| 
 | ||||
| EGLNativeWindowType ContextEGLWayland::GetNativeWindow(EGLConfig config) | ||||
| { | ||||
|   if (m_wl_window) | ||||
|   { | ||||
|     m_wl_egl_window_destroy(m_wl_window); | ||||
|     m_wl_window = nullptr; | ||||
|   } | ||||
| EGLNativeWindowType ContextEGLWayland::GetNativeWindow(EGLConfig config) { | ||||
|     if (m_wl_window) { | ||||
|         m_wl_egl_window_destroy(m_wl_window); | ||||
|         m_wl_window = nullptr; | ||||
|     } | ||||
| 
 | ||||
|   m_wl_window = | ||||
|     m_wl_egl_window_create(static_cast<wl_surface*>(m_wi.window_handle), m_wi.surface_width, m_wi.surface_height); | ||||
|   if (!m_wl_window) | ||||
|     return {}; | ||||
|     m_wl_window = m_wl_egl_window_create(static_cast<wl_surface*>(m_wi.window_handle), | ||||
|                                          m_wi.surface_width, m_wi.surface_height); | ||||
|     if (!m_wl_window) | ||||
|         return {}; | ||||
| 
 | ||||
|   return reinterpret_cast<EGLNativeWindowType>(m_wl_window); | ||||
|     return reinterpret_cast<EGLNativeWindowType>(m_wl_window); | ||||
| } | ||||
| 
 | ||||
| bool ContextEGLWayland::LoadModule() | ||||
| { | ||||
|   m_wl_module = dlopen(WAYLAND_EGL_MODNAME, RTLD_NOW | RTLD_GLOBAL); | ||||
|   if (!m_wl_module) | ||||
|   { | ||||
|     Log_ErrorPrintf("Failed to load %s.", WAYLAND_EGL_MODNAME); | ||||
|     return false; | ||||
|   } | ||||
| bool ContextEGLWayland::LoadModule() { | ||||
|     m_wl_module = dlopen(WAYLAND_EGL_MODNAME, RTLD_NOW | RTLD_GLOBAL); | ||||
|     if (!m_wl_module) { | ||||
|         Log_ErrorPrintf("Failed to load %s.", WAYLAND_EGL_MODNAME); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|   m_wl_egl_window_create = | ||||
|     reinterpret_cast<decltype(m_wl_egl_window_create)>(dlsym(m_wl_module, "wl_egl_window_create")); | ||||
|   m_wl_egl_window_destroy = | ||||
|     reinterpret_cast<decltype(m_wl_egl_window_destroy)>(dlsym(m_wl_module, "wl_egl_window_destroy")); | ||||
|   m_wl_egl_window_resize = | ||||
|     reinterpret_cast<decltype(m_wl_egl_window_resize)>(dlsym(m_wl_module, "wl_egl_window_resize")); | ||||
|   if (!m_wl_egl_window_create || !m_wl_egl_window_destroy || !m_wl_egl_window_resize) | ||||
|   { | ||||
|     Log_ErrorPrintf("Failed to load one or more functions from %s.", WAYLAND_EGL_MODNAME); | ||||
|     return false; | ||||
|   } | ||||
|     m_wl_egl_window_create = reinterpret_cast<decltype(m_wl_egl_window_create)>( | ||||
|         dlsym(m_wl_module, "wl_egl_window_create")); | ||||
|     m_wl_egl_window_destroy = reinterpret_cast<decltype(m_wl_egl_window_destroy)>( | ||||
|         dlsym(m_wl_module, "wl_egl_window_destroy")); | ||||
|     m_wl_egl_window_resize = reinterpret_cast<decltype(m_wl_egl_window_resize)>( | ||||
|         dlsym(m_wl_module, "wl_egl_window_resize")); | ||||
|     if (!m_wl_egl_window_create || !m_wl_egl_window_destroy || !m_wl_egl_window_resize) { | ||||
|         Log_ErrorPrintf("Failed to load one or more functions from %s.", WAYLAND_EGL_MODNAME); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|   return true; | ||||
|     return true; | ||||
| } | ||||
| } // namespace GL
 | ||||
|  |  | |||
|  | @ -1,33 +1,33 @@ | |||
| #pragma once | ||||
| #include "context_egl.h" | ||||
| #include <wayland-egl.h> | ||||
| #include "context_egl.h" | ||||
| 
 | ||||
| namespace GL { | ||||
| 
 | ||||
| class ContextEGLWayland final : public ContextEGL | ||||
| { | ||||
| class ContextEGLWayland final : public ContextEGL { | ||||
| public: | ||||
|   ContextEGLWayland(const WindowInfo& wi); | ||||
|   ~ContextEGLWayland() override; | ||||
|     ContextEGLWayland(const WindowInfo& wi); | ||||
|     ~ContextEGLWayland() override; | ||||
| 
 | ||||
|   static std::unique_ptr<Context> Create(const WindowInfo& wi, const Version* versions_to_try, | ||||
|                                          size_t num_versions_to_try); | ||||
|     static std::unique_ptr<Context> Create(const WindowInfo& wi, const Version* versions_to_try, | ||||
|                                            size_t num_versions_to_try); | ||||
| 
 | ||||
|   std::unique_ptr<Context> CreateSharedContext(const WindowInfo& wi) override; | ||||
|   void ResizeSurface(u32 new_surface_width = 0, u32 new_surface_height = 0) override; | ||||
|     std::unique_ptr<Context> CreateSharedContext(const WindowInfo& wi) override; | ||||
|     void ResizeSurface(u32 new_surface_width = 0, u32 new_surface_height = 0) override; | ||||
| 
 | ||||
| protected: | ||||
|   EGLNativeWindowType GetNativeWindow(EGLConfig config) override; | ||||
|     EGLNativeWindowType GetNativeWindow(EGLConfig config) override; | ||||
| 
 | ||||
| private: | ||||
|   bool LoadModule(); | ||||
|     bool LoadModule(); | ||||
| 
 | ||||
|   wl_egl_window* m_wl_window = nullptr; | ||||
|     wl_egl_window* m_wl_window = nullptr; | ||||
| 
 | ||||
|   void* m_wl_module = nullptr; | ||||
|   wl_egl_window* (*m_wl_egl_window_create)(struct wl_surface* surface, int width, int height); | ||||
|   void (*m_wl_egl_window_destroy)(struct wl_egl_window* egl_window); | ||||
|   void (*m_wl_egl_window_resize)(struct wl_egl_window* egl_window, int width, int height, int dx, int dy); | ||||
|     void* m_wl_module = nullptr; | ||||
|     wl_egl_window* (*m_wl_egl_window_create)(struct wl_surface* surface, int width, int height); | ||||
|     void (*m_wl_egl_window_destroy)(struct wl_egl_window* egl_window); | ||||
|     void (*m_wl_egl_window_resize)(struct wl_egl_window* egl_window, int width, int height, int dx, | ||||
|                                    int dy); | ||||
| }; | ||||
| 
 | ||||
| } // namespace GL
 | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| #include "context_egl_x11.h" | ||||
| #include "../log.h" | ||||
| #include "context_egl_x11.h" | ||||
| Log_SetChannel(GL::ContextEGLX11); | ||||
| 
 | ||||
| namespace GL { | ||||
|  | @ -7,63 +7,59 @@ ContextEGLX11::ContextEGLX11(const WindowInfo& wi) : ContextEGL(wi) {} | |||
| ContextEGLX11::~ContextEGLX11() = default; | ||||
| 
 | ||||
| std::unique_ptr<Context> ContextEGLX11::Create(const WindowInfo& wi, const Version* versions_to_try, | ||||
|                                                size_t num_versions_to_try) | ||||
| { | ||||
|   std::unique_ptr<ContextEGLX11> context = std::make_unique<ContextEGLX11>(wi); | ||||
|   if (!context->Initialize(versions_to_try, num_versions_to_try)) | ||||
|     return nullptr; | ||||
|                                                size_t num_versions_to_try) { | ||||
|     std::unique_ptr<ContextEGLX11> context = std::make_unique<ContextEGLX11>(wi); | ||||
|     if (!context->Initialize(versions_to_try, num_versions_to_try)) | ||||
|         return nullptr; | ||||
| 
 | ||||
|   return context; | ||||
|     return context; | ||||
| } | ||||
| 
 | ||||
| std::unique_ptr<Context> ContextEGLX11::CreateSharedContext(const WindowInfo& wi) | ||||
| { | ||||
|   std::unique_ptr<ContextEGLX11> context = std::make_unique<ContextEGLX11>(wi); | ||||
|   context->m_display = m_display; | ||||
| std::unique_ptr<Context> ContextEGLX11::CreateSharedContext(const WindowInfo& wi) { | ||||
|     std::unique_ptr<ContextEGLX11> context = std::make_unique<ContextEGLX11>(wi); | ||||
|     context->m_display = m_display; | ||||
| 
 | ||||
|   if (!context->CreateContextAndSurface(m_version, m_context, false)) | ||||
|     return nullptr; | ||||
|     if (!context->CreateContextAndSurface(m_version, m_context, false)) | ||||
|         return nullptr; | ||||
| 
 | ||||
|   return context; | ||||
|     return context; | ||||
| } | ||||
| 
 | ||||
| void ContextEGLX11::ResizeSurface(u32 new_surface_width, u32 new_surface_height) | ||||
| { | ||||
|   m_window.Resize(); | ||||
|   ContextEGL::ResizeSurface(new_surface_width, new_surface_height); | ||||
| void ContextEGLX11::ResizeSurface(u32 new_surface_width, u32 new_surface_height) { | ||||
|     m_window.Resize(); | ||||
|     ContextEGL::ResizeSurface(new_surface_width, new_surface_height); | ||||
| } | ||||
| 
 | ||||
| EGLNativeWindowType ContextEGLX11::GetNativeWindow(EGLConfig config) | ||||
| { | ||||
|   X11InhibitErrors ei; | ||||
| EGLNativeWindowType ContextEGLX11::GetNativeWindow(EGLConfig config) { | ||||
|     X11InhibitErrors ei; | ||||
| 
 | ||||
|   EGLint native_visual_id = 0; | ||||
|   if (!eglGetConfigAttrib(m_display, m_config, EGL_NATIVE_VISUAL_ID, &native_visual_id)) | ||||
|   { | ||||
|     Log_ErrorPrintf("Failed to get X11 visual ID"); | ||||
|     return false; | ||||
|   } | ||||
|     EGLint native_visual_id = 0; | ||||
|     if (!eglGetConfigAttrib(m_display, m_config, EGL_NATIVE_VISUAL_ID, &native_visual_id)) { | ||||
|         Log_ErrorPrintf("Failed to get X11 visual ID"); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|   XVisualInfo vi_query = {}; | ||||
|   vi_query.visualid = native_visual_id; | ||||
|     XVisualInfo vi_query = {}; | ||||
|     vi_query.visualid = native_visual_id; | ||||
| 
 | ||||
|   int num_vis; | ||||
|   XVisualInfo* vi = XGetVisualInfo(static_cast<Display*>(m_wi.display_connection), VisualIDMask, &vi_query, &num_vis); | ||||
|   if (num_vis <= 0 || !vi) | ||||
|   { | ||||
|     Log_ErrorPrintf("Failed to query visual from X11"); | ||||
|     return false; | ||||
|   } | ||||
|     int num_vis; | ||||
|     XVisualInfo* vi = XGetVisualInfo(static_cast<Display*>(m_wi.display_connection), VisualIDMask, | ||||
|                                      &vi_query, &num_vis); | ||||
|     if (num_vis <= 0 || !vi) { | ||||
|         Log_ErrorPrintf("Failed to query visual from X11"); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     m_window.Destroy(); | ||||
|     if (!m_window.Create(GetDisplay(), | ||||
|                          static_cast<Window>(reinterpret_cast<uintptr_t>(m_wi.window_handle)), | ||||
|                          vi)) { | ||||
|         Log_ErrorPrintf("Faild to create X11 child window"); | ||||
|         XFree(vi); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|   m_window.Destroy(); | ||||
|   if (!m_window.Create(GetDisplay(), static_cast<Window>(reinterpret_cast<uintptr_t>(m_wi.window_handle)), vi)) | ||||
|   { | ||||
|     Log_ErrorPrintf("Faild to create X11 child window"); | ||||
|     XFree(vi); | ||||
|     return false; | ||||
|   } | ||||
| 
 | ||||
|   XFree(vi); | ||||
|   return static_cast<EGLNativeWindowType>(m_window.GetWindow()); | ||||
|     return static_cast<EGLNativeWindowType>(m_window.GetWindow()); | ||||
| } | ||||
| } // namespace GL
 | ||||
|  |  | |||
|  | @ -4,25 +4,26 @@ | |||
| 
 | ||||
| namespace GL { | ||||
| 
 | ||||
| class ContextEGLX11 final : public ContextEGL | ||||
| { | ||||
| class ContextEGLX11 final : public ContextEGL { | ||||
| public: | ||||
|   ContextEGLX11(const WindowInfo& wi); | ||||
|   ~ContextEGLX11() override; | ||||
|     ContextEGLX11(const WindowInfo& wi); | ||||
|     ~ContextEGLX11() override; | ||||
| 
 | ||||
|   static std::unique_ptr<Context> Create(const WindowInfo& wi, const Version* versions_to_try, | ||||
|                                          size_t num_versions_to_try); | ||||
|     static std::unique_ptr<Context> Create(const WindowInfo& wi, const Version* versions_to_try, | ||||
|                                            size_t num_versions_to_try); | ||||
| 
 | ||||
|   std::unique_ptr<Context> CreateSharedContext(const WindowInfo& wi) override; | ||||
|   void ResizeSurface(u32 new_surface_width = 0, u32 new_surface_height = 0) override; | ||||
|     std::unique_ptr<Context> CreateSharedContext(const WindowInfo& wi) override; | ||||
|     void ResizeSurface(u32 new_surface_width = 0, u32 new_surface_height = 0) override; | ||||
| 
 | ||||
| protected: | ||||
|   EGLNativeWindowType GetNativeWindow(EGLConfig config) override; | ||||
|     EGLNativeWindowType GetNativeWindow(EGLConfig config) override; | ||||
| 
 | ||||
| private: | ||||
|   ALWAYS_INLINE Display* GetDisplay() const { return static_cast<Display*>(m_wi.display_connection); } | ||||
|     ALWAYS_INLINE Display* GetDisplay() const { | ||||
|         return static_cast<Display*>(m_wi.display_connection); | ||||
|     } | ||||
| 
 | ||||
|   X11Window m_window; | ||||
|     X11Window m_window; | ||||
| }; | ||||
| 
 | ||||
| } // namespace GL
 | ||||
|  |  | |||
|  | @ -1,328 +1,281 @@ | |||
| #include "context_glx.h" | ||||
| #include <dlfcn.h> | ||||
| #include "../duckstation_compat.h" | ||||
| #include "../log.h" | ||||
| #include <dlfcn.h> | ||||
| #include "context_glx.h" | ||||
| Log_SetChannel(GL::ContextGLX); | ||||
| 
 | ||||
| namespace GL { | ||||
| ContextGLX::ContextGLX(const WindowInfo& wi) : Context(wi) {} | ||||
| 
 | ||||
| ContextGLX::~ContextGLX() | ||||
| { | ||||
|   if (glXGetCurrentContext() == m_context) | ||||
|     glXMakeCurrent(GetDisplay(), None, nullptr); | ||||
| ContextGLX::~ContextGLX() { | ||||
|     if (glXGetCurrentContext() == m_context) | ||||
|         glXMakeCurrent(GetDisplay(), None, nullptr); | ||||
| 
 | ||||
|   if (m_context) | ||||
|     glXDestroyContext(GetDisplay(), m_context); | ||||
|     if (m_context) | ||||
|         glXDestroyContext(GetDisplay(), m_context); | ||||
| 
 | ||||
|   if (m_vi) | ||||
|     XFree(m_vi); | ||||
|     if (m_vi) | ||||
|         XFree(m_vi); | ||||
| 
 | ||||
|   if (m_libGL_handle) | ||||
|     dlclose(m_libGL_handle); | ||||
|     if (m_libGL_handle) | ||||
|         dlclose(m_libGL_handle); | ||||
| } | ||||
| 
 | ||||
| std::unique_ptr<Context> ContextGLX::Create(const WindowInfo& wi, const Version* versions_to_try, | ||||
|                                             size_t num_versions_to_try) | ||||
| { | ||||
|   std::unique_ptr<ContextGLX> context = std::make_unique<ContextGLX>(wi); | ||||
|   if (!context->Initialize(versions_to_try, num_versions_to_try)) | ||||
|     return nullptr; | ||||
|                                             size_t num_versions_to_try) { | ||||
|     std::unique_ptr<ContextGLX> context = std::make_unique<ContextGLX>(wi); | ||||
|     if (!context->Initialize(versions_to_try, num_versions_to_try)) | ||||
|         return nullptr; | ||||
| 
 | ||||
|   return context; | ||||
|     return context; | ||||
| } | ||||
| 
 | ||||
| bool ContextGLX::Initialize(const Version* versions_to_try, size_t num_versions_to_try) | ||||
| { | ||||
|   // We need libGL loaded, because GLAD loads its own, then releases it.
 | ||||
|   m_libGL_handle = dlopen("libGL.so.1", RTLD_NOW | RTLD_GLOBAL); | ||||
|   if (!m_libGL_handle) | ||||
|   { | ||||
|     m_libGL_handle = dlopen("libGL.so", RTLD_NOW | RTLD_GLOBAL); | ||||
|     if (!m_libGL_handle) | ||||
|     { | ||||
|       Log_ErrorPrintf("Failed to load libGL.so: %s", dlerror()); | ||||
|       return false; | ||||
| bool ContextGLX::Initialize(const Version* versions_to_try, size_t num_versions_to_try) { | ||||
|     // We need libGL loaded, because GLAD loads its own, then releases it.
 | ||||
|     m_libGL_handle = dlopen("libGL.so.1", RTLD_NOW | RTLD_GLOBAL); | ||||
|     if (!m_libGL_handle) { | ||||
|         m_libGL_handle = dlopen("libGL.so", RTLD_NOW | RTLD_GLOBAL); | ||||
|         if (!m_libGL_handle) { | ||||
|             Log_ErrorPrintf("Failed to load libGL.so: %s", dlerror()); | ||||
|             return false; | ||||
|         } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   const int screen = DefaultScreen(GetDisplay()); | ||||
|   if (!gladLoadGLX(GetDisplay(), screen)) | ||||
|   { | ||||
|     Log_ErrorPrintf("Loading GLAD GLX functions failed"); | ||||
|     return false; | ||||
|   } | ||||
| 
 | ||||
|   if (m_wi.type == WindowInfo::Type::X11) | ||||
|   { | ||||
|     if (!CreateWindow(screen)) | ||||
|       return false; | ||||
|   } | ||||
|   else | ||||
|   { | ||||
|     Panic("Create pbuffer"); | ||||
|   } | ||||
| 
 | ||||
|   for (size_t i = 0; i < num_versions_to_try; i++) | ||||
|   { | ||||
|     const Version& cv = versions_to_try[i]; | ||||
|     if (cv.profile == Profile::NoProfile && CreateAnyContext(nullptr, true)) | ||||
|     { | ||||
|       m_version = cv; | ||||
|       return true; | ||||
|     } | ||||
|     else if (cv.profile != Profile::NoProfile && CreateVersionContext(cv, nullptr, true)) | ||||
|     { | ||||
|       m_version = cv; | ||||
|       return true; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   return false; | ||||
| } | ||||
| 
 | ||||
| void* ContextGLX::GetProcAddress(const char* name) | ||||
| { | ||||
|   return reinterpret_cast<void*>(glXGetProcAddress(reinterpret_cast<const GLubyte*>(name))); | ||||
| } | ||||
| 
 | ||||
| bool ContextGLX::ChangeSurface(const WindowInfo& new_wi) | ||||
| { | ||||
|   const bool was_current = (glXGetCurrentContext() == m_context); | ||||
|   if (was_current) | ||||
|     glXMakeCurrent(GetDisplay(), None, nullptr); | ||||
| 
 | ||||
|   m_window.Destroy(); | ||||
|   m_wi = new_wi; | ||||
| 
 | ||||
|   if (new_wi.type == WindowInfo::Type::X11) | ||||
|   { | ||||
|     const int screen = DefaultScreen(GetDisplay()); | ||||
|     if (!CreateWindow(screen)) | ||||
|       return false; | ||||
|   } | ||||
|     if (!gladLoadGLX(GetDisplay(), screen)) { | ||||
|         Log_ErrorPrintf("Loading GLAD GLX functions failed"); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     if (m_wi.type == WindowInfo::Type::X11) { | ||||
|         if (!CreateWindow(screen)) | ||||
|             return false; | ||||
|     } else { | ||||
|         Panic("Create pbuffer"); | ||||
|     } | ||||
| 
 | ||||
|     for (size_t i = 0; i < num_versions_to_try; i++) { | ||||
|         const Version& cv = versions_to_try[i]; | ||||
|         if (cv.profile == Profile::NoProfile && CreateAnyContext(nullptr, true)) { | ||||
|             m_version = cv; | ||||
|             return true; | ||||
|         } else if (cv.profile != Profile::NoProfile && CreateVersionContext(cv, nullptr, true)) { | ||||
|             m_version = cv; | ||||
|             return true; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|   if (was_current && !glXMakeCurrent(GetDisplay(), GetDrawable(), m_context)) | ||||
|   { | ||||
|     Log_ErrorPrintf("Failed to make context current again after surface change"); | ||||
|     return false; | ||||
|   } | ||||
| 
 | ||||
|   return true; | ||||
| } | ||||
| 
 | ||||
| void ContextGLX::ResizeSurface(u32 new_surface_width /*= 0*/, u32 new_surface_height /*= 0*/) | ||||
| { | ||||
|   m_window.Resize(new_surface_width, new_surface_height); | ||||
|   m_wi.surface_width = m_window.GetWidth(); | ||||
|   m_wi.surface_height = m_window.GetHeight(); | ||||
| void* ContextGLX::GetProcAddress(const char* name) { | ||||
|     return reinterpret_cast<void*>(glXGetProcAddress(reinterpret_cast<const GLubyte*>(name))); | ||||
| } | ||||
| 
 | ||||
| bool ContextGLX::SwapBuffers() | ||||
| { | ||||
|   glXSwapBuffers(GetDisplay(), GetDrawable()); | ||||
|   return true; | ||||
| } | ||||
| bool ContextGLX::ChangeSurface(const WindowInfo& new_wi) { | ||||
|     const bool was_current = (glXGetCurrentContext() == m_context); | ||||
|     if (was_current) | ||||
|         glXMakeCurrent(GetDisplay(), None, nullptr); | ||||
| 
 | ||||
| bool ContextGLX::MakeCurrent() | ||||
| { | ||||
|   return (glXMakeCurrent(GetDisplay(), GetDrawable(), m_context) == True); | ||||
| } | ||||
|     m_window.Destroy(); | ||||
|     m_wi = new_wi; | ||||
| 
 | ||||
| bool ContextGLX::DoneCurrent() | ||||
| { | ||||
|   return (glXMakeCurrent(GetDisplay(), None, nullptr) == True); | ||||
| } | ||||
|     if (new_wi.type == WindowInfo::Type::X11) { | ||||
|         const int screen = DefaultScreen(GetDisplay()); | ||||
|         if (!CreateWindow(screen)) | ||||
|             return false; | ||||
|     } | ||||
| 
 | ||||
|     if (was_current && !glXMakeCurrent(GetDisplay(), GetDrawable(), m_context)) { | ||||
|         Log_ErrorPrintf("Failed to make context current again after surface change"); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
| bool ContextGLX::SetSwapInterval(s32 interval) | ||||
| { | ||||
|   if (GLAD_GLX_EXT_swap_control) | ||||
|   { | ||||
|     glXSwapIntervalEXT(GetDisplay(), GetDrawable(), interval); | ||||
|     return true; | ||||
|   } | ||||
|   else if (GLAD_GLX_MESA_swap_control) | ||||
|   { | ||||
|     return (glXSwapIntervalMESA(static_cast<u32>(std::max(interval, 0))) != 0); | ||||
|   } | ||||
|   else if (GLAD_GLX_SGI_swap_control) | ||||
|   { | ||||
|     return (glXSwapIntervalSGI(interval) != 0); | ||||
|   } | ||||
|   else | ||||
|   { | ||||
|     return false; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| std::unique_ptr<Context> ContextGLX::CreateSharedContext(const WindowInfo& wi) | ||||
| { | ||||
|   std::unique_ptr<ContextGLX> context = std::make_unique<ContextGLX>(wi); | ||||
|   if (wi.type == WindowInfo::Type::X11) | ||||
|   { | ||||
|     const int screen = DefaultScreen(context->GetDisplay()); | ||||
|     if (!context->CreateWindow(screen)) | ||||
|       return nullptr; | ||||
|   } | ||||
|   else | ||||
|   { | ||||
|     Panic("Create pbuffer"); | ||||
|   } | ||||
| 
 | ||||
|   if (m_version.profile == Profile::NoProfile) | ||||
|   { | ||||
|     if (!context->CreateAnyContext(m_context, false)) | ||||
|       return nullptr; | ||||
|   } | ||||
|   else | ||||
|   { | ||||
|     if (!context->CreateVersionContext(m_version, m_context, false)) | ||||
|       return nullptr; | ||||
|   } | ||||
| 
 | ||||
|   context->m_version = m_version; | ||||
|   return context; | ||||
| void ContextGLX::ResizeSurface(u32 new_surface_width /*= 0*/, u32 new_surface_height /*= 0*/) { | ||||
|     m_window.Resize(new_surface_width, new_surface_height); | ||||
|     m_wi.surface_width = m_window.GetWidth(); | ||||
|     m_wi.surface_height = m_window.GetHeight(); | ||||
| } | ||||
| 
 | ||||
| bool ContextGLX::CreateWindow(int screen) | ||||
| { | ||||
|   int attribs[32] = {GLX_X_RENDERABLE,  True,           GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, | ||||
|                      GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR, GLX_DOUBLEBUFFER,  True}; | ||||
|   int nattribs = 8; | ||||
| bool ContextGLX::SwapBuffers() { | ||||
|     glXSwapBuffers(GetDisplay(), GetDrawable()); | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
|   switch (m_wi.surface_format) | ||||
|   { | ||||
| bool ContextGLX::MakeCurrent() { | ||||
|     return (glXMakeCurrent(GetDisplay(), GetDrawable(), m_context) == True); | ||||
| } | ||||
| 
 | ||||
| bool ContextGLX::DoneCurrent() { | ||||
|     return (glXMakeCurrent(GetDisplay(), None, nullptr) == True); | ||||
| } | ||||
| 
 | ||||
| bool ContextGLX::SetSwapInterval(s32 interval) { | ||||
|     if (GLAD_GLX_EXT_swap_control) { | ||||
|         glXSwapIntervalEXT(GetDisplay(), GetDrawable(), interval); | ||||
|         return true; | ||||
|     } else if (GLAD_GLX_MESA_swap_control) { | ||||
|         return (glXSwapIntervalMESA(static_cast<u32>(std::max(interval, 0))) != 0); | ||||
|     } else if (GLAD_GLX_SGI_swap_control) { | ||||
|         return (glXSwapIntervalSGI(interval) != 0); | ||||
|     } else { | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| std::unique_ptr<Context> ContextGLX::CreateSharedContext(const WindowInfo& wi) { | ||||
|     std::unique_ptr<ContextGLX> context = std::make_unique<ContextGLX>(wi); | ||||
|     if (wi.type == WindowInfo::Type::X11) { | ||||
|         const int screen = DefaultScreen(context->GetDisplay()); | ||||
|         if (!context->CreateWindow(screen)) | ||||
|             return nullptr; | ||||
|     } else { | ||||
|         Panic("Create pbuffer"); | ||||
|     } | ||||
| 
 | ||||
|     if (m_version.profile == Profile::NoProfile) { | ||||
|         if (!context->CreateAnyContext(m_context, false)) | ||||
|             return nullptr; | ||||
|     } else { | ||||
|         if (!context->CreateVersionContext(m_version, m_context, false)) | ||||
|             return nullptr; | ||||
|     } | ||||
| 
 | ||||
|     context->m_version = m_version; | ||||
|     return context; | ||||
| } | ||||
| 
 | ||||
| bool ContextGLX::CreateWindow(int screen) { | ||||
|     int attribs[32] = {GLX_X_RENDERABLE,  True,           GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, | ||||
|                        GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR, GLX_DOUBLEBUFFER,  True}; | ||||
|     int nattribs = 8; | ||||
| 
 | ||||
|     switch (m_wi.surface_format) { | ||||
|     case WindowInfo::SurfaceFormat::RGB8: | ||||
|       attribs[nattribs++] = GLX_RED_SIZE; | ||||
|       attribs[nattribs++] = 8; | ||||
|       attribs[nattribs++] = GLX_GREEN_SIZE; | ||||
|       attribs[nattribs++] = 8; | ||||
|       attribs[nattribs++] = GLX_BLUE_SIZE; | ||||
|       attribs[nattribs++] = 8; | ||||
|       break; | ||||
|         attribs[nattribs++] = GLX_RED_SIZE; | ||||
|         attribs[nattribs++] = 8; | ||||
|         attribs[nattribs++] = GLX_GREEN_SIZE; | ||||
|         attribs[nattribs++] = 8; | ||||
|         attribs[nattribs++] = GLX_BLUE_SIZE; | ||||
|         attribs[nattribs++] = 8; | ||||
|         break; | ||||
| 
 | ||||
|     case WindowInfo::SurfaceFormat::RGBA8: | ||||
|       attribs[nattribs++] = GLX_RED_SIZE; | ||||
|       attribs[nattribs++] = 8; | ||||
|       attribs[nattribs++] = GLX_GREEN_SIZE; | ||||
|       attribs[nattribs++] = 8; | ||||
|       attribs[nattribs++] = GLX_BLUE_SIZE; | ||||
|       attribs[nattribs++] = 8; | ||||
|       attribs[nattribs++] = GLX_ALPHA_SIZE; | ||||
|       attribs[nattribs++] = 8; | ||||
|       break; | ||||
|         attribs[nattribs++] = GLX_RED_SIZE; | ||||
|         attribs[nattribs++] = 8; | ||||
|         attribs[nattribs++] = GLX_GREEN_SIZE; | ||||
|         attribs[nattribs++] = 8; | ||||
|         attribs[nattribs++] = GLX_BLUE_SIZE; | ||||
|         attribs[nattribs++] = 8; | ||||
|         attribs[nattribs++] = GLX_ALPHA_SIZE; | ||||
|         attribs[nattribs++] = 8; | ||||
|         break; | ||||
| 
 | ||||
|     case WindowInfo::SurfaceFormat::RGB565: | ||||
|       attribs[nattribs++] = GLX_RED_SIZE; | ||||
|       attribs[nattribs++] = 5; | ||||
|       attribs[nattribs++] = GLX_GREEN_SIZE; | ||||
|       attribs[nattribs++] = 6; | ||||
|       attribs[nattribs++] = GLX_BLUE_SIZE; | ||||
|       attribs[nattribs++] = 5; | ||||
|       break; | ||||
|         attribs[nattribs++] = GLX_RED_SIZE; | ||||
|         attribs[nattribs++] = 5; | ||||
|         attribs[nattribs++] = GLX_GREEN_SIZE; | ||||
|         attribs[nattribs++] = 6; | ||||
|         attribs[nattribs++] = GLX_BLUE_SIZE; | ||||
|         attribs[nattribs++] = 5; | ||||
|         break; | ||||
| 
 | ||||
|     case WindowInfo::SurfaceFormat::Auto: | ||||
|       break; | ||||
|         break; | ||||
| 
 | ||||
|     default: | ||||
|       UnreachableCode(); | ||||
|       break; | ||||
|   } | ||||
|         UnreachableCode(); | ||||
|         break; | ||||
|     } | ||||
| 
 | ||||
|   attribs[nattribs++] = None; | ||||
|   attribs[nattribs++] = 0; | ||||
|     attribs[nattribs++] = None; | ||||
|     attribs[nattribs++] = 0; | ||||
| 
 | ||||
|   int fbcount = 0; | ||||
|   GLXFBConfig* fbc = glXChooseFBConfig(GetDisplay(), screen, attribs, &fbcount); | ||||
|   if (!fbc || !fbcount) | ||||
|   { | ||||
|     Log_ErrorPrintf("glXChooseFBConfig() failed"); | ||||
|     return false; | ||||
|   } | ||||
|   m_fb_config = *fbc; | ||||
|   XFree(fbc); | ||||
|     int fbcount = 0; | ||||
|     GLXFBConfig* fbc = glXChooseFBConfig(GetDisplay(), screen, attribs, &fbcount); | ||||
|     if (!fbc || !fbcount) { | ||||
|         Log_ErrorPrintf("glXChooseFBConfig() failed"); | ||||
|         return false; | ||||
|     } | ||||
|     m_fb_config = *fbc; | ||||
|     XFree(fbc); | ||||
| 
 | ||||
|   if (!GLAD_GLX_VERSION_1_3) | ||||
|   { | ||||
|     Log_ErrorPrintf("GLX Version 1.3 is required"); | ||||
|     return false; | ||||
|   } | ||||
|     if (!GLAD_GLX_VERSION_1_3) { | ||||
|         Log_ErrorPrintf("GLX Version 1.3 is required"); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|   m_vi = glXGetVisualFromFBConfig(GetDisplay(), m_fb_config); | ||||
|   if (!m_vi) | ||||
|   { | ||||
|     Log_ErrorPrintf("glXGetVisualFromFBConfig() failed"); | ||||
|     return false; | ||||
|   } | ||||
|     m_vi = glXGetVisualFromFBConfig(GetDisplay(), m_fb_config); | ||||
|     if (!m_vi) { | ||||
|         Log_ErrorPrintf("glXGetVisualFromFBConfig() failed"); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|   return m_window.Create(GetDisplay(), static_cast<Window>(reinterpret_cast<uintptr_t>(m_wi.window_handle)), m_vi); | ||||
|     return m_window.Create( | ||||
|         GetDisplay(), static_cast<Window>(reinterpret_cast<uintptr_t>(m_wi.window_handle)), m_vi); | ||||
| } | ||||
| 
 | ||||
| bool ContextGLX::CreateAnyContext(GLXContext share_context, bool make_current) | ||||
| { | ||||
|   X11InhibitErrors ie; | ||||
| bool ContextGLX::CreateAnyContext(GLXContext share_context, bool make_current) { | ||||
|     X11InhibitErrors ie; | ||||
| 
 | ||||
|   m_context = glXCreateContext(GetDisplay(), m_vi, share_context, True); | ||||
|   if (!m_context || ie.HadError()) | ||||
|   { | ||||
|     Log_ErrorPrintf("glxCreateContext() failed"); | ||||
|     return false; | ||||
|   } | ||||
| 
 | ||||
|   if (make_current) | ||||
|   { | ||||
|     if (!glXMakeCurrent(GetDisplay(), GetDrawable(), m_context)) | ||||
|     { | ||||
|       Log_ErrorPrintf("glXMakeCurrent() failed"); | ||||
|       return false; | ||||
|     m_context = glXCreateContext(GetDisplay(), m_vi, share_context, True); | ||||
|     if (!m_context || ie.HadError()) { | ||||
|         Log_ErrorPrintf("glxCreateContext() failed"); | ||||
|         return false; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   return true; | ||||
|     if (make_current) { | ||||
|         if (!glXMakeCurrent(GetDisplay(), GetDrawable(), m_context)) { | ||||
|             Log_ErrorPrintf("glXMakeCurrent() failed"); | ||||
|             return false; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool ContextGLX::CreateVersionContext(const Version& version, GLXContext share_context, bool make_current) | ||||
| { | ||||
|   // we need create context attribs
 | ||||
|   if (!GLAD_GLX_VERSION_1_3) | ||||
|   { | ||||
|     Log_ErrorPrint("Missing GLX version 1.3."); | ||||
|     return false; | ||||
|   } | ||||
| 
 | ||||
|   int attribs[32]; | ||||
|   int nattribs = 0; | ||||
|   attribs[nattribs++] = GLX_CONTEXT_PROFILE_MASK_ARB; | ||||
|   attribs[nattribs++] = | ||||
|     ((version.profile == Profile::ES) ? | ||||
|        ((version.major_version >= 2) ? GLX_CONTEXT_ES2_PROFILE_BIT_EXT : GLX_CONTEXT_ES_PROFILE_BIT_EXT) : | ||||
|        GLX_CONTEXT_CORE_PROFILE_BIT_ARB); | ||||
|   attribs[nattribs++] = GLX_CONTEXT_MAJOR_VERSION_ARB; | ||||
|   attribs[nattribs++] = version.major_version; | ||||
|   attribs[nattribs++] = GLX_CONTEXT_MINOR_VERSION_ARB; | ||||
|   attribs[nattribs++] = version.minor_version; | ||||
|   attribs[nattribs++] = None; | ||||
|   attribs[nattribs++] = 0; | ||||
| 
 | ||||
|   X11InhibitErrors ie; | ||||
|   m_context = glXCreateContextAttribsARB(GetDisplay(), m_fb_config, share_context, True, attribs); | ||||
|   XSync(GetDisplay(), False); | ||||
|   if (ie.HadError()) | ||||
|     m_context = nullptr; | ||||
|   if (!m_context) | ||||
|     return false; | ||||
| 
 | ||||
|   if (make_current) | ||||
|   { | ||||
|     if (!glXMakeCurrent(GetDisplay(), GetDrawable(), m_context)) | ||||
|     { | ||||
|       Log_ErrorPrint("glXMakeCurrent() failed"); | ||||
|       glXDestroyContext(GetDisplay(), m_context); | ||||
|       m_context = nullptr; | ||||
|       return false; | ||||
| bool ContextGLX::CreateVersionContext(const Version& version, GLXContext share_context, | ||||
|                                       bool make_current) { | ||||
|     // we need create context attribs
 | ||||
|     if (!GLAD_GLX_VERSION_1_3) { | ||||
|         Log_ErrorPrint("Missing GLX version 1.3."); | ||||
|         return false; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   return true; | ||||
|     int attribs[32]; | ||||
|     int nattribs = 0; | ||||
|     attribs[nattribs++] = GLX_CONTEXT_PROFILE_MASK_ARB; | ||||
|     attribs[nattribs++] = ((version.profile == Profile::ES) | ||||
|                                ? ((version.major_version >= 2) ? GLX_CONTEXT_ES2_PROFILE_BIT_EXT | ||||
|                                                                : GLX_CONTEXT_ES_PROFILE_BIT_EXT) | ||||
|                                : GLX_CONTEXT_CORE_PROFILE_BIT_ARB); | ||||
|     attribs[nattribs++] = GLX_CONTEXT_MAJOR_VERSION_ARB; | ||||
|     attribs[nattribs++] = version.major_version; | ||||
|     attribs[nattribs++] = GLX_CONTEXT_MINOR_VERSION_ARB; | ||||
|     attribs[nattribs++] = version.minor_version; | ||||
|     attribs[nattribs++] = None; | ||||
|     attribs[nattribs++] = 0; | ||||
| 
 | ||||
|     X11InhibitErrors ie; | ||||
|     m_context = glXCreateContextAttribsARB(GetDisplay(), m_fb_config, share_context, True, attribs); | ||||
|     XSync(GetDisplay(), False); | ||||
|     if (ie.HadError()) | ||||
|         m_context = nullptr; | ||||
|     if (!m_context) | ||||
|         return false; | ||||
| 
 | ||||
|     if (make_current) { | ||||
|         if (!glXMakeCurrent(GetDisplay(), GetDrawable(), m_context)) { | ||||
|             Log_ErrorPrint("glXMakeCurrent() failed"); | ||||
|             glXDestroyContext(GetDisplay(), m_context); | ||||
|             m_context = nullptr; | ||||
|             return false; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| } // namespace GL
 | ||||
|  |  | |||
|  | @ -1,44 +1,47 @@ | |||
| #pragma once | ||||
| #include "context.h" | ||||
| #include "../../../../../externals/glad/src/glad_glx.h" | ||||
| #include "context.h" | ||||
| #include "x11_window.h" | ||||
| 
 | ||||
| namespace GL { | ||||
| 
 | ||||
| class ContextGLX final : public Context | ||||
| { | ||||
| class ContextGLX final : public Context { | ||||
| public: | ||||
|   ContextGLX(const WindowInfo& wi); | ||||
|   ~ContextGLX() override; | ||||
|     ContextGLX(const WindowInfo& wi); | ||||
|     ~ContextGLX() override; | ||||
| 
 | ||||
|   static std::unique_ptr<Context> Create(const WindowInfo& wi, const Version* versions_to_try, | ||||
|                                          size_t num_versions_to_try); | ||||
|     static std::unique_ptr<Context> Create(const WindowInfo& wi, const Version* versions_to_try, | ||||
|                                            size_t num_versions_to_try); | ||||
| 
 | ||||
|   void* GetProcAddress(const char* name) override; | ||||
|   bool ChangeSurface(const WindowInfo& new_wi) override; | ||||
|   void ResizeSurface(u32 new_surface_width = 0, u32 new_surface_height = 0) override; | ||||
|   bool SwapBuffers() override; | ||||
|   bool MakeCurrent() override; | ||||
|   bool DoneCurrent() override; | ||||
|   bool SetSwapInterval(s32 interval) override; | ||||
|   std::unique_ptr<Context> CreateSharedContext(const WindowInfo& wi) override; | ||||
|     void* GetProcAddress(const char* name) override; | ||||
|     bool ChangeSurface(const WindowInfo& new_wi) override; | ||||
|     void ResizeSurface(u32 new_surface_width = 0, u32 new_surface_height = 0) override; | ||||
|     bool SwapBuffers() override; | ||||
|     bool MakeCurrent() override; | ||||
|     bool DoneCurrent() override; | ||||
|     bool SetSwapInterval(s32 interval) override; | ||||
|     std::unique_ptr<Context> CreateSharedContext(const WindowInfo& wi) override; | ||||
| 
 | ||||
| private: | ||||
|   ALWAYS_INLINE Display* GetDisplay() const { return static_cast<Display*>(m_wi.display_connection); } | ||||
|   ALWAYS_INLINE GLXDrawable GetDrawable() const { return static_cast<GLXDrawable>(m_window.GetWindow()); } | ||||
|     ALWAYS_INLINE Display* GetDisplay() const { | ||||
|         return static_cast<Display*>(m_wi.display_connection); | ||||
|     } | ||||
|     ALWAYS_INLINE GLXDrawable GetDrawable() const { | ||||
|         return static_cast<GLXDrawable>(m_window.GetWindow()); | ||||
|     } | ||||
| 
 | ||||
|   bool Initialize(const Version* versions_to_try, size_t num_versions_to_try); | ||||
|   bool CreateWindow(int screen); | ||||
|   bool CreateAnyContext(GLXContext share_context, bool make_current); | ||||
|   bool CreateVersionContext(const Version& version, GLXContext share_context, bool make_current); | ||||
|     bool Initialize(const Version* versions_to_try, size_t num_versions_to_try); | ||||
|     bool CreateWindow(int screen); | ||||
|     bool CreateAnyContext(GLXContext share_context, bool make_current); | ||||
|     bool CreateVersionContext(const Version& version, GLXContext share_context, bool make_current); | ||||
| 
 | ||||
|   GLXContext m_context = nullptr; | ||||
|   GLXFBConfig m_fb_config = {}; | ||||
|   XVisualInfo* m_vi = nullptr; | ||||
|   X11Window m_window; | ||||
|     GLXContext m_context = nullptr; | ||||
|     GLXFBConfig m_fb_config = {}; | ||||
|     XVisualInfo* m_vi = nullptr; | ||||
|     X11Window m_window; | ||||
| 
 | ||||
|   // GLAD releases its reference to libGL.so, so we need to maintain our own.
 | ||||
|   void* m_libGL_handle = nullptr; | ||||
|     // GLAD releases its reference to libGL.so, so we need to maintain our own.
 | ||||
|     void* m_libGL_handle = nullptr; | ||||
| }; | ||||
| 
 | ||||
| } // namespace GL
 | ||||
|  |  | |||
|  | @ -1,7 +1,7 @@ | |||
| #include "context_wgl.h" | ||||
| #include "../duckstation_compat.h" | ||||
| #include "../log.h" | ||||
| #include "../scoped_guard.h" | ||||
| #include "context_wgl.h" | ||||
| #include "loader.h" | ||||
| using namespace melonDS; | ||||
| Log_SetChannel(GL::ContextWGL); | ||||
|  | @ -9,445 +9,390 @@ Log_SetChannel(GL::ContextWGL); | |||
| // TODO: get rid of this
 | ||||
| #pragma comment(lib, "opengl32.lib") | ||||
| 
 | ||||
| static void* GetProcAddressCallback(const char* name) | ||||
| { | ||||
|   void* addr = reinterpret_cast<void*>(wglGetProcAddress(name)); | ||||
|   if (addr) | ||||
|     return addr; | ||||
| static void* GetProcAddressCallback(const char* name) { | ||||
|     void* addr = reinterpret_cast<void*>(wglGetProcAddress(name)); | ||||
|     if (addr) | ||||
|         return addr; | ||||
| 
 | ||||
|   // try opengl32.dll
 | ||||
|   return reinterpret_cast<void*>(::GetProcAddress(GetModuleHandleA("opengl32.dll"), name)); | ||||
|     // try opengl32.dll
 | ||||
|     return reinterpret_cast<void*>(::GetProcAddress(GetModuleHandleA("opengl32.dll"), name)); | ||||
| } | ||||
| 
 | ||||
| namespace GL { | ||||
| ContextWGL::ContextWGL(const WindowInfo& wi) : Context(wi) {} | ||||
| 
 | ||||
| ContextWGL::~ContextWGL() | ||||
| { | ||||
|   if (wglGetCurrentContext() == m_rc) | ||||
|     wglMakeCurrent(m_dc, nullptr); | ||||
| ContextWGL::~ContextWGL() { | ||||
|     if (wglGetCurrentContext() == m_rc) | ||||
|         wglMakeCurrent(m_dc, nullptr); | ||||
| 
 | ||||
|   if (m_rc) | ||||
|     wglDeleteContext(m_rc); | ||||
|     if (m_rc) | ||||
|         wglDeleteContext(m_rc); | ||||
| 
 | ||||
|   ReleaseDC(); | ||||
|     ReleaseDC(); | ||||
| } | ||||
| 
 | ||||
| std::unique_ptr<Context> ContextWGL::Create(const WindowInfo& wi, const Version* versions_to_try, | ||||
|                                             size_t num_versions_to_try) | ||||
| { | ||||
|   std::unique_ptr<ContextWGL> context = std::make_unique<ContextWGL>(wi); | ||||
|   if (!context->Initialize(versions_to_try, num_versions_to_try)) | ||||
|     return nullptr; | ||||
|                                             size_t num_versions_to_try) { | ||||
|     std::unique_ptr<ContextWGL> context = std::make_unique<ContextWGL>(wi); | ||||
|     if (!context->Initialize(versions_to_try, num_versions_to_try)) | ||||
|         return nullptr; | ||||
| 
 | ||||
|   return context; | ||||
|     return context; | ||||
| } | ||||
| 
 | ||||
| bool ContextWGL::Initialize(const Version* versions_to_try, size_t num_versions_to_try) | ||||
| { | ||||
|   if (m_wi.type == WindowInfo::Type::Win32) | ||||
|   { | ||||
| bool ContextWGL::Initialize(const Version* versions_to_try, size_t num_versions_to_try) { | ||||
|     if (m_wi.type == WindowInfo::Type::Win32) { | ||||
|         if (!InitializeDC()) | ||||
|             return false; | ||||
|     } else { | ||||
|         Log_ErrorPrint("ContextWGL must always start with a valid surface."); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     // Everything including core/ES requires a dummy profile to load the WGL extensions.
 | ||||
|     if (!CreateAnyContext(nullptr, true)) | ||||
|         return false; | ||||
| 
 | ||||
|     for (size_t i = 0; i < num_versions_to_try; i++) { | ||||
|         const Version& cv = versions_to_try[i]; | ||||
|         if (cv.profile == Profile::NoProfile) { | ||||
|             // we already have the dummy context, so just use that
 | ||||
|             m_version = cv; | ||||
|             return true; | ||||
|         } else if (CreateVersionContext(cv, nullptr, true)) { | ||||
|             m_version = cv; | ||||
|             return true; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| void* ContextWGL::GetProcAddress(const char* name) { | ||||
|     return GetProcAddressCallback(name); | ||||
| } | ||||
| 
 | ||||
| bool ContextWGL::ChangeSurface(const WindowInfo& new_wi) { | ||||
|     const bool was_current = (wglGetCurrentContext() == m_rc); | ||||
| 
 | ||||
|     ReleaseDC(); | ||||
| 
 | ||||
|     m_wi = new_wi; | ||||
|     if (!InitializeDC()) | ||||
|       return false; | ||||
|   } | ||||
|   else | ||||
|   { | ||||
|     Log_ErrorPrint("ContextWGL must always start with a valid surface."); | ||||
|     return false; | ||||
|   } | ||||
|         return false; | ||||
| 
 | ||||
|   // Everything including core/ES requires a dummy profile to load the WGL extensions.
 | ||||
|   if (!CreateAnyContext(nullptr, true)) | ||||
|     return false; | ||||
| 
 | ||||
|   for (size_t i = 0; i < num_versions_to_try; i++) | ||||
|   { | ||||
|     const Version& cv = versions_to_try[i]; | ||||
|     if (cv.profile == Profile::NoProfile) | ||||
|     { | ||||
|       // we already have the dummy context, so just use that
 | ||||
|       m_version = cv; | ||||
|       return true; | ||||
|     } | ||||
|     else if (CreateVersionContext(cv, nullptr, true)) | ||||
|     { | ||||
|       m_version = cv; | ||||
|       return true; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   return false; | ||||
| } | ||||
| 
 | ||||
| void* ContextWGL::GetProcAddress(const char* name) | ||||
| { | ||||
|   return GetProcAddressCallback(name); | ||||
| } | ||||
| 
 | ||||
| bool ContextWGL::ChangeSurface(const WindowInfo& new_wi) | ||||
| { | ||||
|   const bool was_current = (wglGetCurrentContext() == m_rc); | ||||
| 
 | ||||
|   ReleaseDC(); | ||||
| 
 | ||||
|   m_wi = new_wi; | ||||
|   if (!InitializeDC()) | ||||
|     return false; | ||||
| 
 | ||||
|   if (was_current && !wglMakeCurrent(m_dc, m_rc)) | ||||
|   { | ||||
|     Log_ErrorPrintf("Failed to make context current again after surface change: 0x%08X", GetLastError()); | ||||
|     return false; | ||||
|   } | ||||
| 
 | ||||
|   return true; | ||||
| } | ||||
| 
 | ||||
| void ContextWGL::ResizeSurface(u32 new_surface_width /*= 0*/, u32 new_surface_height /*= 0*/) | ||||
| { | ||||
|   RECT client_rc = {}; | ||||
|   GetClientRect(GetHWND(), &client_rc); | ||||
|   m_wi.surface_width = static_cast<u32>(client_rc.right - client_rc.left); | ||||
|   m_wi.surface_height = static_cast<u32>(client_rc.bottom - client_rc.top); | ||||
| } | ||||
| 
 | ||||
| bool ContextWGL::SwapBuffers() | ||||
| { | ||||
|   return ::SwapBuffers(m_dc); | ||||
| } | ||||
| 
 | ||||
| bool ContextWGL::MakeCurrent() | ||||
| { | ||||
|   if (!wglMakeCurrent(m_dc, m_rc)) | ||||
|   { | ||||
|     Log_ErrorPrintf("wglMakeCurrent() failed: 0x%08X", GetLastError()); | ||||
|     return false; | ||||
|   } | ||||
| 
 | ||||
|   return true; | ||||
| } | ||||
| 
 | ||||
| bool ContextWGL::DoneCurrent() | ||||
| { | ||||
|   return wglMakeCurrent(m_dc, nullptr); | ||||
| } | ||||
| 
 | ||||
| bool ContextWGL::SetSwapInterval(s32 interval) | ||||
| { | ||||
|   if (!GLAD_WGL_EXT_swap_control) | ||||
|     return false; | ||||
| 
 | ||||
|   return wglSwapIntervalEXT(interval); | ||||
| } | ||||
| 
 | ||||
| std::unique_ptr<Context> ContextWGL::CreateSharedContext(const WindowInfo& wi) | ||||
| { | ||||
|   std::unique_ptr<ContextWGL> context = std::make_unique<ContextWGL>(wi); | ||||
|   if (wi.type == WindowInfo::Type::Win32) | ||||
|   { | ||||
|     if (!context->InitializeDC()) | ||||
|       return nullptr; | ||||
|   } | ||||
|   else | ||||
|   { | ||||
|     Log_ErrorPrint("PBuffer not implemented"); | ||||
|     return nullptr; | ||||
|   } | ||||
| 
 | ||||
|   if (m_version.profile == Profile::NoProfile) | ||||
|   { | ||||
|     if (!context->CreateAnyContext(m_rc, false)) | ||||
|       return nullptr; | ||||
|   } | ||||
|   else | ||||
|   { | ||||
|     if (!context->CreateVersionContext(m_version, m_rc, false)) | ||||
|       return nullptr; | ||||
|   } | ||||
| 
 | ||||
|   context->m_version = m_version; | ||||
|   return context; | ||||
| } | ||||
| 
 | ||||
| HDC ContextWGL::GetDCAndSetPixelFormat(HWND hwnd) | ||||
| { | ||||
|   PIXELFORMATDESCRIPTOR pfd = {}; | ||||
|   pfd.nSize = sizeof(pfd); | ||||
|   pfd.nVersion = 1; | ||||
|   pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; | ||||
|   pfd.iPixelType = PFD_TYPE_RGBA; | ||||
|   pfd.dwLayerMask = PFD_MAIN_PLANE; | ||||
|   pfd.cRedBits = 8; | ||||
|   pfd.cGreenBits = 8; | ||||
|   pfd.cBlueBits = 8; | ||||
|   pfd.cColorBits = 24; | ||||
| 
 | ||||
|   HDC hDC = ::GetDC(hwnd); | ||||
|   if (!hDC) | ||||
|   { | ||||
|     Log_ErrorPrintf("GetDC() failed: 0x%08X", GetLastError()); | ||||
|     return {}; | ||||
|   } | ||||
| 
 | ||||
|   if (!m_pixel_format.has_value()) | ||||
|   { | ||||
|     const int pf = ChoosePixelFormat(hDC, &pfd); | ||||
|     if (pf == 0) | ||||
|     { | ||||
|       Log_ErrorPrintf("ChoosePixelFormat() failed: 0x%08X", GetLastError()); | ||||
|       ::ReleaseDC(hwnd, hDC); | ||||
|       return {}; | ||||
|     } | ||||
| 
 | ||||
|     m_pixel_format = pf; | ||||
|   } | ||||
| 
 | ||||
|   if (!SetPixelFormat(hDC, m_pixel_format.value(), &pfd)) | ||||
|   { | ||||
|     Log_ErrorPrintf("SetPixelFormat() failed: 0x%08X", GetLastError()); | ||||
|     ::ReleaseDC(hwnd, hDC); | ||||
|     return {}; | ||||
|   } | ||||
| 
 | ||||
|   return hDC; | ||||
| } | ||||
| 
 | ||||
| bool ContextWGL::InitializeDC() | ||||
| { | ||||
|   if (m_wi.type == WindowInfo::Type::Win32) | ||||
|   { | ||||
|     m_dc = GetDCAndSetPixelFormat(GetHWND()); | ||||
|     if (!m_dc) | ||||
|     { | ||||
|       Log_ErrorPrint("Failed to get DC for window"); | ||||
|       return false; | ||||
|     if (was_current && !wglMakeCurrent(m_dc, m_rc)) { | ||||
|         Log_ErrorPrintf("Failed to make context current again after surface change: 0x%08X", | ||||
|                         GetLastError()); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     return true; | ||||
|   } | ||||
|   else if (m_wi.type == WindowInfo::Type::Surfaceless) | ||||
|   { | ||||
|     return CreatePBuffer(); | ||||
|   } | ||||
|   else | ||||
|   { | ||||
|     Log_ErrorPrintf("Unknown window info type %u", static_cast<unsigned>(m_wi.type)); | ||||
|     return false; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void ContextWGL::ReleaseDC() | ||||
| { | ||||
|   if (m_pbuffer) | ||||
|   { | ||||
|     wglReleasePbufferDCARB(m_pbuffer, m_dc); | ||||
|     m_dc = {}; | ||||
| 
 | ||||
|     wglDestroyPbufferARB(m_pbuffer); | ||||
|     m_pbuffer = {}; | ||||
| 
 | ||||
|     ::ReleaseDC(m_dummy_window, m_dummy_dc); | ||||
|     m_dummy_dc = {}; | ||||
| 
 | ||||
|     DestroyWindow(m_dummy_window); | ||||
|     m_dummy_window = {}; | ||||
|   } | ||||
|   else if (m_dc) | ||||
|   { | ||||
|     ::ReleaseDC(GetHWND(), m_dc); | ||||
|     m_dc = {}; | ||||
|   } | ||||
| void ContextWGL::ResizeSurface(u32 new_surface_width /*= 0*/, u32 new_surface_height /*= 0*/) { | ||||
|     RECT client_rc = {}; | ||||
|     GetClientRect(GetHWND(), &client_rc); | ||||
|     m_wi.surface_width = static_cast<u32>(client_rc.right - client_rc.left); | ||||
|     m_wi.surface_height = static_cast<u32>(client_rc.bottom - client_rc.top); | ||||
| } | ||||
| 
 | ||||
| bool ContextWGL::CreatePBuffer() | ||||
| { | ||||
|   static bool window_class_registered = false; | ||||
|   static const wchar_t* window_class_name = L"ContextWGLPBuffer"; | ||||
| bool ContextWGL::SwapBuffers() { | ||||
|     return ::SwapBuffers(m_dc); | ||||
| } | ||||
| 
 | ||||
|   if (!window_class_registered) | ||||
|   { | ||||
|     WNDCLASSEXW wc = {}; | ||||
|     wc.cbSize = sizeof(WNDCLASSEXW); | ||||
|     wc.style = 0; | ||||
|     wc.lpfnWndProc = DefWindowProcW; | ||||
|     wc.cbClsExtra = 0; | ||||
|     wc.cbWndExtra = 0; | ||||
|     wc.hInstance = GetModuleHandle(nullptr); | ||||
|     wc.hIcon = NULL; | ||||
|     wc.hCursor = LoadCursor(NULL, IDC_ARROW); | ||||
|     wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); | ||||
|     wc.lpszMenuName = NULL; | ||||
|     wc.lpszClassName = window_class_name; | ||||
|     wc.hIconSm = NULL; | ||||
| 
 | ||||
|     if (!RegisterClassExW(&wc)) | ||||
|     { | ||||
|       Log_ErrorPrint("(ContextWGL::CreatePBuffer) RegisterClassExW() failed"); | ||||
|       return false; | ||||
| bool ContextWGL::MakeCurrent() { | ||||
|     if (!wglMakeCurrent(m_dc, m_rc)) { | ||||
|         Log_ErrorPrintf("wglMakeCurrent() failed: 0x%08X", GetLastError()); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     window_class_registered = true; | ||||
|   } | ||||
| 
 | ||||
|   HWND hwnd = CreateWindowExW(0, window_class_name, window_class_name, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL); | ||||
|   if (!hwnd) | ||||
|   { | ||||
|     Log_ErrorPrint("(ContextWGL::CreatePBuffer) CreateWindowEx() failed"); | ||||
|     return false; | ||||
|   } | ||||
| 
 | ||||
|   ScopedGuard hwnd_guard([hwnd]() { DestroyWindow(hwnd); }); | ||||
| 
 | ||||
|   HDC hdc = GetDCAndSetPixelFormat(hwnd); | ||||
|   if (!hdc) | ||||
|     return false; | ||||
| 
 | ||||
|   ScopedGuard hdc_guard([hdc, hwnd]() { ::ReleaseDC(hwnd, hdc); }); | ||||
| 
 | ||||
|   static constexpr const int pb_attribs[] = {0, 0}; | ||||
| 
 | ||||
|   AssertMsg(m_pixel_format.has_value(), "Has pixel format for pbuffer"); | ||||
|   HPBUFFERARB pbuffer = wglCreatePbufferARB(hdc, m_pixel_format.value(), 1, 1, pb_attribs); | ||||
|   if (!pbuffer) | ||||
|   { | ||||
|     Log_ErrorPrint("(ContextWGL::CreatePBuffer) wglCreatePbufferARB() failed"); | ||||
|     return false; | ||||
|   } | ||||
| 
 | ||||
|   ScopedGuard pbuffer_guard([pbuffer]() { wglDestroyPbufferARB(pbuffer); }); | ||||
| 
 | ||||
|   m_dc = wglGetPbufferDCARB(pbuffer); | ||||
|   if (!m_dc) | ||||
|   { | ||||
|     Log_ErrorPrint("(ContextWGL::CreatePbuffer) wglGetPbufferDCARB() failed"); | ||||
|     return false; | ||||
|   } | ||||
| 
 | ||||
|   m_dummy_window = hwnd; | ||||
|   m_dummy_dc = hdc; | ||||
|   m_pbuffer = pbuffer; | ||||
| 
 | ||||
|   pbuffer_guard.Cancel(); | ||||
|   hdc_guard.Cancel(); | ||||
|   hwnd_guard.Cancel(); | ||||
|   return true; | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool ContextWGL::CreateAnyContext(HGLRC share_context, bool make_current) | ||||
| { | ||||
|   m_rc = wglCreateContext(m_dc); | ||||
|   if (!m_rc) | ||||
|   { | ||||
|     Log_ErrorPrintf("wglCreateContext() failed: 0x%08X", GetLastError()); | ||||
|     return false; | ||||
|   } | ||||
| 
 | ||||
|   if (make_current) | ||||
|   { | ||||
|     if (!wglMakeCurrent(m_dc, m_rc)) | ||||
|     { | ||||
|       Log_ErrorPrintf("wglMakeCurrent() failed: 0x%08X", GetLastError()); | ||||
|       return false; | ||||
|     } | ||||
| 
 | ||||
|     // re-init glad-wgl
 | ||||
|     if (!gladLoadWGLLoader([](const char* name) -> void* { return reinterpret_cast<void*>(wglGetProcAddress(name)); }, m_dc)) | ||||
|     { | ||||
|       Log_ErrorPrint("Loading GLAD WGL functions failed"); | ||||
|       return false; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   if (share_context && !wglShareLists(share_context, m_rc)) | ||||
|   { | ||||
|     Log_ErrorPrintf("wglShareLists() failed: 0x%08X", GetLastError()); | ||||
|     return false; | ||||
|   } | ||||
| 
 | ||||
|   return true; | ||||
| bool ContextWGL::DoneCurrent() { | ||||
|     return wglMakeCurrent(m_dc, nullptr); | ||||
| } | ||||
| 
 | ||||
| bool ContextWGL::CreateVersionContext(const Version& version, HGLRC share_context, bool make_current) | ||||
| { | ||||
|   // we need create context attribs
 | ||||
|   if (!GLAD_WGL_ARB_create_context) | ||||
|   { | ||||
|     Log_ErrorPrint("Missing GLAD_WGL_ARB_create_context."); | ||||
|     return false; | ||||
|   } | ||||
| bool ContextWGL::SetSwapInterval(s32 interval) { | ||||
|     if (!GLAD_WGL_EXT_swap_control) | ||||
|         return false; | ||||
| 
 | ||||
|   HGLRC new_rc; | ||||
|   if (version.profile == Profile::Core) | ||||
|   { | ||||
|     const int attribs[] = {WGL_CONTEXT_PROFILE_MASK_ARB, | ||||
|                            WGL_CONTEXT_CORE_PROFILE_BIT_ARB, | ||||
|                            WGL_CONTEXT_MAJOR_VERSION_ARB, | ||||
|                            version.major_version, | ||||
|                            WGL_CONTEXT_MINOR_VERSION_ARB, | ||||
|                            version.minor_version, | ||||
|     return wglSwapIntervalEXT(interval); | ||||
| } | ||||
| 
 | ||||
| std::unique_ptr<Context> ContextWGL::CreateSharedContext(const WindowInfo& wi) { | ||||
|     std::unique_ptr<ContextWGL> context = std::make_unique<ContextWGL>(wi); | ||||
|     if (wi.type == WindowInfo::Type::Win32) { | ||||
|         if (!context->InitializeDC()) | ||||
|             return nullptr; | ||||
|     } else { | ||||
|         Log_ErrorPrint("PBuffer not implemented"); | ||||
|         return nullptr; | ||||
|     } | ||||
| 
 | ||||
|     if (m_version.profile == Profile::NoProfile) { | ||||
|         if (!context->CreateAnyContext(m_rc, false)) | ||||
|             return nullptr; | ||||
|     } else { | ||||
|         if (!context->CreateVersionContext(m_version, m_rc, false)) | ||||
|             return nullptr; | ||||
|     } | ||||
| 
 | ||||
|     context->m_version = m_version; | ||||
|     return context; | ||||
| } | ||||
| 
 | ||||
| HDC ContextWGL::GetDCAndSetPixelFormat(HWND hwnd) { | ||||
|     PIXELFORMATDESCRIPTOR pfd = {}; | ||||
|     pfd.nSize = sizeof(pfd); | ||||
|     pfd.nVersion = 1; | ||||
|     pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; | ||||
|     pfd.iPixelType = PFD_TYPE_RGBA; | ||||
|     pfd.dwLayerMask = PFD_MAIN_PLANE; | ||||
|     pfd.cRedBits = 8; | ||||
|     pfd.cGreenBits = 8; | ||||
|     pfd.cBlueBits = 8; | ||||
|     pfd.cColorBits = 24; | ||||
| 
 | ||||
|     HDC hDC = ::GetDC(hwnd); | ||||
|     if (!hDC) { | ||||
|         Log_ErrorPrintf("GetDC() failed: 0x%08X", GetLastError()); | ||||
|         return {}; | ||||
|     } | ||||
| 
 | ||||
|     if (!m_pixel_format.has_value()) { | ||||
|         const int pf = ChoosePixelFormat(hDC, &pfd); | ||||
|         if (pf == 0) { | ||||
|             Log_ErrorPrintf("ChoosePixelFormat() failed: 0x%08X", GetLastError()); | ||||
|             ::ReleaseDC(hwnd, hDC); | ||||
|             return {}; | ||||
|         } | ||||
| 
 | ||||
|         m_pixel_format = pf; | ||||
|     } | ||||
| 
 | ||||
|     if (!SetPixelFormat(hDC, m_pixel_format.value(), &pfd)) { | ||||
|         Log_ErrorPrintf("SetPixelFormat() failed: 0x%08X", GetLastError()); | ||||
|         ::ReleaseDC(hwnd, hDC); | ||||
|         return {}; | ||||
|     } | ||||
| 
 | ||||
|     return hDC; | ||||
| } | ||||
| 
 | ||||
| bool ContextWGL::InitializeDC() { | ||||
|     if (m_wi.type == WindowInfo::Type::Win32) { | ||||
|         m_dc = GetDCAndSetPixelFormat(GetHWND()); | ||||
|         if (!m_dc) { | ||||
|             Log_ErrorPrint("Failed to get DC for window"); | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         return true; | ||||
|     } else if (m_wi.type == WindowInfo::Type::Surfaceless) { | ||||
|         return CreatePBuffer(); | ||||
|     } else { | ||||
|         Log_ErrorPrintf("Unknown window info type %u", static_cast<unsigned>(m_wi.type)); | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void ContextWGL::ReleaseDC() { | ||||
|     if (m_pbuffer) { | ||||
|         wglReleasePbufferDCARB(m_pbuffer, m_dc); | ||||
|         m_dc = {}; | ||||
| 
 | ||||
|         wglDestroyPbufferARB(m_pbuffer); | ||||
|         m_pbuffer = {}; | ||||
| 
 | ||||
|         ::ReleaseDC(m_dummy_window, m_dummy_dc); | ||||
|         m_dummy_dc = {}; | ||||
| 
 | ||||
|         DestroyWindow(m_dummy_window); | ||||
|         m_dummy_window = {}; | ||||
|     } else if (m_dc) { | ||||
|         ::ReleaseDC(GetHWND(), m_dc); | ||||
|         m_dc = {}; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| bool ContextWGL::CreatePBuffer() { | ||||
|     static bool window_class_registered = false; | ||||
|     static const wchar_t* window_class_name = L"ContextWGLPBuffer"; | ||||
| 
 | ||||
|     if (!window_class_registered) { | ||||
|         WNDCLASSEXW wc = {}; | ||||
|         wc.cbSize = sizeof(WNDCLASSEXW); | ||||
|         wc.style = 0; | ||||
|         wc.lpfnWndProc = DefWindowProcW; | ||||
|         wc.cbClsExtra = 0; | ||||
|         wc.cbWndExtra = 0; | ||||
|         wc.hInstance = GetModuleHandle(nullptr); | ||||
|         wc.hIcon = NULL; | ||||
|         wc.hCursor = LoadCursor(NULL, IDC_ARROW); | ||||
|         wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); | ||||
|         wc.lpszMenuName = NULL; | ||||
|         wc.lpszClassName = window_class_name; | ||||
|         wc.hIconSm = NULL; | ||||
| 
 | ||||
|         if (!RegisterClassExW(&wc)) { | ||||
|             Log_ErrorPrint("(ContextWGL::CreatePBuffer) RegisterClassExW() failed"); | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         window_class_registered = true; | ||||
|     } | ||||
| 
 | ||||
|     HWND hwnd = CreateWindowExW(0, window_class_name, window_class_name, 0, 0, 0, 0, 0, NULL, NULL, | ||||
|                                 NULL, NULL); | ||||
|     if (!hwnd) { | ||||
|         Log_ErrorPrint("(ContextWGL::CreatePBuffer) CreateWindowEx() failed"); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     ScopedGuard hwnd_guard([hwnd]() { DestroyWindow(hwnd); }); | ||||
| 
 | ||||
|     HDC hdc = GetDCAndSetPixelFormat(hwnd); | ||||
|     if (!hdc) | ||||
|         return false; | ||||
| 
 | ||||
|     ScopedGuard hdc_guard([hdc, hwnd]() { ::ReleaseDC(hwnd, hdc); }); | ||||
| 
 | ||||
|     static constexpr const int pb_attribs[] = {0, 0}; | ||||
| 
 | ||||
|     AssertMsg(m_pixel_format.has_value(), "Has pixel format for pbuffer"); | ||||
|     HPBUFFERARB pbuffer = wglCreatePbufferARB(hdc, m_pixel_format.value(), 1, 1, pb_attribs); | ||||
|     if (!pbuffer) { | ||||
|         Log_ErrorPrint("(ContextWGL::CreatePBuffer) wglCreatePbufferARB() failed"); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     ScopedGuard pbuffer_guard([pbuffer]() { wglDestroyPbufferARB(pbuffer); }); | ||||
| 
 | ||||
|     m_dc = wglGetPbufferDCARB(pbuffer); | ||||
|     if (!m_dc) { | ||||
|         Log_ErrorPrint("(ContextWGL::CreatePbuffer) wglGetPbufferDCARB() failed"); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     m_dummy_window = hwnd; | ||||
|     m_dummy_dc = hdc; | ||||
|     m_pbuffer = pbuffer; | ||||
| 
 | ||||
|     pbuffer_guard.Cancel(); | ||||
|     hdc_guard.Cancel(); | ||||
|     hwnd_guard.Cancel(); | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool ContextWGL::CreateAnyContext(HGLRC share_context, bool make_current) { | ||||
|     m_rc = wglCreateContext(m_dc); | ||||
|     if (!m_rc) { | ||||
|         Log_ErrorPrintf("wglCreateContext() failed: 0x%08X", GetLastError()); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     if (make_current) { | ||||
|         if (!wglMakeCurrent(m_dc, m_rc)) { | ||||
|             Log_ErrorPrintf("wglMakeCurrent() failed: 0x%08X", GetLastError()); | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         // re-init glad-wgl
 | ||||
|         if (!gladLoadWGLLoader( | ||||
|                 [](const char* name) -> void* { | ||||
|                     return reinterpret_cast<void*>(wglGetProcAddress(name)); | ||||
|                 }, | ||||
|                 m_dc)) { | ||||
|             Log_ErrorPrint("Loading GLAD WGL functions failed"); | ||||
|             return false; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if (share_context && !wglShareLists(share_context, m_rc)) { | ||||
|         Log_ErrorPrintf("wglShareLists() failed: 0x%08X", GetLastError()); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool ContextWGL::CreateVersionContext(const Version& version, HGLRC share_context, | ||||
|                                       bool make_current) { | ||||
|     // we need create context attribs
 | ||||
|     if (!GLAD_WGL_ARB_create_context) { | ||||
|         Log_ErrorPrint("Missing GLAD_WGL_ARB_create_context."); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     HGLRC new_rc; | ||||
|     if (version.profile == Profile::Core) { | ||||
|         const int attribs[] = {WGL_CONTEXT_PROFILE_MASK_ARB, | ||||
|                                WGL_CONTEXT_CORE_PROFILE_BIT_ARB, | ||||
|                                WGL_CONTEXT_MAJOR_VERSION_ARB, | ||||
|                                version.major_version, | ||||
|                                WGL_CONTEXT_MINOR_VERSION_ARB, | ||||
|                                version.minor_version, | ||||
| #ifdef _DEBUG | ||||
|                            WGL_CONTEXT_FLAGS_ARB, | ||||
|                            WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB | WGL_CONTEXT_DEBUG_BIT_ARB, | ||||
|                                WGL_CONTEXT_FLAGS_ARB, | ||||
|                                WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB | WGL_CONTEXT_DEBUG_BIT_ARB, | ||||
| #else | ||||
|                            WGL_CONTEXT_FLAGS_ARB, | ||||
|                            WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, | ||||
|                                WGL_CONTEXT_FLAGS_ARB, | ||||
|                                WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, | ||||
| #endif | ||||
|                            0, | ||||
|                            0}; | ||||
|                                0, | ||||
|                                0}; | ||||
| 
 | ||||
|     new_rc = wglCreateContextAttribsARB(m_dc, share_context, attribs); | ||||
|   } | ||||
|   else if (version.profile == Profile::ES) | ||||
|   { | ||||
|     if ((version.major_version >= 2 && !GLAD_WGL_EXT_create_context_es2_profile) || | ||||
|         (version.major_version < 2 && !GLAD_WGL_EXT_create_context_es_profile)) | ||||
|     { | ||||
|       Log_ErrorPrint("WGL_EXT_create_context_es_profile not supported"); | ||||
|       return false; | ||||
|         new_rc = wglCreateContextAttribsARB(m_dc, share_context, attribs); | ||||
|     } else if (version.profile == Profile::ES) { | ||||
|         if ((version.major_version >= 2 && !GLAD_WGL_EXT_create_context_es2_profile) || | ||||
|             (version.major_version < 2 && !GLAD_WGL_EXT_create_context_es_profile)) { | ||||
|             Log_ErrorPrint("WGL_EXT_create_context_es_profile not supported"); | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         const int attribs[] = {WGL_CONTEXT_PROFILE_MASK_ARB, | ||||
|                                ((version.major_version >= 2) ? WGL_CONTEXT_ES2_PROFILE_BIT_EXT | ||||
|                                                              : WGL_CONTEXT_ES_PROFILE_BIT_EXT), | ||||
|                                WGL_CONTEXT_MAJOR_VERSION_ARB, | ||||
|                                version.major_version, | ||||
|                                WGL_CONTEXT_MINOR_VERSION_ARB, | ||||
|                                version.minor_version, | ||||
|                                0, | ||||
|                                0}; | ||||
| 
 | ||||
|         new_rc = wglCreateContextAttribsARB(m_dc, share_context, attribs); | ||||
|     } else { | ||||
|         Log_ErrorPrint("Unknown profile"); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     const int attribs[] = { | ||||
|       WGL_CONTEXT_PROFILE_MASK_ARB, | ||||
|       ((version.major_version >= 2) ? WGL_CONTEXT_ES2_PROFILE_BIT_EXT : WGL_CONTEXT_ES_PROFILE_BIT_EXT), | ||||
|       WGL_CONTEXT_MAJOR_VERSION_ARB, | ||||
|       version.major_version, | ||||
|       WGL_CONTEXT_MINOR_VERSION_ARB, | ||||
|       version.minor_version, | ||||
|       0, | ||||
|       0}; | ||||
|     if (!new_rc) | ||||
|         return false; | ||||
| 
 | ||||
|     new_rc = wglCreateContextAttribsARB(m_dc, share_context, attribs); | ||||
|   } | ||||
|   else | ||||
|   { | ||||
|     Log_ErrorPrint("Unknown profile"); | ||||
|     return false; | ||||
|   } | ||||
|     // destroy and swap contexts
 | ||||
|     if (m_rc) { | ||||
|         if (!wglMakeCurrent(m_dc, make_current ? new_rc : nullptr)) { | ||||
|             Log_ErrorPrintf("wglMakeCurrent() failed: 0x%08X", GetLastError()); | ||||
|             wglDeleteContext(new_rc); | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|   if (!new_rc) | ||||
|     return false; | ||||
|         // re-init glad-wgl
 | ||||
|         if (make_current && !gladLoadWGLLoader( | ||||
|                                 [](const char* name) -> void* { | ||||
|                                     return reinterpret_cast<void*>(wglGetProcAddress(name)); | ||||
|                                 }, | ||||
|                                 m_dc)) { | ||||
|             Log_ErrorPrint("Loading GLAD WGL functions failed"); | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|   // destroy and swap contexts
 | ||||
|   if (m_rc) | ||||
|   { | ||||
|     if (!wglMakeCurrent(m_dc, make_current ? new_rc : nullptr)) | ||||
|     { | ||||
|       Log_ErrorPrintf("wglMakeCurrent() failed: 0x%08X", GetLastError()); | ||||
|       wglDeleteContext(new_rc); | ||||
|       return false; | ||||
|         wglDeleteContext(m_rc); | ||||
|     } | ||||
| 
 | ||||
|     // re-init glad-wgl
 | ||||
|     if (make_current && !gladLoadWGLLoader([](const char* name) -> void* { return reinterpret_cast<void*>(wglGetProcAddress(name)); }, m_dc)) | ||||
|     { | ||||
|       Log_ErrorPrint("Loading GLAD WGL functions failed"); | ||||
|       return false; | ||||
|     } | ||||
| 
 | ||||
|     wglDeleteContext(m_rc); | ||||
|   } | ||||
| 
 | ||||
|   m_rc = new_rc; | ||||
|   return true; | ||||
|     m_rc = new_rc; | ||||
|     return true; | ||||
| } | ||||
| } // namespace GL
 | ||||
|  |  | |||
|  | @ -1,53 +1,54 @@ | |||
| #pragma once | ||||
| #include "../windows_headers.h" | ||||
| 
 | ||||
| #include "context.h" | ||||
| #include "../../../../../externals/glad/src/glad_wgl.h" | ||||
| #include "loader.h" | ||||
| #include <optional> | ||||
| #include "../../../../../externals/glad/src/glad_wgl.h" | ||||
| #include "context.h" | ||||
| #include "loader.h" | ||||
| 
 | ||||
| namespace GL { | ||||
| 
 | ||||
| class ContextWGL final : public Context | ||||
| { | ||||
| class ContextWGL final : public Context { | ||||
| public: | ||||
|   ContextWGL(const WindowInfo& wi); | ||||
|   ~ContextWGL() override; | ||||
|     ContextWGL(const WindowInfo& wi); | ||||
|     ~ContextWGL() override; | ||||
| 
 | ||||
|   static std::unique_ptr<Context> Create(const WindowInfo& wi, const Version* versions_to_try, | ||||
|                                          size_t num_versions_to_try); | ||||
|     static std::unique_ptr<Context> Create(const WindowInfo& wi, const Version* versions_to_try, | ||||
|                                            size_t num_versions_to_try); | ||||
| 
 | ||||
|   void* GetProcAddress(const char* name) override; | ||||
|   bool ChangeSurface(const WindowInfo& new_wi) override; | ||||
|   void ResizeSurface(u32 new_surface_width = 0, u32 new_surface_height = 0) override; | ||||
|   bool SwapBuffers() override; | ||||
|   bool MakeCurrent() override; | ||||
|   bool DoneCurrent() override; | ||||
|   bool SetSwapInterval(s32 interval) override; | ||||
|   std::unique_ptr<Context> CreateSharedContext(const WindowInfo& wi) override; | ||||
|     void* GetProcAddress(const char* name) override; | ||||
|     bool ChangeSurface(const WindowInfo& new_wi) override; | ||||
|     void ResizeSurface(u32 new_surface_width = 0, u32 new_surface_height = 0) override; | ||||
|     bool SwapBuffers() override; | ||||
|     bool MakeCurrent() override; | ||||
|     bool DoneCurrent() override; | ||||
|     bool SetSwapInterval(s32 interval) override; | ||||
|     std::unique_ptr<Context> CreateSharedContext(const WindowInfo& wi) override; | ||||
| 
 | ||||
| private: | ||||
|   ALWAYS_INLINE HWND GetHWND() const { return static_cast<HWND>(m_wi.window_handle); } | ||||
|     ALWAYS_INLINE HWND GetHWND() const { | ||||
|         return static_cast<HWND>(m_wi.window_handle); | ||||
|     } | ||||
| 
 | ||||
|   HDC GetDCAndSetPixelFormat(HWND hwnd); | ||||
|     HDC GetDCAndSetPixelFormat(HWND hwnd); | ||||
| 
 | ||||
|   bool Initialize(const Version* versions_to_try, size_t num_versions_to_try); | ||||
|   bool InitializeDC(); | ||||
|   void ReleaseDC(); | ||||
|   bool CreatePBuffer(); | ||||
|   bool CreateAnyContext(HGLRC share_context, bool make_current); | ||||
|   bool CreateVersionContext(const Version& version, HGLRC share_context, bool make_current); | ||||
|     bool Initialize(const Version* versions_to_try, size_t num_versions_to_try); | ||||
|     bool InitializeDC(); | ||||
|     void ReleaseDC(); | ||||
|     bool CreatePBuffer(); | ||||
|     bool CreateAnyContext(HGLRC share_context, bool make_current); | ||||
|     bool CreateVersionContext(const Version& version, HGLRC share_context, bool make_current); | ||||
| 
 | ||||
|   HDC m_dc = {}; | ||||
|   HGLRC m_rc = {}; | ||||
|     HDC m_dc = {}; | ||||
|     HGLRC m_rc = {}; | ||||
| 
 | ||||
|   // Can't change pixel format once it's set for a RC.
 | ||||
|   std::optional<int> m_pixel_format; | ||||
|     // Can't change pixel format once it's set for a RC.
 | ||||
|     std::optional<int> m_pixel_format; | ||||
| 
 | ||||
|   // Dummy window for creating a PBuffer off when we're surfaceless.
 | ||||
|   HWND m_dummy_window = {}; | ||||
|   HDC m_dummy_dc = {}; | ||||
|   HPBUFFERARB m_pbuffer = {}; | ||||
|     // Dummy window for creating a PBuffer off when we're surfaceless.
 | ||||
|     HWND m_dummy_window = {}; | ||||
|     HDC m_dummy_dc = {}; | ||||
|     HPBUFFERARB m_pbuffer = {}; | ||||
| }; | ||||
| 
 | ||||
| } // namespace GL
 | ||||
|  |  | |||
							
								
								
									
										140
									
								
								src/citra_qt/externals/duckstation/gl/x11_window.cpp
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										140
									
								
								src/citra_qt/externals/duckstation/gl/x11_window.cpp
									
										
									
									
										vendored
									
									
								
							|  | @ -1,101 +1,89 @@ | |||
| #include "x11_window.h" | ||||
| #include "../log.h" | ||||
| #include "../duckstation_compat.h" | ||||
| #include <cstdio> | ||||
| #include "../duckstation_compat.h" | ||||
| #include "../log.h" | ||||
| #include "x11_window.h" | ||||
| Log_SetChannel(X11Window); | ||||
| 
 | ||||
| namespace GL { | ||||
| X11Window::X11Window() = default; | ||||
| 
 | ||||
| X11Window::~X11Window() | ||||
| { | ||||
|   Destroy(); | ||||
| X11Window::~X11Window() { | ||||
|     Destroy(); | ||||
| } | ||||
| 
 | ||||
| bool X11Window::Create(Display* display, Window parent_window, const XVisualInfo* vi) | ||||
| { | ||||
|   m_display = display; | ||||
|   m_parent_window = parent_window; | ||||
|   XSync(m_display, True); | ||||
| bool X11Window::Create(Display* display, Window parent_window, const XVisualInfo* vi) { | ||||
|     m_display = display; | ||||
|     m_parent_window = parent_window; | ||||
|     XSync(m_display, True); | ||||
| 
 | ||||
|   XWindowAttributes parent_wa = {}; | ||||
|   XGetWindowAttributes(m_display, m_parent_window, &parent_wa); | ||||
|   m_width = static_cast<u32>(parent_wa.width); | ||||
|   m_height = static_cast<u32>(parent_wa.height); | ||||
| 
 | ||||
|   // Failed X calls terminate the process so no need to check for errors.
 | ||||
|   // We could swap the error handler out here as well.
 | ||||
|   m_colormap = XCreateColormap(m_display, m_parent_window, vi->visual, AllocNone); | ||||
| 
 | ||||
|   XSetWindowAttributes wa = {}; | ||||
|   wa.colormap = m_colormap; | ||||
| 
 | ||||
|   m_window = XCreateWindow(m_display, m_parent_window, 0, 0, m_width, m_height, 0, vi->depth, InputOutput, vi->visual, | ||||
|                            CWColormap, &wa); | ||||
|   XMapWindow(m_display, m_window); | ||||
|   XSync(m_display, True); | ||||
| 
 | ||||
|   return true; | ||||
| } | ||||
| 
 | ||||
| void X11Window::Destroy() | ||||
| { | ||||
|   if (m_window) | ||||
|   { | ||||
|     XUnmapWindow(m_display, m_window); | ||||
|     XDestroyWindow(m_display, m_window); | ||||
|     m_window = {}; | ||||
|   } | ||||
| 
 | ||||
|   if (m_colormap) | ||||
|   { | ||||
|     XFreeColormap(m_display, m_colormap); | ||||
|     m_colormap = {}; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void X11Window::Resize(u32 width, u32 height) | ||||
| { | ||||
|   if (width != 0 && height != 0) | ||||
|   { | ||||
|     m_width = width; | ||||
|     m_height = height; | ||||
|   } | ||||
|   else | ||||
|   { | ||||
|     XWindowAttributes parent_wa = {}; | ||||
|     XGetWindowAttributes(m_display, m_parent_window, &parent_wa); | ||||
|     m_width = static_cast<u32>(parent_wa.width); | ||||
|     m_height = static_cast<u32>(parent_wa.height); | ||||
|   } | ||||
| 
 | ||||
|   XResizeWindow(m_display, m_window, m_width, m_height); | ||||
|     // Failed X calls terminate the process so no need to check for errors.
 | ||||
|     // We could swap the error handler out here as well.
 | ||||
|     m_colormap = XCreateColormap(m_display, m_parent_window, vi->visual, AllocNone); | ||||
| 
 | ||||
|     XSetWindowAttributes wa = {}; | ||||
|     wa.colormap = m_colormap; | ||||
| 
 | ||||
|     m_window = XCreateWindow(m_display, m_parent_window, 0, 0, m_width, m_height, 0, vi->depth, | ||||
|                              InputOutput, vi->visual, CWColormap, &wa); | ||||
|     XMapWindow(m_display, m_window); | ||||
|     XSync(m_display, True); | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| void X11Window::Destroy() { | ||||
|     if (m_window) { | ||||
|         XUnmapWindow(m_display, m_window); | ||||
|         XDestroyWindow(m_display, m_window); | ||||
|         m_window = {}; | ||||
|     } | ||||
| 
 | ||||
|     if (m_colormap) { | ||||
|         XFreeColormap(m_display, m_colormap); | ||||
|         m_colormap = {}; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void X11Window::Resize(u32 width, u32 height) { | ||||
|     if (width != 0 && height != 0) { | ||||
|         m_width = width; | ||||
|         m_height = height; | ||||
|     } else { | ||||
|         XWindowAttributes parent_wa = {}; | ||||
|         XGetWindowAttributes(m_display, m_parent_window, &parent_wa); | ||||
|         m_width = static_cast<u32>(parent_wa.width); | ||||
|         m_height = static_cast<u32>(parent_wa.height); | ||||
|     } | ||||
| 
 | ||||
|     XResizeWindow(m_display, m_window, m_width, m_height); | ||||
| } | ||||
| 
 | ||||
| static X11InhibitErrors* s_current_error_inhibiter; | ||||
| 
 | ||||
| X11InhibitErrors::X11InhibitErrors() | ||||
| { | ||||
|   Assert(!s_current_error_inhibiter); | ||||
|   m_old_handler = XSetErrorHandler(ErrorHandler); | ||||
|   s_current_error_inhibiter = this; | ||||
| X11InhibitErrors::X11InhibitErrors() { | ||||
|     Assert(!s_current_error_inhibiter); | ||||
|     m_old_handler = XSetErrorHandler(ErrorHandler); | ||||
|     s_current_error_inhibiter = this; | ||||
| } | ||||
| 
 | ||||
| X11InhibitErrors::~X11InhibitErrors() | ||||
| { | ||||
|   Assert(s_current_error_inhibiter == this); | ||||
|   s_current_error_inhibiter = nullptr; | ||||
|   XSetErrorHandler(m_old_handler); | ||||
| X11InhibitErrors::~X11InhibitErrors() { | ||||
|     Assert(s_current_error_inhibiter == this); | ||||
|     s_current_error_inhibiter = nullptr; | ||||
|     XSetErrorHandler(m_old_handler); | ||||
| } | ||||
| 
 | ||||
| int X11InhibitErrors::ErrorHandler(Display* display, XErrorEvent* ee) | ||||
| { | ||||
|   char error_string[256] = {}; | ||||
|   XGetErrorText(display, ee->error_code, error_string, sizeof(error_string)); | ||||
|   Log_WarningPrintf("X11 Error: %s (Error %u Minor %u Request %u)", error_string, ee->error_code, ee->minor_code, | ||||
|                     ee->request_code); | ||||
| int X11InhibitErrors::ErrorHandler(Display* display, XErrorEvent* ee) { | ||||
|     char error_string[256] = {}; | ||||
|     XGetErrorText(display, ee->error_code, error_string, sizeof(error_string)); | ||||
|     Log_WarningPrintf("X11 Error: %s (Error %u Minor %u Request %u)", error_string, ee->error_code, | ||||
|                       ee->minor_code, ee->request_code); | ||||
| 
 | ||||
|   s_current_error_inhibiter->m_had_error = true; | ||||
|   return 0; | ||||
|     s_current_error_inhibiter->m_had_error = true; | ||||
|     return 0; | ||||
| } | ||||
| } // namespace GL
 | ||||
|  |  | |||
|  | @ -1,49 +1,55 @@ | |||
| #pragma once | ||||
| #include "../duckstation_compat.h" | ||||
| #include <X11/Xlib.h> | ||||
| #include <X11/Xutil.h> | ||||
| #include "../duckstation_compat.h" | ||||
| 
 | ||||
| namespace GL { | ||||
| using namespace citra; | ||||
| class X11Window | ||||
| { | ||||
| class X11Window { | ||||
| public: | ||||
|   X11Window(); | ||||
|   ~X11Window(); | ||||
|     X11Window(); | ||||
|     ~X11Window(); | ||||
| 
 | ||||
|   ALWAYS_INLINE Window GetWindow() const { return m_window; } | ||||
|   ALWAYS_INLINE u32 GetWidth() const { return m_width; } | ||||
|   ALWAYS_INLINE u32 GetHeight() const { return m_height; } | ||||
|     ALWAYS_INLINE Window GetWindow() const { | ||||
|         return m_window; | ||||
|     } | ||||
|     ALWAYS_INLINE u32 GetWidth() const { | ||||
|         return m_width; | ||||
|     } | ||||
|     ALWAYS_INLINE u32 GetHeight() const { | ||||
|         return m_height; | ||||
|     } | ||||
| 
 | ||||
|   bool Create(Display* display, Window parent_window, const XVisualInfo* vi); | ||||
|   void Destroy(); | ||||
|     bool Create(Display* display, Window parent_window, const XVisualInfo* vi); | ||||
|     void Destroy(); | ||||
| 
 | ||||
|   // Setting a width/height of 0 will use parent dimensions.
 | ||||
|   void Resize(u32 width = 0, u32 height = 0); | ||||
|     // Setting a width/height of 0 will use parent dimensions.
 | ||||
|     void Resize(u32 width = 0, u32 height = 0); | ||||
| 
 | ||||
| private: | ||||
|   Display* m_display = nullptr; | ||||
|   Window m_parent_window = {}; | ||||
|   Window m_window = {}; | ||||
|   Colormap m_colormap = {}; | ||||
|   u32 m_width = 0; | ||||
|   u32 m_height = 0; | ||||
|     Display* m_display = nullptr; | ||||
|     Window m_parent_window = {}; | ||||
|     Window m_window = {}; | ||||
|     Colormap m_colormap = {}; | ||||
|     u32 m_width = 0; | ||||
|     u32 m_height = 0; | ||||
| }; | ||||
| 
 | ||||
| // Helper class for managing X errors
 | ||||
| class X11InhibitErrors | ||||
| { | ||||
| class X11InhibitErrors { | ||||
| public: | ||||
|   X11InhibitErrors(); | ||||
|   ~X11InhibitErrors(); | ||||
|     X11InhibitErrors(); | ||||
|     ~X11InhibitErrors(); | ||||
| 
 | ||||
|   ALWAYS_INLINE bool HadError() const { return m_had_error; } | ||||
|     ALWAYS_INLINE bool HadError() const { | ||||
|         return m_had_error; | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|   static int ErrorHandler(Display* display, XErrorEvent* ee); | ||||
|     static int ErrorHandler(Display* display, XErrorEvent* ee); | ||||
| 
 | ||||
|   XErrorHandler m_old_handler = {}; | ||||
|   bool m_had_error = false; | ||||
|     XErrorHandler m_old_handler = {}; | ||||
|     bool m_had_error = false; | ||||
| }; | ||||
| 
 | ||||
| } // namespace GL
 | ||||
|  |  | |||
							
								
								
									
										82
									
								
								src/citra_qt/externals/duckstation/log.h
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										82
									
								
								src/citra_qt/externals/duckstation/log.h
									
										
									
									
										vendored
									
									
								
							|  | @ -5,42 +5,74 @@ | |||
| 
 | ||||
| #define Log_SetChannel(ChannelName) | ||||
| #define Log_ErrorPrint(msg) puts(msg "\n"); | ||||
| #define Log_ErrorPrintf(...) do { printf(__VA_ARGS__); putchar('\n'); } while (0) | ||||
| #define Log_ErrorPrintf(...)                                                                       \ | ||||
|     do {                                                                                           \ | ||||
|         printf(__VA_ARGS__);                                                                       \ | ||||
|         putchar('\n');                                                                             \ | ||||
|     } while (0) | ||||
| #define Log_WarningPrint(msg) puts(msg) | ||||
| #define Log_WarningPrintf(...) do { printf(__VA_ARGS__); putchar('\n'); } while (0) | ||||
| #define Log_WarningPrintf(...)                                                                     \ | ||||
|     do {                                                                                           \ | ||||
|         printf(__VA_ARGS__);                                                                       \ | ||||
|         putchar('\n');                                                                             \ | ||||
|     } while (0) | ||||
| #define Log_PerfPrint(msg) puts(msg) | ||||
| #define Log_PerfPrintf(...) do { printf(__VA_ARGS__); putchar('\n'); } while (0) | ||||
| #define Log_PerfPrintf(...)                                                                        \ | ||||
|     do {                                                                                           \ | ||||
|         printf(__VA_ARGS__);                                                                       \ | ||||
|         putchar('\n');                                                                             \ | ||||
|     } while (0) | ||||
| #define Log_InfoPrint(msg) puts(msg) | ||||
| #define Log_InfoPrintf(...) do { printf(__VA_ARGS__); putchar('\n'); } while (0) | ||||
| #define Log_InfoPrintf(...)                                                                        \ | ||||
|     do {                                                                                           \ | ||||
|         printf(__VA_ARGS__);                                                                       \ | ||||
|         putchar('\n');                                                                             \ | ||||
|     } while (0) | ||||
| #define Log_VerbosePrint(msg) puts(msg) | ||||
| #define Log_VerbosePrintf(...) do { printf(__VA_ARGS__); putchar('\n'); } while (0) | ||||
| #define Log_VerbosePrintf(...)                                                                     \ | ||||
|     do {                                                                                           \ | ||||
|         printf(__VA_ARGS__);                                                                       \ | ||||
|         putchar('\n');                                                                             \ | ||||
|     } while (0) | ||||
| #define Log_DevPrint(msg) puts(msg) | ||||
| #define Log_DevPrintf(...) do { printf(__VA_ARGS__); putchar('\n'); } while (0) | ||||
| #define Log_DevPrintf(...)                                                                         \ | ||||
|     do {                                                                                           \ | ||||
|         printf(__VA_ARGS__);                                                                       \ | ||||
|         putchar('\n');                                                                             \ | ||||
|     } while (0) | ||||
| #define Log_ProfilePrint(msg) puts(msg) | ||||
| #define Log_ProfilePrintf(...) do { printf(__VA_ARGS__); putchar('\n'); } while (0) | ||||
| #define Log_ProfilePrintf(...)                                                                     \ | ||||
|     do {                                                                                           \ | ||||
|         printf(__VA_ARGS__);                                                                       \ | ||||
|         putchar('\n');                                                                             \ | ||||
|     } while (0) | ||||
| 
 | ||||
| #ifdef _DEBUG | ||||
| #define Log_DebugPrint(msg) puts(msg) | ||||
| #define Log_DebugPrintf(...) do { printf(__VA_ARGS__); putchar('\n'); } while (0) | ||||
| #define Log_DebugPrintf(...)                                                                       \ | ||||
|     do {                                                                                           \ | ||||
|         printf(__VA_ARGS__);                                                                       \ | ||||
|         putchar('\n');                                                                             \ | ||||
|     } while (0) | ||||
| #define Log_TracePrint(msg) puts(msg) | ||||
| #define Log_TracePrintf(...) do { printf(__VA_ARGS__); putchar('\n'); } while (0) | ||||
| #define Log_TracePrintf(...)                                                                       \ | ||||
|     do {                                                                                           \ | ||||
|         printf(__VA_ARGS__);                                                                       \ | ||||
|         putchar('\n');                                                                             \ | ||||
|     } while (0) | ||||
| #else | ||||
| #define Log_DebugPrint(msg)                                                                                            \ | ||||
|   do                                                                                                                   \ | ||||
|   {                                                                                                                    \ | ||||
|   } while (0) | ||||
| #define Log_DebugPrintf(...)                                                                                           \ | ||||
|   do                                                                                                                   \ | ||||
|   {                                                                                                                    \ | ||||
|   } while (0) | ||||
| #define Log_TracePrint(msg)                                                                                            \ | ||||
|   do                                                                                                                   \ | ||||
|   {                                                                                                                    \ | ||||
|   } while (0) | ||||
| #define Log_TracePrintf(...)                                                                                           \ | ||||
|   do                                                                                                                   \ | ||||
|   {                                                                                                                    \ | ||||
|   } while (0) | ||||
| #define Log_DebugPrint(msg)                                                                        \ | ||||
|     do {                                                                                           \ | ||||
|     } while (0) | ||||
| #define Log_DebugPrintf(...)                                                                       \ | ||||
|     do {                                                                                           \ | ||||
|     } while (0) | ||||
| #define Log_TracePrint(msg)                                                                        \ | ||||
|     do {                                                                                           \ | ||||
|     } while (0) | ||||
| #define Log_TracePrintf(...)                                                                       \ | ||||
|     do {                                                                                           \ | ||||
|     } while (0) | ||||
| #endif | ||||
| 
 | ||||
| #endif | ||||
|  | @ -5,30 +5,34 @@ | |||
| /// ScopedGuard provides an object which runs a function (usually a lambda) when
 | ||||
| /// it goes out of scope. This can be useful for releasing resources or handles
 | ||||
| /// which do not normally have C++ types to automatically release.
 | ||||
| template<typename T> | ||||
| class ScopedGuard final | ||||
| { | ||||
| template <typename T> | ||||
| class ScopedGuard final { | ||||
| public: | ||||
|   ALWAYS_INLINE ScopedGuard(T&& func) : m_func(std::forward<T>(func)) {} | ||||
|   ALWAYS_INLINE ScopedGuard(ScopedGuard&& other) : m_func(std::move(other.m_func)) { other.m_func = nullptr; } | ||||
|   ALWAYS_INLINE ~ScopedGuard() { Invoke(); } | ||||
|     ALWAYS_INLINE ScopedGuard(T&& func) : m_func(std::forward<T>(func)) {} | ||||
|     ALWAYS_INLINE ScopedGuard(ScopedGuard&& other) : m_func(std::move(other.m_func)) { | ||||
|         other.m_func = nullptr; | ||||
|     } | ||||
|     ALWAYS_INLINE ~ScopedGuard() { | ||||
|         Invoke(); | ||||
|     } | ||||
| 
 | ||||
|   ScopedGuard(const ScopedGuard&) = delete; | ||||
|   void operator=(const ScopedGuard&) = delete; | ||||
|     ScopedGuard(const ScopedGuard&) = delete; | ||||
|     void operator=(const ScopedGuard&) = delete; | ||||
| 
 | ||||
|   /// Prevents the function from being invoked when we go out of scope.
 | ||||
|   ALWAYS_INLINE void Cancel() { m_func.reset(); } | ||||
|     /// Prevents the function from being invoked when we go out of scope.
 | ||||
|     ALWAYS_INLINE void Cancel() { | ||||
|         m_func.reset(); | ||||
|     } | ||||
| 
 | ||||
|   /// Explicitly fires the function.
 | ||||
|   ALWAYS_INLINE void Invoke() | ||||
|   { | ||||
|     if (!m_func.has_value()) | ||||
|       return; | ||||
|     /// Explicitly fires the function.
 | ||||
|     ALWAYS_INLINE void Invoke() { | ||||
|         if (!m_func.has_value()) | ||||
|             return; | ||||
| 
 | ||||
|     m_func.value()(); | ||||
|     m_func.reset(); | ||||
|   } | ||||
|         m_func.value()(); | ||||
|         m_func.reset(); | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|   std::optional<T> m_func; | ||||
|     std::optional<T> m_func; | ||||
| }; | ||||
|  |  | |||
							
								
								
									
										280
									
								
								src/citra_qt/externals/duckstation/window_info.cpp
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										280
									
								
								src/citra_qt/externals/duckstation/window_info.cpp
									
										
									
									
										vendored
									
									
								
							|  | @ -1,191 +1,175 @@ | |||
| #include "window_info.h" | ||||
| #include "common/log.h" | ||||
| #include "window_info.h" | ||||
| Log_SetChannel(WindowInfo); | ||||
| 
 | ||||
| #if defined(_WIN32) | ||||
| 
 | ||||
| #include "common/windows_headers.h" | ||||
| #include <dwmapi.h> | ||||
| #include "common/windows_headers.h" | ||||
| 
 | ||||
| static bool GetRefreshRateFromDWM(HWND hwnd, float* refresh_rate) | ||||
| { | ||||
|   static HMODULE dwm_module = nullptr; | ||||
|   static HRESULT(STDAPICALLTYPE * is_composition_enabled)(BOOL * pfEnabled) = nullptr; | ||||
|   static HRESULT(STDAPICALLTYPE * get_timing_info)(HWND hwnd, DWM_TIMING_INFO * pTimingInfo) = nullptr; | ||||
|   static bool load_tried = false; | ||||
|   if (!load_tried) | ||||
|   { | ||||
|     load_tried = true; | ||||
|     dwm_module = LoadLibrary("dwmapi.dll"); | ||||
|     if (dwm_module) | ||||
|     { | ||||
|       std::atexit([]() { | ||||
|         FreeLibrary(dwm_module); | ||||
|         dwm_module = nullptr; | ||||
|       }); | ||||
|       is_composition_enabled = | ||||
|         reinterpret_cast<decltype(is_composition_enabled)>(GetProcAddress(dwm_module, "DwmIsCompositionEnabled")); | ||||
|       get_timing_info = | ||||
|         reinterpret_cast<decltype(get_timing_info)>(GetProcAddress(dwm_module, "DwmGetCompositionTimingInfo")); | ||||
| static bool GetRefreshRateFromDWM(HWND hwnd, float* refresh_rate) { | ||||
|     static HMODULE dwm_module = nullptr; | ||||
|     static HRESULT(STDAPICALLTYPE * is_composition_enabled)(BOOL * pfEnabled) = nullptr; | ||||
|     static HRESULT(STDAPICALLTYPE * get_timing_info)(HWND hwnd, DWM_TIMING_INFO * pTimingInfo) = | ||||
|         nullptr; | ||||
|     static bool load_tried = false; | ||||
|     if (!load_tried) { | ||||
|         load_tried = true; | ||||
|         dwm_module = LoadLibrary("dwmapi.dll"); | ||||
|         if (dwm_module) { | ||||
|             std::atexit([]() { | ||||
|                 FreeLibrary(dwm_module); | ||||
|                 dwm_module = nullptr; | ||||
|             }); | ||||
|             is_composition_enabled = reinterpret_cast<decltype(is_composition_enabled)>( | ||||
|                 GetProcAddress(dwm_module, "DwmIsCompositionEnabled")); | ||||
|             get_timing_info = reinterpret_cast<decltype(get_timing_info)>( | ||||
|                 GetProcAddress(dwm_module, "DwmGetCompositionTimingInfo")); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     BOOL composition_enabled; | ||||
|     if (!is_composition_enabled || | ||||
|         FAILED(is_composition_enabled(&composition_enabled) || !get_timing_info)) | ||||
|         return false; | ||||
| 
 | ||||
|     DWM_TIMING_INFO ti = {}; | ||||
|     ti.cbSize = sizeof(ti); | ||||
|     HRESULT hr = get_timing_info(nullptr, &ti); | ||||
|     if (SUCCEEDED(hr)) { | ||||
|         if (ti.rateRefresh.uiNumerator == 0 || ti.rateRefresh.uiDenominator == 0) | ||||
|             return false; | ||||
| 
 | ||||
|         *refresh_rate = static_cast<float>(ti.rateRefresh.uiNumerator) / | ||||
|                         static_cast<float>(ti.rateRefresh.uiDenominator); | ||||
|         return true; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   BOOL composition_enabled; | ||||
|   if (!is_composition_enabled || FAILED(is_composition_enabled(&composition_enabled) || !get_timing_info)) | ||||
|     return false; | ||||
| 
 | ||||
|   DWM_TIMING_INFO ti = {}; | ||||
|   ti.cbSize = sizeof(ti); | ||||
|   HRESULT hr = get_timing_info(nullptr, &ti); | ||||
|   if (SUCCEEDED(hr)) | ||||
|   { | ||||
|     if (ti.rateRefresh.uiNumerator == 0 || ti.rateRefresh.uiDenominator == 0) | ||||
|       return false; | ||||
| 
 | ||||
|     *refresh_rate = static_cast<float>(ti.rateRefresh.uiNumerator) / static_cast<float>(ti.rateRefresh.uiDenominator); | ||||
|     return true; | ||||
|   } | ||||
| 
 | ||||
|   return false; | ||||
| } | ||||
| 
 | ||||
| static bool GetRefreshRateFromMonitor(HWND hwnd, float* refresh_rate) | ||||
| { | ||||
|   HMONITOR mon = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST); | ||||
|   if (!mon) | ||||
|     return false; | ||||
| static bool GetRefreshRateFromMonitor(HWND hwnd, float* refresh_rate) { | ||||
|     HMONITOR mon = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST); | ||||
|     if (!mon) | ||||
|         return false; | ||||
| 
 | ||||
|   MONITORINFOEXW mi = {}; | ||||
|   mi.cbSize = sizeof(mi); | ||||
|   if (GetMonitorInfoW(mon, &mi)) | ||||
|   { | ||||
|     DEVMODEW dm = {}; | ||||
|     dm.dmSize = sizeof(dm); | ||||
|     MONITORINFOEXW mi = {}; | ||||
|     mi.cbSize = sizeof(mi); | ||||
|     if (GetMonitorInfoW(mon, &mi)) { | ||||
|         DEVMODEW dm = {}; | ||||
|         dm.dmSize = sizeof(dm); | ||||
| 
 | ||||
|     // 0/1 are reserved for "defaults".
 | ||||
|     if (EnumDisplaySettingsW(mi.szDevice, ENUM_CURRENT_SETTINGS, &dm) && dm.dmDisplayFrequency > 1) | ||||
|     { | ||||
|       *refresh_rate = static_cast<float>(dm.dmDisplayFrequency); | ||||
|       return true; | ||||
|         // 0/1 are reserved for "defaults".
 | ||||
|         if (EnumDisplaySettingsW(mi.szDevice, ENUM_CURRENT_SETTINGS, &dm) && | ||||
|             dm.dmDisplayFrequency > 1) { | ||||
|             *refresh_rate = static_cast<float>(dm.dmDisplayFrequency); | ||||
|             return true; | ||||
|         } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   return false; | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| bool WindowInfo::QueryRefreshRateForWindow(const WindowInfo& wi, float* refresh_rate) | ||||
| { | ||||
|   if (wi.type != Type::Win32 || !wi.window_handle) | ||||
|     return false; | ||||
| bool WindowInfo::QueryRefreshRateForWindow(const WindowInfo& wi, float* refresh_rate) { | ||||
|     if (wi.type != Type::Win32 || !wi.window_handle) | ||||
|         return false; | ||||
| 
 | ||||
|   // Try DWM first, then fall back to integer values.
 | ||||
|   const HWND hwnd = static_cast<HWND>(wi.window_handle); | ||||
|   return GetRefreshRateFromDWM(hwnd, refresh_rate) || GetRefreshRateFromMonitor(hwnd, refresh_rate); | ||||
|     // Try DWM first, then fall back to integer values.
 | ||||
|     const HWND hwnd = static_cast<HWND>(wi.window_handle); | ||||
|     return GetRefreshRateFromDWM(hwnd, refresh_rate) || | ||||
|            GetRefreshRateFromMonitor(hwnd, refresh_rate); | ||||
| } | ||||
| 
 | ||||
| #else | ||||
| 
 | ||||
| #ifdef USE_X11 | ||||
| 
 | ||||
| #include <X11/extensions/Xrandr.h> | ||||
| #include "common/scoped_guard.h" | ||||
| #include "gl/x11_window.h" | ||||
| #include <X11/extensions/Xrandr.h> | ||||
| 
 | ||||
| static bool GetRefreshRateFromXRandR(const WindowInfo& wi, float* refresh_rate) | ||||
| { | ||||
|   Display* display = static_cast<Display*>(wi.display_connection); | ||||
|   Window window = static_cast<Window>(reinterpret_cast<uintptr_t>(wi.window_handle)); | ||||
|   if (!display || !window) | ||||
|     return false; | ||||
| static bool GetRefreshRateFromXRandR(const WindowInfo& wi, float* refresh_rate) { | ||||
|     Display* display = static_cast<Display*>(wi.display_connection); | ||||
|     Window window = static_cast<Window>(reinterpret_cast<uintptr_t>(wi.window_handle)); | ||||
|     if (!display || !window) | ||||
|         return false; | ||||
| 
 | ||||
|   GL::X11InhibitErrors inhibiter; | ||||
|     GL::X11InhibitErrors inhibiter; | ||||
| 
 | ||||
|   XRRScreenResources* res = XRRGetScreenResources(display, window); | ||||
|   if (!res) | ||||
|   { | ||||
|     Log_ErrorPrint("XRRGetScreenResources() failed"); | ||||
|     return false; | ||||
|   } | ||||
| 
 | ||||
|   ScopedGuard res_guard([res]() { XRRFreeScreenResources(res); }); | ||||
| 
 | ||||
|   int num_monitors; | ||||
|   XRRMonitorInfo* mi = XRRGetMonitors(display, window, True, &num_monitors); | ||||
|   if (num_monitors < 0) | ||||
|   { | ||||
|     Log_ErrorPrint("XRRGetMonitors() failed"); | ||||
|     return false; | ||||
|   } | ||||
|   else if (num_monitors > 1) | ||||
|   { | ||||
|     Log_WarningPrintf("XRRGetMonitors() returned %d monitors, using first", num_monitors); | ||||
|   } | ||||
| 
 | ||||
|   ScopedGuard mi_guard([mi]() { XRRFreeMonitors(mi); }); | ||||
|   if (mi->noutput <= 0) | ||||
|   { | ||||
|     Log_ErrorPrint("Monitor has no outputs"); | ||||
|     return false; | ||||
|   } | ||||
|   else if (mi->noutput > 1) | ||||
|   { | ||||
|     Log_WarningPrintf("Monitor has %d outputs, using first", mi->noutput); | ||||
|   } | ||||
| 
 | ||||
|   XRROutputInfo* oi = XRRGetOutputInfo(display, res, mi->outputs[0]); | ||||
|   if (!oi) | ||||
|   { | ||||
|     Log_ErrorPrint("XRRGetOutputInfo() failed"); | ||||
|     return false; | ||||
|   } | ||||
| 
 | ||||
|   ScopedGuard oi_guard([oi]() { XRRFreeOutputInfo(oi); }); | ||||
| 
 | ||||
|   XRRCrtcInfo* ci = XRRGetCrtcInfo(display, res, oi->crtc); | ||||
|   if (!ci) | ||||
|   { | ||||
|     Log_ErrorPrint("XRRGetCrtcInfo() failed"); | ||||
|     return false; | ||||
|   } | ||||
| 
 | ||||
|   ScopedGuard ci_guard([ci]() { XRRFreeCrtcInfo(ci); }); | ||||
| 
 | ||||
|   XRRModeInfo* mode = nullptr; | ||||
|   for (int i = 0; i < res->nmode; i++) | ||||
|   { | ||||
|     if (res->modes[i].id == ci->mode) | ||||
|     { | ||||
|       mode = &res->modes[i]; | ||||
|       break; | ||||
|     XRRScreenResources* res = XRRGetScreenResources(display, window); | ||||
|     if (!res) { | ||||
|         Log_ErrorPrint("XRRGetScreenResources() failed"); | ||||
|         return false; | ||||
|     } | ||||
|   } | ||||
|   if (!mode) | ||||
|   { | ||||
|     Log_ErrorPrintf("Failed to look up mode %d (of %d)", static_cast<int>(ci->mode), res->nmode); | ||||
|     return false; | ||||
|   } | ||||
| 
 | ||||
|   if (mode->dotClock == 0 || mode->hTotal == 0 || mode->vTotal == 0) | ||||
|   { | ||||
|     Log_ErrorPrintf("Modeline is invalid: %ld/%d/%d", mode->dotClock, mode->hTotal, mode->vTotal); | ||||
|     return false; | ||||
|   } | ||||
|     ScopedGuard res_guard([res]() { XRRFreeScreenResources(res); }); | ||||
| 
 | ||||
|   *refresh_rate = | ||||
|     static_cast<double>(mode->dotClock) / (static_cast<double>(mode->hTotal) * static_cast<double>(mode->vTotal)); | ||||
|   return true; | ||||
|     int num_monitors; | ||||
|     XRRMonitorInfo* mi = XRRGetMonitors(display, window, True, &num_monitors); | ||||
|     if (num_monitors < 0) { | ||||
|         Log_ErrorPrint("XRRGetMonitors() failed"); | ||||
|         return false; | ||||
|     } else if (num_monitors > 1) { | ||||
|         Log_WarningPrintf("XRRGetMonitors() returned %d monitors, using first", num_monitors); | ||||
|     } | ||||
| 
 | ||||
|     ScopedGuard mi_guard([mi]() { XRRFreeMonitors(mi); }); | ||||
|     if (mi->noutput <= 0) { | ||||
|         Log_ErrorPrint("Monitor has no outputs"); | ||||
|         return false; | ||||
|     } else if (mi->noutput > 1) { | ||||
|         Log_WarningPrintf("Monitor has %d outputs, using first", mi->noutput); | ||||
|     } | ||||
| 
 | ||||
|     XRROutputInfo* oi = XRRGetOutputInfo(display, res, mi->outputs[0]); | ||||
|     if (!oi) { | ||||
|         Log_ErrorPrint("XRRGetOutputInfo() failed"); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     ScopedGuard oi_guard([oi]() { XRRFreeOutputInfo(oi); }); | ||||
| 
 | ||||
|     XRRCrtcInfo* ci = XRRGetCrtcInfo(display, res, oi->crtc); | ||||
|     if (!ci) { | ||||
|         Log_ErrorPrint("XRRGetCrtcInfo() failed"); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     ScopedGuard ci_guard([ci]() { XRRFreeCrtcInfo(ci); }); | ||||
| 
 | ||||
|     XRRModeInfo* mode = nullptr; | ||||
|     for (int i = 0; i < res->nmode; i++) { | ||||
|         if (res->modes[i].id == ci->mode) { | ||||
|             mode = &res->modes[i]; | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
|     if (!mode) { | ||||
|         Log_ErrorPrintf("Failed to look up mode %d (of %d)", static_cast<int>(ci->mode), | ||||
|                         res->nmode); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     if (mode->dotClock == 0 || mode->hTotal == 0 || mode->vTotal == 0) { | ||||
|         Log_ErrorPrintf("Modeline is invalid: %ld/%d/%d", mode->dotClock, mode->hTotal, | ||||
|                         mode->vTotal); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     *refresh_rate = static_cast<double>(mode->dotClock) / | ||||
|                     (static_cast<double>(mode->hTotal) * static_cast<double>(mode->vTotal)); | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| #endif // USE_X11
 | ||||
| 
 | ||||
| bool WindowInfo::QueryRefreshRateForWindow(const WindowInfo& wi, float* refresh_rate) | ||||
| { | ||||
| bool WindowInfo::QueryRefreshRateForWindow(const WindowInfo& wi, float* refresh_rate) { | ||||
| #if defined(USE_X11) | ||||
|   if (wi.type == WindowInfo::Type::X11) | ||||
|     return GetRefreshRateFromXRandR(wi, refresh_rate); | ||||
|     if (wi.type == WindowInfo::Type::X11) | ||||
|         return GetRefreshRateFromXRandR(wi, refresh_rate); | ||||
| #endif | ||||
| 
 | ||||
|   return false; | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
							
								
								
									
										54
									
								
								src/citra_qt/externals/duckstation/window_info.h
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										54
									
								
								src/citra_qt/externals/duckstation/window_info.h
									
										
									
									
										vendored
									
									
								
							|  | @ -2,42 +2,32 @@ | |||
| #include "../types.h" | ||||
| 
 | ||||
| // Contains the information required to create a graphics context in a window.
 | ||||
| struct WindowInfo | ||||
| { | ||||
|   enum class Type | ||||
|   { | ||||
|     Surfaceless, | ||||
|     Win32, | ||||
|     X11, | ||||
|     Wayland, | ||||
|     MacOS, | ||||
|     Android, | ||||
|     Display, | ||||
|   }; | ||||
| struct WindowInfo { | ||||
|     enum class Type { | ||||
|         Surfaceless, | ||||
|         Win32, | ||||
|         X11, | ||||
|         Wayland, | ||||
|         MacOS, | ||||
|         Android, | ||||
|         Display, | ||||
|     }; | ||||
| 
 | ||||
|   enum class SurfaceFormat | ||||
|   { | ||||
|     None, | ||||
|     Auto, | ||||
|     RGB8, | ||||
|     RGBA8, | ||||
|     RGB565, | ||||
|     Count | ||||
|   }; | ||||
|     enum class SurfaceFormat { None, Auto, RGB8, RGBA8, RGB565, Count }; | ||||
| 
 | ||||
|   Type type = Type::Surfaceless; | ||||
|   void* display_connection = nullptr; | ||||
|   void* window_handle = nullptr; | ||||
|   citra::u32 surface_width = 0; | ||||
|   citra::u32 surface_height = 0; | ||||
|   float surface_refresh_rate = 0.0f; | ||||
|   float surface_scale = 1.0f; | ||||
|   SurfaceFormat surface_format = SurfaceFormat::RGB8; | ||||
|     Type type = Type::Surfaceless; | ||||
|     void* display_connection = nullptr; | ||||
|     void* window_handle = nullptr; | ||||
|     citra::u32 surface_width = 0; | ||||
|     citra::u32 surface_height = 0; | ||||
|     float surface_refresh_rate = 0.0f; | ||||
|     float surface_scale = 1.0f; | ||||
|     SurfaceFormat surface_format = SurfaceFormat::RGB8; | ||||
| 
 | ||||
|   // Needed for macOS.
 | ||||
|     // Needed for macOS.
 | ||||
| #ifdef __APPLE__ | ||||
|   void* surface_handle = nullptr; | ||||
|     void* surface_handle = nullptr; | ||||
| #endif | ||||
| 
 | ||||
|   static bool QueryRefreshRateForWindow(const WindowInfo& wi, float* refresh_rate); | ||||
|     static bool QueryRefreshRateForWindow(const WindowInfo& wi, float* refresh_rate); | ||||
| }; | ||||
|  |  | |||
							
								
								
									
										25
									
								
								src/citra_qt/externals/types.h
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										25
									
								
								src/citra_qt/externals/types.h
									
										
									
									
										vendored
									
									
								
							|  | @ -19,21 +19,20 @@ | |||
| #ifndef TYPES_H | ||||
| #define TYPES_H | ||||
| 
 | ||||
| #include <stdint.h> | ||||
| #include <array> | ||||
| #include <stdint.h> | ||||
| 
 | ||||
| namespace citra | ||||
| { | ||||
| typedef uint8_t     u8; | ||||
| typedef uint16_t    u16; | ||||
| typedef uint32_t    u32; | ||||
| typedef uint64_t    u64; | ||||
| typedef int8_t      s8; | ||||
| typedef int16_t     s16; | ||||
| typedef int32_t     s32; | ||||
| typedef int64_t     s64; | ||||
| namespace citra { | ||||
| typedef uint8_t u8; | ||||
| typedef uint16_t u16; | ||||
| typedef uint32_t u32; | ||||
| typedef uint64_t u64; | ||||
| typedef int8_t s8; | ||||
| typedef int16_t s16; | ||||
| typedef int32_t s32; | ||||
| typedef int64_t s64; | ||||
| 
 | ||||
| template<class T, std::size_t A, std::size_t B> | ||||
| template <class T, std::size_t A, std::size_t B> | ||||
| using array2d = std::array<std::array<T, B>, A>; | ||||
| } | ||||
| } // namespace citra
 | ||||
| #endif // TYPES_H
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue