diff --git a/core/os/os.h b/core/os/os.h index e0ec320e32b..c8ac5c8eac7 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -362,9 +362,9 @@ public: // This is invoked by the GDExtensionManager after loading GDExtensions specified by the project. virtual void load_platform_gdextensions() const {} - // Windows only. Tests OpenGL context and Rendering Device simultaneous creation. This function is expected to crash on some NVIDIA drivers. - virtual bool _test_create_rendering_device_and_gl() const { return true; } - virtual bool _test_create_rendering_device() const { return true; } + // Tests OpenGL context and Rendering Device simultaneous creation. This function is expected to crash on some NVIDIA drivers. + virtual bool _test_create_rendering_device_and_gl(const String &p_display_driver) const { return true; } + virtual bool _test_create_rendering_device(const String &p_display_driver) const { return true; } OS(); virtual ~OS(); diff --git a/main/main.cpp b/main/main.cpp index e65f894c549..9a1ab877124 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -979,7 +979,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph String project_path = "."; bool upwards = false; String debug_uri = ""; -#if defined(TOOLS_ENABLED) && defined(WINDOWS_ENABLED) +#if defined(TOOLS_ENABLED) && (defined(WINDOWS_ENABLED) || defined(LINUXBSD_ENABLED)) bool test_rd_creation = false; bool test_rd_support = false; #endif @@ -1671,7 +1671,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph } else if (arg == "--debug-stringnames") { StringName::set_debug_stringnames(true); #endif -#if defined(TOOLS_ENABLED) && defined(WINDOWS_ENABLED) +#if defined(TOOLS_ENABLED) && (defined(WINDOWS_ENABLED) || defined(LINUXBSD_ENABLED)) } else if (arg == "--test-rd-support") { test_rd_support = true; } else if (arg == "--test-rd-creation") { @@ -1880,12 +1880,12 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph #endif } -#if defined(TOOLS_ENABLED) && defined(WINDOWS_ENABLED) +#if defined(TOOLS_ENABLED) && (defined(WINDOWS_ENABLED) || defined(LINUXBSD_ENABLED)) if (test_rd_support) { // Test Rendering Device creation and exit. OS::get_singleton()->set_crash_handler_silent(); - if (OS::get_singleton()->_test_create_rendering_device()) { + if (OS::get_singleton()->_test_create_rendering_device(display_driver)) { exit_err = ERR_HELP; } else { exit_err = ERR_UNAVAILABLE; @@ -1895,7 +1895,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph // Test OpenGL context and Rendering Device simultaneous creation and exit. OS::get_singleton()->set_crash_handler_silent(); - if (OS::get_singleton()->_test_create_rendering_device_and_gl()) { + if (OS::get_singleton()->_test_create_rendering_device_and_gl(display_driver)) { exit_err = ERR_HELP; } else { exit_err = ERR_UNAVAILABLE; diff --git a/platform/linuxbsd/os_linuxbsd.cpp b/platform/linuxbsd/os_linuxbsd.cpp index 9fba97d552a..466841d747f 100644 --- a/platform/linuxbsd/os_linuxbsd.cpp +++ b/platform/linuxbsd/os_linuxbsd.cpp @@ -37,10 +37,12 @@ #include "servers/rendering_server.h" #ifdef X11_ENABLED +#include "x11/detect_prime_x11.h" #include "x11/display_server_x11.h" #endif #ifdef WAYLAND_ENABLED +#include "wayland/detect_prime_egl.h" #include "wayland/display_server_wayland.h" #endif @@ -49,6 +51,22 @@ #include "modules/regex/regex.h" #endif +#if defined(RD_ENABLED) +#include "servers/rendering/rendering_device.h" +#endif + +#if defined(VULKAN_ENABLED) +#ifdef X11_ENABLED +#include "x11/rendering_context_driver_vulkan_x11.h" +#endif +#ifdef WAYLAND_ENABLED +#include "wayland/rendering_context_driver_vulkan_wayland.h" +#endif +#endif +#if defined(GLES3_ENABLED) +#include "drivers/gles3/rasterizer_gles3.h" +#endif + #include #include #include @@ -1180,6 +1198,73 @@ String OS_LinuxBSD::get_system_ca_certificates() { return f->get_as_text(); } +bool OS_LinuxBSD::_test_create_rendering_device(const String &p_display_driver) const { + // Tests Rendering Device creation. + + bool ok = false; +#if defined(RD_ENABLED) + Error err; + RenderingContextDriver *rcd = nullptr; + +#if defined(VULKAN_ENABLED) +#ifdef X11_ENABLED + if (p_display_driver == "x11" || p_display_driver.is_empty()) { + rcd = memnew(RenderingContextDriverVulkanX11); + } +#endif +#ifdef WAYLAND_ENABLED + if (p_display_driver == "wayland") { + rcd = memnew(RenderingContextDriverVulkanWayland); + } +#endif +#endif + if (rcd != nullptr) { + err = rcd->initialize(); + if (err == OK) { + RenderingDevice *rd = memnew(RenderingDevice); + err = rd->initialize(rcd); + memdelete(rd); + rd = nullptr; + if (err == OK) { + ok = true; + } + } + memdelete(rcd); + rcd = nullptr; + } +#endif + return ok; +} + +bool OS_LinuxBSD::_test_create_rendering_device_and_gl(const String &p_display_driver) const { + // Tests OpenGL context and Rendering Device simultaneous creation. This function is expected to crash on some drivers. + +#ifdef GLES3_ENABLED +#ifdef X11_ENABLED + if (p_display_driver == "x11" || p_display_driver.is_empty()) { +#ifdef SOWRAP_ENABLED + if (initialize_xlib(0) != 0) { + return false; + } +#endif + DetectPrimeX11::create_context(); + } +#endif +#ifdef WAYLAND_ENABLED + if (p_display_driver == "wayland") { +#ifdef SOWRAP_ENABLED + if (initialize_wayland_egl(0) != 0) { + return false; + } +#endif + DetectPrimeEGL::create_context(EGL_PLATFORM_WAYLAND_KHR); + } +#endif + RasterizerGLES3::make_current(true); +#endif + return _test_create_rendering_device(p_display_driver); +} + OS_LinuxBSD::OS_LinuxBSD() { main_loop = nullptr; diff --git a/platform/linuxbsd/os_linuxbsd.h b/platform/linuxbsd/os_linuxbsd.h index 9084061eb96..92e57304f3c 100644 --- a/platform/linuxbsd/os_linuxbsd.h +++ b/platform/linuxbsd/os_linuxbsd.h @@ -138,6 +138,9 @@ public: virtual String get_system_ca_certificates() override; + virtual bool _test_create_rendering_device_and_gl(const String &p_display_driver) const override; + virtual bool _test_create_rendering_device(const String &p_display_driver) const override; + OS_LinuxBSD(); ~OS_LinuxBSD(); }; diff --git a/platform/linuxbsd/wayland/detect_prime_egl.h b/platform/linuxbsd/wayland/detect_prime_egl.h index 3391e020d8b..eff5d8a2918 100644 --- a/platform/linuxbsd/wayland/detect_prime_egl.h +++ b/platform/linuxbsd/wayland/detect_prime_egl.h @@ -77,9 +77,9 @@ private: { nullptr, 0 } }; +public: static void create_context(EGLenum p_platform_enum); -public: static int detect_prime(EGLenum p_platform_enum); }; diff --git a/platform/linuxbsd/x11/detect_prime_x11.cpp b/platform/linuxbsd/x11/detect_prime_x11.cpp index c2cb02b9378..5ec5a53b989 100644 --- a/platform/linuxbsd/x11/detect_prime_x11.cpp +++ b/platform/linuxbsd/x11/detect_prime_x11.cpp @@ -60,25 +60,23 @@ typedef GLXContext (*GLXCREATECONTEXTATTRIBSARBPROC)(Display *, GLXFBConfig, GLX // To prevent shadowing warnings #undef glGetString -struct vendor { - const char *glxvendor = nullptr; - int priority = 0; -}; +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)); -vendor vendormap[] = { - { "Advanced Micro Devices, Inc.", 30 }, - { "AMD", 30 }, - { "NVIDIA Corporation", 30 }, - { "X.Org", 30 }, - { "Intel Open Source Technology Center", 20 }, - { "Intel", 20 }, - { "nouveau", 10 }, - { "Mesa Project", 0 }, - { nullptr, 0 } -}; + quick_exit(1); + return 0; +} // Runs inside a child. Exiting will not quit the engine. -void create_context() { +void DetectPrimeX11::create_context() { + XSetErrorHandler(&silent_error_handler); + Display *x11_display = XOpenDisplay(nullptr); Window x11_window; GLXContext glx_context; @@ -137,20 +135,7 @@ 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() { +int DetectPrimeX11::detect_prime() { pid_t p; int priorities[2] = {}; String vendors[2]; @@ -202,7 +187,6 @@ 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]; @@ -253,7 +237,7 @@ int detect_prime() { } for (int i = 1; i >= 0; --i) { - vendor *v = vendormap; + const Vendor *v = vendor_map; while (v->glxvendor) { if (v->glxvendor == vendors[i]) { priorities[i] = v->priority; diff --git a/platform/linuxbsd/x11/detect_prime_x11.h b/platform/linuxbsd/x11/detect_prime_x11.h index 62fe4260267..c8da79bf922 100644 --- a/platform/linuxbsd/x11/detect_prime_x11.h +++ b/platform/linuxbsd/x11/detect_prime_x11.h @@ -33,7 +33,30 @@ #if defined(X11_ENABLED) && defined(GLES3_ENABLED) -int detect_prime(); +class DetectPrimeX11 { +private: + struct Vendor { + const char *glxvendor = nullptr; + int priority = 0; + }; + + static constexpr Vendor vendor_map[] = { + { "Advanced Micro Devices, Inc.", 30 }, + { "AMD", 30 }, + { "NVIDIA Corporation", 30 }, + { "X.Org", 30 }, + { "Intel Open Source Technology Center", 20 }, + { "Intel", 20 }, + { "nouveau", 10 }, + { "Mesa Project", 0 }, + { nullptr, 0 } + }; + +public: + static void create_context(); + + static int detect_prime(); +}; #endif // X11_ENABLED && GLES3_ENABLED diff --git a/platform/linuxbsd/x11/display_server_x11.cpp b/platform/linuxbsd/x11/display_server_x11.cpp index 26c94bf25cf..ea35bf812c4 100644 --- a/platform/linuxbsd/x11/display_server_x11.cpp +++ b/platform/linuxbsd/x11/display_server_x11.cpp @@ -6844,7 +6844,7 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode if (use_prime == -1) { print_verbose("Detecting GPUs, set DRI_PRIME in the environment to override GPU detection logic."); - use_prime = detect_prime(); + use_prime = DetectPrimeX11::detect_prime(); } if (use_prime) { diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index 7ef3de2dd79..49ff7b2d477 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -2359,7 +2359,7 @@ void OS_Windows::add_frame_delay(bool p_can_draw) { } } -bool OS_Windows::_test_create_rendering_device() const { +bool OS_Windows::_test_create_rendering_device(const String &p_display_driver) const { // Tests Rendering Device creation. bool ok = false; @@ -2394,7 +2394,7 @@ bool OS_Windows::_test_create_rendering_device() const { return ok; } -bool OS_Windows::_test_create_rendering_device_and_gl() const { +bool OS_Windows::_test_create_rendering_device_and_gl(const String &p_display_driver) const { // Tests OpenGL context and Rendering Device simultaneous creation. This function is expected to crash on some NVIDIA drivers. WNDCLASSEXW wc_probe; @@ -2438,7 +2438,7 @@ bool OS_Windows::_test_create_rendering_device_and_gl() const { } if (ok) { - ok = _test_create_rendering_device(); + ok = _test_create_rendering_device(p_display_driver); } #ifdef GLES3_ENABLED diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h index c46d86a650e..d9b8233e511 100644 --- a/platform/windows/os_windows.h +++ b/platform/windows/os_windows.h @@ -252,8 +252,8 @@ public: void set_main_window(HWND p_main_window) { main_window = p_main_window; } - virtual bool _test_create_rendering_device_and_gl() const override; - virtual bool _test_create_rendering_device() const override; + virtual bool _test_create_rendering_device_and_gl(const String &p_display_driver) const override; + virtual bool _test_create_rendering_device(const String &p_display_driver) const override; HINSTANCE get_hinstance() { return hInstance; } OS_Windows(HINSTANCE _hInstance); diff --git a/servers/display_server.cpp b/servers/display_server.cpp index c9399d9c65f..87300bd8b6a 100644 --- a/servers/display_server.cpp +++ b/servers/display_server.cpp @@ -1331,10 +1331,14 @@ bool DisplayServer::is_rendering_device_supported() { Error err; -#ifdef WINDOWS_ENABLED - // On some NVIDIA drivers combining OpenGL and RenderingDevice can result in crash, offload the check to the subprocess. +#if defined(WINDOWS_ENABLED) || defined(LINUXBSD_ENABLED) + // On some drivers combining OpenGL and RenderingDevice can result in crash, offload the check to the subprocess. List arguments; arguments.push_back("--test-rd-support"); + if (get_singleton()) { + arguments.push_back("--display-driver"); + arguments.push_back(get_singleton()->get_name().to_lower()); + } String pipe; int exitcode = 0;