mirror of
https://github.com/melonDS-emu/melonDS.git
synced 2025-07-25 15:19:53 -06:00
macos?
This commit is contained in:
49
src/frontend/duckstation/gl/context_agl.h
Normal file
49
src/frontend/duckstation/gl/context_agl.h
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "context.h"
|
||||||
|
#include "loader.h"
|
||||||
|
|
||||||
|
#if defined(__APPLE__) && defined(__OBJC__)
|
||||||
|
#import <AppKit/AppKit.h>
|
||||||
|
#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<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;
|
||||||
|
|
||||||
|
private:
|
||||||
|
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();
|
||||||
|
|
||||||
|
// 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
|
214
src/frontend/duckstation/gl/context_agl.mm
Normal file
214
src/frontend/duckstation/gl/context_agl.mm
Normal file
@ -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
|
@ -90,10 +90,14 @@ if (WIN32)
|
|||||||
target_link_libraries(melonDS PUBLIC opengl32)
|
target_link_libraries(melonDS PUBLIC opengl32)
|
||||||
|
|
||||||
target_sources(melonDS PRIVATE
|
target_sources(melonDS PRIVATE
|
||||||
# the context stuff would probably be better in the frontend?
|
|
||||||
../duckstation/gl/context_wgl.cpp
|
../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()
|
else()
|
||||||
# we only need ECM for Wayland
|
# we only need ECM for Wayland
|
||||||
# so we only require it from here
|
# so we only require it from here
|
||||||
@ -112,7 +116,8 @@ else()
|
|||||||
../duckstation/gl/x11_window.cpp
|
../duckstation/gl/x11_window.cpp
|
||||||
|
|
||||||
../glad/glad_egl.c
|
../glad/glad_egl.c
|
||||||
../glad/glad_glx.c)
|
../glad/glad_glx.c
|
||||||
|
)
|
||||||
target_link_libraries(melonDS PRIVATE "${X11_LIBRARIES}" "${EGL_LIBRARIES}")
|
target_link_libraries(melonDS PRIVATE "${X11_LIBRARIES}" "${EGL_LIBRARIES}")
|
||||||
target_include_directories(melonDS PRIVATE "${X11_INCLUDE_DIR}")
|
target_include_directories(melonDS PRIVATE "${X11_INCLUDE_DIR}")
|
||||||
endif()
|
endif()
|
||||||
|
Reference in New Issue
Block a user