summaryrefslogtreecommitdiff
path: root/platform
diff options
context:
space:
mode:
Diffstat (limited to 'platform')
-rw-r--r--platform/android/dir_access_jandroid.cpp5
-rw-r--r--platform/android/dir_access_jandroid.h2
-rw-r--r--platform/android/export/export.cpp49
-rw-r--r--platform/android/thread_jandroid.cpp17
-rw-r--r--platform/iphone/export/export.cpp24
-rw-r--r--platform/javascript/export/export.cpp4
-rw-r--r--platform/javascript/os_javascript.cpp20
-rw-r--r--platform/osx/detect.py2
-rw-r--r--platform/osx/export/export.cpp4
-rw-r--r--platform/osx/os_osx.h9
-rw-r--r--platform/osx/os_osx.mm72
-rw-r--r--platform/uwp/export/export.cpp26
-rw-r--r--platform/uwp/os_uwp.cpp5
-rw-r--r--platform/uwp/os_uwp.h1
-rw-r--r--platform/windows/detect.py8
-rw-r--r--platform/windows/export/export.cpp4
-rw-r--r--platform/windows/joypad.cpp7
-rw-r--r--platform/windows/os_windows.cpp33
-rw-r--r--platform/windows/os_windows.h1
-rw-r--r--platform/x11/SCsub1
-rw-r--r--platform/x11/detect.py22
-rw-r--r--platform/x11/detect_prime.cpp233
-rw-r--r--platform/x11/detect_prime.h37
-rw-r--r--platform/x11/os_x11.cpp31
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;