From 01113631b55b1a6383cc521f6221395c6f08fad1 Mon Sep 17 00:00:00 2001 From: RSDuck Date: Wed, 12 Oct 2022 23:54:30 +0200 Subject: [PATCH] macos? --- src/frontend/duckstation/gl/context_agl.h | 49 +++++ src/frontend/duckstation/gl/context_agl.mm | 214 +++++++++++++++++++++ src/frontend/qt_sdl/CMakeLists.txt | 11 +- 3 files changed, 271 insertions(+), 3 deletions(-) create mode 100644 src/frontend/duckstation/gl/context_agl.h create mode 100644 src/frontend/duckstation/gl/context_agl.mm diff --git a/src/frontend/duckstation/gl/context_agl.h b/src/frontend/duckstation/gl/context_agl.h new file mode 100644 index 00000000..459bf2fd --- /dev/null +++ b/src/frontend/duckstation/gl/context_agl.h @@ -0,0 +1,49 @@ +#pragma once +#include "context.h" +#include "loader.h" + +#if defined(__APPLE__) && defined(__OBJC__) +#import +#else +struct NSOpenGLContext; +struct NSOpenGLPixelFormat; +struct NSView; +#define __bridge +#endif + +namespace GL { + +class ContextAGL final : public Context +{ +public: + ContextAGL(const WindowInfo& wi); + ~ContextAGL() override; + + static std::unique_ptr 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 CreateSharedContext(const WindowInfo& wi) override; + +private: + ALWAYS_INLINE NSView* GetView() const { return static_cast((__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(); + + // returns true if dimensions have changed + bool UpdateDimensions(); + + NSOpenGLContext* m_context = nullptr; + NSOpenGLPixelFormat* m_pixel_format = nullptr; + void* m_opengl_module_handle = nullptr; +}; + +} // namespace GL diff --git a/src/frontend/duckstation/gl/context_agl.mm b/src/frontend/duckstation/gl/context_agl.mm new file mode 100644 index 00000000..09d8e83d --- /dev/null +++ b/src/frontend/duckstation/gl/context_agl.mm @@ -0,0 +1,214 @@ +#include "context_agl.h" +#include "../duckstation_compat.h" +#include "../log.h" +#include "loader.h" +#include +Log_SetChannel(GL::ContextAGL); + +namespace GL { +ContextAGL::ContextAGL(const WindowInfo& wi) : Context(wi) +{ + m_opengl_module_handle = dlopen("/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL", RTLD_NOW); + if (!m_opengl_module_handle) + Log_ErrorPrint("Could not open OpenGL.framework, function lookups will probably fail"); +} + +ContextAGL::~ContextAGL() +{ + if ([NSOpenGLContext currentContext] == m_context) + [NSOpenGLContext clearCurrentContext]; + + if (m_context) + [m_context release]; + + if (m_pixel_format) + [m_pixel_format release]; + + if (m_opengl_module_handle) + dlclose(m_opengl_module_handle); +} + +std::unique_ptr ContextAGL::Create(const WindowInfo& wi, const Version* versions_to_try, + size_t num_versions_to_try) +{ + std::unique_ptr context = std::make_unique(wi); + if (!context->Initialize(versions_to_try, num_versions_to_try)) + return nullptr; + + return context; +} + +bool ContextAGL::Initialize(const Version* versions_to_try, size_t num_versions_to_try) +{ + for (size_t i = 0; i < num_versions_to_try; i++) + { + const Version& cv = versions_to_try[i]; + if (cv.profile == Profile::NoProfile && CreateContext(nullptr, NSOpenGLProfileVersionLegacy, true)) + { + // we already have the dummy context, so just use that + m_version = cv; + return true; + } + else if (cv.profile == Profile::Core) + { + if (cv.major_version > 4 || cv.minor_version > 1) + continue; + + const NSOpenGLPixelFormatAttribute profile = (cv.major_version > 3 || cv.minor_version > 2) ? NSOpenGLProfileVersion4_1Core : NSOpenGLProfileVersion3_2Core; + if (CreateContext(nullptr, static_cast(profile), true)) + { + m_version = cv; + return true; + } + } + } + + return false; +} + +void* ContextAGL::GetProcAddress(const char* name) +{ + void* addr = m_opengl_module_handle ? dlsym(m_opengl_module_handle, name) : nullptr; + if (addr) + return addr; + + return dlsym(RTLD_NEXT, name); +} + +bool ContextAGL::ChangeSurface(const WindowInfo& new_wi) +{ + m_wi = new_wi; + BindContextToView(); + return true; +} + +void ContextAGL::ResizeSurface(u32 new_surface_width /*= 0*/, u32 new_surface_height /*= 0*/) +{ + UpdateDimensions(); +} + +bool ContextAGL::UpdateDimensions() +{ + const NSSize window_size = [GetView() frame].size; + const CGFloat window_scale = [[GetView() window] backingScaleFactor]; + const u32 new_width = static_cast(static_cast(window_size.width) * window_scale); + const u32 new_height = static_cast(static_cast(window_size.height) * window_scale); + + if (m_wi.surface_width == new_width && m_wi.surface_height == new_height) + return false; + + m_wi.surface_width = new_width; + m_wi.surface_height = new_height; + + dispatch_block_t block = ^{ + [m_context update]; + }; + + if ([NSThread isMainThread]) + block(); + else + dispatch_sync(dispatch_get_main_queue(), block); + + return true; +} + +bool ContextAGL::SwapBuffers() +{ + [m_context flushBuffer]; + return true; +} + +bool ContextAGL::MakeCurrent() +{ + [m_context makeCurrentContext]; + return true; +} + +bool ContextAGL::DoneCurrent() +{ + [NSOpenGLContext clearCurrentContext]; + return true; +} + +bool ContextAGL::SetSwapInterval(s32 interval) +{ + GLint gl_interval = static_cast(interval); + [m_context setValues:&gl_interval forParameter:NSOpenGLCPSwapInterval]; + return true; +} + +std::unique_ptr ContextAGL::CreateSharedContext(const WindowInfo& wi) +{ + std::unique_ptr context = std::make_unique(wi); + + context->m_context = [[NSOpenGLContext alloc] initWithFormat:m_pixel_format shareContext:m_context]; + if (context->m_context == nil) + return nullptr; + + context->m_version = m_version; + context->m_pixel_format = m_pixel_format; + [context->m_pixel_format retain]; + + if (wi.type == WindowInfo::Type::MacOS) + context->BindContextToView(); + + return context; +} + +bool ContextAGL::CreateContext(NSOpenGLContext* share_context, int profile, bool make_current) +{ + if (m_context) + { + [m_context release]; + m_context = nullptr; + } + + if (m_pixel_format) + [m_pixel_format release]; + + const std::array attribs = {{ + NSOpenGLPFADoubleBuffer, + NSOpenGLPFAOpenGLProfile, + static_cast(profile), + NSOpenGLPFAAccelerated, + 0}}; + m_pixel_format = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs.data()]; + if (m_pixel_format == nil) + { + Log_ErrorPrintf("Failed to initialize pixel format"); + return false; + } + + m_context = [[NSOpenGLContext alloc] initWithFormat:m_pixel_format shareContext:nil]; + if (m_context == nil) + return false; + + if (m_wi.type == WindowInfo::Type::MacOS) + BindContextToView(); + + if (make_current) + [m_context makeCurrentContext]; + + return true; +} + +void ContextAGL::BindContextToView() +{ + NSView* const view = GetView(); + NSWindow* const window = [view window]; + [view setWantsBestResolutionOpenGLSurface:YES]; + + UpdateDimensions(); + + dispatch_block_t block = ^{ + [window makeFirstResponder:view]; + [m_context setView:view]; + [window makeKeyAndOrderFront:nil]; + }; + + if ([NSThread isMainThread]) + block(); + else + dispatch_sync(dispatch_get_main_queue(), block); +} +} // namespace GL diff --git a/src/frontend/qt_sdl/CMakeLists.txt b/src/frontend/qt_sdl/CMakeLists.txt index 244c5a74..5e746984 100644 --- a/src/frontend/qt_sdl/CMakeLists.txt +++ b/src/frontend/qt_sdl/CMakeLists.txt @@ -90,10 +90,14 @@ if (WIN32) target_link_libraries(melonDS PUBLIC opengl32) target_sources(melonDS PRIVATE - # the context stuff would probably be better in the frontend? ../duckstation/gl/context_wgl.cpp - ../glad/glad_wgl.c) + ../glad/glad_wgl.c + ) +elseif (APPLE) + target_sources(melonDS PRIVATE + ../duckstation/gl/context_agl.mm + ) else() # we only need ECM for Wayland # so we only require it from here @@ -112,7 +116,8 @@ else() ../duckstation/gl/x11_window.cpp ../glad/glad_egl.c - ../glad/glad_glx.c) + ../glad/glad_glx.c + ) target_link_libraries(melonDS PRIVATE "${X11_LIBRARIES}" "${EGL_LIBRARIES}") target_include_directories(melonDS PRIVATE "${X11_INCLUDE_DIR}") endif()