diff options
author | RSDuck <RSDuck@users.noreply.github.com> | 2022-10-17 22:55:11 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-10-17 22:55:11 +0200 |
commit | ac3118cbc54715da55856958b42817fbd1eed666 (patch) | |
tree | 717e66ec7df79171821f46e02b47d1357256ace2 /src/frontend/duckstation/gl/context_agl.mm | |
parent | 31ba585d392c9745917a141c72b3349d029586f0 (diff) |
No more context mess (#1531)
* WIP: use Duckstation's context code to directly render into QT Widget from separate thread without two OpenGL contexts
currently only works on Windows
* reenable gay OSD
* add back vsync
* make it atleast a little more thread safe
* linux support
* don't segfault on closing
* reorganise and cleanup build system
it's still not good, but better than before
* macos?
* try to get it working on Ubuntu CI
also update instructions
* let's try this
* ok how about this
* try creating an OGL 4.3 context first
(https://i.kym-cdn.com/photos/images/original/001/264/842/220.png)
* fix Ubuntu
* hm
* try again for Windows
* let's try this
* make the OpenGL renderer work again
that was stupid
* do OGL surface resizing from the mainthread
* Fix small mistake in GL context creation on macOS causing version 3.2 to
be considered invalid
* C stupidness
* cleanup
* don't let the emuthread deinit OGL if there's no OGL
* reset lastScreenWidth/Height when deiniting OpenGL
* disable stencil test while drawing framebuffers
* macOS: Link Cocoa framework explicitly when not building with Qt6
Seems to be needed for the classes used by DuckStation's GL context
code.
* Set ScreenPanelGL's minimum size immediately
Fixes GL context creation for OpenGL display on macOS using the wrong
size as the underlying window was not resized to the correct size by Qt
yet.
* don't emit window updates when OGL display is used
* stuff Arisotura said
Co-authored-by: Nadia Holmquist Pedersen <nadia@nhp.sh>
Diffstat (limited to 'src/frontend/duckstation/gl/context_agl.mm')
-rw-r--r-- | src/frontend/duckstation/gl/context_agl.mm | 214 |
1 files changed, 214 insertions, 0 deletions
diff --git a/src/frontend/duckstation/gl/context_agl.mm b/src/frontend/duckstation/gl/context_agl.mm new file mode 100644 index 0000000..f833518 --- /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 <dlfcn.h> +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<Context> ContextAGL::Create(const WindowInfo& wi, const Version* versions_to_try, + size_t num_versions_to_try) +{ + std::unique_ptr<ContextAGL> context = std::make_unique<ContextAGL>(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<int>(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<u32>(static_cast<CGFloat>(window_size.width) * window_scale); + const u32 new_height = static_cast<u32>(static_cast<CGFloat>(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<GLint>(interval); + [m_context setValues:&gl_interval forParameter:NSOpenGLCPSwapInterval]; + return true; +} + +std::unique_ptr<Context> ContextAGL::CreateSharedContext(const WindowInfo& wi) +{ + std::unique_ptr<ContextAGL> context = std::make_unique<ContextAGL>(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<NSOpenGLPixelFormatAttribute, 5> attribs = {{ + NSOpenGLPFADoubleBuffer, + NSOpenGLPFAOpenGLProfile, + static_cast<NSOpenGLPixelFormatAttribute>(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 |