diff --git a/gfx/drivers_context/cocoa_gl_ctx.m b/gfx/drivers_context/cocoa_gl_ctx.m index 7d5f017f51..4c61d811a2 100644 --- a/gfx/drivers_context/cocoa_gl_ctx.m +++ b/gfx/drivers_context/cocoa_gl_ctx.m @@ -14,7 +14,876 @@ * If not, see . */ -#include "cocoa_gl_shared.h" +#ifdef HAVE_CONFIG_H +#include "../../config.h" +#endif + +#if TARGET_OS_IPHONE +#include +#else +#include +#endif +#if defined(HAVE_COCOA) || defined(HAVE_COCOA_METAL) +#include +#include +#include +#include +#elif defined(HAVE_COCOATOUCH) +#include +#endif + +#include +#include + +#include "../../ui/drivers/ui_cocoa.h" +#include "../../ui/drivers/cocoa/cocoa_common.h" +#include "../video_driver.h" +#include "../../configuration.h" +#include "../../verbosity.h" +#ifdef HAVE_VULKAN +#include "../common/vulkan_common.h" +#endif + +typedef struct cocoa_ctx_data +{ + bool core_hw_context_enable; +#ifdef HAVE_VULKAN + gfx_ctx_vulkan_data_t vk; + int swap_interval; +#endif + unsigned width; + unsigned height; +} cocoa_ctx_data_t; + +#if defined(HAVE_COCOATOUCH) +#define GLContextClass EAGLContext +#define GLFrameworkID CFSTR("com.apple.opengles") +#define RAScreen UIScreen + +#ifndef UIUserInterfaceIdiomTV +#define UIUserInterfaceIdiomTV 2 +#endif + +#ifndef UIUserInterfaceIdiomCarPlay +#define UIUserInterfaceIdiomCarPlay 3 +#endif +#else +#define GLContextClass NSOpenGLContext +#define GLFrameworkID CFSTR("com.apple.opengl") +#define RAScreen NSScreen +#endif + +static enum gfx_ctx_api cocoagl_api = GFX_CTX_NONE; + +#if defined(HAVE_COCOATOUCH) +static GLKView *g_view; +UIView *g_pause_indicator_view; +#endif + +static GLContextClass* g_hw_ctx; +static GLContextClass* g_context; + +static int g_fast_forward_skips; +static bool g_is_syncing = true; +static bool g_use_hw_ctx = false; + +static unsigned g_minor = 0; +static unsigned g_major = 0; + +#if defined(HAVE_COCOATOUCH) +@interface EAGLContext (OSXCompat) @end +@implementation EAGLContext (OSXCompat) ++ (void)clearCurrentContext { [EAGLContext setCurrentContext:nil]; } +- (void)makeCurrentContext { [EAGLContext setCurrentContext:self]; } +@end +#else +@interface NSScreen (IOSCompat) @end +@implementation NSScreen (IOSCompat) +- (CGRect)bounds +{ + CGRect cgrect = NSRectToCGRect(self.frame); + return CGRectMake(0, 0, CGRectGetWidth(cgrect), CGRectGetHeight(cgrect)); +} +- (float) scale { return 1.0f; } +@end +#endif + +/* forward declaration */ +void *nsview_get_ptr(void); + +#if defined(HAVE_COCOA) || defined(HAVE_COCOA_METAL) +static NSOpenGLPixelFormat* g_format; + +void *glcontext_get_ptr(void) +{ + return (BRIDGE void *)g_context; +} +#endif + +static uint32_t cocoagl_gfx_ctx_get_flags(void *data) +{ + uint32_t flags = 0; + cocoa_ctx_data_t *cocoa_ctx = (cocoa_ctx_data_t*)data; + + BIT32_SET(flags, GFX_CTX_FLAGS_NONE); + + if (cocoa_ctx->core_hw_context_enable) + BIT32_SET(flags, GFX_CTX_FLAGS_GL_CORE_CONTEXT); + + return flags; +} + +static void cocoagl_gfx_ctx_set_flags(void *data, uint32_t flags) +{ + (void)flags; + cocoa_ctx_data_t *cocoa_ctx = (cocoa_ctx_data_t*)data; + + if (BIT32_GET(flags, GFX_CTX_FLAGS_GL_CORE_CONTEXT)) + cocoa_ctx->core_hw_context_enable = true; +} + +void *glkitview_init(void) +{ +#if defined(HAVE_COCOATOUCH) +#if TARGET_OS_IOS + /* iOS Pause menu and lifecycle. */ + UINib *xib = (UINib*)[UINib nibWithNibName:BOXSTRING("PauseIndicatorView") bundle:nil]; + g_pause_indicator_view = [[xib instantiateWithOwner:[RetroArch_iOS get] options:nil] lastObject]; +#endif + + g_view = [GLKView new]; +#if TARGET_OS_IOS + g_view.multipleTouchEnabled = YES; + [g_view addSubview:g_pause_indicator_view]; +#endif + g_view.enableSetNeedsDisplay = NO; + + return (BRIDGE void *)((GLKView*)g_view); +#else + return nsview_get_ptr(); +#endif +} + +#if defined(HAVE_COCOATOUCH) +void cocoagl_bind_game_view_fbo(void) +{ + if (g_context) + [g_view bindDrawable]; +} +#endif + +static float get_from_selector(Class obj_class, id obj_id, SEL selector, CGFloat *ret) +{ + NSInvocation *invocation = [NSInvocation invocationWithMethodSignature: + [obj_class instanceMethodSignatureForSelector:selector]]; + [invocation setSelector:selector]; + [invocation setTarget:obj_id]; + [invocation invoke]; + [invocation getReturnValue:ret]; + RELEASE(invocation); + return *ret; +} + +void *get_chosen_screen(void) +{ + settings_t *settings = config_get_ptr(); + NSArray *screens = [RAScreen screens]; + if (!screens || !settings) + return NULL; + + if (settings->uints.video_monitor_index >= screens.count) + { + RARCH_WARN("video_monitor_index is greater than the number of connected monitors; using main screen instead."); + return (BRIDGE void*)screens; + } + + return ((BRIDGE void*)[screens objectAtIndex:settings->uints.video_monitor_index]); +} + +float get_backing_scale_factor(void) +{ + static float + backing_scale_def = 0.0f; + RAScreen *screen = NULL; + + (void)screen; + + if (backing_scale_def != 0.0f) + return backing_scale_def; + + backing_scale_def = 1.0f; +#ifdef HAVE_COCOA_METAL + screen = (BRIDGE RAScreen*)get_chosen_screen(); + + if (screen) + { + SEL selector = NSSelectorFromString(BOXSTRING("backingScaleFactor")); + if ([screen respondsToSelector:selector]) + { + CGFloat ret; + NSView *g_view = apple_platform.renderView; + //CocoaView *g_view = (CocoaView*)nsview_get_ptr(); + backing_scale_def = (float)get_from_selector + ([[g_view window] class], [g_view window], selector, &ret); + } + } +#endif + + return backing_scale_def; +} + +void cocoagl_gfx_ctx_update(void) +{ + switch (cocoagl_api) + { + case GFX_CTX_OPENGL_API: +#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) +#if defined(HAVE_COCOA) || defined(HAVE_COCOA_METAL) +#if MAC_OS_X_VERSION_10_7 + CGLUpdateContext(g_hw_ctx.CGLContextObj); + CGLUpdateContext(g_context.CGLContextObj); +#else + [g_hw_ctx update]; + [g_context update]; +#endif +#endif +#endif + break; + default: + break; + } +} + +static void cocoagl_gfx_ctx_destroy(void *data) +{ + cocoa_ctx_data_t *cocoa_ctx = (cocoa_ctx_data_t*)data; + + if (!cocoa_ctx) + return; + + switch (cocoagl_api) + { + case GFX_CTX_OPENGL_API: + case GFX_CTX_OPENGL_ES_API: +#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) + [GLContextClass clearCurrentContext]; + +#if defined(HAVE_COCOA) || defined(HAVE_COCOA_METAL) + [g_context clearDrawable]; + RELEASE(g_context); + RELEASE(g_format); + if (g_hw_ctx) + { + [g_hw_ctx clearDrawable]; + } + RELEASE(g_hw_ctx); +#endif + [GLContextClass clearCurrentContext]; + g_context = nil; +#endif + break; + case GFX_CTX_VULKAN_API: +#ifdef HAVE_VULKAN + vulkan_context_destroy(&cocoa_ctx->vk, cocoa_ctx->vk.vk_surface != VK_NULL_HANDLE); + if (cocoa_ctx->vk.context.queue_lock) { + slock_free(cocoa_ctx->vk.context.queue_lock); + } + memset(&cocoa_ctx->vk, 0, sizeof(cocoa_ctx->vk)); + +#endif + break; + case GFX_CTX_NONE: + default: + break; + } + + free(cocoa_ctx); +} + +static enum gfx_ctx_api cocoagl_gfx_ctx_get_api(void *data) +{ + return cocoagl_api; +} + +static void cocoagl_gfx_ctx_show_mouse(void *data, bool state) +{ + (void)data; + +#if defined(HAVE_COCOA) || defined(HAVE_COCOA_METAL) + if (state) + [NSCursor unhide]; + else + [NSCursor hide]; +#endif +} + +float cocoagl_gfx_ctx_get_native_scale(void) +{ + static CGFloat ret = 0.0f; + SEL selector = NSSelectorFromString(BOXSTRING("nativeScale")); + RAScreen *screen = (BRIDGE RAScreen*)get_chosen_screen(); + + if (ret != 0.0f) + return ret; + if (!screen) + return 0.0f; + + if ([screen respondsToSelector:selector]) + return (float)get_from_selector([screen class], screen, selector, &ret); + + ret = 1.0f; + selector = NSSelectorFromString(BOXSTRING("scale")); + if ([screen respondsToSelector:selector]) + ret = screen.scale; + return ret; +} + +#if defined(HAVE_COCOA) || defined(HAVE_COCOA_METAL) +static void cocoagl_gfx_ctx_update_title(void *data, void *data2) +{ + ui_window_cocoa_t view; + const ui_window_t *window = ui_companion_driver_get_window_ptr(); + +#if defined(HAVE_COCOA) + view.data = (CocoaView*)nsview_get_ptr(); +#elif defined(HAVE_COCOA_METAL) + view.data = (BRIDGE void *)apple_platform.renderView; +#endif + + if (window) + { + char title[128]; + + title[0] = '\0'; + + video_driver_get_window_title(title, sizeof(title)); + + if (title[0]) + window->set_title(&view, title); + } +} +#endif + +static bool cocoagl_gfx_ctx_get_metrics(void *data, enum display_metric_types type, + float *value) +{ + RAScreen *screen = (BRIDGE RAScreen*)get_chosen_screen(); +#if defined(HAVE_COCOA) || defined(HAVE_COCOA_METAL) + NSDictionary *description = [screen deviceDescription]; + NSSize display_pixel_size = [[description objectForKey:NSDeviceSize] sizeValue]; + CGSize display_physical_size = CGDisplayScreenSize( + [[description objectForKey:@"NSScreenNumber"] unsignedIntValue]); + + float display_width = display_pixel_size.width; + float display_height = display_pixel_size.height; + float physical_width = display_physical_size.width; + float physical_height = display_physical_size.height; + float scale = get_backing_scale_factor(); + float dpi = (display_width/ physical_width) * 25.4f * scale; +#elif defined(HAVE_COCOATOUCH) + float scale = cocoagl_gfx_ctx_get_native_scale(); + CGRect screen_rect = [screen bounds]; + float display_height = screen_rect.size.height; + float physical_width = screen_rect.size.width * scale; + float physical_height = screen_rect.size.height * scale; + float dpi = 160 * scale; + unsigned idiom_type = UI_USER_INTERFACE_IDIOM(); + + switch (idiom_type) + { + case -1: /* UIUserInterfaceIdiomUnspecified */ + /* TODO */ + break; + case UIUserInterfaceIdiomPad: + dpi = 132 * scale; + break; + case UIUserInterfaceIdiomPhone: + dpi = 163 * scale; + break; + case UIUserInterfaceIdiomTV: + case UIUserInterfaceIdiomCarPlay: + /* TODO */ + break; + } +#endif + + (void)display_height; + + switch (type) + { + case DISPLAY_METRIC_MM_WIDTH: + *value = physical_width; + break; + case DISPLAY_METRIC_MM_HEIGHT: + *value = physical_height; + break; + case DISPLAY_METRIC_DPI: + *value = dpi; + break; + case DISPLAY_METRIC_NONE: + default: + *value = 0; + return false; + } + + return true; +} + +static bool cocoagl_gfx_ctx_has_focus(void *data) +{ + (void)data; +#if defined(HAVE_COCOATOUCH) + return ([[UIApplication sharedApplication] applicationState] == UIApplicationStateActive); +#else + return [NSApp isActive]; +#endif +} + +static bool cocoagl_gfx_ctx_suppress_screensaver(void *data, bool enable) +{ + (void)data; + (void)enable; + + return false; +} + +#if !defined(HAVE_COCOATOUCH) +static bool cocoagl_gfx_ctx_has_windowed(void *data) +{ + return true; +} +#endif + +static void cocoagl_gfx_ctx_input_driver(void *data, + const char *name, + const input_driver_t **input, void **input_data) +{ + *input = NULL; + *input_data = NULL; +} + +static void cocoagl_gfx_ctx_get_video_size(void *data, unsigned* width, unsigned* height) +{ + float screenscale = cocoagl_gfx_ctx_get_native_scale(); +#if defined(HAVE_COCOA) || defined(HAVE_COCOA_METAL) + CGRect size; + GLsizei backingPixelWidth, backingPixelHeight; +#if defined(HAVE_COCOA_METAL) + NSView *g_view = apple_platform.renderView; +#elif defined(HAVE_COCOA) + CocoaView *g_view = (CocoaView*)nsview_get_ptr(); +#endif + CGRect cgrect = NSRectToCGRect([g_view frame]); +#if MAC_OS_X_VERSION_10_7 + SEL selector = NSSelectorFromString(BOXSTRING("convertRectToBacking:")); + if ([g_view respondsToSelector:selector]) + cgrect = NSRectToCGRect([g_view convertRectToBacking:[g_view bounds]]); +#endif + backingPixelWidth = CGRectGetWidth(cgrect); + backingPixelHeight = CGRectGetHeight(cgrect); + size = CGRectMake(0, 0, backingPixelWidth, backingPixelHeight); +#else + CGRect size = g_view.bounds; +#endif + *width = CGRectGetWidth(size) * screenscale; + *height = CGRectGetHeight(size) * screenscale; +} + +static gfx_ctx_proc_t cocoagl_gfx_ctx_get_proc_address(const char *symbol_name) +{ + switch (cocoagl_api) + { + case GFX_CTX_OPENGL_API: + case GFX_CTX_OPENGL_ES_API: + return (gfx_ctx_proc_t)CFBundleGetFunctionPointerForName( + CFBundleGetBundleWithIdentifier(GLFrameworkID), + (BRIDGE CFStringRef)BOXSTRING(symbol_name) + ); + case GFX_CTX_NONE: + default: + break; + } + + return NULL; +} + +static void cocoagl_gfx_ctx_bind_hw_render(void *data, bool enable) +{ + (void)data; + switch (cocoagl_api) + { + case GFX_CTX_OPENGL_API: + case GFX_CTX_OPENGL_ES_API: + g_use_hw_ctx = enable; + + if (enable) + [g_hw_ctx makeCurrentContext]; + else + [g_context makeCurrentContext]; + break; + case GFX_CTX_NONE: + default: + break; + } +} + +static void cocoagl_gfx_ctx_check_window(void *data, bool *quit, + bool *resize, unsigned *width, unsigned *height, bool is_shutdown) +{ + unsigned new_width, new_height; +#ifdef HAVE_VULKAN + cocoa_ctx_data_t *cocoa_ctx = (cocoa_ctx_data_t*)data; +#endif + + *quit = false; + + switch (cocoagl_api) + { + case GFX_CTX_OPENGL_API: + case GFX_CTX_OPENGL_ES_API: + break; + case GFX_CTX_VULKAN_API: +#ifdef HAVE_VULKAN + *resize = cocoa_ctx->vk.need_new_swapchain; +#endif + break; + case GFX_CTX_NONE: + default: + break; + } + + cocoagl_gfx_ctx_get_video_size(data, &new_width, &new_height); + if (new_width != *width || new_height != *height) + { + *width = new_width; + *height = new_height; + *resize = true; + } +} + +static void cocoagl_gfx_ctx_swap_interval(void *data, int i) +{ + unsigned interval = (unsigned)i; +#ifdef HAVE_VULKAN + cocoa_ctx_data_t *cocoa_ctx = (cocoa_ctx_data_t*)data; +#endif + + switch (cocoagl_api) + { + case GFX_CTX_OPENGL_API: + case GFX_CTX_OPENGL_ES_API: + { +#if defined(HAVE_COCOATOUCH) // < No way to disable Vsync on iOS? + // Just skip presents so fast forward still works. + g_is_syncing = interval ? true : false; + g_fast_forward_skips = interval ? 0 : 3; +#elif defined(HAVE_COCOA) || defined(HAVE_COCOA_METAL) + GLint value = interval ? 1 : 0; + [g_context setValues:&value forParameter:NSOpenGLCPSwapInterval]; +#endif + break; + } + case GFX_CTX_VULKAN_API: +#ifdef HAVE_VULKAN + if (cocoa_ctx->swap_interval != interval) + { + cocoa_ctx->swap_interval = interval; + if (cocoa_ctx->vk.swapchain) + cocoa_ctx->vk.need_new_swapchain = true; + } +#endif + break; + case GFX_CTX_NONE: + default: + break; + } +} + +static void cocoagl_gfx_ctx_swap_buffers(void *data, void *data2) +{ +#ifdef HAVE_VULKAN + cocoa_ctx_data_t *cocoa_ctx = (cocoa_ctx_data_t*)data; +#endif + + switch (cocoagl_api) + { + case GFX_CTX_OPENGL_API: + case GFX_CTX_OPENGL_ES_API: + if (!(--g_fast_forward_skips < 0)) + return; + +#if defined(HAVE_COCOA_METAL) + [g_context flushBuffer]; + [g_hw_ctx flushBuffer]; +#elif defined(HAVE_COCOATOUCH) + if (g_view) + [g_view display]; +#endif + + g_fast_forward_skips = g_is_syncing ? 0 : 3; + break; + case GFX_CTX_VULKAN_API: +#ifdef HAVE_VULKAN + vulkan_present(&cocoa_ctx->vk, cocoa_ctx->vk.context.current_swapchain_index); + vulkan_acquire_next_image(&cocoa_ctx->vk); +#endif + break; + case GFX_CTX_NONE: + default: + break; + } +} + +static bool cocoagl_gfx_ctx_bind_api(void *data, enum gfx_ctx_api api, + unsigned major, unsigned minor) +{ + (void)data; + switch (api) + { +#if defined(HAVE_COCOATOUCH) + case GFX_CTX_OPENGL_ES_API: + break; +#elif defined(HAVE_COCOA_METAL) + case GFX_CTX_OPENGL_API: + break; +#ifdef HAVE_VULKAN + case GFX_CTX_VULKAN_API: + break; +#endif +#endif + case GFX_CTX_NONE: + default: + return false; + } + + cocoagl_api = api; + g_minor = minor; + g_major = major; + + return true; +} + +#ifdef HAVE_VULKAN +static void *cocoagl_gfx_ctx_get_context_data(void *data) +{ + cocoa_ctx_data_t *cocoa_ctx = (cocoa_ctx_data_t*)data; + return &cocoa_ctx->vk.context; +} +#endif + +static bool cocoagl_gfx_ctx_set_video_mode(void *data, + video_frame_info_t *video_info, + unsigned width, unsigned height, bool fullscreen) +{ +#if defined(HAVE_COCOA_METAL) + NSView *g_view = apple_platform.renderView; +#elif defined(HAVE_COCOA) + CocoaView *g_view = (CocoaView*)nsview_get_ptr(); +#endif + cocoa_ctx_data_t *cocoa_ctx = (cocoa_ctx_data_t*)data; + +#if defined(HAVE_COCOA_METAL) + cocoa_ctx->width = width; + cocoa_ctx->height = height; +#endif + + switch (cocoagl_api) + { + case GFX_CTX_OPENGL_API: + case GFX_CTX_OPENGL_ES_API: + { +#if defined(HAVE_COCOA) || defined(HAVE_COCOA_METAL) + if ([g_view respondsToSelector: @selector(setWantsBestResolutionOpenGLSurface:)]) + [g_view setWantsBestResolutionOpenGLSurface:YES]; + + NSOpenGLPixelFormatAttribute attributes [] = { + NSOpenGLPFAColorSize, + 24, + NSOpenGLPFADoubleBuffer, + NSOpenGLPFAAllowOfflineRenderers, + NSOpenGLPFADepthSize, + (NSOpenGLPixelFormatAttribute)16, // 16 bit depth buffer + 0, /* profile */ + 0, /* profile enum */ + (NSOpenGLPixelFormatAttribute)0 + }; + +#if MAC_OS_X_VERSION_10_7 + if (g_major == 3 && (g_minor >= 1 && g_minor <= 3)) + { + attributes[6] = NSOpenGLPFAOpenGLProfile; + attributes[7] = NSOpenGLProfileVersion3_2Core; + } +#endif + +#if MAC_OS_X_VERSION_10_10 + if (g_major == 4 && g_minor == 1) + { + attributes[6] = NSOpenGLPFAOpenGLProfile; + attributes[7] = NSOpenGLProfileVersion4_1Core; + } +#endif + + g_format = [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes]; + +#if MAC_OS_X_VERSION_MIN_REQUIRED < 1050 + if (g_format == nil) + { + /* NSOpenGLFPAAllowOfflineRenderers is + not supported on this OS version. */ + attributes[3] = (NSOpenGLPixelFormatAttribute)0; + g_format = [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes]; + } +#endif + + if (g_use_hw_ctx) + g_hw_ctx = [[NSOpenGLContext alloc] initWithFormat:g_format shareContext:nil]; + g_context = [[NSOpenGLContext alloc] initWithFormat:g_format shareContext:(g_use_hw_ctx) ? g_hw_ctx : nil]; + [g_context setView:g_view]; +#else + if (g_use_hw_ctx) + g_hw_ctx = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; + g_context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; + g_view.context = g_context; +#endif + + [g_context makeCurrentContext]; + break; + } + case GFX_CTX_VULKAN_API: +#ifdef HAVE_VULKAN + RARCH_LOG("[macOS]: Native window size: %u x %u.\n", cocoa_ctx->width, cocoa_ctx->height); + if (!vulkan_surface_create(&cocoa_ctx->vk, + VULKAN_WSI_MVK_MACOS, NULL, + (BRIDGE void *)g_view, cocoa_ctx->width, cocoa_ctx->height, + cocoa_ctx->swap_interval)) + { + RARCH_ERR("[macOS]: Failed to create surface.\n"); + return false; + } +#endif + break; + case GFX_CTX_NONE: + default: + break; + } + +#if defined(HAVE_COCOA_METAL) + static bool has_went_fullscreen = false; + /* TODO: Screen mode support. */ + + if (fullscreen) + { + if (!has_went_fullscreen) + { +#if defined(HAVE_COCOA_METAL) + [g_view enterFullScreenMode:(BRIDGE NSScreen *)get_chosen_screen() withOptions:nil]; +#elif defined(HAVE_COCOA) + [g_view enterFullScreenMode:get_chosen_screen() withOptions:nil]; +#endif + cocoagl_gfx_ctx_show_mouse(data, false); + } + } + else + { + if (has_went_fullscreen) + { + [g_view exitFullScreenModeWithOptions:nil]; + [[g_view window] makeFirstResponder:g_view]; + cocoagl_gfx_ctx_show_mouse(data, true); + } + + [[g_view window] setContentSize:NSMakeSize(width, height)]; + } + + has_went_fullscreen = fullscreen; +#endif + + /* TODO: Maybe iOS users should be able to show/hide the status bar here? */ + + return true; +} + +static void *cocoagl_gfx_ctx_init(video_frame_info_t *video_info, void *video_driver) +{ + cocoa_ctx_data_t *cocoa_ctx = (cocoa_ctx_data_t*) + calloc(1, sizeof(cocoa_ctx_data_t)); + + if (!cocoa_ctx) + return NULL; + + switch (cocoagl_api) + { +#if defined(HAVE_COCOATOUCH) + case GFX_CTX_OPENGL_ES_API: + // setViewType is not (yet?) defined for iOS + // [apple_platform setViewType:APPLE_VIEW_TYPE_OPENGL_ES]; + break; +#elif defined(HAVE_COCOA_METAL) + case GFX_CTX_OPENGL_API: + [apple_platform setViewType:APPLE_VIEW_TYPE_OPENGL]; + break; +#endif + case GFX_CTX_VULKAN_API: +#ifdef HAVE_VULKAN + [apple_platform setViewType:APPLE_VIEW_TYPE_VULKAN]; + if (!vulkan_context_init(&cocoa_ctx->vk, VULKAN_WSI_MVK_MACOS)) + goto error; +#endif + break; + case GFX_CTX_NONE: + default: + break; + } + + return cocoa_ctx; + +error: + free(cocoa_ctx); + return NULL; +} + +#ifdef HAVE_COCOA_METAL +static bool cocoagl_gfx_ctx_set_resize(void *data, unsigned width, unsigned height) +{ +#ifdef HAVE_VULKAN + cocoa_ctx_data_t *cocoa_ctx = (cocoa_ctx_data_t*)data; +#endif + + switch (cocoagl_api) + { + case GFX_CTX_OPENGL_API: + case GFX_CTX_OPENGL_ES_API: + break; + case GFX_CTX_VULKAN_API: +#ifdef HAVE_VULKAN + cocoa_ctx->width = width; + cocoa_ctx->height = height; + + if (vulkan_create_swapchain(&cocoa_ctx->vk, + width, height, cocoa_ctx->swap_interval)) + { + cocoa_ctx->vk.context.invalid_swapchain = true; + if (cocoa_ctx->vk.created_new_swapchain) + vulkan_acquire_next_image(&cocoa_ctx->vk); + } + else + { + RARCH_ERR("[macOS/Vulkan]: Failed to update swapchain.\n"); + return false; + } + + cocoa_ctx->vk.need_new_swapchain = false; +#endif + break; + case GFX_CTX_NONE: + default: + break; + } + + return true; +} +#endif const gfx_ctx_driver_t gfx_ctx_cocoagl = { cocoagl_gfx_ctx_init, @@ -29,14 +898,18 @@ const gfx_ctx_driver_t gfx_ctx_cocoagl = { NULL, /* get_video_output_prev */ NULL, /* get_video_output_next */ cocoagl_gfx_ctx_get_metrics, - NULL, -#if defined(HAVE_COCOA) + NULL, /* translate_aspect */ +#if defined(HAVE_COCOA) || defined(HAVE_COCOA_METAL) cocoagl_gfx_ctx_update_title, #else NULL, /* update_title */ #endif cocoagl_gfx_ctx_check_window, +#if defined(HAVE_COCOA_METAL) + cocoagl_gfx_ctx_set_resize, +#else NULL, /* set_resize */ +#endif cocoagl_gfx_ctx_has_focus, cocoagl_gfx_ctx_suppress_screensaver, #if defined(HAVE_COCOATOUCH) @@ -47,13 +920,17 @@ const gfx_ctx_driver_t gfx_ctx_cocoagl = { cocoagl_gfx_ctx_swap_buffers, cocoagl_gfx_ctx_input_driver, cocoagl_gfx_ctx_get_proc_address, - NULL, - NULL, - NULL, + NULL, /* image_buffer_init */ + NULL, /* image_buffer_write */ + NULL, /* show_mouse */ "cocoagl", cocoagl_gfx_ctx_get_flags, cocoagl_gfx_ctx_set_flags, cocoagl_gfx_ctx_bind_hw_render, - NULL, - NULL +#if defined(HAVE_VULKAN) + cocoagl_gfx_ctx_get_context_data, +#else + NULL, /* get_context_data */ +#endif + NULL /* make_current */ }; diff --git a/gfx/drivers_context/cocoa_gl_ctx_metal.m b/gfx/drivers_context/cocoa_gl_ctx_metal.m deleted file mode 100644 index 8a24492a10..0000000000 --- a/gfx/drivers_context/cocoa_gl_ctx_metal.m +++ /dev/null @@ -1,89 +0,0 @@ -/* RetroArch - A frontend for libretro. - * Copyright (C) 2018 - Stuart Carnie - * - * RetroArch is free software: you can redistribute it and/or modify it under the terms - * of the GNU General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with RetroArch. - * If not, see . - */ - -#include "cocoa_gl_shared.h" - -static bool cocoagl_gfx_ctx_set_resize(void *data, unsigned width, unsigned height) -{ -#ifdef HAVE_VULKAN - cocoa_ctx_data_t *cocoa_ctx = (cocoa_ctx_data_t*)data; -#endif - - switch (cocoagl_api) - { - case GFX_CTX_OPENGL_API: - case GFX_CTX_OPENGL_ES_API: - break; - case GFX_CTX_VULKAN_API: -#ifdef HAVE_VULKAN - cocoa_ctx->width = width; - cocoa_ctx->height = height; - - if (vulkan_create_swapchain(&cocoa_ctx->vk, - width, height, cocoa_ctx->swap_interval)) - { - cocoa_ctx->vk.context.invalid_swapchain = true; - if (cocoa_ctx->vk.created_new_swapchain) - vulkan_acquire_next_image(&cocoa_ctx->vk); - } - else - { - RARCH_ERR("[macOS/Vulkan]: Failed to update swapchain.\n"); - return false; - } - - cocoa_ctx->vk.need_new_swapchain = false; -#endif - break; - case GFX_CTX_NONE: - default: - break; - } - - return true; -} - -const gfx_ctx_driver_t gfx_ctx_cocoagl = { - .init = cocoagl_gfx_ctx_init, - .destroy = cocoagl_gfx_ctx_destroy, - .get_api = cocoagl_gfx_ctx_get_api, - .bind_api = cocoagl_gfx_ctx_bind_api, - .swap_interval = cocoagl_gfx_ctx_swap_interval, - .set_video_mode = cocoagl_gfx_ctx_set_video_mode, - .get_video_size = cocoagl_gfx_ctx_get_video_size, - .get_metrics = cocoagl_gfx_ctx_get_metrics, -#if defined(HAVE_COCOA_METAL) - .update_window_title = cocoagl_gfx_ctx_update_title, -#endif - .check_window = cocoagl_gfx_ctx_check_window, - .set_resize = cocoagl_gfx_ctx_set_resize, - .has_focus = cocoagl_gfx_ctx_has_focus, - .suppress_screensaver = cocoagl_gfx_ctx_suppress_screensaver, -#if !defined(HAVE_COCOATOUCH) - .has_windowed = cocoagl_gfx_ctx_has_windowed, -#endif - .swap_buffers = cocoagl_gfx_ctx_swap_buffers, - .input_driver = cocoagl_gfx_ctx_input_driver, - .get_proc_address = cocoagl_gfx_ctx_get_proc_address, - .ident = "macOS", - .get_flags = cocoagl_gfx_ctx_get_flags, - .set_flags = cocoagl_gfx_ctx_set_flags, - .bind_hw_render = cocoagl_gfx_ctx_bind_hw_render, -#if defined(HAVE_VULKAN) - .get_context_data = cocoagl_gfx_ctx_get_context_data, -#else - .get_context_data = NULL, -#endif -}; diff --git a/gfx/drivers_context/cocoa_gl_shared.h b/gfx/drivers_context/cocoa_gl_shared.h deleted file mode 100644 index 8d9de2efa2..0000000000 --- a/gfx/drivers_context/cocoa_gl_shared.h +++ /dev/null @@ -1,828 +0,0 @@ -#ifdef HAVE_CONFIG_H -#include "../../config.h" -#endif - -#if TARGET_OS_IPHONE -#include -#else -#include -#endif -#if defined(HAVE_COCOA) || defined(HAVE_COCOA_METAL) -#include -#include -#include -#include -#elif defined(HAVE_COCOATOUCH) -#include -#endif - -#include -#include - -#include "../../ui/drivers/ui_cocoa.h" -#include "../../ui/drivers/cocoa/cocoa_common.h" -#include "../video_driver.h" -#include "../../configuration.h" -#include "../../verbosity.h" -#ifdef HAVE_VULKAN -#include "../common/vulkan_common.h" -#endif - -typedef struct cocoa_ctx_data -{ - bool core_hw_context_enable; -#ifdef HAVE_VULKAN - gfx_ctx_vulkan_data_t vk; - int swap_interval; -#endif - unsigned width; - unsigned height; -} cocoa_ctx_data_t; - -#if defined(HAVE_COCOATOUCH) -#define GLContextClass EAGLContext -#define GLFrameworkID CFSTR("com.apple.opengles") -#define RAScreen UIScreen - -#ifndef UIUserInterfaceIdiomTV -#define UIUserInterfaceIdiomTV 2 -#endif - -#ifndef UIUserInterfaceIdiomCarPlay -#define UIUserInterfaceIdiomCarPlay 3 -#endif -#else -#define GLContextClass NSOpenGLContext -#define GLFrameworkID CFSTR("com.apple.opengl") -#define RAScreen NSScreen -#endif - -static enum gfx_ctx_api cocoagl_api = GFX_CTX_NONE; - -#if defined(HAVE_COCOATOUCH) -static GLKView *g_view; -UIView *g_pause_indicator_view; -#endif - -static GLContextClass* g_hw_ctx; -static GLContextClass* g_context; - -static int g_fast_forward_skips; -static bool g_is_syncing = true; -static bool g_use_hw_ctx = false; - -static unsigned g_minor = 0; -static unsigned g_major = 0; - -#if defined(HAVE_COCOATOUCH) -@interface EAGLContext (OSXCompat) @end -@implementation EAGLContext (OSXCompat) -+ (void)clearCurrentContext { [EAGLContext setCurrentContext:nil]; } -- (void)makeCurrentContext { [EAGLContext setCurrentContext:self]; } -@end -#else -@interface NSScreen (IOSCompat) @end -@implementation NSScreen (IOSCompat) -- (CGRect)bounds -{ - CGRect cgrect = NSRectToCGRect(self.frame); - return CGRectMake(0, 0, CGRectGetWidth(cgrect), CGRectGetHeight(cgrect)); -} -- (float) scale { return 1.0f; } -@end -#endif - -/* forward declaration */ -void *nsview_get_ptr(void); - -#if defined(HAVE_COCOA) || defined(HAVE_COCOA_METAL) -static NSOpenGLPixelFormat* g_format; - -void *glcontext_get_ptr(void) -{ - return (BRIDGE void *)g_context; -} -#endif - -static uint32_t cocoagl_gfx_ctx_get_flags(void *data) -{ - uint32_t flags = 0; - cocoa_ctx_data_t *cocoa_ctx = (cocoa_ctx_data_t*)data; - - BIT32_SET(flags, GFX_CTX_FLAGS_NONE); - - if (cocoa_ctx->core_hw_context_enable) - BIT32_SET(flags, GFX_CTX_FLAGS_GL_CORE_CONTEXT); - - return flags; -} - -static void cocoagl_gfx_ctx_set_flags(void *data, uint32_t flags) -{ - (void)flags; - cocoa_ctx_data_t *cocoa_ctx = (cocoa_ctx_data_t*)data; - - if (BIT32_GET(flags, GFX_CTX_FLAGS_GL_CORE_CONTEXT)) - cocoa_ctx->core_hw_context_enable = true; -} - -void *glkitview_init(void) -{ -#if defined(HAVE_COCOATOUCH) -#if TARGET_OS_IOS - /* iOS Pause menu and lifecycle. */ - UINib *xib = (UINib*)[UINib nibWithNibName:BOXSTRING("PauseIndicatorView") bundle:nil]; - g_pause_indicator_view = [[xib instantiateWithOwner:[RetroArch_iOS get] options:nil] lastObject]; -#endif - - g_view = [GLKView new]; -#if TARGET_OS_IOS - g_view.multipleTouchEnabled = YES; - [g_view addSubview:g_pause_indicator_view]; -#endif - g_view.enableSetNeedsDisplay = NO; - - return (BRIDGE void *)((GLKView*)g_view); -#else - return nsview_get_ptr(); -#endif -} - -#if defined(HAVE_COCOATOUCH) -void cocoagl_bind_game_view_fbo(void) -{ - if (g_context) - [g_view bindDrawable]; -} -#endif - -static float get_from_selector(Class obj_class, id obj_id, SEL selector, CGFloat *ret) -{ - NSInvocation *invocation = [NSInvocation invocationWithMethodSignature: - [obj_class instanceMethodSignatureForSelector:selector]]; - [invocation setSelector:selector]; - [invocation setTarget:obj_id]; - [invocation invoke]; - [invocation getReturnValue:ret]; - RELEASE(invocation); - return *ret; -} - -void *get_chosen_screen(void) -{ - settings_t *settings = config_get_ptr(); - NSArray *screens = [RAScreen screens]; - if (!screens || !settings) - return NULL; - - if (settings->uints.video_monitor_index >= screens.count) - { - RARCH_WARN("video_monitor_index is greater than the number of connected monitors; using main screen instead."); - return (BRIDGE void*)screens; - } - - return ((BRIDGE void*)[screens objectAtIndex:settings->uints.video_monitor_index]); -} - -float get_backing_scale_factor(void) -{ - static float - backing_scale_def = 0.0f; - RAScreen *screen = NULL; - - (void)screen; - - if (backing_scale_def != 0.0f) - return backing_scale_def; - - backing_scale_def = 1.0f; -#ifdef HAVE_COCOA_METAL - screen = (BRIDGE RAScreen*)get_chosen_screen(); - - if (screen) - { - SEL selector = NSSelectorFromString(BOXSTRING("backingScaleFactor")); - if ([screen respondsToSelector:selector]) - { - CGFloat ret; - NSView *g_view = apple_platform.renderView; - //CocoaView *g_view = (CocoaView*)nsview_get_ptr(); - backing_scale_def = (float)get_from_selector - ([[g_view window] class], [g_view window], selector, &ret); - } - } -#endif - - return backing_scale_def; -} - -void cocoagl_gfx_ctx_update(void) -{ - switch (cocoagl_api) - { - case GFX_CTX_OPENGL_API: -#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) -#if defined(HAVE_COCOA) || defined(HAVE_COCOA_METAL) -#if MAC_OS_X_VERSION_10_7 - CGLUpdateContext(g_hw_ctx.CGLContextObj); - CGLUpdateContext(g_context.CGLContextObj); -#else - [g_hw_ctx update]; - [g_context update]; -#endif -#endif -#endif - break; - default: - break; - } -} - -static void cocoagl_gfx_ctx_destroy(void *data) -{ - cocoa_ctx_data_t *cocoa_ctx = (cocoa_ctx_data_t*)data; - - if (!cocoa_ctx) - return; - - switch (cocoagl_api) - { - case GFX_CTX_OPENGL_API: - case GFX_CTX_OPENGL_ES_API: -#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) - [GLContextClass clearCurrentContext]; - -#if defined(HAVE_COCOA) || defined(HAVE_COCOA_METAL) - [g_context clearDrawable]; - RELEASE(g_context); - RELEASE(g_format); - if (g_hw_ctx) - { - [g_hw_ctx clearDrawable]; - } - RELEASE(g_hw_ctx); -#endif - [GLContextClass clearCurrentContext]; - g_context = nil; -#endif - break; - case GFX_CTX_VULKAN_API: -#ifdef HAVE_VULKAN - vulkan_context_destroy(&cocoa_ctx->vk, cocoa_ctx->vk.vk_surface != VK_NULL_HANDLE); - if (cocoa_ctx->vk.context.queue_lock) { - slock_free(cocoa_ctx->vk.context.queue_lock); - } - memset(&cocoa_ctx->vk, 0, sizeof(cocoa_ctx->vk)); - -#endif - break; - case GFX_CTX_NONE: - default: - break; - } - - free(cocoa_ctx); -} - -static enum gfx_ctx_api cocoagl_gfx_ctx_get_api(void *data) -{ - return cocoagl_api; -} - -static void cocoagl_gfx_ctx_show_mouse(void *data, bool state) -{ - (void)data; - -#if defined(HAVE_COCOA) || defined(HAVE_COCOA_METAL) - if (state) - [NSCursor unhide]; - else - [NSCursor hide]; -#endif -} - -float cocoagl_gfx_ctx_get_native_scale(void) -{ - static CGFloat ret = 0.0f; - SEL selector = NSSelectorFromString(BOXSTRING("nativeScale")); - RAScreen *screen = (BRIDGE RAScreen*)get_chosen_screen(); - - if (ret != 0.0f) - return ret; - if (!screen) - return 0.0f; - - if ([screen respondsToSelector:selector]) - return (float)get_from_selector([screen class], screen, selector, &ret); - - ret = 1.0f; - selector = NSSelectorFromString(BOXSTRING("scale")); - if ([screen respondsToSelector:selector]) - ret = screen.scale; - return ret; -} - -#if defined(HAVE_COCOA) || defined(HAVE_COCOA_METAL) -static void cocoagl_gfx_ctx_update_title(void *data, void *data2) -{ - ui_window_cocoa_t view; - const ui_window_t *window = ui_companion_driver_get_window_ptr(); - -#if defined(HAVE_COCOA) - view.data = (CocoaView*)nsview_get_ptr(); -#elif defined(HAVE_COCOA_METAL) - view.data = (BRIDGE void *)apple_platform.renderView; -#endif - - if (window) - { - char title[128]; - - title[0] = '\0'; - - video_driver_get_window_title(title, sizeof(title)); - - if (title[0]) - window->set_title(&view, title); - } -} -#endif - -static bool cocoagl_gfx_ctx_get_metrics(void *data, enum display_metric_types type, - float *value) -{ - RAScreen *screen = (BRIDGE RAScreen*)get_chosen_screen(); -#if defined(HAVE_COCOA) || defined(HAVE_COCOA_METAL) - NSDictionary *description = [screen deviceDescription]; - NSSize display_pixel_size = [[description objectForKey:NSDeviceSize] sizeValue]; - CGSize display_physical_size = CGDisplayScreenSize( - [[description objectForKey:@"NSScreenNumber"] unsignedIntValue]); - - float display_width = display_pixel_size.width; - float display_height = display_pixel_size.height; - float physical_width = display_physical_size.width; - float physical_height = display_physical_size.height; - float scale = get_backing_scale_factor(); - float dpi = (display_width/ physical_width) * 25.4f * scale; -#elif defined(HAVE_COCOATOUCH) - float scale = cocoagl_gfx_ctx_get_native_scale(); - CGRect screen_rect = [screen bounds]; - float display_height = screen_rect.size.height; - float physical_width = screen_rect.size.width * scale; - float physical_height = screen_rect.size.height * scale; - float dpi = 160 * scale; - unsigned idiom_type = UI_USER_INTERFACE_IDIOM(); - - switch (idiom_type) - { - case -1: /* UIUserInterfaceIdiomUnspecified */ - /* TODO */ - break; - case UIUserInterfaceIdiomPad: - dpi = 132 * scale; - break; - case UIUserInterfaceIdiomPhone: - dpi = 163 * scale; - break; - case UIUserInterfaceIdiomTV: - case UIUserInterfaceIdiomCarPlay: - /* TODO */ - break; - } -#endif - - (void)display_height; - - switch (type) - { - case DISPLAY_METRIC_MM_WIDTH: - *value = physical_width; - break; - case DISPLAY_METRIC_MM_HEIGHT: - *value = physical_height; - break; - case DISPLAY_METRIC_DPI: - *value = dpi; - break; - case DISPLAY_METRIC_NONE: - default: - *value = 0; - return false; - } - - return true; -} - -static bool cocoagl_gfx_ctx_has_focus(void *data) -{ - (void)data; -#if defined(HAVE_COCOATOUCH) - return ([[UIApplication sharedApplication] applicationState] == UIApplicationStateActive); -#else - return [NSApp isActive]; -#endif -} - -static bool cocoagl_gfx_ctx_suppress_screensaver(void *data, bool enable) -{ - (void)data; - (void)enable; - - return false; -} - -#if !defined(HAVE_COCOATOUCH) -static bool cocoagl_gfx_ctx_has_windowed(void *data) -{ - return true; -} -#endif - -static void cocoagl_gfx_ctx_input_driver(void *data, - const char *name, - const input_driver_t **input, void **input_data) -{ - *input = NULL; - *input_data = NULL; -} - -static void cocoagl_gfx_ctx_get_video_size(void *data, unsigned* width, unsigned* height) -{ - float screenscale = cocoagl_gfx_ctx_get_native_scale(); -#if defined(HAVE_COCOA) || defined(HAVE_COCOA_METAL) - CGRect size; - GLsizei backingPixelWidth, backingPixelHeight; -#if defined(HAVE_COCOA_METAL) - NSView *g_view = apple_platform.renderView; -#elif defined(HAVE_COCOA) - CocoaView *g_view = (CocoaView*)nsview_get_ptr(); -#endif - CGRect cgrect = NSRectToCGRect([g_view frame]); -#if MAC_OS_X_VERSION_10_7 - SEL selector = NSSelectorFromString(BOXSTRING("convertRectToBacking:")); - if ([g_view respondsToSelector:selector]) - cgrect = NSRectToCGRect([g_view convertRectToBacking:[g_view bounds]]); -#endif - backingPixelWidth = CGRectGetWidth(cgrect); - backingPixelHeight = CGRectGetHeight(cgrect); - size = CGRectMake(0, 0, backingPixelWidth, backingPixelHeight); -#else - CGRect size = g_view.bounds; -#endif - *width = CGRectGetWidth(size) * screenscale; - *height = CGRectGetHeight(size) * screenscale; -} - -static gfx_ctx_proc_t cocoagl_gfx_ctx_get_proc_address(const char *symbol_name) -{ - switch (cocoagl_api) - { - case GFX_CTX_OPENGL_API: - case GFX_CTX_OPENGL_ES_API: - return (gfx_ctx_proc_t)CFBundleGetFunctionPointerForName( - CFBundleGetBundleWithIdentifier(GLFrameworkID), - (BRIDGE CFStringRef)BOXSTRING(symbol_name) - ); - case GFX_CTX_NONE: - default: - break; - } - - return NULL; -} - -static void cocoagl_gfx_ctx_bind_hw_render(void *data, bool enable) -{ - (void)data; - switch (cocoagl_api) - { - case GFX_CTX_OPENGL_API: - case GFX_CTX_OPENGL_ES_API: - g_use_hw_ctx = enable; - - if (enable) - [g_hw_ctx makeCurrentContext]; - else - [g_context makeCurrentContext]; - break; - case GFX_CTX_NONE: - default: - break; - } -} - -static void cocoagl_gfx_ctx_check_window(void *data, bool *quit, - bool *resize, unsigned *width, unsigned *height, bool is_shutdown) -{ - unsigned new_width, new_height; -#ifdef HAVE_VULKAN - cocoa_ctx_data_t *cocoa_ctx = (cocoa_ctx_data_t*)data; -#endif - - *quit = false; - - switch (cocoagl_api) - { - case GFX_CTX_OPENGL_API: - case GFX_CTX_OPENGL_ES_API: - break; - case GFX_CTX_VULKAN_API: -#ifdef HAVE_VULKAN - *resize = cocoa_ctx->vk.need_new_swapchain; -#endif - break; - case GFX_CTX_NONE: - default: - break; - } - - cocoagl_gfx_ctx_get_video_size(data, &new_width, &new_height); - if (new_width != *width || new_height != *height) - { - *width = new_width; - *height = new_height; - *resize = true; - } -} - -static void cocoagl_gfx_ctx_swap_interval(void *data, int i) -{ - unsigned interval = (unsigned)i; -#ifdef HAVE_VULKAN - cocoa_ctx_data_t *cocoa_ctx = (cocoa_ctx_data_t*)data; -#endif - - switch (cocoagl_api) - { - case GFX_CTX_OPENGL_API: - case GFX_CTX_OPENGL_ES_API: - { -#if defined(HAVE_COCOATOUCH) // < No way to disable Vsync on iOS? - // Just skip presents so fast forward still works. - g_is_syncing = interval ? true : false; - g_fast_forward_skips = interval ? 0 : 3; -#elif defined(HAVE_COCOA) || defined(HAVE_COCOA_METAL) - GLint value = interval ? 1 : 0; - [g_context setValues:&value forParameter:NSOpenGLCPSwapInterval]; -#endif - break; - } - case GFX_CTX_VULKAN_API: -#ifdef HAVE_VULKAN - if (cocoa_ctx->swap_interval != interval) - { - cocoa_ctx->swap_interval = interval; - if (cocoa_ctx->vk.swapchain) - cocoa_ctx->vk.need_new_swapchain = true; - } -#endif - break; - case GFX_CTX_NONE: - default: - break; - } -} - -static void cocoagl_gfx_ctx_swap_buffers(void *data, void *data2) -{ -#ifdef HAVE_VULKAN - cocoa_ctx_data_t *cocoa_ctx = (cocoa_ctx_data_t*)data; -#endif - - switch (cocoagl_api) - { - case GFX_CTX_OPENGL_API: - case GFX_CTX_OPENGL_ES_API: - if (!(--g_fast_forward_skips < 0)) - return; - -#if defined(HAVE_COCOA_METAL) - [g_context flushBuffer]; - [g_hw_ctx flushBuffer]; -#elif defined(HAVE_COCOATOUCH) - if (g_view) - [g_view display]; -#endif - - g_fast_forward_skips = g_is_syncing ? 0 : 3; - break; - case GFX_CTX_VULKAN_API: -#ifdef HAVE_VULKAN - vulkan_present(&cocoa_ctx->vk, cocoa_ctx->vk.context.current_swapchain_index); - vulkan_acquire_next_image(&cocoa_ctx->vk); -#endif - break; - case GFX_CTX_NONE: - default: - break; - } -} - -static bool cocoagl_gfx_ctx_bind_api(void *data, enum gfx_ctx_api api, - unsigned major, unsigned minor) -{ - (void)data; - switch (api) - { -#if defined(HAVE_COCOATOUCH) - case GFX_CTX_OPENGL_ES_API: - break; -#elif defined(HAVE_COCOA_METAL) - case GFX_CTX_OPENGL_API: - break; -#ifdef HAVE_VULKAN - case GFX_CTX_VULKAN_API: - break; -#endif -#endif - case GFX_CTX_NONE: - default: - return false; - } - - cocoagl_api = api; - g_minor = minor; - g_major = major; - - return true; -} - -#ifdef HAVE_VULKAN -static void *cocoagl_gfx_ctx_get_context_data(void *data) -{ - cocoa_ctx_data_t *cocoa_ctx = (cocoa_ctx_data_t*)data; - return &cocoa_ctx->vk.context; -} -#endif - -static bool cocoagl_gfx_ctx_set_video_mode(void *data, - video_frame_info_t *video_info, - unsigned width, unsigned height, bool fullscreen) -{ -#if defined(HAVE_COCOA_METAL) - NSView *g_view = apple_platform.renderView; -#elif defined(HAVE_COCOA) - CocoaView *g_view = (CocoaView*)nsview_get_ptr(); -#endif - cocoa_ctx_data_t *cocoa_ctx = (cocoa_ctx_data_t*)data; - -#if defined(HAVE_COCOA_METAL) - cocoa_ctx->width = width; - cocoa_ctx->height = height; -#endif - - switch (cocoagl_api) - { - case GFX_CTX_OPENGL_API: - case GFX_CTX_OPENGL_ES_API: - { -#if defined(HAVE_COCOA) || defined(HAVE_COCOA_METAL) - if ([g_view respondsToSelector: @selector(setWantsBestResolutionOpenGLSurface:)]) - [g_view setWantsBestResolutionOpenGLSurface:YES]; - - NSOpenGLPixelFormatAttribute attributes [] = { - NSOpenGLPFAColorSize, - 24, - NSOpenGLPFADoubleBuffer, - NSOpenGLPFAAllowOfflineRenderers, - NSOpenGLPFADepthSize, - (NSOpenGLPixelFormatAttribute)16, // 16 bit depth buffer - 0, /* profile */ - 0, /* profile enum */ - (NSOpenGLPixelFormatAttribute)0 - }; - -#if MAC_OS_X_VERSION_10_7 - if (g_major == 3 && (g_minor >= 1 && g_minor <= 3)) - { - attributes[6] = NSOpenGLPFAOpenGLProfile; - attributes[7] = NSOpenGLProfileVersion3_2Core; - } -#endif - -#if MAC_OS_X_VERSION_10_10 - if (g_major == 4 && g_minor == 1) - { - attributes[6] = NSOpenGLPFAOpenGLProfile; - attributes[7] = NSOpenGLProfileVersion4_1Core; - } -#endif - - g_format = [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes]; - -#if MAC_OS_X_VERSION_MIN_REQUIRED < 1050 - if (g_format == nil) - { - /* NSOpenGLFPAAllowOfflineRenderers is - not supported on this OS version. */ - attributes[3] = (NSOpenGLPixelFormatAttribute)0; - g_format = [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes]; - } -#endif - - if (g_use_hw_ctx) - g_hw_ctx = [[NSOpenGLContext alloc] initWithFormat:g_format shareContext:nil]; - g_context = [[NSOpenGLContext alloc] initWithFormat:g_format shareContext:(g_use_hw_ctx) ? g_hw_ctx : nil]; - [g_context setView:g_view]; -#else - if (g_use_hw_ctx) - g_hw_ctx = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; - g_context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; - g_view.context = g_context; -#endif - - [g_context makeCurrentContext]; - break; - } - case GFX_CTX_VULKAN_API: -#ifdef HAVE_VULKAN - RARCH_LOG("[macOS]: Native window size: %u x %u.\n", cocoa_ctx->width, cocoa_ctx->height); - if (!vulkan_surface_create(&cocoa_ctx->vk, - VULKAN_WSI_MVK_MACOS, NULL, - (BRIDGE void *)g_view, cocoa_ctx->width, cocoa_ctx->height, - cocoa_ctx->swap_interval)) - { - RARCH_ERR("[macOS]: Failed to create surface.\n"); - return false; - } -#endif - break; - case GFX_CTX_NONE: - default: - break; - } - -#if defined(HAVE_COCOA_METAL) - static bool has_went_fullscreen = false; - /* TODO: Screen mode support. */ - - if (fullscreen) - { - if (!has_went_fullscreen) - { -#if defined(HAVE_COCOA_METAL) - [g_view enterFullScreenMode:(BRIDGE NSScreen *)get_chosen_screen() withOptions:nil]; -#elif defined(HAVE_COCOA) - [g_view enterFullScreenMode:get_chosen_screen() withOptions:nil]; -#endif - cocoagl_gfx_ctx_show_mouse(data, false); - } - } - else - { - if (has_went_fullscreen) - { - [g_view exitFullScreenModeWithOptions:nil]; - [[g_view window] makeFirstResponder:g_view]; - cocoagl_gfx_ctx_show_mouse(data, true); - } - - [[g_view window] setContentSize:NSMakeSize(width, height)]; - } - - has_went_fullscreen = fullscreen; -#endif - - /* TODO: Maybe iOS users should be able to show/hide the status bar here? */ - - return true; -} - -static void *cocoagl_gfx_ctx_init(video_frame_info_t *video_info, void *video_driver) -{ - cocoa_ctx_data_t *cocoa_ctx = (cocoa_ctx_data_t*) - calloc(1, sizeof(cocoa_ctx_data_t)); - - if (!cocoa_ctx) - return NULL; - - switch (cocoagl_api) - { -#if defined(HAVE_COCOATOUCH) - case GFX_CTX_OPENGL_ES_API: - // setViewType is not (yet?) defined for iOS - // [apple_platform setViewType:APPLE_VIEW_TYPE_OPENGL_ES]; - break; -#elif defined(HAVE_COCOA_METAL) - case GFX_CTX_OPENGL_API: - [apple_platform setViewType:APPLE_VIEW_TYPE_OPENGL]; - break; -#endif - case GFX_CTX_VULKAN_API: -#ifdef HAVE_VULKAN - [apple_platform setViewType:APPLE_VIEW_TYPE_VULKAN]; - if (!vulkan_context_init(&cocoa_ctx->vk, VULKAN_WSI_MVK_MACOS)) - goto error; -#endif - break; - case GFX_CTX_NONE: - default: - break; - } - - return cocoa_ctx; - -error: - free(cocoa_ctx); - return NULL; -} diff --git a/griffin/griffin_objc.m b/griffin/griffin_objc.m index 1d7ab3dced..03e5c6f985 100644 --- a/griffin/griffin_objc.m +++ b/griffin/griffin_objc.m @@ -30,12 +30,7 @@ #if defined(HAVE_COCOATOUCH) || defined(HAVE_COCOA) || defined(HAVE_COCOA_METAL) #include "../ui/drivers/cocoa/cocoa_common.m" - -#if defined(HAVE_COCOATOUCH) || defined(HAVE_COCOA) #include "../gfx/drivers_context/cocoa_gl_ctx.m" -#else -#include "../gfx/drivers_context/cocoa_gl_ctx_metal.m" -#endif #if defined(HAVE_COCOATOUCH)