mirror of
https://github.com/godotengine/godot.git
synced 2025-10-19 07:53:26 +00:00
[Windows] Offload RenderingDevice
creation test to subprocess.
This commit is contained in:
parent
39c201ca58
commit
ab717497ef
11 changed files with 276 additions and 3 deletions
|
@ -109,6 +109,7 @@ protected:
|
|||
|
||||
HasServerFeatureCallback has_server_feature_callback = nullptr;
|
||||
bool _separate_thread_render = false;
|
||||
bool _silent_crash_handler = false;
|
||||
|
||||
// Functions used by Main to initialize/deinitialize the OS.
|
||||
void add_logger(Logger *p_logger);
|
||||
|
@ -262,6 +263,9 @@ public:
|
|||
void set_stdout_enabled(bool p_enabled);
|
||||
void set_stderr_enabled(bool p_enabled);
|
||||
|
||||
virtual void set_crash_handler_silent() { _silent_crash_handler = true; }
|
||||
virtual bool is_crash_handler_silent() { return _silent_crash_handler; }
|
||||
|
||||
virtual void disable_crash_handler() {}
|
||||
virtual bool is_disable_crash_handler() const { return false; }
|
||||
virtual void initialize_debugging() {}
|
||||
|
@ -358,6 +362,10 @@ 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; }
|
||||
|
||||
OS();
|
||||
virtual ~OS();
|
||||
};
|
||||
|
|
|
@ -973,7 +973,7 @@ ProjectDialog::ProjectDialog() {
|
|||
default_renderer_type = EditorSettings::get_singleton()->get_setting("project_manager/default_renderer");
|
||||
}
|
||||
|
||||
rendering_device_supported = DisplayServer::can_create_rendering_device();
|
||||
rendering_device_supported = DisplayServer::is_rendering_device_supported();
|
||||
|
||||
if (!rendering_device_supported) {
|
||||
default_renderer_type = "gl_compatibility";
|
||||
|
|
|
@ -979,6 +979,10 @@ 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)
|
||||
bool test_rd_creation = false;
|
||||
bool test_rd_support = false;
|
||||
#endif
|
||||
bool skip_breakpoints = false;
|
||||
String main_pack;
|
||||
bool quiet_stdout = false;
|
||||
|
@ -1666,6 +1670,12 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
|
|||
debug_canvas_item_redraw = true;
|
||||
} else if (arg == "--debug-stringnames") {
|
||||
StringName::set_debug_stringnames(true);
|
||||
#endif
|
||||
#if defined(TOOLS_ENABLED) && defined(WINDOWS_ENABLED)
|
||||
} else if (arg == "--test-rd-support") {
|
||||
test_rd_support = true;
|
||||
} else if (arg == "--test-rd-creation") {
|
||||
test_rd_creation = true;
|
||||
#endif
|
||||
} else if (arg == "--remote-debug") {
|
||||
if (N) {
|
||||
|
@ -1870,6 +1880,30 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
|
|||
#endif
|
||||
}
|
||||
|
||||
#if defined(TOOLS_ENABLED) && defined(WINDOWS_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()) {
|
||||
exit_err = ERR_HELP;
|
||||
} else {
|
||||
exit_err = ERR_UNAVAILABLE;
|
||||
}
|
||||
goto error;
|
||||
} else if (test_rd_creation) {
|
||||
// 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()) {
|
||||
exit_err = ERR_HELP;
|
||||
} else {
|
||||
exit_err = ERR_UNAVAILABLE;
|
||||
}
|
||||
goto error;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
if (editor) {
|
||||
Engine::get_singleton()->set_editor_hint(true);
|
||||
|
|
|
@ -57,6 +57,10 @@ static void handle_crash(int sig) {
|
|||
abort();
|
||||
}
|
||||
|
||||
if (OS::get_singleton()->is_crash_handler_silent()) {
|
||||
std::_Exit(0);
|
||||
}
|
||||
|
||||
void *bt_buffer[256];
|
||||
size_t size = backtrace(bt_buffer, 256);
|
||||
String _execpath = OS::get_singleton()->get_executable_path();
|
||||
|
|
|
@ -81,6 +81,10 @@ static void handle_crash(int sig) {
|
|||
abort();
|
||||
}
|
||||
|
||||
if (OS::get_singleton()->is_crash_handler_silent()) {
|
||||
std::_Exit(0);
|
||||
}
|
||||
|
||||
void *bt_buffer[256];
|
||||
size_t size = backtrace(bt_buffer, 256);
|
||||
String _execpath = OS::get_singleton()->get_executable_path();
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
// Backtrace code based on: https://stackoverflow.com/questions/6205981/windows-c-stack-trace-from-a-running-app
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
@ -127,6 +128,10 @@ DWORD CrashHandlerException(EXCEPTION_POINTERS *ep) {
|
|||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
if (OS::get_singleton()->is_crash_handler_silent()) {
|
||||
std::_Exit(0);
|
||||
}
|
||||
|
||||
String msg;
|
||||
const ProjectSettings *proj_settings = ProjectSettings::get_singleton();
|
||||
if (proj_settings) {
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include <cxxabi.h>
|
||||
#include <signal.h>
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
@ -133,6 +134,10 @@ extern void CrashHandlerException(int signal) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (OS::get_singleton()->is_crash_handler_silent()) {
|
||||
std::_Exit(0);
|
||||
}
|
||||
|
||||
String msg;
|
||||
const ProjectSettings *proj_settings = ProjectSettings::get_singleton();
|
||||
if (proj_settings) {
|
||||
|
|
|
@ -62,6 +62,24 @@
|
|||
#include <wbemcli.h>
|
||||
#include <wincrypt.h>
|
||||
|
||||
#if defined(RD_ENABLED)
|
||||
#include "servers/rendering/rendering_device.h"
|
||||
#endif
|
||||
|
||||
#if defined(GLES3_ENABLED)
|
||||
#include "gl_manager_windows_native.h"
|
||||
#endif
|
||||
|
||||
#if defined(VULKAN_ENABLED)
|
||||
#include "rendering_context_driver_vulkan_windows.h"
|
||||
#endif
|
||||
#if defined(D3D12_ENABLED)
|
||||
#include "drivers/d3d12/rendering_context_driver_d3d12.h"
|
||||
#endif
|
||||
#if defined(GLES3_ENABLED)
|
||||
#include "drivers/gles3/rasterizer_gles3.h"
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
#pragma pack(push, before_imagehlp, 8)
|
||||
#include <imagehlp.h>
|
||||
|
@ -2346,6 +2364,99 @@ void OS_Windows::add_frame_delay(bool p_can_draw) {
|
|||
}
|
||||
}
|
||||
|
||||
bool OS_Windows::_test_create_rendering_device() const {
|
||||
// Tests Rendering Device creation.
|
||||
|
||||
bool ok = false;
|
||||
#if defined(RD_ENABLED)
|
||||
Error err;
|
||||
RenderingContextDriver *rcd = nullptr;
|
||||
|
||||
#if defined(VULKAN_ENABLED)
|
||||
rcd = memnew(RenderingContextDriverVulkan);
|
||||
#endif
|
||||
#ifdef D3D12_ENABLED
|
||||
if (rcd == nullptr) {
|
||||
rcd = memnew(RenderingContextDriverD3D12);
|
||||
}
|
||||
#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_Windows::_test_create_rendering_device_and_gl() const {
|
||||
// Tests OpenGL context and Rendering Device simultaneous creation. This function is expected to crash on some NVIDIA drivers.
|
||||
|
||||
WNDCLASSEXW wc_probe;
|
||||
memset(&wc_probe, 0, sizeof(WNDCLASSEXW));
|
||||
wc_probe.cbSize = sizeof(WNDCLASSEXW);
|
||||
wc_probe.style = CS_OWNDC | CS_DBLCLKS;
|
||||
wc_probe.lpfnWndProc = (WNDPROC)::DefWindowProcW;
|
||||
wc_probe.cbClsExtra = 0;
|
||||
wc_probe.cbWndExtra = 0;
|
||||
wc_probe.hInstance = GetModuleHandle(nullptr);
|
||||
wc_probe.hIcon = LoadIcon(nullptr, IDI_WINLOGO);
|
||||
wc_probe.hCursor = nullptr;
|
||||
wc_probe.hbrBackground = nullptr;
|
||||
wc_probe.lpszMenuName = nullptr;
|
||||
wc_probe.lpszClassName = L"Engine probe window";
|
||||
|
||||
if (!RegisterClassExW(&wc_probe)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HWND hWnd = CreateWindowExW(WS_EX_WINDOWEDGE, L"Engine probe window", L"", WS_OVERLAPPEDWINDOW, 0, 0, 800, 600, nullptr, nullptr, GetModuleHandle(nullptr), nullptr);
|
||||
if (!hWnd) {
|
||||
UnregisterClassW(L"Engine probe window", GetModuleHandle(nullptr));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ok = true;
|
||||
#ifdef GLES3_ENABLED
|
||||
GLManagerNative_Windows *test_gl_manager_native = memnew(GLManagerNative_Windows);
|
||||
if (test_gl_manager_native->window_create(DisplayServer::MAIN_WINDOW_ID, hWnd, GetModuleHandle(nullptr), 800, 600) == OK) {
|
||||
RasterizerGLES3::make_current(true);
|
||||
} else {
|
||||
ok = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
MSG msg = {};
|
||||
while (PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE)) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessageW(&msg);
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
ok = _test_create_rendering_device();
|
||||
}
|
||||
|
||||
#ifdef GLES3_ENABLED
|
||||
if (test_gl_manager_native) {
|
||||
memdelete(test_gl_manager_native);
|
||||
}
|
||||
#endif
|
||||
|
||||
DestroyWindow(hWnd);
|
||||
UnregisterClassW(L"Engine probe window", GetModuleHandle(nullptr));
|
||||
return ok;
|
||||
}
|
||||
|
||||
OS_Windows::OS_Windows(HINSTANCE _hInstance) {
|
||||
hInstance = _hInstance;
|
||||
|
||||
|
|
|
@ -252,6 +252,9 @@ 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;
|
||||
|
||||
HINSTANCE get_hinstance() { return hInstance; }
|
||||
OS_Windows(HINSTANCE _hInstance);
|
||||
~OS_Windows();
|
||||
|
|
|
@ -1316,8 +1316,87 @@ void DisplayServer::_input_set_custom_mouse_cursor_func(const Ref<Resource> &p_i
|
|||
singleton->cursor_set_custom_image(p_image, (CursorShape)p_shape, p_hotspot);
|
||||
}
|
||||
|
||||
bool DisplayServer::is_rendering_device_supported() {
|
||||
#if defined(RD_ENABLED)
|
||||
RenderingDevice *device = RenderingDevice::get_singleton();
|
||||
if (device) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (supported_rendering_device == RenderingDeviceCreationStatus::SUCCESS) {
|
||||
return true;
|
||||
} else if (supported_rendering_device == RenderingDeviceCreationStatus::FAILURE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Error err;
|
||||
|
||||
#ifdef WINDOWS_ENABLED
|
||||
// On some NVIDIA drivers combining OpenGL and RenderingDevice can result in crash, offload the check to the subprocess.
|
||||
List<String> arguments;
|
||||
arguments.push_back("--test-rd-support");
|
||||
|
||||
String pipe;
|
||||
int exitcode = 0;
|
||||
err = OS::get_singleton()->execute(OS::get_singleton()->get_executable_path(), arguments, &pipe, &exitcode);
|
||||
if (err == OK && exitcode == 0) {
|
||||
supported_rendering_device = RenderingDeviceCreationStatus::SUCCESS;
|
||||
return true;
|
||||
} else {
|
||||
supported_rendering_device = RenderingDeviceCreationStatus::FAILURE;
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
RenderingContextDriver *rcd = nullptr;
|
||||
|
||||
#if defined(VULKAN_ENABLED)
|
||||
rcd = memnew(RenderingContextDriverVulkan);
|
||||
#endif
|
||||
#ifdef D3D12_ENABLED
|
||||
if (rcd == nullptr) {
|
||||
rcd = memnew(RenderingContextDriverD3D12);
|
||||
}
|
||||
#endif
|
||||
#ifdef METAL_ENABLED
|
||||
if (rcd == nullptr) {
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wunguarded-availability"
|
||||
// Eliminate "RenderingContextDriverMetal is only available on iOS 14.0 or newer".
|
||||
rcd = memnew(RenderingContextDriverMetal);
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
#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) {
|
||||
// Creating a RenderingDevice is quite slow.
|
||||
// Cache the result for future usage, so that it's much faster on subsequent calls.
|
||||
supported_rendering_device = RenderingDeviceCreationStatus::SUCCESS;
|
||||
memdelete(rcd);
|
||||
rcd = nullptr;
|
||||
return true;
|
||||
} else {
|
||||
supported_rendering_device = RenderingDeviceCreationStatus::FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
memdelete(rcd);
|
||||
rcd = nullptr;
|
||||
}
|
||||
|
||||
#endif // RD_ENABLED
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DisplayServer::can_create_rendering_device() {
|
||||
if (get_singleton()->get_name() == "headless") {
|
||||
if (get_singleton() && get_singleton()->get_name() == "headless") {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1334,6 +1413,24 @@ bool DisplayServer::can_create_rendering_device() {
|
|||
}
|
||||
|
||||
Error err;
|
||||
|
||||
#ifdef WINDOWS_ENABLED
|
||||
// On some NVIDIA drivers combining OpenGL and RenderingDevice can result in crash, offload the check to the subprocess.
|
||||
List<String> arguments;
|
||||
arguments.push_back("--test-rd-creation");
|
||||
|
||||
String pipe;
|
||||
int exitcode = 0;
|
||||
err = OS::get_singleton()->execute(OS::get_singleton()->get_executable_path(), arguments, &pipe, &exitcode);
|
||||
if (err == OK && exitcode == 0) {
|
||||
created_rendering_device = RenderingDeviceCreationStatus::SUCCESS;
|
||||
return true;
|
||||
} else {
|
||||
created_rendering_device = RenderingDeviceCreationStatus::FAILURE;
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
RenderingContextDriver *rcd = nullptr;
|
||||
|
||||
#if defined(VULKAN_ENABLED)
|
||||
|
|
|
@ -652,9 +652,11 @@ public:
|
|||
// Used to cache the result of `can_create_rendering_device()` when RenderingDevice isn't currently being used.
|
||||
// This is done as creating a RenderingDevice is quite slow.
|
||||
static inline RenderingDeviceCreationStatus created_rendering_device = RenderingDeviceCreationStatus::UNKNOWN;
|
||||
|
||||
static bool can_create_rendering_device();
|
||||
|
||||
static inline RenderingDeviceCreationStatus supported_rendering_device = RenderingDeviceCreationStatus::UNKNOWN;
|
||||
static bool is_rendering_device_supported();
|
||||
|
||||
DisplayServer();
|
||||
~DisplayServer();
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue