From 9cc6e4a1be4c84dfa27fe6e5458107ed51555270 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pa=CC=84vels=20Nadtoc=CC=8Cajevs?= <7645683+bruvzg@users.noreply.github.com> Date: Thu, 27 Feb 2025 09:35:55 +0200 Subject: [PATCH 1/2] Add support for "ordered" list properties. Add support for "ordered" list properties. --- core/core_constants.cpp | 1 + core/object/object.h | 1 + doc/classes/@GlobalScope.xml | 6 +- editor/editor_properties.cpp | 227 ++++++++++++++++++++++++++++++++++- editor/editor_properties.h | 35 ++++++ scene/gui/tree.cpp | 10 ++ scene/gui/tree.h | 3 +- 7 files changed, 280 insertions(+), 3 deletions(-) diff --git a/core/core_constants.cpp b/core/core_constants.cpp index 4b858c55142..06238371eb2 100644 --- a/core/core_constants.cpp +++ b/core/core_constants.cpp @@ -678,6 +678,7 @@ void register_global_constants() { BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_PASSWORD); BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_TOOL_BUTTON); BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_ONESHOT); + BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_ORDERED_LIST); BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_MAX); BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_NONE); diff --git a/core/object/object.h b/core/object/object.h index 16d8e19eaa0..b4563cb1961 100644 --- a/core/object/object.h +++ b/core/object/object.h @@ -90,6 +90,7 @@ enum PropertyHint { PROPERTY_HINT_TOOL_BUTTON, PROPERTY_HINT_ONESHOT, ///< the property will be changed by self after setting, such as AudioStreamPlayer.playing, Particles.emitting. PROPERTY_HINT_NO_NODEPATH, /// < this property will not contain a NodePath, regardless of type (Array, Dictionary, List, etc.). Needed for SceneTreeDock. + PROPERTY_HINT_ORDERED_LIST, PROPERTY_HINT_MAX, }; diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml index 38b1ec3554b..2f3a911fcaf 100644 --- a/doc/classes/@GlobalScope.xml +++ b/doc/classes/@GlobalScope.xml @@ -2954,7 +2954,11 @@ Hints that a property will be changed on its own after setting, such as [member AudioStreamPlayer.playing] or [member GPUParticles3D.emitting]. - + + Hints that a property is ordered list of values. + The hint string is a comma separated list of display name/value pairs separated by [code]:[/code] such as [code]"Hello:hello,Something Else:else"[/code]. + + Represents the size of the [enum PropertyHint] enum. diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp index 52780d7c588..e8095ca6415 100644 --- a/editor/editor_properties.cpp +++ b/editor/editor_properties.cpp @@ -52,6 +52,7 @@ #include "scene/3d/gpu_particles_3d.h" #include "scene/gui/color_picker.h" #include "scene/gui/grid_container.h" +#include "scene/gui/tree.h" #include "scene/main/window.h" #include "scene/resources/font.h" #include "scene/resources/mesh.h" @@ -249,6 +250,225 @@ EditorPropertyMultilineText::EditorPropertyMultilineText(bool p_expression) { } } +///////////////////// ORDERED LIST ///////////////////////// + +void EditorPropertyOrderedList::_set_read_only(bool p_read_only) { + read_only = p_read_only; + _update_tree(); +} + +void EditorPropertyOrderedList::_update_tree() { + tree->clear(); + + TreeItem *root = tree->create_item(nullptr); + // Add missing keys to the value. + for (const KeyValue &E : names) { + if (!values.has(E.key)) { + values.push_back(E.key); + } + } + + // Update tree. + for (int i = 0; i < values.size(); i++) { + if (!names.has(values[i])) { + WARN_PRINT(vformat("Invalid list item %s for property %s.", values[i], get_edited_property())); + continue; + } + TreeItem *it = tree->create_item(root); + it->set_text(0, names[values[i]]); + it->set_metadata(0, values[i]); + if (!read_only) { + it->add_button(0, get_editor_theme_icon(SNAME("ArrowUp")), BUTTON_UP, (i == 0), TTR("Move Up")); + it->add_button(0, get_editor_theme_icon(SNAME("ArrowDown")), BUTTON_DOWN, (i == values.size() - 1), TTR("Move Down")); + } + } + + // Update size. + Ref font = get_theme_font(SceneStringName(font), SNAME("TextEdit")); + int font_size = get_theme_font_size(SceneStringName(font_size), SNAME("TextEdit")); + tree->set_custom_minimum_size(tree->get_background_size() + Size2i(0, MIN(tree->get_internal_min_size().height, 6 * font->get_height(font_size)))); +} + +Variant EditorPropertyOrderedList::get_drag_data_fw(const Point2 &p_point, Control *p_from) { + if (read_only) { + return Variant(); + } + + if (tree->get_button_id_at_position(p_point) != -1) { + return Variant(); + } + + TreeItem *item = tree->get_next_selected(nullptr); + if (!item) { + return Variant(); + } + String value = item->get_metadata(0); + if (!names.has(value)) { + return Variant(); + } + String name = names[value]; + + // Preview. + HBoxContainer *hb = memnew(HBoxContainer); + Label *label_prev = memnew(Label(vformat("%s (%s)", name, value))); + label_prev->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); + hb->add_child(label_prev); + set_drag_preview(hb); + + // Drag data. + Dictionary drag_data; + drag_data["type"] = "list_reorder"; + drag_data["id"] = get_instance_id(); + drag_data["value"] = value; + + tree->set_drop_mode_flags(Tree::DROP_MODE_INBETWEEN); + + return drag_data; +} + +bool EditorPropertyOrderedList::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const { + if (read_only) { + return false; + } + + Dictionary d = p_data; + if (!d.has("type") || !d.has("id") || !d.has("value")) { + return false; + } + + if (d["type"] != "list_reorder" || d["id"] != get_instance_id()) { + return false; + } + + TreeItem *item = tree->get_item_at_position(p_point); + if (!item) { + return false; + } + + int section = tree->get_drop_section_at_position(p_point); + if (section == -100) { + return false; + } + + return true; +} + +void EditorPropertyOrderedList::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) { + if (!can_drop_data_fw(p_point, p_data, p_from)) { + return; + } + Dictionary d = p_data; + String drop_value = d["value"]; + + TreeItem *item = tree->get_item_at_position(p_point); + ERR_FAIL_COND(!item); + String target_value = item->get_metadata(0); + + int section = tree->get_drop_section_at_position(p_point); + ERR_FAIL_COND(section == -100); + + tree->set_drop_mode_flags(Tree::DROP_MODE_DISABLED); + + Vector new_values = values; + new_values.erase(drop_value); + if (section == 1) { + int pos = new_values.find(target_value); + if (pos == -1) { + return; + } + new_values.insert(pos + 1, drop_value); + } else { + int pos = new_values.find(target_value); + if (pos == -1) { + return; + } + new_values.insert(pos, drop_value); + } + values = new_values; + _update_tree(); + emit_changed(get_edited_property(), String(",").join(values)); +} + +void EditorPropertyOrderedList::_tree_button_pressed(TreeItem *p_item, int p_column, int p_id, MouseButton p_button) { + ERR_FAIL_COND(!p_item); + if (p_button != MouseButton::LEFT) { + return; + } + + String drop_value = p_item->get_metadata(0); + Vector new_values = values; + if (p_id == BUTTON_DOWN) { + int pos = new_values.find(drop_value); + if (pos == -1) { + return; + } + new_values.erase(drop_value); + new_values.insert(pos + 1, drop_value); + } else { + int pos = new_values.find(drop_value); + if (pos == -1) { + return; + } + new_values.erase(drop_value); + new_values.insert(pos - 1, drop_value); + } + values = new_values; + _update_tree(); + emit_changed(get_edited_property(), String(",").join(values)); +} + +void EditorPropertyOrderedList::update_property() { + String current_value = get_edited_property_value(); + values = current_value.split(","); + print_line(values); + _update_tree(); +} + +void EditorPropertyOrderedList::setup(const Vector &p_options) { + values.clear(); + names.clear(); + + for (const String &option : p_options) { + Vector text_split = option.split(":"); + if (text_split.size() != 1) { + names[text_split[1]] = text_split[0]; + } else { + names[text_split[0]] = text_split[0]; + } + } + _update_tree(); +} + +void EditorPropertyOrderedList::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: + case NOTIFICATION_THEME_CHANGED: { + tree->add_theme_style_override(SNAME("panel"), get_theme_stylebox(SNAME("normal"), SNAME("Button"))); + tree->add_theme_style_override(SNAME("focus"), get_theme_stylebox(SNAME("focus"), SNAME("Button"))); + _update_tree(); + } break; + } +} + +EditorPropertyOrderedList::EditorPropertyOrderedList() { + HBoxContainer *hb = memnew(HBoxContainer); + add_child(hb); + + default_layout = memnew(HBoxContainer); + default_layout->set_h_size_flags(SIZE_EXPAND_FILL); + hb->add_child(default_layout); + + tree = memnew(Tree); + tree->set_h_size_flags(SIZE_EXPAND_FILL); + tree->set_hide_root(true); + tree->connect("button_clicked", callable_mp(this, &EditorPropertyOrderedList::_tree_button_pressed)); + default_layout->add_child(tree); + + SET_DRAG_FORWARDING_GCD(tree, EditorPropertyOrderedList); + + add_focusable(tree); +} + ///////////////////// TEXT ENUM ///////////////////////// void EditorPropertyTextEnum::_set_read_only(bool p_read_only) { @@ -3615,7 +3835,12 @@ EditorProperty *EditorInspectorDefaultPlugin::get_editor_for_property(Object *p_ } } break; case Variant::STRING: { - if (p_hint == PROPERTY_HINT_ENUM || p_hint == PROPERTY_HINT_ENUM_SUGGESTION) { + if (p_hint == PROPERTY_HINT_ORDERED_LIST) { + EditorPropertyOrderedList *editor = memnew(EditorPropertyOrderedList); + Vector options = p_hint_text.split(",", false); + editor->setup(options); + return editor; + } else if (p_hint == PROPERTY_HINT_ENUM || p_hint == PROPERTY_HINT_ENUM_SUGGESTION) { EditorPropertyTextEnum *editor = memnew(EditorPropertyTextEnum); Vector options = p_hint_text.split(",", false); editor->setup(options, false, (p_hint == PROPERTY_HINT_ENUM_SUGGESTION)); diff --git a/editor/editor_properties.h b/editor/editor_properties.h index 6fe8cc3c3f3..66c5f282dd3 100644 --- a/editor/editor_properties.h +++ b/editor/editor_properties.h @@ -45,6 +45,8 @@ class PropertySelector; class SceneTreeDialog; class TextEdit; class TextureButton; +class Tree; +class TreeItem; class EditorPropertyNil : public EditorProperty { GDCLASS(EditorPropertyNil, EditorProperty); @@ -132,6 +134,39 @@ public: EditorPropertyTextEnum(); }; +class EditorPropertyOrderedList : public EditorProperty { + GDCLASS(EditorPropertyOrderedList, EditorProperty); + + enum EditorPropertyOrderedListButtonID { + BUTTON_UP, + BUTTON_DOWN, + }; + + HBoxContainer *default_layout = nullptr; + + bool read_only = false; + Tree *tree = nullptr; + + HashMap names; + Vector values; + + void _update_tree(); + void _tree_button_pressed(TreeItem *p_item, int p_column, int p_id, MouseButton p_button); + +protected: + virtual void _set_read_only(bool p_read_only) override; + void _notification(int p_what); + + Variant get_drag_data_fw(const Point2 &p_point, Control *p_from); + bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const; + void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from); + +public: + void setup(const Vector &p_options); + virtual void update_property() override; + EditorPropertyOrderedList(); +}; + class EditorPropertyPath : public EditorProperty { GDCLASS(EditorPropertyPath, EditorProperty); Vector extensions; diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index cd6c51de4b2..899fb4bfb71 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -4196,10 +4196,20 @@ void Tree::set_editor_selection(int p_from_line, int p_to_line, int p_from_colum } } +Size2 Tree::get_background_size() const { + const Ref background = theme_cache.panel_style; + + // This is the background stylebox's content rect. + const real_t width = background->get_margin(SIDE_LEFT) + background->get_margin(SIDE_RIGHT); + const real_t height = background->get_margin(SIDE_TOP) + background->get_margin(SIDE_BOTTOM); + return Size2(width, height); +} + Size2 Tree::get_internal_min_size() const { Size2i size; if (root) { size.height += get_item_height(root); + size.height -= theme_cache.v_separation; } for (int i = 0; i < columns.size(); i++) { size.width += get_column_minimum_width(i); diff --git a/scene/gui/tree.h b/scene/gui/tree.h index 9d3324bd3db..17632361518 100644 --- a/scene/gui/tree.h +++ b/scene/gui/tree.h @@ -657,7 +657,6 @@ private: bool h_scroll_enabled = true; bool v_scroll_enabled = true; - Size2 get_internal_min_size() const; void update_scrollbars(); Rect2 search_item_rect(TreeItem *p_from, TreeItem *p_item); @@ -798,6 +797,8 @@ public: void ensure_cursor_is_visible(); Rect2 get_custom_popup_rect() const; + Size2 get_background_size() const; + Size2 get_internal_min_size() const; int get_item_offset(TreeItem *p_item) const; Rect2 get_item_rect(TreeItem *p_item, int p_column = -1, int p_button = -1) const; From 189d18be580e0bb94a42de6cae53cd1883be1bea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pa=CC=84vels=20Nadtoc=CC=8Cajevs?= <7645683+bruvzg@users.noreply.github.com> Date: Tue, 25 Feb 2025 18:53:22 +0200 Subject: [PATCH 2/2] Use list properties for display drivers. --- doc/classes/ProjectSettings.xml | 89 +---- editor/project_manager.cpp | 2 +- main/main.cpp | 168 ++++----- main/main.h | 1 - modules/openxr/register_types.cpp | 2 +- platform/android/display_server_android.cpp | 125 +++++-- platform/android/display_server_android.h | 3 + platform/ios/display_server_ios.h | 3 + platform/ios/display_server_ios.mm | 170 ++++++--- .../wayland/display_server_wayland.cpp | 309 +++++++++------- .../linuxbsd/wayland/display_server_wayland.h | 3 + platform/linuxbsd/x11/display_server_x11.cpp | 287 ++++++++------- platform/linuxbsd/x11/display_server_x11.h | 4 + platform/macos/display_server_macos.h | 3 + platform/macos/display_server_macos.mm | 190 ++++++---- platform/web/display_server_web.cpp | 118 ++++-- platform/web/display_server_web.h | 5 + platform/windows/display_server_windows.cpp | 345 ++++++++---------- platform/windows/display_server_windows.h | 12 +- servers/display_server.h | 2 + 20 files changed, 1015 insertions(+), 826 deletions(-) diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index 1a29e2003e9..7286c4d2d2d 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -2684,59 +2684,25 @@ Base size used to determine size of froxel buffer in the camera X-axis and Y-axis. The final size is scaled by the aspect ratio of the screen, so actual values may differ from what is set. Set a larger size for more detailed fog, set a smaller size for better performance. - Sets the driver to be used by the renderer when using the Compatibility renderer. Editing this property has no effect in the default configuration, as first-party platforms each have platform-specific overrides. Use those overrides to configure the driver for each platform. - This can be overridden using the [code]--rendering-driver <driver>[/code] command line argument. - Supported values are: - - [code]opengl3[/code], OpenGL 3.3 on desktop platforms, OpenGL ES 3.0 on mobile platforms, WebGL 2.0 on web. - - [code]opengl3_angle[/code], OpenGL ES 3.0 using the ANGLE compatibility layer, supported on macOS (over native OpenGL) and Windows (over Direct3D 11). - - [code]opengl3_es[/code], OpenGL ES 3.0 on Linux/BSD. - [b]Note:[/b] The availability of these options depends on whether the engine was compiled with support for them (determined by SCons options [code]opengl3[/code] and [code]angle_libs[/code]). - [b]Note:[/b] The actual rendering driver may be automatically changed by the engine as a result of a fallback, or a user-specified command line argument. To get the actual rendering driver that is used at runtime, use [method RenderingServer.get_current_rendering_driver_name] instead of reading this project setting's value. + TODO Android override for [member rendering/gl_compatibility/driver]. - Only one option is supported: - - [code]opengl3[/code], OpenGL ES 3.0 from native drivers. iOS override for [member rendering/gl_compatibility/driver]. - Only one option is supported: - - [code]opengl3[/code], OpenGL ES 3.0 from native drivers. - + LinuxBSD override for [member rendering/gl_compatibility/driver]. - Two options are supported: - - [code]opengl3[/code] (default), OpenGL 3.3 from native drivers. - - [code]opengl3_es[/code], OpenGL ES 3.0 from native drivers. If [member rendering/gl_compatibility/fallback_to_gles] is enabled, this is used as a fallback if OpenGL 3.3 is not supported. - + macOS override for [member rendering/gl_compatibility/driver]. - Two options are supported: - - [code]opengl3[/code] (default), OpenGL 3.3 from native drivers. If [member rendering/gl_compatibility/fallback_to_native] is enabled, this is used as a fallback if ANGLE is configured as the preferred driver but not supported. - - [code]opengl3_angle[/code], OpenGL ES 3.0 using the ANGLE compatibility layer over native OpenGL drivers. If [member rendering/gl_compatibility/fallback_to_angle] is enabled, this is used as a fallback if OpenGL 3.3 is not supported. Web override for [member rendering/gl_compatibility/driver]. - Only one option is supported: - - [code]opengl3[/code], WebGL 2.0. The underlying native API depends on the target OS, browser, and browser configuration. - + Windows override for [member rendering/gl_compatibility/driver]. - Two options are supported: - - [code]opengl3[/code] (default), OpenGL 3.3 from native drivers. If [member rendering/gl_compatibility/fallback_to_native] is enabled, this is used as a fallback if ANGLE is configured as the preferred driver but not supported. - - [code]opengl3_angle[/code], OpenGL ES 3.0 using the ANGLE compatibility layer over native Direct3D 11 drivers. If [member rendering/gl_compatibility/fallback_to_angle] is enabled, this is used as a fallback if OpenGL 3.3 is not supported. By default, ANGLE is used as the default driver for some devices listed in [member rendering/gl_compatibility/force_angle_on_devices]. - - - If [code]true[/code], the compatibility renderer will fall back to ANGLE if native OpenGL is not supported or the device is listed in [member rendering/gl_compatibility/force_angle_on_devices]. - [b]Note:[/b] This setting is implemented only on Windows. - - - If [code]true[/code], the compatibility renderer will fall back to OpenGLES if desktop OpenGL is not supported. - [b]Note:[/b] This setting is implemented only on Linux/X11. - - - If [code]true[/code], the compatibility renderer will fall back to native OpenGL if ANGLE is not supported, or ANGLE dynamic libraries aren't found. - [b]Note:[/b] This setting is implemented on macOS and Windows. An [Array] of devices which should always use the ANGLE renderer. @@ -2961,6 +2927,10 @@ Lower-end override for [member rendering/reflections/sky_reflections/texture_array_reflections] on mobile devices, due to performance concerns or driver support. + + + + Sets the renderer that will be used by the project. Options are: [b]forward_plus[/b] (Forward+): High-end renderer designed for desktop devices. Has a higher base overhead, but scales well with complex scenes. Not suitable for older devices or mobile. @@ -2991,57 +2961,22 @@ Depending on the complexity of scenes, this value may be lowered or may need to be raised. - Sets the driver to be used by the renderer when using a RenderingDevice-based renderer like the Forward+ or Mobile renderers. Editing this property has no effect in the default configuration, as first-party platforms each have platform-specific overrides. Use those overrides to configure the driver for each platform. - This can be overridden using the [code]--rendering-driver <driver>[/code] command line argument. - Supported values are: - - [code]metal[/code], Metal (supported on Apple Silicon Macs and iOS). - - [code]vulkan[/code], Vulkan (supported on all desktop and mobile platforms). - - [code]d3d12[/code], Direct3D 12 (supported on Windows). - [b]Note:[/b] The availability of these options depends on whether the engine was compiled with support for them (determined by SCons options [code]vulkan[/code], [code]metal[/code], and [code]d3d12[/code]). - [b]Note:[/b] If a given platform has no registered drivers, it can fall back to the Compatibility renderer (OpenGL 3) if [member rendering/rendering_device/fallback_to_opengl3] is enabled. This fallback happens automatically for the Web platform regardless of that property. - [b]Note:[/b] The actual rendering driver may be automatically changed by the engine as a result of a fallback, or a user-specified command line argument. To get the actual rendering driver that is used at runtime, use [method RenderingServer.get_current_rendering_driver_name] instead of reading this project setting's value. + TODO Android override for [member rendering/rendering_device/driver]. - Only one option is supported: - - [code]vulkan[/code], Vulkan from native drivers. - [b]Note:[/b] If Vulkan was disabled at compile time, there is no alternative RenderingDevice driver. - + iOS override for [member rendering/rendering_device/driver]. - Two options are supported: - - [code]metal[/code] (default), Metal from native drivers. - - [code]vulkan[/code], Vulkan over Metal via MoltenVK. LinuxBSD override for [member rendering/rendering_device/driver]. - Only one option is supported: - - [code]vulkan[/code], Vulkan from native drivers. - [b]Note:[/b] If Vulkan was disabled at compile time, there is no alternative RenderingDevice driver. - + macOS override for [member rendering/rendering_device/driver]. - Two options are supported: - - [code]metal[/code] (default), Metal from native drivers, only supported on Apple Silicon Macs. On Intel Macs, it will automatically fall back to [code]vulkan[/code] as Metal support is not implemented. - - [code]vulkan[/code], Vulkan over Metal via MoltenVK, supported on both Apple Silicon and Intel Macs. - + Windows override for [member rendering/rendering_device/driver]. - Two options are supported: - - [code]vulkan[/code] (default), Vulkan from native drivers. If [member rendering/rendering_device/fallback_to_vulkan] is enabled, this is used as a fallback if Direct3D 12 is not supported. - - [code]d3d12[/code], Direct3D 12 from native drivers. If [member rendering/rendering_device/fallback_to_d3d12] is enabled, this is used as a fallback if Vulkan is not supported. - - - If [code]true[/code], the forward renderer will fall back to Direct3D 12 if Vulkan is not supported. The fallback is always attempted regardless of this setting if Vulkan driver support was disabled at compile time. - [b]Note:[/b] This setting is implemented only on Windows. - - - If [code]true[/code], the forward renderer will fall back to OpenGL 3 if Direct3D 12, Metal, and Vulkan are not supported. - [b]Note:[/b] This setting is implemented only on Windows, Android, macOS, iOS, and Linux/X11. - - - If [code]true[/code], the forward renderer will fall back to Vulkan if Direct3D 12 (on Windows) or Metal (on macOS x86_64) are not supported. The fallback is always attempted regardless of this setting if Direct3D 12 (Windows) or Metal (macOS) driver support was disabled at compile time. - [b]Note:[/b] This setting is implemented only on Windows and macOS. Enable the pipeline cache that is saved to disk if the graphics API supports it. diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index c3bd3acf775..088cfcc428f 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -1017,7 +1017,7 @@ void ProjectManager::_perform_full_project_conversion() { args.push_back(path); args.push_back("--convert-3to4"); args.push_back("--rendering-driver"); - args.push_back(Main::get_rendering_driver_name()); + args.push_back(OS::get_singleton()->get_current_rendering_driver_name()); Error err = OS::get_singleton()->create_instance(args); ERR_FAIL_COND(err); diff --git a/main/main.cpp b/main/main.cpp index 10064b35037..b2166af4e23 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -2072,32 +2072,25 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph { // RenderingDevice driver overrides per platform. - GLOBAL_DEF_RST("rendering/rendering_device/driver", "vulkan"); - GLOBAL_DEF_RST(PropertyInfo(Variant::STRING, "rendering/rendering_device/driver.windows", PROPERTY_HINT_ENUM, "vulkan,d3d12"), "vulkan"); - GLOBAL_DEF_RST(PropertyInfo(Variant::STRING, "rendering/rendering_device/driver.linuxbsd", PROPERTY_HINT_ENUM, "vulkan"), "vulkan"); - GLOBAL_DEF_RST(PropertyInfo(Variant::STRING, "rendering/rendering_device/driver.android", PROPERTY_HINT_ENUM, "vulkan"), "vulkan"); - GLOBAL_DEF_RST(PropertyInfo(Variant::STRING, "rendering/rendering_device/driver.ios", PROPERTY_HINT_ENUM, "metal,vulkan"), "metal"); - GLOBAL_DEF_RST(PropertyInfo(Variant::STRING, "rendering/rendering_device/driver.macos", PROPERTY_HINT_ENUM, "metal,vulkan"), "metal"); - - GLOBAL_DEF_RST("rendering/rendering_device/fallback_to_vulkan", true); - GLOBAL_DEF_RST("rendering/rendering_device/fallback_to_d3d12", true); - GLOBAL_DEF_RST("rendering/rendering_device/fallback_to_opengl3", true); + GLOBAL_DEF_RST(PropertyInfo(Variant::STRING, "rendering/rendering_device/driver", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "vulkan"); + GLOBAL_DEF_RST(PropertyInfo(Variant::STRING, "rendering/rendering_device/driver.windows", PROPERTY_HINT_ORDERED_LIST, "Vulkan:vulkan,Direct3D 12:d3d12"), "vulkan,d3d12"); + GLOBAL_DEF_RST(PropertyInfo(Variant::STRING, "rendering/rendering_device/driver.linuxbsd", PROPERTY_HINT_ORDERED_LIST, "Vulkan:vulkan"), "vulkan"); + GLOBAL_DEF_RST(PropertyInfo(Variant::STRING, "rendering/rendering_device/driver.android", PROPERTY_HINT_ORDERED_LIST, "Vulkan:vulkan"), "vulkan"); + GLOBAL_DEF_RST(PropertyInfo(Variant::STRING, "rendering/rendering_device/driver.ios", PROPERTY_HINT_ORDERED_LIST, "Metal:metal,Vulkan (using MoltenVK):vulkan"), "metal,vulkan"); + GLOBAL_DEF_RST(PropertyInfo(Variant::STRING, "rendering/rendering_device/driver.macos", PROPERTY_HINT_ORDERED_LIST, "Metal (supported on Apple Silicon only):metal,Vulkan (using MoltenVK):vulkan"), "metal,vulkan"); } { // GL Compatibility driver overrides per platform. - GLOBAL_DEF_RST("rendering/gl_compatibility/driver", "opengl3"); - GLOBAL_DEF_RST(PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver.windows", PROPERTY_HINT_ENUM, "opengl3,opengl3_angle"), "opengl3"); - GLOBAL_DEF_RST(PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver.linuxbsd", PROPERTY_HINT_ENUM, "opengl3,opengl3_es"), "opengl3"); - GLOBAL_DEF_RST(PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver.web", PROPERTY_HINT_ENUM, "opengl3"), "opengl3"); - GLOBAL_DEF_RST(PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver.android", PROPERTY_HINT_ENUM, "opengl3"), "opengl3"); - GLOBAL_DEF_RST(PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver.ios", PROPERTY_HINT_ENUM, "opengl3"), "opengl3"); - GLOBAL_DEF_RST(PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver.macos", PROPERTY_HINT_ENUM, "opengl3,opengl3_angle"), "opengl3"); + GLOBAL_DEF_RST(PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "opengl3"); + GLOBAL_DEF_RST(PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver.windows", PROPERTY_HINT_ORDERED_LIST, "OpenGL 3.3:opengl3,OpenGLES 3.0 (using ANGLE):opengl3_angle"), "opengl3,opengl3_angle"); + GLOBAL_DEF_RST(PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver.linuxbsd", PROPERTY_HINT_ORDERED_LIST, "OpenGL 3.3:opengl3,OpenGLES 3.0:opengl3_es"), "opengl3,opengl3_es"); + GLOBAL_DEF_RST(PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver.web", PROPERTY_HINT_ORDERED_LIST, "WebGL 2.0:opengl3"), "opengl3"); + GLOBAL_DEF_RST(PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver.android", PROPERTY_HINT_ORDERED_LIST, "OpenGLES 3.0:opengl3"), "opengl3"); + GLOBAL_DEF_RST(PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver.ios", PROPERTY_HINT_ORDERED_LIST, "OpenGLES 3.0:opengl3"), "opengl3"); + GLOBAL_DEF_RST(PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver.macos", PROPERTY_HINT_ORDERED_LIST, "OpenGL 3.2:opengl3,OpenGLES 3.0 (using ANGLE):opengl3_angle"), "opengl3,opengl3_angle"); GLOBAL_DEF_RST("rendering/gl_compatibility/nvidia_disable_threaded_optimization", true); - GLOBAL_DEF_RST("rendering/gl_compatibility/fallback_to_angle", true); - GLOBAL_DEF_RST("rendering/gl_compatibility/fallback_to_native", true); - GLOBAL_DEF_RST("rendering/gl_compatibility/fallback_to_gles", true); Array device_blocklist; @@ -2272,7 +2265,13 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph } // Default to Compatibility when using the project manager. if (rendering_driver.is_empty() && rendering_method.is_empty() && project_manager) { +#if defined(WINDOWS_ENABLED) + rendering_driver = "opengl3,opengl3_angle"; +#elif defined(LINUXBSD_ENABLED) + rendering_driver = "opengl3,opengl3_es"; +#else rendering_driver = "opengl3"; +#endif rendering_method = "gl_compatibility"; default_renderer_mobile = "gl_compatibility"; } @@ -2304,105 +2303,64 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph } if (!rendering_driver.is_empty()) { - // As the rendering drivers available may depend on the display driver and renderer - // selected, we can't do an exhaustive check here, but we can look through all - // the options in all the display drivers for a match. + rendering_driver = rendering_driver.to_lower(); - bool found = false; + Vector unique_rendering_drivers_modern; + Vector unique_rendering_drivers_compat; for (int i = 0; i < DisplayServer::get_create_function_count(); i++) { Vector r_drivers = DisplayServer::get_create_function_rendering_drivers(i); - for (int d = 0; d < r_drivers.size(); d++) { - if (rendering_driver == r_drivers[d]) { - found = true; - break; + for (const String &ds_driver : r_drivers) { + if (ds_driver == "opengl3" || ds_driver == "opengl3_angle" || ds_driver == "opengl3_es") { + if (!unique_rendering_drivers_modern.has(ds_driver)) { + unique_rendering_drivers_modern.append(ds_driver); + } + } else { + if (!unique_rendering_drivers_compat.has(ds_driver)) { + unique_rendering_drivers_compat.append(ds_driver); + } } } } + Vector pending_drivers = rendering_driver.split(","); + bool has_compat = pending_drivers.has("opengl3") || pending_drivers.has("opengl3_angle") || pending_drivers.has("opengl3_es"); + bool has_modern = pending_drivers.has("metal") || pending_drivers.has("vulkan") || pending_drivers.has("d3d12"); + bool found = false; + for (const String &cmd_driver : pending_drivers) { + if (unique_rendering_drivers_compat.has(cmd_driver) || unique_rendering_drivers_modern.has(cmd_driver)) { + found = true; + break; + } + } + if (!found) { - OS::get_singleton()->print("Unknown rendering driver '%s', aborting.\nValid options are ", - rendering_driver.utf8().get_data()); + OS::get_singleton()->print("Rendering driver argument '%s' has no valid drivers, aborting. Valid options are:\n", rendering_driver.utf8().get_data()); - // Deduplicate driver entries, as a rendering driver may be supported by several display servers. - Vector unique_rendering_drivers; - for (int i = 0; i < DisplayServer::get_create_function_count(); i++) { - Vector r_drivers = DisplayServer::get_create_function_rendering_drivers(i); + OS::get_singleton()->print(" for 'compatibility' rendering method: '%s'.\n", String("', '").join(unique_rendering_drivers_compat).utf8().get_data()); + OS::get_singleton()->print(" for 'forward_plus' and 'mobile' rendering methods: '%s'.\n", String("', '").join(unique_rendering_drivers_modern).utf8().get_data()); - for (int d = 0; d < r_drivers.size(); d++) { - if (!unique_rendering_drivers.has(r_drivers[d])) { - unique_rendering_drivers.append(r_drivers[d]); - } - } - } - - for (int i = 0; i < unique_rendering_drivers.size(); i++) { - if (i == unique_rendering_drivers.size() - 1) { - OS::get_singleton()->print(" and "); - } else if (i != 0) { - OS::get_singleton()->print(", "); - } - OS::get_singleton()->print("'%s'", unique_rendering_drivers[i].utf8().get_data()); - } - - OS::get_singleton()->print(".\n"); + goto error; + } + // Now validate whether the selected driver matches with the renderer. + if (has_compat && (rendering_method == "forward_plus" || rendering_method == "mobile")) { + OS::get_singleton()->print("Invalid rendering method/driver combination '%s' and '%s', aborting. Valid options are: '%s'.\n", rendering_method.utf8().get_data(), rendering_driver.utf8().get_data(), String("', '").join(unique_rendering_drivers_modern).utf8().get_data()); + goto error; + } + if (has_modern && (rendering_method == "gl_compatibility")) { + OS::get_singleton()->print("Invalid rendering method/driver combination '%s' and '%s', aborting. Valid options are: '%s'.\n", rendering_method.utf8().get_data(), rendering_driver.utf8().get_data(), String("', '").join(unique_rendering_drivers_compat).utf8().get_data()); goto error; } // Set a default renderer if none selected. Try to choose one that matches the driver. if (rendering_method.is_empty()) { - if (rendering_driver == "opengl3" || rendering_driver == "opengl3_angle" || rendering_driver == "opengl3_es") { - rendering_method = "gl_compatibility"; - } else { + if (has_modern) { rendering_method = "forward_plus"; + } else { + rendering_method = "gl_compatibility"; } } - - // Now validate whether the selected driver matches with the renderer. - bool valid_combination = false; - Vector available_drivers; - if (rendering_method == "forward_plus" || rendering_method == "mobile") { -#ifdef VULKAN_ENABLED - available_drivers.push_back("vulkan"); -#endif -#ifdef D3D12_ENABLED - available_drivers.push_back("d3d12"); -#endif -#ifdef METAL_ENABLED - available_drivers.push_back("metal"); -#endif - } -#ifdef GLES3_ENABLED - if (rendering_method == "gl_compatibility") { - available_drivers.push_back("opengl3"); - available_drivers.push_back("opengl3_angle"); - available_drivers.push_back("opengl3_es"); - } -#endif - if (available_drivers.is_empty()) { - OS::get_singleton()->print("Unknown renderer name '%s', aborting.\n", rendering_method.utf8().get_data()); - goto error; - } - - for (int i = 0; i < available_drivers.size(); i++) { - if (rendering_driver == available_drivers[i]) { - valid_combination = true; - break; - } - } - - if (!valid_combination) { - OS::get_singleton()->print("Invalid renderer/driver combination '%s' and '%s', aborting. %s only supports the following drivers ", rendering_method.utf8().get_data(), rendering_driver.utf8().get_data(), rendering_method.utf8().get_data()); - - for (int d = 0; d < available_drivers.size(); d++) { - OS::get_singleton()->print("'%s', ", available_drivers[d].utf8().get_data()); - } - - OS::get_singleton()->print(".\n"); - - goto error; - } } default_renderer = renderer_hints.get_slice(",", 0); @@ -2410,6 +2368,9 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph GLOBAL_DEF_RST_BASIC("rendering/renderer/rendering_method.mobile", default_renderer_mobile); GLOBAL_DEF_RST_BASIC("rendering/renderer/rendering_method.web", "gl_compatibility"); // This is a bit of a hack until we have WebGPU support. + GLOBAL_DEF_RST("rendering/renderer/fallback_to_opengl3", true); + GLOBAL_DEF_RST("rendering/renderer/fallback_to_dummy", false); + // Default to ProjectSettings default if nothing set on the command line. if (rendering_method.is_empty()) { rendering_method = GLOBAL_GET("rendering/renderer/rendering_method"); @@ -2423,10 +2384,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph } } - // always convert to lower case for consistency in the code - rendering_driver = rendering_driver.to_lower(); - - OS::get_singleton()->set_current_rendering_driver_name(rendering_driver); + OS::get_singleton()->set_current_rendering_driver_name(rendering_driver.get_slice(",", 0)); OS::get_singleton()->set_current_rendering_method(rendering_method); #ifdef TOOLS_ENABLED @@ -3584,10 +3542,6 @@ void Main::setup_boot_logo() { GLOBAL_GET("rendering/environment/defaults/default_clear_color")); } -String Main::get_rendering_driver_name() { - return rendering_driver; -} - // everything the main loop needs to know about frame timings static MainTimerSync main_timer_sync; diff --git a/main/main.h b/main/main.h index 6dd2ff7d7a8..71286f3d153 100644 --- a/main/main.h +++ b/main/main.h @@ -72,7 +72,6 @@ public: static int test_entrypoint(int argc, char *argv[], bool &tests_need_run); static Error setup(const char *execpath, int argc, char *argv[], bool p_second_phase = true); static Error setup2(bool p_show_boot_logo = true); // The thread calling setup2() will effectively become the main thread. - static String get_rendering_driver_name(); static void setup_boot_logo(); #ifdef TESTS_ENABLED static Error test_setup(); diff --git a/modules/openxr/register_types.cpp b/modules/openxr/register_types.cpp index 69c119d069e..05a275bcffc 100644 --- a/modules/openxr/register_types.cpp +++ b/modules/openxr/register_types.cpp @@ -163,7 +163,7 @@ void initialize_openxr_module(ModuleInitializationLevel p_level) { openxr_api = memnew(OpenXRAPI); ERR_FAIL_NULL(openxr_api); - if (!openxr_api->initialize(Main::get_rendering_driver_name())) { + if (!openxr_api->initialize(OS::get_singleton()->get_current_rendering_driver_name())) { const char *init_error_message = "OpenXR was requested but failed to start.\n" "Please check if your HMD is connected.\n" diff --git a/platform/android/display_server_android.cpp b/platform/android/display_server_android.cpp index f8d960f2b70..7769b807f22 100644 --- a/platform/android/display_server_android.cpp +++ b/platform/android/display_server_android.cpp @@ -52,6 +52,8 @@ #include #endif +#include "servers/rendering/dummy/rasterizer_dummy.h" + DisplayServerAndroid *DisplayServerAndroid::get_singleton() { return static_cast(DisplayServer::get_singleton()); } @@ -578,22 +580,42 @@ Vector DisplayServerAndroid::get_rendering_drivers_func() { #ifdef VULKAN_ENABLED drivers.push_back("vulkan"); #endif + drivers.push_back("dummy"); return drivers; } +String DisplayServerAndroid::get_readable_driver_name(const String &p_driver) const { + if (p_driver == "vulkan") { + return "Vulkan"; + } else if (p_driver == "opengl3") { + return "OpenGLES 3.0"; + } else if (p_driver == "dummy") { + return "Dummy"; + } else { + return p_driver; + } +} + DisplayServer *DisplayServerAndroid::create_func(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Context p_context, int64_t p_parent_window, Error &r_error) { - DisplayServer *ds = memnew(DisplayServerAndroid(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_position, p_resolution, p_screen, p_context, p_parent_window, r_error)); + DisplayServerAndroid *ds = memnew(DisplayServerAndroid(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_position, p_resolution, p_screen, p_context, p_parent_window, r_error)); if (r_error != OK) { - if (p_rendering_driver == "vulkan") { + Vector names; + for (const String &driver : ds->tested_drivers) { + names.push_back(ds->get_readable_driver_name(driver)); + } + + if (!ds->tested_drivers.has("opengl3")) { OS::get_singleton()->alert( - "Your device seems not to support the required Vulkan version.\n\n" - "Please try exporting your game using the 'gl_compatibility' renderer.", - "Unable to initialize Vulkan video driver"); + vformat("Your device seem not to support the required version of the following drivers:\n%s.\n\n" + "Please try exporting your game using the 'gl_compatibility' renderer.", + String(", ").join(names)), + "Unable to initialize video driver"); } else { OS::get_singleton()->alert( - "Your device seems not to support the required OpenGL ES 3.0 version.", - "Unable to initialize OpenGL video driver"); + vformat("Your device seem not to support the required version of the following drivers:\n%s.\n\n", + String(", ").join(names)), + "Unable to initialize video driver"); } } return ds; @@ -657,37 +679,71 @@ DisplayServerAndroid::DisplayServerAndroid(const String &p_rendering_driver, Dis native_menu = memnew(NativeMenu); -#if defined(RD_ENABLED) - rendering_context = nullptr; - rendering_device = nullptr; - -#if defined(VULKAN_ENABLED) - if (rendering_driver == "vulkan") { - rendering_context = memnew(RenderingContextDriverVulkanAndroid); + Vector driver_list; + for (const String &drv : p_rendering_driver.split(",")) { + if (!driver_list.has(drv)) { + driver_list.push_back(drv); + } } -#endif - - if (rendering_context) { - if (rendering_context->initialize() != OK) { - memdelete(rendering_context); - rendering_context = nullptr; -#if defined(GLES3_ENABLED) - bool fallback_to_opengl3 = GLOBAL_GET("rendering/rendering_device/fallback_to_opengl3"); - if (fallback_to_opengl3 && rendering_driver != "opengl3") { - WARN_PRINT("Your device seem not to support Vulkan, switching to OpenGL 3."); - rendering_driver = "opengl3"; - OS::get_singleton()->set_current_rendering_method("gl_compatibility"); - OS::get_singleton()->set_current_rendering_driver_name(rendering_driver); - } else -#endif - { - ERR_PRINT(vformat("Failed to initialize %s context", rendering_driver)); - r_error = ERR_UNAVAILABLE; - return; + if (GLOBAL_GET("rendering/renderer/fallback_to_opengl3").operator bool()) { + for (const String &drv : GLOBAL_GET("rendering/gl_compatibility/driver").operator String().split(",")) { + if (!driver_list.has(drv)) { + driver_list.push_back(drv); } } } + if (GLOBAL_GET("rendering/renderer/fallback_to_dummy").operator bool()) { + if (!driver_list.has("dummy")) { + driver_list.push_back("dummy"); + } + } + bool driver_found = false; + for (const String &driver : driver_list) { + print_line(vformat("Trying to initialize \"%s\" rendering driver.", get_readable_driver_name(driver))); + tested_drivers.push_back(driver); +#if defined(RD_ENABLED) +#if defined(VULKAN_ENABLED) + if (driver == "vulkan") { + rendering_context = memnew(RenderingContextDriverVulkanAndroid); + if (rendering_context->initialize() == OK) { + rendering_driver = driver; + OS::get_singleton()->set_current_rendering_driver_name(rendering_driver); + driver_found = true; + break; + } + memdelete(rendering_context); + rendering_context = nullptr; + } +#endif // VULKAN_ENABLED +#endif // RD_ENABLED +#if defined(GLES3_ENABLED) + if (driver == "opengl3") { + rendering_driver = driver; + OS::get_singleton()->set_current_rendering_method("gl_compatibility"); + OS::get_singleton()->set_current_rendering_driver_name(rendering_driver); + driver_found = true; + break; + } +#endif // GLES3_ENABLED + if (driver == "dummy") { + rendering_driver = driver; + OS::get_singleton()->set_current_rendering_method("gl_compatibility"); + OS::get_singleton()->set_current_rendering_driver_name(rendering_driver); + driver_found = true; + break; + } + print_line(vformat(" \"%s\" rendering driver initialization failed.", get_readable_driver_name(driver))); + } + + if (driver_found) { + print_line(vformat(" \"%s\" rendering driver initialized successfully.", get_readable_driver_name(rendering_driver))); + } else { + r_error = ERR_UNAVAILABLE; + ERR_FAIL_MSG("Could not initialize any of the rendering drivers."); + } + +#if defined(RD_ENABLED) if (rendering_context) { union { #ifdef VULKAN_ENABLED @@ -733,6 +789,9 @@ DisplayServerAndroid::DisplayServerAndroid(const String &p_rendering_driver, Dis RasterizerGLES3::make_current(false); } #endif + if (rendering_driver == "dummy") { + RasterizerDummy::make_current(); + } Input::get_singleton()->set_event_dispatch_function(_dispatch_input_events); diff --git a/platform/android/display_server_android.h b/platform/android/display_server_android.h index 587d8731a10..b87eead99bb 100644 --- a/platform/android/display_server_android.h +++ b/platform/android/display_server_android.h @@ -42,6 +42,7 @@ class DisplayServerAndroid : public DisplayServer { // No need to register with GDCLASS, it's platform-specific and nothing is added. String rendering_driver; + Vector tested_drivers; // https://developer.android.com/reference/android/view/PointerIcon // mapping between Godot's cursor shape to Android's' @@ -254,6 +255,8 @@ public: virtual void set_native_icon(const String &p_filename) override; virtual void set_icon(const Ref &p_icon) override; + String get_readable_driver_name(const String &p_driver) const override; + DisplayServerAndroid(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Context p_context, int64_t p_parent_window, Error &r_error); ~DisplayServerAndroid(); }; diff --git a/platform/ios/display_server_ios.h b/platform/ios/display_server_ios.h index 696f72b0f8d..e053c42c9e9 100644 --- a/platform/ios/display_server_ios.h +++ b/platform/ios/display_server_ios.h @@ -89,6 +89,9 @@ class DisplayServerIOS : public DisplayServer { public: String rendering_driver; + Vector tested_drivers; + + String get_readable_driver_name(const String &p_driver) const override; static DisplayServerIOS *get_singleton(); diff --git a/platform/ios/display_server_ios.mm b/platform/ios/display_server_ios.mm index 09acc199bf9..dbd750a68ee 100644 --- a/platform/ios/display_server_ios.mm +++ b/platform/ios/display_server_ios.mm @@ -43,6 +43,8 @@ #include "core/config/project_settings.h" #include "core/io/file_access_pack.h" +#include "servers/rendering/dummy/rasterizer_dummy.h" + #import #import @@ -56,7 +58,7 @@ DisplayServerIOS *DisplayServerIOS::get_singleton() { DisplayServerIOS::DisplayServerIOS(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Context p_context, int64_t p_parent_window, Error &r_error) { KeyMappingIOS::initialize(); - rendering_driver = p_rendering_driver; + CALayer *layer = nullptr; // Init TTS bool tts_enabled = GLOBAL_GET("audio/general/text_to_speech"); @@ -65,12 +67,93 @@ DisplayServerIOS::DisplayServerIOS(const String &p_rendering_driver, WindowMode } native_menu = memnew(NativeMenu); + Vector driver_list; + for (const String &drv : p_rendering_driver.split(",")) { + if (!driver_list.has(drv)) { + driver_list.push_back(drv); + } + } + if (GLOBAL_GET("rendering/renderer/fallback_to_opengl3").operator bool()) { + for (const String &drv : GLOBAL_GET("rendering/gl_compatibility/driver").operator String().split(",")) { + if (!driver_list.has(drv)) { + driver_list.push_back(drv); + } + } + } + if (GLOBAL_GET("rendering/renderer/fallback_to_dummy").operator bool()) { + if (!driver_list.has("dummy")) { + driver_list.push_back("dummy"); + } + } + + bool driver_found = false; + for (const String &driver : driver_list) { + print_line(vformat("Trying to initialize \"%s\" rendering driver.", get_readable_driver_name(driver))); + tested_drivers.push_back(driver); #if defined(RD_ENABLED) - rendering_context = nullptr; - rendering_device = nullptr; +#if defined(METAL_ENABLED) + if (driver == "metal") { + if (@available(iOS 14.0, *)) { + layer = [AppDelegate.viewController.godotView initializeRenderingForDriver:@"metal"]; + rendering_context = memnew(RenderingContextDriverMetal); + if (rendering_context->initialize() == OK && layer) { + rendering_driver = driver; + OS::get_singleton()->set_current_rendering_driver_name(rendering_driver); + driver_found = true; + break; + } + memdelete(rendering_context); + rendering_context = nullptr; + layer = nullptr; + } + } +#endif // METAL_ENABLED +#if defined(VULKAN_ENABLED) + if (driver == "vulkan") { + layer = [AppDelegate.viewController.godotView initializeRenderingForDriver:@"vulkan"]; + rendering_context = memnew(RenderingContextDriverVulkanIOS); + if (rendering_context->initialize() == OK && layer) { + rendering_driver = driver; + OS::get_singleton()->set_current_rendering_driver_name(rendering_driver); + driver_found = true; + break; + } + memdelete(rendering_context); + rendering_context = nullptr; + layer = nullptr; + } +#endif // VULKAN_ENABLED +#endif // RD_ENABLED +#if defined(GLES3_ENABLED) + if (driver == "opengl3") { + layer = [AppDelegate.viewController.godotView initializeRenderingForDriver:@"opengl3"]; + if (layer) { + rendering_driver = driver; + OS::get_singleton()->set_current_rendering_method("gl_compatibility"); + OS::get_singleton()->set_current_rendering_driver_name(rendering_driver); + driver_found = true; + break; + } + } +#endif // GLES3_ENABLED + if (driver == "dummy") { + rendering_driver = driver; + OS::get_singleton()->set_current_rendering_method("gl_compatibility"); + OS::get_singleton()->set_current_rendering_driver_name(rendering_driver); + driver_found = true; + break; + } + print_line(vformat(" \"%s\" rendering driver initialization failed.", get_readable_driver_name(driver))); + } - CALayer *layer = nullptr; + if (driver_found) { + print_line(vformat(" \"%s\" rendering driver initialized successfully.", get_readable_driver_name(rendering_driver))); + } else { + r_error = ERR_UNAVAILABLE; + ERR_FAIL_MSG("Could not initialize any of the rendering drivers."); + } +#if defined(RD_ENABLED) union { #ifdef VULKAN_ENABLED RenderingContextDriverVulkanIOS::WindowPlatformData vulkan; @@ -86,47 +169,16 @@ DisplayServerIOS::DisplayServerIOS(const String &p_rendering_driver, WindowMode #if defined(VULKAN_ENABLED) if (rendering_driver == "vulkan") { - layer = [AppDelegate.viewController.godotView initializeRenderingForDriver:@"vulkan"]; - if (!layer) { - ERR_FAIL_MSG("Failed to create iOS Vulkan rendering layer."); - } wpd.vulkan.layer_ptr = (CAMetalLayer *const *)&layer; - rendering_context = memnew(RenderingContextDriverVulkanIOS); } #endif #ifdef METAL_ENABLED if (rendering_driver == "metal") { if (@available(iOS 14.0, *)) { - layer = [AppDelegate.viewController.godotView initializeRenderingForDriver:@"metal"]; wpd.metal.layer = (CAMetalLayer *)layer; - rendering_context = memnew(RenderingContextDriverMetal); - } else { - OS::get_singleton()->alert("Metal is only supported on iOS 14.0 and later."); - r_error = ERR_UNAVAILABLE; - return; } } #endif - if (rendering_context) { - if (rendering_context->initialize() != OK) { - memdelete(rendering_context); - rendering_context = nullptr; -#if defined(GLES3_ENABLED) - bool fallback_to_opengl3 = GLOBAL_GET("rendering/rendering_device/fallback_to_opengl3"); - if (fallback_to_opengl3 && rendering_driver != "opengl3") { - WARN_PRINT("Your device seem not to support MoltenVK or Metal, switching to OpenGL 3."); - rendering_driver = "opengl3"; - OS::get_singleton()->set_current_rendering_method("gl_compatibility"); - OS::get_singleton()->set_current_rendering_driver_name(rendering_driver); - } else -#endif - { - ERR_PRINT(vformat("Failed to initialize %s context", rendering_driver)); - r_error = ERR_UNAVAILABLE; - return; - } - } - } if (rendering_context) { if (rendering_context->window_create(MAIN_WINDOW_ID, &wpd) != OK) { @@ -157,15 +209,12 @@ DisplayServerIOS::DisplayServerIOS(const String &p_rendering_driver, WindowMode #if defined(GLES3_ENABLED) if (rendering_driver == "opengl3") { - CALayer *layer = [AppDelegate.viewController.godotView initializeRenderingForDriver:@"opengl3"]; - - if (!layer) { - ERR_FAIL_MSG("Failed to create iOS OpenGLES rendering layer."); - } - RasterizerGLES3::make_current(false); } #endif + if (rendering_driver == "dummy") { + RasterizerDummy::make_current(); + } bool keep_screen_on = bool(GLOBAL_GET("display/window/energy_saving/keep_screen_on")); screen_set_keep_on(keep_screen_on); @@ -196,8 +245,44 @@ DisplayServerIOS::~DisplayServerIOS() { #endif } +String DisplayServerIOS::get_readable_driver_name(const String &p_driver) const { + if (p_driver == "metal") { + return "Metal"; + } else if (p_driver == "vulkan") { + return "Vulkan (MoltenVK)"; + } else if (p_driver == "opengl3") { + return "OpenGLES 3.0"; + } else if (p_driver == "opengl3_angle") { + return "OpenGLES 3.0 (ANGLE)"; + } else if (p_driver == "dummy") { + return "Dummy"; + } else { + return p_driver; + } +} + DisplayServer *DisplayServerIOS::create_func(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Context p_context, int64_t p_parent_window, Error &r_error) { - return memnew(DisplayServerIOS(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_position, p_resolution, p_screen, p_context, p_parent_window, r_error)); + DisplayServerIOS *ds = memnew(DisplayServerIOS(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_position, p_resolution, p_screen, p_context, p_parent_window, r_error)); + if (r_error != OK) { + Vector names; + for (const String &driver : ds->tested_drivers) { + names.push_back(ds->get_readable_driver_name(driver)); + } + + if (!ds->tested_drivers.has("opengl3")) { + OS::get_singleton()->alert( + vformat("Your device seem not to support the required version of the following drivers:\n%s.\n\n" + "Please try exporting your game using the 'gl_compatibility' renderer.", + String(", ").join(names)), + "Unable to initialize video driver"); + } else { + OS::get_singleton()->alert( + vformat("Your device seem not to support the required version of the following drivers:\n%s.\n\n", + String(", ").join(names)), + "Unable to initialize video driver"); + } + } + return ds; } Vector DisplayServerIOS::get_rendering_drivers_func() { @@ -214,6 +299,7 @@ Vector DisplayServerIOS::get_rendering_drivers_func() { #if defined(GLES3_ENABLED) drivers.push_back("opengl3"); #endif + drivers.push_back("dummy"); return drivers; } diff --git a/platform/linuxbsd/wayland/display_server_wayland.cpp b/platform/linuxbsd/wayland/display_server_wayland.cpp index 5334446b224..94b20c4f475 100644 --- a/platform/linuxbsd/wayland/display_server_wayland.cpp +++ b/platform/linuxbsd/wayland/display_server_wayland.cpp @@ -50,6 +50,8 @@ #include "wayland/egl_manager_wayland_gles.h" #endif +#include "servers/rendering/dummy/rasterizer_dummy.h" + String DisplayServerWayland::_get_app_id_from_context(Context p_context) { String app_id; @@ -1381,17 +1383,53 @@ Vector DisplayServerWayland::get_rendering_drivers_func() { drivers.push_back("opengl3"); drivers.push_back("opengl3_es"); #endif + drivers.push_back("dummy"); return drivers; } -DisplayServer *DisplayServerWayland::create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Point2i *p_position, const Size2i &p_resolution, int p_screen, Context p_context, int64_t p_parent_window, Error &r_error) { - DisplayServer *ds = memnew(DisplayServerWayland(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_resolution, p_context, p_parent_window, r_error)); - if (r_error != OK) { - ERR_PRINT("Can't create the Wayland display server."); - memdelete(ds); +String DisplayServerWayland::get_readable_driver_name(const String &p_driver) const { + if (p_driver == "vulkan") { + return "Vulkan"; + } else if (p_driver == "opengl3") { + return "OpenGL 3.2"; + } else if (p_driver == "opengl3_es") { + return "OpenGLES 3.0"; + } else if (p_driver == "dummy") { + return "Dummy"; + } else { + return p_driver; + } +} - return nullptr; +DisplayServer *DisplayServerWayland::create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Point2i *p_position, const Size2i &p_resolution, int p_screen, Context p_context, int64_t p_parent_window, Error &r_error) { + DisplayServerWayland *ds = memnew(DisplayServerWayland(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_resolution, p_context, p_parent_window, r_error)); + if (r_error != OK) { + Vector names; + for (const String &driver : ds->tested_drivers) { + names.push_back(ds->get_readable_driver_name(driver)); + } + + if (!ds->tested_drivers.has("opengl3") && !ds->tested_drivers.has("opengl3_es")) { + String executable_command = vformat("\"%s\" --rendering-driver opengl3", OS::get_singleton()->get_executable_path()); + + OS::get_singleton()->alert( + vformat("Your video card drivers seem not to support the required version of the following drivers:\n%s.\n\n" + "If possible, consider updating your video card drivers or using the OpenGL 3 driver.\n" + "If you have recently updated your video card drivers, try rebooting.\n\n" + "You can enable the OpenGL 3 driver by starting the engine from the\n" + "command line with the command:\n\n %s", + String(", ").join(names), + executable_command), + "Unable to initialize video driver"); + } else { + OS::get_singleton()->alert( + vformat("Your video card drivers seem not to support the required version of the following drivers:\n%s.\n\n" + "If possible, consider updating your video card drivers\n" + "If you have recently updated your video card drivers, try rebooting.", + String(", ").join(names)), + "Unable to initialize video driver"); + } } return ds; } @@ -1427,165 +1465,152 @@ DisplayServerWayland::DisplayServerWayland(const String &p_rendering_driver, Win tts = memnew(TTS_Linux); #endif - rendering_driver = p_rendering_driver; - - bool driver_found = false; - String executable_name = OS::get_singleton()->get_executable_path().get_file(); - -#ifdef RD_ENABLED -#ifdef VULKAN_ENABLED - if (rendering_driver == "vulkan") { - rendering_context = memnew(RenderingContextDriverVulkanWayland); + Vector driver_list; + for (const String &drv : p_rendering_driver.split(",")) { + if (!driver_list.has(drv)) { + driver_list.push_back(drv); + } + } + if (GLOBAL_GET("rendering/renderer/fallback_to_opengl3").operator bool()) { + for (const String &drv : GLOBAL_GET("rendering/gl_compatibility/driver").operator String().split(",")) { + if (!driver_list.has(drv)) { + driver_list.push_back(drv); + } + } + } + if (GLOBAL_GET("rendering/renderer/fallback_to_dummy").operator bool()) { + if (!driver_list.has("dummy")) { + driver_list.push_back("dummy"); + } } -#endif // VULKAN_ENABLED - if (rendering_context) { - if (rendering_context->initialize() != OK) { + bool egl_dri_checked = false; + bool egl_found = true; + bool driver_found = false; + for (const String &driver : driver_list) { + print_line(vformat("Trying to initialize \"%s\" rendering driver.", get_readable_driver_name(driver))); + tested_drivers.push_back(driver); +#if defined(RD_ENABLED) +#if defined(VULKAN_ENABLED) + if (driver == "vulkan") { + rendering_context = memnew(RenderingContextDriverVulkanWayland); + if (rendering_context->initialize() == OK) { + rendering_driver = driver; + OS::get_singleton()->set_current_rendering_driver_name(rendering_driver); + driver_found = true; + break; + } memdelete(rendering_context); rendering_context = nullptr; -#if defined(GLES3_ENABLED) - bool fallback_to_opengl3 = GLOBAL_GET("rendering/rendering_device/fallback_to_opengl3"); - if (fallback_to_opengl3 && rendering_driver != "opengl3") { - WARN_PRINT("Your video card drivers seem not to support the required Vulkan version, switching to OpenGL 3."); - rendering_driver = "opengl3"; - OS::get_singleton()->set_current_rendering_method("gl_compatibility"); - OS::get_singleton()->set_current_rendering_driver_name(rendering_driver); - } else -#endif // GLES3_ENABLED - { - r_error = ERR_CANT_CREATE; - - if (p_rendering_driver == "vulkan") { - OS::get_singleton()->alert( - vformat("Your video card drivers seem not to support the required Vulkan version.\n\n" - "If possible, consider updating your video card drivers or using the OpenGL 3 driver.\n\n" - "You can enable the OpenGL 3 driver by starting the engine from the\n" - "command line with the command:\n\n \"%s\" --rendering-driver opengl3\n\n" - "If you recently updated your video card drivers, try rebooting.", - executable_name), - "Unable to initialize Vulkan video driver"); - } - - ERR_FAIL_MSG(vformat("Could not initialize %s", rendering_driver)); - } } - - driver_found = true; - } +#endif // VULKAN_ENABLED #endif // RD_ENABLED - -#ifdef GLES3_ENABLED - if (rendering_driver == "opengl3" || rendering_driver == "opengl3_es") { +#if defined(GLES3_ENABLED) + if (driver == "opengl3" || driver == "opengl3_es") { + if (!egl_dri_checked) { + egl_dri_checked = true; #ifdef SOWRAP_ENABLED - if (initialize_wayland_egl(dylibloader_verbose) != 0) { - WARN_PRINT("Can't load the Wayland EGL library."); - return; - } + if (initialize_wayland_egl(dylibloader_verbose) != 0) { + egl_found = false; + WARN_PRINT("Can't load the Wayland EGL library."); + continue; + } #endif // SOWRAP_ENABLED + if (getenv("DRI_PRIME") == nullptr) { + int prime_idx = -1; - if (getenv("DRI_PRIME") == nullptr) { - int prime_idx = -1; - - if (getenv("PRIMUS_DISPLAY") || - getenv("PRIMUS_libGLd") || - getenv("PRIMUS_libGLa") || - getenv("PRIMUS_libGL") || - getenv("PRIMUS_LOAD_GLOBAL") || - getenv("BUMBLEBEE_SOCKET") || - getenv("__NV_PRIME_RENDER_OFFLOAD")) { - print_verbose("Optirun/primusrun detected. Skipping GPU detection"); - prime_idx = 0; - } - - // Some tools use fake libGL libraries and have them override the real one using - // LD_LIBRARY_PATH, so we skip them. *But* Steam also sets LD_LIBRARY_PATH for its - // runtime and includes system `/lib` and `/lib64`... so ignore Steam. - if (prime_idx == -1 && getenv("LD_LIBRARY_PATH") && !getenv("STEAM_RUNTIME_LIBRARY_PATH")) { - String ld_library_path(getenv("LD_LIBRARY_PATH")); - Vector libraries = ld_library_path.split(":"); - - for (int i = 0; i < libraries.size(); ++i) { - if (FileAccess::exists(libraries[i] + "/libGL.so.1") || - FileAccess::exists(libraries[i] + "/libGL.so")) { - print_verbose("Custom libGL override detected. Skipping GPU detection"); + if (getenv("PRIMUS_DISPLAY") || + getenv("PRIMUS_libGLd") || + getenv("PRIMUS_libGLa") || + getenv("PRIMUS_libGL") || + getenv("PRIMUS_LOAD_GLOBAL") || + getenv("BUMBLEBEE_SOCKET") || + getenv("__NV_PRIME_RENDER_OFFLOAD")) { + print_verbose("Optirun/primusrun detected. Skipping GPU detection"); prime_idx = 0; } + + // Some tools use fake libGL libraries and have them override the real one using + // LD_LIBRARY_PATH, so we skip them. *But* Steam also sets LD_LIBRARY_PATH for its + // runtime and includes system `/lib` and `/lib64`... so ignore Steam. + if (prime_idx == -1 && getenv("LD_LIBRARY_PATH") && !getenv("STEAM_RUNTIME_LIBRARY_PATH")) { + String ld_library_path(getenv("LD_LIBRARY_PATH")); + Vector libraries = ld_library_path.split(":"); + + for (int i = 0; i < libraries.size(); ++i) { + if (FileAccess::exists(libraries[i] + "/libGL.so.1") || + FileAccess::exists(libraries[i] + "/libGL.so")) { + print_verbose("Custom libGL override detected. Skipping GPU detection"); + prime_idx = 0; + } + } + } + + if (prime_idx == -1) { + print_verbose("Detecting GPUs, set DRI_PRIME in the environment to override GPU detection logic."); + prime_idx = DetectPrimeEGL::detect_prime(EGL_PLATFORM_WAYLAND_KHR); + } + + if (prime_idx) { + print_line(vformat("Found discrete GPU, setting DRI_PRIME=%d to use it.", prime_idx)); + print_line("Note: Set DRI_PRIME=0 in the environment to disable Godot from using the discrete GPU."); + setenv("DRI_PRIME", itos(prime_idx).utf8().ptr(), 1); + } } } - - if (prime_idx == -1) { - print_verbose("Detecting GPUs, set DRI_PRIME in the environment to override GPU detection logic."); - prime_idx = DetectPrimeEGL::detect_prime(EGL_PLATFORM_WAYLAND_KHR); - } - - if (prime_idx) { - print_line(vformat("Found discrete GPU, setting DRI_PRIME=%d to use it.", prime_idx)); - print_line("Note: Set DRI_PRIME=0 in the environment to disable Godot from using the discrete GPU."); - setenv("DRI_PRIME", itos(prime_idx).utf8().ptr(), 1); - } } - - if (rendering_driver == "opengl3") { + if (egl_found && driver == "opengl3") { egl_manager = memnew(EGLManagerWayland); - - if (egl_manager->initialize(wayland_thread.get_wl_display()) != OK || egl_manager->open_display(wayland_thread.get_wl_display()) != OK) { - memdelete(egl_manager); - egl_manager = nullptr; - - 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"; - OS::get_singleton()->set_current_rendering_driver_name(rendering_driver); - } else { - r_error = ERR_UNAVAILABLE; - - OS::get_singleton()->alert( - vformat("Your video card drivers seem not to support the required OpenGL 3.3 version.\n\n" - "If possible, consider updating your video card drivers or using the Vulkan driver.\n\n" - "You can enable the Vulkan driver by starting the engine from the\n" - "command line with the command:\n\n \"%s\" --rendering-driver vulkan\n\n" - "If you recently updated your video card drivers, try rebooting.", - executable_name), - "Unable to initialize OpenGL video driver"); - - ERR_FAIL_MSG("Could not initialize OpenGL."); - } - } else { - RasterizerGLES3::make_current(true); + if (egl_manager->initialize(wayland_thread.get_wl_display()) == OK && egl_manager->open_display(wayland_thread.get_wl_display()) == OK) { + rendering_driver = driver; + OS::get_singleton()->set_current_rendering_method("gl_compatibility"); + OS::get_singleton()->set_current_rendering_driver_name(rendering_driver); driver_found = true; + break; } + memdelete(egl_manager); + egl_manager = nullptr; } - - if (rendering_driver == "opengl3_es") { + if (egl_found && driver == "opengl3_es") { egl_manager = memnew(EGLManagerWaylandGLES); - - if (egl_manager->initialize(wayland_thread.get_wl_display()) != OK || egl_manager->open_display(wayland_thread.get_wl_display()) != OK) { - memdelete(egl_manager); - egl_manager = nullptr; - r_error = ERR_CANT_CREATE; - - OS::get_singleton()->alert( - vformat("Your video card drivers seem not to support the required OpenGL ES 3.0 version.\n\n" - "If possible, consider updating your video card drivers or using the Vulkan driver.\n\n" - "You can enable the Vulkan driver by starting the engine from the\n" - "command line with the command:\n\n \"%s\" --rendering-driver vulkan\n\n" - "If you recently updated your video card drivers, try rebooting.", - executable_name), - "Unable to initialize OpenGL ES video driver"); - - ERR_FAIL_MSG("Could not initialize OpenGL ES."); + if (egl_manager->initialize(wayland_thread.get_wl_display()) == OK && egl_manager->open_display(wayland_thread.get_wl_display()) == OK) { + rendering_driver = driver; + OS::get_singleton()->set_current_rendering_method("gl_compatibility"); + OS::get_singleton()->set_current_rendering_driver_name(rendering_driver); + driver_found = true; + break; } - - RasterizerGLES3::make_current(false); - driver_found = true; + memdelete(egl_manager); + egl_manager = nullptr; } +#endif // GLES3_ENABLED + if (driver == "dummy") { + rendering_driver = driver; + OS::get_singleton()->set_current_rendering_method("gl_compatibility"); + OS::get_singleton()->set_current_rendering_driver_name(rendering_driver); + driver_found = true; + break; + } + print_line(vformat(" \"%s\" rendering driver initialization failed.", get_readable_driver_name(driver))); + } + + if (driver_found) { + print_line(vformat(" \"%s\" rendering driver initialized successfully.", get_readable_driver_name(rendering_driver))); + } else { + r_error = ERR_UNAVAILABLE; + ERR_FAIL_MSG("Could not initialize any of the rendering drivers."); + } + +#ifdef GLES3_ENABLED + if (rendering_driver == "opengl3") { + RasterizerGLES3::make_current(true); + } + if (rendering_driver == "opengl3_es") { + RasterizerGLES3::make_current(false); } #endif // GLES3_ENABLED - - if (!driver_found) { - r_error = ERR_UNAVAILABLE; - ERR_FAIL_MSG("Video driver not found."); + if (rendering_driver == "dummy") { + RasterizerDummy::make_current(); } cursor_set_shape(CURSOR_BUSY); diff --git a/platform/linuxbsd/wayland/display_server_wayland.h b/platform/linuxbsd/wayland/display_server_wayland.h index 4e21aea6a55..ceb9d5a4c1c 100644 --- a/platform/linuxbsd/wayland/display_server_wayland.h +++ b/platform/linuxbsd/wayland/display_server_wayland.h @@ -132,6 +132,7 @@ class DisplayServerWayland : public DisplayServer { bool emulate_vsync = false; String rendering_driver; + Vector tested_drivers; #ifdef RD_ENABLED RenderingContextDriver *rendering_context = nullptr; @@ -314,6 +315,8 @@ public: static void register_wayland_driver(); + String get_readable_driver_name(const String &p_driver) const override; + DisplayServerWayland(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Context p_context, int64_t p_parent_window, Error &r_error); ~DisplayServerWayland(); }; diff --git a/platform/linuxbsd/x11/display_server_x11.cpp b/platform/linuxbsd/x11/display_server_x11.cpp index 26c94bf25cf..50e057e8b9d 100644 --- a/platform/linuxbsd/x11/display_server_x11.cpp +++ b/platform/linuxbsd/x11/display_server_x11.cpp @@ -50,6 +50,8 @@ #include "drivers/gles3/rasterizer_gles3.h" #endif +#include "servers/rendering/dummy/rasterizer_dummy.h" + #include #include #include @@ -6030,12 +6032,54 @@ Vector DisplayServerX11::get_rendering_drivers_func() { drivers.push_back("opengl3"); drivers.push_back("opengl3_es"); #endif + drivers.push_back("dummy"); return drivers; } +String DisplayServerX11::get_readable_driver_name(const String &p_driver) const { + if (p_driver == "vulkan") { + return "Vulkan"; + } else if (p_driver == "opengl3") { + return "OpenGL 3.2"; + } else if (p_driver == "opengl3_es") { + return "OpenGLES 3.0"; + } else if (p_driver == "dummy") { + return "Dummy"; + } else { + return p_driver; + } +} + DisplayServer *DisplayServerX11::create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Context p_context, int64_t p_parent_window, Error &r_error) { - DisplayServer *ds = memnew(DisplayServerX11(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_position, p_resolution, p_screen, p_context, p_parent_window, r_error)); + DisplayServerX11 *ds = memnew(DisplayServerX11(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_position, p_resolution, p_screen, p_context, p_parent_window, r_error)); + if (r_error != OK) { + Vector names; + for (const String &driver : ds->tested_drivers) { + names.push_back(ds->get_readable_driver_name(driver)); + } + + if (!ds->tested_drivers.has("opengl3") && !ds->tested_drivers.has("opengl3_es")) { + String executable_command = vformat("\"%s\" --rendering-driver opengl3", OS::get_singleton()->get_executable_path()); + + OS::get_singleton()->alert( + vformat("Your video card drivers seem not to support the required version of the following drivers:\n%s.\n\n" + "If possible, consider updating your video card drivers or using the OpenGL 3 driver.\n" + "If you have recently updated your video card drivers, try rebooting.\n\n" + "You can enable the OpenGL 3 driver by starting the engine from the\n" + "command line with the command:\n\n %s", + String(", ").join(names), + executable_command), + "Unable to initialize video driver"); + } else { + OS::get_singleton()->alert( + vformat("Your video card drivers seem not to support the required version of the following drivers:\n%s.\n\n" + "If possible, consider updating your video card drivers\n" + "If you have recently updated your video card drivers, try rebooting.", + String(", ").join(names)), + "Unable to initialize video driver"); + } + } return ds; } @@ -6761,150 +6805,147 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode } #endif - //!!!!!!!!!!!!!!!!!!!!!!!!!! - //TODO - do Vulkan and OpenGL support checks, driver selection and fallback - rendering_driver = p_rendering_driver; - - bool driver_found = false; - String executable_name = OS::get_singleton()->get_executable_path().get_file(); - - // Initialize context and rendering device. - -#if defined(RD_ENABLED) -#if defined(VULKAN_ENABLED) - if (rendering_driver == "vulkan") { - rendering_context = memnew(RenderingContextDriverVulkanX11); + Vector driver_list; + for (const String &drv : p_rendering_driver.split(",")) { + if (!driver_list.has(drv)) { + driver_list.push_back(drv); + } } -#endif // VULKAN_ENABLED - - if (rendering_context) { - if (rendering_context->initialize() != OK) { - memdelete(rendering_context); - rendering_context = nullptr; -#if defined(GLES3_ENABLED) - bool fallback_to_opengl3 = GLOBAL_GET("rendering/rendering_device/fallback_to_opengl3"); - if (fallback_to_opengl3 && rendering_driver != "opengl3") { - WARN_PRINT("Your video card drivers seem not to support the required Vulkan version, switching to OpenGL 3."); - rendering_driver = "opengl3"; - OS::get_singleton()->set_current_rendering_method("gl_compatibility"); - OS::get_singleton()->set_current_rendering_driver_name(rendering_driver); - } else -#endif // GLES3_ENABLED - { - r_error = ERR_CANT_CREATE; - - if (p_rendering_driver == "vulkan") { - OS::get_singleton()->alert( - vformat("Your video card drivers seem not to support the required Vulkan version.\n\n" - "If possible, consider updating your video card drivers or using the OpenGL 3 driver.\n\n" - "You can enable the OpenGL 3 driver by starting the engine from the\n" - "command line with the command:\n\n \"%s\" --rendering-driver opengl3\n\n" - "If you recently updated your video card drivers, try rebooting.", - executable_name), - "Unable to initialize Vulkan video driver"); - } - - ERR_FAIL_MSG(vformat("Could not initialize %s", rendering_driver)); + if (GLOBAL_GET("rendering/renderer/fallback_to_opengl3").operator bool()) { + for (const String &drv : GLOBAL_GET("rendering/gl_compatibility/driver").operator String().split(",")) { + if (!driver_list.has(drv)) { + driver_list.push_back(drv); } } - driver_found = true; } -#endif // RD_ENABLED + if (GLOBAL_GET("rendering/renderer/fallback_to_dummy").operator bool()) { + if (!driver_list.has("dummy")) { + driver_list.push_back("dummy"); + } + } -#if defined(GLES3_ENABLED) - if (rendering_driver == "opengl3" || rendering_driver == "opengl3_es") { - if (getenv("DRI_PRIME") == nullptr) { - int use_prime = -1; - - if (getenv("PRIMUS_DISPLAY") || - getenv("PRIMUS_libGLd") || - getenv("PRIMUS_libGLa") || - getenv("PRIMUS_libGL") || - getenv("PRIMUS_LOAD_GLOBAL") || - getenv("BUMBLEBEE_SOCKET")) { - print_verbose("Optirun/primusrun detected. Skipping GPU detection"); - use_prime = 0; + bool egl_dri_checked = false; + bool driver_found = false; + for (const String &driver : driver_list) { + print_line(vformat("Trying to initialize \"%s\" rendering driver.", get_readable_driver_name(driver))); + tested_drivers.push_back(driver); +#if defined(RD_ENABLED) +#if defined(VULKAN_ENABLED) + if (driver == "vulkan") { + rendering_context = memnew(RenderingContextDriverVulkanX11); + if (rendering_context->initialize() == OK) { + rendering_driver = driver; + OS::get_singleton()->set_current_rendering_driver_name(rendering_driver); + driver_found = true; + break; } + memdelete(rendering_context); + rendering_context = nullptr; + } +#endif // VULKAN_ENABLED +#endif // RD_ENABLED +#if defined(GLES3_ENABLED) + if (driver == "opengl3" || driver == "opengl3_es") { + if (!egl_dri_checked) { + egl_dri_checked = true; + if (getenv("DRI_PRIME") == nullptr) { + int use_prime = -1; - // Some tools use fake libGL libraries and have them override the real one using - // LD_LIBRARY_PATH, so we skip them. *But* Steam also sets LD_LIBRARY_PATH for its - // runtime and includes system `/lib` and `/lib64`... so ignore Steam. - if (use_prime == -1 && getenv("LD_LIBRARY_PATH") && !getenv("STEAM_RUNTIME_LIBRARY_PATH")) { - String ld_library_path(getenv("LD_LIBRARY_PATH")); - Vector libraries = ld_library_path.split(":"); - - for (int i = 0; i < libraries.size(); ++i) { - if (FileAccess::exists(libraries[i] + "/libGL.so.1") || - FileAccess::exists(libraries[i] + "/libGL.so")) { - print_verbose("Custom libGL override detected. Skipping GPU detection"); + if (getenv("PRIMUS_DISPLAY") || + getenv("PRIMUS_libGLd") || + getenv("PRIMUS_libGLa") || + getenv("PRIMUS_libGL") || + getenv("PRIMUS_LOAD_GLOBAL") || + getenv("BUMBLEBEE_SOCKET")) { + print_verbose("Optirun/primusrun detected. Skipping GPU detection"); use_prime = 0; } + + // Some tools use fake libGL libraries and have them override the real one using + // LD_LIBRARY_PATH, so we skip them. *But* Steam also sets LD_LIBRARY_PATH for its + // runtime and includes system `/lib` and `/lib64`... so ignore Steam. + if (use_prime == -1 && getenv("LD_LIBRARY_PATH") && !getenv("STEAM_RUNTIME_LIBRARY_PATH")) { + String ld_library_path(getenv("LD_LIBRARY_PATH")); + Vector libraries = ld_library_path.split(":"); + + for (int i = 0; i < libraries.size(); ++i) { + if (FileAccess::exists(libraries[i] + "/libGL.so.1") || + FileAccess::exists(libraries[i] + "/libGL.so")) { + print_verbose("Custom libGL override detected. Skipping GPU detection"); + use_prime = 0; + } + } + } + + if (use_prime == -1) { + print_verbose("Detecting GPUs, set DRI_PRIME in the environment to override GPU detection logic."); + 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); + } } } - - if (use_prime == -1) { - print_verbose("Detecting GPUs, set DRI_PRIME in the environment to override GPU detection logic."); - 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); - } } - } - 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) { + if (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) { + rendering_driver = driver; + OS::get_singleton()->set_current_rendering_method("gl_compatibility"); + OS::get_singleton()->set_current_rendering_driver_name(rendering_driver); + driver_found = true; + break; + } memdelete(gl_manager); gl_manager = nullptr; - 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"; - OS::get_singleton()->set_current_rendering_driver_name(rendering_driver); - } else { - r_error = ERR_UNAVAILABLE; - - OS::get_singleton()->alert( - vformat("Your video card drivers seem not to support the required OpenGL 3.3 version.\n\n" - "If possible, consider updating your video card drivers or using the Vulkan driver.\n\n" - "You can enable the Vulkan driver by starting the engine from the\n" - "command line with the command:\n\n \"%s\" --rendering-driver vulkan\n\n" - "If you recently updated your video card drivers, try rebooting.", - executable_name), - "Unable to initialize OpenGL video driver"); - - ERR_FAIL_MSG("Could not initialize OpenGL."); - } - } else { - driver_found = true; - RasterizerGLES3::make_current(true); } + if (driver == "opengl3_es") { + gl_manager_egl = memnew(GLManagerEGL_X11); + if (gl_manager_egl->initialize() == OK && gl_manager_egl->open_display(x11_display) == OK) { + rendering_driver = driver; + OS::get_singleton()->set_current_rendering_method("gl_compatibility"); + OS::get_singleton()->set_current_rendering_driver_name(rendering_driver); + driver_found = true; + break; + } + memdelete(gl_manager); + gl_manager = nullptr; + } +#endif // GLES3_ENABLED + if (driver == "dummy") { + rendering_driver = driver; + OS::get_singleton()->set_current_rendering_method("gl_compatibility"); + OS::get_singleton()->set_current_rendering_driver_name(rendering_driver); + driver_found = true; + break; + } + print_line(vformat(" \"%s\" rendering driver initialization failed.", get_readable_driver_name(driver))); + } + + if (driver_found) { + print_line(vformat(" \"%s\" rendering driver initialized successfully.", get_readable_driver_name(rendering_driver))); + } else { + r_error = ERR_UNAVAILABLE; + ERR_FAIL_MSG("Could not initialize any of the rendering drivers."); + } + +#if defined(GLES3_ENABLED) + if (rendering_driver == "opengl3") { + RasterizerGLES3::make_current(true); } if (rendering_driver == "opengl3_es") { - gl_manager_egl = memnew(GLManagerEGL_X11); - if (gl_manager_egl->initialize() != OK || gl_manager_egl->open_display(x11_display) != OK) { - memdelete(gl_manager_egl); - gl_manager_egl = nullptr; - r_error = ERR_UNAVAILABLE; - - OS::get_singleton()->alert( - "Your video card drivers seem not to support the required OpenGL ES 3.0 version.\n\n" - "If possible, consider updating your video card drivers.\n\n" - "If you recently updated your video card drivers, try rebooting.", - "Unable to initialize OpenGL ES video driver"); - - ERR_FAIL_MSG("Could not initialize OpenGL ES."); - } - driver_found = true; RasterizerGLES3::make_current(false); } - #endif // GLES3_ENABLED + if (rendering_driver == "dummy") { + RasterizerDummy::make_current(); + } + if (!driver_found) { r_error = ERR_UNAVAILABLE; ERR_FAIL_MSG("Video driver not found."); diff --git a/platform/linuxbsd/x11/display_server_x11.h b/platform/linuxbsd/x11/display_server_x11.h index b21d9024627..fee68888b89 100644 --- a/platform/linuxbsd/x11/display_server_x11.h +++ b/platform/linuxbsd/x11/display_server_x11.h @@ -326,6 +326,8 @@ class DisplayServerX11 : public DisplayServer { HashMap> cursors_cache; String rendering_driver; + Vector tested_drivers; + void set_wm_fullscreen(bool p_enabled); void set_wm_above(bool p_enabled); @@ -573,6 +575,8 @@ public: static void register_x11_driver(); + String get_readable_driver_name(const String &p_driver) const override; + DisplayServerX11(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Context p_context, int64_t p_parent_window, Error &r_error); ~DisplayServerX11(); }; diff --git a/platform/macos/display_server_macos.h b/platform/macos/display_server_macos.h index eb536f9894c..61e8cb1c3a8 100644 --- a/platform/macos/display_server_macos.h +++ b/platform/macos/display_server_macos.h @@ -148,6 +148,7 @@ private: RenderingDevice *rendering_device = nullptr; #endif String rendering_driver; + Vector tested_drivers; struct WarpEvent { NSTimeInterval timestamp; @@ -464,6 +465,8 @@ public: static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Context p_context, int64_t p_parent_window, Error &r_error); static Vector get_rendering_drivers_func(); + String get_readable_driver_name(const String &p_driver) const override; + static void register_macos_driver(); DisplayServerMacOS(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Context p_context, int64_t p_parent_window, Error &r_error); diff --git a/platform/macos/display_server_macos.mm b/platform/macos/display_server_macos.mm index 556c4c966ef..36267f05299 100644 --- a/platform/macos/display_server_macos.mm +++ b/platform/macos/display_server_macos.mm @@ -60,6 +60,8 @@ #include "servers/rendering/renderer_rd/renderer_compositor_rd.h" #endif +#include "servers/rendering/dummy/rasterizer_dummy.h" + #import #import #import @@ -3462,10 +3464,31 @@ bool DisplayServerMacOS::is_window_transparency_available() const { return OS::get_singleton()->is_layered_allowed(); } +String DisplayServerMacOS::get_readable_driver_name(const String &p_driver) const { + if (p_driver == "metal") { + return "Metal"; + } else if (p_driver == "vulkan") { + return "Vulkan (MoltenVK)"; + } else if (p_driver == "opengl3") { + return "OpenGL 3.2"; + } else if (p_driver == "opengl3_angle") { + return "OpenGLES 3.0 (ANGLE)"; + } else if (p_driver == "dummy") { + return "Dummy"; + } else { + return p_driver; + } +} + DisplayServer *DisplayServerMacOS::create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Context p_context, int64_t p_parent_window, Error &r_error) { - DisplayServer *ds = memnew(DisplayServerMacOS(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_position, p_resolution, p_screen, p_context, p_parent_window, r_error)); + DisplayServerMacOS *ds = memnew(DisplayServerMacOS(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_position, p_resolution, p_screen, p_context, p_parent_window, r_error)); if (r_error != OK) { - if (p_rendering_driver == "vulkan") { + Vector names; + for (const String &driver : ds->tested_drivers) { + names.push_back(ds->get_readable_driver_name(driver)); + } + + if (!ds->tested_drivers.has("opengl3") && !ds->tested_drivers.has("opengl3_angle")) { String executable_command; if (OS::get_singleton()->get_bundle_resource_dir() == OS::get_singleton()->get_executable_path().get_base_dir()) { executable_command = vformat("\"%s\" --rendering-driver opengl3", OS::get_singleton()->get_executable_path()); @@ -3473,17 +3496,19 @@ DisplayServer *DisplayServerMacOS::create_func(const String &p_rendering_driver, executable_command = vformat("open \"%s\" --args --rendering-driver opengl3", OS::get_singleton()->get_bundle_resource_dir().path_join("../..").simplify_path()); } OS::get_singleton()->alert( - vformat("Your video card drivers seem not to support the required Vulkan version.\n\n" + vformat("Your video card drivers seem not to support the required version of the following drivers:\n%s.\n\n" "If possible, consider updating your macOS version or using the OpenGL 3 driver.\n\n" "You can enable the OpenGL 3 driver by starting the engine from the\n" "command line with the command:\n\n %s", + String(", ").join(names), executable_command), - "Unable to initialize Vulkan video driver"); + "Unable to initialize video driver"); } else { OS::get_singleton()->alert( - "Your video card drivers seem not to support the required OpenGL 3.3 version.\n\n" - "If possible, consider updating your macOS version.", - "Unable to initialize OpenGL video driver"); + vformat("Your video card drivers seem not to support the required version of the following drivers:\n%s.\n\n" + "If possible, consider updating your macOS version.", + String(", ").join(names)), + "Unable to initialize video driver"); } } return ds; @@ -3502,6 +3527,7 @@ Vector DisplayServerMacOS::get_rendering_drivers_func() { drivers.push_back("opengl3"); drivers.push_back("opengl3_angle"); #endif + drivers.push_back("dummy"); return drivers; } @@ -3783,86 +3809,99 @@ DisplayServerMacOS::DisplayServerMacOS(const String &p_rendering_driver, WindowM native_menu->_register_system_menus(main_menu, application_menu, window_menu, help_menu, dock_menu); - //!!!!!!!!!!!!!!!!!!!!!!!!!! - //TODO - do Vulkan and OpenGL support checks, driver selection and fallback - rendering_driver = p_rendering_driver; + Vector driver_list; + for (const String &drv : p_rendering_driver.split(",")) { + if (!driver_list.has(drv)) { + driver_list.push_back(drv); + } + } + if (GLOBAL_GET("rendering/renderer/fallback_to_opengl3").operator bool()) { + for (const String &drv : GLOBAL_GET("rendering/gl_compatibility/driver").operator String().split(",")) { + if (!driver_list.has(drv)) { + driver_list.push_back(drv); + } + } + } + if (GLOBAL_GET("rendering/renderer/fallback_to_dummy").operator bool()) { + if (!driver_list.has("dummy")) { + driver_list.push_back("dummy"); + } + } + bool driver_found = false; + for (const String &driver : driver_list) { + print_line(vformat("Trying to initialize \"%s\" rendering driver.", get_readable_driver_name(driver))); + tested_drivers.push_back(driver); #if defined(RD_ENABLED) -#if defined(VULKAN_ENABLED) -#if defined(__x86_64__) - bool fallback_to_vulkan = GLOBAL_GET("rendering/rendering_device/fallback_to_vulkan"); - if (!fallback_to_vulkan) { - WARN_PRINT("Metal is not supported on Intel Macs, switching to Vulkan."); - } - // Metal rendering driver not available on Intel. - if (rendering_driver == "metal") { - rendering_driver = "vulkan"; - OS::get_singleton()->set_current_rendering_driver_name(rendering_driver); - } -#endif - if (rendering_driver == "vulkan") { - rendering_context = memnew(RenderingContextDriverVulkanMacOS); - } -#endif #if defined(METAL_ENABLED) - if (rendering_driver == "metal") { - rendering_context = memnew(RenderingContextDriverMetal); - } -#endif - - if (rendering_context) { - if (rendering_context->initialize() != OK) { + if (driver == "metal") { + rendering_context = memnew(RenderingContextDriverMetal); + if (rendering_context->initialize() == OK) { + rendering_driver = driver; + OS::get_singleton()->set_current_rendering_driver_name(rendering_driver); + driver_found = true; + break; + } memdelete(rendering_context); rendering_context = nullptr; + } +#endif // METAL_ENABLED +#if defined(VULKAN_ENABLED) + if (driver == "vulkan") { + rendering_context = memnew(RenderingContextDriverVulkanMacOS); + if (rendering_context->initialize() == OK) { + rendering_driver = driver; + OS::get_singleton()->set_current_rendering_driver_name(rendering_driver); + driver_found = true; + break; + } + memdelete(rendering_context); + rendering_context = nullptr; + } +#endif // VULKAN_ENABLED +#endif // RD_ENABLED #if defined(GLES3_ENABLED) - bool fallback_to_opengl3 = GLOBAL_GET("rendering/rendering_device/fallback_to_opengl3"); - if (fallback_to_opengl3 && rendering_driver != "opengl3") { - WARN_PRINT("Your device seem not to support MoltenVK or Metal, switching to OpenGL 3."); - rendering_driver = "opengl3"; + if (driver == "opengl3") { + gl_manager_legacy = memnew(GLManagerLegacy_MacOS); + if (gl_manager_legacy->initialize() == OK) { + rendering_driver = driver; OS::get_singleton()->set_current_rendering_method("gl_compatibility"); OS::get_singleton()->set_current_rendering_driver_name(rendering_driver); - } else -#endif - { - r_error = ERR_CANT_CREATE; - ERR_FAIL_MSG("Could not initialize " + rendering_driver); + driver_found = true; + break; } - } - } -#endif - -#if defined(GLES3_ENABLED) - if (rendering_driver == "opengl3_angle") { - gl_manager_angle = memnew(GLManagerANGLE_MacOS); - if (gl_manager_angle->initialize() != OK || gl_manager_angle->open_display(nullptr) != OK) { - memdelete(gl_manager_angle); - gl_manager_angle = nullptr; - bool fallback = GLOBAL_GET("rendering/gl_compatibility/fallback_to_native"); - if (fallback) { -#ifdef EGL_STATIC - WARN_PRINT("Your video card drivers seem not to support GLES3 / ANGLE, switching to native OpenGL."); -#else - WARN_PRINT("Your video card drivers seem not to support GLES3 / ANGLE or ANGLE dynamic libraries (libEGL.dylib and libGLESv2.dylib) are missing, switching to native OpenGL."); -#endif - rendering_driver = "opengl3"; - OS::get_singleton()->set_current_rendering_driver_name(rendering_driver); - } else { - r_error = ERR_UNAVAILABLE; - ERR_FAIL_MSG("Could not initialize ANGLE OpenGL."); - } - } - } - - if (rendering_driver == "opengl3") { - gl_manager_legacy = memnew(GLManagerLegacy_MacOS); - if (gl_manager_legacy->initialize() != OK) { memdelete(gl_manager_legacy); gl_manager_legacy = nullptr; - r_error = ERR_UNAVAILABLE; - ERR_FAIL_MSG("Could not initialize native OpenGL."); } + if (driver == "opengl3_angle") { + gl_manager_angle = memnew(GLManagerANGLE_MacOS); + if (gl_manager_angle->initialize() == OK && gl_manager_angle->open_display(nullptr) == OK) { + rendering_driver = driver; + OS::get_singleton()->set_current_rendering_method("gl_compatibility"); + OS::get_singleton()->set_current_rendering_driver_name(rendering_driver); + driver_found = true; + break; + } + memdelete(gl_manager_angle); + gl_manager_angle = nullptr; + } +#endif // GLES3_ENABLED + if (driver == "dummy") { + rendering_driver = driver; + OS::get_singleton()->set_current_rendering_method("gl_compatibility"); + OS::get_singleton()->set_current_rendering_driver_name(rendering_driver); + driver_found = true; + break; + } + print_line(vformat(" \"%s\" rendering driver initialization failed.", get_readable_driver_name(driver))); + } + + if (driver_found) { + print_line(vformat(" \"%s\" rendering driver initialized successfully.", get_readable_driver_name(rendering_driver))); + } else { + r_error = ERR_UNAVAILABLE; + ERR_FAIL_MSG("Could not initialize any of the rendering drivers."); } -#endif Point2i window_position; if (p_position != nullptr) { @@ -3902,6 +3941,9 @@ DisplayServerMacOS::DisplayServerMacOS(const String &p_rendering_driver, WindowM RendererCompositorRD::make_current(); } #endif + if (rendering_driver == "dummy") { + RasterizerDummy::make_current(); + } screen_set_keep_on(GLOBAL_GET("display/window/energy_saving/keep_screen_on")); } diff --git a/platform/web/display_server_web.cpp b/platform/web/display_server_web.cpp index 180c05ef411..331f3d2ebcd 100644 --- a/platform/web/display_server_web.cpp +++ b/platform/web/display_server_web.cpp @@ -975,6 +975,8 @@ Vector DisplayServerWeb::get_rendering_drivers_func() { #ifdef GLES3_ENABLED drivers.push_back("opengl3"); #endif + drivers.push_back("dummy"); + return drivers; } @@ -1079,8 +1081,32 @@ void DisplayServerWeb::_dispatch_input_event(const Ref &p_event) { } } +String DisplayServerWeb::get_readable_driver_name(const String &p_driver) const { + if (p_driver == "opengl3") { + return "WebGL 2.0"; + } else if (p_driver == "dummy") { + return "Dummy"; + } else { + return p_driver; + } +} + DisplayServer *DisplayServerWeb::create_func(const String &p_rendering_driver, WindowMode p_window_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Point2i *p_position, const Size2i &p_resolution, int p_screen, Context p_context, int64_t p_parent_window, Error &r_error) { - return memnew(DisplayServerWeb(p_rendering_driver, p_window_mode, p_vsync_mode, p_flags, p_position, p_resolution, p_screen, p_context, p_parent_window, r_error)); + DisplayServerWeb *ds = memnew(DisplayServerWeb(p_rendering_driver, p_window_mode, p_vsync_mode, p_flags, p_position, p_resolution, p_screen, p_context, p_parent_window, r_error)); + if (r_error != OK) { + Vector names; + for (const String &driver : ds->tested_drivers) { + names.push_back(ds->get_readable_driver_name(driver)); + } + + OS::get_singleton()->alert( + vformat("Your browser seem not to support the required version of the following drivers:\n%s.\n\n" + "If possible, consider updating your browser version and video card drivers.\n" + "If you have recently updated your video card drivers, try rebooting.", + String(", ").join(names)), + "Unable to initialize video driver"); + } + return ds; } DisplayServerWeb::DisplayServerWeb(const String &p_rendering_driver, WindowMode p_window_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Point2i *p_position, const Size2i &p_resolution, int p_screen, Context p_context, int64_t p_parent_window, Error &r_error) { @@ -1101,35 +1127,77 @@ DisplayServerWeb::DisplayServerWeb(const String &p_rendering_driver, WindowMode // Expose method for requesting quit. godot_js_os_request_quit_cb(request_quit_callback); -#ifdef GLES3_ENABLED - bool webgl2_inited = false; - if (godot_js_display_has_webgl(2)) { - EmscriptenWebGLContextAttributes attributes; - emscripten_webgl_init_context_attributes(&attributes); - attributes.alpha = OS::get_singleton()->is_layered_allowed(); - attributes.antialias = false; - attributes.majorVersion = 2; - attributes.explicitSwapControl = true; - - webgl_ctx = emscripten_webgl_create_context(canvas_id, &attributes); - webgl2_inited = webgl_ctx && emscripten_webgl_make_context_current(webgl_ctx) == EMSCRIPTEN_RESULT_SUCCESS; - } - if (webgl2_inited) { - if (!emscripten_webgl_enable_extension(webgl_ctx, "OVR_multiview2")) { - print_verbose("Failed to enable WebXR extension."); + Vector driver_list; + for (const String &drv : p_rendering_driver.split(",")) { + if (!driver_list.has(drv)) { + driver_list.push_back(drv); } - RasterizerGLES3::make_current(false); + } + if (GLOBAL_GET("rendering/renderer/fallback_to_opengl3").operator bool()) { + for (const String &drv : GLOBAL_GET("rendering/gl_compatibility/driver").operator String().split(",")) { + if (!driver_list.has(drv)) { + driver_list.push_back(drv); + } + } + } + if (GLOBAL_GET("rendering/renderer/fallback_to_dummy").operator bool()) { + if (!driver_list.has("dummy")) { + driver_list.push_back("dummy"); + } + } + bool driver_found = false; + for (const String &driver : driver_list) { + print_line(vformat("Trying to initialize \"%s\" rendering driver.", get_readable_driver_name(driver))); + tested_drivers.push_back(driver); +#if defined(GLES3_ENABLED) + if (driver == "opengl3") { + bool webgl2_inited = false; + if (godot_js_display_has_webgl(2)) { + EmscriptenWebGLContextAttributes attributes; + emscripten_webgl_init_context_attributes(&attributes); + attributes.alpha = OS::get_singleton()->is_layered_allowed(); + attributes.antialias = false; + attributes.majorVersion = 2; + attributes.explicitSwapControl = true; + + webgl_ctx = emscripten_webgl_create_context(canvas_id, &attributes); + webgl2_inited = webgl_ctx && emscripten_webgl_make_context_current(webgl_ctx) == EMSCRIPTEN_RESULT_SUCCESS; + } + if (webgl2_inited) { + rendering_driver = driver; + OS::get_singleton()->set_current_rendering_method("gl_compatibility"); + OS::get_singleton()->set_current_rendering_driver_name(rendering_driver); + driver_found = true; + break; + } + } +#endif // GLES3_ENABLED + if (driver == "dummy") { + rendering_driver = driver; + OS::get_singleton()->set_current_rendering_method("gl_compatibility"); + OS::get_singleton()->set_current_rendering_driver_name(rendering_driver); + driver_found = true; + break; + } + print_line(vformat(" \"%s\" rendering driver initialization failed.", get_readable_driver_name(driver))); + } + + if (driver_found) { + print_line(vformat(" \"%s\" rendering driver initialized successfully.", get_readable_driver_name(rendering_driver))); } else { - OS::get_singleton()->alert( - "Your browser seems not to support WebGL 2.\n\n" - "If possible, consider updating your browser version and video card drivers.", - "Unable to initialize WebGL 2 video driver"); + r_error = ERR_UNAVAILABLE; + ERR_FAIL_MSG("Could not initialize any of the rendering drivers."); + } + +#ifdef GLES3_ENABLED + if (rendering_driver == "opengl3") { + RasterizerGLES3::make_current(false); + } +#endif + if (rendering_driver == "dummy") { RasterizerDummy::make_current(); } -#else - RasterizerDummy::make_current(); -#endif // JS Input interface (js/libs/library_godot_input.js) godot_js_input_mouse_button_cb(&DisplayServerWeb::mouse_button_callback); diff --git a/platform/web/display_server_web.h b/platform/web/display_server_web.h index 2d0d13c19a3..b80670a08bf 100644 --- a/platform/web/display_server_web.h +++ b/platform/web/display_server_web.h @@ -152,6 +152,9 @@ private: void process_joypads(); void process_keys(); + String rendering_driver; + Vector tested_drivers; + static Vector get_rendering_drivers_func(); static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_window_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Context p_context, int64_t p_parent_window, Error &r_error); @@ -289,6 +292,8 @@ public: virtual bool get_swap_cancel_ok() override; virtual void swap_buffers() override; + String get_readable_driver_name(const String &p_driver) const override; + static void register_web_driver(); DisplayServerWeb(const String &p_rendering_driver, WindowMode p_window_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Point2i *p_position, const Size2i &p_resolution, int p_screen, Context p_context, int64_t p_parent_window, Error &r_error); ~DisplayServerWeb(); diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index 20b9236e462..fce6364e483 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -51,6 +51,7 @@ #if defined(GLES3_ENABLED) #include "drivers/gles3/rasterizer_gles3.h" #endif +#include "servers/rendering/dummy/rasterizer_dummy.h" #include #include @@ -6415,8 +6416,6 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode, return id; } -BitField DisplayServerWindows::tested_drivers = 0; - // WinTab API. bool DisplayServerWindows::wintab_available = false; WTOpenPtr DisplayServerWindows::wintab_WTOpen = nullptr; @@ -6785,180 +6784,132 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win _register_raw_input_devices(INVALID_WINDOW_ID); + Vector driver_list; + for (const String &drv : p_rendering_driver.split(",")) { + if (!driver_list.has(drv)) { + driver_list.push_back(drv); + } + } + if (GLOBAL_GET("rendering/renderer/fallback_to_opengl3").operator bool()) { + for (const String &drv : GLOBAL_GET("rendering/gl_compatibility/driver").operator String().split(",")) { + if (!driver_list.has(drv)) { + driver_list.push_back(drv); + } + } + } + if (GLOBAL_GET("rendering/renderer/fallback_to_dummy").operator bool()) { + if (!driver_list.has("dummy")) { + driver_list.push_back("dummy"); + } + } + + bool gl_support_checked = false; + bool force_angle = false; + bool driver_found = false; + for (const String &driver : driver_list) { + print_line(vformat("Trying to initialize \"%s\" rendering driver.", get_readable_driver_name(driver))); + tested_drivers.push_back(driver); #if defined(RD_ENABLED) - [[maybe_unused]] bool fallback_to_vulkan = GLOBAL_GET("rendering/rendering_device/fallback_to_vulkan"); - [[maybe_unused]] bool fallback_to_d3d12 = GLOBAL_GET("rendering/rendering_device/fallback_to_d3d12"); - -#if defined(VULKAN_ENABLED) - if (rendering_driver == "vulkan") { - rendering_context = memnew(RenderingContextDriverVulkanWindows); - tested_drivers.set_flag(DRIVER_ID_RD_VULKAN); - } -#else - fallback_to_d3d12 = true; // Always enable fallback if engine was built w/o other driver support. -#endif #if defined(D3D12_ENABLED) - if (rendering_driver == "d3d12") { - rendering_context = memnew(RenderingContextDriverD3D12); - tested_drivers.set_flag(DRIVER_ID_RD_D3D12); - } -#else - fallback_to_vulkan = true; // Always enable fallback if engine was built w/o other driver support. -#endif - - if (rendering_context) { - if (rendering_context->initialize() != OK) { - bool failed = true; + if (driver == "d3d12") { + rendering_context = memnew(RenderingContextDriverD3D12); + if (rendering_context->initialize() == OK) { + rendering_driver = driver; + OS::get_singleton()->set_current_rendering_driver_name(rendering_driver); + driver_found = true; + break; + } + memdelete(rendering_context); + rendering_context = nullptr; + } +#endif // METAL_ENABLED #if defined(VULKAN_ENABLED) - if (failed && fallback_to_vulkan && rendering_driver != "vulkan") { - memdelete(rendering_context); - rendering_context = memnew(RenderingContextDriverVulkanWindows); - tested_drivers.set_flag(DRIVER_ID_RD_VULKAN); - if (rendering_context->initialize() == OK) { - WARN_PRINT("Your video card drivers seem not to support Direct3D 12, switching to Vulkan."); - rendering_driver = "vulkan"; - OS::get_singleton()->set_current_rendering_driver_name(rendering_driver); - failed = false; - } + if (driver == "vulkan") { + rendering_context = memnew(RenderingContextDriverVulkanWindows); + if (rendering_context->initialize() == OK) { + rendering_driver = driver; + OS::get_singleton()->set_current_rendering_driver_name(rendering_driver); + driver_found = true; + break; } -#endif -#if defined(D3D12_ENABLED) - if (failed && fallback_to_d3d12 && rendering_driver != "d3d12") { - memdelete(rendering_context); - rendering_context = memnew(RenderingContextDriverD3D12); - tested_drivers.set_flag(DRIVER_ID_RD_D3D12); - if (rendering_context->initialize() == OK) { - WARN_PRINT("Your video card drivers seem not to support Vulkan, switching to Direct3D 12."); - rendering_driver = "d3d12"; - OS::get_singleton()->set_current_rendering_driver_name(rendering_driver); - failed = false; - } - } -#endif + memdelete(rendering_context); + rendering_context = nullptr; + } +#endif // VULKAN_ENABLED +#endif // RD_ENABLED #if defined(GLES3_ENABLED) - bool fallback_to_opengl3 = GLOBAL_GET("rendering/rendering_device/fallback_to_opengl3"); - if (failed && fallback_to_opengl3 && rendering_driver != "opengl3") { - memdelete(rendering_context); - rendering_context = nullptr; - tested_drivers.set_flag(DRIVER_ID_COMPAT_OPENGL3); - WARN_PRINT("Your video card drivers seem not to support Direct3D 12 or Vulkan, switching to OpenGL 3."); - rendering_driver = "opengl3"; + if (driver == "opengl3" || driver == "opengl3_angle") { + if (!gl_support_checked) { + gl_support_checked = true; + + Dictionary gl_info = detect_wgl(); + if (gl_info["version"].operator int() >= 30003) { + Vector2i device_id = _get_device_ids(gl_info["name"]); + Array device_list = GLOBAL_GET("rendering/gl_compatibility/force_angle_on_devices"); + for (int i = 0; i < device_list.size(); i++) { + const Dictionary &device = device_list[i]; + if (device.has("vendor") && device.has("name")) { + const String &vendor = device["vendor"]; + const String &name = device["name"]; + if (device_id != Vector2i() && vendor.begins_with("0x") && name.begins_with("0x") && device_id.x == vendor.lstrip("0x").hex_to_int() && device_id.y == name.lstrip("0x").hex_to_int()) { + // Check vendor/device IDs. + force_angle = true; + break; + } else if (gl_info["vendor"].operator String().to_upper().contains(vendor.to_upper()) && (name == "*" || gl_info["name"].operator String().to_upper().contains(name.to_upper()))) { + // Check vendor/device names. + force_angle = true; + break; + } + } + } + } else { + force_angle = true; + } + } + } + if (!force_angle && driver == "opengl3") { + gl_manager_native = memnew(GLManagerNative_Windows); + if (gl_manager_native->initialize() == OK) { + rendering_driver = driver; OS::get_singleton()->set_current_rendering_method("gl_compatibility"); OS::get_singleton()->set_current_rendering_driver_name(rendering_driver); - failed = false; + driver_found = true; + break; } -#endif - if (failed) { - memdelete(rendering_context); - rendering_context = nullptr; - r_error = ERR_UNAVAILABLE; - return; - } - } - } -#endif -// Init context and rendering device -#if defined(GLES3_ENABLED) - - bool fallback = GLOBAL_GET("rendering/gl_compatibility/fallback_to_angle"); - bool show_warning = true; - - if (rendering_driver == "opengl3") { - // There's no native OpenGL drivers on Windows for ARM, always enable fallback. -#if defined(__arm__) || defined(__aarch64__) || defined(_M_ARM) || defined(_M_ARM64) - fallback = true; - show_warning = false; -#else - typedef BOOL(WINAPI * IsWow64Process2Ptr)(HANDLE, USHORT *, USHORT *); - - IsWow64Process2Ptr IsWow64Process2 = (IsWow64Process2Ptr)(void *)GetProcAddress(GetModuleHandle(TEXT("kernel32")), "IsWow64Process2"); - if (IsWow64Process2) { - USHORT process_arch = 0; - USHORT machine_arch = 0; - if (!IsWow64Process2(GetCurrentProcess(), &process_arch, &machine_arch)) { - machine_arch = 0; - } - if (machine_arch == 0xAA64) { - fallback = true; - show_warning = false; - } - } -#endif - } - - bool gl_supported = true; - if (fallback && (rendering_driver == "opengl3")) { - Dictionary gl_info = detect_wgl(); - - bool force_angle = false; - gl_supported = gl_info["version"].operator int() >= 30003; - - Vector2i device_id = _get_device_ids(gl_info["name"]); - Array device_list = GLOBAL_GET("rendering/gl_compatibility/force_angle_on_devices"); - for (int i = 0; i < device_list.size(); i++) { - const Dictionary &device = device_list[i]; - if (device.has("vendor") && device.has("name")) { - const String &vendor = device["vendor"]; - const String &name = device["name"]; - if (device_id != Vector2i() && vendor.begins_with("0x") && name.begins_with("0x") && device_id.x == vendor.lstrip("0x").hex_to_int() && device_id.y == name.lstrip("0x").hex_to_int()) { - // Check vendor/device IDs. - force_angle = true; - break; - } else if (gl_info["vendor"].operator String().to_upper().contains(vendor.to_upper()) && (name == "*" || gl_info["name"].operator String().to_upper().contains(name.to_upper()))) { - // Check vendor/device names. - force_angle = true; - break; - } - } - } - - if (force_angle || (gl_info["version"].operator int() < 30003)) { - tested_drivers.set_flag(DRIVER_ID_COMPAT_OPENGL3); - if (show_warning) { - if (gl_info["version"].operator int() < 30003) { - WARN_PRINT("Your video card drivers seem not to support the required OpenGL 3.3 version, switching to ANGLE."); - } else { - WARN_PRINT("Your video card drivers are known to have low quality OpenGL 3.3 support, switching to ANGLE."); - } - } - rendering_driver = "opengl3_angle"; - OS::get_singleton()->set_current_rendering_driver_name(rendering_driver); - } - } - - if (rendering_driver == "opengl3_angle") { - gl_manager_angle = memnew(GLManagerANGLE_Windows); - tested_drivers.set_flag(DRIVER_ID_COMPAT_ANGLE_D3D11); - - if (gl_manager_angle->initialize() != OK) { - memdelete(gl_manager_angle); - gl_manager_angle = nullptr; - bool fallback_to_native = GLOBAL_GET("rendering/gl_compatibility/fallback_to_native"); - if (fallback_to_native && gl_supported) { -#ifdef EGL_STATIC - WARN_PRINT("Your video card drivers seem not to support GLES3 / ANGLE, switching to native OpenGL."); -#else - WARN_PRINT("Your video card drivers seem not to support GLES3 / ANGLE or ANGLE dynamic libraries (libEGL.dll and libGLESv2.dll) are missing, switching to native OpenGL."); -#endif - rendering_driver = "opengl3"; - } else { - r_error = ERR_UNAVAILABLE; - ERR_FAIL_MSG("Could not initialize ANGLE OpenGL."); - } - } - } - if (rendering_driver == "opengl3") { - gl_manager_native = memnew(GLManagerNative_Windows); - tested_drivers.set_flag(DRIVER_ID_COMPAT_OPENGL3); - - if (gl_manager_native->initialize() != OK) { memdelete(gl_manager_native); gl_manager_native = nullptr; - r_error = ERR_UNAVAILABLE; - ERR_FAIL_MSG("Could not initialize native OpenGL."); } + if (force_angle || driver == "opengl3_angle") { + gl_manager_angle = memnew(GLManagerANGLE_Windows); + if (gl_manager_angle->initialize() == OK) { + rendering_driver = "opengl3_angle"; + OS::get_singleton()->set_current_rendering_method("gl_compatibility"); + OS::get_singleton()->set_current_rendering_driver_name(rendering_driver); + driver_found = true; + break; + } + memdelete(gl_manager_angle); + gl_manager_angle = nullptr; + } +#endif // GLES3_ENABLED + if (driver == "dummy") { + rendering_driver = driver; + OS::get_singleton()->set_current_rendering_method("gl_compatibility"); + OS::get_singleton()->set_current_rendering_driver_name(rendering_driver); + driver_found = true; + break; + } + print_line(vformat(" \"%s\" rendering driver initialization failed.", get_readable_driver_name(driver))); } + if (driver_found) { + print_line(vformat(" \"%s\" rendering driver initialized successfully.", get_readable_driver_name(rendering_driver))); + } else { + r_error = ERR_UNAVAILABLE; + ERR_FAIL_MSG("Could not initialize any of the rendering drivers."); + } + +#if defined(GLES3_ENABLED) if (rendering_driver == "opengl3") { RasterizerGLES3::make_current(true); } @@ -6966,6 +6917,10 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win RasterizerGLES3::make_current(false); } #endif + if (rendering_driver == "dummy") { + RasterizerDummy::make_current(); + } + String appname; if (Engine::get_singleton()->is_editor_hint()) { appname = "Godot.GodotEditor." + String(VERSION_FULL_CONFIG); @@ -7089,47 +7044,53 @@ Vector DisplayServerWindows::get_rendering_drivers_func() { drivers.push_back("opengl3"); drivers.push_back("opengl3_angle"); #endif + drivers.push_back("dummy"); return drivers; } +String DisplayServerWindows::get_readable_driver_name(const String &p_driver) const { + if (p_driver == "d3d12") { + return "Direct3D 12"; + } else if (p_driver == "vulkan") { + return "Vulkan"; + } else if (p_driver == "opengl3") { + return "OpenGL 3.2"; + } else if (p_driver == "opengl3_angle") { + return "OpenGLES 3.0 (ANGLE)"; + } else if (p_driver == "dummy") { + return "Dummy"; + } else { + return p_driver; + } +} + DisplayServer *DisplayServerWindows::create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Context p_context, int64_t p_parent_window, Error &r_error) { - DisplayServer *ds = memnew(DisplayServerWindows(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_position, p_resolution, p_screen, p_context, p_parent_window, r_error)); + DisplayServerWindows *ds = memnew(DisplayServerWindows(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_position, p_resolution, p_screen, p_context, p_parent_window, r_error)); if (r_error != OK) { - if (tested_drivers == 0) { - OS::get_singleton()->alert("Failed to register the window class.", "Unable to initialize DisplayServer"); - } else if (tested_drivers.has_flag(DRIVER_ID_RD_VULKAN) || tested_drivers.has_flag(DRIVER_ID_RD_D3D12)) { - Vector drivers; - if (tested_drivers.has_flag(DRIVER_ID_RD_VULKAN)) { - drivers.push_back("Vulkan"); - } - if (tested_drivers.has_flag(DRIVER_ID_RD_D3D12)) { - drivers.push_back("Direct3D 12"); - } - String executable_name = OS::get_singleton()->get_executable_path().get_file(); + Vector names; + for (const String &driver : ds->tested_drivers) { + names.push_back(ds->get_readable_driver_name(driver)); + } + + if (!ds->tested_drivers.has("opengl3") && !ds->tested_drivers.has("opengl3_angle")) { + String executable_command = vformat("\"%s\" --rendering-driver opengl3", OS::get_singleton()->get_executable_path()); + OS::get_singleton()->alert( - vformat("Your video card drivers seem not to support the required %s version.\n\n" - "If possible, consider updating your video card drivers or using the OpenGL 3 driver.\n\n" + vformat("Your video card drivers seem not to support the required version of the following drivers:\n%s.\n\n" + "If possible, consider updating your video card drivers or using the OpenGL 3 driver.\n" + "If you have recently updated your video card drivers, try rebooting.\n\n" "You can enable the OpenGL 3 driver by starting the engine from the\n" - "command line with the command:\n\n \"%s\" --rendering-driver opengl3\n\n" - "If you have recently updated your video card drivers, try rebooting.", - String(" or ").join(drivers), - executable_name), + "command line with the command:\n\n %s", + String(", ").join(names), + executable_command), "Unable to initialize video driver"); } else { - Vector drivers; - if (tested_drivers.has_flag(DRIVER_ID_COMPAT_OPENGL3)) { - drivers.push_back("OpenGL 3.3"); - } - if (tested_drivers.has_flag(DRIVER_ID_COMPAT_ANGLE_D3D11)) { - drivers.push_back("Direct3D 11"); - } OS::get_singleton()->alert( - vformat( - "Your video card drivers seem not to support the required %s version.\n\n" - "If possible, consider updating your video card drivers.\n\n" + vformat("Your video card drivers seem not to support the required version of the following drivers:\n%s.\n\n" + "If possible, consider updating your video card drivers\n" "If you have recently updated your video card drivers, try rebooting.", - String(" or ").join(drivers)), + String(", ").join(names)), "Unable to initialize video driver"); } } diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h index 4a6b51b5923..aa4230f94d7 100644 --- a/platform/windows/display_server_windows.h +++ b/platform/windows/display_server_windows.h @@ -407,14 +407,6 @@ class DisplayServerWindows : public DisplayServer { Vector tablet_drivers; bool winink_disabled = false; - enum DriverID { - DRIVER_ID_COMPAT_OPENGL3 = 1 << 0, - DRIVER_ID_COMPAT_ANGLE_D3D11 = 1 << 1, - DRIVER_ID_RD_VULKAN = 1 << 2, - DRIVER_ID_RD_D3D12 = 1 << 3, - }; - static BitField tested_drivers; - enum TimerID { TIMER_ID_MOVE_REDRAW = 1, TIMER_ID_WINDOW_ACTIVATION = 2, @@ -458,6 +450,8 @@ class DisplayServerWindows : public DisplayServer { int pressrc; HINSTANCE hInstance; // Holds The Instance Of The Application String rendering_driver; + Vector tested_drivers; + bool app_focused = false; bool keep_screen_on = false; HANDLE power_request; @@ -885,6 +879,8 @@ public: static Vector get_rendering_drivers_func(); static void register_windows_driver(); + String get_readable_driver_name(const String &p_driver) const override; + DisplayServerWindows(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Context p_context, int64_t p_parent_window, Error &r_error); ~DisplayServerWindows(); }; diff --git a/servers/display_server.h b/servers/display_server.h index 80bba6897ff..f086c77da9c 100644 --- a/servers/display_server.h +++ b/servers/display_server.h @@ -637,6 +637,8 @@ public: void unregister_additional_output(Object *p_output); bool has_additional_outputs() const { return additional_outputs.size() > 0; } + virtual String get_readable_driver_name(const String &p_driver) const { return p_driver; } + static void register_create_function(const char *p_name, CreateFunction p_function, GetRenderingDriversFunction p_get_drivers); static int get_create_function_count(); static const char *get_create_function_name(int p_index);