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_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; }