diff options
Diffstat (limited to 'platform')
| -rw-r--r-- | platform/android/dir_access_jandroid.cpp | 5 | ||||
| -rw-r--r-- | platform/android/dir_access_jandroid.h | 2 | ||||
| -rw-r--r-- | platform/android/export/export.cpp | 49 | ||||
| -rw-r--r-- | platform/android/thread_jandroid.cpp | 17 | ||||
| -rw-r--r-- | platform/iphone/export/export.cpp | 24 | ||||
| -rw-r--r-- | platform/javascript/export/export.cpp | 4 | ||||
| -rw-r--r-- | platform/javascript/os_javascript.cpp | 20 | ||||
| -rw-r--r-- | platform/osx/detect.py | 2 | ||||
| -rw-r--r-- | platform/osx/export/export.cpp | 4 | ||||
| -rw-r--r-- | platform/osx/os_osx.h | 9 | ||||
| -rw-r--r-- | platform/osx/os_osx.mm | 72 | ||||
| -rw-r--r-- | platform/uwp/export/export.cpp | 26 | ||||
| -rw-r--r-- | platform/uwp/os_uwp.cpp | 5 | ||||
| -rw-r--r-- | platform/uwp/os_uwp.h | 1 | ||||
| -rw-r--r-- | platform/windows/detect.py | 8 | ||||
| -rw-r--r-- | platform/windows/export/export.cpp | 4 | ||||
| -rw-r--r-- | platform/windows/joypad.cpp | 7 | ||||
| -rw-r--r-- | platform/windows/os_windows.cpp | 33 | ||||
| -rw-r--r-- | platform/windows/os_windows.h | 1 | ||||
| -rw-r--r-- | platform/x11/SCsub | 1 | ||||
| -rw-r--r-- | platform/x11/detect.py | 22 | ||||
| -rw-r--r-- | platform/x11/detect_prime.cpp | 233 | ||||
| -rw-r--r-- | platform/x11/detect_prime.h | 37 | ||||
| -rw-r--r-- | platform/x11/os_x11.cpp | 31 |
24 files changed, 493 insertions, 124 deletions
diff --git a/platform/android/dir_access_jandroid.cpp b/platform/android/dir_access_jandroid.cpp index af31c758ee..4b3d93aaa7 100644 --- a/platform/android/dir_access_jandroid.cpp +++ b/platform/android/dir_access_jandroid.cpp @@ -212,6 +212,11 @@ Error DirAccessJAndroid::remove(String p_name) { ERR_FAIL_V(ERR_UNAVAILABLE); } +String DirAccessJAndroid::get_filesystem_type() const { + + return "APK"; +} + //FileType get_file_type() const; size_t DirAccessJAndroid::get_space_left() { diff --git a/platform/android/dir_access_jandroid.h b/platform/android/dir_access_jandroid.h index 1d989dd35e..e7a2d5ada1 100644 --- a/platform/android/dir_access_jandroid.h +++ b/platform/android/dir_access_jandroid.h @@ -75,6 +75,8 @@ public: virtual Error rename(String p_from, String p_to); virtual Error remove(String p_name); + virtual String get_filesystem_type() const; + //virtual FileType get_file_type() const; size_t get_space_left(); diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp index 405fe0b294..f293eef2ba 100644 --- a/platform/android/export/export.cpp +++ b/platform/android/export/export.cpp @@ -426,7 +426,7 @@ class EditorExportAndroid : public EditorExportPlatform { if (pname.length() == 0) { if (r_error) { - *r_error = "Package name is missing."; + *r_error = TTR("Package name is missing."); } return false; } @@ -437,7 +437,7 @@ class EditorExportAndroid : public EditorExportPlatform { CharType c = pname[i]; if (first && c == '.') { if (r_error) { - *r_error = "Package segments must be of non-zero length."; + *r_error = TTR("Package segments must be of non-zero length."); } return false; } @@ -448,19 +448,19 @@ class EditorExportAndroid : public EditorExportPlatform { } if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_')) { if (r_error) { - *r_error = "The character '" + String::chr(c) + "' is not allowed in Android application package names."; + *r_error = vformat(TTR("The character '%s' is not allowed in Android application package names."), String::chr(c)); } return false; } if (first && (c >= '0' && c <= '9')) { if (r_error) { - *r_error = "A digit cannot be the first character in a package segment."; + *r_error = TTR("A digit cannot be the first character in a package segment."); } return false; } if (first && c == '_') { if (r_error) { - *r_error = "The character '" + String::chr(c) + "' cannot be the first character in a package segment."; + *r_error = vformat(TTR("The character '%s' cannot be the first character in a package segment."), String::chr(c)); } return false; } @@ -469,14 +469,14 @@ class EditorExportAndroid : public EditorExportPlatform { if (segments == 0) { if (r_error) { - *r_error = "The package must have at least one '.' separator."; + *r_error = TTR("The package must have at least one '.' separator."); } return false; } if (first) { if (r_error) { - *r_error = "Package segments must be of non-zero length."; + *r_error = TTR("Package segments must be of non-zero length."); } return false; } @@ -584,7 +584,7 @@ class EditorExportAndroid : public EditorExportPlatform { static Error save_apk_so(void *p_userdata, const SharedObject &p_so) { if (!p_so.path.get_file().begins_with("lib")) { String err = "Android .so file names must start with \"lib\", but got: " + p_so.path; - ERR_PRINT(err.utf8().get_data()); + ERR_PRINTS(err); return FAILED; } APKExportData *ed = (APKExportData *)p_userdata; @@ -605,7 +605,7 @@ class EditorExportAndroid : public EditorExportPlatform { if (!exported) { String abis_string = String(" ").join(abis); String err = "Cannot determine ABI for library \"" + p_so.path + "\". One of the supported ABIs must be used as a tag: " + abis_string; - ERR_PRINT(err.utf8().get_data()); + ERR_PRINTS(err); return FAILED; } return OK; @@ -1390,7 +1390,7 @@ public: if (FileAccess::exists(p_preset->get("custom_package/debug"))) { r_missing_templates = false; } else { - err += "Custom debug package not found.\n"; + err += TTR("Custom debug template not found.") + "\n"; } } @@ -1398,7 +1398,7 @@ public: if (FileAccess::exists(p_preset->get("custom_package/release"))) { r_missing_templates = false; } else { - err += "Custom release package not found.\n"; + err += TTR("Custom release template not found.") + "\n"; } } @@ -1409,7 +1409,7 @@ public: if (!FileAccess::exists(adb)) { valid = false; - err += "ADB executable not configured in the Editor Settings.\n"; + err += TTR("ADB executable not configured in the Editor Settings.") + "\n"; } String js = EditorSettings::get_singleton()->get("export/android/jarsigner"); @@ -1417,7 +1417,7 @@ public: if (!FileAccess::exists(js)) { valid = false; - err += "OpenJDK 8 jarsigner not configured in the Editor Settings.\n"; + err += TTR("OpenJDK jarsigner not configured in the Editor Settings.") + "\n"; } String dk = p_preset->get("keystore/debug"); @@ -1427,7 +1427,7 @@ public: dk = EditorSettings::get_singleton()->get("export/android/debug_keystore"); if (!FileAccess::exists(dk)) { valid = false; - err += "Debug keystore not configured in the Editor Settings nor in the preset.\n"; + err += TTR("Debug keystore not configured in the Editor Settings nor in the preset.") + "\n"; } } @@ -1435,19 +1435,12 @@ public: if (apk_expansion) { - /* - if (apk_expansion_salt=="") { - valid=false; - err+="Invalid SALT for apk expansion.\n"; - } - */ - String apk_expansion_pkey = p_preset->get("apk_expansion/public_key"); if (apk_expansion_pkey == "") { valid = false; - err += "Invalid public key for APK expansion.\n"; + err += TTR("Invalid public key for APK expansion.") + "\n"; } } @@ -1457,7 +1450,7 @@ public: if (!is_package_name_valid(get_package_name(pn), &pn_err)) { valid = false; - err += "Invalid package name - " + pn_err + "\n"; + err += TTR("Invalid package name:") + " " + pn_err + "\n"; } r_error = err; @@ -1656,16 +1649,6 @@ public: if (p_flags & DEBUG_FLAG_DUMB_CLIENT) { - /*String host = EditorSettings::get_singleton()->get("filesystem/file_server/host"); - int port = EditorSettings::get_singleton()->get("filesystem/file_server/post"); - String passwd = EditorSettings::get_singleton()->get("filesystem/file_server/password"); - cl.push_back("--remote-fs"); - cl.push_back(host+":"+itos(port)); - if (passwd!="") { - cl.push_back("--remote-fs-password"); - cl.push_back(passwd); - }*/ - APKExportData ed; ed.ep = &ep; ed.apk = unaligned_apk; diff --git a/platform/android/thread_jandroid.cpp b/platform/android/thread_jandroid.cpp index 98f6e79dcb..9df9e57b24 100644 --- a/platform/android/thread_jandroid.cpp +++ b/platform/android/thread_jandroid.cpp @@ -34,9 +34,13 @@ #include "core/safe_refcount.h" #include "core/script_language.h" +static void _thread_id_key_destr_callback(void *p_value) { + memdelete(static_cast<Thread::ID *>(p_value)); +} + static pthread_key_t _create_thread_id_key() { pthread_key_t key; - pthread_key_create(&key, NULL); + pthread_key_create(&key, &_thread_id_key_destr_callback); return key; } @@ -59,7 +63,7 @@ void *ThreadAndroid::thread_callback(void *userdata) { setup_thread(); ScriptServer::thread_enter(); //scripts may need to attach a stack t->id = atomic_increment(&next_thread_id); - pthread_setspecific(thread_id_key, (void *)t->id); + pthread_setspecific(thread_id_key, (void *)memnew(ID(t->id))); t->callback(t->user); ScriptServer::thread_exit(); return NULL; @@ -80,7 +84,14 @@ Thread *ThreadAndroid::create_func_jandroid(ThreadCreateCallback p_callback, voi Thread::ID ThreadAndroid::get_thread_id_func_jandroid() { - return (ID)pthread_getspecific(thread_id_key); + void *value = pthread_getspecific(thread_id_key); + + if (value) + return *static_cast<ID *>(value); + + ID new_id = atomic_increment(&next_thread_id); + pthread_setspecific(thread_id_key, (void *)memnew(ID(new_id))); + return new_id; } void ThreadAndroid::wait_to_finish_func_jandroid(Thread *p_thread) { diff --git a/platform/iphone/export/export.cpp b/platform/iphone/export/export.cpp index ef81981ec0..849e6d4a14 100644 --- a/platform/iphone/export/export.cpp +++ b/platform/iphone/export/export.cpp @@ -105,7 +105,7 @@ class EditorExportPlatformIOS : public EditorExportPlatform { if (pname.length() == 0) { if (r_error) { - *r_error = "Identifier is missing."; + *r_error = TTR("Identifier is missing."); } return false; } @@ -116,7 +116,7 @@ class EditorExportPlatformIOS : public EditorExportPlatform { CharType c = pname[i]; if (first && c == '.') { if (r_error) { - *r_error = "Identifier segments must be of non-zero length."; + *r_error = TTR("Identifier segments must be of non-zero length."); } return false; } @@ -127,19 +127,19 @@ class EditorExportPlatformIOS : public EditorExportPlatform { } if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_')) { if (r_error) { - *r_error = "The character '" + String::chr(c) + "' is not allowed in Identifier."; + *r_error = vformat(TTR("The character '%s' is not allowed in Identifier."), String::chr(c)); } return false; } if (first && (c >= '0' && c <= '9')) { if (r_error) { - *r_error = "A digit cannot be the first character in a Identifier segment."; + *r_error = TTR("A digit cannot be the first character in a Identifier segment."); } return false; } if (first && c == '_') { if (r_error) { - *r_error = "The character '" + String::chr(c) + "' cannot be the first character in a Identifier segment."; + *r_error = vformat(TTR("The character '%s' cannot be the first character in a Identifier segment."), String::chr(c)); } return false; } @@ -148,14 +148,14 @@ class EditorExportPlatformIOS : public EditorExportPlatform { if (segments == 0) { if (r_error) { - *r_error = "The Identifier must have at least one '.' separator."; + *r_error = TTR("The Identifier must have at least one '.' separator."); } return false; } if (first) { if (r_error) { - *r_error = "Identifier segments must be of non-zero length."; + *r_error = TTR("Identifier segments must be of non-zero length."); } return false; } @@ -1036,7 +1036,7 @@ bool EditorExportPlatformIOS::can_export(const Ref<EditorExportPreset> &p_preset if (FileAccess::exists(p_preset->get("custom_package/debug"))) { r_missing_templates = false; } else { - err += "Custom debug package not found.\n"; + err += TTR("Custom debug template not found.") + "\n"; } } @@ -1044,7 +1044,7 @@ bool EditorExportPlatformIOS::can_export(const Ref<EditorExportPreset> &p_preset if (FileAccess::exists(p_preset->get("custom_package/release"))) { r_missing_templates = false; } else { - err += "Custom release package not found.\n"; + err += TTR("Custom release template not found.") + "\n"; } } @@ -1052,14 +1052,14 @@ bool EditorExportPlatformIOS::can_export(const Ref<EditorExportPreset> &p_preset String team_id = p_preset->get("application/app_store_team_id"); if (team_id.length() == 0) { - err += "App Store Team ID not specified - cannot configure the project.\n"; + err += TTR("App Store Team ID not specified - cannot configure the project.") + "\n"; valid = false; } String identifier = p_preset->get("application/identifier"); String pn_err; if (!is_package_name_valid(identifier, &pn_err)) { - err += "Invalid Identifier - " + pn_err + "\n"; + err += TTR("Invalid Identifier:") + " " + pn_err + "\n"; valid = false; } @@ -1068,7 +1068,7 @@ bool EditorExportPlatformIOS::can_export(const Ref<EditorExportPreset> &p_preset String icon_path = p_preset->get(info.preset_key); if (icon_path.length() == 0) { if (info.is_required) { - err += "Required icon is not specified in the preset.\n"; + err += TTR("Required icon is not specified in the preset.") + "\n"; valid = false; } break; diff --git a/platform/javascript/export/export.cpp b/platform/javascript/export/export.cpp index b3f90b9011..123c6ae645 100644 --- a/platform/javascript/export/export.cpp +++ b/platform/javascript/export/export.cpp @@ -155,7 +155,7 @@ bool EditorExportPlatformJavaScript::can_export(const Ref<EditorExportPreset> &p if (FileAccess::exists(p_preset->get("custom_template/debug"))) { valid = true; } else { - err += "Custom debug template not found.\n"; + err += TTR("Custom debug template not found.") + "\n"; } } @@ -163,7 +163,7 @@ bool EditorExportPlatformJavaScript::can_export(const Ref<EditorExportPreset> &p if (FileAccess::exists(p_preset->get("custom_template/release"))) { valid = true; } else { - err += "Custom release template not found.\n"; + err += TTR("Custom release template not found.") + "\n"; } } diff --git a/platform/javascript/os_javascript.cpp b/platform/javascript/os_javascript.cpp index b92634c8d6..e820d07a2a 100644 --- a/platform/javascript/os_javascript.cpp +++ b/platform/javascript/os_javascript.cpp @@ -442,6 +442,9 @@ void OS_JavaScript::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_s if (texture.is_valid()) { image = texture->get_data(); + if (image.is_valid()) { + image->duplicate(); + } } if (!image.is_valid() && atlas_texture.is_valid()) { @@ -468,6 +471,8 @@ void OS_JavaScript::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_s ERR_FAIL_COND(!image.is_valid()); + image = image->duplicate(); + if (atlas_texture.is_valid()) image->crop_from_point( atlas_rect.position.x, @@ -861,8 +866,21 @@ Error OS_JavaScript::initialize(const VideoMode &p_desired, int p_video_driver, video_driver_index = p_video_driver; video_mode = p_desired; - // Can't fulfill fullscreen request during start-up due to browser security. + // fullscreen_change_callback will correct this if the request is successful. video_mode.fullscreen = false; + // Emscripten only attempts fullscreen requests if the user input callback + // was registered through one its own functions, so request manually for + // start-up fullscreen. + if (p_desired.fullscreen) { + /* clang-format off */ + EM_ASM({ + (canvas.requestFullscreen || canvas.msRequestFullscreen || + canvas.mozRequestFullScreen || canvas.mozRequestFullscreen || + canvas.webkitRequestFullscreen + ).call(canvas); + }); + /* clang-format on */ + } /* clang-format off */ if (EM_ASM_INT_V({ return Module.resizeCanvasOnStart })) { /* clang-format on */ diff --git a/platform/osx/detect.py b/platform/osx/detect.py index 31fcbc0427..36a753e683 100644 --- a/platform/osx/detect.py +++ b/platform/osx/detect.py @@ -126,7 +126,7 @@ def configure(env): env.Append(CPPPATH=['#platform/osx']) env.Append(CPPFLAGS=['-DOSX_ENABLED', '-DUNIX_ENABLED', '-DGLES_ENABLED', '-DAPPLE_STYLE_KEYS', '-DCOREAUDIO_ENABLED', '-DCOREMIDI_ENABLED']) - env.Append(LINKFLAGS=['-framework', 'Cocoa', '-framework', 'Carbon', '-framework', 'OpenGL', '-framework', 'AGL', '-framework', 'AudioUnit', '-framework', 'CoreAudio', '-framework', 'CoreMIDI', '-lz', '-framework', 'IOKit', '-framework', 'ForceFeedback']) + env.Append(LINKFLAGS=['-framework', 'Cocoa', '-framework', 'Carbon', '-framework', 'OpenGL', '-framework', 'AGL', '-framework', 'AudioUnit', '-framework', 'CoreAudio', '-framework', 'CoreMIDI', '-lz', '-framework', 'IOKit', '-framework', 'ForceFeedback', '-framework', 'CoreVideo']) env.Append(LIBS=['pthread']) env.Append(CPPFLAGS=['-mmacosx-version-min=10.9']) diff --git a/platform/osx/export/export.cpp b/platform/osx/export/export.cpp index 845ef4e893..b8f6977b39 100644 --- a/platform/osx/export/export.cpp +++ b/platform/osx/export/export.cpp @@ -749,7 +749,7 @@ bool EditorExportPlatformOSX::can_export(const Ref<EditorExportPreset> &p_preset if (FileAccess::exists(p_preset->get("custom_package/debug"))) { valid = true; } else { - err += "Custom debug package not found.\n"; + err += TTR("Custom debug template not found.") + "\n"; } } @@ -757,7 +757,7 @@ bool EditorExportPlatformOSX::can_export(const Ref<EditorExportPreset> &p_preset if (FileAccess::exists(p_preset->get("custom_package/release"))) { valid = true; } else { - err += "Custom release package not found.\n"; + err += TTR("Custom release template not found.") + "\n"; } } diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h index 262079fa89..927c8c9b00 100644 --- a/platform/osx/os_osx.h +++ b/platform/osx/os_osx.h @@ -43,8 +43,10 @@ #include "servers/visual/rasterizer.h" #include "servers/visual/visual_server_wrap_mt.h" #include "servers/visual_server.h" +#include <AppKit/AppKit.h> #include <AppKit/NSCursor.h> #include <ApplicationServices/ApplicationServices.h> +#include <CoreVideo/CoreVideo.h> #undef CursorShape /** @@ -102,10 +104,13 @@ public: id window_view; id autoreleasePool; id cursor; - id pixelFormat; - id context; + NSOpenGLPixelFormat *pixelFormat; + NSOpenGLContext *context; bool layered_window; + bool waiting_for_vsync; + NSCondition *vsync_condition; + CVDisplayLinkRef displayLink; CursorShape cursor_shape; NSCursor *cursors[CURSOR_MAX]; diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm index ddd98ab88c..6b65c1a529 100644 --- a/platform/osx/os_osx.mm +++ b/platform/osx/os_osx.mm @@ -117,6 +117,21 @@ static Vector2 get_mouse_pos(NSPoint locationInWindow, CGFloat backingScaleFacto return Vector2(mouse_x, mouse_y); } +// DisplayLinkCallback is called from our DisplayLink OS thread informing us right before +// a screen update is required. We can use it to work around the broken vsync. +static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp *now, const CVTimeStamp *outputTime, CVOptionFlags flagsIn, CVOptionFlags *flagsOut, void *displayLinkContext) { + OS_OSX *os = (OS_OSX *)displayLinkContext; + + // Set flag so we know we can output our next frame and signal our conditional lock + // if we're not doing vsync this will be ignored + [os->vsync_condition lock]; + os->waiting_for_vsync = false; + [os->vsync_condition signal]; + [os->vsync_condition unlock]; + + return kCVReturnSuccess; +} + @interface GodotApplication : NSApplication @end @@ -267,7 +282,9 @@ static Vector2 get_mouse_pos(NSPoint locationInWindow, CGFloat backingScaleFacto NSWindow *window = (NSWindow *)[notification object]; CGFloat newBackingScaleFactor = [window backingScaleFactor]; CGFloat oldBackingScaleFactor = [[[notification userInfo] objectForKey:@"NSBackingPropertyOldScaleFactorKey"] doubleValue]; - [OS_OSX::singleton->window_view setWantsBestResolutionOpenGLSurface:YES]; + if (OS_OSX::singleton->is_hidpi_allowed()) { + [OS_OSX::singleton->window_view setWantsBestResolutionOpenGLSurface:YES]; + } if (newBackingScaleFactor != oldBackingScaleFactor) { //Set new display scale and window size @@ -304,7 +321,9 @@ static Vector2 get_mouse_pos(NSPoint locationInWindow, CGFloat backingScaleFacto if (OS_OSX::singleton->main_loop) { Main::force_redraw(); //Event retrieval blocks until resize is over. Call Main::iteration() directly. - Main::iteration(); + if (!Main::is_iterating()) { //avoid cyclic loop + Main::iteration(); + } } /* @@ -1364,6 +1383,15 @@ Error OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_a [context makeCurrentContext]; + // setup our display link, this will inform us when a refresh is needed + CVDisplayLinkCreateWithActiveCGDisplays(&displayLink); + CVDisplayLinkSetOutputCallback(displayLink, &DisplayLinkCallback, this); + CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(displayLink, context.CGLContextObj, pixelFormat.CGLPixelFormatObj); + CVDisplayLinkStart(displayLink); + + // initialise a conditional lock object + vsync_condition = [[NSCondition alloc] init]; + set_use_vsync(p_desired.use_vsync); [NSApp activateIgnoringOtherApps:YES]; @@ -1451,6 +1479,11 @@ void OS_OSX::finalize() { midi_driver.close(); #endif + if (displayLink) { + CVDisplayLinkRelease(displayLink); + } + [vsync_condition release]; + CFNotificationCenterRemoveObserver(CFNotificationCenterGetDistributedCenter(), NULL, kTISNotifySelectedKeyboardInputSourceChanged, NULL); CGDisplayRemoveReconfigurationCallback(displays_arrangement_changed, NULL); @@ -1965,6 +1998,17 @@ String OS_OSX::get_locale() const { } void OS_OSX::swap_buffers() { + if (is_vsync_enabled()) { + // Wait until our DisplayLink callback unsets our flag... + [vsync_condition lock]; + while (waiting_for_vsync) + [vsync_condition wait]; + + // Make sure we wait again next frame around + waiting_for_vsync = true; + + [vsync_condition unlock]; + } [context flushBuffer]; } @@ -2631,22 +2675,22 @@ Error OS_OSX::move_to_trash(const String &p_path) { } void OS_OSX::_set_use_vsync(bool p_enable) { - CGLContextObj ctx = CGLGetCurrentContext(); + // CGLCPSwapInterval broke in OSX 10.14 and it seems Apple is not interested in fixing + // it as OpenGL is now deprecated and Metal solves this differently. + // Following SDLs example we're working around this using DisplayLink + // When vsync is enabled we set a flag "waiting_for_vsync" to true. + // This flag is set to false when DisplayLink informs us our display is about to refresh. + + /* CGLContextObj ctx = CGLGetCurrentContext(); if (ctx) { GLint swapInterval = p_enable ? 1 : 0; CGLSetParameter(ctx, kCGLCPSwapInterval, &swapInterval); - } -} -/* -bool OS_OSX::is_vsync_enabled() const { - GLint swapInterval = 0; - CGLContextObj ctx = CGLGetCurrentContext(); - if (ctx) { - CGLGetParameter(ctx, kCGLCPSwapInterval, &swapInterval); - } - return swapInterval ? true : false; + }*/ + + ///TODO Maybe pause/unpause display link? + waiting_for_vsync = p_enable; } -*/ + OS_OSX *OS_OSX::singleton = NULL; OS_OSX::OS_OSX() { diff --git a/platform/uwp/export/export.cpp b/platform/uwp/export/export.cpp index 4dcb6cf38e..6808016f13 100644 --- a/platform/uwp/export/export.cpp +++ b/platform/uwp/export/export.cpp @@ -1151,12 +1151,12 @@ public: if (!FileAccess::exists(custom_debug_binary)) { dvalid = false; - err = "\nCustom debug binary not found."; + err += TTR("Custom debug template not found.") + "\n"; } if (!FileAccess::exists(custom_release_binary)) { rvalid = false; - err += "\nCustom release binary not found."; + err += TTR("Custom release template not found.") + "\n"; } if (dvalid || rvalid) @@ -1169,57 +1169,57 @@ public: if (!_valid_resource_name(p_preset->get("package/unique_name"))) { valid = false; - err += "\nInvalid unique name."; + err += TTR("Invalid package unique name.") + "\n"; } if (!_valid_guid(p_preset->get("identity/product_guid"))) { valid = false; - err += "\nInvalid product GUID."; + err += TTR("Invalid product GUID.") + "\n"; } if (!_valid_guid(p_preset->get("identity/publisher_guid"))) { valid = false; - err += "\nInvalid publisher GUID."; + err += TTR("Invalid publisher GUID.") + "\n"; } if (!_valid_bgcolor(p_preset->get("images/background_color"))) { valid = false; - err += "\nInvalid background color."; + err += TTR("Invalid background color.") + "\n"; } if (!p_preset->get("images/store_logo").is_zero() && !_valid_image((Object::cast_to<StreamTexture>((Object *)p_preset->get("images/store_logo"))), 50, 50)) { valid = false; - err += "\nInvalid Store Logo image dimensions (should be 50x50)."; + err += TTR("Invalid Store Logo image dimensions (should be 50x50).") + "\n"; } if (!p_preset->get("images/square44x44_logo").is_zero() && !_valid_image((Object::cast_to<StreamTexture>((Object *)p_preset->get("images/square44x44_logo"))), 44, 44)) { valid = false; - err += "\nInvalid square 44x44 logo image dimensions (should be 44x44)."; + err += TTR("Invalid square 44x44 logo image dimensions (should be 44x44).") + "\n"; } if (!p_preset->get("images/square71x71_logo").is_zero() && !_valid_image((Object::cast_to<StreamTexture>((Object *)p_preset->get("images/square71x71_logo"))), 71, 71)) { valid = false; - err += "\nInvalid square 71x71 logo image dimensions (should be 71x71)."; + err += TTR("Invalid square 71x71 logo image dimensions (should be 71x71).") + "\n"; } if (!p_preset->get("images/square150x150_logo").is_zero() && !_valid_image((Object::cast_to<StreamTexture>((Object *)p_preset->get("images/square150x150_logo"))), 150, 0)) { valid = false; - err += "\nInvalid square 150x150 logo image dimensions (should be 150x150)."; + err += TTR("Invalid square 150x150 logo image dimensions (should be 150x150).") + "\n"; } if (!p_preset->get("images/square310x310_logo").is_zero() && !_valid_image((Object::cast_to<StreamTexture>((Object *)p_preset->get("images/square310x310_logo"))), 310, 310)) { valid = false; - err += "\nInvalid square 310x310 logo image dimensions (should be 310x310)."; + err += TTR("Invalid square 310x310 logo image dimensions (should be 310x310).") + "\n"; } if (!p_preset->get("images/wide310x150_logo").is_zero() && !_valid_image((Object::cast_to<StreamTexture>((Object *)p_preset->get("images/wide310x150_logo"))), 310, 150)) { valid = false; - err += "\nInvalid wide 310x150 logo image dimensions (should be 310x150)."; + err += TTR("Invalid wide 310x150 logo image dimensions (should be 310x150).") + "\n"; } if (!p_preset->get("images/splash_screen").is_zero() && !_valid_image((Object::cast_to<StreamTexture>((Object *)p_preset->get("images/splash_screen"))), 620, 300)) { valid = false; - err += "\nInvalid splash screen image dimensions (should be 620x300)."; + err += TTR("Invalid splash screen image dimensions (should be 620x300).") + "\n"; } r_error = err; diff --git a/platform/uwp/os_uwp.cpp b/platform/uwp/os_uwp.cpp index ea0193b8ed..ea4f63b49c 100644 --- a/platform/uwp/os_uwp.cpp +++ b/platform/uwp/os_uwp.cpp @@ -739,6 +739,11 @@ String OSUWP::get_environment(const String &p_var) const { return ""; }; +bool OSUWP::set_environment(const String &p_var, const String &p_value) const { + + return false; +} + String OSUWP::get_stdin_string(bool p_block) { return String(); diff --git a/platform/uwp/os_uwp.h b/platform/uwp/os_uwp.h index 491c9bce03..5475c4e60a 100644 --- a/platform/uwp/os_uwp.h +++ b/platform/uwp/os_uwp.h @@ -213,6 +213,7 @@ public: virtual bool has_environment(const String &p_var) const; virtual String get_environment(const String &p_var) const; + virtual bool set_environment(const String &p_var, const String &p_value) const; virtual void set_clipboard(const String &p_text); virtual String get_clipboard() const; diff --git a/platform/windows/detect.py b/platform/windows/detect.py index e14db9a201..0662bc2edc 100644 --- a/platform/windows/detect.py +++ b/platform/windows/detect.py @@ -208,8 +208,8 @@ def configure_msvc(env, manual_msvc_config): 'RTAUDIO_ENABLED', 'WASAPI_ENABLED', 'WINMIDI_ENABLED', 'TYPED_METHOD_BIND', 'WIN32', 'MSVC', - 'WINVER=$target_win_version', - '_WIN32_WINNT=$target_win_version']) + 'WINVER=%s' % env["target_win_version"], + '_WIN32_WINNT=%s' % env["target_win_version"]]) env.AppendUnique(CPPDEFINES=['NOMINMAX']) # disable bogus min/max WinDef.h macros if env["bits"] == "64": env.AppendUnique(CPPDEFINES=['_WIN64']) @@ -218,7 +218,7 @@ def configure_msvc(env, manual_msvc_config): LIBS = ['winmm', 'opengl32', 'dsound', 'kernel32', 'ole32', 'oleaut32', 'user32', 'gdi32', 'IPHLPAPI', 'Shlwapi', 'wsock32', 'Ws2_32', - 'shell32', 'advapi32', 'dinput8', 'dxguid', 'imm32', 'bcrypt'] + 'shell32', 'advapi32', 'dinput8', 'dxguid', 'imm32', 'bcrypt','Avrt'] env.Append(LINKFLAGS=[p + env["LIBSUFFIX"] for p in LIBS]) if manual_msvc_config: @@ -329,7 +329,7 @@ def configure_mingw(env): env.Append(CCFLAGS=['-DRTAUDIO_ENABLED']) env.Append(CCFLAGS=['-DWASAPI_ENABLED']) env.Append(CCFLAGS=['-DWINVER=%s' % env['target_win_version'], '-D_WIN32_WINNT=%s' % env['target_win_version']]) - env.Append(LIBS=['mingw32', 'opengl32', 'dsound', 'ole32', 'd3d9', 'winmm', 'gdi32', 'iphlpapi', 'shlwapi', 'wsock32', 'ws2_32', 'kernel32', 'oleaut32', 'dinput8', 'dxguid', 'ksuser', 'imm32', 'bcrypt']) + env.Append(LIBS=['mingw32', 'opengl32', 'dsound', 'ole32', 'd3d9', 'winmm', 'gdi32', 'iphlpapi', 'shlwapi', 'wsock32', 'ws2_32', 'kernel32', 'oleaut32', 'dinput8', 'dxguid', 'ksuser', 'imm32', 'bcrypt','avrt']) env.Append(CPPFLAGS=['-DMINGW_ENABLED']) diff --git a/platform/windows/export/export.cpp b/platform/windows/export/export.cpp index ca2f71ca18..141ab96370 100644 --- a/platform/windows/export/export.cpp +++ b/platform/windows/export/export.cpp @@ -73,7 +73,7 @@ Error EditorExportPlatformWindows::export_project(const Ref<EditorExportPreset> } #endif - String icon_path = p_preset->get("application/icon"); + String icon_path = ProjectSettings::get_singleton()->globalize_path(p_preset->get("application/icon")); String file_verion = p_preset->get("application/file_version"); String product_version = p_preset->get("application/product_version"); String company_name = p_preset->get("application/company_name"); @@ -137,7 +137,7 @@ Error EditorExportPlatformWindows::export_project(const Ref<EditorExportPreset> void EditorExportPlatformWindows::get_export_options(List<ExportOption> *r_options) { EditorExportPlatformPC::get_export_options(r_options); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/icon", PROPERTY_HINT_GLOBAL_FILE, "*.ico"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/icon", PROPERTY_HINT_FILE, "*.ico"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/file_version"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/product_version"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/company_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Company Name"), "")); diff --git a/platform/windows/joypad.cpp b/platform/windows/joypad.cpp index ba05d2e495..5fafc7c8c0 100644 --- a/platform/windows/joypad.cpp +++ b/platform/windows/joypad.cpp @@ -29,9 +29,9 @@ /*************************************************************************/ #include "joypad.h" + #include <oleauto.h> #include <wbemidl.h> -#include <iostream> #ifndef __GNUC__ #define __builtin_bswap32 _byteswap_ulong @@ -149,15 +149,12 @@ bool JoypadWindows::setup_dinput_joypad(const DIDEVICEINSTANCE *instance) { const DWORD devtype = (instance->dwDevType & 0xFF); if ((devtype != DI8DEVTYPE_JOYSTICK) && (devtype != DI8DEVTYPE_GAMEPAD) && (devtype != DI8DEVTYPE_1STPERSON)) { - //printf("ignore device %s, type %x\n", instance->tszProductName, devtype); return false; } hr = dinput->CreateDevice(instance->guidInstance, &joy->di_joy, NULL); if (FAILED(hr)) { - - //std::wcout << "failed to create device: " << instance->tszProductName << std::endl; return false; } @@ -383,8 +380,6 @@ void JoypadWindows::process_joypads() { hr = joy->di_joy->GetDeviceState(sizeof(DIJOYSTATE2), &js); if (FAILED(hr)) { - - //printf("failed to read joy #%d\n", i); continue; } diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index 3b41f1b901..9ae1be9afd 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -50,6 +50,7 @@ #include "servers/visual/visual_server_raster.h" #include "servers/visual/visual_server_wrap_mt.h" #include "windows_terminal_logger.h" +#include <avrt.h> #include <process.h> #include <regstr.h> @@ -783,7 +784,9 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) case WM_TIMER: { if (wParam == move_timer_id) { process_key_events(); - Main::iteration(); + if (!Main::is_iterating()) { + Main::iteration(); + } } } break; @@ -802,6 +805,13 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) gr_mem = alt_mem; } + if (mouse_mode == MOUSE_MODE_CAPTURED) { + // When SetCapture is used, ALT+F4 hotkey is ignored by Windows, so handle it ourselves + if (wParam == VK_F4 && alt_mem && (uMsg == WM_KEYDOWN || uMsg == WM_SYSKEYDOWN)) { + if (main_loop) + main_loop->notification(MainLoop::NOTIFICATION_WM_QUIT_REQUEST); + } + } /* if (wParam==VK_WIN) TODO wtf is this? meta_mem=uMsg==WM_KEYDOWN; @@ -1371,6 +1381,19 @@ Error OS_Windows::initialize(const VideoMode &p_desired, int p_video_driver, int set_ime_active(false); + if (!OS::get_singleton()->is_in_low_processor_usage_mode()) { + //SetPriorityClass(GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS); + SetPriorityClass(GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS); + DWORD index = 0; + HANDLE handle = AvSetMmThreadCharacteristics("Games", &index); + if (handle) + AvSetMmThreadPriority(handle, AVRT_PRIORITY_CRITICAL); + + // This is needed to make sure that background work does not starve the main thread. + // This is only setting priority of this thread, not the whole process. + SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); + } + return OK; } @@ -2319,6 +2342,9 @@ void OS_Windows::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shap iconinfo.hbmMask = hAndMask; iconinfo.hbmColor = hXorMask; + if (cursors[p_shape]) + DestroyIcon(cursors[p_shape]); + cursors[p_shape] = CreateIconIndirect(&iconinfo); if (p_shape == cursor_shape) { @@ -2578,6 +2604,11 @@ String OS_Windows::get_environment(const String &p_var) const { return ""; } +bool OS_Windows::set_environment(const String &p_var, const String &p_value) const { + + return (bool)SetEnvironmentVariableW(p_var.c_str(), p_value.c_str()); +} + String OS_Windows::get_stdin_string(bool p_block) { if (p_block) { diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h index 4936a69120..771789c86b 100644 --- a/platform/windows/os_windows.h +++ b/platform/windows/os_windows.h @@ -268,6 +268,7 @@ public: virtual bool has_environment(const String &p_var) const; virtual String get_environment(const String &p_var) const; + virtual bool set_environment(const String &p_var, const String &p_value) const; virtual void set_clipboard(const String &p_text); virtual String get_clipboard() const; diff --git a/platform/x11/SCsub b/platform/x11/SCsub index 97d3d1b514..e302f09c88 100644 --- a/platform/x11/SCsub +++ b/platform/x11/SCsub @@ -13,6 +13,7 @@ common_x11 = [ "key_mapping_x11.cpp", "joypad_linux.cpp", "power_x11.cpp", + "detect_prime.cpp" ] prog = env.add_program('#bin/godot', ['godot_x11.cpp'] + common_x11) diff --git a/platform/x11/detect.py b/platform/x11/detect.py index 415e8ceaa6..72139538b7 100644 --- a/platform/x11/detect.py +++ b/platform/x11/detect.py @@ -61,8 +61,9 @@ def get_opts(): return [ BoolVariable('use_llvm', 'Use the LLVM compiler', False), BoolVariable('use_static_cpp', 'Link libgcc and libstdc++ statically for better portability', False), - BoolVariable('use_sanitizer', 'Use LLVM compiler address sanitizer', False), - BoolVariable('use_leak_sanitizer', 'Use LLVM compiler memory leaks sanitizer (implies use_sanitizer)', False), + BoolVariable('use_ubsan', 'Use LLVM/GCC compiler undefined behavior sanitizer (UBSAN)', False), + BoolVariable('use_asan', 'Use LLVM/GCC compiler address sanitizer (ASAN))', False), + BoolVariable('use_lsan', 'Use LLVM/GCC compiler leak sanitizer (LSAN))', False), BoolVariable('pulseaudio', 'Detect & use pulseaudio', True), BoolVariable('udev', 'Use udev for gamepad connection callbacks', False), EnumVariable('debug_symbols', 'Add debugging symbols to release builds', 'yes', ('yes', 'no', 'full')), @@ -131,12 +132,19 @@ def configure(env): env.Append(CPPFLAGS=['-DTYPED_METHOD_BIND']) env.extra_suffix = ".llvm" + env.extra_suffix - # leak sanitizer requires (address) sanitizer - if env['use_sanitizer'] or env['use_leak_sanitizer']: - env.Append(CCFLAGS=['-fsanitize=address', '-fno-omit-frame-pointer']) - env.Append(LINKFLAGS=['-fsanitize=address']) + + if env['use_ubsan'] or env['use_asan'] or env['use_lsan']: env.extra_suffix += "s" - if env['use_leak_sanitizer']: + + if env['use_ubsan']: + env.Append(CCFLAGS=['-fsanitize=undefined']) + env.Append(LINKFLAGS=['-fsanitize=undefined']) + + if env['use_asan']: + env.Append(CCFLAGS=['-fsanitize=address']) + env.Append(LINKFLAGS=['-fsanitize=address']) + + if env['use_lsan']: env.Append(CCFLAGS=['-fsanitize=leak']) env.Append(LINKFLAGS=['-fsanitize=leak']) diff --git a/platform/x11/detect_prime.cpp b/platform/x11/detect_prime.cpp new file mode 100644 index 0000000000..04a825fac9 --- /dev/null +++ b/platform/x11/detect_prime.cpp @@ -0,0 +1,233 @@ +/*************************************************************************/ +/* detect_prime.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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. */ +/*************************************************************************/ + +#ifdef X11_ENABLED +#if defined(OPENGL_ENABLED) + +#include "core/print_string.h" +#include "core/ustring.h" + +#include <stdlib.h> + +#include <GL/gl.h> +#include <GL/glx.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> + +#include <cstring> + +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> + +#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091 +#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092 + +typedef GLXContext (*GLXCREATECONTEXTATTRIBSARBPROC)(Display *, GLXFBConfig, GLXContext, Bool, const int *); + +struct vendor { + const char *glxvendor; + int priority; +}; + +vendor vendormap[] = { + { "Advanced Micro Devices, Inc.", 30 }, + { "NVIDIA Corporation", 30 }, + { "X.Org", 30 }, + { "Intel Open Source Technology Center", 20 }, + { "nouveau", 10 }, + { "Mesa Project", 0 }, + { NULL, 0 } +}; + +// Runs inside a child. Exiting will not quit the engine. +void create_context() { + Display *x11_display = XOpenDisplay(NULL); + Window x11_window; + GLXContext glx_context; + + GLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB = (GLXCREATECONTEXTATTRIBSARBPROC)glXGetProcAddress((const GLubyte *)"glXCreateContextAttribsARB"); + + static int visual_attribs[] = { + GLX_RENDER_TYPE, GLX_RGBA_BIT, + GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, + GLX_DOUBLEBUFFER, true, + GLX_RED_SIZE, 1, + GLX_GREEN_SIZE, 1, + GLX_BLUE_SIZE, 1, + GLX_DEPTH_SIZE, 24, + None + }; + + int fbcount; + GLXFBConfig fbconfig = 0; + XVisualInfo *vi = NULL; + + XSetWindowAttributes swa; + swa.event_mask = StructureNotifyMask; + swa.border_pixel = 0; + unsigned long valuemask = CWBorderPixel | CWColormap | CWEventMask; + + GLXFBConfig *fbc = glXChooseFBConfig(x11_display, DefaultScreen(x11_display), visual_attribs, &fbcount); + if (!fbc) + exit(1); + + vi = glXGetVisualFromFBConfig(x11_display, fbc[0]); + + fbconfig = fbc[0]; + + static int context_attribs[] = { + GLX_CONTEXT_MAJOR_VERSION_ARB, 3, + GLX_CONTEXT_MINOR_VERSION_ARB, 3, + GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, + GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, + None + }; + + glx_context = glXCreateContextAttribsARB(x11_display, fbconfig, NULL, true, context_attribs); + + swa.colormap = XCreateColormap(x11_display, RootWindow(x11_display, vi->screen), vi->visual, AllocNone); + x11_window = XCreateWindow(x11_display, RootWindow(x11_display, vi->screen), 0, 0, 10, 10, 0, vi->depth, InputOutput, vi->visual, valuemask, &swa); + + if (!x11_window) + exit(1); + + glXMakeCurrent(x11_display, x11_window, glx_context); + XFree(vi); +} + +int detect_prime() { + pid_t p; + int priorities[2]; + String vendors[2]; + String renderers[2]; + + vendors[0] = "Unknown"; + vendors[1] = "Unknown"; + renderers[0] = "Unknown"; + renderers[1] = "Unknown"; + + for (int i = 0; i < 2; ++i) { + int fdset[2]; + + if (pipe(fdset) == -1) { + print_verbose("Failed to pipe(), using default GPU"); + return 0; + } + + // Fork so the driver initialization can crash without taking down the engine. + p = fork(); + + if (p > 0) { + // Main thread + + int stat_loc = 0; + char string[201]; + string[200] = '\0'; + + close(fdset[1]); + + waitpid(p, &stat_loc, 0); + + if (!stat_loc) { + // No need to do anything complicated here. Anything less than + // PIPE_BUF will be delivered in one read() call. + read(fdset[0], string, sizeof(string) - 1); + + vendors[i] = string; + renderers[i] = string + strlen(string) + 1; + } + + close(fdset[0]); + + } else { + // In child, exit() here will not quit the engine. + + char string[201]; + + close(fdset[0]); + + if (i) setenv("DRI_PRIME", "1", 1); + create_context(); + + const char *vendor = (const char *)glGetString(GL_VENDOR); + const char *renderer = (const char *)glGetString(GL_RENDERER); + + int vendor_len = strlen(vendor) + 1; + int renderer_len = strlen(renderer) + 1; + + if (vendor_len + renderer_len >= sizeof(string)) { + renderer_len = 200 - vendor_len; + } + + memcpy(&string, vendor, vendor_len); + memcpy(&string[vendor_len], renderer, renderer_len); + + write(fdset[1], string, vendor_len + renderer_len); + + close(fdset[1]); + exit(0); + } + } + + int preferred = 0; + int priority = 0; + + if (vendors[0] == vendors[1]) { + print_verbose("Only one GPU found, using default."); + return 0; + } + + for (int i = 1; i >= 0; --i) { + vendor *v = vendormap; + while (v->glxvendor) { + if (v->glxvendor == vendors[i]) { + priorities[i] = v->priority; + + if (v->priority >= priority) { + priority = v->priority; + preferred = i; + } + } + ++v; + } + } + + print_verbose("Found renderers:"); + for (int i = 0; i < 2; ++i) { + print_verbose("Renderer " + itos(i) + ": " + renderers[i] + " with priority: " + itos(priorities[i])); + } + + print_verbose("Using renderer: " + renderers[preferred]); + return preferred; +} + +#endif +#endif diff --git a/platform/x11/detect_prime.h b/platform/x11/detect_prime.h new file mode 100644 index 0000000000..13bcf6fc38 --- /dev/null +++ b/platform/x11/detect_prime.h @@ -0,0 +1,37 @@ +/*************************************************************************/ +/* detect_prime.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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. */ +/*************************************************************************/ + +#ifdef X11_ENABLED +#if defined(OPENGL_ENABLED) + +int detect_prime(); + +#endif +#endif diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp index 0db79fa3e9..e0924fc982 100644 --- a/platform/x11/os_x11.cpp +++ b/platform/x11/os_x11.cpp @@ -29,6 +29,8 @@ /*************************************************************************/ #include "os_x11.h" +#include "detect_prime.h" + #include "core/os/dir_access.h" #include "core/print_string.h" #include "drivers/gles2/rasterizer_gles2.h" @@ -240,28 +242,15 @@ Error OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_a // maybe contextgl wants to be in charge of creating the window #if defined(OPENGL_ENABLED) - // Set DRI_PRIME if not set. This means that Godot should default to a higher-power GPU if it exists. - // Note: Due to the final '0' parameter to setenv any existing DRI_PRIME environment variables will not - // be overwritten. - bool enable_dri_prime = true; - // Check if Nouveau is loaded, we don't want to force dGPU usage with that driver. - if (FileAccess *f = FileAccess::open("/proc/modules", FileAccess::READ)) { - // Match driver name + space - String nouveau_str = "nouveau "; - - while (!f->eof_reached()) { - String line = f->get_line(); - - if (line.begins_with(nouveau_str)) { - enable_dri_prime = false; - break; - } + if (getenv("DRI_PRIME") == NULL) { + print_verbose("Detecting GPUs, set DRI_PRIME in the environment to override GPU detection logic."); + int use_prime = detect_prime(); + + if (use_prime) { + print_line("Found discrete GPU, setting DRI_PRIME=1 to use it."); + print_line("Note: Set DRI_PRIME=0 in the environment to disable Godot from using the discrete GPU."); + setenv("DRI_PRIME", "1", 1); } - f->close(); - memdelete(f); - } - if (enable_dri_prime) { - setenv("DRI_PRIME", "1", 0); } ContextGL_X11::ContextType opengl_api_type = ContextGL_X11::GLES_3_0_COMPATIBLE; |