diff options
Diffstat (limited to 'platform/linuxbsd')
-rw-r--r-- | platform/linuxbsd/crash_handler_linuxbsd.cpp | 10 | ||||
-rw-r--r-- | platform/linuxbsd/detect.py | 25 | ||||
-rw-r--r-- | platform/linuxbsd/freedesktop_portal_desktop.cpp | 117 | ||||
-rw-r--r-- | platform/linuxbsd/freedesktop_portal_desktop.h | 12 | ||||
-rw-r--r-- | platform/linuxbsd/godot_linuxbsd.cpp | 2 | ||||
-rw-r--r-- | platform/linuxbsd/platform_config.h | 2 | ||||
-rw-r--r-- | platform/linuxbsd/platform_gl.h | 45 | ||||
-rw-r--r-- | platform/linuxbsd/tts_linux.cpp | 20 | ||||
-rw-r--r-- | platform/linuxbsd/tts_linux.h | 4 | ||||
-rw-r--r-- | platform/linuxbsd/x11/SCsub | 4 | ||||
-rw-r--r-- | platform/linuxbsd/x11/detect_prime_x11.cpp | 14 | ||||
-rw-r--r-- | platform/linuxbsd/x11/display_server_x11.cpp | 395 | ||||
-rw-r--r-- | platform/linuxbsd/x11/display_server_x11.h | 5 | ||||
-rw-r--r-- | platform/linuxbsd/x11/gl_manager_x11.cpp | 24 | ||||
-rw-r--r-- | platform/linuxbsd/x11/gl_manager_x11.h | 1 | ||||
-rw-r--r-- | platform/linuxbsd/x11/gl_manager_x11_egl.cpp | 63 | ||||
-rw-r--r-- | platform/linuxbsd/x11/gl_manager_x11_egl.h | 61 |
17 files changed, 664 insertions, 140 deletions
diff --git a/platform/linuxbsd/crash_handler_linuxbsd.cpp b/platform/linuxbsd/crash_handler_linuxbsd.cpp index 3a245460b4..fd4bcf92be 100644 --- a/platform/linuxbsd/crash_handler_linuxbsd.cpp +++ b/platform/linuxbsd/crash_handler_linuxbsd.cpp @@ -49,6 +49,10 @@ #include <stdlib.h> static void handle_crash(int sig) { + signal(SIGSEGV, SIG_DFL); + signal(SIGFPE, SIG_DFL); + signal(SIGILL, SIG_DFL); + if (OS::get_singleton() == nullptr) { abort(); } @@ -156,9 +160,9 @@ void CrashHandler::disable() { } #ifdef CRASH_HANDLER_ENABLED - signal(SIGSEGV, nullptr); - signal(SIGFPE, nullptr); - signal(SIGILL, nullptr); + signal(SIGSEGV, SIG_DFL); + signal(SIGFPE, SIG_DFL); + signal(SIGILL, SIG_DFL); #endif disabled = true; diff --git a/platform/linuxbsd/detect.py b/platform/linuxbsd/detect.py index a723bb5d58..59cc6e7962 100644 --- a/platform/linuxbsd/detect.py +++ b/platform/linuxbsd/detect.py @@ -85,6 +85,16 @@ def configure(env: "Environment"): # gdb works fine without it though, so maybe our crash handler could too. env.Append(LINKFLAGS=["-rdynamic"]) + # Cross-compilation + # TODO: Support cross-compilation on architectures other than x86. + host_is_64_bit = sys.maxsize > 2**32 + if host_is_64_bit and env["arch"] == "x86_32": + env.Append(CCFLAGS=["-m32"]) + env.Append(LINKFLAGS=["-m32"]) + elif not host_is_64_bit and env["arch"] == "x86_64": + env.Append(CCFLAGS=["-m64"]) + env.Append(LINKFLAGS=["-m64"]) + # CPU architecture flags. if env["arch"] == "rv64": # G = General-purpose extensions, C = Compression extension (very common). @@ -106,7 +116,7 @@ def configure(env: "Environment"): print("Using linker program: " + env["linker"]) if env["linker"] == "mold" and using_gcc(env): # GCC < 12.1 doesn't support -fuse-ld=mold. cc_version = get_compiler_version(env) - cc_semver = (int(cc_version["major"]), int(cc_version["minor"])) + cc_semver = (cc_version["major"], cc_version["minor"]) if cc_semver < (12, 1): found_wrapper = False for path in ["/usr/libexec", "/usr/local/libexec", "/usr/lib", "/usr/local/lib"]: @@ -455,7 +465,7 @@ def configure(env: "Environment"): linker_version_str = subprocess.check_output( [env.subst(env["LINK"]), "-Wl,--version"] + env.subst(env["LINKFLAGS"]) ).decode("utf-8") - gnu_ld_version = re.search("^GNU ld [^$]*(\d+\.\d+)$", linker_version_str, re.MULTILINE) + gnu_ld_version = re.search(r"^GNU ld [^$]*(\d+\.\d+)$", linker_version_str, re.MULTILINE) if not gnu_ld_version: print( "Warning: Creating export template binaries enabled for PCK embedding is currently only supported with GNU ld, not gold, LLD or mold." @@ -469,22 +479,11 @@ def configure(env: "Environment"): if platform.system() == "FreeBSD": env.Append(LINKFLAGS=["-lkvm"]) - ## Cross-compilation - # TODO: Support cross-compilation on architectures other than x86. - host_is_64_bit = sys.maxsize > 2**32 - if host_is_64_bit and env["arch"] == "x86_32": - env.Append(CCFLAGS=["-m32"]) - env.Append(LINKFLAGS=["-m32", "-L/usr/lib/i386-linux-gnu"]) - elif not host_is_64_bit and env["arch"] == "x86_64": - env.Append(CCFLAGS=["-m64"]) - env.Append(LINKFLAGS=["-m64", "-L/usr/lib/i686-linux-gnu"]) - # Link those statically for portability if env["use_static_cpp"]: env.Append(LINKFLAGS=["-static-libgcc", "-static-libstdc++"]) if env["use_llvm"] and platform.system() != "FreeBSD": env["LINKCOM"] = env["LINKCOM"] + " -l:libatomic.a" - else: if env["use_llvm"] and platform.system() != "FreeBSD": env.Append(LIBS=["atomic"]) diff --git a/platform/linuxbsd/freedesktop_portal_desktop.cpp b/platform/linuxbsd/freedesktop_portal_desktop.cpp index 91c14e0e91..d9aa98ba70 100644 --- a/platform/linuxbsd/freedesktop_portal_desktop.cpp +++ b/platform/linuxbsd/freedesktop_portal_desktop.cpp @@ -142,36 +142,40 @@ void FreeDesktopPortalDesktop::append_dbus_string(DBusMessageIter *p_iter, const } } -void FreeDesktopPortalDesktop::append_dbus_dict_filters(DBusMessageIter *p_iter, const Vector<String> &p_filters) { +void FreeDesktopPortalDesktop::append_dbus_dict_filters(DBusMessageIter *p_iter, const Vector<String> &p_filter_names, const Vector<String> &p_filter_exts) { DBusMessageIter dict_iter; DBusMessageIter var_iter; DBusMessageIter arr_iter; const char *filters_key = "filters"; + ERR_FAIL_COND(p_filter_names.size() != p_filter_exts.size()); + dbus_message_iter_open_container(p_iter, DBUS_TYPE_DICT_ENTRY, nullptr, &dict_iter); dbus_message_iter_append_basic(&dict_iter, DBUS_TYPE_STRING, &filters_key); dbus_message_iter_open_container(&dict_iter, DBUS_TYPE_VARIANT, "a(sa(us))", &var_iter); dbus_message_iter_open_container(&var_iter, DBUS_TYPE_ARRAY, "(sa(us))", &arr_iter); - for (int i = 0; i < p_filters.size(); i++) { - Vector<String> tokens = p_filters[i].split(";"); - if (tokens.size() == 2) { - DBusMessageIter struct_iter; - DBusMessageIter array_iter; - DBusMessageIter array_struct_iter; - dbus_message_iter_open_container(&arr_iter, DBUS_TYPE_STRUCT, nullptr, &struct_iter); - append_dbus_string(&struct_iter, tokens[0]); - - dbus_message_iter_open_container(&struct_iter, DBUS_TYPE_ARRAY, "(us)", &array_iter); + for (int i = 0; i < p_filter_names.size(); i++) { + DBusMessageIter struct_iter; + DBusMessageIter array_iter; + DBusMessageIter array_struct_iter; + dbus_message_iter_open_container(&arr_iter, DBUS_TYPE_STRUCT, nullptr, &struct_iter); + append_dbus_string(&struct_iter, p_filter_names[i]); + + dbus_message_iter_open_container(&struct_iter, DBUS_TYPE_ARRAY, "(us)", &array_iter); + String flt = p_filter_exts[i]; + int filter_slice_count = flt.get_slice_count(","); + for (int j = 0; j < filter_slice_count; j++) { dbus_message_iter_open_container(&array_iter, DBUS_TYPE_STRUCT, nullptr, &array_struct_iter); + String str = (flt.get_slice(",", j).strip_edges()); { const unsigned nil = 0; dbus_message_iter_append_basic(&array_struct_iter, DBUS_TYPE_UINT32, &nil); } - append_dbus_string(&array_struct_iter, tokens[1]); + append_dbus_string(&array_struct_iter, str); dbus_message_iter_close_container(&array_iter, &array_struct_iter); - dbus_message_iter_close_container(&struct_iter, &array_iter); - dbus_message_iter_close_container(&arr_iter, &struct_iter); } + dbus_message_iter_close_container(&struct_iter, &array_iter); + dbus_message_iter_close_container(&arr_iter, &struct_iter); } dbus_message_iter_close_container(&var_iter, &arr_iter); dbus_message_iter_close_container(&dict_iter, &var_iter); @@ -219,7 +223,7 @@ void FreeDesktopPortalDesktop::append_dbus_dict_bool(DBusMessageIter *p_iter, co dbus_message_iter_close_container(p_iter, &dict_iter); } -bool FreeDesktopPortalDesktop::file_chooser_parse_response(DBusMessageIter *p_iter, bool &r_cancel, Vector<String> &r_urls) { +bool FreeDesktopPortalDesktop::file_chooser_parse_response(DBusMessageIter *p_iter, const Vector<String> &p_names, bool &r_cancel, Vector<String> &r_urls, int &r_index) { ERR_FAIL_COND_V(dbus_message_iter_get_arg_type(p_iter) != DBUS_TYPE_UINT32, false); dbus_uint32_t resp_code; @@ -243,7 +247,22 @@ bool FreeDesktopPortalDesktop::file_chooser_parse_response(DBusMessageIter *p_it DBusMessageIter var_iter; dbus_message_iter_recurse(&iter, &var_iter); - if (strcmp(key, "uris") == 0) { + if (strcmp(key, "current_filter") == 0) { // (sa(us)) + if (dbus_message_iter_get_arg_type(&var_iter) == DBUS_TYPE_STRUCT) { + DBusMessageIter struct_iter; + dbus_message_iter_recurse(&var_iter, &struct_iter); + while (dbus_message_iter_get_arg_type(&struct_iter) == DBUS_TYPE_STRING) { + const char *value; + dbus_message_iter_get_basic(&struct_iter, &value); + String name = String::utf8(value); + + r_index = p_names.find(name); + if (!dbus_message_iter_next(&struct_iter)) { + break; + } + } + } + } else if (strcmp(key, "uris") == 0) { // as if (dbus_message_iter_get_arg_type(&var_iter) == DBUS_TYPE_ARRAY) { DBusMessageIter uri_iter; dbus_message_iter_recurse(&var_iter, &uri_iter); @@ -266,17 +285,43 @@ bool FreeDesktopPortalDesktop::file_chooser_parse_response(DBusMessageIter *p_it return true; } -Error FreeDesktopPortalDesktop::file_dialog_show(const String &p_xid, const String &p_title, const String &p_current_directory, const String &p_filename, DisplayServer::FileDialogMode p_mode, const Vector<String> &p_filters, const Callable &p_callback) { +Error FreeDesktopPortalDesktop::file_dialog_show(DisplayServer::WindowID p_window_id, const String &p_xid, const String &p_title, const String &p_current_directory, const String &p_filename, DisplayServer::FileDialogMode p_mode, const Vector<String> &p_filters, const Callable &p_callback) { if (unsupported) { return FAILED; } + ERR_FAIL_INDEX_V(int(p_mode), DisplayServer::FILE_DIALOG_MODE_SAVE_MAX, FAILED); + + Vector<String> filter_names; + Vector<String> filter_exts; + for (int i = 0; i < p_filters.size(); i++) { + Vector<String> tokens = p_filters[i].split(";"); + if (tokens.size() >= 1) { + String flt = tokens[0].strip_edges(); + if (!flt.is_empty()) { + if (tokens.size() == 2) { + filter_exts.push_back(flt); + filter_names.push_back(tokens[1]); + } else { + filter_exts.push_back(flt); + filter_names.push_back(flt); + } + } + } + } + if (filter_names.is_empty()) { + filter_exts.push_back("*.*"); + filter_names.push_back(RTR("All Files")); + } + DBusError err; dbus_error_init(&err); // Open connection and add signal handler. FileDialogData fd; fd.callback = p_callback; + fd.prev_focus = p_window_id; + fd.filter_names = filter_names; CryptoCore::RandomGenerator rng; ERR_FAIL_COND_V_MSG(rng.init(), FAILED, "Failed to initialize random number generator."); @@ -307,16 +352,10 @@ Error FreeDesktopPortalDesktop::file_dialog_show(const String &p_xid, const Stri // Generate FileChooser message. const char *method = nullptr; - switch (p_mode) { - case DisplayServer::FILE_DIALOG_MODE_SAVE_FILE: { - method = "SaveFile"; - } break; - case DisplayServer::FILE_DIALOG_MODE_OPEN_ANY: - case DisplayServer::FILE_DIALOG_MODE_OPEN_FILE: - case DisplayServer::FILE_DIALOG_MODE_OPEN_DIR: - case DisplayServer::FILE_DIALOG_MODE_OPEN_FILES: { - method = "OpenFile"; - } break; + if (p_mode == DisplayServer::FILE_DIALOG_MODE_SAVE_FILE) { + method = "SaveFile"; + } else { + method = "OpenFile"; } DBusMessage *message = dbus_message_new_method_call(BUS_OBJECT_NAME, BUS_OBJECT_PATH, BUS_INTERFACE_FILE_CHOOSER, method); @@ -333,7 +372,7 @@ Error FreeDesktopPortalDesktop::file_dialog_show(const String &p_xid, const Stri append_dbus_dict_string(&arr_iter, "handle_token", token); append_dbus_dict_bool(&arr_iter, "multiple", p_mode == DisplayServer::FILE_DIALOG_MODE_OPEN_FILES); append_dbus_dict_bool(&arr_iter, "directory", p_mode == DisplayServer::FILE_DIALOG_MODE_OPEN_DIR); - append_dbus_dict_filters(&arr_iter, p_filters); + append_dbus_dict_filters(&arr_iter, filter_names, filter_exts); append_dbus_dict_string(&arr_iter, "current_folder", p_current_directory, true); if (p_mode == DisplayServer::FILE_DIALOG_MODE_SAVE_FILE) { append_dbus_dict_string(&arr_iter, "current_name", p_filename); @@ -388,6 +427,17 @@ Error FreeDesktopPortalDesktop::file_dialog_show(const String &p_xid, const Stri return OK; } +void FreeDesktopPortalDesktop::_file_dialog_callback(const Callable &p_callable, const Variant &p_status, const Variant &p_list, const Variant &p_index) { + Variant ret; + Callable::CallError ce; + const Variant *args[3] = { &p_status, &p_list, &p_index }; + + p_callable.callp(args, 3, ret, ce); + if (ce.error != Callable::CallError::CALL_OK) { + ERR_PRINT(vformat(RTR("Failed to execute file dialogs callback: %s."), Variant::get_callable_error_text(p_callable, args, 3, ce))); + } +} + void FreeDesktopPortalDesktop::_thread_file_dialog_monitor(void *p_ud) { FreeDesktopPortalDesktop *portal = (FreeDesktopPortalDesktop *)p_ud; @@ -408,13 +458,14 @@ void FreeDesktopPortalDesktop::_thread_file_dialog_monitor(void *p_ud) { if (dbus_message_iter_init(msg, &iter)) { bool cancel = false; Vector<String> uris; - file_chooser_parse_response(&iter, cancel, uris); + int index = 0; + file_chooser_parse_response(&iter, fd.filter_names, cancel, uris, index); if (fd.callback.is_valid()) { - Variant v_status = !cancel; - Variant v_files = uris; - Variant *v_args[2] = { &v_status, &v_files }; - fd.callback.call_deferredp((const Variant **)&v_args, 2); + callable_mp(portal, &FreeDesktopPortalDesktop::_file_dialog_callback).call_deferred(fd.callback, !cancel, uris, index); + } + if (fd.prev_focus != DisplayServer::INVALID_WINDOW_ID) { + callable_mp(DisplayServer::get_singleton(), &DisplayServer::window_move_to_foreground).call_deferred(fd.prev_focus); } } dbus_message_unref(msg); diff --git a/platform/linuxbsd/freedesktop_portal_desktop.h b/platform/linuxbsd/freedesktop_portal_desktop.h index a9b83b3844..71e9812ea9 100644 --- a/platform/linuxbsd/freedesktop_portal_desktop.h +++ b/platform/linuxbsd/freedesktop_portal_desktop.h @@ -40,7 +40,7 @@ struct DBusMessage; struct DBusConnection; struct DBusMessageIter; -class FreeDesktopPortalDesktop { +class FreeDesktopPortalDesktop : public Object { private: bool unsupported = false; @@ -49,13 +49,17 @@ private: bool read_setting(const char *p_namespace, const char *p_key, int p_type, void *r_value); static void append_dbus_string(DBusMessageIter *p_iter, const String &p_string); - static void append_dbus_dict_filters(DBusMessageIter *p_iter, const Vector<String> &p_filters); + static void append_dbus_dict_filters(DBusMessageIter *p_iter, const Vector<String> &p_filter_names, const Vector<String> &p_filter_exts); static void append_dbus_dict_string(DBusMessageIter *p_iter, const String &p_key, const String &p_value, bool p_as_byte_array = false); static void append_dbus_dict_bool(DBusMessageIter *p_iter, const String &p_key, bool p_value); - static bool file_chooser_parse_response(DBusMessageIter *p_iter, bool &r_cancel, Vector<String> &r_urls); + static bool file_chooser_parse_response(DBusMessageIter *p_iter, const Vector<String> &p_names, bool &r_cancel, Vector<String> &r_urls, int &r_index); + + void _file_dialog_callback(const Callable &p_callable, const Variant &p_status, const Variant &p_list, const Variant &p_index); struct FileDialogData { + Vector<String> filter_names; DBusConnection *connection = nullptr; + DisplayServer::WindowID prev_focus = DisplayServer::INVALID_WINDOW_ID; Callable callback; String path; }; @@ -73,7 +77,7 @@ public: bool is_supported() { return !unsupported; } - Error file_dialog_show(const String &p_xid, const String &p_title, const String &p_current_directory, const String &p_filename, DisplayServer::FileDialogMode p_mode, const Vector<String> &p_filters, const Callable &p_callback); + Error file_dialog_show(DisplayServer::WindowID p_window_id, const String &p_xid, const String &p_title, const String &p_current_directory, const String &p_filename, DisplayServer::FileDialogMode p_mode, const Vector<String> &p_filters, const Callable &p_callback); // Retrieve the system's preferred color scheme. // 0: No preference or unknown. diff --git a/platform/linuxbsd/godot_linuxbsd.cpp b/platform/linuxbsd/godot_linuxbsd.cpp index d059d60b72..efad9c8594 100644 --- a/platform/linuxbsd/godot_linuxbsd.cpp +++ b/platform/linuxbsd/godot_linuxbsd.cpp @@ -56,7 +56,7 @@ int main(int argc, char *argv[]) { TEST_MAIN_OVERRIDE char *cwd = (char *)malloc(PATH_MAX); - ERR_FAIL_COND_V(!cwd, ERR_OUT_OF_MEMORY); + ERR_FAIL_NULL_V(cwd, ERR_OUT_OF_MEMORY); char *ret = getcwd(cwd, PATH_MAX); Error err = Main::setup(argv[0], argc - 1, &argv[1]); diff --git a/platform/linuxbsd/platform_config.h b/platform/linuxbsd/platform_config.h index 82c9c54879..c372ef28f6 100644 --- a/platform/linuxbsd/platform_config.h +++ b/platform/linuxbsd/platform_config.h @@ -43,5 +43,3 @@ #define PTHREAD_BSD_SET_NAME #endif #endif - -#define OPENGL_INCLUDE_H "thirdparty/glad/glad/gl.h" diff --git a/platform/linuxbsd/platform_gl.h b/platform/linuxbsd/platform_gl.h new file mode 100644 index 0000000000..5d4c2d8978 --- /dev/null +++ b/platform/linuxbsd/platform_gl.h @@ -0,0 +1,45 @@ +/**************************************************************************/ +/* platform_gl.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#ifndef PLATFORM_GL_H +#define PLATFORM_GL_H + +#ifndef GL_API_ENABLED +#define GL_API_ENABLED // Allow using desktop GL. +#endif + +#ifndef GLES_API_ENABLED +#define GLES_API_ENABLED // Allow using GLES. +#endif + +#include "thirdparty/glad/glad/egl.h" +#include "thirdparty/glad/glad/gl.h" + +#endif // PLATFORM_GL_H diff --git a/platform/linuxbsd/tts_linux.cpp b/platform/linuxbsd/tts_linux.cpp index 8bc83f5b9c..46291bb4da 100644 --- a/platform/linuxbsd/tts_linux.cpp +++ b/platform/linuxbsd/tts_linux.cpp @@ -82,11 +82,11 @@ void TTS_Linux::speech_init_thread_func(void *p_userdata) { void TTS_Linux::speech_event_index_mark(size_t p_msg_id, size_t p_client_id, SPDNotificationType p_type, char *p_index_mark) { TTS_Linux *tts = TTS_Linux::get_singleton(); if (tts) { - callable_mp(tts, &TTS_Linux::_speech_index_mark).call_deferred(p_msg_id, p_client_id, (int)p_type, String::utf8(p_index_mark)); + callable_mp(tts, &TTS_Linux::_speech_index_mark).call_deferred((int)p_msg_id, (int)p_type, String::utf8(p_index_mark)); } } -void TTS_Linux::_speech_index_mark(size_t p_msg_id, size_t p_client_id, int p_type, const String &p_index_mark) { +void TTS_Linux::_speech_index_mark(int p_msg_id, int p_type, const String &p_index_mark) { _THREAD_SAFE_METHOD_ if (ids.has(p_msg_id)) { @@ -97,7 +97,7 @@ void TTS_Linux::_speech_index_mark(size_t p_msg_id, size_t p_client_id, int p_ty void TTS_Linux::speech_event_callback(size_t p_msg_id, size_t p_client_id, SPDNotificationType p_type) { TTS_Linux *tts = TTS_Linux::get_singleton(); if (tts) { - callable_mp(tts, &TTS_Linux::_speech_event).call_deferred(p_msg_id, p_client_id, (int)p_type); + callable_mp(tts, &TTS_Linux::_speech_event).call_deferred((int)p_msg_id, (int)p_type); } } @@ -119,7 +119,7 @@ void TTS_Linux::_load_voices() { } } -void TTS_Linux::_speech_event(size_t p_msg_id, size_t p_client_id, int p_type) { +void TTS_Linux::_speech_event(int p_msg_id, int p_type) { _THREAD_SAFE_METHOD_ if (!paused && ids.has(p_msg_id)) { @@ -186,7 +186,7 @@ bool TTS_Linux::is_paused() const { Array TTS_Linux::get_voices() const { _THREAD_SAFE_METHOD_ - ERR_FAIL_COND_V(!synth, Array()); + ERR_FAIL_NULL_V(synth, Array()); const_cast<TTS_Linux *>(this)->_load_voices(); Array list; @@ -204,7 +204,7 @@ Array TTS_Linux::get_voices() const { void TTS_Linux::speak(const String &p_text, const String &p_voice, int p_volume, float p_pitch, float p_rate, int p_utterance_id, bool p_interrupt) { _THREAD_SAFE_METHOD_ - ERR_FAIL_COND(!synth); + ERR_FAIL_NULL(synth); if (p_interrupt) { stop(); } @@ -226,14 +226,14 @@ void TTS_Linux::speak(const String &p_text, const String &p_voice, int p_volume, if (is_paused()) { resume(); } else { - _speech_event(0, 0, (int)SPD_EVENT_BEGIN); + _speech_event(0, (int)SPD_EVENT_BEGIN); } } void TTS_Linux::pause() { _THREAD_SAFE_METHOD_ - ERR_FAIL_COND(!synth); + ERR_FAIL_NULL(synth); if (spd_pause(synth) == 0) { paused = true; } @@ -242,7 +242,7 @@ void TTS_Linux::pause() { void TTS_Linux::resume() { _THREAD_SAFE_METHOD_ - ERR_FAIL_COND(!synth); + ERR_FAIL_NULL(synth); spd_resume(synth); paused = false; } @@ -250,7 +250,7 @@ void TTS_Linux::resume() { void TTS_Linux::stop() { _THREAD_SAFE_METHOD_ - ERR_FAIL_COND(!synth); + ERR_FAIL_NULL(synth); for (DisplayServer::TTSUtterance &message : queue) { DisplayServer::get_singleton()->tts_post_utterance_event(DisplayServer::TTS_UTTERANCE_CANCELED, message.id); } diff --git a/platform/linuxbsd/tts_linux.h b/platform/linuxbsd/tts_linux.h index ec68219689..2a3d33221d 100644 --- a/platform/linuxbsd/tts_linux.h +++ b/platform/linuxbsd/tts_linux.h @@ -72,8 +72,8 @@ class TTS_Linux : public Object { protected: void _load_voices(); - void _speech_event(size_t p_msg_id, size_t p_client_id, int p_type); - void _speech_index_mark(size_t p_msg_id, size_t p_client_id, int p_type, const String &p_index_mark); + void _speech_event(int p_msg_id, int p_type); + void _speech_index_mark(int p_msg_id, int p_type, const String &p_index_mark); public: static TTS_Linux *get_singleton(); diff --git a/platform/linuxbsd/x11/SCsub b/platform/linuxbsd/x11/SCsub index a4890391ce..bbfaaf10d1 100644 --- a/platform/linuxbsd/x11/SCsub +++ b/platform/linuxbsd/x11/SCsub @@ -25,7 +25,9 @@ if env["vulkan"]: if env["opengl3"]: env.Append(CPPDEFINES=["GLAD_GLX_NO_X11"]) - source_files.append(["gl_manager_x11.cpp", "detect_prime_x11.cpp", "#thirdparty/glad/glx.c"]) + source_files.append( + ["gl_manager_x11_egl.cpp", "gl_manager_x11.cpp", "detect_prime_x11.cpp", "#thirdparty/glad/glx.c"] + ) objects = [] diff --git a/platform/linuxbsd/x11/detect_prime_x11.cpp b/platform/linuxbsd/x11/detect_prime_x11.cpp index 2b5776ce54..c2cb02b937 100644 --- a/platform/linuxbsd/x11/detect_prime_x11.cpp +++ b/platform/linuxbsd/x11/detect_prime_x11.cpp @@ -137,6 +137,19 @@ void create_context() { XFree(vi); } +int silent_error_handler(Display *display, XErrorEvent *error) { + static char message[1024]; + XGetErrorText(display, error->error_code, message, sizeof(message)); + print_verbose(vformat("XServer error: %s" + "\n Major opcode of failed request: %d" + "\n Serial number of failed request: %d" + "\n Current serial number in output stream: %d", + String::utf8(message), (uint64_t)error->request_code, (uint64_t)error->minor_code, (uint64_t)error->serial)); + + quick_exit(1); + return 0; +} + int detect_prime() { pid_t p; int priorities[2] = {}; @@ -189,6 +202,7 @@ int detect_prime() { // cleaning up these processes, and fork() makes a copy // of all globals. CoreGlobals::leak_reporting_enabled = false; + XSetErrorHandler(&silent_error_handler); char string[201]; diff --git a/platform/linuxbsd/x11/display_server_x11.cpp b/platform/linuxbsd/x11/display_server_x11.cpp index f38a9dd278..3bafdfb53d 100644 --- a/platform/linuxbsd/x11/display_server_x11.cpp +++ b/platform/linuxbsd/x11/display_server_x11.cpp @@ -39,6 +39,7 @@ #include "core/math/math_funcs.h" #include "core/string/print_string.h" #include "core/string/ustring.h" +#include "drivers/png/png_driver_common.h" #include "main/main.h" #include "scene/resources/atlas_texture.h" @@ -307,37 +308,37 @@ void DisplayServerX11::_flush_mouse_motion() { #ifdef SPEECHD_ENABLED bool DisplayServerX11::tts_is_speaking() const { - ERR_FAIL_COND_V_MSG(!tts, false, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech."); + ERR_FAIL_NULL_V_MSG(tts, false, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech."); return tts->is_speaking(); } bool DisplayServerX11::tts_is_paused() const { - ERR_FAIL_COND_V_MSG(!tts, false, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech."); + ERR_FAIL_NULL_V_MSG(tts, false, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech."); return tts->is_paused(); } TypedArray<Dictionary> DisplayServerX11::tts_get_voices() const { - ERR_FAIL_COND_V_MSG(!tts, TypedArray<Dictionary>(), "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech."); + ERR_FAIL_NULL_V_MSG(tts, TypedArray<Dictionary>(), "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech."); return tts->get_voices(); } void DisplayServerX11::tts_speak(const String &p_text, const String &p_voice, int p_volume, float p_pitch, float p_rate, int p_utterance_id, bool p_interrupt) { - ERR_FAIL_COND_MSG(!tts, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech."); + ERR_FAIL_NULL_MSG(tts, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech."); tts->speak(p_text, p_voice, p_volume, p_pitch, p_rate, p_utterance_id, p_interrupt); } void DisplayServerX11::tts_pause() { - ERR_FAIL_COND_MSG(!tts, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech."); + ERR_FAIL_NULL_MSG(tts, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech."); tts->pause(); } void DisplayServerX11::tts_resume() { - ERR_FAIL_COND_MSG(!tts, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech."); + ERR_FAIL_NULL_MSG(tts, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech."); tts->resume(); } void DisplayServerX11::tts_stop() { - ERR_FAIL_COND_MSG(!tts, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech."); + ERR_FAIL_NULL_MSG(tts, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech."); tts->stop(); } @@ -364,14 +365,14 @@ bool DisplayServerX11::is_dark_mode() const { } Error DisplayServerX11::file_dialog_show(const String &p_title, const String &p_current_directory, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const Callable &p_callback) { - WindowID window_id = _get_focused_window_or_popup(); + WindowID window_id = last_focused_window; if (!windows.has(window_id)) { window_id = MAIN_WINDOW_ID; } String xid = vformat("x11:%x", (uint64_t)windows[window_id].x11_window); - return portal_desktop->file_dialog_show(xid, p_title, p_current_directory, p_filename, p_mode, p_filters, p_callback); + return portal_desktop->file_dialog_show(last_focused_window, xid, p_title, p_current_directory, p_filename, p_mode, p_filters, p_callback); } #endif @@ -519,7 +520,7 @@ Bool DisplayServerX11::_predicate_clipboard_selection(Display *display, XEvent * } Bool DisplayServerX11::_predicate_clipboard_incr(Display *display, XEvent *event, XPointer arg) { - if (event->type == PropertyNotify && event->xproperty.state == PropertyNewValue) { + if (event->type == PropertyNotify && event->xproperty.state == PropertyNewValue && event->xproperty.atom == *(Atom *)arg) { return True; } else { return False; @@ -593,7 +594,7 @@ String DisplayServerX11::_clipboard_get_impl(Atom p_source, Window x11_window, A // Non-blocking wait for next event and remove it from the queue. XEvent ev; - while (XCheckIfEvent(x11_display, &ev, _predicate_clipboard_incr, nullptr)) { + while (XCheckIfEvent(x11_display, &ev, _predicate_clipboard_incr, (XPointer)&selection)) { result = XGetWindowProperty(x11_display, x11_window, selection, // selection type 0, LONG_MAX, // offset - len @@ -664,6 +665,74 @@ String DisplayServerX11::_clipboard_get_impl(Atom p_source, Window x11_window, A return ret; } +Atom DisplayServerX11::_clipboard_get_image_target(Atom p_source, Window x11_window) const { + Atom target = XInternAtom(x11_display, "TARGETS", 0); + Atom png = XInternAtom(x11_display, "image/png", 0); + Atom *valid_targets = nullptr; + unsigned long atom_count = 0; + + Window selection_owner = XGetSelectionOwner(x11_display, p_source); + if (selection_owner != None && selection_owner != x11_window) { + // Block events polling while processing selection events. + MutexLock mutex_lock(events_mutex); + + Atom selection = XA_PRIMARY; + XConvertSelection(x11_display, p_source, target, selection, x11_window, CurrentTime); + + XFlush(x11_display); + + // Blocking wait for predicate to be True and remove the event from the queue. + XEvent event; + XIfEvent(x11_display, &event, _predicate_clipboard_selection, (XPointer)&x11_window); + // Do not get any data, see how much data is there. + Atom type; + int format, result; + unsigned long len, bytes_left, dummy; + XGetWindowProperty(x11_display, x11_window, + selection, // Tricky.. + 0, 0, // offset - len + 0, // Delete 0==FALSE + XA_ATOM, // flag + &type, // return type + &format, // return format + &len, &bytes_left, // data length + (unsigned char **)&valid_targets); + + if (valid_targets) { + XFree(valid_targets); + valid_targets = nullptr; + } + + if (type == XA_ATOM && bytes_left > 0) { + // Data is ready and can be processed all at once. + result = XGetWindowProperty(x11_display, x11_window, + selection, 0, bytes_left / 4, 0, + XA_ATOM, &type, &format, + &len, &dummy, (unsigned char **)&valid_targets); + if (result == Success) { + atom_count = len; + } else { + print_verbose("Failed to get selection data."); + return None; + } + } else { + return None; + } + } else { + return None; + } + for (unsigned long i = 0; i < atom_count; i++) { + Atom atom = valid_targets[i]; + if (atom == png) { + XFree(valid_targets); + return png; + } + } + + XFree(valid_targets); + return None; +} + String DisplayServerX11::_clipboard_get(Atom p_source, Window x11_window) const { String ret; Atom utf8_atom = XInternAtom(x11_display, "UTF8_STRING", True); @@ -702,6 +771,158 @@ String DisplayServerX11::clipboard_get_primary() const { return ret; } +Ref<Image> DisplayServerX11::clipboard_get_image() const { + _THREAD_SAFE_METHOD_ + Atom clipboard = XInternAtom(x11_display, "CLIPBOARD", 0); + Window x11_window = windows[MAIN_WINDOW_ID].x11_window; + Ref<Image> ret; + Atom target = _clipboard_get_image_target(clipboard, x11_window); + if (target == None) { + return ret; + } + + Window selection_owner = XGetSelectionOwner(x11_display, clipboard); + + if (selection_owner != None && selection_owner != x11_window) { + // Block events polling while processing selection events. + MutexLock mutex_lock(events_mutex); + + // Identifier for the property the other window + // will send the converted data to. + Atom transfer_prop = XA_PRIMARY; + XConvertSelection(x11_display, + clipboard, // source selection + target, // format to convert to + transfer_prop, // output property + x11_window, CurrentTime); + + XFlush(x11_display); + + // Blocking wait for predicate to be True and remove the event from the queue. + XEvent event; + XIfEvent(x11_display, &event, _predicate_clipboard_selection, (XPointer)&x11_window); + + // Do not get any data, see how much data is there. + Atom type; + int format, result; + unsigned long len, bytes_left, dummy; + unsigned char *data; + XGetWindowProperty(x11_display, x11_window, + transfer_prop, // Property data is transferred through + 0, 1, // offset, len (4 so we can get the size if INCR is used) + 0, // Delete 0==FALSE + AnyPropertyType, // flag + &type, // return type + &format, // return format + &len, &bytes_left, // data length + &data); + + if (type == XInternAtom(x11_display, "INCR", 0)) { + ERR_FAIL_COND_V_MSG(len != 1, ret, "Incremental transfer initial value was not length."); + + // Data is going to be received incrementally. + DEBUG_LOG_X11("INCR selection started.\n"); + + LocalVector<uint8_t> incr_data; + uint32_t data_size = 0; + bool success = false; + + // Initial response is the lower bound of the length of the transferred data. + incr_data.resize(*(unsigned long *)data); + XFree(data); + data = nullptr; + + // Delete INCR property to notify the owner. + XDeleteProperty(x11_display, x11_window, transfer_prop); + + // Process events from the queue. + bool done = false; + while (!done) { + if (!_wait_for_events()) { + // Error or timeout, abort. + break; + } + // Non-blocking wait for next event and remove it from the queue. + XEvent ev; + while (XCheckIfEvent(x11_display, &ev, _predicate_clipboard_incr, (XPointer)&transfer_prop)) { + result = XGetWindowProperty(x11_display, x11_window, + transfer_prop, // output property + 0, LONG_MAX, // offset - len + True, // delete property to notify the owner + AnyPropertyType, // flag + &type, // return type + &format, // return format + &len, &bytes_left, // data length + &data); + + DEBUG_LOG_X11("PropertyNotify: len=%lu, format=%i\n", len, format); + + if (result == Success) { + if (data && (len > 0)) { + uint32_t prev_size = incr_data.size(); + // New chunk, resize to be safe and append data. + incr_data.resize(MAX(data_size + len, prev_size)); + memcpy(incr_data.ptr() + data_size, data, len); + data_size += len; + } else if (!(format == 0 && len == 0)) { + // For unclear reasons the first GetWindowProperty always returns a length and format of 0. + // Otherwise, last chunk, process finished. + done = true; + success = true; + } + } else { + print_verbose("Failed to get selection data chunk."); + done = true; + } + + if (data) { + XFree(data); + data = nullptr; + } + + if (done) { + break; + } + } + } + + if (success && (data_size > 0)) { + ret.instantiate(); + PNGDriverCommon::png_to_image(incr_data.ptr(), incr_data.size(), false, ret); + } + } else if (bytes_left > 0) { + if (data) { + XFree(data); + data = nullptr; + } + // Data is ready and can be processed all at once. + result = XGetWindowProperty(x11_display, x11_window, + transfer_prop, 0, bytes_left + 4, 0, + AnyPropertyType, &type, &format, + &len, &dummy, &data); + if (result == Success) { + ret.instantiate(); + PNGDriverCommon::png_to_image((uint8_t *)data, bytes_left, false, ret); + } else { + print_verbose("Failed to get selection data."); + } + + if (data) { + XFree(data); + } + } + } + + return ret; +} + +bool DisplayServerX11::clipboard_has_image() const { + Atom target = _clipboard_get_image_target( + XInternAtom(x11_display, "CLIPBOARD", 0), + windows[MAIN_WINDOW_ID].x11_window); + return target != None; +} + Bool DisplayServerX11::_predicate_clipboard_save_targets(Display *display, XEvent *event, XPointer arg) { if (event->xany.window == *(Window *)arg) { return (event->type == SelectionRequest) || @@ -1350,7 +1571,7 @@ float DisplayServerX11::screen_get_refresh_rate(int p_screen) const { //Use xrandr to get screen refresh rate. if (xrandr_ext_ok) { - XRRScreenResources *screen_info = XRRGetScreenResources(x11_display, windows[MAIN_WINDOW_ID].x11_window); + XRRScreenResources *screen_info = XRRGetScreenResourcesCurrent(x11_display, windows[MAIN_WINDOW_ID].x11_window); if (screen_info) { RRMode current_mode = 0; xrr_monitor_info *monitors = nullptr; @@ -1495,6 +1716,9 @@ void DisplayServerX11::delete_sub_window(WindowID p_id) { if (gl_manager) { gl_manager->window_destroy(p_id); } + if (gl_manager_egl) { + gl_manager_egl->window_destroy(p_id); + } #endif if (wd.xic) { @@ -1534,6 +1758,9 @@ int64_t DisplayServerX11::window_get_native_handle(HandleType p_handle_type, Win if (gl_manager) { return (int64_t)gl_manager->get_glx_context(p_window); } + if (gl_manager_egl) { + return (int64_t)gl_manager_egl->get_context(p_window); + } return 0; } #endif @@ -1711,6 +1938,9 @@ void DisplayServerX11::gl_window_make_current(DisplayServer::WindowID p_window_i if (gl_manager) { gl_manager->window_make_current(p_window_id); } + if (gl_manager_egl) { + gl_manager_egl->window_make_current(p_window_id); + } #endif } @@ -2012,6 +2242,9 @@ void DisplayServerX11::window_set_size(const Size2i p_size, WindowID p_window) { if (gl_manager) { gl_manager->window_resize(p_window, xwa.width, xwa.height); } + if (gl_manager_egl) { + gl_manager_egl->window_resize(p_window, xwa.width, xwa.height); + } #endif } @@ -2862,7 +3095,7 @@ void DisplayServerX11::cursor_set_custom_image(const Ref<Resource> &p_cursor, Cu *(cursor_image->pixels + index) = image->get_pixel(column_index, row_index).to_argb32(); } - ERR_FAIL_COND(cursor_image->pixels == nullptr); + ERR_FAIL_NULL(cursor_image->pixels); // Save it for a further usage cursors[p_shape] = XcursorImageLoadCursor(x11_display, cursor_image); @@ -3721,17 +3954,13 @@ void DisplayServerX11::_window_changed(XEvent *event) { if (gl_manager) { gl_manager->window_resize(window_id, wd.size.width, wd.size.height); } + if (gl_manager_egl) { + gl_manager_egl->window_resize(window_id, wd.size.width, wd.size.height); + } #endif - if (!wd.rect_changed_callback.is_null()) { - Rect2i r = new_rect; - - Variant rect = r; - - Variant *rectp = ▭ - Variant ret; - Callable::CallError ce; - wd.rect_changed_callback.callp((const Variant **)&rectp, 1, ret, ce); + if (wd.rect_changed_callback.is_valid()) { + wd.rect_changed_callback.call(new_rect); } } @@ -3749,11 +3978,6 @@ void DisplayServerX11::_dispatch_input_events(const Ref<InputEvent> &p_event) { } void DisplayServerX11::_dispatch_input_event(const Ref<InputEvent> &p_event) { - Variant ev = p_event; - Variant *evp = &ev; - Variant ret; - Callable::CallError ce; - { List<WindowID>::Element *E = popup_list.back(); if (E && Object::cast_to<InputEventKey>(*p_event)) { @@ -3761,7 +3985,7 @@ void DisplayServerX11::_dispatch_input_event(const Ref<InputEvent> &p_event) { if (windows.has(E->get())) { Callable callable = windows[E->get()].input_event_callback; if (callable.is_valid()) { - callable.callp((const Variant **)&evp, 1, ret, ce); + callable.call(p_event); } } return; @@ -3774,7 +3998,7 @@ void DisplayServerX11::_dispatch_input_event(const Ref<InputEvent> &p_event) { if (windows.has(event_from_window->get_window_id())) { Callable callable = windows[event_from_window->get_window_id()].input_event_callback; if (callable.is_valid()) { - callable.callp((const Variant **)&evp, 1, ret, ce); + callable.call(p_event); } } } else { @@ -3782,19 +4006,16 @@ void DisplayServerX11::_dispatch_input_event(const Ref<InputEvent> &p_event) { for (KeyValue<WindowID, WindowData> &E : windows) { Callable callable = E.value.input_event_callback; if (callable.is_valid()) { - callable.callp((const Variant **)&evp, 1, ret, ce); + callable.call(p_event); } } } } void DisplayServerX11::_send_window_event(const WindowData &wd, WindowEvent p_event) { - if (!wd.event_callback.is_null()) { + if (wd.event_callback.is_valid()) { Variant event = int(p_event); - Variant *eventp = &event; - Variant ret; - Callable::CallError ce; - wd.event_callback.callp((const Variant **)&eventp, 1, ret, ce); + wd.event_callback.call(event); } } @@ -4085,9 +4306,6 @@ void DisplayServerX11::process_events() { if (XGetEventData(x11_display, &event.xcookie)) { if (event.xcookie.type == GenericEvent && event.xcookie.extension == xi.opcode) { XIDeviceEvent *event_data = (XIDeviceEvent *)event.xcookie.data; - int index = event_data->detail; - Vector2 pos = Vector2(event_data->event_x, event_data->event_y); - switch (event_data->evtype) { case XI_HierarchyChanged: case XI_DeviceChanged: { @@ -4204,6 +4422,9 @@ void DisplayServerX11::process_events() { } bool is_begin = event_data->evtype == XI_TouchBegin; + int index = event_data->detail; + Vector2 pos = Vector2(event_data->event_x, event_data->event_y); + Ref<InputEventScreenTouch> st; st.instantiate(); st->set_window_id(window_id); @@ -4235,6 +4456,10 @@ void DisplayServerX11::process_events() { if (ime_window_event || ignore_events) { break; } + + int index = event_data->detail; + Vector2 pos = Vector2(event_data->event_x, event_data->event_y); + HashMap<int, Vector2>::Iterator curr_pos_elem = xi.state.find(index); if (!curr_pos_elem) { // Defensive break; @@ -4739,11 +4964,7 @@ void DisplayServerX11::process_events() { } if (!windows[window_id].drop_files_callback.is_null()) { - Variant v = files; - Variant *vp = &v; - Variant ret; - Callable::CallError ce; - windows[window_id].drop_files_callback.callp((const Variant **)&vp, 1, ret, ce); + windows[window_id].drop_files_callback.call(files); } //Reply that all is well. @@ -4855,6 +5076,9 @@ void DisplayServerX11::release_rendering_thread() { if (gl_manager) { gl_manager->release_current(); } + if (gl_manager_egl) { + gl_manager_egl->release_current(); + } #endif } @@ -4863,6 +5087,9 @@ void DisplayServerX11::make_rendering_thread() { if (gl_manager) { gl_manager->make_current(); } + if (gl_manager_egl) { + gl_manager_egl->make_current(); + } #endif } @@ -4871,6 +5098,9 @@ void DisplayServerX11::swap_buffers() { if (gl_manager) { gl_manager->swap_buffers(); } + if (gl_manager_egl) { + gl_manager_egl->swap_buffers(); + } #endif } @@ -5024,6 +5254,9 @@ void DisplayServerX11::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mo if (gl_manager) { gl_manager->set_use_vsync(p_vsync_mode != DisplayServer::VSYNC_DISABLED); } + if (gl_manager_egl) { + gl_manager_egl->set_use_vsync(p_vsync_mode != DisplayServer::VSYNC_DISABLED); + } #endif } @@ -5038,6 +5271,9 @@ DisplayServer::VSyncMode DisplayServerX11::window_get_vsync_mode(WindowID p_wind if (gl_manager) { return gl_manager->is_using_vsync() ? DisplayServer::VSYNC_ENABLED : DisplayServer::VSYNC_DISABLED; } + if (gl_manager_egl) { + return gl_manager_egl->is_using_vsync() ? DisplayServer::VSYNC_ENABLED : DisplayServer::VSYNC_DISABLED; + } #endif return DisplayServer::VSYNC_ENABLED; } @@ -5050,6 +5286,7 @@ Vector<String> DisplayServerX11::get_rendering_drivers_func() { #endif #ifdef GLES3_ENABLED drivers.push_back("opengl3"); + drivers.push_back("opengl3_es"); #endif return drivers; @@ -5092,6 +5329,21 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, V ERR_FAIL_COND_V_MSG(err != OK, INVALID_WINDOW_ID, "Can't acquire visual info from display."); vi_selected = true; } + if (gl_manager_egl) { + XVisualInfo visual_info_template; + int visual_id = gl_manager_egl->display_get_native_visual_id(x11_display); + ERR_FAIL_COND_V_MSG(visual_id < 0, INVALID_WINDOW_ID, "Unable to get a visual id."); + + visual_info_template.visualid = (VisualID)visual_id; + + int number_of_visuals = 0; + XVisualInfo *vi_list = XGetVisualInfo(x11_display, VisualIDMask, &visual_info_template, &number_of_visuals); + ERR_FAIL_COND_V(number_of_visuals <= 0, INVALID_WINDOW_ID); + + visualInfo = vi_list[0]; + + XFree(vi_list); + } #endif if (!vi_selected) { @@ -5100,7 +5352,7 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, V XVisualInfo vInfoTemplate = {}; vInfoTemplate.screen = DefaultScreen(x11_display); XVisualInfo *vi_list = XGetVisualInfo(x11_display, visualMask, &vInfoTemplate, &numberOfVisuals); - ERR_FAIL_COND_V(!vi_list, INVALID_WINDOW_ID); + ERR_FAIL_NULL_V(vi_list, INVALID_WINDOW_ID); visualInfo = vi_list[0]; if (OS::get_singleton()->is_layered_allowed()) { @@ -5364,8 +5616,12 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, V if (gl_manager) { Error err = gl_manager->window_create(id, wd.x11_window, x11_display, win_rect.size.width, win_rect.size.height); ERR_FAIL_COND_V_MSG(err != OK, INVALID_WINDOW_ID, "Can't create an OpenGL window"); - window_set_vsync_mode(p_vsync_mode, id); } + if (gl_manager_egl) { + Error err = gl_manager_egl->window_create(id, x11_display, &wd.x11_window, win_rect.size.width, win_rect.size.height); + ERR_FAIL_COND_V_MSG(err != OK, INVALID_WINDOW_ID, "Failed to create an OpenGLES window."); + } + window_set_vsync_mode(p_vsync_mode, id); #endif //set_class_hint(x11_display, wd.x11_window); @@ -5766,7 +6022,7 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode #endif // Initialize context and rendering device. #if defined(GLES3_ENABLED) - if (rendering_driver == "opengl3") { + if (rendering_driver == "opengl3" || rendering_driver == "opengl3_es") { if (getenv("DRI_PRIME") == nullptr) { int use_prime = -1; @@ -5807,28 +6063,38 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode setenv("DRI_PRIME", "1", 1); } } - - GLManager_X11::ContextType opengl_api_type = GLManager_X11::GLES_3_0_COMPATIBLE; - - gl_manager = memnew(GLManager_X11(p_resolution, opengl_api_type)); - - if (gl_manager->initialize(x11_display) != OK) { + } + if (rendering_driver == "opengl3") { + gl_manager = memnew(GLManager_X11(p_resolution, GLManager_X11::GLES_3_0_COMPATIBLE)); + if (gl_manager->initialize(x11_display) != OK || gl_manager->open_display(x11_display) != OK) { memdelete(gl_manager); gl_manager = nullptr; - r_error = ERR_UNAVAILABLE; - return; + bool fallback = GLOBAL_GET("rendering/gl_compatibility/fallback_to_gles"); + if (fallback) { + WARN_PRINT("Your video card drivers seem not to support the required OpenGL version, switching to OpenGLES."); + rendering_driver = "opengl3_es"; + } else { + r_error = ERR_UNAVAILABLE; + ERR_FAIL_MSG("Could not initialize OpenGL."); + } + } else { + driver_found = true; + RasterizerGLES3::make_current(true); } - driver_found = true; + } - if (true) { - RasterizerGLES3::make_current(); - } else { - memdelete(gl_manager); - gl_manager = nullptr; + if (rendering_driver == "opengl3_es") { + gl_manager_egl = memnew(GLManagerEGL_X11); + if (gl_manager_egl->initialize() != OK) { + memdelete(gl_manager_egl); + gl_manager_egl = nullptr; r_error = ERR_UNAVAILABLE; - return; + ERR_FAIL_MSG("Could not initialize OpenGLES."); } + driver_found = true; + RasterizerGLES3::make_current(false); } + #endif if (!driver_found) { r_error = ERR_UNAVAILABLE; @@ -6044,6 +6310,9 @@ DisplayServerX11::~DisplayServerX11() { if (gl_manager) { gl_manager->window_destroy(E.key); } + if (gl_manager_egl) { + gl_manager_egl->window_destroy(E.key); + } #endif WindowData &wd = E.value; @@ -6094,6 +6363,10 @@ DisplayServerX11::~DisplayServerX11() { memdelete(gl_manager); gl_manager = nullptr; } + if (gl_manager_egl) { + memdelete(gl_manager_egl); + gl_manager_egl = nullptr; + } #endif if (xrandr_handle) { diff --git a/platform/linuxbsd/x11/display_server_x11.h b/platform/linuxbsd/x11/display_server_x11.h index 71beddce76..a8d134a6c7 100644 --- a/platform/linuxbsd/x11/display_server_x11.h +++ b/platform/linuxbsd/x11/display_server_x11.h @@ -54,6 +54,7 @@ #if defined(GLES3_ENABLED) #include "x11/gl_manager_x11.h" +#include "x11/gl_manager_x11_egl.h" #endif #if defined(VULKAN_ENABLED) @@ -138,6 +139,7 @@ class DisplayServerX11 : public DisplayServer { #if defined(GLES3_ENABLED) GLManager_X11 *gl_manager = nullptr; + GLManagerEGL_X11 *gl_manager_egl = nullptr; #endif #if defined(VULKAN_ENABLED) VulkanContextX11 *context_vulkan = nullptr; @@ -302,6 +304,7 @@ class DisplayServerX11 : public DisplayServer { String _clipboard_get_impl(Atom p_source, Window x11_window, Atom target) const; String _clipboard_get(Atom p_source, Window x11_window) const; + Atom _clipboard_get_image_target(Atom p_source, Window x11_window) const; void _clipboard_transfer_ownership(Atom p_source, Window x11_window) const; bool do_mouse_warp = false; @@ -406,6 +409,8 @@ public: virtual void clipboard_set(const String &p_text) override; virtual String clipboard_get() const override; + virtual Ref<Image> clipboard_get_image() const override; + virtual bool clipboard_has_image() const override; virtual void clipboard_set_primary(const String &p_text) override; virtual String clipboard_get_primary() const override; diff --git a/platform/linuxbsd/x11/gl_manager_x11.cpp b/platform/linuxbsd/x11/gl_manager_x11.cpp index f24bac5e19..602dd784e0 100644 --- a/platform/linuxbsd/x11/gl_manager_x11.cpp +++ b/platform/linuxbsd/x11/gl_manager_x11.cpp @@ -103,7 +103,7 @@ Error GLManager_X11::_create_context(GLDisplay &gl_display) { GLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB = (GLXCREATECONTEXTATTRIBSARBPROC)glXGetProcAddress((const GLubyte *)"glXCreateContextAttribsARB"); - ERR_FAIL_COND_V(!glXCreateContextAttribsARB, ERR_UNCONFIGURED); + ERR_FAIL_NULL_V(glXCreateContextAttribsARB, ERR_UNCONFIGURED); static int visual_attribs[] = { GLX_RENDER_TYPE, GLX_RGBA_BIT, @@ -134,7 +134,7 @@ Error GLManager_X11::_create_context(GLDisplay &gl_display) { if (OS::get_singleton()->is_layered_allowed()) { GLXFBConfig *fbc = glXChooseFBConfig(x11_display, DefaultScreen(x11_display), visual_attribs_layered, &fbcount); - ERR_FAIL_COND_V(!fbc, ERR_UNCONFIGURED); + ERR_FAIL_NULL_V(fbc, ERR_UNCONFIGURED); for (int i = 0; i < fbcount; i++) { vi = (XVisualInfo *)glXGetVisualFromFBConfig(x11_display, fbc[i]); @@ -156,10 +156,10 @@ Error GLManager_X11::_create_context(GLDisplay &gl_display) { } XFree(fbc); - ERR_FAIL_COND_V(!fbconfig, ERR_UNCONFIGURED); + ERR_FAIL_NULL_V(fbconfig, ERR_UNCONFIGURED); } else { GLXFBConfig *fbc = glXChooseFBConfig(x11_display, DefaultScreen(x11_display), visual_attribs, &fbcount); - ERR_FAIL_COND_V(!fbc, ERR_UNCONFIGURED); + ERR_FAIL_NULL_V(fbc, ERR_UNCONFIGURED); vi = glXGetVisualFromFBConfig(x11_display, fbc[0]); @@ -208,6 +208,15 @@ XVisualInfo GLManager_X11::get_vi(Display *p_display, Error &r_error) { return _displays[display_id].x_vi; } +Error GLManager_X11::open_display(Display *p_display) { + int gldisplay_id = _find_or_create_display(p_display); + if (gldisplay_id < 0) { + return ERR_CANT_CREATE; + } else { + return OK; + } +} + Error GLManager_X11::window_create(DisplayServer::WindowID p_window_id, ::Window p_window, Display *p_display, int p_width, int p_height) { // make sure vector is big enough... // we can mirror the external vector, it is simpler @@ -347,12 +356,6 @@ Error GLManager_X11::initialize(Display *p_display) { } void GLManager_X11::set_use_vsync(bool p_use) { - // force vsync in the editor for now, as a safety measure - bool is_editor = Engine::get_singleton()->is_editor_hint(); - if (is_editor) { - p_use = true; - } - // we need an active window to get a display to set the vsync if (!_current_window) { return; @@ -368,6 +371,7 @@ void GLManager_X11::set_use_vsync(bool p_use) { GLXDrawable drawable = glXGetCurrentDrawable(); glXSwapIntervalEXT(disp.x11_display, drawable, val); } else { + WARN_PRINT("Could not set V-Sync mode. V-Sync is not supported."); return; } use_vsync = p_use; diff --git a/platform/linuxbsd/x11/gl_manager_x11.h b/platform/linuxbsd/x11/gl_manager_x11.h index d3a25506a8..235c7d22f9 100644 --- a/platform/linuxbsd/x11/gl_manager_x11.h +++ b/platform/linuxbsd/x11/gl_manager_x11.h @@ -129,6 +129,7 @@ public: void *get_glx_context(DisplayServer::WindowID p_window_id); + Error open_display(Display *p_display); GLManager_X11(const Vector2i &p_size, ContextType p_context_type); ~GLManager_X11(); }; diff --git a/platform/linuxbsd/x11/gl_manager_x11_egl.cpp b/platform/linuxbsd/x11/gl_manager_x11_egl.cpp new file mode 100644 index 0000000000..544684ebf1 --- /dev/null +++ b/platform/linuxbsd/x11/gl_manager_x11_egl.cpp @@ -0,0 +1,63 @@ +/**************************************************************************/ +/* gl_manager_x11_egl.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#include "gl_manager_x11_egl.h" + +#if defined(X11_ENABLED) && defined(GLES3_ENABLED) + +#include <stdio.h> +#include <stdlib.h> + +const char *GLManagerEGL_X11::_get_platform_extension_name() const { + return "EGL_KHR_platform_x11"; +} + +EGLenum GLManagerEGL_X11::_get_platform_extension_enum() const { + return EGL_PLATFORM_X11_KHR; +} + +Vector<EGLAttrib> GLManagerEGL_X11::_get_platform_display_attributes() const { + return Vector<EGLAttrib>(); +} + +EGLenum GLManagerEGL_X11::_get_platform_api_enum() const { + return EGL_OPENGL_ES_API; +} + +Vector<EGLint> GLManagerEGL_X11::_get_platform_context_attribs() const { + Vector<EGLint> ret; + ret.push_back(EGL_CONTEXT_CLIENT_VERSION); + ret.push_back(3); + ret.push_back(EGL_NONE); + + return ret; +} + +#endif // WINDOWS_ENABLED && GLES3_ENABLED diff --git a/platform/linuxbsd/x11/gl_manager_x11_egl.h b/platform/linuxbsd/x11/gl_manager_x11_egl.h new file mode 100644 index 0000000000..b9c96619c4 --- /dev/null +++ b/platform/linuxbsd/x11/gl_manager_x11_egl.h @@ -0,0 +1,61 @@ +/**************************************************************************/ +/* gl_manager_x11_egl.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#ifndef GL_MANAGER_X11_EGL_H +#define GL_MANAGER_X11_EGL_H + +#if defined(X11_ENABLED) && defined(GLES3_ENABLED) + +#include "core/error/error_list.h" +#include "core/os/os.h" +#include "core/templates/local_vector.h" +#include "drivers/egl/egl_manager.h" +#include "servers/display_server.h" + +#include <X11/Xlib.h> + +class GLManagerEGL_X11 : public EGLManager { +private: + virtual const char *_get_platform_extension_name() const override; + virtual EGLenum _get_platform_extension_enum() const override; + virtual EGLenum _get_platform_api_enum() const override; + virtual Vector<EGLAttrib> _get_platform_display_attributes() const override; + virtual Vector<EGLint> _get_platform_context_attribs() const override; + +public: + void window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height) {} + + GLManagerEGL_X11(){}; + ~GLManagerEGL_X11(){}; +}; + +#endif // X11_ENABLED && GLES3_ENABLED + +#endif // GL_MANAGER_X11_EGL_H |