diff options
Diffstat (limited to 'platform')
| -rw-r--r-- | platform/android/export/export_plugin.cpp | 4 | ||||
| -rw-r--r-- | platform/android/java/app/config.gradle | 4 | ||||
| -rw-r--r-- | platform/android/java/lib/AndroidManifest.xml | 3 | ||||
| -rw-r--r-- | platform/android/java/lib/src/org/godotengine/godot/Godot.java | 2 | ||||
| -rw-r--r-- | platform/iphone/export/export_plugin.cpp | 10 | ||||
| -rw-r--r-- | platform/javascript/export/export_plugin.cpp | 4 | ||||
| -rw-r--r-- | platform/linuxbsd/detect.py | 12 | ||||
| -rw-r--r-- | platform/linuxbsd/display_server_x11.cpp | 296 | ||||
| -rw-r--r-- | platform/osx/SCsub | 2 | ||||
| -rw-r--r-- | platform/osx/context_gl_osx.mm | 161 | ||||
| -rw-r--r-- | platform/osx/detect.py | 7 | ||||
| -rw-r--r-- | platform/osx/display_server_osx.h | 13 | ||||
| -rw-r--r-- | platform/osx/display_server_osx.mm | 130 | ||||
| -rw-r--r-- | platform/osx/export/export_plugin.cpp | 17 | ||||
| -rw-r--r-- | platform/osx/gl_manager_osx.h (renamed from platform/osx/context_gl_osx.h) | 74 | ||||
| -rw-r--r-- | platform/osx/gl_manager_osx.mm | 233 | ||||
| -rw-r--r-- | platform/osx/os_osx.h | 4 | ||||
| -rw-r--r-- | platform/osx/os_osx.mm | 81 | ||||
| -rw-r--r-- | platform/windows/os_windows.cpp | 4 |
19 files changed, 782 insertions, 279 deletions
diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp index 2faae7f52a..4c45be5210 100644 --- a/platform/android/export/export_plugin.cpp +++ b/platform/android/export/export_plugin.cpp @@ -1612,11 +1612,11 @@ Vector<String> EditorExportPlatformAndroid::get_enabled_abis(const Ref<EditorExp void EditorExportPlatformAndroid::get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) { String driver = ProjectSettings::get_singleton()->get("rendering/driver/driver_name"); - if (driver == "OpenGL3") { + if (driver == "opengl3") { r_features->push_back("etc"); } // FIXME: Review what texture formats are used for Vulkan. - if (driver == "Vulkan") { + if (driver == "vulkan") { r_features->push_back("etc2"); } diff --git a/platform/android/java/app/config.gradle b/platform/android/java/app/config.gradle index 3fafdf8573..2a2850df0f 100644 --- a/platform/android/java/app/config.gradle +++ b/platform/android/java/app/config.gradle @@ -1,8 +1,8 @@ ext.versions = [ androidGradlePlugin: '7.0.3', compileSdk : 30, - minSdk : 19, - targetSdk : 30, + minSdk : 19, // Also update 'platform/android/java/lib/AndroidManifest.xml#minSdkVersion' value + targetSdk : 30, // Also update 'platform/android/java/lib/AndroidManifest.xml#targetSdkVersion' value buildTools : '30.0.3', kotlinVersion : '1.5.10', fragmentVersion : '1.3.6', diff --git a/platform/android/java/lib/AndroidManifest.xml b/platform/android/java/lib/AndroidManifest.xml index 3034794d69..2de62271c4 100644 --- a/platform/android/java/lib/AndroidManifest.xml +++ b/platform/android/java/lib/AndroidManifest.xml @@ -4,6 +4,9 @@ android:versionCode="1" android:versionName="1.0"> + <!-- Should match the mindSdk and targetSdk values in platform/android/java/app/config.gradle --> + <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="30" /> + <application> <!-- Records the version of the Godot library --> diff --git a/platform/android/java/lib/src/org/godotengine/godot/Godot.java b/platform/android/java/lib/src/org/godotengine/godot/Godot.java index 7f6e90f31e..d872d5ed8a 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/Godot.java +++ b/platform/android/java/lib/src/org/godotengine/godot/Godot.java @@ -263,7 +263,7 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC GodotLib.setup(command_line); final String videoDriver = GodotLib.getGlobal("rendering/driver/driver_name"); - if (videoDriver.equals("Vulkan")) { + if (videoDriver.equals("vulkan")) { mRenderView = new GodotVulkanRenderView(activity, this); } else { mRenderView = new GodotGLRenderView(activity, this, xrMode, depth_buffer_bits, diff --git a/platform/iphone/export/export_plugin.cpp b/platform/iphone/export/export_plugin.cpp index 54fb597c62..7450215cfb 100644 --- a/platform/iphone/export/export_plugin.cpp +++ b/platform/iphone/export/export_plugin.cpp @@ -33,7 +33,7 @@ void EditorExportPlatformIOS::get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) { String driver = ProjectSettings::get_singleton()->get("rendering/driver/driver_name"); r_features->push_back("pvrtc"); - if (driver == "Vulkan") { + if (driver == "vulkan") { // FIXME: Review if this is correct. r_features->push_back("etc2"); } @@ -1685,8 +1685,10 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p archive_args.push_back("archive"); archive_args.push_back("-archivePath"); archive_args.push_back(archive_path); - err = OS::get_singleton()->execute("xcodebuild", archive_args); + String archive_str; + err = OS::get_singleton()->execute("xcodebuild", archive_args, &archive_str, nullptr, true); ERR_FAIL_COND_V(err, err); + print_line("xcodebuild (.xcarchive):\n" + archive_str); if (ep.step("Making .ipa", 4)) { return ERR_SKIP; @@ -1700,8 +1702,10 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p export_args.push_back("-allowProvisioningUpdates"); export_args.push_back("-exportPath"); export_args.push_back(dest_dir); - err = OS::get_singleton()->execute("xcodebuild", export_args); + String export_str; + err = OS::get_singleton()->execute("xcodebuild", export_args, &export_str, nullptr, true); ERR_FAIL_COND_V(err, err); + print_line("xcodebuild (.ipa):\n" + export_str); #else print_line(".ipa can only be built on macOS. Leaving Xcode project without building the package."); #endif diff --git a/platform/javascript/export/export_plugin.cpp b/platform/javascript/export/export_plugin.cpp index b4f93b9b44..018dd3b664 100644 --- a/platform/javascript/export/export_plugin.cpp +++ b/platform/javascript/export/export_plugin.cpp @@ -300,9 +300,9 @@ void EditorExportPlatformJavaScript::get_preset_features(const Ref<EditorExportP if (p_preset->get("vram_texture_compression/for_mobile")) { String driver = ProjectSettings::get_singleton()->get("rendering/driver/driver_name"); - if (driver == "OpenGL3") { + if (driver == "opengl3") { r_features->push_back("etc"); - } else if (driver == "Vulkan") { + } else if (driver == "vulkan") { // FIXME: Review if this is correct. r_features->push_back("etc2"); } diff --git a/platform/linuxbsd/detect.py b/platform/linuxbsd/detect.py index a9e8fb64c3..07e16a982b 100644 --- a/platform/linuxbsd/detect.py +++ b/platform/linuxbsd/detect.py @@ -119,8 +119,16 @@ def configure(env): if env["bits"] == "default": env["bits"] = "64" if is64 else "32" - if env["arch"] == "" and platform.machine() == "riscv64": - env["arch"] = "rv64" + machines = { + "riscv64": "rv64", + "ppc64le": "ppc64", + "ppc64": "ppc64", + "ppcle": "ppc", + "ppc": "ppc", + } + + if env["arch"] == "" and platform.machine() in machines: + env["arch"] = machines[platform.machine()] if env["arch"] == "rv64": # G = General-purpose extensions, C = Compression extension (very common). diff --git a/platform/linuxbsd/display_server_x11.cpp b/platform/linuxbsd/display_server_x11.cpp index d00a5794ca..9349d378d0 100644 --- a/platform/linuxbsd/display_server_x11.cpp +++ b/platform/linuxbsd/display_server_x11.cpp @@ -733,6 +733,16 @@ Size2i DisplayServerX11::screen_get_size(int p_screen) const { return _screen_get_rect(p_screen).size; } +bool g_bad_window = false; +int bad_window_error_handler(Display *display, XErrorEvent *error) { + if (error->error_code == BadWindow) { + g_bad_window = true; + } else { + ERR_PRINT("Unhandled XServer error code: " + itos(error->error_code)); + } + return 0; +} + Rect2i DisplayServerX11::screen_get_usable_rect(int p_screen) const { _THREAD_SAFE_METHOD_ @@ -740,21 +750,276 @@ Rect2i DisplayServerX11::screen_get_usable_rect(int p_screen) const { p_screen = window_get_current_screen(); } - // Using Xinerama Extension - int event_base, error_base; - const Bool ext_okay = XineramaQueryExtension(x11_display, &event_base, &error_base); - if (!ext_okay) { - return Rect2i(0, 0, 0, 0); + int screen_count = get_screen_count(); + + // Check if screen is valid. + ERR_FAIL_INDEX_V(p_screen, screen_count, Rect2i(0, 0, 0, 0)); + + bool is_multiscreen = screen_count > 1; + + // Use full monitor size as fallback. + Rect2i rect = _screen_get_rect(p_screen); + + // There's generally only one screen reported by xlib even in multi-screen setup, + // in this case it's just one virtual screen composed of all physical monitors. + int x11_screen_count = ScreenCount(x11_display); + Window x11_window = RootWindow(x11_display, p_screen < x11_screen_count ? p_screen : 0); + + Atom type; + int format = 0; + unsigned long remaining = 0; + + // Find active desktop for the root window. + unsigned int desktop_index = 0; + Atom desktop_prop = XInternAtom(x11_display, "_NET_CURRENT_DESKTOP", True); + if (desktop_prop != None) { + unsigned long desktop_len = 0; + unsigned char *desktop_data = nullptr; + if (XGetWindowProperty(x11_display, x11_window, desktop_prop, 0, LONG_MAX, False, XA_CARDINAL, &type, &format, &desktop_len, &remaining, &desktop_data) == Success) { + if ((format == 32) && (desktop_len > 0) && desktop_data) { + desktop_index = (unsigned int)desktop_data[0]; + } + if (desktop_data) { + XFree(desktop_data); + } + } } - int count; - XineramaScreenInfo *xsi = XineramaQueryScreens(x11_display, &count); + bool use_simple_method = true; + + // First check for GTK work area, which is more accurate for multi-screen setup. + if (is_multiscreen) { + // Use already calculated work area when available. + Atom gtk_workareas_prop = XInternAtom(x11_display, "_GTK_WORKAREAS", False); + if (gtk_workareas_prop != None) { + char gtk_workarea_prop_name[32]; + snprintf(gtk_workarea_prop_name, 32, "_GTK_WORKAREAS_D%d", desktop_index); + Atom gtk_workarea_prop = XInternAtom(x11_display, gtk_workarea_prop_name, True); + if (gtk_workarea_prop != None) { + unsigned long workarea_len = 0; + unsigned char *workarea_data = nullptr; + if (XGetWindowProperty(x11_display, x11_window, gtk_workarea_prop, 0, LONG_MAX, False, XA_CARDINAL, &type, &format, &workarea_len, &remaining, &workarea_data) == Success) { + if ((format == 32) && (workarea_len % 4 == 0) && workarea_data) { + long *rect_data = (long *)workarea_data; + for (uint32_t data_offset = 0; data_offset < workarea_len; data_offset += 4) { + Rect2i workarea_rect; + workarea_rect.position.x = rect_data[data_offset]; + workarea_rect.position.y = rect_data[data_offset + 1]; + workarea_rect.size.x = rect_data[data_offset + 2]; + workarea_rect.size.y = rect_data[data_offset + 3]; + + // Intersect with actual monitor size to find the correct area, + // because areas are not in the same order as screens from Xinerama. + if (rect.grow(-1).intersects(workarea_rect)) { + rect = rect.intersection(workarea_rect); + XFree(workarea_data); + return rect; + } + } + } + } + if (workarea_data) { + XFree(workarea_data); + } + } + } - // Check if screen is valid - ERR_FAIL_INDEX_V(p_screen, count, Rect2i(0, 0, 0, 0)); + // Fallback to calculating work area by hand from struts. + Atom client_list_prop = XInternAtom(x11_display, "_NET_CLIENT_LIST", True); + if (client_list_prop != None) { + unsigned long clients_len = 0; + unsigned char *clients_data = nullptr; + if (XGetWindowProperty(x11_display, x11_window, client_list_prop, 0, LONG_MAX, False, XA_WINDOW, &type, &format, &clients_len, &remaining, &clients_data) == Success) { + if ((format == 32) && (clients_len > 0) && clients_data) { + Window *windows_data = (Window *)clients_data; + + Rect2i desktop_rect; + bool desktop_valid = false; + + // Get full desktop size. + { + Atom desktop_geometry_prop = XInternAtom(x11_display, "_NET_DESKTOP_GEOMETRY", True); + if (desktop_geometry_prop != None) { + unsigned long geom_len = 0; + unsigned char *geom_data = nullptr; + if (XGetWindowProperty(x11_display, x11_window, desktop_geometry_prop, 0, LONG_MAX, False, XA_CARDINAL, &type, &format, &geom_len, &remaining, &geom_data) == Success) { + if ((format == 32) && (geom_len >= 2) && geom_data) { + desktop_valid = true; + long *size_data = (long *)geom_data; + desktop_rect.size.x = size_data[0]; + desktop_rect.size.y = size_data[1]; + } + } + if (geom_data) { + XFree(geom_data); + } + } + } + + // Get full desktop position. + if (desktop_valid) { + Atom desktop_viewport_prop = XInternAtom(x11_display, "_NET_DESKTOP_VIEWPORT", True); + if (desktop_viewport_prop != None) { + unsigned long viewport_len = 0; + unsigned char *viewport_data = nullptr; + if (XGetWindowProperty(x11_display, x11_window, desktop_viewport_prop, 0, LONG_MAX, False, XA_CARDINAL, &type, &format, &viewport_len, &remaining, &viewport_data) == Success) { + if ((format == 32) && (viewport_len >= 2) && viewport_data) { + desktop_valid = true; + long *pos_data = (long *)viewport_data; + desktop_rect.position.x = pos_data[0]; + desktop_rect.position.y = pos_data[1]; + } + } + if (viewport_data) { + XFree(viewport_data); + } + } + } + + if (desktop_valid) { + use_simple_method = false; + + // Handle bad window errors silently because there's no other way to check + // that one of the windows has been destroyed in the meantime. + int (*oldHandler)(Display *, XErrorEvent *) = XSetErrorHandler(&bad_window_error_handler); + + for (unsigned long win_index = 0; win_index < clients_len; ++win_index) { + g_bad_window = false; + + // Remove strut size from desktop size to get a more accurate result. + bool strut_found = false; + unsigned long strut_len = 0; + unsigned char *strut_data = nullptr; + Atom strut_partial_prop = XInternAtom(x11_display, "_NET_WM_STRUT_PARTIAL", True); + if (strut_partial_prop != None) { + if (XGetWindowProperty(x11_display, windows_data[win_index], strut_partial_prop, 0, LONG_MAX, False, XA_CARDINAL, &type, &format, &strut_len, &remaining, &strut_data) == Success) { + strut_found = true; + } + } + // Fallback to older strut property. + if (!g_bad_window && !strut_found) { + Atom strut_prop = XInternAtom(x11_display, "_NET_WM_STRUT", True); + if (strut_prop != None) { + if (XGetWindowProperty(x11_display, windows_data[win_index], strut_prop, 0, LONG_MAX, False, XA_CARDINAL, &type, &format, &strut_len, &remaining, &strut_data) == Success) { + strut_found = true; + } + } + } + if (!g_bad_window && strut_found && (format == 32) && (strut_len >= 4) && strut_data) { + long *struts = (long *)strut_data; + + long left = struts[0]; + long right = struts[1]; + long top = struts[2]; + long bottom = struts[3]; + + long left_start_y, left_end_y, right_start_y, right_end_y; + long top_start_x, top_end_x, bottom_start_x, bottom_end_x; + + if (strut_len >= 12) { + left_start_y = struts[4]; + left_end_y = struts[5]; + right_start_y = struts[6]; + right_end_y = struts[7]; + top_start_x = struts[8]; + top_end_x = struts[9]; + bottom_start_x = struts[10]; + bottom_end_x = struts[11]; + } else { + left_start_y = 0; + left_end_y = desktop_rect.size.y; + right_start_y = 0; + right_end_y = desktop_rect.size.y; + top_start_x = 0; + top_end_x = desktop_rect.size.x; + bottom_start_x = 0; + bottom_end_x = desktop_rect.size.x; + } + + const Point2i &pos = desktop_rect.position; + const Size2i &size = desktop_rect.size; + + Rect2i left_rect(pos.x, pos.y + left_start_y, left, left_end_y - left_start_y); + if (left_rect.size.x > 0) { + Rect2i intersection = rect.intersection(left_rect); + if (!intersection.has_no_area() && intersection.size.x < rect.size.x) { + rect.position.x = left_rect.size.x; + rect.size.x = rect.size.x - intersection.size.x; + } + } + + Rect2i right_rect(pos.x + size.x - right, pos.y + right_start_y, right, right_end_y - right_start_y); + if (right_rect.size.x > 0) { + Rect2i intersection = rect.intersection(right_rect); + if (!intersection.has_no_area() && right_rect.size.x < rect.size.x) { + rect.size.x = intersection.position.x - rect.position.x; + } + } + + Rect2i top_rect(pos.x + top_start_x, pos.y, top_end_x - top_start_x, top); + if (top_rect.size.y > 0) { + Rect2i intersection = rect.intersection(top_rect); + if (!intersection.has_no_area() && intersection.size.y < rect.size.y) { + rect.position.y = top_rect.size.y; + rect.size.y = rect.size.y - intersection.size.y; + } + } + + Rect2i bottom_rect(pos.x + bottom_start_x, pos.y + size.y - bottom, bottom_end_x - bottom_start_x, bottom); + if (bottom_rect.size.y > 0) { + Rect2i intersection = rect.intersection(bottom_rect); + if (!intersection.has_no_area() && right_rect.size.y < rect.size.y) { + rect.size.y = intersection.position.y - rect.position.y; + } + } + } + if (strut_data) { + XFree(strut_data); + } + } + + // Restore default error handler. + XSetErrorHandler(oldHandler); + } + } + } + if (clients_data) { + XFree(clients_data); + } + } + } + + // Single screen or fallback for multi screen. + if (use_simple_method) { + // Get desktop available size from the global work area. + Atom workarea_prop = XInternAtom(x11_display, "_NET_WORKAREA", True); + if (workarea_prop != None) { + unsigned long workarea_len = 0; + unsigned char *workarea_data = nullptr; + if (XGetWindowProperty(x11_display, x11_window, workarea_prop, 0, LONG_MAX, False, XA_CARDINAL, &type, &format, &workarea_len, &remaining, &workarea_data) == Success) { + if ((format == 32) && (workarea_len >= ((desktop_index + 1) * 4)) && workarea_data) { + long *rect_data = (long *)workarea_data; + int data_offset = desktop_index * 4; + Rect2i workarea_rect; + workarea_rect.position.x = rect_data[data_offset]; + workarea_rect.position.y = rect_data[data_offset + 1]; + workarea_rect.size.x = rect_data[data_offset + 2]; + workarea_rect.size.y = rect_data[data_offset + 3]; + + // Intersect with actual monitor size to get a proper approximation in multi-screen setup. + if (!is_multiscreen) { + rect = workarea_rect; + } else if (rect.intersects(workarea_rect)) { + rect = rect.intersection(workarea_rect); + } + } + } + if (workarea_data) { + XFree(workarea_data); + } + } + } - Rect2i rect = Rect2i(xsi[p_screen].x_org, xsi[p_screen].y_org, xsi[p_screen].width, xsi[p_screen].height); - XFree(xsi); return rect; } @@ -3420,11 +3685,18 @@ void DisplayServerX11::process_events() { } break; case KeyPress: case KeyRelease: { +#ifdef DISPLAY_SERVER_X11_DEBUG_LOGS_ENABLED + if (event.type == KeyPress) { + DEBUG_LOG_X11("[%u] KeyPress window=%lu (%u), keycode=%u, time=%lu \n", frame, event.xkey.window, window_id, event.xkey.keycode, event.xkey.time); + } else { + DEBUG_LOG_X11("[%u] KeyRelease window=%lu (%u), keycode=%u, time=%lu \n", frame, event.xkey.window, window_id, event.xkey.keycode, event.xkey.time); + } +#endif last_timestamp = event.xkey.time; // key event is a little complex, so // it will be handled in its own function. - _handle_key_event(window_id, (XKeyEvent *)&event, events, event_index); + _handle_key_event(window_id, &event.xkey, events, event_index); } break; case SelectionNotify: diff --git a/platform/osx/SCsub b/platform/osx/SCsub index 46c13d8550..8ba106d1c2 100644 --- a/platform/osx/SCsub +++ b/platform/osx/SCsub @@ -13,7 +13,7 @@ files = [ "dir_access_osx.mm", "joypad_osx.cpp", "vulkan_context_osx.mm", - "context_gl_osx.mm", + "gl_manager_osx.mm", ] prog = env.add_program("#bin/godot", files) diff --git a/platform/osx/context_gl_osx.mm b/platform/osx/context_gl_osx.mm deleted file mode 100644 index eab9d8dc0c..0000000000 --- a/platform/osx/context_gl_osx.mm +++ /dev/null @@ -1,161 +0,0 @@ -/*************************************************************************/ -/* context_gl_osx.mm */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "context_gl_osx.h" - -#if defined(GLES3_ENABLED) || defined(GLES_ENABLED) - -void ContextGL_OSX::release_current() { - [NSOpenGLContext clearCurrentContext]; -} - -void ContextGL_OSX::make_current() { - [context makeCurrentContext]; -} - -void ContextGL_OSX::update() { - [context update]; -} - -void ContextGL_OSX::set_opacity(GLint p_opacity) { - [context setValues:&p_opacity forParameter:NSOpenGLCPSurfaceOpacity]; -} - -int ContextGL_OSX::get_window_width() { - return OS::get_singleton()->get_video_mode().width; -} - -int ContextGL_OSX::get_window_height() { - return OS::get_singleton()->get_video_mode().height; -} - -void ContextGL_OSX::swap_buffers() { - [context flushBuffer]; -} - -void ContextGL_OSX::set_use_vsync(bool p_use) { - CGLContextObj ctx = CGLGetCurrentContext(); - if (ctx) { - GLint swapInterval = p_use ? 1 : 0; - CGLSetParameter(ctx, kCGLCPSwapInterval, &swapInterval); - use_vsync = p_use; - } -} - -bool ContextGL_OSX::is_using_vsync() const { - return use_vsync; -} - -Error ContextGL_OSX::initialize() { - framework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl")); - ERR_FAIL_COND_V(!framework, ERR_CANT_CREATE); - - unsigned int attributeCount = 0; - - // OS X needs non-zero color size, so set reasonable values - int colorBits = 32; - - // Fail if a robustness strategy was requested - -#define ADD_ATTR(x) \ - { attributes[attributeCount++] = x; } -#define ADD_ATTR2(x, y) \ - { \ - ADD_ATTR(x); \ - ADD_ATTR(y); \ - } - - // Arbitrary array size here - NSOpenGLPixelFormatAttribute attributes[40]; - - ADD_ATTR(NSOpenGLPFADoubleBuffer); - ADD_ATTR(NSOpenGLPFAClosestPolicy); - - if (!gles3_context) { - ADD_ATTR2(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersionLegacy); - } else { - //we now need OpenGL 3 or better, maybe even change this to 3_3Core ? - ADD_ATTR2(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core); - } - - ADD_ATTR2(NSOpenGLPFAColorSize, colorBits); - - /* - if (fbconfig->alphaBits > 0) - ADD_ATTR2(NSOpenGLPFAAlphaSize, fbconfig->alphaBits); -*/ - - ADD_ATTR2(NSOpenGLPFADepthSize, 24); - - ADD_ATTR2(NSOpenGLPFAStencilSize, 8); - - /* - if (fbconfig->stereo) - ADD_ATTR(NSOpenGLPFAStereo); -*/ - - /* - if (fbconfig->samples > 0) { - ADD_ATTR2(NSOpenGLPFASampleBuffers, 1); - ADD_ATTR2(NSOpenGLPFASamples, fbconfig->samples); - } -*/ - - // NOTE: All NSOpenGLPixelFormats on the relevant cards support sRGB - // framebuffer, so there's no need (and no way) to request it - - ADD_ATTR(0); - -#undef ADD_ATTR -#undef ADD_ATTR2 - - pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes]; - ERR_FAIL_COND_V(pixelFormat == nil, ERR_CANT_CREATE); - - context = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:nil]; - - ERR_FAIL_COND_V(context == nil, ERR_CANT_CREATE); - - [context setView:window_view]; - - [context makeCurrentContext]; - - return OK; -} - -ContextGL_OSX::ContextGL_OSX(id p_view, bool p_gles3_context) { - gles3_context = p_gles3_context; - window_view = p_view; - use_vsync = false; -} - -ContextGL_OSX::~ContextGL_OSX() {} - -#endif diff --git a/platform/osx/detect.py b/platform/osx/detect.py index d9b55631cd..6bd79c7d4f 100644 --- a/platform/osx/detect.py +++ b/platform/osx/detect.py @@ -183,10 +183,13 @@ def configure(env): ) env.Append(LIBS=["pthread", "z"]) + if env["opengl3"]: + env.Append(CPPDEFINES=["GLES_ENABLED", "GLES3_ENABLED"]) + env.Append(CCFLAGS=["-Wno-deprecated-declarations"]) # Disable deprecation warnings + env.Append(LINKFLAGS=["-framework", "OpenGL"]) + if env["vulkan"]: env.Append(CPPDEFINES=["VULKAN_ENABLED"]) env.Append(LINKFLAGS=["-framework", "Metal", "-framework", "QuartzCore", "-framework", "IOSurface"]) if not env["use_volk"]: env.Append(LINKFLAGS=["-L$VULKAN_SDK_PATH/MoltenVK/MoltenVK.xcframework/macos-arm64_x86_64/", "-lMoltenVK"]) - - # env.Append(CPPDEFINES=['GLES_ENABLED', 'GLES3_ENABLED']) diff --git a/platform/osx/display_server_osx.h b/platform/osx/display_server_osx.h index 96baeb4dec..c45b470078 100644 --- a/platform/osx/display_server_osx.h +++ b/platform/osx/display_server_osx.h @@ -37,8 +37,7 @@ #include "servers/display_server.h" #if defined(GLES3_ENABLED) -#include "context_gl_osx.h" -//TODO - reimplement OpenGLES +#include "gl_manager_osx.h" #endif #if defined(VULKAN_ENABLED) @@ -65,11 +64,11 @@ public: void _menu_callback(id p_sender); #if defined(GLES3_ENABLED) - ContextGL_OSX *context_gles2; + GLManager_OSX *gl_manager = nullptr; #endif #if defined(VULKAN_ENABLED) - VulkanContextOSX *context_vulkan; - RenderingDeviceVulkan *rendering_device_vulkan; + VulkanContextOSX *context_vulkan = nullptr; + RenderingDeviceVulkan *rendering_device_vulkan = nullptr; #endif const NSMenu *_get_menu_root(const String &p_menu_root) const; @@ -109,9 +108,6 @@ public: Vector<Vector2> mpath; -#if defined(GLES3_ENABLED) - ContextGL_OSX *context_gles2 = nullptr; -#endif Point2i mouse_pos; Size2i min_size; @@ -287,6 +283,7 @@ public: virtual void window_attach_instance_id(ObjectID p_instance, WindowID p_window = MAIN_WINDOW_ID) override; virtual ObjectID window_get_attached_instance_id(WindowID p_window = MAIN_WINDOW_ID) const override; + virtual void gl_window_make_current(DisplayServer::WindowID p_window_id) override; virtual void window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window = MAIN_WINDOW_ID) override; virtual DisplayServer::VSyncMode window_get_vsync_mode(WindowID p_vsync_mode) const override; diff --git a/platform/osx/display_server_osx.mm b/platform/osx/display_server_osx.mm index d89e64cd7d..03301af0af 100644 --- a/platform/osx/display_server_osx.mm +++ b/platform/osx/display_server_osx.mm @@ -46,7 +46,7 @@ #include <IOKit/hid/IOHIDLib.h> #if defined(GLES3_ENABLED) -//TODO - reimplement OpenGLES +#include "drivers/gles3/rasterizer_gles3.h" #import <AppKit/NSOpenGLView.h> #endif @@ -167,8 +167,8 @@ static NSCursor *_cursorFromSelector(SEL selector, SEL fallback = nil) { } #if defined(GLES3_ENABLED) - if (DS_OSX->rendering_driver == "opengl_es") { - //TODO - reimplement OpenGLES + if (DS_OSX->rendering_driver == "opengl3") { + DS_OSX->gl_manager->window_destroy(window_id); } #endif #ifdef VULKAN_ENABLED @@ -272,8 +272,8 @@ static NSCursor *_cursorFromSelector(SEL selector, SEL fallback = nil) { } #if defined(GLES3_ENABLED) - if (DS_OSX->rendering_driver == "opengl_es") { - //TODO - reimplement OpenGLES + if (DS_OSX->rendering_driver == "opengl3") { + DS_OSX->gl_manager->window_resize(window_id, wd.size.width, wd.size.height); } #endif #if defined(VULKAN_ENABLED) @@ -289,14 +289,6 @@ static NSCursor *_cursorFromSelector(SEL selector, SEL fallback = nil) { Callable::CallError ce; wd.rect_changed_callback.call((const Variant **)&sizep, 1, ret, ce); } - - if (OS_OSX::get_singleton()->get_main_loop()) { - Main::force_redraw(); - //Event retrieval blocks until resize is over. Call Main::iteration() directly. - if (!Main::is_iterating()) { //avoid cyclic loop - Main::iteration(); - } - } } - (void)windowDidMove:(NSNotification *)notification { @@ -377,7 +369,12 @@ static NSCursor *_cursorFromSelector(SEL selector, SEL fallback = nil) { /* GodotContentView */ /*************************************************************************/ +#if defined(GLES3_ENABLED) +@interface GodotContentView : NSOpenGLView <NSTextInputClient> { +#else @interface GodotContentView : NSView <NSTextInputClient> { +#endif + DisplayServerOSX::WindowID window_id; NSTrackingArea *trackingArea; NSMutableAttributedString *markedText; @@ -405,12 +402,6 @@ static NSCursor *_cursorFromSelector(SEL selector, SEL fallback = nil) { } - (CALayer *)makeBackingLayer { -#if defined(GLES3_ENABLED) - if (DS_OSX->rendering_driver == "opengl_es") { - CALayer *layer = [[NSOpenGLLayer class] layer]; - return layer; - } -#endif #if defined(VULKAN_ENABLED) if (DS_OSX->rendering_driver == "vulkan") { CALayer *layer = [[CAMetalLayer class] layer]; @@ -422,9 +413,8 @@ static NSCursor *_cursorFromSelector(SEL selector, SEL fallback = nil) { - (void)updateLayer { #if defined(GLES3_ENABLED) - if (DS_OSX->rendering_driver == "opengl_es") { - [super updateLayer]; - //TODO - reimplement OpenGLES + if (DS_OSX->rendering_driver == "opengl3") { + DS_OSX->gl_manager->window_update(window_id); } #endif #if defined(VULKAN_ENABLED) @@ -2587,7 +2577,7 @@ void DisplayServerOSX::_set_window_per_pixel_transparency_enabled(bool p_enabled } #endif #if defined(GLES3_ENABLED) - if (rendering_driver == "opengl_es") { + if (rendering_driver == "opengl3") { //TODO - reimplement OpenGLES } #endif @@ -2606,14 +2596,14 @@ void DisplayServerOSX::_set_window_per_pixel_transparency_enabled(bool p_enabled } #endif #if defined(GLES3_ENABLED) - if (rendering_driver == "opengl_es") { + if (rendering_driver == "opengl3") { //TODO - reimplement OpenGLES } #endif wd.layered_window = false; } #if defined(GLES3_ENABLED) - if (rendering_driver == "opengl_es") { + if (rendering_driver == "opengl3") { //TODO - reimplement OpenGLES } #endif @@ -3455,18 +3445,31 @@ void DisplayServerOSX::set_icon(const Ref<Image> &p_icon) { void DisplayServerOSX::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) { _THREAD_SAFE_METHOD_ +#if defined(GLES3_ENABLED) + if (rendering_driver == "opengl3") { + gl_manager->swap_buffers(); + } +#endif #if defined(VULKAN_ENABLED) - context_vulkan->set_vsync_mode(p_window, p_vsync_mode); + if (rendering_driver == "vulkan") { + context_vulkan->set_vsync_mode(p_window, p_vsync_mode); + } #endif } DisplayServer::VSyncMode DisplayServerOSX::window_get_vsync_mode(WindowID p_window) const { _THREAD_SAFE_METHOD_ +#if defined(GLES3_ENABLED) + if (rendering_driver == "opengl3") { + return (gl_manager->is_using_vsync() ? DisplayServer::VSyncMode::VSYNC_ENABLED : DisplayServer::VSyncMode::VSYNC_DISABLED); + } +#endif #if defined(VULKAN_ENABLED) - return context_vulkan->get_vsync_mode(p_window); -#else - return DisplayServer::VSYNC_ENABLED; + if (rendering_driver == "vulkan") { + return context_vulkan->get_vsync_mode(p_window); + } #endif + return DisplayServer::VSYNC_ENABLED; } Vector<String> DisplayServerOSX::get_rendering_drivers_func() { @@ -3476,12 +3479,18 @@ Vector<String> DisplayServerOSX::get_rendering_drivers_func() { drivers.push_back("vulkan"); #endif #if defined(GLES3_ENABLED) - drivers.push_back("opengl_es"); + drivers.push_back("opengl3"); #endif return drivers; } +void DisplayServerOSX::gl_window_make_current(DisplayServer::WindowID p_window_id) { +#if defined(GLES3_ENABLED) + gl_manager->window_make_current(p_window_id); +#endif +} + Point2i DisplayServerOSX::ime_get_selection() const { return im_selection; } @@ -3522,7 +3531,7 @@ ObjectID DisplayServerOSX::window_get_attached_instance_id(WindowID p_window) co DisplayServer *DisplayServerOSX::create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) { DisplayServer *ds = memnew(DisplayServerOSX(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_resolution, r_error)); if (r_error != OK) { - OS::get_singleton()->alert("Your video card driver does not support any of the supported Metal versions.", "Unable to initialize Video driver"); + OS::get_singleton()->alert("Your video card driver does not support any of the supported Vulkan or OpenGL versions.", "Unable to initialize Video driver"); } return ds; } @@ -3580,8 +3589,11 @@ DisplayServerOSX::WindowID DisplayServerOSX::_create_window(WindowMode p_mode, V } #endif #if defined(GLES3_ENABLED) - if (rendering_driver == "opengl_es") { - //TODO - reimplement OpenGLES + if (rendering_driver == "opengl3") { + if (gl_manager) { + Error err = gl_manager->window_create(window_id_counter, wd.window_view, p_rect.size.width, p_rect.size.height); + ERR_FAIL_COND_V_MSG(err != OK, INVALID_WINDOW_ID, "Can't create an OpenGL context"); + } } #endif id = window_id_counter++; @@ -3601,8 +3613,8 @@ DisplayServerOSX::WindowID DisplayServerOSX::_create_window(WindowMode p_mode, V } #if defined(GLES3_ENABLED) - if (rendering_driver == "opengl_es") { - //TODO - reimplement OpenGLES + if (rendering_driver == "opengl3") { + gl_manager->window_resize(id, wd.size.width, wd.size.height); } #endif #if defined(VULKAN_ENABLED) @@ -3654,15 +3666,15 @@ void DisplayServerOSX::_dispatch_input_event(const Ref<InputEvent> &p_event) { } void DisplayServerOSX::release_rendering_thread() { - //TODO - reimplement OpenGLES } void DisplayServerOSX::make_rendering_thread() { - //TODO - reimplement OpenGLES } void DisplayServerOSX::swap_buffers() { - //TODO - reimplement OpenGLES +#if defined(GLES3_ENABLED) + gl_manager->swap_buffers(); +#endif } void DisplayServerOSX::console_set_visible(bool p_enabled) { @@ -3753,14 +3765,17 @@ DisplayServerOSX::DisplayServerOSX(const String &p_rendering_driver, WindowMode //TODO - do Vulkan and OpenGL support checks, driver selection and fallback rendering_driver = p_rendering_driver; -#ifndef _MSC_VER -#warning Forcing vulkan rendering driver because OpenGL not implemented yet -#endif - rendering_driver = "vulkan"; - #if defined(GLES3_ENABLED) - if (rendering_driver == "opengl_es") { - //TODO - reimplement OpenGLES + if (rendering_driver == "opengl3") { + GLManager_OSX::ContextType opengl_api_type = GLManager_OSX::GLES_3_0_COMPATIBLE; + gl_manager = memnew(GLManager_OSX(opengl_api_type)); + if (gl_manager->initialize() != OK) { + memdelete(gl_manager); + gl_manager = nullptr; + r_error = ERR_UNAVAILABLE; + ERR_FAIL_MSG("Could not initialize OpenGL"); + return; + } } #endif #if defined(VULKAN_ENABLED) @@ -3788,8 +3803,8 @@ DisplayServerOSX::DisplayServerOSX(const String &p_rendering_driver, WindowMode show_window(MAIN_WINDOW_ID); #if defined(GLES3_ENABLED) - if (rendering_driver == "opengl_es") { - //TODO - reimplement OpenGLES + if (rendering_driver == "opengl3") { + RasterizerGLES3::make_current(); } #endif #if defined(VULKAN_ENABLED) @@ -3821,20 +3836,21 @@ DisplayServerOSX::~DisplayServerOSX() { //destroy drivers #if defined(GLES3_ENABLED) - if (rendering_driver == "opengl_es") { - //TODO - reimplement OpenGLES + if (gl_manager) { + memdelete(gl_manager); + gl_manager = nullptr; } #endif #if defined(VULKAN_ENABLED) - if (rendering_driver == "vulkan") { - if (rendering_device_vulkan) { - rendering_device_vulkan->finalize(); - memdelete(rendering_device_vulkan); - } + if (rendering_device_vulkan) { + rendering_device_vulkan->finalize(); + memdelete(rendering_device_vulkan); + rendering_device_vulkan = nullptr; + } - if (context_vulkan) { - memdelete(context_vulkan); - } + if (context_vulkan) { + memdelete(context_vulkan); + context_vulkan = nullptr; } #endif diff --git a/platform/osx/export/export_plugin.cpp b/platform/osx/export/export_plugin.cpp index 1e80dcd97b..a88f7bb332 100644 --- a/platform/osx/export/export_plugin.cpp +++ b/platform/osx/export/export_plugin.cpp @@ -1048,8 +1048,21 @@ void EditorExportPlatformOSX::_zip_folder_recursive(zipFile &p_zip, const String 0x0314, // "version made by", 0x03 - Unix, 0x14 - ZIP specification version 2.0, required to store Unix file permissions 0); - Vector<uint8_t> array = FileAccess::get_file_as_array(dir.plus_file(f)); - zipWriteInFileInZip(p_zip, array.ptr(), array.size()); + FileAccessRef fa = FileAccess::open(dir.plus_file(f), FileAccess::READ); + if (!fa) { + ERR_FAIL_MSG("Can't open file to read from path '" + String(dir.plus_file(f)) + "'."); + } + const int bufsize = 16384; + uint8_t buf[bufsize]; + + while (true) { + uint64_t got = fa->get_buffer(buf, bufsize); + if (got == 0) { + break; + } + zipWriteInFileInZip(p_zip, buf, got); + } + zipCloseFileInZip(p_zip); } } diff --git a/platform/osx/context_gl_osx.h b/platform/osx/gl_manager_osx.h index 77bae3247d..f86bc805c1 100644 --- a/platform/osx/context_gl_osx.h +++ b/platform/osx/gl_manager_osx.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* context_gl_osx.h */ +/* gl_manager_osx.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,47 +28,79 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef CONTEXT_GL_OSX_H -#define CONTEXT_GL_OSX_H +#ifndef GL_MANAGER_OSX_H +#define GL_MANAGER_OSX_H -#if defined(GLES3_ENABLED) || defined(GLES_ENABLED) +#if defined(OSX_ENABLED) && defined(GLES3_ENABLED) #include "core/error/error_list.h" #include "core/os/os.h" +#include "core/templates/local_vector.h" +#include "servers/display_server.h" #include <AppKit/AppKit.h> #include <ApplicationServices/ApplicationServices.h> #include <CoreVideo/CoreVideo.h> -class ContextGL_OSX { - bool gles3_context; - bool use_vsync; +class GLManager_OSX { +public: + enum ContextType { + GLES_3_0_COMPATIBLE, + }; + +private: + struct GLWindow { + GLWindow() { in_use = false; } + bool in_use; + + DisplayServer::WindowID window_id; + int width; + int height; + + id window_view; + NSOpenGLContext *context; + }; + + LocalVector<GLWindow> _windows; + + NSOpenGLContext *_shared_context = nullptr; + GLWindow *_current_window; + + Error _create_context(GLWindow &win); + void _internal_set_current_window(GLWindow *p_win); - void *framework; - id window_view; - NSOpenGLPixelFormat *pixelFormat; - NSOpenGLContext *context; + GLWindow &get_window(unsigned int id) { return _windows[id]; } + const GLWindow &get_window(unsigned int id) const { return _windows[id]; } + + bool use_vsync; + ContextType context_type; public: - void release_current(); + Error window_create(DisplayServer::WindowID p_window_id, id p_view, int p_width, int p_height); + void window_destroy(DisplayServer::WindowID p_window_id); + void window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height); + + // get directly from the cached GLWindow + int window_get_width(DisplayServer::WindowID p_window_id = 0); + int window_get_height(DisplayServer::WindowID p_window_id = 0); + void release_current(); void make_current(); - void update(); + void swap_buffers(); - void set_opacity(GLint p_opacity); + void window_make_current(DisplayServer::WindowID p_window_id); - int get_window_width(); - int get_window_height(); - void swap_buffers(); + void window_update(DisplayServer::WindowID p_window_id); Error initialize(); void set_use_vsync(bool p_use); bool is_using_vsync() const; - ContextGL_OSX(id p_view, bool p_gles3_context); - ~ContextGL_OSX(); + GLManager_OSX(ContextType p_context_type); + ~GLManager_OSX(); }; -#endif -#endif +#endif // defined(OSX_ENABLED) && defined(GLES3_ENABLED) + +#endif // GL_MANAGER_OSX_H diff --git a/platform/osx/gl_manager_osx.mm b/platform/osx/gl_manager_osx.mm new file mode 100644 index 0000000000..cce58530ee --- /dev/null +++ b/platform/osx/gl_manager_osx.mm @@ -0,0 +1,233 @@ +/*************************************************************************/ +/* gl_manager_osx.mm */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "gl_manager_osx.h" + +#ifdef OSX_ENABLED +#ifdef GLES3_ENABLED + +#include <stdio.h> +#include <stdlib.h> + +Error GLManager_OSX::_create_context(GLWindow &win) { + NSOpenGLPixelFormatAttribute attributes[] = { + NSOpenGLPFADoubleBuffer, + NSOpenGLPFAClosestPolicy, + NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core, + NSOpenGLPFAColorSize, 32, + NSOpenGLPFADepthSize, 24, + NSOpenGLPFAStencilSize, 8, + 0 + }; + + NSOpenGLPixelFormat *pixel_format = [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes]; + ERR_FAIL_COND_V(pixel_format == nil, ERR_CANT_CREATE); + + win.context = [[NSOpenGLContext alloc] initWithFormat:pixel_format shareContext:_shared_context]; + ERR_FAIL_COND_V(win.context == nil, ERR_CANT_CREATE); + if (_shared_context == nullptr) { + _shared_context = win.context; + } + + [win.context setView:win.window_view]; + [win.context makeCurrentContext]; + + return OK; +} + +Error GLManager_OSX::window_create(DisplayServer::WindowID p_window_id, id p_view, int p_width, int p_height) { + if (p_window_id >= (int)_windows.size()) { + _windows.resize(p_window_id + 1); + } + + GLWindow &win = _windows[p_window_id]; + win.in_use = true; + win.window_id = p_window_id; + win.width = p_width; + win.height = p_height; + win.window_view = p_view; + + if (_create_context(win) != OK) { + _windows.remove(_windows.size() - 1); + return FAILED; + } + + window_make_current(_windows.size() - 1); + + return OK; +} + +void GLManager_OSX::_internal_set_current_window(GLWindow *p_win) { + _current_window = p_win; +} + +void GLManager_OSX::window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height) { + if (p_window_id == -1) { + return; + } + + GLWindow &win = _windows[p_window_id]; + if (!win.in_use) { + return; + } + + win.width = p_width; + win.height = p_height; + + GLint dim[2]; + dim[0] = p_width; + dim[1] = p_height; + CGLSetParameter((CGLContextObj)[win.context CGLContextObj], kCGLCPSurfaceBackingSize, &dim[0]); + CGLEnable((CGLContextObj)[win.context CGLContextObj], kCGLCESurfaceBackingSize); + if (OS::get_singleton()->is_hidpi_allowed()) { + [win.window_view setWantsBestResolutionOpenGLSurface:YES]; + } else { + [win.window_view setWantsBestResolutionOpenGLSurface:NO]; + } + + [win.context update]; +} + +int GLManager_OSX::window_get_width(DisplayServer::WindowID p_window_id) { + return get_window(p_window_id).width; +} + +int GLManager_OSX::window_get_height(DisplayServer::WindowID p_window_id) { + return get_window(p_window_id).height; +} + +void GLManager_OSX::window_destroy(DisplayServer::WindowID p_window_id) { + GLWindow &win = get_window(p_window_id); + win.in_use = false; + + if (_current_window == &win) { + _current_window = nullptr; + } +} + +void GLManager_OSX::release_current() { + if (!_current_window) { + return; + } + + [NSOpenGLContext clearCurrentContext]; +} + +void GLManager_OSX::window_make_current(DisplayServer::WindowID p_window_id) { + if (p_window_id == -1) { + return; + } + + GLWindow &win = _windows[p_window_id]; + if (!win.in_use) { + return; + } + + if (&win == _current_window) { + return; + } + + [win.context makeCurrentContext]; + + _internal_set_current_window(&win); +} + +void GLManager_OSX::make_current() { + if (!_current_window) { + return; + } + if (!_current_window->in_use) { + WARN_PRINT("current window not in use!"); + return; + } + [_current_window->context makeCurrentContext]; +} + +void GLManager_OSX::swap_buffers() { + // NO NEED TO CALL SWAP BUFFERS for each window... + // see https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glXSwapBuffers.xml + + if (!_current_window) { + return; + } + if (!_current_window->in_use) { + WARN_PRINT("current window not in use!"); + return; + } + [_current_window->context flushBuffer]; +} + +void GLManager_OSX::window_update(DisplayServer::WindowID p_window_id) { + if (p_window_id == -1) { + return; + } + + GLWindow &win = _windows[p_window_id]; + if (!win.in_use) { + return; + } + + if (&win == _current_window) { + return; + } + + [win.context update]; +} + +Error GLManager_OSX::initialize() { + return OK; +} + +void GLManager_OSX::set_use_vsync(bool p_use) { + use_vsync = p_use; + CGLContextObj ctx = CGLGetCurrentContext(); + if (ctx) { + GLint swapInterval = p_use ? 1 : 0; + CGLSetParameter(ctx, kCGLCPSwapInterval, &swapInterval); + use_vsync = p_use; + } +} + +bool GLManager_OSX::is_using_vsync() const { + return use_vsync; +} + +GLManager_OSX::GLManager_OSX(ContextType p_context_type) { + context_type = p_context_type; + use_vsync = false; + _current_window = nullptr; +} + +GLManager_OSX::~GLManager_OSX() { + release_current(); +} + +#endif // GLES3_ENABLED +#endif // OSX diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h index a52436a70a..7e02f4e154 100644 --- a/platform/osx/os_osx.h +++ b/platform/osx/os_osx.h @@ -57,6 +57,8 @@ class OS_OSX : public OS_Unix { MainLoop *main_loop; + static void pre_wait_observer_cb(CFRunLoopObserverRef p_observer, CFRunLoopActivity p_activiy, void *p_context); + public: String open_with_filename; @@ -92,6 +94,8 @@ public: String get_locale() const override; virtual String get_executable_path() const override; + virtual Error create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id = nullptr) override; + virtual Error create_instance(const List<String> &p_arguments, ProcessID *r_child_id = nullptr) override; virtual String get_unique_id() const override; //++ diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm index 489cbe074b..45a81be80a 100644 --- a/platform/osx/os_osx.mm +++ b/platform/osx/os_osx.mm @@ -491,14 +491,89 @@ String OS_OSX::get_executable_path() const { } } +Error OS_OSX::create_instance(const List<String> &p_arguments, ProcessID *r_child_id) { + // If executable is bundled, always execute editor instances as an app bundle to ensure app window is registered and activated correctly. + NSString *nsappname = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"]; + if (nsappname != nil) { + String path; + path.parse_utf8([[[NSBundle mainBundle] bundlePath] UTF8String]); + return create_process(path, p_arguments, r_child_id); + } else { + return create_process(get_executable_path(), p_arguments, r_child_id); + } +} + +Error OS_OSX::create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id) { + if (@available(macOS 10.15, *)) { + // Use NSWorkspace if path is an .app bundle. + NSURL *url = [NSURL fileURLWithPath:@(p_path.utf8().get_data())]; + NSBundle *bundle = [NSBundle bundleWithURL:url]; + if (bundle) { + NSMutableArray *arguments = [[NSMutableArray alloc] init]; + for (const List<String>::Element *E = p_arguments.front(); E; E = E->next()) { + [arguments addObject:[NSString stringWithUTF8String:E->get().utf8().get_data()]]; + } + NSWorkspaceOpenConfiguration *configuration = [[NSWorkspaceOpenConfiguration alloc] init]; + [configuration setArguments:arguments]; + [configuration setCreatesNewApplicationInstance:YES]; + __block dispatch_semaphore_t lock = dispatch_semaphore_create(0); + __block Error err = ERR_TIMEOUT; + __block pid_t pid = 0; + [[NSWorkspace sharedWorkspace] openApplicationAtURL:url + configuration:configuration + completionHandler:^(NSRunningApplication *app, NSError *error) { + if (error) { + err = ERR_CANT_FORK; + NSLog(@"Failed to execute: %@", error.localizedDescription); + } else { + pid = [app processIdentifier]; + err = OK; + } + dispatch_semaphore_signal(lock); + }]; + dispatch_semaphore_wait(lock, dispatch_time(DISPATCH_TIME_NOW, 20000000000)); // 20 sec timeout, wait for app to launch. + dispatch_release(lock); + + if (err == OK) { + if (r_child_id) { + *r_child_id = (ProcessID)pid; + } + } + + return err; + } else { + return OS_Unix::create_process(p_path, p_arguments, r_child_id); + } + } else { + return OS_Unix::create_process(p_path, p_arguments, r_child_id); + } +} + +void OS_OSX::pre_wait_observer_cb(CFRunLoopObserverRef p_observer, CFRunLoopActivity p_activiy, void *p_context) { + // Prevent main loop from sleeping and redraw window during resize / modal popups. + + if (get_singleton()->get_main_loop()) { + Main::force_redraw(); + if (!Main::is_iterating()) { // Avoid cyclic loop. + Main::iteration(); + } + } + + CFRunLoopWakeUp(CFRunLoopGetCurrent()); // Prevent main loop from sleeping. +} + void OS_OSX::run() { force_quit = false; - if (!main_loop) + if (!main_loop) { return; + } main_loop->initialize(); + CFRunLoopObserverRef pre_wait_observer = CFRunLoopObserverCreate(kCFAllocatorDefault, kCFRunLoopBeforeWaiting, true, 0, &pre_wait_observer_cb, nullptr); + CFRunLoopAddObserver(CFRunLoopGetCurrent(), pre_wait_observer, kCFRunLoopCommonModes); + bool quit = false; while (!force_quit && !quit) { @try { @@ -514,6 +589,10 @@ void OS_OSX::run() { ERR_PRINT("NSException: " + String([exception reason].UTF8String)); } }; + + CFRunLoopRemoveObserver(CFRunLoopGetCurrent(), pre_wait_observer, kCFRunLoopCommonModes); + CFRelease(pre_wait_observer); + main_loop->finalize(); } diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index 22c0219ea6..2c21390d73 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -447,7 +447,7 @@ Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments, ZeroMemory(&pi.pi, sizeof(pi.pi)); LPSTARTUPINFOW si_w = (LPSTARTUPINFOW)&pi.si; - int ret = CreateProcessW(nullptr, (LPWSTR)(command.utf16().ptrw()), nullptr, nullptr, false, NORMAL_PRIORITY_CLASS & CREATE_NO_WINDOW, nullptr, nullptr, si_w, &pi.pi); + int ret = CreateProcessW(nullptr, (LPWSTR)(command.utf16().ptrw()), nullptr, nullptr, false, NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW, nullptr, nullptr, si_w, &pi.pi); ERR_FAIL_COND_V_MSG(ret == 0, ERR_CANT_FORK, "Could not create child process: " + command); WaitForSingleObject(pi.pi.hProcess, INFINITE); @@ -475,7 +475,7 @@ Error OS_Windows::create_process(const String &p_path, const List<String> &p_arg ZeroMemory(&pi.pi, sizeof(pi.pi)); LPSTARTUPINFOW si_w = (LPSTARTUPINFOW)&pi.si; - int ret = CreateProcessW(nullptr, (LPWSTR)(command.utf16().ptrw()), nullptr, nullptr, false, NORMAL_PRIORITY_CLASS & CREATE_NO_WINDOW, nullptr, nullptr, si_w, &pi.pi); + int ret = CreateProcessW(nullptr, (LPWSTR)(command.utf16().ptrw()), nullptr, nullptr, false, NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW, nullptr, nullptr, si_w, &pi.pi); ERR_FAIL_COND_V_MSG(ret == 0, ERR_CANT_FORK, "Could not create child process: " + command); ProcessID pid = pi.pi.dwProcessId; |