summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--COPYRIGHT.txt2
-rw-r--r--core/core_bind.cpp14
-rw-r--r--core/core_bind.h14
-rw-r--r--core/core_constants.cpp2
-rw-r--r--core/core_constants.h2
-rw-r--r--core/extension/gdextension.cpp4
-rw-r--r--core/extension/gdextension.h4
-rw-r--r--core/io/image.h4
-rw-r--r--core/io/plist.cpp (renamed from platform/macos/export/plist.cpp)54
-rw-r--r--core/io/plist.h (renamed from platform/macos/export/plist.h)8
-rw-r--r--core/io/resource.cpp118
-rw-r--r--core/io/resource.h7
-rw-r--r--core/io/resource_loader.cpp27
-rw-r--r--core/object/script_language.h2
-rw-r--r--core/object/script_language_extension.h2
-rw-r--r--core/object/worker_thread_pool.cpp522
-rw-r--r--core/object/worker_thread_pool.h64
-rw-r--r--core/os/condition_variable.h2
-rw-r--r--core/os/semaphore.h8
-rw-r--r--core/register_core_types.cpp1
-rw-r--r--core/string/translation.cpp10
-rw-r--r--core/templates/command_queue_mt.h50
-rw-r--r--core/templates/paged_allocator.h6
-rw-r--r--core/templates/self_list.h6
-rw-r--r--core/variant/callable.cpp3
-rw-r--r--core/variant/variant.h4
-rw-r--r--core/variant/variant_call.cpp10
-rw-r--r--doc/classes/AnimationMixer.xml6
-rw-r--r--doc/classes/AudioEffectCapture.xml3
-rw-r--r--doc/classes/AudioEffectRecord.xml5
-rw-r--r--doc/classes/CanvasTexture.xml2
-rw-r--r--doc/classes/CollisionPolygon2D.xml1
-rw-r--r--doc/classes/EditorImportPlugin.xml7
-rw-r--r--doc/classes/EditorNode3DGizmo.xml7
-rw-r--r--doc/classes/EditorNode3DGizmoPlugin.xml8
-rw-r--r--doc/classes/GDExtension.xml17
-rw-r--r--doc/classes/GDExtensionManager.xml19
-rw-r--r--doc/classes/GraphNode.xml30
-rw-r--r--doc/classes/Image.xml11
-rw-r--r--doc/classes/Node.xml4
-rw-r--r--doc/classes/ProjectSettings.xml8
-rw-r--r--doc/classes/RDUniform.xml3
-rw-r--r--doc/classes/RenderingDevice.xml106
-rw-r--r--doc/classes/RenderingServer.xml12
-rw-r--r--doc/classes/String.xml20
-rw-r--r--doc/classes/StringName.xml21
-rw-r--r--doc/classes/TabContainer.xml14
-rw-r--r--doc/classes/TextServer.xml3
-rw-r--r--doc/classes/Window.xml6
-rw-r--r--doc/classes/WorkerThreadPool.xml2
-rwxr-xr-xdoc/tools/make_rst.py1
-rw-r--r--drivers/d3d12/d3d12_context.cpp40
-rw-r--r--drivers/d3d12/d3d12_context.h6
-rw-r--r--drivers/d3d12/rendering_device_driver_d3d12.cpp14
-rw-r--r--drivers/d3d12/rendering_device_driver_d3d12.h7
-rw-r--r--drivers/egl/egl_manager.h2
-rw-r--r--drivers/gles3/effects/copy_effects.cpp12
-rw-r--r--drivers/gles3/effects/copy_effects.h1
-rw-r--r--drivers/gles3/rasterizer_gles3.cpp14
-rw-r--r--drivers/gles3/rasterizer_gles3.h1
-rw-r--r--drivers/gles3/shaders/copy.glsl5
-rw-r--r--drivers/gles3/storage/texture_storage.cpp13
-rw-r--r--drivers/vulkan/rendering_device_driver_vulkan.cpp50
-rw-r--r--drivers/vulkan/rendering_device_driver_vulkan.h7
-rw-r--r--drivers/vulkan/vulkan_context.cpp56
-rw-r--r--drivers/vulkan/vulkan_context.h6
-rw-r--r--drivers/wasapi/audio_driver_wasapi.cpp8
-rw-r--r--editor/action_map_editor.cpp4
-rw-r--r--editor/animation_bezier_editor.cpp5
-rw-r--r--editor/animation_track_editor.cpp76
-rw-r--r--editor/animation_track_editor.h10
-rw-r--r--editor/audio_stream_preview.cpp3
-rw-r--r--editor/code_editor.cpp14
-rw-r--r--editor/create_dialog.cpp2
-rw-r--r--editor/debugger/debug_adapter/debug_adapter_parser.cpp21
-rw-r--r--editor/debugger/debug_adapter/debug_adapter_parser.h4
-rw-r--r--editor/debugger/debug_adapter/debug_adapter_protocol.cpp5
-rw-r--r--editor/debugger/debug_adapter/debug_adapter_protocol.h1
-rw-r--r--editor/debugger/editor_debugger_node.cpp2
-rw-r--r--editor/debugger/editor_debugger_tree.cpp2
-rw-r--r--editor/editor_audio_buses.cpp9
-rw-r--r--editor/editor_autoload_settings.cpp5
-rw-r--r--editor/editor_command_palette.cpp32
-rw-r--r--editor/editor_command_palette.h5
-rw-r--r--editor/editor_data.cpp3
-rw-r--r--editor/editor_file_system.cpp2
-rw-r--r--editor/editor_help.cpp2
-rw-r--r--editor/editor_help_search.cpp2
-rw-r--r--editor/editor_inspector.cpp9
-rw-r--r--editor/editor_interface.cpp15
-rw-r--r--editor/editor_interface.h2
-rw-r--r--editor/editor_node.cpp42
-rw-r--r--editor/editor_plugin.cpp4
-rw-r--r--editor/editor_properties.cpp2
-rw-r--r--editor/editor_properties_array_dict.cpp4
-rw-r--r--editor/editor_resource_picker.cpp2
-rw-r--r--editor/editor_resource_picker.h2
-rw-r--r--editor/editor_resource_preview.cpp3
-rw-r--r--editor/export/editor_export_platform.cpp2
-rw-r--r--editor/export/project_export.cpp3
-rw-r--r--editor/filesystem_dock.cpp9
-rw-r--r--editor/find_in_files.cpp2
-rw-r--r--editor/group_settings_editor.cpp3
-rw-r--r--editor/groups_editor.cpp20
-rw-r--r--editor/groups_editor.h6
-rw-r--r--editor/gui/editor_spin_slider.cpp8
-rw-r--r--editor/gui/editor_toaster.cpp7
-rw-r--r--editor/gui/editor_toaster.h1
-rw-r--r--editor/gui/scene_tree_editor.cpp14
-rw-r--r--editor/import/3d/post_import_plugin_skeleton_renamer.cpp4
-rw-r--r--editor/import/3d/post_import_plugin_skeleton_renamer.h2
-rw-r--r--editor/import/3d/resource_importer_obj.cpp35
-rw-r--r--editor/import/audio_stream_import_settings.cpp4
-rw-r--r--editor/import/dynamic_font_import_settings.cpp4
-rw-r--r--editor/import/editor_import_plugin.cpp10
-rw-r--r--editor/import/editor_import_plugin.h2
-rw-r--r--editor/inspector_dock.cpp9
-rw-r--r--editor/localization_editor.cpp2
-rw-r--r--editor/plugins/animation_blend_tree_editor_plugin.cpp1
-rw-r--r--editor/plugins/animation_library_editor.cpp23
-rw-r--r--editor/plugins/animation_library_editor.h4
-rw-r--r--editor/plugins/animation_player_editor_plugin.cpp2
-rw-r--r--editor/plugins/animation_state_machine_editor.cpp8
-rw-r--r--editor/plugins/bone_map_editor_plugin.cpp2
-rw-r--r--editor/plugins/bone_map_editor_plugin.h2
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp47
-rw-r--r--editor/plugins/canvas_item_editor_plugin.h10
-rw-r--r--editor/plugins/gizmos/joint_3d_gizmo_plugin.cpp2
-rw-r--r--editor/plugins/lightmap_gi_editor_plugin.cpp2
-rw-r--r--editor/plugins/node_3d_editor_gizmos.cpp2
-rw-r--r--editor/plugins/node_3d_editor_plugin.cpp18
-rw-r--r--editor/plugins/path_2d_editor_plugin.cpp32
-rw-r--r--editor/plugins/path_2d_editor_plugin.h1
-rw-r--r--editor/plugins/polygon_2d_editor_plugin.cpp152
-rw-r--r--editor/plugins/polygon_2d_editor_plugin.h9
-rw-r--r--editor/plugins/root_motion_editor_plugin.cpp1
-rw-r--r--editor/plugins/script_editor_plugin.cpp22
-rw-r--r--editor/plugins/script_text_editor.cpp14
-rw-r--r--editor/plugins/shader_editor_plugin.cpp4
-rw-r--r--editor/plugins/skeleton_3d_editor_plugin.cpp28
-rw-r--r--editor/plugins/skeleton_3d_editor_plugin.h1
-rw-r--r--editor/plugins/text_editor.cpp12
-rw-r--r--editor/plugins/text_shader_editor.cpp10
-rw-r--r--editor/plugins/theme_editor_plugin.cpp2
-rw-r--r--editor/plugins/theme_editor_plugin.h2
-rw-r--r--editor/plugins/tiles/tile_data_editors.cpp40
-rw-r--r--editor/plugins/tiles/tile_data_editors.h22
-rw-r--r--editor/plugins/tiles/tile_set_atlas_source_editor.cpp4
-rw-r--r--editor/plugins/tiles/tile_set_atlas_source_editor.h2
-rw-r--r--editor/plugins/tiles/tiles_editor_plugin.cpp2
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp28
-rw-r--r--editor/progress_dialog.cpp17
-rw-r--r--editor/progress_dialog.h5
-rw-r--r--editor/project_converter_3_to_4.cpp2
-rw-r--r--editor/project_manager.cpp85
-rw-r--r--editor/project_manager.h1
-rw-r--r--editor/project_settings_editor.cpp2
-rw-r--r--editor/renames_map_3_to_4.cpp4
-rw-r--r--editor/scene_create_dialog.cpp2
-rw-r--r--editor/scene_tree_dock.cpp130
-rw-r--r--editor/scene_tree_dock.h3
-rw-r--r--editor/shader_globals_editor.cpp35
-rw-r--r--editor/shader_globals_editor.h3
-rw-r--r--editor/surface_upgrade_tool.cpp2
-rw-r--r--editor/window_wrapper.cpp2
-rw-r--r--main/main.cpp14
-rw-r--r--main/performance.cpp1
-rw-r--r--misc/dist/macos_template.app/Contents/Info.plist1
-rw-r--r--misc/extension_api_validation/4.2-stable.expected30
-rw-r--r--modules/SCsub3
-rw-r--r--modules/basis_universal/register_types.cpp2
-rw-r--r--modules/csg/csg_shape.cpp4
-rw-r--r--modules/gdscript/README.md139
-rw-r--r--modules/gdscript/gdscript.h2
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp2
-rw-r--r--modules/gdscript/gdscript_analyzer.h2
-rw-r--r--modules/gdscript/gdscript_editor.cpp12
-rw-r--r--modules/gdscript/language_server/gdscript_text_document.cpp2
-rw-r--r--modules/gdscript/tests/gdscript_test_runner.cpp2
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/get_node_member_annotated.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/get_node_member_annotated.gd6
-rw-r--r--modules/gdscript/tests/scripts/lsp/class.gd (renamed from modules/gdscript/tests/scripts/lsp/class.notest.gd)0
-rw-r--r--modules/gdscript/tests/scripts/lsp/enums.gd (renamed from modules/gdscript/tests/scripts/lsp/enums.notest.gd)0
-rw-r--r--modules/gdscript/tests/scripts/lsp/indentation.gd (renamed from modules/gdscript/tests/scripts/lsp/indentation.notest.gd)0
-rw-r--r--modules/gdscript/tests/scripts/lsp/lambdas.gd (renamed from modules/gdscript/tests/scripts/lsp/lambdas.notest.gd)0
-rw-r--r--modules/gdscript/tests/scripts/lsp/local_variables.gd (renamed from modules/gdscript/tests/scripts/lsp/local_variables.notest.gd)0
-rw-r--r--modules/gdscript/tests/scripts/lsp/properties.gd (renamed from modules/gdscript/tests/scripts/lsp/properties.notest.gd)0
-rw-r--r--modules/gdscript/tests/scripts/lsp/scopes.gd (renamed from modules/gdscript/tests/scripts/lsp/scopes.notest.gd)0
-rw-r--r--modules/gdscript/tests/scripts/lsp/shadowing_initializer.gd (renamed from modules/gdscript/tests/scripts/lsp/shadowing_initializer.notest.gd)0
-rw-r--r--modules/gdscript/tests/scripts/project.godot2
-rw-r--r--modules/gdscript/tests/test_completion.h199
-rw-r--r--modules/gdscript/tests/test_lsp.h18
-rw-r--r--modules/glslang/config.py4
-rw-r--r--modules/gltf/editor/editor_scene_importer_blend.cpp14
-rw-r--r--modules/gltf/extensions/gltf_document_extension.h2
-rw-r--r--modules/gltf/gltf_document.cpp11
-rw-r--r--modules/gltf/structures/gltf_skeleton.h2
-rw-r--r--modules/gltf/structures/gltf_skin.h1
-rw-r--r--modules/gridmap/grid_map.cpp4
-rw-r--r--modules/lightmapper_rd/lightmapper_rd.cpp4
-rw-r--r--modules/lightmapper_rd/lm_compute.glsl11
-rw-r--r--modules/mono/csharp_script.cpp4
-rw-r--r--modules/mono/csharp_script.h2
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotTools.BuildLogger.csproj4
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.IdeMessaging.CLI/GodotTools.IdeMessaging.CLI.csproj7
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.OpenVisualStudio/GodotTools.OpenVisualStudio.csproj23
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.OpenVisualStudio/Program.cs2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj4
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs13
-rw-r--r--modules/multiplayer/scene_replication_interface.cpp4
-rw-r--r--modules/multiplayer/scene_replication_interface.h4
-rw-r--r--modules/navigation/nav_agent.cpp4
-rw-r--r--modules/noise/noise_texture_2d.cpp8
-rw-r--r--modules/noise/noise_texture_3d.cpp8
-rw-r--r--modules/openxr/SCsub1
-rw-r--r--modules/openxr/action_map/openxr_interaction_profile_metadata.cpp3
-rw-r--r--modules/openxr/doc_classes/OpenXRHand.xml18
-rw-r--r--modules/openxr/doc_classes/OpenXRInterface.xml22
-rw-r--r--modules/openxr/editor/openxr_action_map_editor.cpp3
-rw-r--r--modules/openxr/extensions/openxr_hand_tracking_extension.cpp57
-rw-r--r--modules/openxr/extensions/openxr_hand_tracking_extension.h12
-rw-r--r--modules/openxr/extensions/openxr_meta_controller_extension.cpp184
-rw-r--r--modules/openxr/extensions/openxr_meta_controller_extension.h55
-rw-r--r--modules/openxr/openxr_interface.cpp28
-rw-r--r--modules/openxr/openxr_interface.h10
-rw-r--r--modules/openxr/register_types.cpp2
-rw-r--r--modules/openxr/scene/openxr_hand.cpp227
-rw-r--r--modules/openxr/scene/openxr_hand.h24
-rw-r--r--modules/regex/regex.cpp12
-rw-r--r--modules/regex/tests/test_regex.h139
-rw-r--r--modules/svg/SCsub2
-rw-r--r--modules/text_server_adv/gdextension_build/SConstruct2
-rw-r--r--modules/text_server_adv/register_types.h2
-rw-r--r--modules/text_server_adv/script_iterator.h2
-rw-r--r--modules/text_server_adv/text_server_adv.cpp8
-rw-r--r--modules/text_server_adv/text_server_adv.h2
-rw-r--r--modules/text_server_adv/thorvg_bounds_iterator.cpp2
-rw-r--r--modules/text_server_adv/thorvg_bounds_iterator.h2
-rw-r--r--modules/text_server_adv/thorvg_svg_in_ot.cpp2
-rw-r--r--modules/text_server_adv/thorvg_svg_in_ot.h2
-rw-r--r--modules/text_server_fb/gdextension_build/SConstruct2
-rw-r--r--modules/text_server_fb/register_types.h2
-rw-r--r--modules/text_server_fb/text_server_fb.cpp6
-rw-r--r--modules/text_server_fb/text_server_fb.h2
-rw-r--r--modules/text_server_fb/thorvg_bounds_iterator.cpp2
-rw-r--r--modules/text_server_fb/thorvg_bounds_iterator.h2
-rw-r--r--modules/text_server_fb/thorvg_svg_in_ot.cpp2
-rw-r--r--modules/text_server_fb/thorvg_svg_in_ot.h2
-rw-r--r--modules/zip/zip_packer.cpp2
-rw-r--r--platform/android/export/export.cpp1
-rw-r--r--platform/android/export/export_plugin.cpp4
-rw-r--r--platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt4
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/GodotActivity.kt8
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/utils/PermissionsUtil.java14
-rw-r--r--platform/android/java_godot_lib_jni.cpp2
-rw-r--r--platform/android/java_godot_wrapper.cpp2
-rw-r--r--platform/android/java_godot_wrapper.h2
-rw-r--r--platform/android/os_android.cpp2
-rw-r--r--platform/ios/SCsub1
-rw-r--r--platform/ios/doc_classes/EditorExportPlatformIOS.xml7
-rw-r--r--platform/ios/export/export_plugin.cpp395
-rw-r--r--platform/ios/export/export_plugin.h11
-rw-r--r--platform/ios/ios_terminal_logger.h45
-rw-r--r--platform/ios/ios_terminal_logger.mm74
-rw-r--r--platform/ios/os_ios.mm8
-rw-r--r--platform/linuxbsd/x11/display_server_x11.cpp7
-rw-r--r--platform/linuxbsd/x11/display_server_x11.h2
-rw-r--r--platform/macos/display_server_macos.h2
-rw-r--r--platform/macos/display_server_macos.mm4
-rw-r--r--platform/macos/doc_classes/EditorExportPlatformMacOS.xml7
-rw-r--r--platform/macos/export/codesign.cpp2
-rw-r--r--platform/macos/export/codesign.h3
-rw-r--r--platform/macos/export/export_plugin.cpp25
-rw-r--r--platform/web/export/export_plugin.cpp2
-rw-r--r--platform/web/export/export_plugin.h2
-rw-r--r--platform/windows/SCsub16
-rw-r--r--platform/windows/display_server_windows.cpp4
-rw-r--r--platform/windows/display_server_windows.h2
-rw-r--r--platform/windows/vulkan_context_win.h2
-rw-r--r--scene/2d/camera_2d.cpp2
-rw-r--r--scene/2d/collision_object_2d.cpp16
-rw-r--r--scene/2d/gpu_particles_2d.cpp13
-rw-r--r--scene/2d/gpu_particles_2d.h1
-rw-r--r--scene/2d/light_2d.cpp11
-rw-r--r--scene/2d/light_2d.h3
-rw-r--r--scene/2d/navigation_region_2d.cpp2
-rw-r--r--scene/2d/polygon_2d.cpp6
-rw-r--r--scene/2d/skeleton_2d.cpp39
-rw-r--r--scene/2d/tile_map_layer.cpp2
-rw-r--r--scene/2d/tile_map_layer.h16
-rw-r--r--scene/3d/bone_attachment_3d.cpp2
-rw-r--r--scene/3d/collision_object_3d.cpp8
-rw-r--r--scene/3d/gpu_particles_3d.cpp7
-rw-r--r--scene/3d/gpu_particles_3d.h1
-rw-r--r--scene/3d/navigation_region_3d.cpp3
-rw-r--r--scene/3d/node_3d.cpp5
-rw-r--r--scene/3d/skeleton_3d.cpp1
-rw-r--r--scene/3d/soft_body_3d.cpp4
-rw-r--r--scene/3d/visual_instance_3d.cpp2
-rw-r--r--scene/3d/visual_instance_3d.h2
-rw-r--r--scene/3d/xr_nodes.cpp12
-rw-r--r--scene/3d/xr_nodes.h12
-rw-r--r--scene/animation/animation_blend_space_2d.cpp4
-rw-r--r--scene/animation/animation_mixer.compat.inc44
-rw-r--r--scene/animation/animation_mixer.cpp408
-rw-r--r--scene/animation/animation_mixer.h54
-rw-r--r--scene/animation/animation_tree.cpp4
-rw-r--r--scene/animation/root_motion_view.cpp4
-rw-r--r--scene/gui/color_picker.cpp20
-rw-r--r--scene/gui/container.cpp3
-rw-r--r--scene/gui/control.cpp3
-rw-r--r--scene/gui/dialogs.cpp2
-rw-r--r--scene/gui/graph_edit_arranger.cpp4
-rw-r--r--scene/gui/graph_edit_arranger.h4
-rw-r--r--scene/gui/graph_node.cpp48
-rw-r--r--scene/gui/graph_node.h6
-rw-r--r--scene/gui/line_edit.cpp11
-rw-r--r--scene/gui/popup.cpp2
-rw-r--r--scene/gui/popup_menu.cpp11
-rw-r--r--scene/gui/rich_text_label.cpp4
-rw-r--r--scene/gui/scroll_container.cpp4
-rw-r--r--scene/gui/spin_box.cpp4
-rw-r--r--scene/gui/tab_bar.cpp11
-rw-r--r--scene/gui/tab_bar.h3
-rw-r--r--scene/gui/tab_container.cpp105
-rw-r--r--scene/gui/tab_container.h16
-rw-r--r--scene/gui/text_edit.cpp31
-rw-r--r--scene/gui/tree.cpp4
-rw-r--r--scene/main/canvas_item.cpp5
-rw-r--r--scene/main/http_request.cpp4
-rw-r--r--scene/main/node.cpp36
-rw-r--r--scene/main/node.h4
-rw-r--r--scene/main/viewport.cpp8
-rw-r--r--scene/main/window.cpp82
-rw-r--r--scene/main/window.h6
-rw-r--r--scene/register_scene_types.cpp2
-rw-r--r--scene/resources/animation.cpp22
-rw-r--r--scene/resources/animation.h11
-rw-r--r--scene/resources/bone_map.cpp10
-rw-r--r--scene/resources/bone_map.h10
-rw-r--r--scene/resources/compressed_texture.h1
-rw-r--r--scene/resources/curve_texture.cpp4
-rw-r--r--scene/resources/material.cpp2
-rw-r--r--scene/resources/material.h2
-rw-r--r--scene/resources/navigation_mesh.cpp2
-rw-r--r--scene/resources/navigation_mesh.h2
-rw-r--r--scene/resources/navigation_polygon.cpp2
-rw-r--r--scene/resources/navigation_polygon.h2
-rw-r--r--scene/resources/portable_compressed_texture.cpp27
-rw-r--r--scene/resources/portable_compressed_texture.h8
-rw-r--r--scene/resources/primitive_meshes.cpp25
-rw-r--r--scene/resources/resource_format_text.cpp10
-rw-r--r--scene/resources/skeleton_profile.cpp18
-rw-r--r--scene/resources/skeleton_profile.h18
-rw-r--r--scene/resources/theme.cpp25
-rw-r--r--scene/resources/theme.h14
-rw-r--r--scene/resources/tile_set.cpp3
-rw-r--r--scene/theme/default_theme.cpp16
-rw-r--r--scene/theme/theme_owner.cpp4
-rw-r--r--scene/theme/theme_owner.h4
-rw-r--r--servers/audio_server.cpp8
-rw-r--r--servers/audio_server.h8
-rw-r--r--servers/display_server.cpp4
-rw-r--r--servers/display_server.h2
-rw-r--r--servers/navigation_server_3d.cpp22
-rw-r--r--servers/rendering/dummy/rasterizer_dummy.h2
-rw-r--r--servers/rendering/renderer_canvas_cull.cpp24
-rw-r--r--servers/rendering/renderer_canvas_cull.h6
-rw-r--r--servers/rendering/renderer_canvas_render.cpp2
-rw-r--r--servers/rendering/renderer_compositor.cpp4
-rw-r--r--servers/rendering/renderer_compositor.h1
-rw-r--r--servers/rendering/renderer_rd/api_context_rd.h7
-rw-r--r--servers/rendering/renderer_rd/cluster_builder_rd.cpp16
-rw-r--r--servers/rendering/renderer_rd/effects/bokeh_dof.cpp12
-rw-r--r--servers/rendering/renderer_rd/effects/copy_effects.cpp28
-rw-r--r--servers/rendering/renderer_rd/effects/copy_effects.h2
-rw-r--r--servers/rendering/renderer_rd/effects/debug_effects.cpp6
-rw-r--r--servers/rendering/renderer_rd/effects/fsr.cpp2
-rw-r--r--servers/rendering/renderer_rd/effects/fsr2.cpp9
-rw-r--r--servers/rendering/renderer_rd/effects/luminance.cpp2
-rw-r--r--servers/rendering/renderer_rd/effects/resolve.cpp8
-rw-r--r--servers/rendering/renderer_rd/effects/resolve.h4
-rw-r--r--servers/rendering/renderer_rd/effects/ss_effects.cpp12
-rw-r--r--servers/rendering/renderer_rd/effects/tone_mapper.cpp2
-rw-r--r--servers/rendering/renderer_rd/effects/vrs.cpp2
-rw-r--r--servers/rendering/renderer_rd/environment/fog.cpp6
-rw-r--r--servers/rendering/renderer_rd/environment/gi.cpp67
-rw-r--r--servers/rendering/renderer_rd/environment/gi.h6
-rw-r--r--servers/rendering/renderer_rd/environment/sky.cpp10
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp142
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h15
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp2
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp80
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h15
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp2
-rw-r--r--servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp13
-rw-r--r--servers/rendering/renderer_rd/renderer_compositor_rd.h1
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_rd.cpp12
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_rd.h3
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/fsr2/SCsub5
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/specular_merge.glsl2
-rw-r--r--servers/rendering/renderer_rd/storage_rd/light_storage.cpp8
-rw-r--r--servers/rendering/renderer_rd/storage_rd/material_storage.cpp4
-rw-r--r--servers/rendering/renderer_rd/storage_rd/material_storage.h2
-rw-r--r--servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp10
-rw-r--r--servers/rendering/renderer_rd/storage_rd/mesh_storage.h1
-rw-r--r--servers/rendering/renderer_rd/storage_rd/particles_storage.cpp20
-rw-r--r--servers/rendering/renderer_rd/storage_rd/particles_storage.h3
-rw-r--r--servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp16
-rw-r--r--servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h6
-rw-r--r--servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.cpp2
-rw-r--r--servers/rendering/renderer_rd/storage_rd/texture_storage.cpp8
-rw-r--r--servers/rendering/renderer_viewport.cpp8
-rw-r--r--servers/rendering/rendering_device.compat.inc106
-rw-r--r--servers/rendering/rendering_device.cpp2702
-rw-r--r--servers/rendering/rendering_device.h241
-rw-r--r--servers/rendering/rendering_device_commons.h2
-rw-r--r--servers/rendering/rendering_device_driver.h13
-rw-r--r--servers/rendering/rendering_device_graph.cpp1930
-rw-r--r--servers/rendering/rendering_device_graph.h668
-rw-r--r--servers/rendering/rendering_server_default.cpp8
-rw-r--r--servers/rendering/rendering_server_default.h2
-rw-r--r--servers/rendering/shader_language.cpp4
-rw-r--r--servers/rendering/shader_language.h4
-rw-r--r--servers/rendering_server.cpp31
-rw-r--r--servers/rendering_server.h14
-rw-r--r--tests/core/string/test_node_path.h22
-rw-r--r--tests/core/variant/test_array.h2
-rw-r--r--tests/test_main.cpp32
-rw-r--r--thirdparty/README.md4
-rw-r--r--thirdparty/amd-fsr2/shaders/ffx_fsr2_depth_clip_pass.glsl1
-rw-r--r--thirdparty/openxr/COPYING.adoc2
-rw-r--r--thirdparty/openxr/include/openxr/openxr.h439
-rw-r--r--thirdparty/openxr/include/openxr/openxr_loader_negotiation.h140
-rw-r--r--thirdparty/openxr/include/openxr/openxr_platform.h6
-rw-r--r--thirdparty/openxr/include/openxr/openxr_platform_defines.h2
-rw-r--r--thirdparty/openxr/include/openxr/openxr_reflection.h341
-rw-r--r--thirdparty/openxr/include/openxr/openxr_reflection_parent_structs.h3
-rw-r--r--thirdparty/openxr/include/openxr/openxr_reflection_structs.h18
-rw-r--r--thirdparty/openxr/src/common/extra_algorithms.h4
-rw-r--r--thirdparty/openxr/src/common/filesystem_utils.cpp2
-rw-r--r--thirdparty/openxr/src/common/filesystem_utils.hpp2
-rw-r--r--thirdparty/openxr/src/common/hex_and_handles.h4
-rw-r--r--thirdparty/openxr/src/common/loader_interfaces.h114
-rw-r--r--thirdparty/openxr/src/common/object_info.cpp4
-rw-r--r--thirdparty/openxr/src/common/object_info.h4
-rw-r--r--thirdparty/openxr/src/common/platform_utils.hpp2
-rw-r--r--thirdparty/openxr/src/common/stdfs_conditions.h2
-rw-r--r--thirdparty/openxr/src/common/unique_asset.h2
-rw-r--r--thirdparty/openxr/src/common/vulkan_debug_object_namer.hpp2
-rw-r--r--thirdparty/openxr/src/common/xr_dependencies.h2
-rw-r--r--thirdparty/openxr/src/common/xr_linear.h2
-rw-r--r--thirdparty/openxr/src/loader/android_utilities.cpp32
-rw-r--r--thirdparty/openxr/src/loader/android_utilities.h4
-rw-r--r--thirdparty/openxr/src/loader/api_layer_interface.cpp69
-rw-r--r--thirdparty/openxr/src/loader/api_layer_interface.hpp4
-rw-r--r--thirdparty/openxr/src/loader/exception_handling.hpp4
-rw-r--r--thirdparty/openxr/src/loader/loader_core.cpp5
-rw-r--r--thirdparty/openxr/src/loader/loader_init_data.cpp59
-rw-r--r--thirdparty/openxr/src/loader/loader_init_data.hpp92
-rw-r--r--thirdparty/openxr/src/loader/loader_instance.cpp6
-rw-r--r--thirdparty/openxr/src/loader/loader_instance.hpp4
-rw-r--r--thirdparty/openxr/src/loader/loader_logger.cpp2
-rw-r--r--thirdparty/openxr/src/loader/loader_logger.hpp2
-rw-r--r--thirdparty/openxr/src/loader/loader_logger_recorders.cpp2
-rw-r--r--thirdparty/openxr/src/loader/loader_logger_recorders.hpp4
-rw-r--r--thirdparty/openxr/src/loader/loader_platform.hpp2
-rw-r--r--thirdparty/openxr/src/loader/manifest_file.cpp7
-rw-r--r--thirdparty/openxr/src/loader/manifest_file.hpp2
-rw-r--r--thirdparty/openxr/src/loader/runtime_interface.cpp117
-rw-r--r--thirdparty/openxr/src/loader/runtime_interface.hpp14
-rw-r--r--thirdparty/openxr/src/loader/xr_generated_loader.cpp4
-rw-r--r--thirdparty/openxr/src/loader/xr_generated_loader.hpp7
-rw-r--r--thirdparty/openxr/src/xr_generated_dispatch_table_core.c4
-rw-r--r--thirdparty/openxr/src/xr_generated_dispatch_table_core.h4
-rw-r--r--thirdparty/thorvg/AUTHORS2
-rw-r--r--thirdparty/thorvg/LICENSE2
-rw-r--r--thirdparty/thorvg/inc/config.h2
-rw-r--r--thirdparty/thorvg/inc/thorvg.h355
-rw-r--r--thirdparty/thorvg/src/common/tvgArray.h7
-rw-r--r--thirdparty/thorvg/src/common/tvgBezier.cpp2
-rw-r--r--thirdparty/thorvg/src/common/tvgBezier.h2
-rw-r--r--thirdparty/thorvg/src/common/tvgCompressor.cpp2
-rw-r--r--thirdparty/thorvg/src/common/tvgCompressor.h2
-rw-r--r--thirdparty/thorvg/src/common/tvgInlist.h111
-rw-r--r--thirdparty/thorvg/src/common/tvgList.h90
-rw-r--r--thirdparty/thorvg/src/common/tvgMath.cpp2
-rw-r--r--thirdparty/thorvg/src/common/tvgMath.h14
-rw-r--r--thirdparty/thorvg/src/common/tvgStr.cpp2
-rw-r--r--thirdparty/thorvg/src/common/tvgStr.h2
-rw-r--r--thirdparty/thorvg/src/loaders/external_png/tvgPngLoader.cpp62
-rw-r--r--thirdparty/thorvg/src/loaders/external_png/tvgPngLoader.h12
-rw-r--r--thirdparty/thorvg/src/loaders/jpg/tvgJpgLoader.cpp67
-rw-r--r--thirdparty/thorvg/src/loaders/jpg/tvgJpgLoader.h12
-rw-r--r--thirdparty/thorvg/src/loaders/jpg/tvgJpgd.cpp2
-rw-r--r--thirdparty/thorvg/src/loaders/jpg/tvgJpgd.h2
-rw-r--r--thirdparty/thorvg/src/loaders/png/tvgLodePng.cpp2
-rw-r--r--thirdparty/thorvg/src/loaders/png/tvgLodePng.h2
-rw-r--r--thirdparty/thorvg/src/loaders/png/tvgPngLoader.cpp91
-rw-r--r--thirdparty/thorvg/src/loaders/png/tvgPngLoader.h12
-rw-r--r--thirdparty/thorvg/src/loaders/raw/tvgRawLoader.cpp55
-rw-r--r--thirdparty/thorvg/src/loaders/raw/tvgRawLoader.h11
-rw-r--r--thirdparty/thorvg/src/loaders/svg/tvgSvgCssStyle.cpp2
-rw-r--r--thirdparty/thorvg/src/loaders/svg/tvgSvgCssStyle.h2
-rw-r--r--thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp24
-rw-r--r--thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.h9
-rw-r--r--thirdparty/thorvg/src/loaders/svg/tvgSvgLoaderCommon.h2
-rw-r--r--thirdparty/thorvg/src/loaders/svg/tvgSvgPath.cpp10
-rw-r--r--thirdparty/thorvg/src/loaders/svg/tvgSvgPath.h4
-rw-r--r--thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.cpp16
-rw-r--r--thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.h4
-rw-r--r--thirdparty/thorvg/src/loaders/svg/tvgSvgUtil.cpp2
-rw-r--r--thirdparty/thorvg/src/loaders/svg/tvgSvgUtil.h2
-rw-r--r--thirdparty/thorvg/src/loaders/svg/tvgXmlParser.cpp2
-rw-r--r--thirdparty/thorvg/src/loaders/svg/tvgXmlParser.h2
-rw-r--r--thirdparty/thorvg/src/renderer/sw_engine/tvgSwCommon.h17
-rw-r--r--thirdparty/thorvg/src/renderer/sw_engine/tvgSwFill.cpp3
-rw-r--r--thirdparty/thorvg/src/renderer/sw_engine/tvgSwImage.cpp2
-rw-r--r--thirdparty/thorvg/src/renderer/sw_engine/tvgSwMath.cpp2
-rw-r--r--thirdparty/thorvg/src/renderer/sw_engine/tvgSwMemPool.cpp2
-rw-r--r--thirdparty/thorvg/src/renderer/sw_engine/tvgSwRaster.cpp13
-rw-r--r--thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterAvx.h2
-rw-r--r--thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterC.h2
-rw-r--r--thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterNeon.h2
-rw-r--r--thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterTexmap.h2
-rw-r--r--thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp19
-rw-r--r--thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.h2
-rw-r--r--thirdparty/thorvg/src/renderer/sw_engine/tvgSwRle.cpp2
-rw-r--r--thirdparty/thorvg/src/renderer/sw_engine/tvgSwShape.cpp2
-rw-r--r--thirdparty/thorvg/src/renderer/sw_engine/tvgSwStroke.cpp2
-rw-r--r--thirdparty/thorvg/src/renderer/tvgAccessor.cpp2
-rw-r--r--thirdparty/thorvg/src/renderer/tvgAnimation.cpp10
-rw-r--r--thirdparty/thorvg/src/renderer/tvgBinaryDesc.h4
-rw-r--r--thirdparty/thorvg/src/renderer/tvgCanvas.cpp2
-rw-r--r--thirdparty/thorvg/src/renderer/tvgCanvas.h11
-rw-r--r--thirdparty/thorvg/src/renderer/tvgCommon.h5
-rw-r--r--thirdparty/thorvg/src/renderer/tvgFill.cpp2
-rw-r--r--thirdparty/thorvg/src/renderer/tvgFill.h2
-rw-r--r--thirdparty/thorvg/src/renderer/tvgFrameModule.h5
-rw-r--r--thirdparty/thorvg/src/renderer/tvgGlCanvas.cpp2
-rw-r--r--thirdparty/thorvg/src/renderer/tvgInitializer.cpp35
-rw-r--r--thirdparty/thorvg/src/renderer/tvgIteratorAccessor.h2
-rw-r--r--thirdparty/thorvg/src/renderer/tvgLoadModule.h74
-rw-r--r--thirdparty/thorvg/src/renderer/tvgLoader.cpp184
-rw-r--r--thirdparty/thorvg/src/renderer/tvgLoader.h11
-rw-r--r--thirdparty/thorvg/src/renderer/tvgPaint.cpp4
-rw-r--r--thirdparty/thorvg/src/renderer/tvgPaint.h2
-rw-r--r--thirdparty/thorvg/src/renderer/tvgPicture.cpp99
-rw-r--r--thirdparty/thorvg/src/renderer/tvgPicture.h124
-rw-r--r--thirdparty/thorvg/src/renderer/tvgRender.cpp2
-rw-r--r--thirdparty/thorvg/src/renderer/tvgRender.h37
-rw-r--r--thirdparty/thorvg/src/renderer/tvgSaveModule.h4
-rw-r--r--thirdparty/thorvg/src/renderer/tvgSaver.cpp18
-rw-r--r--thirdparty/thorvg/src/renderer/tvgScene.cpp2
-rw-r--r--thirdparty/thorvg/src/renderer/tvgScene.h21
-rw-r--r--thirdparty/thorvg/src/renderer/tvgShape.cpp2
-rw-r--r--thirdparty/thorvg/src/renderer/tvgShape.h17
-rw-r--r--thirdparty/thorvg/src/renderer/tvgSwCanvas.cpp2
-rw-r--r--thirdparty/thorvg/src/renderer/tvgTaskScheduler.cpp62
-rw-r--r--thirdparty/thorvg/src/renderer/tvgTaskScheduler.h5
-rw-r--r--thirdparty/thorvg/src/renderer/tvgText.cpp109
-rw-r--r--thirdparty/thorvg/src/renderer/tvgText.h191
-rw-r--r--thirdparty/thorvg/src/renderer/tvgWgCanvas.cpp81
-rwxr-xr-xthirdparty/thorvg/update-thorvg.sh3
565 files changed, 11112 insertions, 5321 deletions
diff --git a/COPYRIGHT.txt b/COPYRIGHT.txt
index 4b8a246df0..c549761beb 100644
--- a/COPYRIGHT.txt
+++ b/COPYRIGHT.txt
@@ -483,7 +483,7 @@ License: Expat
Files: ./thirdparty/thorvg/
Comment: ThorVG
-Copyright: 2020-2023, The ThorVG Project
+Copyright: 2020-2024, The ThorVG Project
License: Expat
Files: ./thirdparty/tinyexr/
diff --git a/core/core_bind.cpp b/core/core_bind.cpp
index e3dad09091..e5363f9acc 100644
--- a/core/core_bind.cpp
+++ b/core/core_bind.cpp
@@ -1375,11 +1375,11 @@ Variant ClassDB::instantiate(const StringName &p_class) const {
}
}
-bool ClassDB::class_has_signal(StringName p_class, StringName p_signal) const {
+bool ClassDB::class_has_signal(const StringName &p_class, const StringName &p_signal) const {
return ::ClassDB::has_signal(p_class, p_signal);
}
-Dictionary ClassDB::class_get_signal(StringName p_class, StringName p_signal) const {
+Dictionary ClassDB::class_get_signal(const StringName &p_class, const StringName &p_signal) const {
MethodInfo signal;
if (::ClassDB::get_signal(p_class, p_signal, &signal)) {
return signal.operator Dictionary();
@@ -1388,7 +1388,7 @@ Dictionary ClassDB::class_get_signal(StringName p_class, StringName p_signal) co
}
}
-TypedArray<Dictionary> ClassDB::class_get_signal_list(StringName p_class, bool p_no_inheritance) const {
+TypedArray<Dictionary> ClassDB::class_get_signal_list(const StringName &p_class, bool p_no_inheritance) const {
List<MethodInfo> signals;
::ClassDB::get_signal_list(p_class, &signals, p_no_inheritance);
TypedArray<Dictionary> ret;
@@ -1400,7 +1400,7 @@ TypedArray<Dictionary> ClassDB::class_get_signal_list(StringName p_class, bool p
return ret;
}
-TypedArray<Dictionary> ClassDB::class_get_property_list(StringName p_class, bool p_no_inheritance) const {
+TypedArray<Dictionary> ClassDB::class_get_property_list(const StringName &p_class, bool p_no_inheritance) const {
List<PropertyInfo> plist;
::ClassDB::get_property_list(p_class, &plist, p_no_inheritance);
TypedArray<Dictionary> ret;
@@ -1428,11 +1428,11 @@ Error ClassDB::class_set_property(Object *p_object, const StringName &p_property
return OK;
}
-bool ClassDB::class_has_method(StringName p_class, StringName p_method, bool p_no_inheritance) const {
+bool ClassDB::class_has_method(const StringName &p_class, const StringName &p_method, bool p_no_inheritance) const {
return ::ClassDB::has_method(p_class, p_method, p_no_inheritance);
}
-TypedArray<Dictionary> ClassDB::class_get_method_list(StringName p_class, bool p_no_inheritance) const {
+TypedArray<Dictionary> ClassDB::class_get_method_list(const StringName &p_class, bool p_no_inheritance) const {
List<MethodInfo> methods;
::ClassDB::get_method_list(p_class, &methods, p_no_inheritance);
TypedArray<Dictionary> ret;
@@ -1513,7 +1513,7 @@ StringName ClassDB::class_get_integer_constant_enum(const StringName &p_class, c
return ::ClassDB::get_integer_constant_enum(p_class, p_name, p_no_inheritance);
}
-bool ClassDB::is_class_enabled(StringName p_class) const {
+bool ClassDB::is_class_enabled(const StringName &p_class) const {
return ::ClassDB::is_class_enabled(p_class);
}
diff --git a/core/core_bind.h b/core/core_bind.h
index a8244cf7c5..94d95f2ce9 100644
--- a/core/core_bind.h
+++ b/core/core_bind.h
@@ -435,17 +435,17 @@ public:
bool can_instantiate(const StringName &p_class) const;
Variant instantiate(const StringName &p_class) const;
- bool class_has_signal(StringName p_class, StringName p_signal) const;
- Dictionary class_get_signal(StringName p_class, StringName p_signal) const;
- TypedArray<Dictionary> class_get_signal_list(StringName p_class, bool p_no_inheritance = false) const;
+ bool class_has_signal(const StringName &p_class, const StringName &p_signal) const;
+ Dictionary class_get_signal(const StringName &p_class, const StringName &p_signal) const;
+ TypedArray<Dictionary> class_get_signal_list(const StringName &p_class, bool p_no_inheritance = false) const;
- TypedArray<Dictionary> class_get_property_list(StringName p_class, bool p_no_inheritance = false) const;
+ TypedArray<Dictionary> class_get_property_list(const StringName &p_class, bool p_no_inheritance = false) const;
Variant class_get_property(Object *p_object, const StringName &p_property) const;
Error class_set_property(Object *p_object, const StringName &p_property, const Variant &p_value) const;
- bool class_has_method(StringName p_class, StringName p_method, bool p_no_inheritance = false) const;
+ bool class_has_method(const StringName &p_class, const StringName &p_method, bool p_no_inheritance = false) const;
- TypedArray<Dictionary> class_get_method_list(StringName p_class, bool p_no_inheritance = false) const;
+ TypedArray<Dictionary> class_get_method_list(const StringName &p_class, bool p_no_inheritance = false) const;
PackedStringArray class_get_integer_constant_list(const StringName &p_class, bool p_no_inheritance = false) const;
bool class_has_integer_constant(const StringName &p_class, const StringName &p_name) const;
@@ -456,7 +456,7 @@ public:
PackedStringArray class_get_enum_constants(const StringName &p_class, const StringName &p_enum, bool p_no_inheritance = false) const;
StringName class_get_integer_constant_enum(const StringName &p_class, const StringName &p_name, bool p_no_inheritance = false) const;
- bool is_class_enabled(StringName p_class) const;
+ bool is_class_enabled(const StringName &p_class) const;
ClassDB() {}
~ClassDB() {}
diff --git a/core/core_constants.cpp b/core/core_constants.cpp
index 2f70fdf219..3b96fc20c6 100644
--- a/core/core_constants.cpp
+++ b/core/core_constants.cpp
@@ -845,7 +845,7 @@ bool CoreConstants::is_global_enum(const StringName &p_enum) {
return _global_enums.has(p_enum);
}
-void CoreConstants::get_enum_values(StringName p_enum, HashMap<StringName, int64_t> *p_values) {
+void CoreConstants::get_enum_values(const StringName &p_enum, HashMap<StringName, int64_t> *p_values) {
ERR_FAIL_NULL_MSG(p_values, "Trying to get enum values with null map.");
ERR_FAIL_COND_MSG(!_global_enums.has(p_enum), "Trying to get values of non-existing enum.");
for (const _CoreConstant &constant : _global_enums[p_enum]) {
diff --git a/core/core_constants.h b/core/core_constants.h
index 51842490c8..82d626c749 100644
--- a/core/core_constants.h
+++ b/core/core_constants.h
@@ -45,7 +45,7 @@ public:
static bool is_global_constant(const StringName &p_name);
static int get_global_constant_index(const StringName &p_name);
static bool is_global_enum(const StringName &p_enum);
- static void get_enum_values(StringName p_enum, HashMap<StringName, int64_t> *p_values);
+ static void get_enum_values(const StringName &p_enum, HashMap<StringName, int64_t> *p_values);
};
#endif // CORE_CONSTANTS_H
diff --git a/core/extension/gdextension.cpp b/core/extension/gdextension.cpp
index 19ffe96a09..ce01531b5c 100644
--- a/core/extension/gdextension.cpp
+++ b/core/extension/gdextension.cpp
@@ -666,12 +666,12 @@ void GDExtension::_get_library_path(GDExtensionClassLibraryPtr p_library, GDExte
HashMap<StringName, GDExtensionInterfaceFunctionPtr> GDExtension::gdextension_interface_functions;
-void GDExtension::register_interface_function(StringName p_function_name, GDExtensionInterfaceFunctionPtr p_function_pointer) {
+void GDExtension::register_interface_function(const StringName &p_function_name, GDExtensionInterfaceFunctionPtr p_function_pointer) {
ERR_FAIL_COND_MSG(gdextension_interface_functions.has(p_function_name), "Attempt to register interface function '" + p_function_name + "', which appears to be already registered.");
gdextension_interface_functions.insert(p_function_name, p_function_pointer);
}
-GDExtensionInterfaceFunctionPtr GDExtension::get_interface_function(StringName p_function_name) {
+GDExtensionInterfaceFunctionPtr GDExtension::get_interface_function(const StringName &p_function_name) {
GDExtensionInterfaceFunctionPtr *function = gdextension_interface_functions.getptr(p_function_name);
ERR_FAIL_NULL_V_MSG(function, nullptr, "Attempt to get non-existent interface function: " + String(p_function_name) + ".");
return *function;
diff --git a/core/extension/gdextension.h b/core/extension/gdextension.h
index 0d20b8e50c..0b39581751 100644
--- a/core/extension/gdextension.h
+++ b/core/extension/gdextension.h
@@ -154,8 +154,8 @@ public:
void initialize_library(InitializationLevel p_level);
void deinitialize_library(InitializationLevel p_level);
- static void register_interface_function(StringName p_function_name, GDExtensionInterfaceFunctionPtr p_function_pointer);
- static GDExtensionInterfaceFunctionPtr get_interface_function(StringName p_function_name);
+ static void register_interface_function(const StringName &p_function_name, GDExtensionInterfaceFunctionPtr p_function_pointer);
+ static GDExtensionInterfaceFunctionPtr get_interface_function(const StringName &p_function_name);
static void initialize_gdextensions();
static void finalize_gdextensions();
diff --git a/core/io/image.h b/core/io/image.h
index a5025ee8a1..be308b0ac1 100644
--- a/core/io/image.h
+++ b/core/io/image.h
@@ -313,8 +313,8 @@ public:
Error save_jpg(const String &p_path, float p_quality = 0.75) const;
Vector<uint8_t> save_png_to_buffer() const;
Vector<uint8_t> save_jpg_to_buffer(float p_quality = 0.75) const;
- Vector<uint8_t> save_exr_to_buffer(bool p_grayscale) const;
- Error save_exr(const String &p_path, bool p_grayscale) const;
+ Vector<uint8_t> save_exr_to_buffer(bool p_grayscale = false) const;
+ Error save_exr(const String &p_path, bool p_grayscale = false) const;
Error save_webp(const String &p_path, const bool p_lossy = false, const float p_quality = 0.75f) const;
Vector<uint8_t> save_webp_to_buffer(const bool p_lossy = false, const float p_quality = 0.75f) const;
diff --git a/platform/macos/export/plist.cpp b/core/io/plist.cpp
index f494c58fc9..86737609bf 100644
--- a/platform/macos/export/plist.cpp
+++ b/core/io/plist.cpp
@@ -448,7 +448,9 @@ PList::PList() {
}
PList::PList(const String &p_string) {
- load_string(p_string);
+ String err_str;
+ bool ok = load_string(p_string, err_str);
+ ERR_FAIL_COND_MSG(!ok, "PList: " + err_str);
}
uint64_t PList::read_bplist_var_size_int(Ref<FileAccess> p_file, uint8_t p_size) {
@@ -642,11 +644,15 @@ bool PList::load_file(const String &p_filename) {
String ret;
ret.parse_utf8((const char *)array.ptr(), array.size());
- return load_string(ret);
+ String err_str;
+ bool ok = load_string(ret, err_str);
+ ERR_FAIL_COND_V_MSG(!ok, false, "PList: " + err_str);
+
+ return true;
}
}
-bool PList::load_string(const String &p_string) {
+bool PList::load_string(const String &p_string, String &r_err_out) {
root = Ref<PListNode>();
int pos = 0;
@@ -657,14 +663,16 @@ bool PList::load_string(const String &p_string) {
while (pos >= 0) {
int open_token_s = p_string.find("<", pos);
if (open_token_s == -1) {
- ERR_FAIL_V_MSG(false, "PList: Unexpected end of data. No tags found.");
+ r_err_out = "Unexpected end of data. No tags found.";
+ return false;
}
int open_token_e = p_string.find(">", open_token_s);
pos = open_token_e;
String token = p_string.substr(open_token_s + 1, open_token_e - open_token_s - 1);
if (token.is_empty()) {
- ERR_FAIL_V_MSG(false, "PList: Invalid token name.");
+ r_err_out = "Invalid token name.";
+ return false;
}
String value;
if (token[0] == '?' || token[0] == '!') { // Skip <?xml ... ?> and <!DOCTYPE ... >
@@ -684,7 +692,8 @@ bool PList::load_string(const String &p_string) {
}
if (!in_plist) {
- ERR_FAIL_V_MSG(false, "PList: Node outside of <plist> tag.");
+ r_err_out = "Node outside of <plist> tag.";
+ return false;
}
if (token == "dict") {
@@ -693,13 +702,15 @@ bool PList::load_string(const String &p_string) {
Ref<PListNode> dict = PListNode::new_dict();
dict->data_type = PList::PLNodeType::PL_NODE_TYPE_DICT;
if (!stack.back()->get()->push_subnode(dict, key)) {
- ERR_FAIL_V_MSG(false, "PList: Can't push subnode, invalid parent type.");
+ r_err_out = "Can't push subnode, invalid parent type.";
+ return false;
}
stack.push_back(dict);
} else {
// Add root node.
if (!root.is_null()) {
- ERR_FAIL_V_MSG(false, "PList: Root node already set.");
+ r_err_out = "Root node already set.";
+ return false;
}
Ref<PListNode> dict = PListNode::new_dict();
stack.push_back(dict);
@@ -711,7 +722,8 @@ bool PList::load_string(const String &p_string) {
if (token == "/dict") {
// Exit current dict.
if (stack.is_empty() || stack.back()->get()->data_type != PList::PLNodeType::PL_NODE_TYPE_DICT) {
- ERR_FAIL_V_MSG(false, "PList: Mismatched </dict> tag.");
+ r_err_out = "Mismatched </dict> tag.";
+ return false;
}
stack.pop_back();
continue;
@@ -722,13 +734,15 @@ bool PList::load_string(const String &p_string) {
// Add subnode end enter it.
Ref<PListNode> arr = PListNode::new_array();
if (!stack.back()->get()->push_subnode(arr, key)) {
- ERR_FAIL_V_MSG(false, "PList: Can't push subnode, invalid parent type.");
+ r_err_out = "Can't push subnode, invalid parent type.";
+ return false;
}
stack.push_back(arr);
} else {
// Add root node.
if (!root.is_null()) {
- ERR_FAIL_V_MSG(false, "PList: Root node already set.");
+ r_err_out = "Root node already set.";
+ return false;
}
Ref<PListNode> arr = PListNode::new_array();
stack.push_back(arr);
@@ -740,7 +754,8 @@ bool PList::load_string(const String &p_string) {
if (token == "/array") {
// Exit current array.
if (stack.is_empty() || stack.back()->get()->data_type != PList::PLNodeType::PL_NODE_TYPE_ARRAY) {
- ERR_FAIL_V_MSG(false, "PList: Mismatched </array> tag.");
+ r_err_out = "Mismatched </array> tag.";
+ return false;
}
stack.pop_back();
continue;
@@ -751,13 +766,15 @@ bool PList::load_string(const String &p_string) {
} else {
int end_token_s = p_string.find("</", pos);
if (end_token_s == -1) {
- ERR_FAIL_V_MSG(false, vformat("PList: Mismatched <%s> tag.", token));
+ r_err_out = vformat("Mismatched <%s> tag.", token);
+ return false;
}
int end_token_e = p_string.find(">", end_token_s);
pos = end_token_e;
String end_token = p_string.substr(end_token_s + 2, end_token_e - end_token_s - 2);
if (end_token != token) {
- ERR_FAIL_V_MSG(false, vformat("PList: Mismatched <%s> and <%s> token pair.", token, end_token));
+ r_err_out = vformat("Mismatched <%s> and <%s> token pair.", token, end_token);
+ return false;
}
value = p_string.substr(open_token_e + 1, end_token_s - open_token_e - 1);
}
@@ -780,15 +797,18 @@ bool PList::load_string(const String &p_string) {
} else if (token == "date") {
var = PListNode::new_date(value);
} else {
- ERR_FAIL_V_MSG(false, "PList: Invalid value type.");
+ r_err_out = vformat("Invalid value type: %s.", token);
+ return false;
}
if (stack.is_empty() || !stack.back()->get()->push_subnode(var, key)) {
- ERR_FAIL_V_MSG(false, "PList: Can't push subnode, invalid parent type.");
+ r_err_out = "Can't push subnode, invalid parent type.";
+ return false;
}
}
}
if (!stack.is_empty() || !done_plist) {
- ERR_FAIL_V_MSG(false, "PList: Unexpected end of data. Root node is not closed.");
+ r_err_out = "Unexpected end of data. Root node is not closed.";
+ return false;
}
return true;
}
diff --git a/platform/macos/export/plist.h b/core/io/plist.h
index 28b02e4eb7..7d8b8ef0b4 100644
--- a/platform/macos/export/plist.h
+++ b/core/io/plist.h
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
-#ifndef MACOS_PLIST_H
-#define MACOS_PLIST_H
+#ifndef PLIST_H
+#define PLIST_H
// Property list file format (application/x-plist) parser, property list ASN-1 serialization.
@@ -75,7 +75,7 @@ public:
PList(const String &p_string);
bool load_file(const String &p_filename);
- bool load_string(const String &p_string);
+ bool load_string(const String &p_string, String &r_err_out);
PackedByteArray save_asn1() const;
String save_text() const;
@@ -125,4 +125,4 @@ public:
~PListNode() {}
};
-#endif // MACOS_PLIST_H
+#endif // PLIST_H
diff --git a/core/io/resource.cpp b/core/io/resource.cpp
index 04ecabaf27..daa57be76f 100644
--- a/core/io/resource.cpp
+++ b/core/io/resource.cpp
@@ -204,7 +204,58 @@ void Resource::reload_from_file() {
copy_from(s);
}
-Ref<Resource> Resource::duplicate_for_local_scene(Node *p_for_scene, HashMap<Ref<Resource>, Ref<Resource>> &remap_cache) {
+void Resource::_dupe_sub_resources(Variant &r_variant, Node *p_for_scene, HashMap<Ref<Resource>, Ref<Resource>> &p_remap_cache) {
+ switch (r_variant.get_type()) {
+ case Variant::ARRAY: {
+ Array a = r_variant;
+ for (int i = 0; i < a.size(); i++) {
+ _dupe_sub_resources(a[i], p_for_scene, p_remap_cache);
+ }
+ } break;
+ case Variant::DICTIONARY: {
+ Dictionary d = r_variant;
+ List<Variant> keys;
+ d.get_key_list(&keys);
+ for (Variant &k : keys) {
+ if (k.get_type() == Variant::OBJECT) {
+ // Replace in dictionary key.
+ Ref<Resource> sr = k;
+ if (sr.is_valid() && sr->is_local_to_scene()) {
+ if (p_remap_cache.has(sr)) {
+ d[p_remap_cache[sr]] = d[k];
+ d.erase(k);
+ } else {
+ Ref<Resource> dupe = sr->duplicate_for_local_scene(p_for_scene, p_remap_cache);
+ d[dupe] = d[k];
+ d.erase(k);
+ p_remap_cache[sr] = dupe;
+ }
+ }
+ } else {
+ _dupe_sub_resources(k, p_for_scene, p_remap_cache);
+ }
+
+ _dupe_sub_resources(d[k], p_for_scene, p_remap_cache);
+ }
+ } break;
+ case Variant::OBJECT: {
+ Ref<Resource> sr = r_variant;
+ if (sr.is_valid() && sr->is_local_to_scene()) {
+ if (p_remap_cache.has(sr)) {
+ r_variant = p_remap_cache[sr];
+ } else {
+ Ref<Resource> dupe = sr->duplicate_for_local_scene(p_for_scene, p_remap_cache);
+ r_variant = dupe;
+ p_remap_cache[sr] = dupe;
+ }
+ }
+ } break;
+ default: {
+ }
+ }
+}
+
+Ref<Resource> Resource::duplicate_for_local_scene(Node *p_for_scene, HashMap<Ref<Resource>, Ref<Resource>> &p_remap_cache) {
List<PropertyInfo> plist;
get_property_list(&plist);
@@ -217,21 +268,9 @@ Ref<Resource> Resource::duplicate_for_local_scene(Node *p_for_scene, HashMap<Ref
if (!(E.usage & PROPERTY_USAGE_STORAGE)) {
continue;
}
- Variant p = get(E.name);
- if (p.get_type() == Variant::OBJECT) {
- Ref<Resource> sr = p;
- if (sr.is_valid()) {
- if (sr->is_local_to_scene()) {
- if (remap_cache.has(sr)) {
- p = remap_cache[sr];
- } else {
- Ref<Resource> dupe = sr->duplicate_for_local_scene(p_for_scene, remap_cache);
- p = dupe;
- remap_cache[sr] = dupe;
- }
- }
- }
- }
+ Variant p = get(E.name).duplicate(true);
+
+ _dupe_sub_resources(p, p_for_scene, p_remap_cache);
r->set(E.name, p);
}
@@ -239,7 +278,35 @@ Ref<Resource> Resource::duplicate_for_local_scene(Node *p_for_scene, HashMap<Ref
return r;
}
-void Resource::configure_for_local_scene(Node *p_for_scene, HashMap<Ref<Resource>, Ref<Resource>> &remap_cache) {
+void Resource::_find_sub_resources(const Variant &p_variant, HashSet<Ref<Resource>> &p_resources_found) {
+ switch (p_variant.get_type()) {
+ case Variant::ARRAY: {
+ Array a = p_variant;
+ for (int i = 0; i < a.size(); i++) {
+ _find_sub_resources(a[i], p_resources_found);
+ }
+ } break;
+ case Variant::DICTIONARY: {
+ Dictionary d = p_variant;
+ List<Variant> keys;
+ d.get_key_list(&keys);
+ for (const Variant &k : keys) {
+ _find_sub_resources(k, p_resources_found);
+ _find_sub_resources(d[k], p_resources_found);
+ }
+ } break;
+ case Variant::OBJECT: {
+ Ref<Resource> r = p_variant;
+ if (r.is_valid()) {
+ p_resources_found.insert(r);
+ }
+ } break;
+ default: {
+ }
+ }
+}
+
+void Resource::configure_for_local_scene(Node *p_for_scene, HashMap<Ref<Resource>, Ref<Resource>> &p_remap_cache) {
List<PropertyInfo> plist;
get_property_list(&plist);
@@ -251,14 +318,15 @@ void Resource::configure_for_local_scene(Node *p_for_scene, HashMap<Ref<Resource
continue;
}
Variant p = get(E.name);
- if (p.get_type() == Variant::OBJECT) {
- Ref<Resource> sr = p;
- if (sr.is_valid()) {
- if (sr->is_local_to_scene()) {
- if (!remap_cache.has(sr)) {
- sr->configure_for_local_scene(p_for_scene, remap_cache);
- remap_cache[sr] = sr;
- }
+
+ HashSet<Ref<Resource>> sub_resources;
+ _find_sub_resources(p, sub_resources);
+
+ for (Ref<Resource> sr : sub_resources) {
+ if (sr->is_local_to_scene()) {
+ if (!p_remap_cache.has(sr)) {
+ sr->configure_for_local_scene(p_for_scene, p_remap_cache);
+ p_remap_cache[sr] = sr;
}
}
}
diff --git a/core/io/resource.h b/core/io/resource.h
index 610c2150db..b885b773ac 100644
--- a/core/io/resource.h
+++ b/core/io/resource.h
@@ -74,6 +74,9 @@ private:
SelfList<Resource> remapped_list;
+ void _dupe_sub_resources(Variant &r_variant, Node *p_for_scene, HashMap<Ref<Resource>, Ref<Resource>> &p_remap_cache);
+ void _find_sub_resources(const Variant &p_variant, HashSet<Ref<Resource>> &p_resources_found);
+
protected:
virtual void _resource_path_changed();
static void _bind_methods();
@@ -111,8 +114,8 @@ public:
String get_scene_unique_id() const;
virtual Ref<Resource> duplicate(bool p_subresources = false) const;
- Ref<Resource> duplicate_for_local_scene(Node *p_for_scene, HashMap<Ref<Resource>, Ref<Resource>> &remap_cache);
- void configure_for_local_scene(Node *p_for_scene, HashMap<Ref<Resource>, Ref<Resource>> &remap_cache);
+ Ref<Resource> duplicate_for_local_scene(Node *p_for_scene, HashMap<Ref<Resource>, Ref<Resource>> &p_remap_cache);
+ void configure_for_local_scene(Node *p_for_scene, HashMap<Ref<Resource>, Ref<Resource>> &p_remap_cache);
void set_local_to_scene(bool p_enable);
bool is_local_to_scene() const;
diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp
index 0c7764392a..ba11d84bce 100644
--- a/core/io/resource_loader.cpp
+++ b/core/io/resource_loader.cpp
@@ -340,7 +340,7 @@ void ResourceLoader::_thread_load_function(void *p_userdata) {
if (load_task.resource.is_valid()) {
if (load_task.cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE) {
- load_task.resource->set_path(load_task.local_path, load_task.cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE);
+ load_task.resource->set_path(load_task.local_path);
} else if (!load_task.local_path.is_resource_file()) {
load_task.resource->set_path_cache(load_task.local_path);
}
@@ -361,17 +361,6 @@ void ResourceLoader::_thread_load_function(void *p_userdata) {
if (_loaded_callback) {
_loaded_callback(load_task.resource, load_task.local_path);
}
- } else if (load_task.cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE) {
- Ref<Resource> existing = ResourceCache::get_ref(load_task.local_path);
- if (existing.is_valid()) {
- load_task.resource = existing;
- load_task.status = THREAD_LOAD_LOADED;
- load_task.progress = 1.0;
-
- if (_loaded_callback) {
- _loaded_callback(load_task.resource, load_task.local_path);
- }
- }
}
thread_load_mutex.unlock();
@@ -474,7 +463,7 @@ Ref<ResourceLoader::LoadToken> ResourceLoader::_load_start(const String &p_path,
load_task.type_hint = p_type_hint;
load_task.cache_mode = p_cache_mode;
load_task.use_sub_threads = p_thread_mode == LOAD_THREAD_DISTRIBUTE;
- if (p_cache_mode == ResourceFormatLoader::CACHE_MODE_REUSE) {
+ if (p_cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE) {
Ref<Resource> existing = ResourceCache::get_ref(local_path);
if (existing.is_valid()) {
//referencing is fine
@@ -641,15 +630,16 @@ Ref<Resource> ResourceLoader::_load_complete_inner(LoadToken &p_load_token, Erro
if (load_task.task_id != 0) {
// Loading thread is in the worker pool.
- load_task.awaited = true;
thread_load_mutex.unlock();
Error err = WorkerThreadPool::get_singleton()->wait_for_task_completion(load_task.task_id);
if (err == ERR_BUSY) {
- // The WorkerThreadPool has scheduled tasks in a way that the current load depends on
- // another one in a lower stack frame. Restart such load here. When the stack is eventually
- // unrolled, the original load will have been notified to go on.
+ // The WorkerThreadPool has reported that the current task wants to await on an older one.
+ // That't not allowed for safety, to avoid deadlocks. Fortunately, though, in the context of
+ // resource loading that means that the task to wait for can be restarted here to break the
+ // cycle, with as much recursion into this process as needed.
+ // When the stack is eventually unrolled, the original load will have been notified to go on.
#ifdef DEV_ENABLED
- print_verbose("ResourceLoader: Load task happened to wait on another one deep in the call stack. Attempting to avoid deadlock by re-issuing the load now.");
+ print_verbose("ResourceLoader: Potential for deadlock detected in task dependency. Attempting to avoid it by re-issuing the load now.");
#endif
// CACHE_MODE_IGNORE is needed because, otherwise, the new request would just see there's
// an ongoing load for that resource and wait for it again. This value forces a new load.
@@ -663,6 +653,7 @@ Ref<Resource> ResourceLoader::_load_complete_inner(LoadToken &p_load_token, Erro
} else {
DEV_ASSERT(err == OK);
thread_load_mutex.lock();
+ load_task.awaited = true;
}
} else {
// Loading thread is main or user thread.
diff --git a/core/object/script_language.h b/core/object/script_language.h
index 69da50f074..66106bf139 100644
--- a/core/object/script_language.h
+++ b/core/object/script_language.h
@@ -243,7 +243,7 @@ public:
virtual void get_doc_comment_delimiters(List<String> *p_delimiters) const = 0;
virtual void get_string_delimiters(List<String> *p_delimiters) const = 0;
virtual Ref<Script> make_template(const String &p_template, const String &p_class_name, const String &p_base_class_name) const { return Ref<Script>(); }
- virtual Vector<ScriptTemplate> get_built_in_templates(StringName p_object) { return Vector<ScriptTemplate>(); }
+ virtual Vector<ScriptTemplate> get_built_in_templates(const StringName &p_object) { return Vector<ScriptTemplate>(); }
virtual bool is_using_templates() { return false; }
virtual bool validate(const String &p_script, const String &p_path = "", List<String> *r_functions = nullptr, List<ScriptError> *r_errors = nullptr, List<Warning> *r_warnings = nullptr, HashSet<int> *r_safe_lines = nullptr) const = 0;
virtual String validate_path(const String &p_path) const { return ""; }
diff --git a/core/object/script_language_extension.h b/core/object/script_language_extension.h
index 852b2aebd8..8b01667519 100644
--- a/core/object/script_language_extension.h
+++ b/core/object/script_language_extension.h
@@ -265,7 +265,7 @@ public:
GDVIRTUAL1RC(TypedArray<Dictionary>, _get_built_in_templates, StringName)
- virtual Vector<ScriptTemplate> get_built_in_templates(StringName p_object) override {
+ virtual Vector<ScriptTemplate> get_built_in_templates(const StringName &p_object) override {
TypedArray<Dictionary> ret;
GDVIRTUAL_REQUIRED_CALL(_get_built_in_templates, p_object, ret);
Vector<ScriptTemplate> stret;
diff --git a/core/object/worker_thread_pool.cpp b/core/object/worker_thread_pool.cpp
index 631767219f..8e8a2ef06b 100644
--- a/core/object/worker_thread_pool.cpp
+++ b/core/object/worker_thread_pool.cpp
@@ -33,6 +33,7 @@
#include "core/object/script_language.h"
#include "core/os/os.h"
#include "core/os/thread_safe.h"
+#include "core/templates/command_queue_mt.h"
void WorkerThreadPool::Task::free_template_userdata() {
ERR_FAIL_NULL(template_userdata);
@@ -43,24 +44,17 @@ void WorkerThreadPool::Task::free_template_userdata() {
WorkerThreadPool *WorkerThreadPool::singleton = nullptr;
-void WorkerThreadPool::_process_task_queue() {
- task_mutex.lock();
- Task *task = task_queue.first()->self();
- task_queue.remove(task_queue.first());
- task_mutex.unlock();
- _process_task(task);
-}
+thread_local CommandQueueMT *WorkerThreadPool::flushing_cmd_queue = nullptr;
void WorkerThreadPool::_process_task(Task *p_task) {
- bool low_priority = p_task->low_priority;
- int pool_thread_index = -1;
- Task *prev_low_prio_task = nullptr; // In case this is recursively called.
+ int pool_thread_index = thread_ids[Thread::get_caller_id()];
+ ThreadData &curr_thread = threads[pool_thread_index];
+ Task *prev_task = nullptr; // In case this is recursively called.
+ bool safe_for_nodes_backup = is_current_thread_safe_for_nodes();
- if (!use_native_low_priority_threads) {
+ {
// Tasks must start with this unset. They are free to set-and-forget otherwise.
set_current_thread_safe_for_nodes(false);
- pool_thread_index = thread_ids[Thread::get_caller_id()];
- ThreadData &curr_thread = threads[pool_thread_index];
// Since the WorkerThreadPool is started before the script server,
// its pre-created threads can't have ScriptServer::thread_enter() called on them early.
// Therefore, we do it late at the first opportunity, so in case the task
@@ -71,13 +65,8 @@ void WorkerThreadPool::_process_task(Task *p_task) {
}
task_mutex.lock();
p_task->pool_thread_index = pool_thread_index;
- if (low_priority) {
- low_priority_tasks_running++;
- prev_low_prio_task = curr_thread.current_low_prio_task;
- curr_thread.current_low_prio_task = p_task;
- } else {
- curr_thread.current_low_prio_task = nullptr;
- }
+ prev_task = curr_thread.current_task;
+ curr_thread.current_task = p_task;
task_mutex.unlock();
}
@@ -111,33 +100,24 @@ void WorkerThreadPool::_process_task(Task *p_task) {
memdelete(p_task->template_userdata); // This is no longer needed at this point, so get rid of it.
}
- if (low_priority && use_native_low_priority_threads) {
- p_task->completed = true;
- p_task->done_semaphore.post();
- if (do_post) {
- p_task->group->completed.set_to(true);
- }
- } else {
- if (do_post) {
- p_task->group->done_semaphore.post();
- p_task->group->completed.set_to(true);
- }
- uint32_t max_users = p_task->group->tasks_used + 1; // Add 1 because the thread waiting for it is also user. Read before to avoid another thread freeing task after increment.
- uint32_t finished_users = p_task->group->finished.increment();
-
- if (finished_users == max_users) {
- // Get rid of the group, because nobody else is using it.
- task_mutex.lock();
- group_allocator.free(p_task->group);
- task_mutex.unlock();
- }
-
- // For groups, tasks get rid of themselves.
+ if (do_post) {
+ p_task->group->done_semaphore.post();
+ p_task->group->completed.set_to(true);
+ }
+ uint32_t max_users = p_task->group->tasks_used + 1; // Add 1 because the thread waiting for it is also user. Read before to avoid another thread freeing task after increment.
+ uint32_t finished_users = p_task->group->finished.increment();
+ if (finished_users == max_users) {
+ // Get rid of the group, because nobody else is using it.
task_mutex.lock();
- task_allocator.free(p_task);
+ group_allocator.free(p_task->group);
task_mutex.unlock();
}
+
+ // For groups, tasks get rid of themselves.
+
+ task_mutex.lock();
+ task_allocator.free(p_task);
} else {
if (p_task->native_func) {
p_task->native_func(p_task->native_func_userdata);
@@ -150,88 +130,162 @@ void WorkerThreadPool::_process_task(Task *p_task) {
task_mutex.lock();
p_task->completed = true;
- for (uint8_t i = 0; i < p_task->waiting; i++) {
- p_task->done_semaphore.post();
+ p_task->pool_thread_index = -1;
+ if (p_task->waiting_user) {
+ p_task->done_semaphore.post(p_task->waiting_user);
}
- if (!use_native_low_priority_threads) {
- p_task->pool_thread_index = -1;
+ // Let awaiters know.
+ for (uint32_t i = 0; i < threads.size(); i++) {
+ if (threads[i].awaited_task == p_task) {
+ threads[i].cond_var.notify_one();
+ threads[i].signaled = true;
+ }
}
- task_mutex.unlock(); // Keep mutex down to here since on unlock the task may be freed.
}
- // Task may have been freed by now (all callers notified).
- p_task = nullptr;
-
- if (!use_native_low_priority_threads) {
- bool post = false;
- task_mutex.lock();
- ThreadData &curr_thread = threads[pool_thread_index];
- curr_thread.current_low_prio_task = prev_low_prio_task;
- if (low_priority) {
+ {
+ curr_thread.current_task = prev_task;
+ if (p_task->low_priority) {
low_priority_threads_used--;
- low_priority_tasks_running--;
- // A low prioriry task was freed, so see if we can move a pending one to the high priority queue.
- if (_try_promote_low_priority_task()) {
- post = true;
- }
- if (low_priority_tasks_awaiting_others == low_priority_tasks_running) {
- _prevent_low_prio_saturation_deadlock();
+ if (_try_promote_low_priority_task()) {
+ if (prev_task) { // Otherwise, this thread will catch it.
+ _notify_threads(&curr_thread, 1, 0);
+ }
}
}
+
task_mutex.unlock();
- if (post) {
- task_available_semaphore.post();
- }
}
+
+ set_current_thread_safe_for_nodes(safe_for_nodes_backup);
}
void WorkerThreadPool::_thread_function(void *p_user) {
+ ThreadData *thread_data = (ThreadData *)p_user;
while (true) {
- singleton->task_available_semaphore.wait();
- if (singleton->exit_threads) {
- break;
+ Task *task_to_process = nullptr;
+ {
+ MutexLock lock(singleton->task_mutex);
+ if (singleton->exit_threads) {
+ return;
+ }
+ thread_data->signaled = false;
+
+ if (singleton->task_queue.first()) {
+ task_to_process = singleton->task_queue.first()->self();
+ singleton->task_queue.remove(singleton->task_queue.first());
+ } else {
+ thread_data->cond_var.wait(lock);
+ DEV_ASSERT(singleton->exit_threads || thread_data->signaled);
+ }
}
- singleton->_process_task_queue();
- }
-}
-void WorkerThreadPool::_native_low_priority_thread_function(void *p_user) {
- Task *task = (Task *)p_user;
- singleton->_process_task(task);
+ if (task_to_process) {
+ singleton->_process_task(task_to_process);
+ }
+ }
}
-void WorkerThreadPool::_post_task(Task *p_task, bool p_high_priority) {
+void WorkerThreadPool::_post_tasks_and_unlock(Task **p_tasks, uint32_t p_count, bool p_high_priority) {
// Fall back to processing on the calling thread if there are no worker threads.
// Separated into its own variable to make it easier to extend this logic
// in custom builds.
bool process_on_calling_thread = threads.size() == 0;
if (process_on_calling_thread) {
- _process_task(p_task);
+ task_mutex.unlock();
+ for (uint32_t i = 0; i < p_count; i++) {
+ _process_task(p_tasks[i]);
+ }
return;
}
- task_mutex.lock();
- p_task->low_priority = !p_high_priority;
- if (!p_high_priority && use_native_low_priority_threads) {
- p_task->low_priority_thread = native_thread_allocator.alloc();
- task_mutex.unlock();
+ uint32_t to_process = 0;
+ uint32_t to_promote = 0;
- if (p_task->group) {
- p_task->group->low_priority_native_tasks.push_back(p_task);
+ ThreadData *caller_pool_thread = thread_ids.has(Thread::get_caller_id()) ? &threads[thread_ids[Thread::get_caller_id()]] : nullptr;
+
+ for (uint32_t i = 0; i < p_count; i++) {
+ p_tasks[i]->low_priority = !p_high_priority;
+ if (p_high_priority || low_priority_threads_used < max_low_priority_threads) {
+ task_queue.add_last(&p_tasks[i]->task_elem);
+ if (!p_high_priority) {
+ low_priority_threads_used++;
+ }
+ to_process++;
+ } else {
+ // Too many threads using low priority, must go to queue.
+ low_priority_task_queue.add_last(&p_tasks[i]->task_elem);
+ to_promote++;
}
- p_task->low_priority_thread->start(_native_low_priority_thread_function, p_task); // Pask task directly to thread.
- } else if (p_high_priority || low_priority_threads_used < max_low_priority_threads) {
- task_queue.add_last(&p_task->task_elem);
- if (!p_high_priority) {
- low_priority_threads_used++;
+ }
+
+ _notify_threads(caller_pool_thread, to_process, to_promote);
+
+ task_mutex.unlock();
+}
+
+void WorkerThreadPool::_notify_threads(const ThreadData *p_current_thread_data, uint32_t p_process_count, uint32_t p_promote_count) {
+ uint32_t to_process = p_process_count;
+ uint32_t to_promote = p_promote_count;
+
+ // This is where which threads are awaken is decided according to the workload.
+ // Threads that will anyway have a chance to check the situation and process/promote tasks
+ // are excluded from being notified. Others will be tried anyway to try to distribute load.
+ // The current thread, if is a pool thread, is also excluded depending on the promoting/processing
+ // needs because it will anyway loop again. However, it will contribute to decreasing the count,
+ // which helps reducing sync traffic.
+
+ uint32_t thread_count = threads.size();
+
+ // First round:
+ // 1. For processing: notify threads that are not running tasks, to keep the stacks as shallow as possible.
+ // 2. For promoting: since it's exclusive with processing, we fin threads able to promote low-prio tasks now.
+ for (uint32_t i = 0;
+ i < thread_count && (to_process || to_promote);
+ i++, notify_index = (notify_index + 1) % thread_count) {
+ ThreadData &th = threads[notify_index];
+
+ if (th.signaled) {
+ continue;
+ }
+ if (th.current_task) {
+ // Good thread for promoting low-prio?
+ if (to_promote && th.awaited_task && th.current_task->low_priority) {
+ if (likely(&th != p_current_thread_data)) {
+ th.cond_var.notify_one();
+ }
+ th.signaled = true;
+ to_promote--;
+ }
+ } else {
+ if (to_process) {
+ if (likely(&th != p_current_thread_data)) {
+ th.cond_var.notify_one();
+ }
+ th.signaled = true;
+ to_process--;
+ }
+ }
+ }
+
+ // Second round:
+ // For processing: if the first round wasn't enough, let's try now with threads processing tasks but currently awaiting.
+ for (uint32_t i = 0;
+ i < thread_count && to_process;
+ i++, notify_index = (notify_index + 1) % thread_count) {
+ ThreadData &th = threads[notify_index];
+
+ if (th.signaled) {
+ continue;
+ }
+ if (th.awaited_task) {
+ if (likely(&th != p_current_thread_data)) {
+ th.cond_var.notify_one();
+ }
+ th.signaled = true;
+ to_process--;
}
- task_mutex.unlock();
- task_available_semaphore.post();
- } else {
- // Too many threads using low priority, must go to queue.
- low_priority_task_queue.add_last(&p_task->task_elem);
- task_mutex.unlock();
}
}
@@ -247,23 +301,6 @@ bool WorkerThreadPool::_try_promote_low_priority_task() {
}
}
-void WorkerThreadPool::_prevent_low_prio_saturation_deadlock() {
- if (low_priority_tasks_awaiting_others == low_priority_tasks_running) {
-#ifdef DEV_ENABLED
- print_verbose("WorkerThreadPool: Low-prio slots saturated with tasks all waiting for other low-prio tasks. Attempting to avoid deadlock by scheduling one extra task.");
-#endif
- // In order not to create dependency cycles, we can only schedule the next one.
- // We'll keep doing the same until the deadlock is broken,
- SelfList<Task> *to_promote = low_priority_task_queue.first();
- if (to_promote) {
- low_priority_task_queue.remove(to_promote);
- task_queue.add_last(to_promote);
- low_priority_threads_used++;
- task_available_semaphore.post();
- }
- }
-}
-
WorkerThreadPool::TaskID WorkerThreadPool::add_native_task(void (*p_func)(void *), void *p_userdata, bool p_high_priority, const String &p_description) {
return _add_task(Callable(), p_func, p_userdata, nullptr, p_high_priority, p_description);
}
@@ -273,15 +310,15 @@ WorkerThreadPool::TaskID WorkerThreadPool::_add_task(const Callable &p_callable,
// Get a free task
Task *task = task_allocator.alloc();
TaskID id = last_task++;
+ task->self = id;
task->callable = p_callable;
task->native_func = p_func;
task->native_func_userdata = p_userdata;
task->description = p_description;
task->template_userdata = p_template_userdata;
tasks.insert(id, task);
- task_mutex.unlock();
- _post_task(task, p_high_priority);
+ _post_tasks_and_unlock(&task, 1, p_high_priority);
return id;
}
@@ -313,105 +350,117 @@ Error WorkerThreadPool::wait_for_task_completion(TaskID p_task_id) {
}
Task *task = *taskp;
- if (!task->completed) {
- if (!use_native_low_priority_threads && task->pool_thread_index != -1) { // Otherwise, it's not running yet.
- int caller_pool_th_index = thread_ids.has(Thread::get_caller_id()) ? thread_ids[Thread::get_caller_id()] : -1;
- if (caller_pool_th_index == task->pool_thread_index) {
- // Deadlock prevention.
- // Waiting for a task run on this same thread? That means the task to be awaited started waiting as well
- // and another task was run to make use of the thread in the meantime, with enough bad luck as to
- // the need to wait for the original task arose in turn.
- // In other words, the task we want to wait for is buried in the stack.
- // Let's report the caller about the issue to it handles as it sees fit.
- task_mutex.unlock();
- return ERR_BUSY;
- }
+ if (task->completed) {
+ if (task->waiting_pool == 0 && task->waiting_user == 0) {
+ tasks.erase(p_task_id);
+ task_allocator.free(task);
}
+ task_mutex.unlock();
+ return OK;
+ }
+
+ ThreadData *caller_pool_thread = thread_ids.has(Thread::get_caller_id()) ? &threads[thread_ids[Thread::get_caller_id()]] : nullptr;
+ if (caller_pool_thread && p_task_id <= caller_pool_thread->current_task->self) {
+ // Deadlock prevention:
+ // When a pool thread wants to wait for an older task, the following situations can happen:
+ // 1. Awaited task is deep in the stack of the awaiter.
+ // 2. A group of awaiter threads end up depending on some tasks buried in the stack
+ // of their worker threads in such a way that progress can't be made.
+ // Both would entail a deadlock. Some may be handled here in the WorkerThreadPool
+ // with some extra logic and bookkeeping. However, there would still be unavoidable
+ // cases of deadlock because of the way waiting threads process outstanding tasks.
+ // Taking into account there's no feasible solution for every possible case
+ // with the current design, we just simply reject attempts to await on older tasks,
+ // with a specific error code that signals the situation so the caller can handle it.
+ task_mutex.unlock();
+ return ERR_BUSY;
+ }
- task->waiting++;
-
- bool is_low_prio_waiting_for_another = false;
- if (!use_native_low_priority_threads) {
- // Deadlock prevention:
- // If all low-prio tasks are waiting for other low-prio tasks and there are no more free low-prio slots,
- // we have a no progressable situation. We can apply a workaround, consisting in promoting an awaited queued
- // low-prio task to the schedule queue so it can run and break the "impasse".
- // NOTE: A similar reasoning could be made about high priority tasks, but there are usually much more
- // than low-prio. Therefore, a deadlock there would only happen when dealing with a very complex task graph
- // or when there are too few worker threads (limited platforms or exotic settings). If that turns out to be
- // an issue in the real world, a further fix can be applied against that.
- if (task->low_priority) {
- bool awaiter_is_a_low_prio_task = thread_ids.has(Thread::get_caller_id()) && threads[thread_ids[Thread::get_caller_id()]].current_low_prio_task;
- if (awaiter_is_a_low_prio_task) {
- is_low_prio_waiting_for_another = true;
- low_priority_tasks_awaiting_others++;
- if (low_priority_tasks_awaiting_others == low_priority_tasks_running) {
- _prevent_low_prio_saturation_deadlock();
+ if (caller_pool_thread) {
+ task->waiting_pool++;
+ } else {
+ task->waiting_user++;
+ }
+
+ task_mutex.unlock();
+
+ if (caller_pool_thread) {
+ while (true) {
+ Task *task_to_process = nullptr;
+ {
+ MutexLock lock(task_mutex);
+ bool was_signaled = caller_pool_thread->signaled;
+ caller_pool_thread->signaled = false;
+
+ if (task->completed) {
+ // This thread was awaken also for some reason, but it's about to exit.
+ // Let's find out what may be pending and forward the requests.
+ if (!exit_threads && was_signaled) {
+ uint32_t to_process = task_queue.first() ? 1 : 0;
+ uint32_t to_promote = caller_pool_thread->current_task->low_priority && low_priority_task_queue.first() ? 1 : 0;
+ if (to_process || to_promote) {
+ // This thread must be left alone since it won't loop again.
+ caller_pool_thread->signaled = true;
+ _notify_threads(caller_pool_thread, to_process, to_promote);
+ }
+ }
+
+ task->waiting_pool--;
+ if (task->waiting_pool == 0 && task->waiting_user == 0) {
+ tasks.erase(p_task_id);
+ task_allocator.free(task);
}
+
+ break;
}
- }
- }
- task_mutex.unlock();
+ if (!exit_threads) {
+ // This is a thread from the pool. It shouldn't just idle.
+ // Let's try to process other tasks while we wait.
- if (use_native_low_priority_threads && task->low_priority) {
- task->done_semaphore.wait();
- } else {
- bool current_is_pool_thread = thread_ids.has(Thread::get_caller_id());
- if (current_is_pool_thread) {
- // We are an actual process thread, we must not be blocked so continue processing stuff if available.
- bool must_exit = false;
- while (true) {
- if (task->done_semaphore.try_wait()) {
- // If done, exit
- break;
+ if (caller_pool_thread->current_task->low_priority && low_priority_task_queue.first()) {
+ if (_try_promote_low_priority_task()) {
+ _notify_threads(caller_pool_thread, 1, 0);
+ }
+ }
+
+ if (singleton->task_queue.first()) {
+ task_to_process = task_queue.first()->self();
+ task_queue.remove(task_queue.first());
}
- if (!must_exit) {
- if (task_available_semaphore.try_wait()) {
- if (exit_threads) {
- must_exit = true;
- } else {
- // Solve tasks while they are around.
- bool safe_for_nodes_backup = is_current_thread_safe_for_nodes();
- _process_task_queue();
- set_current_thread_safe_for_nodes(safe_for_nodes_backup);
- continue;
- }
- } else if (!use_native_low_priority_threads && task->low_priority) {
- // A low prioriry task started waiting, so see if we can move a pending one to the high priority queue.
- task_mutex.lock();
- bool post = _try_promote_low_priority_task();
- task_mutex.unlock();
- if (post) {
- task_available_semaphore.post();
- }
+
+ if (!task_to_process) {
+ caller_pool_thread->awaited_task = task;
+
+ if (flushing_cmd_queue) {
+ flushing_cmd_queue->unlock();
}
+ caller_pool_thread->cond_var.wait(lock);
+ if (flushing_cmd_queue) {
+ flushing_cmd_queue->lock();
+ }
+
+ DEV_ASSERT(exit_threads || caller_pool_thread->signaled || task->completed);
+ caller_pool_thread->awaited_task = nullptr;
}
- OS::get_singleton()->delay_usec(1); // Microsleep, this could be converted to waiting for multiple objects in supported platforms for a bit more performance.
}
- } else {
- task->done_semaphore.wait();
}
- }
- task_mutex.lock();
- if (is_low_prio_waiting_for_another) {
- low_priority_tasks_awaiting_others--;
+ if (task_to_process) {
+ _process_task(task_to_process);
+ }
}
-
- task->waiting--;
- }
-
- if (task->waiting == 0) {
- if (use_native_low_priority_threads && task->low_priority) {
- task->low_priority_thread->wait_to_finish();
- native_thread_allocator.free(task->low_priority_thread);
+ } else {
+ task->done_semaphore.wait();
+ task_mutex.lock();
+ task->waiting_user--;
+ if (task->waiting_pool == 0 && task->waiting_user == 0) {
+ tasks.erase(p_task_id);
+ task_allocator.free(task);
}
- tasks.erase(p_task_id);
- task_allocator.free(task);
+ task_mutex.unlock();
}
- task_mutex.unlock();
return OK;
}
@@ -455,11 +504,8 @@ WorkerThreadPool::GroupID WorkerThreadPool::_add_group_task(const Callable &p_ca
}
groups[id] = group;
- task_mutex.unlock();
- for (int i = 0; i < p_tasks; i++) {
- _post_task(tasks_posted[i], p_high_priority);
- }
+ _post_tasks_and_unlock(tasks_posted, p_tasks, p_high_priority);
return id;
}
@@ -502,22 +548,17 @@ void WorkerThreadPool::wait_for_group_task_completion(GroupID p_group) {
if (!groupp) {
ERR_FAIL_MSG("Invalid Group ID");
}
- Group *group = *groupp;
- if (group->low_priority_native_tasks.size() > 0) {
- for (Task *task : group->low_priority_native_tasks) {
- task->low_priority_thread->wait_to_finish();
- task_mutex.lock();
- native_thread_allocator.free(task->low_priority_thread);
- task_allocator.free(task);
- task_mutex.unlock();
- }
+ {
+ Group *group = *groupp;
- task_mutex.lock();
- group_allocator.free(group);
- task_mutex.unlock();
- } else {
+ if (flushing_cmd_queue) {
+ flushing_cmd_queue->unlock();
+ }
group->done_semaphore.wait();
+ if (flushing_cmd_queue) {
+ flushing_cmd_queue->lock();
+ }
uint32_t max_users = group->tasks_used + 1; // Add 1 because the thread waiting for it is also user. Read before to avoid another thread freeing task after increment.
uint32_t finished_users = group->finished.increment(); // fetch happens before inc, so increment later.
@@ -540,19 +581,23 @@ int WorkerThreadPool::get_thread_index() {
return singleton->thread_ids.has(tid) ? singleton->thread_ids[tid] : -1;
}
-void WorkerThreadPool::init(int p_thread_count, bool p_use_native_threads_low_priority, float p_low_priority_task_ratio) {
+void WorkerThreadPool::thread_enter_command_queue_mt_flush(CommandQueueMT *p_queue) {
+ ERR_FAIL_COND(flushing_cmd_queue != nullptr);
+ flushing_cmd_queue = p_queue;
+}
+
+void WorkerThreadPool::thread_exit_command_queue_mt_flush() {
+ ERR_FAIL_NULL(flushing_cmd_queue);
+ flushing_cmd_queue = nullptr;
+}
+
+void WorkerThreadPool::init(int p_thread_count, float p_low_priority_task_ratio) {
ERR_FAIL_COND(threads.size() > 0);
if (p_thread_count < 0) {
p_thread_count = OS::get_singleton()->get_default_thread_pool_size();
}
- if (p_use_native_threads_low_priority) {
- max_low_priority_threads = 0;
- } else {
- max_low_priority_threads = CLAMP(p_thread_count * p_low_priority_task_ratio, 1, p_thread_count - 1);
- }
-
- use_native_low_priority_threads = p_use_native_threads_low_priority;
+ max_low_priority_threads = CLAMP(p_thread_count * p_low_priority_task_ratio, 1, p_thread_count - 1);
threads.resize(p_thread_count);
@@ -568,24 +613,33 @@ void WorkerThreadPool::finish() {
return;
}
- task_mutex.lock();
- SelfList<Task> *E = low_priority_task_queue.first();
- while (E) {
- print_error("Task waiting was never re-claimed: " + E->self()->description);
- E = E->next();
+ {
+ MutexLock lock(task_mutex);
+ SelfList<Task> *E = low_priority_task_queue.first();
+ while (E) {
+ print_error("Task waiting was never re-claimed: " + E->self()->description);
+ E = E->next();
+ }
}
- task_mutex.unlock();
- exit_threads = true;
-
- for (uint32_t i = 0; i < threads.size(); i++) {
- task_available_semaphore.post();
+ {
+ MutexLock lock(task_mutex);
+ exit_threads = true;
+ }
+ for (ThreadData &data : threads) {
+ data.cond_var.notify_one();
}
-
for (ThreadData &data : threads) {
data.thread.wait_to_finish();
}
+ {
+ MutexLock lock(task_mutex);
+ for (KeyValue<TaskID, Task *> &E : tasks) {
+ task_allocator.free(E.value);
+ }
+ }
+
threads.clear();
}
diff --git a/core/object/worker_thread_pool.h b/core/object/worker_thread_pool.h
index dd56f95cae..c9921c808d 100644
--- a/core/object/worker_thread_pool.h
+++ b/core/object/worker_thread_pool.h
@@ -31,6 +31,7 @@
#ifndef WORKER_THREAD_POOL_H
#define WORKER_THREAD_POOL_H
+#include "core/os/condition_variable.h"
#include "core/os/memory.h"
#include "core/os/os.h"
#include "core/os/semaphore.h"
@@ -40,6 +41,8 @@
#include "core/templates/rid.h"
#include "core/templates/safe_refcount.h"
+class CommandQueueMT;
+
class WorkerThreadPool : public Object {
GDCLASS(WorkerThreadPool, Object)
public:
@@ -60,7 +63,7 @@ private:
};
struct Group {
- GroupID self;
+ GroupID self = -1;
SafeNumeric<uint32_t> index;
SafeNumeric<uint32_t> completed_index;
uint32_t max = 0;
@@ -68,23 +71,23 @@ private:
SafeFlag completed;
SafeNumeric<uint32_t> finished;
uint32_t tasks_used = 0;
- TightLocalVector<Task *> low_priority_native_tasks;
};
struct Task {
+ TaskID self = -1;
Callable callable;
void (*native_func)(void *) = nullptr;
void (*native_group_func)(void *, uint32_t) = nullptr;
void *native_func_userdata = nullptr;
String description;
- Semaphore done_semaphore;
+ Semaphore done_semaphore; // For user threads awaiting.
bool completed = false;
Group *group = nullptr;
SelfList<Task> task_elem;
- uint32_t waiting = 0;
+ uint32_t waiting_pool = 0;
+ uint32_t waiting_user = 0;
bool low_priority = false;
BaseTemplateUserdata *template_userdata = nullptr;
- Thread *low_priority_thread = nullptr;
int pool_thread_index = -1;
void free_template_userdata();
@@ -92,51 +95,65 @@ private:
task_elem(this) {}
};
- PagedAllocator<Task> task_allocator;
- PagedAllocator<Group> group_allocator;
- PagedAllocator<Thread> native_thread_allocator;
+ static const uint32_t TASKS_PAGE_SIZE = 1024;
+ static const uint32_t GROUPS_PAGE_SIZE = 256;
+
+ PagedAllocator<Task, false, TASKS_PAGE_SIZE> task_allocator;
+ PagedAllocator<Group, false, GROUPS_PAGE_SIZE> group_allocator;
SelfList<Task>::List low_priority_task_queue;
SelfList<Task>::List task_queue;
- Mutex task_mutex;
- Semaphore task_available_semaphore;
+ BinaryMutex task_mutex;
struct ThreadData {
- uint32_t index;
+ uint32_t index = 0;
Thread thread;
- Task *current_low_prio_task = nullptr;
bool ready_for_scripting = false;
+ bool signaled = false;
+ Task *current_task = nullptr;
+ Task *awaited_task = nullptr; // Null if not awaiting the condition variable. Special value for idle-waiting.
+ ConditionVariable cond_var;
};
TightLocalVector<ThreadData> threads;
bool exit_threads = false;
HashMap<Thread::ID, int> thread_ids;
- HashMap<TaskID, Task *> tasks;
- HashMap<GroupID, Group *> groups;
+ HashMap<
+ TaskID,
+ Task *,
+ HashMapHasherDefault,
+ HashMapComparatorDefault<TaskID>,
+ PagedAllocator<HashMapElement<TaskID, Task *>, false, TASKS_PAGE_SIZE>>
+ tasks;
+ HashMap<
+ GroupID,
+ Group *,
+ HashMapHasherDefault,
+ HashMapComparatorDefault<GroupID>,
+ PagedAllocator<HashMapElement<GroupID, Group *>, false, GROUPS_PAGE_SIZE>>
+ groups;
- bool use_native_low_priority_threads = false;
uint32_t max_low_priority_threads = 0;
uint32_t low_priority_threads_used = 0;
- uint32_t low_priority_tasks_running = 0;
- uint32_t low_priority_tasks_awaiting_others = 0;
+ uint32_t notify_index = 0; // For rotating across threads, no help distributing load.
uint64_t last_task = 1;
static void _thread_function(void *p_user);
- static void _native_low_priority_thread_function(void *p_user);
- void _process_task_queue();
void _process_task(Task *task);
- void _post_task(Task *p_task, bool p_high_priority);
+ void _post_tasks_and_unlock(Task **p_tasks, uint32_t p_count, bool p_high_priority);
+ void _notify_threads(const ThreadData *p_current_thread_data, uint32_t p_process_count, uint32_t p_promote_count);
bool _try_promote_low_priority_task();
- void _prevent_low_prio_saturation_deadlock();
static WorkerThreadPool *singleton;
+ static thread_local CommandQueueMT *flushing_cmd_queue;
+
TaskID _add_task(const Callable &p_callable, void (*p_func)(void *), void *p_userdata, BaseTemplateUserdata *p_template_userdata, bool p_high_priority, const String &p_description);
GroupID _add_group_task(const Callable &p_callable, void (*p_func)(void *, uint32_t), void *p_userdata, BaseTemplateUserdata *p_template_userdata, int p_elements, int p_tasks, bool p_high_priority, const String &p_description);
@@ -199,7 +216,10 @@ public:
static WorkerThreadPool *get_singleton() { return singleton; }
static int get_thread_index();
- void init(int p_thread_count = -1, bool p_use_native_threads_low_priority = true, float p_low_priority_task_ratio = 0.3);
+ static void thread_enter_command_queue_mt_flush(CommandQueueMT *p_queue);
+ static void thread_exit_command_queue_mt_flush();
+
+ void init(int p_thread_count = -1, float p_low_priority_task_ratio = 0.3);
void finish();
WorkerThreadPool();
~WorkerThreadPool();
diff --git a/core/os/condition_variable.h b/core/os/condition_variable.h
index 6a6996019d..6a49ced31b 100644
--- a/core/os/condition_variable.h
+++ b/core/os/condition_variable.h
@@ -31,6 +31,8 @@
#ifndef CONDITION_VARIABLE_H
#define CONDITION_VARIABLE_H
+#include "core/os/mutex.h"
+
#ifdef MINGW_ENABLED
#define MINGW_STDTHREAD_REDUNDANCY_WARNING
#include "thirdparty/mingw-std-threads/mingw.condition_variable.h"
diff --git a/core/os/semaphore.h b/core/os/semaphore.h
index 8bb1529bbd..b8ae35b86b 100644
--- a/core/os/semaphore.h
+++ b/core/os/semaphore.h
@@ -58,10 +58,12 @@ private:
#endif
public:
- _ALWAYS_INLINE_ void post() const {
+ _ALWAYS_INLINE_ void post(uint32_t p_count = 1) const {
std::lock_guard lock(mutex);
- count++;
- condition.notify_one();
+ count += p_count;
+ for (uint32_t i = 0; i < p_count; ++i) {
+ condition.notify_one();
+ }
}
_ALWAYS_INLINE_ void wait() const {
diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp
index 2785d1daa5..82b3d27942 100644
--- a/core/register_core_types.cpp
+++ b/core/register_core_types.cpp
@@ -307,7 +307,6 @@ void register_core_settings() {
GLOBAL_DEF(PropertyInfo(Variant::STRING, "network/tls/certificate_bundle_override", PROPERTY_HINT_FILE, "*.crt"), "");
GLOBAL_DEF("threading/worker_pool/max_threads", -1);
- GLOBAL_DEF("threading/worker_pool/use_system_threads_for_low_priority_tasks", true);
GLOBAL_DEF("threading/worker_pool/low_priority_thread_ratio", 0.3);
}
diff --git a/core/string/translation.cpp b/core/string/translation.cpp
index 8fcf2b24b5..829c9bf777 100644
--- a/core/string/translation.cpp
+++ b/core/string/translation.cpp
@@ -881,7 +881,7 @@ StringName TranslationServer::tool_pseudolocalize(const StringName &p_message) c
String TranslationServer::get_override_string(String &p_message) const {
String res;
- for (int i = 0; i < p_message.size(); i++) {
+ for (int i = 0; i < p_message.length(); i++) {
if (pseudolocalization_skip_placeholders_enabled && is_placeholder(p_message, i)) {
res += p_message[i];
res += p_message[i + 1];
@@ -895,7 +895,7 @@ String TranslationServer::get_override_string(String &p_message) const {
String TranslationServer::double_vowels(String &p_message) const {
String res;
- for (int i = 0; i < p_message.size(); i++) {
+ for (int i = 0; i < p_message.length(); i++) {
if (pseudolocalization_skip_placeholders_enabled && is_placeholder(p_message, i)) {
res += p_message[i];
res += p_message[i + 1];
@@ -913,7 +913,7 @@ String TranslationServer::double_vowels(String &p_message) const {
String TranslationServer::replace_with_accented_string(String &p_message) const {
String res;
- for (int i = 0; i < p_message.size(); i++) {
+ for (int i = 0; i < p_message.length(); i++) {
if (pseudolocalization_skip_placeholders_enabled && is_placeholder(p_message, i)) {
res += p_message[i];
res += p_message[i + 1];
@@ -936,7 +936,7 @@ String TranslationServer::wrap_with_fakebidi_characters(String &p_message) const
char32_t fakebidisuffix = U'\u202c';
res += fakebidiprefix;
// The fake bidi unicode gets popped at every newline so pushing it back at every newline.
- for (int i = 0; i < p_message.size(); i++) {
+ for (int i = 0; i < p_message.length(); i++) {
if (p_message[i] == '\n') {
res += fakebidisuffix;
res += p_message[i];
@@ -978,7 +978,7 @@ const char32_t *TranslationServer::get_accented_version(char32_t p_character) co
}
bool TranslationServer::is_placeholder(String &p_message, int p_index) const {
- return p_index < p_message.size() - 1 && p_message[p_index] == '%' &&
+ return p_index < p_message.length() - 1 && p_message[p_index] == '%' &&
(p_message[p_index + 1] == 's' || p_message[p_index + 1] == 'c' || p_message[p_index + 1] == 'd' ||
p_message[p_index + 1] == 'o' || p_message[p_index + 1] == 'x' || p_message[p_index + 1] == 'X' || p_message[p_index + 1] == 'f');
}
diff --git a/core/templates/command_queue_mt.h b/core/templates/command_queue_mt.h
index 7e480653ac..b1010f7f43 100644
--- a/core/templates/command_queue_mt.h
+++ b/core/templates/command_queue_mt.h
@@ -31,6 +31,7 @@
#ifndef COMMAND_QUEUE_MT_H
#define COMMAND_QUEUE_MT_H
+#include "core/object/worker_thread_pool.h"
#include "core/os/memory.h"
#include "core/os/mutex.h"
#include "core/os/semaphore.h"
@@ -306,15 +307,15 @@ class CommandQueueMT {
struct CommandBase {
virtual void call() = 0;
- virtual void post() {}
- virtual ~CommandBase() {}
+ virtual SyncSemaphore *get_sync_semaphore() { return nullptr; }
+ virtual ~CommandBase() = default; // Won't be called.
};
struct SyncCommand : public CommandBase {
SyncSemaphore *sync_sem = nullptr;
- virtual void post() override {
- sync_sem->sem.post();
+ virtual SyncSemaphore *get_sync_semaphore() override {
+ return sync_sem;
}
};
@@ -340,6 +341,7 @@ class CommandQueueMT {
SyncSemaphore sync_sems[SYNC_SEMAPHORES];
Mutex mutex;
Semaphore *sync = nullptr;
+ uint64_t flush_read_ptr = 0;
template <class T>
T *allocate() {
@@ -362,31 +364,41 @@ class CommandQueueMT {
void _flush() {
lock();
- uint64_t read_ptr = 0;
- uint64_t limit = command_mem.size();
-
- while (read_ptr < limit) {
- uint64_t size = *(uint64_t *)&command_mem[read_ptr];
- read_ptr += 8;
- CommandBase *cmd = reinterpret_cast<CommandBase *>(&command_mem[read_ptr]);
-
- cmd->call(); //execute the function
- cmd->post(); //release in case it needs sync/ret
- cmd->~CommandBase(); //should be done, so erase the command
-
- read_ptr += size;
+ WorkerThreadPool::thread_enter_command_queue_mt_flush(this);
+ while (flush_read_ptr < command_mem.size()) {
+ uint64_t size = *(uint64_t *)&command_mem[flush_read_ptr];
+ flush_read_ptr += 8;
+ CommandBase *cmd = reinterpret_cast<CommandBase *>(&command_mem[flush_read_ptr]);
+
+ SyncSemaphore *sync_sem = cmd->get_sync_semaphore();
+ cmd->call();
+ if (sync_sem) {
+ sync_sem->sem.post(); // Release in case it needs sync/ret.
+ }
+
+ if (unlikely(flush_read_ptr == 0)) {
+ // A reentrant call flushed.
+ DEV_ASSERT(command_mem.is_empty());
+ unlock();
+ return;
+ }
+
+ flush_read_ptr += size;
}
+ WorkerThreadPool::thread_exit_command_queue_mt_flush();
command_mem.clear();
+ flush_read_ptr = 0;
unlock();
}
- void lock();
- void unlock();
void wait_for_flush();
SyncSemaphore *_alloc_sync_sem();
public:
+ void lock();
+ void unlock();
+
/* NORMAL PUSH COMMANDS */
DECL_PUSH(0)
SPACE_SEP_LIST(DECL_PUSH, 15)
diff --git a/core/templates/paged_allocator.h b/core/templates/paged_allocator.h
index 6f3f78d4d2..d880eae0c3 100644
--- a/core/templates/paged_allocator.h
+++ b/core/templates/paged_allocator.h
@@ -40,7 +40,7 @@
#include <type_traits>
#include <typeinfo>
-template <class T, bool thread_safe = false>
+template <class T, bool thread_safe = false, uint32_t DEFAULT_PAGE_SIZE = 4096>
class PagedAllocator {
T **page_pool = nullptr;
T ***available_pool = nullptr;
@@ -53,10 +53,6 @@ class PagedAllocator {
SpinLock spin_lock;
public:
- enum {
- DEFAULT_PAGE_SIZE = 4096
- };
-
template <class... Args>
T *alloc(Args &&...p_args) {
if (thread_safe) {
diff --git a/core/templates/self_list.h b/core/templates/self_list.h
index fdf91beacc..afa0501c75 100644
--- a/core/templates/self_list.h
+++ b/core/templates/self_list.h
@@ -159,6 +159,9 @@ public:
_FORCE_INLINE_ SelfList<T> *first() { return _first; }
_FORCE_INLINE_ const SelfList<T> *first() const { return _first; }
+ // Forbid copying, which has broken behavior.
+ void operator=(const List &) = delete;
+
_FORCE_INLINE_ List() {}
_FORCE_INLINE_ ~List() {
// A self list must be empty on destruction.
@@ -185,6 +188,9 @@ public:
_FORCE_INLINE_ const SelfList<T> *prev() const { return _prev; }
_FORCE_INLINE_ T *self() const { return _self; }
+ // Forbid copying, which has broken behavior.
+ void operator=(const SelfList<T> &) = delete;
+
_FORCE_INLINE_ SelfList(T *p_self) {
_self = p_self;
}
diff --git a/core/variant/callable.cpp b/core/variant/callable.cpp
index 0b1174c873..55f687bdf9 100644
--- a/core/variant/callable.cpp
+++ b/core/variant/callable.cpp
@@ -31,13 +31,12 @@
#include "callable.h"
#include "callable_bind.h"
-#include "core/object/message_queue.h"
#include "core/object/object.h"
#include "core/object/ref_counted.h"
#include "core/object/script_language.h"
void Callable::call_deferredp(const Variant **p_arguments, int p_argcount) const {
- MessageQueue::get_singleton()->push_callablep(*this, p_arguments, p_argcount);
+ MessageQueue::get_singleton()->push_callablep(*this, p_arguments, p_argcount, true);
}
void Callable::callp(const Variant **p_arguments, int p_argcount, Variant &r_return_value, CallError &r_call_error) const {
diff --git a/core/variant/variant.h b/core/variant/variant.h
index 296319d408..602d287f22 100644
--- a/core/variant/variant.h
+++ b/core/variant/variant.h
@@ -781,8 +781,8 @@ public:
static Variant get_constant_value(Variant::Type p_type, const StringName &p_value, bool *r_valid = nullptr);
static void get_enums_for_type(Variant::Type p_type, List<StringName> *p_enums);
- static void get_enumerations_for_enum(Variant::Type p_type, StringName p_enum_name, List<StringName> *p_enumerations);
- static int get_enum_value(Variant::Type p_type, StringName p_enum_name, StringName p_enumeration, bool *r_valid = nullptr);
+ static void get_enumerations_for_enum(Variant::Type p_type, const StringName &p_enum_name, List<StringName> *p_enumerations);
+ static int get_enum_value(Variant::Type p_type, const StringName &p_enum_name, const StringName &p_enumeration, bool *r_valid = nullptr);
typedef String (*ObjectDeConstruct)(const Variant &p_object, void *ud);
typedef void (*ObjectConstruct)(const String &p_text, void *ud, Variant &r_value);
diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp
index 1daad2058e..03836985f3 100644
--- a/core/variant/variant_call.cpp
+++ b/core/variant/variant_call.cpp
@@ -1071,14 +1071,14 @@ struct _VariantCall {
static ConstantData *constant_data;
- static void add_constant(int p_type, StringName p_constant_name, int64_t p_constant_value) {
+ static void add_constant(int p_type, const StringName &p_constant_name, int64_t p_constant_value) {
constant_data[p_type].value[p_constant_name] = p_constant_value;
#ifdef DEBUG_ENABLED
constant_data[p_type].value_ordered.push_back(p_constant_name);
#endif
}
- static void add_variant_constant(int p_type, StringName p_constant_name, const Variant &p_constant_value) {
+ static void add_variant_constant(int p_type, const StringName &p_constant_name, const Variant &p_constant_value) {
constant_data[p_type].variant_value[p_constant_name] = p_constant_value;
#ifdef DEBUG_ENABLED
constant_data[p_type].variant_value_ordered.push_back(p_constant_name);
@@ -1091,7 +1091,7 @@ struct _VariantCall {
static EnumData *enum_data;
- static void add_enum_constant(int p_type, StringName p_enum_type_name, StringName p_enumeration_name, int p_enum_value) {
+ static void add_enum_constant(int p_type, const StringName &p_enum_type_name, const StringName &p_enumeration_name, int p_enum_value) {
enum_data[p_type].value[p_enum_type_name][p_enumeration_name] = p_enum_value;
}
};
@@ -1504,7 +1504,7 @@ void Variant::get_enums_for_type(Variant::Type p_type, List<StringName> *p_enums
}
}
-void Variant::get_enumerations_for_enum(Variant::Type p_type, StringName p_enum_name, List<StringName> *p_enumerations) {
+void Variant::get_enumerations_for_enum(Variant::Type p_type, const StringName &p_enum_name, List<StringName> *p_enumerations) {
ERR_FAIL_INDEX(p_type, Variant::VARIANT_MAX);
_VariantCall::EnumData &enum_data = _VariantCall::enum_data[p_type];
@@ -1516,7 +1516,7 @@ void Variant::get_enumerations_for_enum(Variant::Type p_type, StringName p_enum_
}
}
-int Variant::get_enum_value(Variant::Type p_type, StringName p_enum_name, StringName p_enumeration, bool *r_valid) {
+int Variant::get_enum_value(Variant::Type p_type, const StringName &p_enum_name, const StringName &p_enumeration, bool *r_valid) {
if (r_valid) {
*r_valid = false;
}
diff --git a/doc/classes/AnimationMixer.xml b/doc/classes/AnimationMixer.xml
index 4a489a3ef2..31308c4e20 100644
--- a/doc/classes/AnimationMixer.xml
+++ b/doc/classes/AnimationMixer.xml
@@ -15,10 +15,10 @@
<param index="0" name="animation" type="Animation" />
<param index="1" name="track" type="int" />
<param index="2" name="value" type="Variant" />
- <param index="3" name="object" type="Object" />
- <param index="4" name="object_idx" type="int" />
+ <param index="3" name="object_id" type="int" />
+ <param index="4" name="object_sub_idx" type="int" />
<description>
- A virtual function for processing after key getting during playback.
+ A virtual function for processing after getting a key during playback.
</description>
</method>
<method name="add_animation_library">
diff --git a/doc/classes/AudioEffectCapture.xml b/doc/classes/AudioEffectCapture.xml
index 275e5ab0b6..e17c510907 100644
--- a/doc/classes/AudioEffectCapture.xml
+++ b/doc/classes/AudioEffectCapture.xml
@@ -6,11 +6,10 @@
<description>
AudioEffectCapture is an AudioEffect which copies all audio frames from the attached audio effect bus into its internal ring buffer.
Application code should consume these audio frames from this ring buffer using [method get_buffer] and process it as needed, for example to capture data from an [AudioStreamMicrophone], implement application-defined effects, or to transmit audio over the network. When capturing audio data from a microphone, the format of the samples will be stereo 32-bit floating point PCM.
- [b]Note:[/b] [member ProjectSettings.audio/driver/enable_input] must be [code]true[/code] for audio input to work. See also that setting's description for caveats related to permissions and operating system privacy settings.
+ Unlike [AudioEffectRecord], this effect only returns the raw audio samples instead of encoding them into an [AudioStream].
</description>
<tutorials>
<link title="Audio buses">$DOCS_URL/tutorials/audio/audio_buses.html</link>
- <link title="Audio Mic Record Demo">https://github.com/godotengine/godot-demo-projects/tree/master/audio/mic_record</link>
</tutorials>
<methods>
<method name="can_get_buffer" qualifiers="const">
diff --git a/doc/classes/AudioEffectRecord.xml b/doc/classes/AudioEffectRecord.xml
index e07d66fa7b..5b43c5ebaa 100644
--- a/doc/classes/AudioEffectRecord.xml
+++ b/doc/classes/AudioEffectRecord.xml
@@ -4,9 +4,10 @@
Audio effect used for recording the sound from an audio bus.
</brief_description>
<description>
- Allows the user to record the sound from an audio bus. This can include all audio output by Godot when used on the "Master" audio bus.
+ Allows the user to record the sound from an audio bus into an [AudioStreamWAV]. When used on the "Master" audio bus, this includes all audio output by Godot.
+ Unlike [AudioEffectCapture], this effect encodes the recording with the given format (8-bit, 16-bit, or compressed) instead of giving access to the raw audio samples.
Can be used (with an [AudioStreamMicrophone]) to record from a microphone.
- It sets and gets the format in which the audio file will be recorded (8-bit, 16-bit, or compressed). It checks whether or not the recording is active, and if it is, records the sound. It then returns the recorded sample.
+ [b]Note:[/b] [member ProjectSettings.audio/driver/enable_input] must be [code]true[/code] for audio input to work. See also that setting's description for caveats related to permissions and operating system privacy settings.
</description>
<tutorials>
<link title="Recording with microphone">$DOCS_URL/tutorials/audio/recording_with_microphone.html</link>
diff --git a/doc/classes/CanvasTexture.xml b/doc/classes/CanvasTexture.xml
index 1b22adb723..a14f71cc46 100644
--- a/doc/classes/CanvasTexture.xml
+++ b/doc/classes/CanvasTexture.xml
@@ -5,7 +5,7 @@
</brief_description>
<description>
[CanvasTexture] is an alternative to [ImageTexture] for 2D rendering. It allows using normal maps and specular maps in any node that inherits from [CanvasItem]. [CanvasTexture] also allows overriding the texture's filter and repeat mode independently of the node's properties (or the project settings).
- [b]Note:[/b] [CanvasTexture] cannot be used in 3D rendering. For physically-based materials in 3D, use [BaseMaterial3D] instead.
+ [b]Note:[/b] [CanvasTexture] cannot be used in 3D. It will not display correctly when applied to any [VisualInstance3D], such as [Sprite3D] or [Decal]. For physically-based materials in 3D, use [BaseMaterial3D] instead.
</description>
<tutorials>
<link title="2D Lights and Shadows">$DOCS_URL/tutorials/2d/2d_lights_and_shadows.html</link>
diff --git a/doc/classes/CollisionPolygon2D.xml b/doc/classes/CollisionPolygon2D.xml
index d6f3b7cb5d..acb3f66c17 100644
--- a/doc/classes/CollisionPolygon2D.xml
+++ b/doc/classes/CollisionPolygon2D.xml
@@ -25,6 +25,7 @@
</member>
<member name="polygon" type="PackedVector2Array" setter="set_polygon" getter="get_polygon" default="PackedVector2Array()">
The polygon's list of vertices. Each point will be connected to the next, and the final point will be connected to the first.
+ [b]Note:[/b] The returned vertices are in the local coordinate space of the given [CollisionPolygon2D].
[b]Warning:[/b] The returned value is a clone of the [PackedVector2Array], not a reference.
</member>
</members>
diff --git a/doc/classes/EditorImportPlugin.xml b/doc/classes/EditorImportPlugin.xml
index 82ba956151..88a6eeec26 100644
--- a/doc/classes/EditorImportPlugin.xml
+++ b/doc/classes/EditorImportPlugin.xml
@@ -120,6 +120,13 @@
<link title="Import plugins">$DOCS_URL/tutorials/plugins/editor/import_plugins.html</link>
</tutorials>
<methods>
+ <method name="_can_import_threaded" qualifiers="virtual const">
+ <return type="bool" />
+ <description>
+ Tells whether this importer can be run in parallel on threads, or, on the contrary, it's only safe for the editor to call it from the main thread, for one file at a time.
+ If this method is not overridden, it will return [code]true[/code] by default (i.e., safe for parallel importing).
+ </description>
+ </method>
<method name="_get_import_options" qualifiers="virtual const">
<return type="Dictionary[]" />
<param index="0" name="path" type="String" />
diff --git a/doc/classes/EditorNode3DGizmo.xml b/doc/classes/EditorNode3DGizmo.xml
index 1680400384..7597489601 100644
--- a/doc/classes/EditorNode3DGizmo.xml
+++ b/doc/classes/EditorNode3DGizmo.xml
@@ -9,6 +9,13 @@
<tutorials>
</tutorials>
<methods>
+ <method name="_begin_handle_action" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="id" type="int" />
+ <param index="1" name="secondary" type="bool" />
+ <description>
+ </description>
+ </method>
<method name="_commit_handle" qualifiers="virtual">
<return type="void" />
<param index="0" name="id" type="int" />
diff --git a/doc/classes/EditorNode3DGizmoPlugin.xml b/doc/classes/EditorNode3DGizmoPlugin.xml
index da7ee17335..8fd7c167d9 100644
--- a/doc/classes/EditorNode3DGizmoPlugin.xml
+++ b/doc/classes/EditorNode3DGizmoPlugin.xml
@@ -11,6 +11,14 @@
<link title="Node3D gizmo plugins">$DOCS_URL/tutorials/plugins/editor/3d_gizmos.html</link>
</tutorials>
<methods>
+ <method name="_begin_handle_action" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="gizmo" type="EditorNode3DGizmo" />
+ <param index="1" name="handle_id" type="int" />
+ <param index="2" name="secondary" type="bool" />
+ <description>
+ </description>
+ </method>
<method name="_can_be_hidden" qualifiers="virtual const">
<return type="bool" />
<description>
diff --git a/doc/classes/GDExtension.xml b/doc/classes/GDExtension.xml
index ee55c89131..533b32218f 100644
--- a/doc/classes/GDExtension.xml
+++ b/doc/classes/GDExtension.xml
@@ -1,31 +1,42 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="GDExtension" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
+ A native library for GDExtension.
</brief_description>
<description>
+ The [GDExtension] resource type represents a [url=https://en.wikipedia.org/wiki/Shared_library]shared library[/url] which can expand the functionality of the engine. The [GDExtensionManager] singleton is responsible for loading, reloading, and unloading [GDExtension] resources.
+ [b]Note:[/b] GDExtension itself is not a scripting language and has no relation to [GDScript] resources.
</description>
<tutorials>
+ <link title="GDExtension overview">$DOCS_URL/tutorials/scripting/gdextension/what_is_gdextension.html</link>
+ <link title="GDExtension example in C++">$DOCS_URL/tutorials/scripting/gdextension/gdextension_cpp_example.html</link>
</tutorials>
<methods>
<method name="close_library">
<return type="void" />
<description>
+ Closes the current library.
+ [b]Note:[/b] You normally should not call this method directly. This is handled automatically by [method GDExtensionManager.unload_extension].
</description>
</method>
<method name="get_minimum_library_initialization_level" qualifiers="const">
<return type="int" enum="GDExtension.InitializationLevel" />
<description>
+ Returns the lowest level required for this extension to be properly initialized (see the [enum InitializationLevel] enum).
</description>
</method>
<method name="initialize_library">
<return type="void" />
<param index="0" name="level" type="int" enum="GDExtension.InitializationLevel" />
<description>
+ Initializes the library bound to this GDextension at the given initialization [param level].
+ [b]Note:[/b] You normally should not call this method directly. This is handled automatically by [method GDExtensionManager.load_extension].
</description>
</method>
<method name="is_library_open" qualifiers="const">
<return type="bool" />
<description>
+ Returns [code]true[/code] if this extension's library has been opened.
</description>
</method>
<method name="open_library">
@@ -33,17 +44,23 @@
<param index="0" name="path" type="String" />
<param index="1" name="entry_symbol" type="String" />
<description>
+ Opens the library at the specified [param path].
+ [b]Note:[/b] You normally should not call this method directly. This is handled automatically by [method GDExtensionManager.load_extension].
</description>
</method>
</methods>
<constants>
<constant name="INITIALIZATION_LEVEL_CORE" value="0" enum="InitializationLevel">
+ The library is initialized at the same time as the core features of the engine.
</constant>
<constant name="INITIALIZATION_LEVEL_SERVERS" value="1" enum="InitializationLevel">
+ The library is initialized at the same time as the engine's servers (such as [RenderingServer] or [PhysicsServer3D]).
</constant>
<constant name="INITIALIZATION_LEVEL_SCENE" value="2" enum="InitializationLevel">
+ The library is initialized at the same time as the engine's scene-related classes.
</constant>
<constant name="INITIALIZATION_LEVEL_EDITOR" value="3" enum="InitializationLevel">
+ The library is initialized at the same time as the engine's editor classes. Only happens when loading the GDExtension in the editor.
</constant>
</constants>
</class>
diff --git a/doc/classes/GDExtensionManager.xml b/doc/classes/GDExtensionManager.xml
index 8d2515dc28..1ecb23a03b 100644
--- a/doc/classes/GDExtensionManager.xml
+++ b/doc/classes/GDExtensionManager.xml
@@ -1,65 +1,82 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="GDExtensionManager" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
+ Provides access to GDExtension functionality.
</brief_description>
<description>
+ The GDExtensionManager loads, initializes, and keeps track of all available [GDExtension] libraries in the project.
+ [b]Note:[/b] Do not worry about GDExtension unless you know what you are doing.
</description>
<tutorials>
+ <link title="GDExtension overview">$DOCS_URL/tutorials/scripting/gdextension/what_is_gdextension.html</link>
+ <link title="GDExtension example in C++">$DOCS_URL/tutorials/scripting/gdextension/gdextension_cpp_example.html</link>
</tutorials>
<methods>
<method name="get_extension">
<return type="GDExtension" />
<param index="0" name="path" type="String" />
<description>
+ Returns the [GDExtension] at the given file [param path], or [code]null[/code] if it has not been loaded or does not exist.
</description>
</method>
<method name="get_loaded_extensions" qualifiers="const">
<return type="PackedStringArray" />
<description>
+ Returns the file paths of all currently loaded extensions.
</description>
</method>
<method name="is_extension_loaded" qualifiers="const">
<return type="bool" />
<param index="0" name="path" type="String" />
<description>
+ Returns [code]true[/code] if the extension at the given file [param path] has already been loaded successfully. See also [method get_loaded_extensions].
</description>
</method>
<method name="load_extension">
<return type="int" enum="GDExtensionManager.LoadStatus" />
<param index="0" name="path" type="String" />
<description>
+ Loads an extension by absolute file path. The [param path] needs to point to a valid [GDExtension]. Returns [constant LOAD_STATUS_OK] if successful.
</description>
</method>
<method name="reload_extension">
<return type="int" enum="GDExtensionManager.LoadStatus" />
<param index="0" name="path" type="String" />
<description>
+ Reloads the extension at the given file path. The [param path] needs to point to a valid [GDExtension], otherwise this method may return either [constant LOAD_STATUS_NOT_LOADED] or [constant LOAD_STATUS_FAILED].
+ [b]Note:[/b] You can only reload extensions in the editor. In release builds, this method always fails and returns [constant LOAD_STATUS_FAILED].
</description>
</method>
<method name="unload_extension">
<return type="int" enum="GDExtensionManager.LoadStatus" />
<param index="0" name="path" type="String" />
<description>
+ Unloads an extension by file path. The [param path] needs to point to an already loaded [GDExtension], otherwise this method returns [constant LOAD_STATUS_NOT_LOADED].
</description>
</method>
</methods>
<signals>
<signal name="extensions_reloaded">
<description>
- Emitted after the editor has automatically reloaded any extensions.
+ Emitted after the editor has finished reloading one or more extensions.
</description>
</signal>
</signals>
<constants>
<constant name="LOAD_STATUS_OK" value="0" enum="LoadStatus">
+ The extension has loaded successfully.
</constant>
<constant name="LOAD_STATUS_FAILED" value="1" enum="LoadStatus">
+ The extension has failed to load, possibly because it does not exist or has missing dependencies.
</constant>
<constant name="LOAD_STATUS_ALREADY_LOADED" value="2" enum="LoadStatus">
+ The extension has already been loaded.
</constant>
<constant name="LOAD_STATUS_NOT_LOADED" value="3" enum="LoadStatus">
+ The extension has not been loaded.
</constant>
<constant name="LOAD_STATUS_NEEDS_RESTART" value="4" enum="LoadStatus">
+ The extension requires the application to restart to fully load.
</constant>
</constants>
</class>
diff --git a/doc/classes/GraphNode.xml b/doc/classes/GraphNode.xml
index 9e1392567a..5bb3a25158 100644
--- a/doc/classes/GraphNode.xml
+++ b/doc/classes/GraphNode.xml
@@ -116,6 +116,20 @@
Returns the right (output) [Color] of the slot with the given [param slot_index].
</description>
</method>
+ <method name="get_slot_custom_icon_left" qualifiers="const">
+ <return type="Texture2D" />
+ <param index="0" name="slot_index" type="int" />
+ <description>
+ Returns the left (input) custom [Texture2D] of the slot with the given [param slot_index].
+ </description>
+ </method>
+ <method name="get_slot_custom_icon_right" qualifiers="const">
+ <return type="Texture2D" />
+ <param index="0" name="slot_index" type="int" />
+ <description>
+ Returns the right (output) custom [Texture2D] of the slot with the given [param slot_index].
+ </description>
+ </method>
<method name="get_slot_type_left" qualifiers="const">
<return type="int" />
<param index="0" name="slot_index" type="int" />
@@ -195,6 +209,22 @@
Sets the [Color] of the right (output) side of the slot with the given [param slot_index] to [param color].
</description>
</method>
+ <method name="set_slot_custom_icon_left">
+ <return type="void" />
+ <param index="0" name="slot_index" type="int" />
+ <param index="1" name="custom_icon" type="Texture2D" />
+ <description>
+ Sets the custom [Texture2D] of the left (input) side of the slot with the given [param slot_index] to [param custom_icon].
+ </description>
+ </method>
+ <method name="set_slot_custom_icon_right">
+ <return type="void" />
+ <param index="0" name="slot_index" type="int" />
+ <param index="1" name="custom_icon" type="Texture2D" />
+ <description>
+ Sets the custom [Texture2D] of the right (output) side of the slot with the given [param slot_index] to [param custom_icon].
+ </description>
+ </method>
<method name="set_slot_draw_stylebox">
<return type="void" />
<param index="0" name="slot_index" type="int" />
diff --git a/doc/classes/Image.xml b/doc/classes/Image.xml
index 872277b033..6c1ecb3aea 100644
--- a/doc/classes/Image.xml
+++ b/doc/classes/Image.xml
@@ -19,6 +19,7 @@
<param index="1" name="contrast" type="float" />
<param index="2" name="saturation" type="float" />
<description>
+ Adjusts this image's [param brightness], [param contrast], and [param saturation] by the given values. Does not work if the image is compressed (see [method is_compressed]).
</description>
</method>
<method name="blend_rect">
@@ -163,6 +164,7 @@
<return type="int" enum="Image.UsedChannels" />
<param index="0" name="source" type="int" enum="Image.CompressSource" default="0" />
<description>
+ Returns the color channels used by this image, as one of the [enum UsedChannels] constants. If the image is compressed, the original [param source] must be specified.
</description>
</method>
<method name="fill">
@@ -612,6 +614,7 @@
OpenGL texture format [code]RGBA[/code] with four components, each with a bitdepth of 4.
</constant>
<constant name="FORMAT_RGB565" value="7" enum="Format">
+ OpenGL texture format [code]RGB[/code] with three components. Red and blue have a bitdepth of 5, and green has a bitdepth of 6.
</constant>
<constant name="FORMAT_RF" value="8" enum="Format">
OpenGL texture format [code]GL_R32F[/code] where there's one component, a 32-bit floating-point value.
@@ -696,8 +699,10 @@
[b]Note:[/b] When creating an [ImageTexture], an sRGB to linear color space conversion is performed.
</constant>
<constant name="FORMAT_ETC2_RA_AS_RG" value="33" enum="Format">
+ [url=https://en.wikipedia.org/wiki/Ericsson_Texture_Compression#ETC2_and_EAC]Ericsson Texture Compression format 2[/url] ([code]RGBA8[/code] variant), which compresses RA data and interprets it as two channels (red and green). See also [constant FORMAT_ETC2_RGBA8].
</constant>
<constant name="FORMAT_DXT5_RA_AS_RG" value="34" enum="Format">
+ The [url=https://en.wikipedia.org/wiki/S3_Texture_Compression]S3TC[/url] texture format also known as Block Compression 3 or BC3, which compresses RA data and interprets it as two channels (red and green). See also [constant FORMAT_DXT5].
</constant>
<constant name="FORMAT_ASTC_4x4" value="35" enum="Format">
[url=https://en.wikipedia.org/wiki/Adaptive_scalable_texture_compression]Adaptive Scalable Texture Compression[/url]. This implements the 4x4 (high quality) mode.
@@ -761,16 +766,22 @@
Represents the size of the [enum CompressMode] enum.
</constant>
<constant name="USED_CHANNELS_L" value="0" enum="UsedChannels">
+ The image only uses one channel for luminance (grayscale).
</constant>
<constant name="USED_CHANNELS_LA" value="1" enum="UsedChannels">
+ The image uses two channels for luminance and alpha, respectively.
</constant>
<constant name="USED_CHANNELS_R" value="2" enum="UsedChannels">
+ The image only uses the red channel.
</constant>
<constant name="USED_CHANNELS_RG" value="3" enum="UsedChannels">
+ The image uses two channels for red and green.
</constant>
<constant name="USED_CHANNELS_RGB" value="4" enum="UsedChannels">
+ The image uses three channels for red, green, and blue.
</constant>
<constant name="USED_CHANNELS_RGBA" value="5" enum="UsedChannels">
+ The image uses four channels for red, green, blue, and alpha.
</constant>
<constant name="COMPRESS_SOURCE_GENERIC" value="0" enum="CompressSource">
Source texture (before compression) is a regular texture. Default for all textures.
diff --git a/doc/classes/Node.xml b/doc/classes/Node.xml
index 4d31b5b8ed..5dd3d22062 100644
--- a/doc/classes/Node.xml
+++ b/doc/classes/Node.xml
@@ -267,7 +267,7 @@
<param index="0" name="idx" type="int" />
<param index="1" name="include_internal" type="bool" default="false" />
<description>
- Fetches a child node by its index. Each child node has an index relative its siblings (see [method get_index]). The first child is at index 0. Negative values can also be used to start from the end of the list. This method can be used in combination with [method get_child_count] to iterate over this node's children.
+ Fetches a child node by its index. Each child node has an index relative its siblings (see [method get_index]). The first child is at index 0. Negative values can also be used to start from the end of the list. This method can be used in combination with [method get_child_count] to iterate over this node's children. If no child exists at the given index, this method returns [code]null[/code] and an error is generated.
If [param include_internal] is [code]false[/code], internal children are ignored (see [method add_child]'s [code]internal[/code] parameter).
[codeblock]
# Assuming the following are children of this node, in order:
@@ -739,7 +739,7 @@
<param index="0" name="new_parent" type="Node" />
<param index="1" name="keep_global_transform" type="bool" default="true" />
<description>
- Changes the parent of this [Node] to the [param new_parent]. The node needs to already have a parent.
+ Changes the parent of this [Node] to the [param new_parent]. The node needs to already have a parent. The node's [member owner] is preserved if its owner is still reachable from the new location (i.e., the node is still a descendant of the new parent after the operation).
If [param keep_global_transform] is [code]true[/code], the node's global transform will be preserved if supported. [Node2D], [Node3D] and [Control] support this argument (but [Control] keeps only position).
</description>
</method>
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index b969e3bb8e..e80b349da9 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -810,7 +810,9 @@
Main window can't be focused. No-focus window will ignore all input, except mouse clicks.
</member>
<member name="display/window/size/resizable" type="bool" setter="" getter="" default="true">
- Allows the window to be resizable by default.
+ If [code]true[/code], allows the window to be resizable by default.
+ [b]Note:[/b] This property is only read when the project starts. To change whether the window is resizable at runtime, set [member Window.unresizable] instead on the root Window, which can be retrieved using [code]get_viewport().get_window()[/code]. [member Window.unresizable] takes the opposite value of this setting.
+ [b]Note:[/b] Certain window managers can be configured to ignore the non-resizable status of a window. Do not rely on this setting as a guarantee that the window will [i]never[/i] be resizable.
[b]Note:[/b] This setting is ignored on iOS.
</member>
<member name="display/window/size/transparent" type="bool" setter="" getter="" default="false">
@@ -2534,8 +2536,6 @@
Decreasing this value may improve GPU performance on certain setups, even if the maximum number of clustered elements is never reached in the project.
[b]Note:[/b] This setting is only effective when using the Forward+ rendering method, not Mobile and Compatibility.
</member>
- <member name="rendering/limits/forward_renderer/threaded_render_minimum_instances" type="int" setter="" getter="" default="500">
- </member>
<member name="rendering/limits/global_shader_variables/buffer_size" type="int" setter="" getter="" default="65536">
</member>
<member name="rendering/limits/opengl/max_lights_per_object" type="int" setter="" getter="" default="8">
@@ -2768,8 +2768,6 @@
<member name="threading/worker_pool/max_threads" type="int" setter="" getter="" default="-1">
Maximum number of threads to be used by [WorkerThreadPool]. Value of [code]-1[/code] means no limit.
</member>
- <member name="threading/worker_pool/use_system_threads_for_low_priority_tasks" type="bool" setter="" getter="" default="true">
- </member>
<member name="xr/openxr/default_action_map" type="String" setter="" getter="" default="&quot;res://openxr_action_map.tres&quot;">
Action map configuration to load by default.
</member>
diff --git a/doc/classes/RDUniform.xml b/doc/classes/RDUniform.xml
index 7aab8b2810..77aaf0aae7 100644
--- a/doc/classes/RDUniform.xml
+++ b/doc/classes/RDUniform.xml
@@ -13,16 +13,19 @@
<return type="void" />
<param index="0" name="id" type="RID" />
<description>
+ Binds the given id to the uniform. The data associated with the id is then used when the uniform is passed to a shader.
</description>
</method>
<method name="clear_ids">
<return type="void" />
<description>
+ Unbinds all ids currently bound to the uniform.
</description>
</method>
<method name="get_ids" qualifiers="const">
<return type="RID[]" />
<description>
+ Returns an array of all ids currently bound to the uniform.
</description>
</method>
</methods>
diff --git a/doc/classes/RenderingDevice.xml b/doc/classes/RenderingDevice.xml
index 5ca6d38267..54f3281e17 100644
--- a/doc/classes/RenderingDevice.xml
+++ b/doc/classes/RenderingDevice.xml
@@ -14,12 +14,12 @@
<link title="Using compute shaders">$DOCS_URL/tutorials/shaders/compute_shaders.html</link>
</tutorials>
<methods>
- <method name="barrier">
+ <method name="barrier" is_deprecated="true">
<return type="void" />
<param index="0" name="from" type="int" enum="RenderingDevice.BarrierMask" is_bitfield="true" default="32767" />
<param index="1" name="to" type="int" enum="RenderingDevice.BarrierMask" is_bitfield="true" default="32767" />
<description>
- Puts a memory barrier in place. This is used for synchronization to avoid data races. See also [method full_barrier], which may be useful for debugging.
+ [i]Deprecated.[/i] Barriers are automatically inserted by RenderingDevice.
</description>
</method>
<method name="buffer_clear">
@@ -27,9 +27,8 @@
<param index="0" name="buffer" type="RID" />
<param index="1" name="offset" type="int" />
<param index="2" name="size_bytes" type="int" />
- <param index="3" name="post_barrier" type="int" enum="RenderingDevice.BarrierMask" is_bitfield="true" default="32767" />
<description>
- Clears the contents of the [param buffer], clearing [param size_bytes] bytes, starting at [param offset]. Always raises a memory barrier.
+ Clears the contents of the [param buffer], clearing [param size_bytes] bytes, starting at [param offset].
Prints an error if:
- the size isn't a multiple of four
- the region specified by [param offset] + [param size_bytes] exceeds the buffer
@@ -37,6 +36,21 @@
- a compute list is currently active (created by [method compute_list_begin])
</description>
</method>
+ <method name="buffer_copy">
+ <return type="int" enum="Error" />
+ <param index="0" name="src_buffer" type="RID" />
+ <param index="1" name="dst_buffer" type="RID" />
+ <param index="2" name="src_offset" type="int" />
+ <param index="3" name="dst_offset" type="int" />
+ <param index="4" name="size" type="int" />
+ <description>
+ Copies [param size] bytes from the [param src_buffer] at [param src_offset] into [param dst_buffer] at [param dst_offset].
+ Prints an error if:
+ - [param size] exceeds the size of either [param src_buffer] or [param dst_buffer] at their corresponding offsets
+ - a draw list is currently active (created by [method draw_list_begin])
+ - a compute list is currently active (created by [method compute_list_begin])
+ </description>
+ </method>
<method name="buffer_get_data">
<return type="PackedByteArray" />
<param index="0" name="buffer" type="RID" />
@@ -52,9 +66,8 @@
<param index="1" name="offset" type="int" />
<param index="2" name="size_bytes" type="int" />
<param index="3" name="data" type="PackedByteArray" />
- <param index="4" name="post_barrier" type="int" enum="RenderingDevice.BarrierMask" is_bitfield="true" default="32767" />
<description>
- Updates a region of [param size_bytes] bytes, starting at [param offset], in the buffer, with the specified [param data]. Raises a memory barrier except when [param post_barrier] is set to [constant BARRIER_MASK_NO_BARRIER].
+ Updates a region of [param size_bytes] bytes, starting at [param offset], in the buffer, with the specified [param data].
Prints an error if:
- the region specified by [param offset] + [param size_bytes] exceeds the buffer
- a draw list is currently active (created by [method draw_list_begin])
@@ -77,10 +90,9 @@
</method>
<method name="compute_list_begin">
<return type="int" />
- <param index="0" name="allow_draw_overlap" type="bool" default="false" />
<description>
Starts a list of compute commands created with the [code]compute_*[/code] methods. The returned value should be passed to other [code]compute_list_*[/code] functions.
- If [param allow_draw_overlap] is [code]true[/code], you may have one draw list running at the same time as one compute list. Multiple compute lists cannot be created at the same time; you must finish the previous compute list first using [method compute_list_end].
+ Multiple compute lists cannot be created at the same time; you must finish the previous compute list first using [method compute_list_end].
A simple compute operation might look like this (code is not a complete example):
[codeblock]
var rd = RenderingDevice.new()
@@ -128,7 +140,6 @@
</method>
<method name="compute_list_end">
<return type="void" />
- <param index="0" name="post_barrier" type="int" enum="RenderingDevice.BarrierMask" is_bitfield="true" default="32767" />
<description>
Finishes a list of compute commands created with the [code]compute_*[/code] methods.
</description>
@@ -170,7 +181,7 @@
<param index="1" name="color" type="Color" />
<description>
Create a command buffer debug label region that can be displayed in third-party tools such as [url=https://renderdoc.org/]RenderDoc[/url]. All regions must be ended with a [method draw_command_end_label] call. When viewed from the linear series of submissions to a single queue, calls to [method draw_command_begin_label] and [method draw_command_end_label] must be matched and balanced.
- The [code]VK_EXT_DEBUG_UTILS_EXTENSION_NAME[/code] Vulkan extension must be available and enabled for command buffer debug label region to work. See also [method draw_command_insert_label] and [method draw_command_end_label].
+ The [code]VK_EXT_DEBUG_UTILS_EXTENSION_NAME[/code] Vulkan extension must be available and enabled for command buffer debug label region to work. See also [method draw_command_end_label].
</description>
</method>
<method name="draw_command_end_label">
@@ -179,12 +190,12 @@
Ends the command buffer debug label region started by a [method draw_command_begin_label] call.
</description>
</method>
- <method name="draw_command_insert_label">
+ <method name="draw_command_insert_label" is_deprecated="true">
<return type="void" />
<param index="0" name="name" type="String" />
<param index="1" name="color" type="Color" />
<description>
- Inserts a command buffer debug label region in the current command buffer. Unlike [method draw_command_begin_label], this region should not be ended with a [method draw_command_end_label] call.
+ [i]Deprecated.[/i] Inserting labels no longer applies due to command reordering.
</description>
</method>
<method name="draw_list_begin">
@@ -198,7 +209,6 @@
<param index="6" name="clear_depth" type="float" default="1.0" />
<param index="7" name="clear_stencil" type="int" default="0" />
<param index="8" name="region" type="Rect2" default="Rect2(0, 0, 0, 0)" />
- <param index="9" name="storage_textures" type="RID[]" default="[]" />
<description>
Starts a list of raster drawing commands created with the [code]draw_*[/code] methods. The returned value should be passed to other [code]draw_list_*[/code] functions.
Multiple draw lists cannot be created at the same time; you must finish the previous draw list first using [method draw_list_end].
@@ -232,7 +242,7 @@
[b]Note:[/b] Cannot be used with local RenderingDevices, as these don't have a screen. If called on a local RenderingDevice, [method draw_list_begin_for_screen] returns [constant INVALID_ID].
</description>
</method>
- <method name="draw_list_begin_split">
+ <method name="draw_list_begin_split" is_deprecated="true">
<return type="PackedInt64Array" />
<param index="0" name="framebuffer" type="RID" />
<param index="1" name="splits" type="int" />
@@ -246,7 +256,7 @@
<param index="9" name="region" type="Rect2" default="Rect2(0, 0, 0, 0)" />
<param index="10" name="storage_textures" type="RID[]" default="[]" />
<description>
- Variant of [method draw_list_begin] with support for multiple splits. The [param splits] parameter determines how many splits are created.
+ [i]Deprecated.[/i] Split draw lists are used automatically by RenderingDevice.
</description>
</method>
<method name="draw_list_bind_index_array">
@@ -310,7 +320,6 @@
</method>
<method name="draw_list_end">
<return type="void" />
- <param index="0" name="post_barrier" type="int" enum="RenderingDevice.BarrierMask" is_bitfield="true" default="32767" />
<description>
Finishes a list of raster drawing commands created with the [code]draw_*[/code] methods.
</description>
@@ -335,14 +344,14 @@
<method name="draw_list_switch_to_next_pass">
<return type="int" />
<description>
- Switches to the next draw pass and returns the split's ID. Equivalent to [method draw_list_switch_to_next_pass_split] with [code]splits[/code] set to [code]1[/code].
+ Switches to the next draw pass.
</description>
</method>
- <method name="draw_list_switch_to_next_pass_split">
+ <method name="draw_list_switch_to_next_pass_split" is_deprecated="true">
<return type="PackedInt64Array" />
<param index="0" name="splits" type="int" />
<description>
- Switches to the next draw pass, with the number of splits allocated specified in [param splits]. The return value is an array containing the ID of each split. For single-split usage, see [method draw_list_switch_to_next_pass].
+ [i]Deprecated.[/i] Split draw lists are used automatically by RenderingDevice.
</description>
</method>
<method name="framebuffer_create">
@@ -430,10 +439,10 @@
Tries to free an object in the RenderingDevice. To avoid memory leaks, this should be called after using an object as memory management does not occur automatically when using RenderingDevice directly.
</description>
</method>
- <method name="full_barrier">
+ <method name="full_barrier" is_deprecated="true">
<return type="void" />
<description>
- Puts a [i]full[/i] memory barrier in place. This is a memory [method barrier] with all flags enabled. [method full_barrier] it should only be used for debugging as it can severely impact performance.
+ [i]Deprecated.[/i] Barriers are automatically inserted by RenderingDevice.
</description>
</method>
<method name="get_captured_timestamp_cpu_time" qualifiers="const">
@@ -704,7 +713,6 @@
<param index="3" name="mipmap_count" type="int" />
<param index="4" name="base_layer" type="int" />
<param index="5" name="layer_count" type="int" />
- <param index="6" name="post_barrier" type="int" enum="RenderingDevice.BarrierMask" is_bitfield="true" default="32767" />
<description>
Clears the specified [param texture] by replacing all of its pixels with the specified [param color]. [param base_mipmap] and [param mipmap_count] determine which mipmaps of the texture are affected by this clear operation, while [param base_layer] and [param layer_count] determine which layers of a 3D texture (or texture array) are affected by this clear operation. For 2D textures (which only have one layer by design), [param base_layer] must be [code]0[/code] and [param layer_count] must be [code]1[/code].
[b]Note:[/b] [param texture] can't be cleared while a draw list that uses it as part of a framebuffer is being created. Ensure the draw list is finalized (and that the color/depth texture using it is not set to [constant FINAL_ACTION_CONTINUE]) to clear this texture.
@@ -721,7 +729,6 @@
<param index="6" name="dst_mipmap" type="int" />
<param index="7" name="src_layer" type="int" />
<param index="8" name="dst_layer" type="int" />
- <param index="9" name="post_barrier" type="int" enum="RenderingDevice.BarrierMask" is_bitfield="true" default="32767" />
<description>
Copies the [param from_texture] to [param to_texture] with the specified [param from_pos], [param to_pos] and [param size] coordinates. The Z axis of the [param from_pos], [param to_pos] and [param size] must be [code]0[/code] for 2-dimensional textures. Source and destination mipmaps/layers must also be specified, with these parameters being [code]0[/code] for textures without mipmaps or single-layer textures. Returns [constant @GlobalScope.OK] if the texture copy was successful or [constant @GlobalScope.ERR_INVALID_PARAMETER] otherwise.
[b]Note:[/b] [param from_texture] texture can't be copied while a draw list that uses it as part of a framebuffer is being created. Ensure the draw list is finalized (and that the color/depth texture using it is not set to [constant FINAL_ACTION_CONTINUE]) to copy this texture.
@@ -831,7 +838,6 @@
<return type="int" enum="Error" />
<param index="0" name="from_texture" type="RID" />
<param index="1" name="to_texture" type="RID" />
- <param index="2" name="post_barrier" type="int" enum="RenderingDevice.BarrierMask" is_bitfield="true" default="32767" />
<description>
Resolves the [param from_texture] texture onto [param to_texture] with multisample antialiasing enabled. This must be used when rendering a framebuffer for MSAA to work. Returns [constant @GlobalScope.OK] if successful, [constant @GlobalScope.ERR_INVALID_PARAMETER] otherwise.
[b]Note:[/b] [param from_texture] and [param to_texture] textures must have the same dimension, format and type (color or depth).
@@ -848,7 +854,6 @@
<param index="0" name="texture" type="RID" />
<param index="1" name="layer" type="int" />
<param index="2" name="data" type="PackedByteArray" />
- <param index="3" name="post_barrier" type="int" enum="RenderingDevice.BarrierMask" is_bitfield="true" default="32767" />
<description>
Updates texture data with new data, replacing the previous data in place. The updated texture data must have the same dimensions and format. For 2D textures (which only have one layer), [param layer] must be [code]0[/code]. Returns [constant @GlobalScope.OK] if the update was successful, [constant @GlobalScope.ERR_INVALID_PARAMETER] otherwise.
[b]Note:[/b] Updating textures is forbidden during creation of a draw or compute list.
@@ -2150,39 +2155,48 @@
</constant>
<constant name="DYNAMIC_STATE_STENCIL_REFERENCE" value="64" enum="PipelineDynamicStateFlags" is_bitfield="true">
</constant>
- <constant name="INITIAL_ACTION_CLEAR" value="0" enum="InitialAction">
- Start rendering and clear the whole framebuffer.
+ <constant name="INITIAL_ACTION_LOAD" value="0" enum="InitialAction">
+ Load the previous contents of the framebuffer.
</constant>
- <constant name="INITIAL_ACTION_CLEAR_REGION" value="1" enum="InitialAction">
- Start rendering and clear the framebuffer in the specified region.
+ <constant name="INITIAL_ACTION_CLEAR" value="1" enum="InitialAction">
+ Clear the whole framebuffer or its specified region.
</constant>
- <constant name="INITIAL_ACTION_CLEAR_REGION_CONTINUE" value="2" enum="InitialAction">
- Continue rendering and clear the framebuffer in the specified region. Framebuffer must have been left in [constant FINAL_ACTION_CONTINUE] state as the final action previously.
+ <constant name="INITIAL_ACTION_DISCARD" value="2" enum="InitialAction">
+ Ignore the previous contents of the framebuffer. This is the fastest option if you'll overwrite all of the pixels and don't need to read any of them.
</constant>
- <constant name="INITIAL_ACTION_KEEP" value="3" enum="InitialAction">
- Start rendering, but keep attached color texture contents. If the framebuffer was previously used to read in a shader, this will automatically insert a layout transition.
+ <constant name="INITIAL_ACTION_MAX" value="3" enum="InitialAction">
+ Represents the size of the [enum InitialAction] enum.
</constant>
- <constant name="INITIAL_ACTION_DROP" value="4" enum="InitialAction">
- Start rendering, ignore what is there; write above it. In general, this is the fastest option when you will be writing every single pixel and you don't need a clear color.
+ <constant name="INITIAL_ACTION_CLEAR_REGION" value="1" enum="InitialAction" is_deprecated="true">
+ [i]Deprecated.[/i] Use [constant INITIAL_ACTION_CLEAR] instead.
</constant>
- <constant name="INITIAL_ACTION_CONTINUE" value="5" enum="InitialAction">
- Continue rendering. Framebuffer must have been left in [constant FINAL_ACTION_CONTINUE] state as the final action previously.
+ <constant name="INITIAL_ACTION_CLEAR_REGION_CONTINUE" value="1" enum="InitialAction" is_deprecated="true">
+ [i]Deprecated.[/i] Use [constant INITIAL_ACTION_LOAD] instead.
</constant>
- <constant name="INITIAL_ACTION_MAX" value="6" enum="InitialAction">
- Represents the size of the [enum InitialAction] enum.
+ <constant name="INITIAL_ACTION_KEEP" value="0" enum="InitialAction" is_deprecated="true">
+ [i]Deprecated.[/i] Use [constant INITIAL_ACTION_LOAD] instead.
</constant>
- <constant name="FINAL_ACTION_READ" value="0" enum="FinalAction">
- Store the texture for reading and make it read-only if it has the [constant TEXTURE_USAGE_SAMPLING_BIT] bit (only applies to color, depth and stencil attachments).
+ <constant name="INITIAL_ACTION_DROP" value="2" enum="InitialAction" is_deprecated="true">
+ [i]Deprecated.[/i] Use [constant INITIAL_ACTION_DISCARD] instead.
</constant>
- <constant name="FINAL_ACTION_DISCARD" value="1" enum="FinalAction">
- Discard the texture data and make it read-only if it has the [constant TEXTURE_USAGE_SAMPLING_BIT] bit (only applies to color, depth and stencil attachments).
+ <constant name="INITIAL_ACTION_CONTINUE" value="0" enum="InitialAction" is_deprecated="true">
+ [i]Deprecated.[/i] Use [constant INITIAL_ACTION_LOAD] instead.
</constant>
- <constant name="FINAL_ACTION_CONTINUE" value="2" enum="FinalAction">
- Store the texture and continue for further processing. Similar to [constant FINAL_ACTION_READ], but does not make the texture read-only if it has the [constant TEXTURE_USAGE_SAMPLING_BIT] bit.
+ <constant name="FINAL_ACTION_STORE" value="0" enum="FinalAction">
+ Store the result of the draw list in the framebuffer. This is generally what you want to do.
</constant>
- <constant name="FINAL_ACTION_MAX" value="3" enum="FinalAction">
+ <constant name="FINAL_ACTION_DISCARD" value="1" enum="FinalAction">
+ Discard the contents of the framebuffer. This is the fastest option if you don't need to use the results of the draw list.
+ </constant>
+ <constant name="FINAL_ACTION_MAX" value="2" enum="FinalAction">
Represents the size of the [enum FinalAction] enum.
</constant>
+ <constant name="FINAL_ACTION_READ" value="0" enum="FinalAction" is_deprecated="true">
+ [i]Deprecated.[/i] Use [constant FINAL_ACTION_STORE] instead.
+ </constant>
+ <constant name="FINAL_ACTION_CONTINUE" value="0" enum="FinalAction" is_deprecated="true">
+ [i]Deprecated.[/i] Use [constant FINAL_ACTION_STORE] instead.
+ </constant>
<constant name="SHADER_STAGE_VERTEX" value="0" enum="ShaderStage">
Vertex shader stage. This can be used to manipulate vertices from a shader (but not create new vertices).
</constant>
diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml
index a3ec4d25f1..42a164bbeb 100644
--- a/doc/classes/RenderingServer.xml
+++ b/doc/classes/RenderingServer.xml
@@ -1556,11 +1556,11 @@
Returns [code]true[/code] if changes have been made to the RenderingServer's data. [method force_draw] is usually called if this happens.
</description>
</method>
- <method name="has_feature" qualifiers="const">
+ <method name="has_feature" qualifiers="const" is_deprecated="true">
<return type="bool" />
<param index="0" name="feature" type="int" enum="RenderingServer.Features" />
<description>
- Not yet implemented. Always returns [code]false[/code].
+ [i]Deprecated.[/i] This method has not been used since Godot 3.0. Always returns false.
</description>
</method>
<method name="has_os_feature" qualifiers="const">
@@ -5332,11 +5332,11 @@
<constant name="RENDERING_INFO_VIDEO_MEM_USED" value="5" enum="RenderingInfo">
Video memory used (in bytes). When using the Forward+ or mobile rendering backends, this is always greater than the sum of [constant RENDERING_INFO_TEXTURE_MEM_USED] and [constant RENDERING_INFO_BUFFER_MEM_USED], since there is miscellaneous data not accounted for by those two metrics. When using the GL Compatibility backend, this is equal to the sum of [constant RENDERING_INFO_TEXTURE_MEM_USED] and [constant RENDERING_INFO_BUFFER_MEM_USED].
</constant>
- <constant name="FEATURE_SHADERS" value="0" enum="Features">
- Hardware supports shaders. This enum is currently unused in Godot 3.x.
+ <constant name="FEATURE_SHADERS" value="0" enum="Features" is_deprecated="true">
+ [i]Deprecated.[/i] This constant has not been used since Godot 3.0.
</constant>
- <constant name="FEATURE_MULTITHREADED" value="1" enum="Features">
- Hardware supports multithreading. This enum is currently unused in Godot 3.x.
+ <constant name="FEATURE_MULTITHREADED" value="1" enum="Features" is_deprecated="true">
+ [i]Deprecated.[/i] This constant has not been used since Godot 3.0.
</constant>
</constants>
</class>
diff --git a/doc/classes/String.xml b/doc/classes/String.xml
index 277d84ab90..e1b60b1656 100644
--- a/doc/classes/String.xml
+++ b/doc/classes/String.xml
@@ -96,13 +96,14 @@
[gdscript]
"move_local_x".capitalize() # Returns "Move Local X"
"sceneFile_path".capitalize() # Returns "Scene File Path"
+ "2D, FPS, PNG".capitalize() # Returns "2d, Fps, Png"
[/gdscript]
[csharp]
"move_local_x".Capitalize(); // Returns "Move Local X"
"sceneFile_path".Capitalize(); // Returns "Scene File Path"
+ "2D, FPS, PNG".Capitalize(); // Returns "2d, Fps, Png"
[/csharp]
[/codeblocks]
- [b]Note:[/b] This method not the same as the default appearance of properties in the Inspector dock, as it does not capitalize acronyms ([code]"2D"[/code], [code]"FPS"[/code], [code]"PNG"[/code], etc.) as you may expect.
</description>
</method>
<method name="casecmp_to" qualifiers="const">
@@ -949,7 +950,7 @@
<method name="to_lower" qualifiers="const">
<return type="String" />
<description>
- Returns the string converted to lowercase.
+ Returns the string converted to [code]lowercase[/code].
</description>
</method>
<method name="to_pascal_case" qualifiers="const">
@@ -962,12 +963,25 @@
<return type="String" />
<description>
Returns the string converted to [code]snake_case[/code].
+ [b]Note:[/b] Numbers followed by a [i]single[/i] letter are not separated in the conversion to keep some words (such as "2D") together.
+ [codeblocks]
+ [gdscript]
+ "Node2D".to_snake_case() # Returns "node_2d"
+ "2nd place".to_snake_case() # Returns "2_nd_place"
+ "Texture3DAssetFolder".to_snake_case() # Returns "texture_3d_asset_folder"
+ [/gdscript]
+ [csharp]
+ "Node2D".ToSnakeCase(); // Returns "node_2d"
+ "2nd place".ToSnakeCase(); // Returns "2_nd_place"
+ "Texture3DAssetFolder".ToSnakeCase(); // Returns "texture_3d_asset_folder"
+ [/csharp]
+ [/codeblocks]
</description>
</method>
<method name="to_upper" qualifiers="const">
<return type="String" />
<description>
- Returns the string converted to uppercase.
+ Returns the string converted to [code]UPPERCASE[/code].
</description>
</method>
<method name="to_utf8_buffer" qualifiers="const">
diff --git a/doc/classes/StringName.xml b/doc/classes/StringName.xml
index 4d9587f7aa..844782eb9a 100644
--- a/doc/classes/StringName.xml
+++ b/doc/classes/StringName.xml
@@ -8,6 +8,7 @@
You will usually just pass a [String] to methods expecting a [StringName] and it will be automatically converted, but you may occasionally want to construct a [StringName] ahead of time with the [StringName] constructor or, in GDScript, the literal syntax [code]&amp;"example"[/code].
See also [NodePath], which is a similar concept specifically designed to store pre-parsed scene tree paths.
All of [String]'s methods are available in this class too. They convert the [StringName] into a string, and they also return a string. This is highly inefficient and should only be used if the string is desired.
+ [b]Note:[/b] In C#, an explicit conversion to [code]System.String[/code] is required to use the methods listed on this page. Use the [code]ToString()[/code] method to cast a [StringName] to a string, and then use the equivalent methods in [code]System.String[/code] or [code]StringExtensions[/code].
[b]Note:[/b] In a boolean context, a [StringName] will evaluate to [code]false[/code] if it is empty ([code]StringName("")[/code]). Otherwise, a [StringName] will always evaluate to [code]true[/code]. The [code]not[/code] operator cannot be used. Instead, [method is_empty] should be used to check for empty [StringName]s.
</description>
<tutorials>
@@ -90,13 +91,14 @@
[gdscript]
"move_local_x".capitalize() # Returns "Move Local X"
"sceneFile_path".capitalize() # Returns "Scene File Path"
+ "2D, FPS, PNG".capitalize() # Returns "2d, Fps, Png"
[/gdscript]
[csharp]
"move_local_x".Capitalize(); // Returns "Move Local X"
"sceneFile_path".Capitalize(); // Returns "Scene File Path"
+ "2D, FPS, PNG".Capitalize(); // Returns "2d, Fps, Png"
[/csharp]
[/codeblocks]
- [b]Note:[/b] This method not the same as the default appearance of properties in the Inspector dock, as it does not capitalize acronyms ([code]"2D"[/code], [code]"FPS"[/code], [code]"PNG"[/code], etc.) as you may expect.
</description>
</method>
<method name="casecmp_to" qualifiers="const">
@@ -856,7 +858,7 @@
<method name="to_lower" qualifiers="const">
<return type="String" />
<description>
- Returns the string converted to lowercase.
+ Returns the string converted to [code]lowercase[/code].
</description>
</method>
<method name="to_pascal_case" qualifiers="const">
@@ -869,12 +871,25 @@
<return type="String" />
<description>
Returns the string converted to [code]snake_case[/code].
+ [b]Note:[/b] Numbers followed by a [i]single[/i] letter are not separated in the conversion to keep some words (such as "2D") together.
+ [codeblocks]
+ [gdscript]
+ "Node2D".to_snake_case() # Returns "node_2d"
+ "2nd place".to_snake_case() # Returns "2_nd_place"
+ "Texture3DAssetFolder".to_snake_case() # Returns "texture_3d_asset_folder"
+ [/gdscript]
+ [csharp]
+ "Node2D".ToSnakeCase(); // Returns "node_2d"
+ "2nd place".ToSnakeCase(); // Returns "2_nd_place"
+ "Texture3DAssetFolder".ToSnakeCase(); // Returns "texture_3d_asset_folder"
+ [/csharp]
+ [/codeblocks]
</description>
</method>
<method name="to_upper" qualifiers="const">
<return type="String" />
<description>
- Returns the string converted to uppercase.
+ Returns the string converted to [code]UPPERCASE[/code].
</description>
</method>
<method name="to_utf8_buffer" qualifiers="const">
diff --git a/doc/classes/TabContainer.xml b/doc/classes/TabContainer.xml
index b3a9264569..1f3c3531c6 100644
--- a/doc/classes/TabContainer.xml
+++ b/doc/classes/TabContainer.xml
@@ -193,6 +193,9 @@
<member name="tab_focus_mode" type="int" setter="set_tab_focus_mode" getter="get_tab_focus_mode" enum="Control.FocusMode" default="2">
The focus access mode for the internal [TabBar] node.
</member>
+ <member name="tabs_position" type="int" setter="set_tabs_position" getter="get_tabs_position" enum="TabContainer.TabPosition" default="0">
+ Sets the position of the tab bar. See [enum TabPosition] for details.
+ </member>
<member name="tabs_rearrange_group" type="int" setter="set_tabs_rearrange_group" getter="get_tabs_rearrange_group" default="-1">
[TabContainer]s with the same rearrange group ID will allow dragging the tabs between them. Enable drag with [member drag_to_rearrange_enabled].
Setting this to [code]-1[/code] will disable rearranging between [TabContainer]s.
@@ -247,6 +250,17 @@
</description>
</signal>
</signals>
+ <constants>
+ <constant name="POSITION_TOP" value="0" enum="TabPosition">
+ Places the tab bar at the top.
+ </constant>
+ <constant name="POSITION_BOTTOM" value="1" enum="TabPosition">
+ Places the tab bar at the bottom. The tab bar's [StyleBox] will be flipped vertically.
+ </constant>
+ <constant name="POSITION_MAX" value="2" enum="TabPosition">
+ Represents the size of the [enum TabPosition] enum.
+ </constant>
+ </constants>
<theme_items>
<theme_item name="drop_mark_color" data_type="color" type="Color" default="Color(1, 1, 1, 1)">
Modulation color for the [theme_item drop_mark] icon.
diff --git a/doc/classes/TextServer.xml b/doc/classes/TextServer.xml
index 09f484f523..cf4d92d119 100644
--- a/doc/classes/TextServer.xml
+++ b/doc/classes/TextServer.xml
@@ -1744,6 +1744,7 @@
Vertical BGR subpixel layout.
</constant>
<constant name="FONT_LCD_SUBPIXEL_LAYOUT_MAX" value="5" enum="FontLCDSubpixelLayout">
+ Represents the size of the [enum FontLCDSubpixelLayout] enum.
</constant>
<constant name="DIRECTION_AUTO" value="0" enum="Direction">
Text direction is determined based on contents and current locale.
@@ -1867,6 +1868,7 @@
Determines whether the ellipsis at the end of the text is enforced and may not be hidden.
</constant>
<constant name="OVERRUN_JUSTIFICATION_AWARE" value="16" enum="TextOverrunFlag" is_bitfield="true">
+ Accounts for the text being justified before attempting to trim it (see [enum JustificationFlag]).
</constant>
<constant name="GRAPHEME_IS_VALID" value="1" enum="GraphemeFlag" is_bitfield="true">
Grapheme is supported by the font, and can be drawn.
@@ -2005,6 +2007,7 @@
Spacing at the bottom of the line.
</constant>
<constant name="SPACING_MAX" value="4" enum="SpacingType">
+ Represents the size of the [enum SpacingType] enum.
</constant>
<constant name="FONT_BOLD" value="1" enum="FontStyle" is_bitfield="true">
Font is bold.
diff --git a/doc/classes/Window.xml b/doc/classes/Window.xml
index 5f6b1960b7..618a774aae 100644
--- a/doc/classes/Window.xml
+++ b/doc/classes/Window.xml
@@ -357,10 +357,11 @@
Centers a native window on the current screen and an embedded window on its embedder [Viewport].
</description>
</method>
- <method name="move_to_foreground">
+ <method name="move_to_foreground" is_deprecated="true">
<return type="void" />
<description>
Moves the [Window] on top of other windows and focuses it.
+ [i]Deprecated.[/i] Use [method Window.grab_focus] instead.
</description>
</method>
<method name="popup">
@@ -668,6 +669,9 @@
If [code]true[/code], the [Window] is transient, i.e. it's considered a child of another [Window]. The transient window will be destroyed with its transient parent and will return focus to their parent when closed. The transient window is displayed on top of a non-exclusive full-screen parent window. Transient windows can't enter full-screen mode.
Note that behavior might be different depending on the platform.
</member>
+ <member name="transient_to_focused" type="bool" setter="set_transient_to_focused" getter="is_transient_to_focused" default="false">
+ If [code]true[/code], and the [Window] is [member transient], this window will (at the time of becoming visible) become transient to the currently focused window instead of the immediate parent window in the hierarchy. Note that the transient parent is assigned at the time this window becomes visible, so changing it afterwards has no effect until re-shown.
+ </member>
<member name="transparent" type="bool" setter="set_flag" getter="get_flag" default="false">
If [code]true[/code], the [Window]'s background can be transparent. This is best used with embedded windows.
[b]Note:[/b] Transparency support is implemented on Linux, macOS and Windows, but availability might vary depending on GPU driver, display manager, and compositor capabilities.
diff --git a/doc/classes/WorkerThreadPool.xml b/doc/classes/WorkerThreadPool.xml
index d6751d31ce..fa1f08b149 100644
--- a/doc/classes/WorkerThreadPool.xml
+++ b/doc/classes/WorkerThreadPool.xml
@@ -106,7 +106,7 @@
Pauses the thread that calls this method until the task with the given ID is completed.
Returns [constant @GlobalScope.OK] if the task could be successfully awaited.
Returns [constant @GlobalScope.ERR_INVALID_PARAMETER] if a task with the passed ID does not exist (maybe because it was already awaited and disposed of).
- Returns [constant @GlobalScope.ERR_BUSY] if the call is made from another running task and, due to task scheduling, the task to await is at a lower level in the call stack and therefore can't progress. This is an advanced situation that should only matter when some tasks depend on others.
+ Returns [constant @GlobalScope.ERR_BUSY] if the call is made from another running task and, due to task scheduling, there's potential for deadlocking (e.g., the task to await may be at a lower level in the call stack and therefore can't progress). This is an advanced situation that should only matter when some tasks depend on others (in the current implementation, the tricky case is a task trying to wait on an older one).
</description>
</method>
</methods>
diff --git a/doc/tools/make_rst.py b/doc/tools/make_rst.py
index c3a21f3d7b..df3e928538 100755
--- a/doc/tools/make_rst.py
+++ b/doc/tools/make_rst.py
@@ -105,6 +105,7 @@ EDITOR_CLASSES: List[str] = [
CLASSES_WITH_CSHARP_DIFFERENCES: List[str] = [
"@GlobalScope",
"String",
+ "StringName",
"NodePath",
"Signal",
"Callable",
diff --git a/drivers/d3d12/d3d12_context.cpp b/drivers/d3d12/d3d12_context.cpp
index 97f5d91f3a..37066a811d 100644
--- a/drivers/d3d12/d3d12_context.cpp
+++ b/drivers/d3d12/d3d12_context.cpp
@@ -76,6 +76,8 @@ char godot_nir_arch_name[32];
#endif
#endif
+#define D3D12_DEBUG_LAYER_BREAK_ON_ERROR 0
+
void D3D12Context::_debug_message_func(
D3D12_MESSAGE_CATEGORY p_category,
D3D12_MESSAGE_SEVERITY p_severity,
@@ -563,6 +565,11 @@ Error D3D12Context::_create_device(DeviceBasics &r_basics) {
res = info_queue->PushStorageFilter(&filter);
ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
+
+#if D3D12_DEBUG_LAYER_BREAK_ON_ERROR
+ res = info_queue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_ERROR, true);
+ ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
+#endif
}
return OK;
@@ -889,7 +896,9 @@ void D3D12Context::_wait_for_idle_queue(ID3D12CommandQueue *p_queue) {
#endif
}
-void D3D12Context::flush(bool p_flush_setup, bool p_flush_pending) {
+void D3D12Context::flush(bool p_flush_setup, bool p_flush_pending, bool p_sync) {
+ ERR_FAIL_COND_MSG(!p_sync, "Flush without sync is not supported."); // This is a special case for Vulkan on mobile XR hardware, not applicable to D3D12
+
if (p_flush_setup && command_list_queue[0]) {
md.queue->ExecuteCommandLists(1, command_list_queue.ptr());
command_list_queue[0] = nullptr;
@@ -1054,27 +1063,6 @@ void D3D12Context::local_device_free(RID p_local_device) {
local_device_owner.free(p_local_device);
}
-void D3D12Context::command_begin_label(RDD::CommandBufferID p_command_buffer, String p_label_name, const Color &p_color) {
-#ifdef PIX_ENABLED
- const RenderingDeviceDriverD3D12::CommandBufferInfo *cmd_buf_info = (const RenderingDeviceDriverD3D12::CommandBufferInfo *)p_command_buffer.id;
- PIXBeginEvent(cmd_buf_info->cmd_list.Get(), p_color.to_argb32(), p_label_name.utf8().get_data());
-#endif
-}
-
-void D3D12Context::command_insert_label(RDD::CommandBufferID p_command_buffer, String p_label_name, const Color &p_color) {
-#ifdef PIX_ENABLED
- const RenderingDeviceDriverD3D12::CommandBufferInfo *cmd_buf_info = (const RenderingDeviceDriverD3D12::CommandBufferInfo *)p_command_buffer.id;
- PIXSetMarker(cmd_buf_info->cmd_list.Get(), p_color.to_argb32(), p_label_name.utf8().get_data());
-#endif
-}
-
-void D3D12Context::command_end_label(RDD::CommandBufferID p_command_buffer) {
-#ifdef PIX_ENABLED
- const RenderingDeviceDriverD3D12::CommandBufferInfo *cmd_buf_info = (const RenderingDeviceDriverD3D12::CommandBufferInfo *)p_command_buffer.id;
- PIXEndEvent(cmd_buf_info->cmd_list.Get());
-#endif
-}
-
void D3D12Context::set_object_name(ID3D12Object *p_object, String p_object_name) {
ERR_FAIL_NULL(p_object);
int name_len = p_object_name.size();
@@ -1123,6 +1111,14 @@ RenderingDeviceDriver *D3D12Context::get_driver(RID p_local_device) {
}
}
+bool D3D12Context::is_debug_utils_enabled() const {
+#ifdef PIX_ENABLED
+ return true;
+#else
+ return false;
+#endif
+}
+
D3D12Context::D3D12Context() {
command_list_queue.resize(1); // First one is always the setup command.
command_list_queue[0] = nullptr;
diff --git a/drivers/d3d12/d3d12_context.h b/drivers/d3d12/d3d12_context.h
index 27ec93bb7d..ac90d38467 100644
--- a/drivers/d3d12/d3d12_context.h
+++ b/drivers/d3d12/d3d12_context.h
@@ -234,15 +234,12 @@ public:
virtual void set_setup_buffer(RDD::CommandBufferID p_command_buffer) override final;
virtual void append_command_buffer(RDD::CommandBufferID p_command_buffer) override final;
void resize_notify();
- virtual void flush(bool p_flush_setup = false, bool p_flush_pending = false) override final;
+ virtual void flush(bool p_flush_setup = false, bool p_flush_pending = false, bool p_sync = true) override final;
virtual Error prepare_buffers(RDD::CommandBufferID p_command_buffer) override final;
virtual void postpare_buffers(RDD::CommandBufferID p_command_buffer) override final;
virtual Error swap_buffers() override final;
virtual Error initialize() override final;
- virtual void command_begin_label(RDD::CommandBufferID p_command_buffer, String p_label_name, const Color &p_color) override final;
- virtual void command_insert_label(RDD::CommandBufferID p_command_buffer, String p_label_name, const Color &p_color) override final;
- virtual void command_end_label(RDD::CommandBufferID p_command_buffer) override final;
void set_object_name(ID3D12Object *p_object, String p_object_name);
virtual String get_device_vendor_name() const override final;
@@ -255,6 +252,7 @@ public:
virtual DisplayServer::VSyncMode get_vsync_mode(DisplayServer::WindowID p_window = 0) const override final;
virtual RenderingDeviceDriver *get_driver(RID p_local_device = RID()) override final;
+ virtual bool is_debug_utils_enabled() const override final;
D3D12Context();
virtual ~D3D12Context();
diff --git a/drivers/d3d12/rendering_device_driver_d3d12.cpp b/drivers/d3d12/rendering_device_driver_d3d12.cpp
index 6a2a3c32b0..d3a7344c9d 100644
--- a/drivers/d3d12/rendering_device_driver_d3d12.cpp
+++ b/drivers/d3d12/rendering_device_driver_d3d12.cpp
@@ -5162,6 +5162,20 @@ void RenderingDeviceDriverD3D12::command_timestamp_write(CommandBufferID p_cmd_b
cmd_buf_info->cmd_list->ResolveQueryData(tqp_info->query_heap.Get(), D3D12_QUERY_TYPE_TIMESTAMP, p_index, tqp_info->query_count, results_buffer, p_index * sizeof(uint64_t));
}
+void RenderingDeviceDriverD3D12::command_begin_label(CommandBufferID p_cmd_buffer, const char *p_label_name, const Color &p_color) {
+#ifdef PIX_ENABLED
+ const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;
+ PIXBeginEvent(cmd_buf_info->cmd_list.Get(), p_color.to_argb32(), p_label_name);
+#endif
+}
+
+void RenderingDeviceDriverD3D12::command_end_label(CommandBufferID p_cmd_buffer) {
+#ifdef PIX_ENABLED
+ const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;
+ PIXEndEvent(cmd_buf_info->cmd_list.Get());
+#endif
+}
+
/****************/
/**** SCREEN ****/
/****************/
diff --git a/drivers/d3d12/rendering_device_driver_d3d12.h b/drivers/d3d12/rendering_device_driver_d3d12.h
index bd19572878..0da339c6fd 100644
--- a/drivers/d3d12/rendering_device_driver_d3d12.h
+++ b/drivers/d3d12/rendering_device_driver_d3d12.h
@@ -771,6 +771,13 @@ public:
virtual void command_timestamp_write(CommandBufferID p_cmd_buffer, QueryPoolID p_pool_id, uint32_t p_index) override final;
/****************/
+ /**** LABELS ****/
+ /****************/
+
+ virtual void command_begin_label(CommandBufferID p_cmd_buffer, const char *p_label_name, const Color &p_color) override final;
+ virtual void command_end_label(CommandBufferID p_cmd_buffer) override final;
+
+ /****************/
/**** SCREEN ****/
/****************/
diff --git a/drivers/egl/egl_manager.h b/drivers/egl/egl_manager.h
index c3a749cd19..61d3289b2d 100644
--- a/drivers/egl/egl_manager.h
+++ b/drivers/egl/egl_manager.h
@@ -45,7 +45,7 @@
class EGLManager {
private:
- // An EGL-side rappresentation of a display with its own rendering
+ // An EGL-side representation of a display with its own rendering
// context.
struct GLDisplay {
void *display = nullptr;
diff --git a/drivers/gles3/effects/copy_effects.cpp b/drivers/gles3/effects/copy_effects.cpp
index 996e7eee7f..c6fb6ca70b 100644
--- a/drivers/gles3/effects/copy_effects.cpp
+++ b/drivers/gles3/effects/copy_effects.cpp
@@ -125,6 +125,18 @@ void CopyEffects::copy_to_rect(const Rect2 &p_rect) {
draw_screen_quad();
}
+void CopyEffects::copy_to_and_from_rect(const Rect2 &p_rect) {
+ bool success = copy.shader.version_bind_shader(copy.shader_version, CopyShaderGLES3::MODE_COPY_SECTION_SOURCE);
+ if (!success) {
+ return;
+ }
+
+ copy.shader.version_set_uniform(CopyShaderGLES3::COPY_SECTION, p_rect.position.x, p_rect.position.y, p_rect.size.x, p_rect.size.y, copy.shader_version, CopyShaderGLES3::MODE_COPY_SECTION_SOURCE);
+ copy.shader.version_set_uniform(CopyShaderGLES3::SOURCE_SECTION, p_rect.position.x, p_rect.position.y, p_rect.size.x, p_rect.size.y, copy.shader_version, CopyShaderGLES3::MODE_COPY_SECTION_SOURCE);
+
+ draw_screen_quad();
+}
+
void CopyEffects::copy_screen() {
bool success = copy.shader.version_bind_shader(copy.shader_version, CopyShaderGLES3::MODE_DEFAULT);
if (!success) {
diff --git a/drivers/gles3/effects/copy_effects.h b/drivers/gles3/effects/copy_effects.h
index 6e2cb07382..509d07b955 100644
--- a/drivers/gles3/effects/copy_effects.h
+++ b/drivers/gles3/effects/copy_effects.h
@@ -62,6 +62,7 @@ public:
// These functions assume that a framebuffer and texture are bound already. They only manage the shader, uniforms, and vertex array.
void copy_to_rect(const Rect2 &p_rect);
+ void copy_to_and_from_rect(const Rect2 &p_rect);
void copy_screen();
void copy_cube_to_rect(const Rect2 &p_rect);
void bilinear_blur(GLuint p_source_texture, int p_mipmap_count, const Rect2i &p_region);
diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp
index c048e9bf37..6ab98a9473 100644
--- a/drivers/gles3/rasterizer_gles3.cpp
+++ b/drivers/gles3/rasterizer_gles3.cpp
@@ -103,6 +103,11 @@ void RasterizerGLES3::begin_frame(double frame_step) {
}
void RasterizerGLES3::end_frame(bool p_swap_buffers) {
+ GLES3::Utilities *utils = GLES3::Utilities::get_singleton();
+ utils->capture_timestamps_end();
+}
+
+void RasterizerGLES3::end_viewport(bool p_swap_buffers) {
if (p_swap_buffers) {
DisplayServer::get_singleton()->swap_buffers();
} else {
@@ -352,13 +357,6 @@ RasterizerGLES3::~RasterizerGLES3() {
}
void RasterizerGLES3::prepare_for_blitting_render_targets() {
- // This is a hack, but this function is called one time after all viewports have been updated.
- // So it marks the end of the frame for all viewports
- // In the OpenGL renderer we have to call end_frame for each viewport so we can swap the
- // buffers for each window before proceeding to the next.
- // This allows us to only increment the frame after all viewports are done.
- GLES3::Utilities *utils = GLES3::Utilities::get_singleton();
- utils->capture_timestamps_end();
}
void RasterizerGLES3::_blit_render_target_to_screen(RID p_render_target, DisplayServer::WindowID p_screen, const Rect2 &p_screen_rect, uint32_t p_layer, bool p_first) {
@@ -474,7 +472,7 @@ void RasterizerGLES3::set_boot_image(const Ref<Image> &p_image, const Color &p_c
copy_effects->copy_to_rect(screenrect);
glBindTexture(GL_TEXTURE_2D, 0);
- end_frame(true);
+ end_viewport(true);
texture_storage->texture_free(texture);
}
diff --git a/drivers/gles3/rasterizer_gles3.h b/drivers/gles3/rasterizer_gles3.h
index b19ca0e9c9..d9f436a2ec 100644
--- a/drivers/gles3/rasterizer_gles3.h
+++ b/drivers/gles3/rasterizer_gles3.h
@@ -93,6 +93,7 @@ public:
void prepare_for_blitting_render_targets();
void blit_render_targets_to_screen(DisplayServer::WindowID p_screen, const BlitToScreen *p_render_targets, int p_amount);
+ void end_viewport(bool p_swap_buffers);
void end_frame(bool p_swap_buffers);
void finalize();
diff --git a/drivers/gles3/shaders/copy.glsl b/drivers/gles3/shaders/copy.glsl
index 265acc1430..f37968a4fd 100644
--- a/drivers/gles3/shaders/copy.glsl
+++ b/drivers/gles3/shaders/copy.glsl
@@ -3,6 +3,7 @@
mode_default = #define MODE_SIMPLE_COPY
mode_copy_section = #define USE_COPY_SECTION \n#define MODE_SIMPLE_COPY
+mode_copy_section_source = #define USE_COPY_SECTION \n#define MODE_SIMPLE_COPY \n#define MODE_COPY_FROM
mode_gaussian_blur = #define MODE_GAUSSIAN_BLUR
mode_mipmap = #define MODE_MIPMAP
mode_simple_color = #define MODE_SIMPLE_COLOR \n#define USE_COPY_SECTION
@@ -21,7 +22,7 @@ out vec2 uv_interp;
// Defined in 0-1 coords.
uniform highp vec4 copy_section;
#endif
-#ifdef MODE_GAUSSIAN_BLUR
+#if defined(MODE_GAUSSIAN_BLUR) || defined(MODE_COPY_FROM)
uniform highp vec4 source_section;
#endif
@@ -32,7 +33,7 @@ void main() {
#if defined(USE_COPY_SECTION) || defined(MODE_GAUSSIAN_BLUR)
gl_Position.xy = (copy_section.xy + uv_interp.xy * copy_section.zw) * 2.0 - 1.0;
#endif
-#ifdef MODE_GAUSSIAN_BLUR
+#if defined(MODE_GAUSSIAN_BLUR) || defined(MODE_COPY_FROM)
uv_interp = source_section.xy + uv_interp * source_section.zw;
#endif
}
diff --git a/drivers/gles3/storage/texture_storage.cpp b/drivers/gles3/storage/texture_storage.cpp
index a44352a3e4..5a59f6c772 100644
--- a/drivers/gles3/storage/texture_storage.cpp
+++ b/drivers/gles3/storage/texture_storage.cpp
@@ -1475,7 +1475,7 @@ void TextureStorage::update_texture_atlas() {
//generate atlas
Vector<TextureAtlas::SortItem> itemsv;
itemsv.resize(texture_atlas.textures.size());
- int base_size = 8;
+ uint32_t base_size = 8;
int idx = 0;
@@ -1488,7 +1488,7 @@ void TextureStorage::update_texture_atlas() {
si.size.height = (src_tex->height / border) + 1;
si.pixel_size = Size2i(src_tex->width, src_tex->height);
- if (base_size < si.size.width) {
+ if (base_size < (uint32_t)si.size.width) {
base_size = nearest_power_of_2_templated(si.size.width);
}
@@ -1519,7 +1519,7 @@ void TextureStorage::update_texture_atlas() {
TextureAtlas::SortItem &si = items[i];
int best_idx = -1;
int best_height = 0x7FFFFFFF;
- for (int j = 0; j <= base_size - si.size.width; j++) {
+ for (uint32_t j = 0; j <= base_size - si.size.width; j++) {
int height = 0;
for (int k = 0; k < si.size.width; k++) {
int h = v_offsets[k + j];
@@ -1550,7 +1550,7 @@ void TextureStorage::update_texture_atlas() {
}
}
- if (max_height <= base_size * 2) {
+ if ((uint32_t)max_height <= base_size * 2) {
atlas_height = max_height;
break; //good ratio, break;
}
@@ -2647,7 +2647,10 @@ void TextureStorage::render_target_copy_to_back_buffer(RID p_render_target, cons
glBindFramebuffer(GL_FRAMEBUFFER, rt->backbuffer_fbo);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, rt->color);
- GLES3::CopyEffects::get_singleton()->copy_screen();
+ Rect2 normalized_region = region;
+ normalized_region.position = normalized_region.position / Size2(rt->size);
+ normalized_region.size = normalized_region.size / Size2(rt->size);
+ GLES3::CopyEffects::get_singleton()->copy_to_and_from_rect(normalized_region);
if (p_gen_mipmaps) {
GLES3::CopyEffects::get_singleton()->gaussian_blur(rt->backbuffer, rt->mipmap_count, region, rt->size);
diff --git a/drivers/vulkan/rendering_device_driver_vulkan.cpp b/drivers/vulkan/rendering_device_driver_vulkan.cpp
index 714394b505..8378e26666 100644
--- a/drivers/vulkan/rendering_device_driver_vulkan.cpp
+++ b/drivers/vulkan/rendering_device_driver_vulkan.cpp
@@ -733,6 +733,9 @@ RDD::TextureID RenderingDeviceDriverVulkan::texture_create_shared_from_slice(Tex
case TEXTURE_SLICE_2D_ARRAY: {
image_view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
} break;
+ default: {
+ return TextureID(nullptr);
+ }
}
image_view_create_info.format = RD_TO_VK_FORMAT[p_view.format];
image_view_create_info.components.r = (VkComponentSwizzle)p_view.swizzle_r;
@@ -1175,7 +1178,7 @@ bool RenderingDeviceDriverVulkan::command_buffer_begin_secondary(CommandBufferID
VkCommandBufferBeginInfo cmd_buf_begin_info = {};
cmd_buf_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
- cmd_buf_begin_info.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT | VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT;
+ cmd_buf_begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT | VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT;
cmd_buf_begin_info.pInheritanceInfo = &inheritance_info;
VkResult err = vkBeginCommandBuffer((VkCommandBuffer)p_cmd_buffer.id, &cmd_buf_begin_info);
@@ -1560,11 +1563,9 @@ RDD::ShaderID RenderingDeviceDriverVulkan::shader_create_from_bytecode(const Vec
read_offset += sizeof(ShaderBinary::SpecializationConstant);
}
- struct Stage {
- ShaderStage type = SHADER_STAGE_MAX;
- Vector<uint8_t> spirv;
- };
- Vector<Stage> stages;
+ Vector<Vector<uint8_t>> stages_spirv;
+ stages_spirv.resize(binary_data.stage_count);
+ r_shader_desc.stages.resize(binary_data.stage_count);
for (uint32_t i = 0; i < binary_data.stage_count; i++) {
ERR_FAIL_COND_V(read_offset + sizeof(uint32_t) * 3 >= binsize, ShaderID());
@@ -1590,17 +1591,14 @@ RDD::ShaderID RenderingDeviceDriverVulkan::shader_create_from_bytecode(const Vec
src_smolv = binptr + read_offset;
}
- Vector<uint8_t> spirv;
+ Vector<uint8_t> &spirv = stages_spirv.ptrw()[i];
uint32_t spirv_size = smolv::GetDecodedBufferSize(src_smolv, smolv_size);
spirv.resize(spirv_size);
if (!smolv::Decode(src_smolv, smolv_size, spirv.ptrw(), spirv_size)) {
ERR_FAIL_V_MSG(ShaderID(), "Malformed smolv input uncompressing shader stage:" + String(SHADER_STAGE_NAMES[stage]));
}
- Stage stage_entry;
- stage_entry.type = ShaderStage(stage);
- stage_entry.spirv = spirv;
- stages.push_back(stage_entry);
+ r_shader_desc.stages.set(i, ShaderStage(stage));
if (buf_size % 4 != 0) {
buf_size += 4 - (buf_size % 4);
@@ -1617,22 +1615,22 @@ RDD::ShaderID RenderingDeviceDriverVulkan::shader_create_from_bytecode(const Vec
String error_text;
- for (int i = 0; i < stages.size(); i++) {
+ for (int i = 0; i < r_shader_desc.stages.size(); i++) {
VkShaderModuleCreateInfo shader_module_create_info = {};
shader_module_create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
- shader_module_create_info.codeSize = stages[i].spirv.size();
- shader_module_create_info.pCode = (const uint32_t *)stages[i].spirv.ptr();
+ shader_module_create_info.codeSize = stages_spirv[i].size();
+ shader_module_create_info.pCode = (const uint32_t *)stages_spirv[i].ptr();
VkShaderModule vk_module = VK_NULL_HANDLE;
VkResult res = vkCreateShaderModule(vk_device, &shader_module_create_info, nullptr, &vk_module);
if (res) {
- error_text = "Error (" + itos(res) + ") creating shader module for stage: " + String(SHADER_STAGE_NAMES[stages[i].type]);
+ error_text = "Error (" + itos(res) + ") creating shader module for stage: " + String(SHADER_STAGE_NAMES[r_shader_desc.stages[i]]);
break;
}
VkPipelineShaderStageCreateInfo create_info = {};
create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
- create_info.stage = RD_STAGE_TO_VK_SHADER_STAGE_BITS[stages[i].type];
+ create_info.stage = RD_STAGE_TO_VK_SHADER_STAGE_BITS[r_shader_desc.stages[i]];
create_info.module = vk_module;
create_info.pName = "main";
@@ -3057,6 +3055,26 @@ void RenderingDeviceDriverVulkan::command_timestamp_write(CommandBufferID p_cmd_
}
/****************/
+/**** LABELS ****/
+/****************/
+
+void RenderingDeviceDriverVulkan::command_begin_label(CommandBufferID p_cmd_buffer, const char *p_label_name, const Color &p_color) {
+ VkDebugUtilsLabelEXT label;
+ label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
+ label.pNext = nullptr;
+ label.pLabelName = p_label_name;
+ label.color[0] = p_color[0];
+ label.color[1] = p_color[1];
+ label.color[2] = p_color[2];
+ label.color[3] = p_color[3];
+ vkCmdBeginDebugUtilsLabelEXT((VkCommandBuffer)p_cmd_buffer.id, &label);
+}
+
+void RenderingDeviceDriverVulkan::command_end_label(CommandBufferID p_cmd_buffer) {
+ vkCmdEndDebugUtilsLabelEXT((VkCommandBuffer)p_cmd_buffer.id);
+}
+
+/****************/
/**** SCREEN ****/
/****************/
diff --git a/drivers/vulkan/rendering_device_driver_vulkan.h b/drivers/vulkan/rendering_device_driver_vulkan.h
index 6d8f6fd0e0..1edee6b76e 100644
--- a/drivers/vulkan/rendering_device_driver_vulkan.h
+++ b/drivers/vulkan/rendering_device_driver_vulkan.h
@@ -433,6 +433,13 @@ public:
virtual void command_timestamp_write(CommandBufferID p_cmd_buffer, QueryPoolID p_pool_id, uint32_t p_index) override final;
/****************/
+ /**** LABELS ****/
+ /****************/
+
+ virtual void command_begin_label(CommandBufferID p_cmd_buffer, const char *p_label_name, const Color &p_color) override final;
+ virtual void command_end_label(CommandBufferID p_cmd_buffer) override final;
+
+ /****************/
/**** SCREEN ****/
/****************/
diff --git a/drivers/vulkan/vulkan_context.cpp b/drivers/vulkan/vulkan_context.cpp
index 1b1d4fa50f..7db2a9cd66 100644
--- a/drivers/vulkan/vulkan_context.cpp
+++ b/drivers/vulkan/vulkan_context.cpp
@@ -2395,9 +2395,11 @@ void VulkanContext::append_command_buffer(RDD::CommandBufferID p_command_buffer)
command_buffer_count++;
}
-void VulkanContext::flush(bool p_flush_setup, bool p_flush_pending) {
+void VulkanContext::flush(bool p_flush_setup, bool p_flush_pending, bool p_sync) {
// Ensure everything else pending is executed.
- vkDeviceWaitIdle(device);
+ if (p_sync) {
+ vkDeviceWaitIdle(device);
+ }
// Flush the pending setup buffer.
@@ -2440,7 +2442,9 @@ void VulkanContext::flush(bool p_flush_setup, bool p_flush_pending) {
ERR_FAIL_COND(err);
}
- vkDeviceWaitIdle(device);
+ if (p_sync) {
+ vkDeviceWaitIdle(device);
+ }
}
Error VulkanContext::prepare_buffers(RDD::CommandBufferID p_command_buffer) {
@@ -2504,7 +2508,7 @@ Error VulkanContext::swap_buffers() {
return OK;
}
- // print_line("swapbuffers?");
+ //print_line("swap_buffers");
VkResult err;
#if 0
@@ -2818,46 +2822,6 @@ void VulkanContext::local_device_free(RID p_local_device) {
local_device_owner.free(p_local_device);
}
-void VulkanContext::command_begin_label(RDD::CommandBufferID p_command_buffer, String p_label_name, const Color &p_color) {
- if (!is_instance_extension_enabled(VK_EXT_DEBUG_UTILS_EXTENSION_NAME)) {
- return;
- }
-
- CharString cs = p_label_name.utf8();
- VkDebugUtilsLabelEXT label;
- label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
- label.pNext = nullptr;
- label.pLabelName = cs.get_data();
- label.color[0] = p_color[0];
- label.color[1] = p_color[1];
- label.color[2] = p_color[2];
- label.color[3] = p_color[3];
- CmdBeginDebugUtilsLabelEXT((VkCommandBuffer)p_command_buffer.id, &label);
-}
-
-void VulkanContext::command_insert_label(RDD::CommandBufferID p_command_buffer, String p_label_name, const Color &p_color) {
- if (!is_instance_extension_enabled(VK_EXT_DEBUG_UTILS_EXTENSION_NAME)) {
- return;
- }
- CharString cs = p_label_name.utf8();
- VkDebugUtilsLabelEXT label;
- label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
- label.pNext = nullptr;
- label.pLabelName = cs.get_data();
- label.color[0] = p_color[0];
- label.color[1] = p_color[1];
- label.color[2] = p_color[2];
- label.color[3] = p_color[3];
- CmdInsertDebugUtilsLabelEXT((VkCommandBuffer)p_command_buffer.id, &label);
-}
-
-void VulkanContext::command_end_label(RDD::CommandBufferID p_command_buffer) {
- if (!is_instance_extension_enabled(VK_EXT_DEBUG_UTILS_EXTENSION_NAME)) {
- return;
- }
- CmdEndDebugUtilsLabelEXT((VkCommandBuffer)p_command_buffer.id);
-}
-
void VulkanContext::set_object_name(VkObjectType p_object_type, uint64_t p_object_handle, String p_object_name) {
if (!is_instance_extension_enabled(VK_EXT_DEBUG_UTILS_EXTENSION_NAME)) {
return;
@@ -2913,6 +2877,10 @@ RenderingDeviceDriver *VulkanContext::get_driver(RID p_local_device) {
}
}
+bool VulkanContext::is_debug_utils_enabled() const {
+ return is_instance_extension_enabled(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
+}
+
VulkanContext::VulkanContext() {
command_buffer_queue.resize(1); // First one is always the setup command.
command_buffer_queue[0] = nullptr;
diff --git a/drivers/vulkan/vulkan_context.h b/drivers/vulkan/vulkan_context.h
index ce1299a559..cbb6cf326f 100644
--- a/drivers/vulkan/vulkan_context.h
+++ b/drivers/vulkan/vulkan_context.h
@@ -321,15 +321,12 @@ public:
virtual void set_setup_buffer(RDD::CommandBufferID p_command_buffer) override final;
virtual void append_command_buffer(RDD::CommandBufferID p_command_buffer) override final;
void resize_notify();
- virtual void flush(bool p_flush_setup = false, bool p_flush_pending = false) override final;
+ virtual void flush(bool p_flush_setup = false, bool p_flush_pending = false, bool p_sync = true) override final;
virtual Error prepare_buffers(RDD::CommandBufferID p_command_buffer) override final;
virtual void postpare_buffers(RDD::CommandBufferID p_command_buffer) override final;
virtual Error swap_buffers() override final;
virtual Error initialize() override final;
- virtual void command_begin_label(RDD::CommandBufferID p_command_buffer, String p_label_name, const Color &p_color) override final;
- virtual void command_insert_label(RDD::CommandBufferID p_command_buffer, String p_label_name, const Color &p_color) override final;
- virtual void command_end_label(RDD::CommandBufferID p_command_buffer) override final;
void set_object_name(VkObjectType p_object_type, uint64_t p_object_handle, String p_object_name);
virtual String get_device_vendor_name() const override final;
@@ -342,6 +339,7 @@ public:
virtual DisplayServer::VSyncMode get_vsync_mode(DisplayServer::WindowID p_window = 0) const override final;
virtual RenderingDeviceDriver *get_driver(RID p_local_device = RID()) override final;
+ virtual bool is_debug_utils_enabled() const override final;
VulkanContext();
virtual ~VulkanContext();
diff --git a/drivers/wasapi/audio_driver_wasapi.cpp b/drivers/wasapi/audio_driver_wasapi.cpp
index e39373e7a0..64f2d1f203 100644
--- a/drivers/wasapi/audio_driver_wasapi.cpp
+++ b/drivers/wasapi/audio_driver_wasapi.cpp
@@ -557,13 +557,11 @@ Error AudioDriverWASAPI::init() {
target_latency_ms = Engine::get_singleton()->get_audio_output_latency();
- Error err = init_output_device();
- if (err != OK) {
- ERR_PRINT("WASAPI: init_output_device error");
- }
-
exit_thread.clear();
+ Error err = init_output_device();
+ ERR_FAIL_COND_V_MSG(err != OK, err, "WASAPI: init_output_device error.");
+
thread.start(thread_func, this);
return OK;
diff --git a/editor/action_map_editor.cpp b/editor/action_map_editor.cpp
index 7bb6ec0d5d..d7302d873f 100644
--- a/editor/action_map_editor.cpp
+++ b/editor/action_map_editor.cpp
@@ -36,6 +36,7 @@
#include "editor/event_listener_line_edit.h"
#include "editor/input_event_configuration_dialog.h"
#include "scene/gui/check_button.h"
+#include "scene/gui/separator.h"
#include "scene/gui/tree.h"
#include "scene/scene_string_names.h"
@@ -357,6 +358,7 @@ void ActionMapEditor::_notification(int p_what) {
case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
action_list_search->set_right_icon(get_editor_theme_icon(SNAME("Search")));
+ add_button->set_icon(get_editor_theme_icon(SNAME("Add")));
if (!actions_cache.is_empty()) {
update_action_list();
}
@@ -570,6 +572,8 @@ ActionMapEditor::ActionMapEditor() {
// Disable the button and set its tooltip.
_add_edit_text_changed(add_edit->get_text());
+ add_hbox->add_child(memnew(VSeparator));
+
show_builtin_actions_checkbutton = memnew(CheckButton);
show_builtin_actions_checkbutton->set_text(TTR("Show Built-in Actions"));
show_builtin_actions_checkbutton->connect("toggled", callable_mp(this, &ActionMapEditor::set_show_builtin_actions));
diff --git a/editor/animation_bezier_editor.cpp b/editor/animation_bezier_editor.cpp
index 08306256f1..4849a6824c 100644
--- a/editor/animation_bezier_editor.cpp
+++ b/editor/animation_bezier_editor.cpp
@@ -908,7 +908,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
if (Math::is_finite(minimum_time) && Math::is_finite(maximum_time) && maximum_time - minimum_time > CMP_EPSILON) {
timeline->get_zoom()->set_value(zoom_value);
- timeline->call_deferred("set_value", minimum_time);
+ callable_mp((Range *)timeline, &Range::set_value).call_deferred(minimum_time);
}
if (Math::is_finite(minimum_value) && Math::is_finite(maximum_value)) {
@@ -1520,7 +1520,7 @@ void AnimationBezierTrackEdit::_zoom_callback(float p_zoom_factor, Vector2 p_ori
// Alternate zoom (doesn't affect timeline).
timeline_v_zoom = CLAMP(timeline_v_zoom * p_zoom_factor, 0.000001, 100000);
} else {
- timeline->get_zoom()->set_value(timeline->get_zoom()->get_value() / p_zoom_factor);
+ timeline->_zoom_callback(p_zoom_factor, p_origin, p_event);
}
timeline_v_scroll = timeline_v_scroll + (p_origin.y - get_size().y / 2.0) * (timeline_v_zoom - v_zoom_orig);
queue_redraw();
@@ -1688,6 +1688,7 @@ void AnimationBezierTrackEdit::_bind_methods() {
AnimationBezierTrackEdit::AnimationBezierTrackEdit() {
panner.instantiate();
panner->set_callbacks(callable_mp(this, &AnimationBezierTrackEdit::_pan_callback), callable_mp(this, &AnimationBezierTrackEdit::_zoom_callback));
+ panner->set_scroll_zoom_factor(AnimationTimelineEdit::SCROLL_ZOOM_FACTOR);
play_position = memnew(Control);
play_position->set_mouse_filter(MOUSE_FILTER_PASS);
diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp
index d9d28e5c09..41a6d77860 100644
--- a/editor/animation_track_editor.cpp
+++ b/editor/animation_track_editor.cpp
@@ -1247,6 +1247,58 @@ void AnimationMultiTrackKeyEdit::set_use_fps(bool p_enable) {
}
void AnimationTimelineEdit::_zoom_changed(double) {
+ double zoom_pivot = 0; // Point on timeline to stay fixed.
+ double zoom_pivot_delta = 0; // Delta seconds from left-most point on timeline to zoom pivot.
+
+ int timeline_width_pixels = get_size().width - get_buttons_width() - get_name_limit();
+ double timeline_width_seconds = timeline_width_pixels / last_zoom_scale; // Length (in seconds) of visible part of timeline before zoom.
+ double updated_timeline_width_seconds = timeline_width_pixels / get_zoom_scale(); // Length after zoom.
+ double updated_timeline_half_width = updated_timeline_width_seconds / 2.0;
+ bool zooming = updated_timeline_width_seconds < timeline_width_seconds;
+
+ double timeline_left = get_value();
+ double timeline_right = timeline_left + timeline_width_seconds;
+ double timeline_center = timeline_left + timeline_width_seconds / 2.0;
+
+ if (zoom_callback_occured) { // Zooming with scroll wheel will focus on the position of the mouse.
+ double zoom_scroll_origin_norm = (zoom_scroll_origin.x - get_name_limit()) / timeline_width_pixels;
+ zoom_scroll_origin_norm = MAX(zoom_scroll_origin_norm, 0);
+ zoom_pivot = timeline_left + timeline_width_seconds * zoom_scroll_origin_norm;
+ zoom_pivot_delta = updated_timeline_width_seconds * zoom_scroll_origin_norm;
+ zoom_callback_occured = false;
+ } else { // Zooming with slider will depend on the current play position.
+ // If the play position is not in range, or exactly in the center, zoom in on the center.
+ if (get_play_position() < timeline_left || get_play_position() > timeline_left + timeline_width_seconds || get_play_position() == timeline_center) {
+ zoom_pivot = timeline_center;
+ zoom_pivot_delta = updated_timeline_half_width;
+ }
+ // Zoom from right if play position is right of center,
+ // and shrink from right if play position is left of center.
+ else if ((get_play_position() > timeline_center) == zooming) {
+ // If play position crosses to other side of center, center it.
+ bool center_passed = (get_play_position() < timeline_right - updated_timeline_half_width) == zooming;
+ zoom_pivot = center_passed ? get_play_position() : timeline_right;
+ double center_offset = CMP_EPSILON * (zooming ? 1 : -1); // Small offset to prevent crossover.
+ zoom_pivot_delta = center_passed ? updated_timeline_half_width + center_offset : updated_timeline_width_seconds;
+ }
+ // Zoom from left if play position is left of center,
+ // and shrink from left if play position is right of center.
+ else if ((get_play_position() <= timeline_center) == zooming) {
+ // If play position crosses to other side of center, center it.
+ bool center_passed = (get_play_position() > timeline_left + updated_timeline_half_width) == zooming;
+ zoom_pivot = center_passed ? get_play_position() : timeline_left;
+ double center_offset = CMP_EPSILON * (zooming ? -1 : 1); // Small offset to prevent crossover.
+ zoom_pivot_delta = center_passed ? updated_timeline_half_width + center_offset : 0;
+ }
+ }
+
+ double hscroll_pos = zoom_pivot - zoom_pivot_delta;
+ hscroll_pos = CLAMP(hscroll_pos, hscroll->get_min(), hscroll->get_max());
+
+ hscroll->set_value(hscroll_pos);
+ hscroll_on_zoom_buffer = hscroll_pos; // In case of page update.
+ last_zoom_scale = get_zoom_scale();
+
queue_redraw();
play_position->queue_redraw();
emit_signal(SNAME("zoom_changed"));
@@ -1428,6 +1480,11 @@ void AnimationTimelineEdit::_notification(int p_what) {
set_page(zoomw / scale);
+ if (hscroll->is_visible() && hscroll_on_zoom_buffer >= 0) {
+ hscroll->set_value(hscroll_on_zoom_buffer);
+ hscroll_on_zoom_buffer = -1.0;
+ }
+
int end_px = (l - get_value()) * scale;
int begin_px = -get_value() * scale;
Color notimecol = get_theme_color(SNAME("dark_color_2"), EditorStringName(Editor));
@@ -1733,7 +1790,9 @@ void AnimationTimelineEdit::_pan_callback(Vector2 p_scroll_vec, Ref<InputEvent>
void AnimationTimelineEdit::_zoom_callback(float p_zoom_factor, Vector2 p_origin, Ref<InputEvent> p_event) {
double current_zoom_value = get_zoom()->get_value();
- get_zoom()->set_value(MAX(0.01, current_zoom_value * p_zoom_factor));
+ zoom_scroll_origin = p_origin;
+ zoom_callback_occured = true;
+ get_zoom()->set_value(MAX(0.01, current_zoom_value - (1.0 - p_zoom_factor)));
}
void AnimationTimelineEdit::set_use_fps(bool p_use_fps) {
@@ -1809,6 +1868,7 @@ AnimationTimelineEdit::AnimationTimelineEdit() {
len_hb->hide();
panner.instantiate();
+ panner->set_scroll_zoom_factor(SCROLL_ZOOM_FACTOR);
panner->set_callbacks(callable_mp(this, &AnimationTimelineEdit::_pan_callback), callable_mp(this, &AnimationTimelineEdit::_zoom_callback));
panner->set_pan_axis(ViewPanner::PAN_AXIS_HORIZONTAL);
@@ -4553,7 +4613,7 @@ void AnimationTrackEditor::_animation_changed() {
}
animation_changing_awaiting_update = true;
- call_deferred(SNAME("_animation_update"));
+ callable_mp(this, &AnimationTrackEditor::_animation_update).call_deferred();
}
void AnimationTrackEditor::_snap_mode_changed(int p_mode) {
@@ -5493,8 +5553,7 @@ void AnimationTrackEditor::_pan_callback(Vector2 p_scroll_vec, Ref<InputEvent> p
}
void AnimationTrackEditor::_zoom_callback(float p_zoom_factor, Vector2 p_origin, Ref<InputEvent> p_event) {
- double current_zoom_value = timeline->get_zoom()->get_value();
- timeline->get_zoom()->set_value(MAX(0.01, current_zoom_value * p_zoom_factor));
+ timeline->_zoom_callback(p_zoom_factor, p_origin, p_event);
}
void AnimationTrackEditor::_cancel_bezier_edit() {
@@ -6075,9 +6134,12 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
if (animation->track_get_type(sk.track) == Animation::TYPE_VALUE) {
undo_redo->add_do_method(reset.ptr(), "value_track_set_update_mode", dst_track, animation->value_track_get_update_mode(sk.track));
- undo_redo->add_do_method(reset.ptr(), "track_set_interpolation_type", dst_track, animation->track_get_interpolation_type(sk.track));
- undo_redo->add_do_method(reset.ptr(), "track_set_interpolation_loop_wrap", dst_track, animation->track_get_interpolation_loop_wrap(sk.track));
}
+ if (animation->track_get_type(sk.track) == Animation::TYPE_AUDIO) {
+ undo_redo->add_do_method(reset.ptr(), "audio_track_set_use_blend", dst_track, animation->audio_track_is_use_blend(sk.track));
+ }
+ undo_redo->add_do_method(reset.ptr(), "track_set_interpolation_type", dst_track, animation->track_get_interpolation_type(sk.track));
+ undo_redo->add_do_method(reset.ptr(), "track_set_interpolation_loop_wrap", dst_track, animation->track_get_interpolation_loop_wrap(sk.track));
undo_redo->add_do_method(reset.ptr(), "track_insert_key", dst_track, 0, animation->track_get_key_value(sk.track, sk.key), animation->track_get_key_transition(sk.track, sk.key));
undo_redo->add_undo_method(reset.ptr(), "track_remove_key_at_time", dst_track, 0);
@@ -6416,7 +6478,6 @@ void AnimationTrackEditor::_select_all_tracks_for_copy() {
}
void AnimationTrackEditor::_bind_methods() {
- ClassDB::bind_method("_animation_update", &AnimationTrackEditor::_animation_update);
ClassDB::bind_method("_track_grab_focus", &AnimationTrackEditor::_track_grab_focus);
ClassDB::bind_method("_redraw_tracks", &AnimationTrackEditor::_redraw_tracks);
ClassDB::bind_method("_clear_selection_for_anim", &AnimationTrackEditor::_clear_selection_for_anim);
@@ -6530,6 +6591,7 @@ AnimationTrackEditor::AnimationTrackEditor() {
timeline->connect("length_changed", callable_mp(this, &AnimationTrackEditor::_update_length));
panner.instantiate();
+ panner->set_scroll_zoom_factor(AnimationTimelineEdit::SCROLL_ZOOM_FACTOR);
panner->set_callbacks(callable_mp(this, &AnimationTrackEditor::_pan_callback), callable_mp(this, &AnimationTrackEditor::_zoom_callback));
scroll = memnew(ScrollContainer);
diff --git a/editor/animation_track_editor.h b/editor/animation_track_editor.h
index 0667b8e80e..b5242e2f67 100644
--- a/editor/animation_track_editor.h
+++ b/editor/animation_track_editor.h
@@ -131,6 +131,11 @@ protected:
class AnimationTimelineEdit : public Range {
GDCLASS(AnimationTimelineEdit, Range);
+ friend class AnimationBezierTrackEdit;
+ friend class AnimationTrackEditor;
+
+ static constexpr float SCROLL_ZOOM_FACTOR = 1.02f; // Zoom factor per mouse scroll in the animation editor. The closer to 1.0, the finer the control.
+
Ref<Animation> animation;
bool read_only = false;
@@ -167,6 +172,11 @@ class AnimationTimelineEdit : public Range {
bool dragging_hsize = false;
float dragging_hsize_from = 0.0f;
float dragging_hsize_at = 0.0f;
+ double last_zoom_scale = 1.0;
+ double hscroll_on_zoom_buffer = -1.0;
+
+ Vector2 zoom_scroll_origin;
+ bool zoom_callback_occured = false;
virtual void gui_input(const Ref<InputEvent> &p_event) override;
void _track_added(int p_track);
diff --git a/editor/audio_stream_preview.cpp b/editor/audio_stream_preview.cpp
index c1935b4844..0b9289ff06 100644
--- a/editor/audio_stream_preview.cpp
+++ b/editor/audio_stream_preview.cpp
@@ -158,7 +158,7 @@ void AudioStreamPreviewGenerator::_preview_thread(void *p_preview) {
}
frames_todo -= to_read;
- singleton->call_deferred(SNAME("_update_emit"), preview->id);
+ callable_mp(singleton, &AudioStreamPreviewGenerator::_update_emit).call_deferred(preview->id);
}
preview->preview->version++;
@@ -216,7 +216,6 @@ Ref<AudioStreamPreview> AudioStreamPreviewGenerator::generate_preview(const Ref<
}
void AudioStreamPreviewGenerator::_bind_methods() {
- ClassDB::bind_method("_update_emit", &AudioStreamPreviewGenerator::_update_emit);
ClassDB::bind_method(D_METHOD("generate_preview", "stream"), &AudioStreamPreviewGenerator::generate_preview);
ADD_SIGNAL(MethodInfo("preview_updated", PropertyInfo(Variant::INT, "obj_id")));
diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp
index b17affa246..d9101466fc 100644
--- a/editor/code_editor.cpp
+++ b/editor/code_editor.cpp
@@ -336,7 +336,7 @@ void FindReplaceBar::_replace_all() {
matches_label->add_theme_color_override("font_color", rc > 0 ? get_theme_color(SNAME("font_color"), SNAME("Label")) : get_theme_color(SNAME("error_color"), EditorStringName(Editor)));
matches_label->set_text(vformat(TTR("%d replaced."), rc));
- text_editor->call_deferred(SNAME("connect"), "text_changed", callable_mp(this, &FindReplaceBar::_editor_text_changed));
+ callable_mp((Object *)text_editor, &Object::connect).call_deferred("text_changed", callable_mp(this, &FindReplaceBar::_editor_text_changed), 0U);
results_count = -1;
results_count_to_current = -1;
needs_to_count_results = true;
@@ -517,10 +517,10 @@ void FindReplaceBar::_show_search(bool p_focus_replace, bool p_show_only) {
if (p_focus_replace) {
search_text->deselect();
- replace_text->call_deferred(SNAME("grab_focus"));
+ callable_mp((Control *)replace_text, &Control::grab_focus).call_deferred();
} else {
replace_text->deselect();
- search_text->call_deferred(SNAME("grab_focus"));
+ callable_mp((Control *)search_text, &Control::grab_focus).call_deferred();
}
if (text_editor->has_selection(0) && !is_selection_only()) {
@@ -1572,20 +1572,20 @@ void CodeTextEditor::goto_line(int p_line) {
text_editor->remove_secondary_carets();
text_editor->deselect();
text_editor->unfold_line(p_line);
- text_editor->call_deferred(SNAME("set_caret_line"), p_line);
+ callable_mp((TextEdit *)text_editor, &TextEdit::set_caret_line).call_deferred(p_line, true, true, 0, 0);
}
void CodeTextEditor::goto_line_selection(int p_line, int p_begin, int p_end) {
text_editor->remove_secondary_carets();
text_editor->unfold_line(p_line);
- text_editor->call_deferred(SNAME("set_caret_line"), p_line);
- text_editor->call_deferred(SNAME("set_caret_column"), p_begin);
+ callable_mp((TextEdit *)text_editor, &TextEdit::set_caret_line).call_deferred(p_line, true, true, 0, 0);
+ callable_mp((TextEdit *)text_editor, &TextEdit::set_caret_column).call_deferred(p_begin, true, 0);
text_editor->select(p_line, p_begin, p_line, p_end);
}
void CodeTextEditor::goto_line_centered(int p_line) {
goto_line(p_line);
- text_editor->call_deferred(SNAME("center_viewport_to_caret"));
+ callable_mp((TextEdit *)text_editor, &TextEdit::center_viewport_to_caret).call_deferred(0);
}
void CodeTextEditor::set_executing_line(int p_line) {
diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp
index c4ca90d1e1..49d997fc6a 100644
--- a/editor/create_dialog.cpp
+++ b/editor/create_dialog.cpp
@@ -474,7 +474,7 @@ void CreateDialog::_notification(int p_what) {
case NOTIFICATION_VISIBILITY_CHANGED: {
if (is_visible()) {
- search_box->call_deferred(SNAME("grab_focus")); // still not visible
+ callable_mp((Control *)search_box, &Control::grab_focus).call_deferred(); // Still not visible.
search_box->select_all();
} else {
EditorSettings::get_singleton()->set_project_metadata("dialog_bounds", "create_new_node", Rect2(get_position(), get_size()));
diff --git a/editor/debugger/debug_adapter/debug_adapter_parser.cpp b/editor/debugger/debug_adapter/debug_adapter_parser.cpp
index 929f323e80..e854681010 100644
--- a/editor/debugger/debug_adapter/debug_adapter_parser.cpp
+++ b/editor/debugger/debug_adapter/debug_adapter_parser.cpp
@@ -44,7 +44,7 @@ void DebugAdapterParser::_bind_methods() {
ClassDB::bind_method(D_METHOD("req_attach", "params"), &DebugAdapterParser::req_attach);
ClassDB::bind_method(D_METHOD("req_restart", "params"), &DebugAdapterParser::req_restart);
ClassDB::bind_method(D_METHOD("req_terminate", "params"), &DebugAdapterParser::req_terminate);
- ClassDB::bind_method(D_METHOD("req_configurationDone", "params"), &DebugAdapterParser::prepare_success_response);
+ ClassDB::bind_method(D_METHOD("req_configurationDone", "params"), &DebugAdapterParser::req_configurationDone);
ClassDB::bind_method(D_METHOD("req_pause", "params"), &DebugAdapterParser::req_pause);
ClassDB::bind_method(D_METHOD("req_continue", "params"), &DebugAdapterParser::req_continue);
ClassDB::bind_method(D_METHOD("req_threads", "params"), &DebugAdapterParser::req_threads);
@@ -180,6 +180,13 @@ Dictionary DebugAdapterParser::req_launch(const Dictionary &p_params) const {
DebugAdapterProtocol::get_singleton()->get_current_peer()->supportsCustomData = args["godot/custom_data"];
}
+ DebugAdapterProtocol::get_singleton()->get_current_peer()->pending_launch = p_params;
+
+ return Dictionary();
+}
+
+Dictionary DebugAdapterParser::_launch_process(const Dictionary &p_params) const {
+ Dictionary args = p_params["arguments"];
ScriptEditorDebugger *dbg = EditorDebuggerNode::get_singleton()->get_default_debugger();
if ((bool)args["noDebug"] != dbg->is_skip_breakpoints()) {
dbg->debug_skip_breakpoints();
@@ -246,7 +253,7 @@ Dictionary DebugAdapterParser::req_restart(const Dictionary &p_params) const {
args = args["arguments"];
params["arguments"] = args;
- Dictionary response = DebugAdapterProtocol::get_singleton()->get_current_peer()->attached ? req_attach(params) : req_launch(params);
+ Dictionary response = DebugAdapterProtocol::get_singleton()->get_current_peer()->attached ? req_attach(params) : _launch_process(params);
if (!response["success"]) {
response["command"] = p_params["command"];
return response;
@@ -261,6 +268,16 @@ Dictionary DebugAdapterParser::req_terminate(const Dictionary &p_params) const {
return prepare_success_response(p_params);
}
+Dictionary DebugAdapterParser::req_configurationDone(const Dictionary &p_params) const {
+ Ref<DAPeer> peer = DebugAdapterProtocol::get_singleton()->get_current_peer();
+ if (!peer->pending_launch.is_empty()) {
+ peer->res_queue.push_back(_launch_process(peer->pending_launch));
+ peer->pending_launch.clear();
+ }
+
+ return prepare_success_response(p_params);
+}
+
Dictionary DebugAdapterParser::req_pause(const Dictionary &p_params) const {
EditorRunBar::get_singleton()->get_pause_button()->set_pressed(true);
EditorDebuggerNode::get_singleton()->_paused();
diff --git a/editor/debugger/debug_adapter/debug_adapter_parser.h b/editor/debugger/debug_adapter/debug_adapter_parser.h
index 9995066ab4..e5493a4b9f 100644
--- a/editor/debugger/debug_adapter/debug_adapter_parser.h
+++ b/editor/debugger/debug_adapter/debug_adapter_parser.h
@@ -71,6 +71,7 @@ public:
Dictionary req_attach(const Dictionary &p_params) const;
Dictionary req_restart(const Dictionary &p_params) const;
Dictionary req_terminate(const Dictionary &p_params) const;
+ Dictionary req_configurationDone(const Dictionary &p_params) const;
Dictionary req_pause(const Dictionary &p_params) const;
Dictionary req_continue(const Dictionary &p_params) const;
Dictionary req_threads(const Dictionary &p_params) const;
@@ -84,6 +85,9 @@ public:
Dictionary req_evaluate(const Dictionary &p_params) const;
Dictionary req_godot_put_msg(const Dictionary &p_params) const;
+ // Internal requests
+ Dictionary _launch_process(const Dictionary &p_params) const;
+
// Events
Dictionary ev_initialized() const;
Dictionary ev_process(const String &p_command) const;
diff --git a/editor/debugger/debug_adapter/debug_adapter_protocol.cpp b/editor/debugger/debug_adapter/debug_adapter_protocol.cpp
index 26fb73570e..7417a3d8f7 100644
--- a/editor/debugger/debug_adapter/debug_adapter_protocol.cpp
+++ b/editor/debugger/debug_adapter/debug_adapter_protocol.cpp
@@ -678,7 +678,10 @@ bool DebugAdapterProtocol::process_message(const String &p_text) {
if (!response.is_empty()) {
_current_peer->res_queue.push_front(response);
} else {
- completed = false;
+ // Launch request needs to be deferred until we receive a configurationDone request.
+ if (command != "req_launch") {
+ completed = false;
+ }
}
}
diff --git a/editor/debugger/debug_adapter/debug_adapter_protocol.h b/editor/debugger/debug_adapter/debug_adapter_protocol.h
index ddc55816db..fb1c533bbb 100644
--- a/editor/debugger/debug_adapter/debug_adapter_protocol.h
+++ b/editor/debugger/debug_adapter/debug_adapter_protocol.h
@@ -63,6 +63,7 @@ struct DAPeer : RefCounted {
// Internal client info
bool attached = false;
+ Dictionary pending_launch;
Error handle_data();
Error send_data();
diff --git a/editor/debugger/editor_debugger_node.cpp b/editor/debugger/editor_debugger_node.cpp
index 8229abb5a0..372d558aab 100644
--- a/editor/debugger/editor_debugger_node.cpp
+++ b/editor/debugger/editor_debugger_node.cpp
@@ -455,7 +455,7 @@ void EditorDebuggerNode::_debugger_wants_stop(int p_id) {
// Ask editor to kill PID.
int pid = get_debugger(p_id)->get_remote_pid();
if (pid) {
- EditorNode::get_singleton()->call_deferred(SNAME("stop_child_process"), pid);
+ callable_mp(EditorNode::get_singleton(), &EditorNode::stop_child_process).call_deferred(pid);
}
}
diff --git a/editor/debugger/editor_debugger_tree.cpp b/editor/debugger/editor_debugger_tree.cpp
index 6305b7435a..7d3ea33fb5 100644
--- a/editor/debugger/editor_debugger_tree.cpp
+++ b/editor/debugger/editor_debugger_tree.cpp
@@ -253,7 +253,7 @@ void EditorDebuggerTree::update_scene_tree(const SceneDebuggerTree *p_tree, int
}
debugger_id = p_debugger; // Needed by hook, could be avoided if every debugger had its own tree
if (scroll_item) {
- call_deferred(SNAME("scroll_to_item"), scroll_item);
+ callable_mp((Tree *)this, &Tree::scroll_to_item).call_deferred(scroll_item, false);
}
last_filter = filter;
updating_scene_tree = false;
diff --git a/editor/editor_audio_buses.cpp b/editor/editor_audio_buses.cpp
index f4a9e0a2ef..c1183c8d66 100644
--- a/editor/editor_audio_buses.cpp
+++ b/editor/editor_audio_buses.cpp
@@ -1234,7 +1234,7 @@ void EditorAudioBuses::_load_default_layout() {
AudioServer::get_singleton()->set_bus_layout(state);
_rebuild_buses();
EditorUndoRedoManager::get_singleton()->clear_history(true, EditorUndoRedoManager::GLOBAL_HISTORY);
- call_deferred(SNAME("_select_layout"));
+ callable_mp(this, &EditorAudioBuses::_select_layout).call_deferred();
}
void EditorAudioBuses::_file_dialog_callback(const String &p_string) {
@@ -1250,7 +1250,7 @@ void EditorAudioBuses::_file_dialog_callback(const String &p_string) {
AudioServer::get_singleton()->set_bus_layout(state);
_rebuild_buses();
EditorUndoRedoManager::get_singleton()->clear_history(true, EditorUndoRedoManager::GLOBAL_HISTORY);
- call_deferred(SNAME("_select_layout"));
+ callable_mp(this, &EditorAudioBuses::_select_layout).call_deferred();
} else if (file_dialog->get_file_mode() == EditorFileDialog::FILE_MODE_SAVE_FILE) {
if (new_layout) {
@@ -1270,14 +1270,13 @@ void EditorAudioBuses::_file_dialog_callback(const String &p_string) {
file->set_text(String(TTR("Layout:")) + " " + p_string.get_file());
_rebuild_buses();
EditorUndoRedoManager::get_singleton()->clear_history(true, EditorUndoRedoManager::GLOBAL_HISTORY);
- call_deferred(SNAME("_select_layout"));
+ callable_mp(this, &EditorAudioBuses::_select_layout).call_deferred();
}
}
void EditorAudioBuses::_bind_methods() {
ClassDB::bind_method("_update_bus", &EditorAudioBuses::_update_bus);
ClassDB::bind_method("_update_sends", &EditorAudioBuses::_update_sends);
- ClassDB::bind_method("_select_layout", &EditorAudioBuses::_select_layout);
}
EditorAudioBuses::EditorAudioBuses() {
@@ -1370,7 +1369,7 @@ void EditorAudioBuses::open_layout(const String &p_path) {
AudioServer::get_singleton()->set_bus_layout(state);
_rebuild_buses();
EditorUndoRedoManager::get_singleton()->clear_history(true, EditorUndoRedoManager::GLOBAL_HISTORY);
- call_deferred(SNAME("_select_layout"));
+ callable_mp(this, &EditorAudioBuses::_select_layout).call_deferred();
}
void AudioBusesEditorPlugin::edit(Object *p_node) {
diff --git a/editor/editor_autoload_settings.cpp b/editor/editor_autoload_settings.cpp
index 204b717296..45de4a54ae 100644
--- a/editor/editor_autoload_settings.cpp
+++ b/editor/editor_autoload_settings.cpp
@@ -57,7 +57,7 @@ void EditorAutoloadSettings::_notification(int p_what) {
for (const AutoloadInfo &info : autoload_cache) {
if (info.node && info.in_editor) {
- get_tree()->get_root()->call_deferred(SNAME("add_child"), info.node);
+ callable_mp((Node *)get_tree()->get_root(), &Node::add_child).call_deferred(info.node, false, Node::INTERNAL_MODE_DISABLED);
}
}
browse_button->set_icon(get_editor_theme_icon(SNAME("Folder")));
@@ -65,6 +65,7 @@ void EditorAutoloadSettings::_notification(int p_what) {
case NOTIFICATION_THEME_CHANGED: {
browse_button->set_icon(get_editor_theme_icon(SNAME("Folder")));
+ add_autoload->set_icon(get_editor_theme_icon(SNAME("Add")));
} break;
case NOTIFICATION_VISIBILITY_CHANGED: {
@@ -533,7 +534,7 @@ void EditorAutoloadSettings::update_autoload() {
}
if (info.in_editor) {
ERR_CONTINUE(!info.node);
- get_tree()->get_root()->call_deferred(SNAME("remove_child"), info.node);
+ callable_mp((Node *)get_tree()->get_root(), &Node::remove_child).call_deferred(info.node);
}
if (info.node) {
diff --git a/editor/editor_command_palette.cpp b/editor/editor_command_palette.cpp
index 337271ea3d..ce5d8619e1 100644
--- a/editor/editor_command_palette.cpp
+++ b/editor/editor_command_palette.cpp
@@ -74,7 +74,7 @@ void EditorCommandPalette::_update_command_search(const String &search_text) {
CommandEntry r;
r.key_name = E.key;
r.display_name = E.value.name;
- r.shortcut_text = E.value.shortcut;
+ r.shortcut_text = E.value.shortcut_text;
r.last_used = E.value.last_used;
bool is_subsequence_of_key_name = search_text.is_subsequence_ofn(r.key_name);
@@ -166,6 +166,19 @@ void EditorCommandPalette::_notification(int p_what) {
case NOTIFICATION_THEME_CHANGED: {
command_search_box->set_right_icon(get_editor_theme_icon(SNAME("Search")));
} break;
+
+ case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
+ if (!EditorSettings::get_singleton()->check_changed_settings_in_group("shortcuts")) {
+ break;
+ }
+
+ for (KeyValue<String, Command> &kv : commands) {
+ Command &c = kv.value;
+ if (c.shortcut.is_valid()) {
+ c.shortcut_text = c.shortcut->get_as_text();
+ }
+ }
+ } break;
}
}
@@ -219,7 +232,7 @@ void EditorCommandPalette::remove_command(String p_key_name) {
commands.erase(p_key_name);
}
-void EditorCommandPalette::add_command(String p_command_name, String p_key_name, Callable p_action, Vector<Variant> arguments, String p_shortcut_text) {
+void EditorCommandPalette::add_command(String p_command_name, String p_key_name, Callable p_action, Vector<Variant> arguments, const Ref<Shortcut> &p_shortcut) {
ERR_FAIL_COND_MSG(commands.has(p_key_name), "The Command '" + String(p_command_name) + "' already exists. Unable to add it.");
const Variant **argptrs = (const Variant **)alloca(sizeof(Variant *) * arguments.size());
@@ -229,7 +242,12 @@ void EditorCommandPalette::add_command(String p_command_name, String p_key_name,
Command command;
command.name = p_command_name;
command.callable = p_action.bindp(argptrs, arguments.size());
- command.shortcut = p_shortcut_text;
+ if (p_shortcut.is_null()) {
+ command.shortcut_text = "None";
+ } else {
+ command.shortcut = p_shortcut;
+ command.shortcut_text = p_shortcut->get_as_text();
+ }
commands[p_key_name] = command;
}
@@ -240,7 +258,7 @@ void EditorCommandPalette::_add_command(String p_command_name, String p_key_name
Command command;
command.name = p_command_name;
command.callable = p_binded_action;
- command.shortcut = p_shortcut_text;
+ command.shortcut_text = p_shortcut_text;
// Commands added from plugins don't exist yet when the history is loaded, so we assign the last use time here if it was recorded.
Dictionary command_history = EditorSettings::get_singleton()->get_project_metadata("command_palette", "command_history", Dictionary());
@@ -273,8 +291,7 @@ void EditorCommandPalette::register_shortcuts_as_command() {
Ref<InputEventShortcut> ev;
ev.instantiate();
ev->set_shortcut(shortcut);
- String shortcut_text = String(shortcut->get_as_text());
- add_command(command_name, E.key, callable_mp(EditorNode::get_singleton()->get_viewport(), &Viewport::push_input), varray(ev, false), shortcut_text);
+ add_command(command_name, E.key, callable_mp(EditorNode::get_singleton()->get_viewport(), &Viewport::push_input), varray(ev, false), shortcut);
}
unregistered_shortcuts.clear();
@@ -294,8 +311,7 @@ Ref<Shortcut> EditorCommandPalette::add_shortcut_command(const String &p_command
Ref<InputEventShortcut> ev;
ev.instantiate();
ev->set_shortcut(p_shortcut);
- String shortcut_text = String(p_shortcut->get_as_text());
- add_command(p_command, p_key, callable_mp(EditorNode::get_singleton()->get_viewport(), &Viewport::push_input), varray(ev, false), shortcut_text);
+ add_command(p_command, p_key, callable_mp(EditorNode::get_singleton()->get_viewport(), &Viewport::push_input), varray(ev, false), p_shortcut);
} else {
const String key_name = String(p_key);
const String command_name = String(p_command);
diff --git a/editor/editor_command_palette.h b/editor/editor_command_palette.h
index 5d666aeaa3..cc0f726b3a 100644
--- a/editor/editor_command_palette.h
+++ b/editor/editor_command_palette.h
@@ -46,7 +46,8 @@ class EditorCommandPalette : public ConfirmationDialog {
struct Command {
Callable callable;
String name;
- String shortcut;
+ Ref<Shortcut> shortcut;
+ String shortcut_text;
int last_used = 0; // Store time as int, because doubles have problems with text serialization.
};
@@ -93,7 +94,7 @@ protected:
public:
void open_popup();
void get_actions_list(List<String> *p_list) const;
- void add_command(String p_command_name, String p_key_name, Callable p_action, Vector<Variant> arguments, String p_shortcut_text = "None");
+ void add_command(String p_command_name, String p_key_name, Callable p_action, Vector<Variant> arguments, const Ref<Shortcut> &p_shortcut);
void execute_command(const String &p_command_name);
void register_shortcuts_as_command();
Ref<Shortcut> add_shortcut_command(const String &p_command, const String &p_key, Ref<Shortcut> p_shortcut);
diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp
index fe8c42ea3b..5f77959127 100644
--- a/editor/editor_data.cpp
+++ b/editor/editor_data.cpp
@@ -1242,7 +1242,6 @@ void EditorSelection::_bind_methods() {
ClassDB::bind_method(D_METHOD("remove_node", "node"), &EditorSelection::remove_node);
ClassDB::bind_method(D_METHOD("get_selected_nodes"), &EditorSelection::get_selected_nodes);
ClassDB::bind_method(D_METHOD("get_transformable_selected_nodes"), &EditorSelection::_get_transformable_selected_nodes);
- ClassDB::bind_method(D_METHOD("_emit_change"), &EditorSelection::_emit_change);
ADD_SIGNAL(MethodInfo("selection_changed"));
}
@@ -1290,7 +1289,7 @@ void EditorSelection::update() {
changed = false;
if (!emitted) {
emitted = true;
- call_deferred(SNAME("_emit_change"));
+ callable_mp(this, &EditorSelection::_emit_change).call_deferred();
}
}
diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp
index d52dd42493..aab433ac27 100644
--- a/editor/editor_file_system.cpp
+++ b/editor/editor_file_system.cpp
@@ -2693,7 +2693,7 @@ EditorFileSystem::EditorFileSystem() {
using_fat32_or_exfat = (da->get_filesystem_type() == "FAT32" || da->get_filesystem_type() == "exFAT");
scan_total = 0;
- MessageQueue::get_singleton()->push_callable(callable_mp(ResourceUID::get_singleton(), &ResourceUID::clear)); // Will be updated on scan.
+ callable_mp(ResourceUID::get_singleton(), &ResourceUID::clear).call_deferred(); // Will be updated on scan.
ResourceSaver::set_get_resource_id_for_path(_resource_saver_get_resource_id_for_path);
}
diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp
index cdb187bd44..6e448d8866 100644
--- a/editor/editor_help.cpp
+++ b/editor/editor_help.cpp
@@ -1966,7 +1966,7 @@ void EditorHelp::_help_callback(const String &p_topic) {
}
if (class_desc->is_ready()) {
- class_desc->call_deferred(SNAME("scroll_to_paragraph"), line);
+ callable_mp(class_desc, &RichTextLabel::scroll_to_paragraph).call_deferred(line);
} else {
scroll_to = line;
}
diff --git a/editor/editor_help_search.cpp b/editor/editor_help_search.cpp
index 44698d93f6..64bd209d4d 100644
--- a/editor/editor_help_search.cpp
+++ b/editor/editor_help_search.cpp
@@ -96,7 +96,7 @@ void EditorHelpSearch::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_VISIBILITY_CHANGED: {
if (!is_visible()) {
- results_tree->call_deferred(SNAME("clear")); // Wait for the Tree's mouse event propagation.
+ callable_mp(results_tree, &Tree::clear).call_deferred(); // Wait for the Tree's mouse event propagation.
get_ok_button()->set_disabled(true);
EditorSettings::get_singleton()->set_project_metadata("dialog_bounds", "search_help", Rect2(get_position(), get_size()));
}
diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp
index 5fd387bbdc..6809739dc1 100644
--- a/editor/editor_inspector.cpp
+++ b/editor/editor_inspector.cpp
@@ -695,15 +695,14 @@ void EditorProperty::gui_input(const Ref<InputEvent> &p_event) {
new_coords.y++;
}
if (new_coords.x < int64_t(object->get("hframes")) && new_coords.y < int64_t(object->get("vframes"))) {
- call_deferred(SNAME("emit_changed"), property, new_coords, "", false);
+ callable_mp(this, &EditorProperty::emit_changed).call_deferred(property, new_coords, "", false);
}
} else {
if (int64_t(object->get(property)) + 1 < (int64_t(object->get("hframes")) * int64_t(object->get("vframes")))) {
- call_deferred(SNAME("emit_changed"), property, object->get(property).operator int64_t() + 1, "", false);
+ callable_mp(this, &EditorProperty::emit_changed).call_deferred(property, object->get(property).operator int64_t() + 1, "", false);
}
}
-
- call_deferred(SNAME("update_property"));
+ callable_mp(this, &EditorProperty::update_property).call_deferred();
}
}
if (delete_rect.has_point(mpos)) {
@@ -3980,7 +3979,7 @@ void EditorInspector::_notification(int p_what) {
case NOTIFICATION_PROCESS: {
if (update_scroll_request >= 0) {
- get_v_scroll_bar()->call_deferred(SNAME("set_value"), update_scroll_request);
+ callable_mp((Range *)get_v_scroll_bar(), &Range::set_value).call_deferred(update_scroll_request);
update_scroll_request = -1;
}
if (update_tree_pending) {
diff --git a/editor/editor_interface.cpp b/editor/editor_interface.cpp
index af1d23a4fe..b007f6d530 100644
--- a/editor/editor_interface.cpp
+++ b/editor/editor_interface.cpp
@@ -400,6 +400,21 @@ bool EditorInterface::is_movie_maker_enabled() const {
}
// Base.
+void EditorInterface::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const {
+ String pf = p_function;
+ if (p_idx == 0) {
+ if (pf == "set_main_screen_editor") {
+ for (String E : { "\"2D\"", "\"3D\"", "\"Script\"", "\"AssetLib\"" }) {
+ r_options->push_back(E);
+ }
+ } else if (pf == "get_editor_viewport_3d") {
+ for (uint32_t i = 0; i < Node3DEditor::VIEWPORTS_COUNT; i++) {
+ r_options->push_back(String::num_int64(i));
+ }
+ }
+ }
+ Object::get_argument_options(p_function, p_idx, r_options);
+}
void EditorInterface::_bind_methods() {
ClassDB::bind_method(D_METHOD("restart_editor", "save"), &EditorInterface::restart_editor, DEFVAL(true));
diff --git a/editor/editor_interface.h b/editor/editor_interface.h
index 079fc169f2..73e89ae2f2 100644
--- a/editor/editor_interface.h
+++ b/editor/editor_interface.h
@@ -152,6 +152,8 @@ public:
// Base.
+ virtual void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const override;
+
static void create();
static void free();
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 91e27efeee..fd1d598f90 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -38,7 +38,6 @@
#include "core/io/resource_loader.h"
#include "core/io/resource_saver.h"
#include "core/object/class_db.h"
-#include "core/object/message_queue.h"
#include "core/os/keyboard.h"
#include "core/os/os.h"
#include "core/os/time.h"
@@ -668,7 +667,7 @@ void EditorNode::_notification(int p_what) {
command_palette->register_shortcuts_as_command();
- MessageQueue::get_singleton()->push_callable(callable_mp(this, &EditorNode::_begin_first_scan));
+ callable_mp(this, &EditorNode::_begin_first_scan).call_deferred();
/* DO NOT LOAD SCENES HERE, WAIT FOR FILE SCANNING AND REIMPORT TO COMPLETE */
} break;
@@ -1107,7 +1106,7 @@ void EditorNode::_scan_external_changes() {
}
if (need_reload) {
- disk_changed->call_deferred(SNAME("popup_centered_ratio"), 0.3);
+ callable_mp((Window *)disk_changed, &Window::popup_centered_ratio).call_deferred(0.3);
}
}
@@ -3013,6 +3012,16 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
} break;
case SET_RENDERER_NAME_SAVE_AND_RESTART: {
ProjectSettings::get_singleton()->set("rendering/renderer/rendering_method", renderer_request);
+ if (renderer_request == "mobile" || renderer_request == "gl_compatibility") {
+ // Also change the mobile override if changing to a compatible rendering method.
+ // This prevents visual discrepancies between desktop and mobile platforms.
+ ProjectSettings::get_singleton()->set("rendering/renderer/rendering_method.mobile", renderer_request);
+ } else if (renderer_request == "forward_plus") {
+ // Use the equivalent mobile rendering method. This prevents the rendering method from staying
+ // on its old choice if moving from `gl_compatibility` to `forward_plus`.
+ ProjectSettings::get_singleton()->set("rendering/renderer/rendering_method.mobile", "mobile");
+ }
+
ProjectSettings::get_singleton()->save();
save_all_scenes();
@@ -3697,7 +3706,7 @@ void EditorNode::_set_current_scene_nocheck(int p_idx) {
callable_mp(scene_tabs, &EditorSceneTabs::update_scene_tabs).call_deferred();
if (tabs_to_close.is_empty()) {
- call_deferred(SNAME("_set_main_scene_state"), state, get_edited_scene()); // Do after everything else is done setting up.
+ callable_mp(this, &EditorNode::_set_main_scene_state).call_deferred(state, get_edited_scene()); // Do after everything else is done setting up.
}
}
@@ -4087,7 +4096,7 @@ bool EditorNode::has_previous_scenes() const {
void EditorNode::edit_foreign_resource(Ref<Resource> p_resource) {
load_scene(p_resource->get_path().get_slice("::", 0));
- InspectorDock::get_singleton()->call_deferred("edit_resource", p_resource);
+ callable_mp(InspectorDock::get_singleton(), &InspectorDock::edit_resource).call_deferred(p_resource);
}
bool EditorNode::is_resource_read_only(Ref<Resource> p_resource, bool p_foreign_resources_are_writable) {
@@ -4166,7 +4175,7 @@ void EditorNode::_add_to_recent_scenes(const String &p_scene) {
void EditorNode::_open_recent_scene(int p_idx) {
if (p_idx == recent_scenes->get_item_count() - 1) {
EditorSettings::get_singleton()->set_project_metadata("recent_files", "scenes", Array());
- call_deferred(SNAME("_update_recent_scenes"));
+ callable_mp(this, &EditorNode::_update_recent_scenes).call_deferred();
} else {
Array rc = EditorSettings::get_singleton()->get_project_metadata("recent_files", "scenes", Array());
ERR_FAIL_INDEX(p_idx, rc.size());
@@ -5249,7 +5258,7 @@ void EditorNode::_load_docks_from_config(Ref<ConfigFile> p_layout, const String
int selected_tab_idx = p_layout->get_value(p_section, "dock_" + itos(i + 1) + "_selected_tab_idx");
if (selected_tab_idx >= 0 && selected_tab_idx < dock_slot[i]->get_tab_count()) {
- dock_slot[i]->call_deferred("set_current_tab", selected_tab_idx);
+ callable_mp(dock_slot[i], &TabContainer::set_current_tab).call_deferred(selected_tab_idx);
}
}
@@ -6160,7 +6169,8 @@ void EditorNode::reload_instances_with_path_in_edited_scenes(const String &p_ins
if (edited_scene_map.size() > 0) {
// Reload the new instance.
Error err;
- Ref<PackedScene> instance_scene_packed_scene = ResourceLoader::load(p_instance_path, "", ResourceFormatLoader::CACHE_MODE_REPLACE, &err);
+ Ref<PackedScene> instance_scene_packed_scene = ResourceLoader::load(p_instance_path, "", ResourceFormatLoader::CACHE_MODE_IGNORE, &err);
+ instance_scene_packed_scene->set_path(p_instance_path, true);
ERR_FAIL_COND(err != OK);
ERR_FAIL_COND(instance_scene_packed_scene.is_null());
@@ -6267,7 +6277,8 @@ void EditorNode::reload_instances_with_path_in_edited_scenes(const String &p_ins
// be properly updated.
for (String path : required_load_paths) {
if (!local_scene_cache.find(path)) {
- current_packed_scene = ResourceLoader::load(path, "", ResourceFormatLoader::CACHE_MODE_REPLACE, &err);
+ current_packed_scene = ResourceLoader::load(path, "", ResourceFormatLoader::CACHE_MODE_IGNORE, &err);
+ current_packed_scene->set_path(path, true);
local_scene_cache[path] = current_packed_scene;
} else {
current_packed_scene = local_scene_cache[path];
@@ -6576,6 +6587,9 @@ void EditorNode::_renderer_selected(int p_which) {
}
renderer_request = rendering_method;
+ video_restart_dialog->set_text(
+ vformat(TTR("Changing the renderer requires restarting the editor.\n\nChoosing Save & Restart will change the rendering method to:\n- Desktop platforms: %s\n- Mobile platforms: %s\n- Web platform: gl_compatibility"),
+ renderer_request, renderer_request.replace("forward_plus", "mobile")));
video_restart_dialog->popup_centered();
renderer->select(renderer_current);
_update_renderer_color();
@@ -6662,15 +6676,9 @@ void EditorNode::_bind_methods() {
ClassDB::bind_method(D_METHOD("push_item", "object", "property", "inspector_only"), &EditorNode::push_item, DEFVAL(""), DEFVAL(false));
ClassDB::bind_method("set_edited_scene", &EditorNode::set_edited_scene);
- ClassDB::bind_method("open_request", &EditorNode::open_request);
- ClassDB::bind_method("edit_foreign_resource", &EditorNode::edit_foreign_resource);
- ClassDB::bind_method("is_resource_read_only", &EditorNode::is_resource_read_only);
ClassDB::bind_method("stop_child_process", &EditorNode::stop_child_process);
- ClassDB::bind_method("_set_main_scene_state", &EditorNode::_set_main_scene_state);
- ClassDB::bind_method("_update_recent_scenes", &EditorNode::_update_recent_scenes);
-
ADD_SIGNAL(MethodInfo("request_help_search"));
ADD_SIGNAL(MethodInfo("script_add_function_request", PropertyInfo(Variant::OBJECT, "obj"), PropertyInfo(Variant::STRING, "function"), PropertyInfo(Variant::PACKED_STRING_ARRAY, "args")));
ADD_SIGNAL(MethodInfo("resource_saved", PropertyInfo(Variant::OBJECT, "obj")));
@@ -7553,7 +7561,7 @@ EditorNode::EditorNode() {
renderer->set_focus_mode(Control::FOCUS_NONE);
renderer->add_theme_font_override("font", theme->get_font(SNAME("bold"), EditorStringName(EditorFonts)));
renderer->add_theme_font_size_override("font_size", theme->get_font_size(SNAME("bold_size"), EditorStringName(EditorFonts)));
- renderer->set_tooltip_text(TTR("Choose a renderer."));
+ renderer->set_tooltip_text(TTR("Choose a rendering method.\n\nNotes:\n- On mobile platforms, the Mobile rendering method is used if Forward+ is selected here.\n- On the web platform, the Compatibility rendering method is always used."));
right_menu_hb->add_child(renderer);
@@ -7595,7 +7603,6 @@ EditorNode::EditorNode() {
_update_renderer_color();
video_restart_dialog = memnew(ConfirmationDialog);
- video_restart_dialog->set_text(TTR("Changing the renderer requires restarting the editor."));
video_restart_dialog->set_ok_button_text(TTR("Save & Restart"));
video_restart_dialog->connect("confirmed", callable_mp(this, &EditorNode::_menu_option).bind(SET_RENDERER_NAME_SAVE_AND_RESTART));
gui_base->add_child(video_restart_dialog);
@@ -7810,6 +7817,7 @@ EditorNode::EditorNode() {
file = memnew(EditorFileDialog);
gui_base->add_child(file);
file->set_current_dir("res://");
+ file->set_transient_to_focused(true);
file_export_lib = memnew(EditorFileDialog);
file_export_lib->set_title(TTR("Export Library"));
diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp
index e79f662cc9..49c62a3a6c 100644
--- a/editor/editor_plugin.cpp
+++ b/editor/editor_plugin.cpp
@@ -402,13 +402,13 @@ void EditorPlugin::remove_translation_parser_plugin(const Ref<EditorTranslationP
void EditorPlugin::add_import_plugin(const Ref<EditorImportPlugin> &p_importer, bool p_first_priority) {
ERR_FAIL_COND(!p_importer.is_valid());
ResourceFormatImporter::get_singleton()->add_importer(p_importer, p_first_priority);
- EditorFileSystem::get_singleton()->call_deferred(SNAME("scan"));
+ callable_mp(EditorFileSystem::get_singleton(), &EditorFileSystem::scan).call_deferred();
}
void EditorPlugin::remove_import_plugin(const Ref<EditorImportPlugin> &p_importer) {
ERR_FAIL_COND(!p_importer.is_valid());
ResourceFormatImporter::get_singleton()->remove_importer(p_importer);
- EditorFileSystem::get_singleton()->call_deferred(SNAME("scan"));
+ callable_mp(EditorFileSystem::get_singleton(), &EditorFileSystem::scan).call_deferred();
}
void EditorPlugin::add_export_plugin(const Ref<EditorExportPlugin> &p_exporter) {
diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp
index 27530dc641..404f1151f1 100644
--- a/editor/editor_properties.cpp
+++ b/editor/editor_properties.cpp
@@ -3013,7 +3013,7 @@ void EditorPropertyResource::_resource_selected(const Ref<Resource> &p_resource,
if (extensions.find(parent.get_extension()) && (!EditorNode::get_singleton()->get_edited_scene() || EditorNode::get_singleton()->get_edited_scene()->get_scene_file_path() != parent)) {
// If the resource belongs to another (non-imported) scene, edit it in that scene instead.
if (!FileAccess::exists(parent + ".import")) {
- EditorNode::get_singleton()->call_deferred("edit_foreign_resource", p_resource);
+ callable_mp(EditorNode::get_singleton(), &EditorNode::edit_foreign_resource).call_deferred(p_resource);
return;
}
}
diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp
index 256f9c0ea9..7f9d80961b 100644
--- a/editor/editor_properties_array_dict.cpp
+++ b/editor/editor_properties_array_dict.cpp
@@ -407,8 +407,8 @@ void EditorPropertyArray::update_property() {
new_prop->connect(SNAME("object_id_selected"), callable_mp(this, &EditorPropertyArray::_object_id_selected));
new_prop->set_h_size_flags(SIZE_EXPAND_FILL);
new_prop->set_read_only(is_read_only());
- slot.prop->call_deferred("add_sibling", new_prop);
- slot.prop->call_deferred("queue_free");
+ callable_mp((Node *)slot.prop, &Node::add_sibling).call_deferred(new_prop, false);
+ callable_mp((Node *)slot.prop, &Node::queue_free).call_deferred();
slot.prop = new_prop;
slot.set_index(idx);
}
diff --git a/editor/editor_resource_picker.cpp b/editor/editor_resource_picker.cpp
index ed20e50685..011cb26621 100644
--- a/editor/editor_resource_picker.cpp
+++ b/editor/editor_resource_picker.cpp
@@ -675,7 +675,7 @@ bool EditorResourcePicker::_is_drop_valid(const Dictionary &p_drag_data) const {
return false;
}
-bool EditorResourcePicker::_is_type_valid(const String p_type_name, HashSet<StringName> p_allowed_types) const {
+bool EditorResourcePicker::_is_type_valid(const String p_type_name, const HashSet<StringName> &p_allowed_types) const {
for (const StringName &E : p_allowed_types) {
String at = E;
if (p_type_name == at || ClassDB::is_parent_class(p_type_name, at) || EditorNode::get_editor_data().script_class_is_parent(p_type_name, at)) {
diff --git a/editor/editor_resource_picker.h b/editor/editor_resource_picker.h
index 35703bcbeb..fb54455e89 100644
--- a/editor/editor_resource_picker.h
+++ b/editor/editor_resource_picker.h
@@ -99,7 +99,7 @@ class EditorResourcePicker : public HBoxContainer {
String _get_resource_type(const Ref<Resource> &p_resource) const;
void _get_allowed_types(bool p_with_convert, HashSet<StringName> *p_vector) const;
bool _is_drop_valid(const Dictionary &p_drag_data) const;
- bool _is_type_valid(const String p_type_name, HashSet<StringName> p_allowed_types) const;
+ bool _is_type_valid(const String p_type_name, const HashSet<StringName> &p_allowed_types) const;
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;
diff --git a/editor/editor_resource_preview.cpp b/editor/editor_resource_preview.cpp
index b3340dffc1..f21f0ac216 100644
--- a/editor/editor_resource_preview.cpp
+++ b/editor/editor_resource_preview.cpp
@@ -34,7 +34,6 @@
#include "core/io/file_access.h"
#include "core/io/resource_loader.h"
#include "core/io/resource_saver.h"
-#include "core/object/message_queue.h"
#include "core/variant/variant_utility.h"
#include "editor/editor_node.h"
#include "editor/editor_paths.h"
@@ -123,7 +122,7 @@ void EditorResourcePreview::_preview_ready(const String &p_path, int p_hash, con
cache[p_path] = item;
}
- MessageQueue::get_singleton()->push_call(id, p_func, p_path, p_texture, p_small_texture, p_ud);
+ Callable(id, p_func).call_deferred(p_path, p_texture, p_small_texture, p_ud);
}
void EditorResourcePreview::_generate_preview(Ref<ImageTexture> &r_texture, Ref<ImageTexture> &r_small_texture, const QueueItem &p_item, const String &cache_base, Dictionary &p_metadata) {
diff --git a/editor/export/editor_export_platform.cpp b/editor/export/editor_export_platform.cpp
index 9a0d84d751..855d610d72 100644
--- a/editor/export/editor_export_platform.cpp
+++ b/editor/export/editor_export_platform.cpp
@@ -901,7 +901,7 @@ Vector<String> EditorExportPlatform::get_forced_export_files() {
if (FileAccess::exists(abs_path)) {
files.push_back(ts_data);
// Remove the file later.
- MessageQueue::get_singleton()->push_callable(callable_mp_static(DirAccess::remove_absolute), abs_path);
+ callable_mp_static(DirAccess::remove_absolute).call_deferred(abs_path);
}
}
}
diff --git a/editor/export/project_export.cpp b/editor/export/project_export.cpp
index 5d84e4f78f..4c0efde4c5 100644
--- a/editor/export/project_export.cpp
+++ b/editor/export/project_export.cpp
@@ -1277,6 +1277,7 @@ ProjectExportDialog::ProjectExportDialog() {
server_strip_message = memnew(Label);
server_strip_message->set_visible(false);
server_strip_message->set_autowrap_mode(TextServer::AUTOWRAP_WORD_SMART);
+ server_strip_message->set_custom_minimum_size(Size2(300 * EDSCALE, 1));
resources_vb->add_child(server_strip_message);
{
@@ -1284,7 +1285,7 @@ ProjectExportDialog::ProjectExportDialog() {
ClassDB::get_inheriters_from_class("Resource", &resource_names);
PackedStringArray strippable;
- for (StringName resource_name : resource_names) {
+ for (const StringName &resource_name : resource_names) {
if (ClassDB::has_method(resource_name, "create_placeholder", true)) {
strippable.push_back(resource_name);
}
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index 12a3478e44..4e94ff1129 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -651,7 +651,7 @@ void FileSystemDock::_notification(int p_what) {
void FileSystemDock::_tree_multi_selected(Object *p_item, int p_column, bool p_selected) {
// Update the import dock.
import_dock_needs_update = true;
- call_deferred(SNAME("_update_import_dock"));
+ callable_mp(this, &FileSystemDock::_update_import_dock).call_deferred();
// Return if we don't select something new.
if (!p_selected) {
@@ -3329,7 +3329,7 @@ void FileSystemDock::_file_multi_selected(int p_index, bool p_selected) {
// Update the import dock.
import_dock_needs_update = true;
- call_deferred(SNAME("_update_import_dock"));
+ callable_mp(this, &FileSystemDock::_update_import_dock).call_deferred();
}
void FileSystemDock::_tree_mouse_exited() {
@@ -3645,16 +3645,11 @@ MenuButton *FileSystemDock::_create_file_menu_button() {
}
void FileSystemDock::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_update_tree"), &FileSystemDock::_update_tree);
-
ClassDB::bind_method(D_METHOD("_file_list_thumbnail_done"), &FileSystemDock::_file_list_thumbnail_done);
ClassDB::bind_method(D_METHOD("_tree_thumbnail_done"), &FileSystemDock::_tree_thumbnail_done);
- ClassDB::bind_method(D_METHOD("_select_file"), &FileSystemDock::_select_file);
ClassDB::bind_method(D_METHOD("navigate_to_path", "path"), &FileSystemDock::navigate_to_path);
- ClassDB::bind_method(D_METHOD("_update_import_dock"), &FileSystemDock::_update_import_dock);
-
ClassDB::bind_method(D_METHOD("add_resource_tooltip_plugin", "plugin"), &FileSystemDock::add_resource_tooltip_plugin);
ClassDB::bind_method(D_METHOD("remove_resource_tooltip_plugin", "plugin"), &FileSystemDock::remove_resource_tooltip_plugin);
diff --git a/editor/find_in_files.cpp b/editor/find_in_files.cpp
index c83fa82c13..a81aa971f3 100644
--- a/editor/find_in_files.cpp
+++ b/editor/find_in_files.cpp
@@ -465,7 +465,7 @@ void FindInFilesDialog::_notification(int p_what) {
case NOTIFICATION_VISIBILITY_CHANGED: {
if (is_visible()) {
// Doesn't work more than once if not deferred...
- _search_text_line_edit->call_deferred(SNAME("grab_focus"));
+ callable_mp((Control *)_search_text_line_edit, &Control::grab_focus).call_deferred();
_search_text_line_edit->select_all();
// Extensions might have changed in the meantime, we clean them and instance them again.
for (int i = 0; i < _filters_container->get_child_count(); i++) {
diff --git a/editor/group_settings_editor.cpp b/editor/group_settings_editor.cpp
index a91154ae36..42e117f4c1 100644
--- a/editor/group_settings_editor.cpp
+++ b/editor/group_settings_editor.cpp
@@ -45,6 +45,9 @@ void GroupSettingsEditor::_notification(int p_what) {
case NOTIFICATION_ENTER_TREE: {
update_groups();
} break;
+ case NOTIFICATION_THEME_CHANGED: {
+ add_button->set_icon(get_editor_theme_icon(SNAME("Add")));
+ } break;
}
}
diff --git a/editor/groups_editor.cpp b/editor/groups_editor.cpp
index 9fa9fe5a9d..77a867f34b 100644
--- a/editor/groups_editor.cpp
+++ b/editor/groups_editor.cpp
@@ -274,20 +274,22 @@ void GroupsEditor::_update_groups_and_tree() {
_update_tree();
}
-void GroupsEditor::_update_scene_groups(Node *p_node) {
- if (scene_groups_cache.has(p_node)) {
- scene_groups = scene_groups_cache[p_node];
- scene_groups_cache.erase(p_node);
+void GroupsEditor::_update_scene_groups(const ObjectID &p_id) {
+ HashMap<ObjectID, HashMap<StringName, bool>>::Iterator I = scene_groups_cache.find(p_id);
+ if (I) {
+ scene_groups = I->value;
+ scene_groups_cache.remove(I);
} else {
scene_groups = HashMap<StringName, bool>();
}
}
-void GroupsEditor::_cache_scene_groups(Node *p_node) {
+void GroupsEditor::_cache_scene_groups(const ObjectID &p_id) {
const int edited_scene_count = EditorNode::get_editor_data().get_edited_scene_count();
for (int i = 0; i < edited_scene_count; i++) {
- if (p_node == EditorNode::get_editor_data().get_edited_scene_root(i)) {
- scene_groups_cache[p_node] = scene_groups_for_caching;
+ Node *edited_scene_root = EditorNode::get_editor_data().get_edited_scene_root(i);
+ if (edited_scene_root && p_id == edited_scene_root->get_instance_id()) {
+ scene_groups_cache[p_id] = scene_groups_for_caching;
break;
}
}
@@ -305,7 +307,7 @@ void GroupsEditor::set_current(Node *p_node) {
if (scene_tree->get_edited_scene_root() != scene_root_node) {
scene_root_node = scene_tree->get_edited_scene_root();
- _update_scene_groups(scene_root_node);
+ _update_scene_groups(scene_root_node->get_instance_id());
_update_groups();
}
@@ -803,7 +805,7 @@ void GroupsEditor::_bind_methods() {
void GroupsEditor::_node_removed(Node *p_node) {
if (scene_root_node == p_node) {
scene_groups_for_caching = scene_groups;
- callable_mp(this, &GroupsEditor::_cache_scene_groups).call_deferred(p_node);
+ callable_mp(this, &GroupsEditor::_cache_scene_groups).call_deferred(p_node->get_instance_id());
scene_root_node = nullptr;
}
diff --git a/editor/groups_editor.h b/editor/groups_editor.h
index cf74470b1b..8a0ca067de 100644
--- a/editor/groups_editor.h
+++ b/editor/groups_editor.h
@@ -78,14 +78,14 @@ class GroupsEditor : public VBoxContainer {
Button *add = nullptr;
Tree *tree = nullptr;
- HashMap<Node *, HashMap<StringName, bool>> scene_groups_cache;
+ HashMap<ObjectID, HashMap<StringName, bool>> scene_groups_cache;
HashMap<StringName, bool> scene_groups_for_caching;
HashMap<StringName, bool> scene_groups;
HashMap<StringName, String> global_groups;
- void _update_scene_groups(Node *p_node);
- void _cache_scene_groups(Node *p_node);
+ void _update_scene_groups(const ObjectID &p_id);
+ void _cache_scene_groups(const ObjectID &p_id);
void _show_add_group_dialog();
void _show_rename_group_dialog();
diff --git a/editor/gui/editor_spin_slider.cpp b/editor/gui/editor_spin_slider.cpp
index 750837cce9..051e4340bc 100644
--- a/editor/gui/editor_spin_slider.cpp
+++ b/editor/gui/editor_spin_slider.cpp
@@ -92,7 +92,7 @@ void EditorSpinSlider::gui_input(const Ref<InputEvent> &p_event) {
}
} else if (mb->get_button_index() == MouseButton::WHEEL_UP || mb->get_button_index() == MouseButton::WHEEL_DOWN) {
if (grabber->is_visible()) {
- call_deferred(SNAME("queue_redraw"));
+ callable_mp((CanvasItem *)this, &CanvasItem::queue_redraw).call_deferred();
}
}
}
@@ -637,11 +637,11 @@ void EditorSpinSlider::_focus_entered() {
_ensure_input_popup();
value_input->set_text(get_text_value());
value_input_popup->set_size(get_size());
- value_input_popup->call_deferred(SNAME("show"));
- value_input->call_deferred(SNAME("grab_focus"));
- value_input->call_deferred(SNAME("select_all"));
value_input->set_focus_next(find_next_valid_focus()->get_path());
value_input->set_focus_previous(find_prev_valid_focus()->get_path());
+ callable_mp((CanvasItem *)value_input_popup, &CanvasItem::show).call_deferred();
+ callable_mp((Control *)value_input, &Control::grab_focus).call_deferred();
+ callable_mp(value_input, &LineEdit ::select_all).call_deferred();
emit_signal("value_focus_entered");
}
diff --git a/editor/gui/editor_toaster.cpp b/editor/gui/editor_toaster.cpp
index 1abb591508..ac54a5a371 100644
--- a/editor/gui/editor_toaster.cpp
+++ b/editor/gui/editor_toaster.cpp
@@ -406,7 +406,7 @@ void EditorToaster::popup_str(String p_message, Severity p_severity, String p_to
// Since "_popup_str" adds nodes to the tree, and since the "add_child" method is not
// thread-safe, it's better to defer the call to the next cycle to be thread-safe.
is_processing_error = true;
- call_deferred(SNAME("_popup_str"), p_message, p_severity, p_tooltip);
+ callable_mp(this, &EditorToaster::_popup_str).call_deferred(p_message, p_severity, p_tooltip);
is_processing_error = false;
}
@@ -499,11 +499,6 @@ EditorToaster *EditorToaster::get_singleton() {
return singleton;
}
-void EditorToaster::_bind_methods() {
- // Binding method to make it defer-able.
- ClassDB::bind_method(D_METHOD("_popup_str", "message", "severity", "tooltip"), &EditorToaster::_popup_str);
-}
-
EditorToaster::EditorToaster() {
set_notify_transform(true);
set_process_internal(true);
diff --git a/editor/gui/editor_toaster.h b/editor/gui/editor_toaster.h
index 3e39d9d519..5034cb66fc 100644
--- a/editor/gui/editor_toaster.h
+++ b/editor/gui/editor_toaster.h
@@ -105,7 +105,6 @@ private:
protected:
static EditorToaster *singleton;
- static void _bind_methods();
void _notification(int p_what);
diff --git a/editor/gui/scene_tree_editor.cpp b/editor/gui/scene_tree_editor.cpp
index 33135a6bea..766a507260 100644
--- a/editor/gui/scene_tree_editor.cpp
+++ b/editor/gui/scene_tree_editor.cpp
@@ -31,7 +31,6 @@
#include "scene_tree_editor.h"
#include "core/config/project_settings.h"
-#include "core/object/message_queue.h"
#include "core/object/script_language.h"
#include "editor/editor_file_system.h"
#include "editor/editor_node.h"
@@ -593,7 +592,7 @@ void SceneTreeEditor::_node_script_changed(Node *p_node) {
return;
}
- MessageQueue::get_singleton()->push_call(this, "_update_tree");
+ callable_mp(this, &SceneTreeEditor::_update_tree).call_deferred(false);
tree_dirty = true;
}
@@ -626,7 +625,7 @@ void SceneTreeEditor::_node_renamed(Node *p_node) {
emit_signal(SNAME("node_renamed"));
if (!tree_dirty) {
- MessageQueue::get_singleton()->push_call(this, "_update_tree");
+ callable_mp(this, &SceneTreeEditor::_update_tree).call_deferred(false);
tree_dirty = true;
}
}
@@ -843,12 +842,12 @@ void SceneTreeEditor::_test_update_tree() {
return; // did not change
}
- MessageQueue::get_singleton()->push_call(this, "_update_tree");
+ callable_mp(this, &SceneTreeEditor::_update_tree).call_deferred(false);
tree_dirty = true;
}
void SceneTreeEditor::_tree_process_mode_changed() {
- MessageQueue::get_singleton()->push_call(this, "_update_tree");
+ callable_mp(this, &SceneTreeEditor::_update_tree).call_deferred(false);
tree_dirty = true;
}
@@ -863,7 +862,7 @@ void SceneTreeEditor::_tree_changed() {
return;
}
- MessageQueue::get_singleton()->push_call(this, "_test_update_tree");
+ callable_mp(this, &SceneTreeEditor::_test_update_tree).call_deferred();
pending_test_update = true;
}
@@ -1484,7 +1483,6 @@ void SceneTreeEditor::set_connecting_signal(bool p_enable) {
void SceneTreeEditor::_bind_methods() {
ClassDB::bind_method(D_METHOD("_update_tree"), &SceneTreeEditor::_update_tree, DEFVAL(false)); // Still used by UndoRedo.
ClassDB::bind_method("_rename_node", &SceneTreeEditor::_rename_node);
- ClassDB::bind_method("_test_update_tree", &SceneTreeEditor::_test_update_tree);
ClassDB::bind_method(D_METHOD("update_tree"), &SceneTreeEditor::update_tree);
@@ -1642,7 +1640,7 @@ void SceneTreeDialog::_notification(int p_what) {
tree->update_tree();
// Select the search bar by default.
- filter->call_deferred(SNAME("grab_focus"));
+ callable_mp((Control *)filter, &Control::grab_focus).call_deferred();
}
} break;
diff --git a/editor/import/3d/post_import_plugin_skeleton_renamer.cpp b/editor/import/3d/post_import_plugin_skeleton_renamer.cpp
index 6ce6aca896..ffe75f189c 100644
--- a/editor/import/3d/post_import_plugin_skeleton_renamer.cpp
+++ b/editor/import/3d/post_import_plugin_skeleton_renamer.cpp
@@ -45,7 +45,7 @@ void PostImportPluginSkeletonRenamer::get_internal_import_options(InternalImport
}
}
-void PostImportPluginSkeletonRenamer::_internal_process(InternalImportCategory p_category, Node *p_base_scene, Node *p_node, Ref<Resource> p_resource, const Dictionary &p_options, HashMap<String, String> p_rename_map) {
+void PostImportPluginSkeletonRenamer::_internal_process(InternalImportCategory p_category, Node *p_base_scene, Node *p_node, Ref<Resource> p_resource, const Dictionary &p_options, const HashMap<String, String> &p_rename_map) {
// Prepare objects.
Object *map = p_options["retarget/bone_map"].get_validated_object();
if (!map || !bool(p_options["retarget/bone_renamer/rename_bones"])) {
@@ -121,7 +121,7 @@ void PostImportPluginSkeletonRenamer::_internal_process(InternalImportCategory p
// Rename bones in all Nodes by calling method.
{
Dictionary rename_map_dict;
- for (HashMap<String, String>::Iterator E = p_rename_map.begin(); E; ++E) {
+ for (HashMap<String, String>::ConstIterator E = p_rename_map.begin(); E; ++E) {
rename_map_dict[E->key] = E->value;
}
diff --git a/editor/import/3d/post_import_plugin_skeleton_renamer.h b/editor/import/3d/post_import_plugin_skeleton_renamer.h
index 98f778f6c2..a977117374 100644
--- a/editor/import/3d/post_import_plugin_skeleton_renamer.h
+++ b/editor/import/3d/post_import_plugin_skeleton_renamer.h
@@ -40,7 +40,7 @@ public:
virtual void get_internal_import_options(InternalImportCategory p_category, List<ResourceImporter::ImportOption> *r_options) override;
virtual void internal_process(InternalImportCategory p_category, Node *p_base_scene, Node *p_node, Ref<Resource> p_resource, const Dictionary &p_options) override;
- void _internal_process(InternalImportCategory p_category, Node *p_base_scene, Node *p_node, Ref<Resource> p_resource, const Dictionary &p_options, HashMap<String, String> p_rename_map);
+ void _internal_process(InternalImportCategory p_category, Node *p_base_scene, Node *p_node, Ref<Resource> p_resource, const Dictionary &p_options, const HashMap<String, String> &p_rename_map);
PostImportPluginSkeletonRenamer();
};
diff --git a/editor/import/3d/resource_importer_obj.cpp b/editor/import/3d/resource_importer_obj.cpp
index 082e78fdbe..a5e51636af 100644
--- a/editor/import/3d/resource_importer_obj.cpp
+++ b/editor/import/3d/resource_importer_obj.cpp
@@ -202,7 +202,7 @@ static Error _parse_material_library(const String &p_path, HashMap<String, Ref<S
return OK;
}
-static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_single_mesh, bool p_generate_tangents, bool p_optimize, Vector3 p_scale_mesh, Vector3 p_offset_mesh, bool p_disable_compression, List<String> *r_missing_deps) {
+static Error _parse_obj(const String &p_path, List<Ref<ImporterMesh>> &r_meshes, bool p_single_mesh, bool p_generate_tangents, bool p_optimize, Vector3 p_scale_mesh, Vector3 p_offset_mesh, bool p_disable_compression, List<String> *r_missing_deps) {
Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ);
ERR_FAIL_COND_V_MSG(f.is_null(), ERR_CANT_OPEN, vformat("Couldn't open OBJ file '%s', it may not exist or not be readable.", p_path));
@@ -220,7 +220,7 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_
ERR_FAIL_COND_V_MSG(coff_header_machines.find(first_bytes) != -1, ERR_FILE_CORRUPT, vformat("Couldn't read OBJ file '%s', it seems to be binary, corrupted, or empty.", p_path));
f->seek(0);
- Ref<ArrayMesh> mesh;
+ Ref<ImporterMesh> mesh;
mesh.instantiate();
bool generate_tangents = p_generate_tangents;
@@ -400,24 +400,24 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_
print_verbose("OBJ: Current material library " + current_material_library + " has " + itos(material_map.has(current_material_library)));
print_verbose("OBJ: Current material " + current_material + " has " + itos(material_map.has(current_material_library) && material_map[current_material_library].has(current_material)));
-
+ Ref<StandardMaterial3D> material;
if (material_map.has(current_material_library) && material_map[current_material_library].has(current_material)) {
- Ref<StandardMaterial3D> &material = material_map[current_material_library][current_material];
+ material = material_map[current_material_library][current_material];
if (!colors.is_empty()) {
material->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
}
surf_tool->set_material(material);
}
- mesh = surf_tool->commit(mesh, mesh_flags);
-
if (!current_material.is_empty()) {
- mesh->surface_set_name(mesh->get_surface_count() - 1, current_material.get_basename());
+ mesh->set_surface_name(mesh->get_surface_count() - 1, current_material.get_basename());
} else if (!current_group.is_empty()) {
- mesh->surface_set_name(mesh->get_surface_count() - 1, current_group);
+ mesh->set_surface_name(mesh->get_surface_count() - 1, current_group);
}
+ Array array = surf_tool->commit_to_arrays();
+ mesh->add_surface(Mesh::PRIMITIVE_TRIANGLES, array, TypedArray<Array>(), Dictionary(), material, name, mesh_flags);
+ print_verbose("OBJ: Added surface :" + mesh->get_surface_name(mesh->get_surface_count() - 1));
- print_verbose("OBJ: Added surface :" + mesh->surface_get_name(mesh->get_surface_count() - 1));
surf_tool->clear();
surf_tool->begin(Mesh::PRIMITIVE_TRIANGLES);
}
@@ -476,7 +476,7 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_
}
Node *EditorOBJImporter::import_scene(const String &p_path, uint32_t p_flags, const HashMap<StringName, Variant> &p_options, List<String> *r_missing_deps, Error *r_err) {
- List<Ref<Mesh>> meshes;
+ List<Ref<ImporterMesh>> meshes;
Error err = _parse_obj(p_path, meshes, false, p_flags & IMPORT_GENERATE_TANGENT_ARRAYS, false, Vector3(1, 1, 1), Vector3(0, 0, 0), p_flags & IMPORT_FORCE_DISABLE_MESH_COMPRESSION, r_missing_deps);
@@ -489,16 +489,9 @@ Node *EditorOBJImporter::import_scene(const String &p_path, uint32_t p_flags, co
Node3D *scene = memnew(Node3D);
- for (const Ref<Mesh> &m : meshes) {
- Ref<ImporterMesh> mesh;
- mesh.instantiate();
- mesh->set_name(m->get_name());
- for (int i = 0; i < m->get_surface_count(); i++) {
- mesh->add_surface(m->surface_get_primitive_type(i), m->surface_get_arrays(i), Array(), Dictionary(), m->surface_get_material(i), String(), m->surface_get_format(i));
- }
-
+ for (Ref<ImporterMesh> m : meshes) {
ImporterMeshInstance3D *mi = memnew(ImporterMeshInstance3D);
- mi->set_mesh(mesh);
+ mi->set_mesh(m);
mi->set_name(m->get_name());
scene->add_child(mi, true);
mi->set_owner(scene);
@@ -565,7 +558,7 @@ bool ResourceImporterOBJ::get_option_visibility(const String &p_path, const Stri
}
Error ResourceImporterOBJ::import(const String &p_source_file, const String &p_save_path, const HashMap<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) {
- List<Ref<Mesh>> meshes;
+ List<Ref<ImporterMesh>> meshes;
Error err = _parse_obj(p_source_file, meshes, true, p_options["generate_tangents"], p_options["optimize_mesh"], p_options["scale_mesh"], p_options["offset_mesh"], p_options["force_disable_mesh_compression"], nullptr);
@@ -574,7 +567,7 @@ Error ResourceImporterOBJ::import(const String &p_source_file, const String &p_s
String save_path = p_save_path + ".mesh";
- err = ResourceSaver::save(meshes.front()->get(), save_path);
+ err = ResourceSaver::save(meshes.front()->get()->get_mesh(), save_path);
ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot save Mesh to file '" + save_path + "'.");
diff --git a/editor/import/audio_stream_import_settings.cpp b/editor/import/audio_stream_import_settings.cpp
index 5414c6e74b..bc96191d33 100644
--- a/editor/import/audio_stream_import_settings.cpp
+++ b/editor/import/audio_stream_import_settings.cpp
@@ -277,6 +277,8 @@ void AudioStreamImportSettingsDialog::_draw_indicator() {
rect.size.height -= y_ofs;
}
+ _current_label->set_text(String::num(_current, 2).pad_decimals(2) + " /");
+
float ofs_x = (_current - zoom_bar->get_value()) * rect.size.width / zoom_bar->get_page();
if (ofs_x < 0 || ofs_x >= rect.size.width) {
return;
@@ -310,8 +312,6 @@ void AudioStreamImportSettingsDialog::_draw_indicator() {
}
}
}
-
- _current_label->set_text(String::num(_current, 2).pad_decimals(2) + " /");
}
void AudioStreamImportSettingsDialog::_on_indicator_mouse_exited() {
diff --git a/editor/import/dynamic_font_import_settings.cpp b/editor/import/dynamic_font_import_settings.cpp
index 5564726594..ad65fcebd7 100644
--- a/editor/import/dynamic_font_import_settings.cpp
+++ b/editor/import/dynamic_font_import_settings.cpp
@@ -1345,6 +1345,7 @@ DynamicFontImportSettingsDialog::DynamicFontImportSettingsDialog() {
page2_description->set_text(TTR("Add font size, and variation coordinates, and select glyphs to pre-render:"));
page2_description->set_h_size_flags(Control::SIZE_EXPAND_FILL);
page2_description->set_autowrap_mode(TextServer::AUTOWRAP_WORD_SMART);
+ page2_description->set_custom_minimum_size(Size2(300 * EDSCALE, 1));
page2_vb->add_child(page2_description);
HSplitContainer *page2_hb = memnew(HSplitContainer);
@@ -1418,6 +1419,7 @@ DynamicFontImportSettingsDialog::DynamicFontImportSettingsDialog() {
page2_0_description->set_text(TTR("Select translations to add all required glyphs to pre-render list:"));
page2_0_description->set_h_size_flags(Control::SIZE_EXPAND_FILL);
page2_0_description->set_autowrap_mode(TextServer::AUTOWRAP_WORD_SMART);
+ page2_0_description->set_custom_minimum_size(Size2(300 * EDSCALE, 1));
page2_0_vb->add_child(page2_0_description);
locale_tree = memnew(Tree);
@@ -1449,6 +1451,7 @@ DynamicFontImportSettingsDialog::DynamicFontImportSettingsDialog() {
page2_1_description->set_text(TTR("Enter a text and select OpenType features to shape and add all required glyphs to pre-render list:"));
page2_1_description->set_h_size_flags(Control::SIZE_EXPAND_FILL);
page2_1_description->set_autowrap_mode(TextServer::AUTOWRAP_WORD_SMART);
+ page2_1_description->set_custom_minimum_size(Size2(300 * EDSCALE, 1));
page2_1_vb->add_child(page2_1_description);
HSplitContainer *page2_1_hb = memnew(HSplitContainer);
@@ -1486,6 +1489,7 @@ DynamicFontImportSettingsDialog::DynamicFontImportSettingsDialog() {
page2_2_description->set_text(TTR("Add or remove glyphs from the character map to pre-render list:\nNote: Some stylistic alternatives and glyph variants do not have one-to-one correspondence to character, and not shown in this map, use \"Glyphs from the text\" tab to add these."));
page2_2_description->set_h_size_flags(Control::SIZE_EXPAND_FILL);
page2_2_description->set_autowrap_mode(TextServer::AUTOWRAP_WORD_SMART);
+ page2_2_description->set_custom_minimum_size(Size2(300 * EDSCALE, 1));
page2_2_vb->add_child(page2_2_description);
HSplitContainer *glyphs_split = memnew(HSplitContainer);
diff --git a/editor/import/editor_import_plugin.cpp b/editor/import/editor_import_plugin.cpp
index 7afce116b8..3243dcf256 100644
--- a/editor/import/editor_import_plugin.cpp
+++ b/editor/import/editor_import_plugin.cpp
@@ -186,6 +186,15 @@ Error EditorImportPlugin::import(const String &p_source_file, const String &p_sa
ERR_FAIL_V_MSG(ERR_METHOD_NOT_FOUND, "Unimplemented _import in add-on.");
}
+bool EditorImportPlugin::can_import_threaded() const {
+ bool ret = false;
+ if (GDVIRTUAL_CALL(_can_import_threaded, ret)) {
+ return ret;
+ } else {
+ return ResourceImporter::can_import_threaded();
+ }
+}
+
Error EditorImportPlugin::_append_import_external_resource(const String &p_file, const Dictionary &p_custom_options, const String &p_custom_importer, Variant p_generator_parameters) {
HashMap<StringName, Variant> options;
List<Variant> keys;
@@ -213,5 +222,6 @@ void EditorImportPlugin::_bind_methods() {
GDVIRTUAL_BIND(_get_import_order)
GDVIRTUAL_BIND(_get_option_visibility, "path", "option_name", "options")
GDVIRTUAL_BIND(_import, "source_file", "save_path", "options", "platform_variants", "gen_files");
+ GDVIRTUAL_BIND(_can_import_threaded);
ClassDB::bind_method(D_METHOD("append_import_external_resource", "path", "custom_options", "custom_importer", "generator_parameters"), &EditorImportPlugin::_append_import_external_resource, DEFVAL(Dictionary()), DEFVAL(String()), DEFVAL(Variant()));
}
diff --git a/editor/import/editor_import_plugin.h b/editor/import/editor_import_plugin.h
index fb164c7f15..ea5cfc2682 100644
--- a/editor/import/editor_import_plugin.h
+++ b/editor/import/editor_import_plugin.h
@@ -52,6 +52,7 @@ protected:
GDVIRTUAL0RC(int, _get_import_order)
GDVIRTUAL3RC(bool, _get_option_visibility, String, StringName, Dictionary)
GDVIRTUAL5RC(Error, _import, String, String, Dictionary, TypedArray<String>, TypedArray<String>)
+ GDVIRTUAL0RC(bool, _can_import_threaded)
Error _append_import_external_resource(const String &p_file, const Dictionary &p_custom_options = Dictionary(), const String &p_custom_importer = String(), Variant p_generator_parameters = Variant());
@@ -69,6 +70,7 @@ public:
virtual void get_import_options(const String &p_path, List<ImportOption> *r_options, int p_preset) const override;
virtual bool get_option_visibility(const String &p_path, const String &p_option, const HashMap<StringName, Variant> &p_options) const override;
virtual Error import(const String &p_source_file, const String &p_save_path, const HashMap<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata = nullptr) override;
+ virtual bool can_import_threaded() const override;
Error append_import_external_resource(const String &p_file, const HashMap<StringName, Variant> &p_custom_options = HashMap<StringName, Variant>(), const String &p_custom_importer = String(), Variant p_generator_parameters = Variant());
};
diff --git a/editor/inspector_dock.cpp b/editor/inspector_dock.cpp
index 1ee273f64b..1b413c0978 100644
--- a/editor/inspector_dock.cpp
+++ b/editor/inspector_dock.cpp
@@ -461,15 +461,6 @@ void InspectorDock::_notification(int p_what) {
}
void InspectorDock::_bind_methods() {
- ClassDB::bind_method("_unref_resource", &InspectorDock::_unref_resource);
- ClassDB::bind_method("_paste_resource", &InspectorDock::_paste_resource);
- ClassDB::bind_method("_copy_resource", &InspectorDock::_copy_resource);
-
- ClassDB::bind_method("_menu_collapseall", &InspectorDock::_menu_collapseall);
- ClassDB::bind_method("_menu_expandall", &InspectorDock::_menu_expandall);
-
- ClassDB::bind_method("edit_resource", &InspectorDock::edit_resource);
-
ClassDB::bind_method("store_script_properties", &InspectorDock::store_script_properties);
ClassDB::bind_method("apply_script_properties", &InspectorDock::apply_script_properties);
diff --git a/editor/localization_editor.cpp b/editor/localization_editor.cpp
index 71906b58e7..46c6ef5712 100644
--- a/editor/localization_editor.cpp
+++ b/editor/localization_editor.cpp
@@ -189,7 +189,7 @@ void LocalizationEditor::_translation_res_select() {
if (updating_translations) {
return;
}
- call_deferred(SNAME("update_translations"));
+ callable_mp(this, &LocalizationEditor::update_translations).call_deferred();
}
void LocalizationEditor::_translation_res_option_popup(bool p_arrow_clicked) {
diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp
index 5011c5cf18..5ffb89ac65 100644
--- a/editor/plugins/animation_blend_tree_editor_plugin.cpp
+++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp
@@ -41,6 +41,7 @@
#include "editor/editor_string_names.h"
#include "editor/editor_undo_redo_manager.h"
#include "editor/gui/editor_file_dialog.h"
+#include "scene/3d/skeleton_3d.h"
#include "scene/animation/animation_player.h"
#include "scene/gui/check_box.h"
#include "scene/gui/menu_button.h"
diff --git a/editor/plugins/animation_library_editor.cpp b/editor/plugins/animation_library_editor.cpp
index 642dfa58df..c302226357 100644
--- a/editor/plugins/animation_library_editor.cpp
+++ b/editor/plugins/animation_library_editor.cpp
@@ -767,6 +767,15 @@ void AnimationLibraryEditor::show_dialog() {
popup_centered_ratio(0.5);
}
+void AnimationLibraryEditor::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_THEME_CHANGED: {
+ new_library_button->set_icon(get_editor_theme_icon(SNAME("Add")));
+ load_library_button->set_icon(get_editor_theme_icon(SNAME("Load")));
+ }
+ }
+}
+
void AnimationLibraryEditor::_update_editor(Object *p_mixer) {
emit_signal("update_editor", p_mixer);
}
@@ -800,12 +809,14 @@ AnimationLibraryEditor::AnimationLibraryEditor() {
VBoxContainer *vb = memnew(VBoxContainer);
HBoxContainer *hb = memnew(HBoxContainer);
hb->add_spacer(true);
- Button *b = memnew(Button(TTR("Add Library")));
- b->connect("pressed", callable_mp(this, &AnimationLibraryEditor::_add_library));
- hb->add_child(b);
- b = memnew(Button(TTR("Load Library")));
- b->connect("pressed", callable_mp(this, &AnimationLibraryEditor::_load_library));
- hb->add_child(b);
+ new_library_button = memnew(Button(TTR("New Library")));
+ new_library_button->set_tooltip_text(TTR("Create new empty animation library."));
+ new_library_button->connect("pressed", callable_mp(this, &AnimationLibraryEditor::_add_library));
+ hb->add_child(new_library_button);
+ load_library_button = memnew(Button(TTR("Load Library")));
+ load_library_button->set_tooltip_text(TTR("Load animation library from disk."));
+ load_library_button->connect("pressed", callable_mp(this, &AnimationLibraryEditor::_load_library));
+ hb->add_child(load_library_button);
vb->add_child(hb);
tree = memnew(Tree);
vb->add_child(tree);
diff --git a/editor/plugins/animation_library_editor.h b/editor/plugins/animation_library_editor.h
index 42b4d38e49..c003e9a10b 100644
--- a/editor/plugins/animation_library_editor.h
+++ b/editor/plugins/animation_library_editor.h
@@ -80,6 +80,9 @@ class AnimationLibraryEditor : public AcceptDialog {
StringName file_dialog_animation;
StringName file_dialog_library;
+ Button *new_library_button = nullptr;
+ Button *load_library_button = nullptr;
+
AcceptDialog *error_dialog = nullptr;
bool adding_animation = false;
StringName adding_animation_to_library;
@@ -108,6 +111,7 @@ class AnimationLibraryEditor : public AcceptDialog {
bool updating = false;
protected:
+ void _notification(int p_what);
void _update_editor(Object *p_mixer);
static void _bind_methods();
diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp
index 84251e1476..fe2ce70735 100644
--- a/editor/plugins/animation_player_editor_plugin.cpp
+++ b/editor/plugins/animation_player_editor_plugin.cpp
@@ -2139,7 +2139,7 @@ void AnimationPlayerEditorPlugin::_clear_dummy_player() {
}
Node *parent = dummy_player->get_parent();
if (parent) {
- parent->call_deferred("remove_child", dummy_player);
+ callable_mp(parent, &Node::remove_child).call_deferred(dummy_player);
}
dummy_player->queue_free();
dummy_player = nullptr;
diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp
index e9c8b0c610..0e61a7e29f 100644
--- a/editor/plugins/animation_state_machine_editor.cpp
+++ b/editor/plugins/animation_state_machine_editor.cpp
@@ -203,7 +203,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
}
if (node_rects[i].edit.has_point(mb->get_position())) { //edit name
- call_deferred(SNAME("_open_editor"), node_rects[i].node_name);
+ callable_mp(this, &AnimationNodeStateMachineEditor::_open_editor).call_deferred(node_rects[i].node_name);
return;
}
@@ -1610,12 +1610,6 @@ void AnimationNodeStateMachineEditor::_update_mode() {
void AnimationNodeStateMachineEditor::_bind_methods() {
ClassDB::bind_method("_update_graph", &AnimationNodeStateMachineEditor::_update_graph);
- ClassDB::bind_method("_open_editor", &AnimationNodeStateMachineEditor::_open_editor);
- ClassDB::bind_method("_connect_to", &AnimationNodeStateMachineEditor::_connect_to);
- ClassDB::bind_method("_stop_connecting", &AnimationNodeStateMachineEditor::_stop_connecting);
- ClassDB::bind_method("_delete_selected", &AnimationNodeStateMachineEditor::_delete_selected);
- ClassDB::bind_method("_delete_all", &AnimationNodeStateMachineEditor::_delete_all);
- ClassDB::bind_method("_delete_tree_draw", &AnimationNodeStateMachineEditor::_delete_tree_draw);
BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_STYLEBOX, AnimationNodeStateMachineEditor, panel_style, "panel", "GraphStateMachine");
BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_STYLEBOX, AnimationNodeStateMachineEditor, error_panel_style, "error_panel", "GraphStateMachine");
diff --git a/editor/plugins/bone_map_editor_plugin.cpp b/editor/plugins/bone_map_editor_plugin.cpp
index 72a53088dc..153f192838 100644
--- a/editor/plugins/bone_map_editor_plugin.cpp
+++ b/editor/plugins/bone_map_editor_plugin.cpp
@@ -95,7 +95,7 @@ void BoneMapperButton::_notification(int p_what) {
}
}
-BoneMapperButton::BoneMapperButton(const StringName p_profile_bone_name, bool p_require, bool p_selected) {
+BoneMapperButton::BoneMapperButton(const StringName &p_profile_bone_name, bool p_require, bool p_selected) {
profile_bone_name = p_profile_bone_name;
require = p_require;
selected = p_selected;
diff --git a/editor/plugins/bone_map_editor_plugin.h b/editor/plugins/bone_map_editor_plugin.h
index 9ff32707c7..9479ed3730 100644
--- a/editor/plugins/bone_map_editor_plugin.h
+++ b/editor/plugins/bone_map_editor_plugin.h
@@ -78,7 +78,7 @@ public:
bool is_require() const;
- BoneMapperButton(const StringName p_profile_bone_name, bool p_require, bool p_selected);
+ BoneMapperButton(const StringName &p_profile_bone_name, bool p_require, bool p_selected);
~BoneMapperButton();
};
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index 7d4502b69d..f16aff555c 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -345,7 +345,7 @@ void CanvasItemEditor::_snap_other_nodes(
}
}
-Point2 CanvasItemEditor::snap_point(Point2 p_target, unsigned int p_modes, unsigned int p_forced_modes, const CanvasItem *p_self_canvas_item, List<CanvasItem *> p_other_nodes_exceptions) {
+Point2 CanvasItemEditor::snap_point(Point2 p_target, unsigned int p_modes, unsigned int p_forced_modes, const CanvasItem *p_self_canvas_item, const List<CanvasItem *> &p_other_nodes_exceptions) {
snap_target[0] = SNAP_TARGET_NONE;
snap_target[1] = SNAP_TARGET_NONE;
@@ -535,7 +535,7 @@ void CanvasItemEditor::_keying_changed() {
}
}
-Rect2 CanvasItemEditor::_get_encompassing_rect_from_list(List<CanvasItem *> p_list) {
+Rect2 CanvasItemEditor::_get_encompassing_rect_from_list(const List<CanvasItem *> &p_list) {
ERR_FAIL_COND_V(p_list.is_empty(), Rect2());
// Handles the first element
@@ -830,7 +830,7 @@ Vector2 CanvasItemEditor::_position_to_anchor(const Control *p_control, Vector2
return output;
}
-void CanvasItemEditor::_save_canvas_item_state(List<CanvasItem *> p_canvas_items, bool save_bones) {
+void CanvasItemEditor::_save_canvas_item_state(const List<CanvasItem *> &p_canvas_items, bool save_bones) {
original_transform = Transform2D();
bool transform_stored = false;
@@ -853,14 +853,14 @@ void CanvasItemEditor::_save_canvas_item_state(List<CanvasItem *> p_canvas_items
}
}
-void CanvasItemEditor::_restore_canvas_item_state(List<CanvasItem *> p_canvas_items, bool restore_bones) {
+void CanvasItemEditor::_restore_canvas_item_state(const List<CanvasItem *> &p_canvas_items, bool restore_bones) {
for (CanvasItem *ci : drag_selection) {
CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(ci);
ci->_edit_set_state(se->undo_state);
}
}
-void CanvasItemEditor::_commit_canvas_item_state(List<CanvasItem *> p_canvas_items, String action_name, bool commit_bones) {
+void CanvasItemEditor::_commit_canvas_item_state(const List<CanvasItem *> &p_canvas_items, String action_name, bool commit_bones) {
List<CanvasItem *> modified_canvas_items;
for (CanvasItem *ci : p_canvas_items) {
Dictionary old_state = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(ci)->undo_state;
@@ -976,7 +976,7 @@ void CanvasItemEditor::_node_created(Node *p_node) {
c->_edit_set_position(xform.xform(node_create_position));
}
- call_deferred(SNAME("_reset_create_position")); // Defer the call in case more than one node is added.
+ callable_mp(this, &CanvasItemEditor::_reset_create_position).call_deferred(); // Defer the call in case more than one node is added.
}
void CanvasItemEditor::_reset_create_position() {
@@ -2014,14 +2014,14 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {
if ((b->is_alt_pressed() && !b->is_command_or_control_pressed()) || tool == TOOL_MOVE) {
List<CanvasItem *> selection = _get_edited_canvas_items();
- drag_selection.clear();
- for (int i = 0; i < selection.size(); i++) {
- if (_is_node_movable(selection[i], true)) {
- drag_selection.push_back(selection[i]);
+ if (selection.size() > 0) {
+ drag_selection.clear();
+ for (int i = 0; i < selection.size(); i++) {
+ if (_is_node_movable(selection[i], true)) {
+ drag_selection.push_back(selection[i]);
+ }
}
- }
- if (selection.size() > 0) {
drag_type = DRAG_MOVE;
CanvasItem *ci = selection[0];
@@ -2043,8 +2043,9 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {
drag_from = transform.affine_inverse().xform(b->get_position());
_save_canvas_item_state(drag_selection);
+
+ return true;
}
- return true;
}
}
}
@@ -2344,7 +2345,7 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) {
return true;
}
- if (b.is_valid() && b->get_button_index() == MouseButton::LEFT && b->is_pressed() && tool == TOOL_SELECT && !panner->is_panning()) {
+ if (b.is_valid() && b->get_button_index() == MouseButton::LEFT && b->is_pressed() && !panner->is_panning() && (tool == TOOL_SELECT || tool == TOOL_MOVE || tool == TOOL_SCALE || tool == TOOL_ROTATE)) {
// Single item selection
Point2 click = transform.affine_inverse().xform(b->get_position());
@@ -2379,7 +2380,7 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) {
} else {
bool still_selected = _select_click_on_item(ci, click, b->is_shift_pressed());
// Start dragging
- if (still_selected) {
+ if (still_selected && (tool == TOOL_SELECT || tool == TOOL_MOVE)) {
// Drag the node(s) if requested
drag_start_origin = click;
drag_type = DRAG_QUEUED;
@@ -2463,7 +2464,7 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) {
}
}
- if (k.is_valid() && k->is_action_pressed(SNAME("ui_cancel"), false, true) && drag_type == DRAG_NONE && tool == TOOL_SELECT) {
+ if (k.is_valid() && k->is_action_pressed(SNAME("ui_cancel"), false, true) && drag_type == DRAG_NONE) {
// Unselect everything
editor_selection->clear();
viewport->queue_redraw();
@@ -2609,7 +2610,7 @@ void CanvasItemEditor::_gui_input_viewport(const Ref<InputEvent> &p_event) {
// Grab focus
if (!viewport->has_focus() && (!get_viewport()->gui_get_focus_owner() || !get_viewport()->gui_get_focus_owner()->is_text_field())) {
- viewport->call_deferred(SNAME("grab_focus"));
+ callable_mp((Control *)viewport, &Control::grab_focus).call_deferred();
}
}
@@ -3910,6 +3911,11 @@ void CanvasItemEditor::_update_editor_settings() {
void CanvasItemEditor::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_READY: {
+ EditorRunBar::get_singleton()->connect("play_pressed", callable_mp(this, &CanvasItemEditor::_update_override_camera_button).bind(true));
+ EditorRunBar::get_singleton()->connect("stop_pressed", callable_mp(this, &CanvasItemEditor::_update_override_camera_button).bind(false));
+ } break;
+
case NOTIFICATION_PHYSICS_PROCESS: {
EditorNode::get_singleton()->get_scene_root()->set_snap_controls_to_pixels(GLOBAL_GET("gui/common/snap_controls_to_pixels"));
@@ -4722,7 +4728,7 @@ void CanvasItemEditor::_focus_selection(int p_op) {
zoom *= 0.90;
zoom_widget->set_zoom(zoom);
viewport->queue_redraw(); // Redraw to update the global canvas transform after zoom changes.
- call_deferred(SNAME("center_at"), rect.get_center()); // Defer because the updated transform is needed.
+ callable_mp(this, &CanvasItemEditor::center_at).call_deferred(rect.get_center()); // Defer because the updated transform is needed.
} else {
center_at(rect.get_center());
}
@@ -5079,9 +5085,6 @@ CanvasItemEditor::CanvasItemEditor() {
SceneTreeDock::get_singleton()->connect("node_created", callable_mp(this, &CanvasItemEditor::_node_created));
SceneTreeDock::get_singleton()->connect("add_node_used", callable_mp(this, &CanvasItemEditor::_reset_create_position));
- EditorRunBar::get_singleton()->call_deferred(SNAME("connect"), "play_pressed", callable_mp(this, &CanvasItemEditor::_update_override_camera_button).bind(true));
- EditorRunBar::get_singleton()->call_deferred(SNAME("connect"), "stop_pressed", callable_mp(this, &CanvasItemEditor::_update_override_camera_button).bind(false));
-
// Add some margin to the sides for better esthetics.
// This prevents the first button's hover/pressed effect from "touching" the panel's border,
// which looks ugly.
@@ -5842,7 +5845,7 @@ void CanvasItemEditorViewport::_perform_drop_data() {
Vector<String> error_files;
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
- undo_redo->create_action(TTR("Create Node"));
+ undo_redo->create_action_for_history(TTR("Create Node"), EditorNode::get_editor_data().get_current_edited_scene_history_id());
for (int i = 0; i < selected_files.size(); i++) {
String path = selected_files[i];
diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h
index 1939326321..7fe63e6282 100644
--- a/editor/plugins/canvas_item_editor_plugin.h
+++ b/editor/plugins/canvas_item_editor_plugin.h
@@ -393,9 +393,9 @@ private:
CanvasItem *ref_item = nullptr;
- void _save_canvas_item_state(List<CanvasItem *> p_canvas_items, bool save_bones = false);
- void _restore_canvas_item_state(List<CanvasItem *> p_canvas_items, bool restore_bones = false);
- void _commit_canvas_item_state(List<CanvasItem *> p_canvas_items, String action_name, bool commit_bones = false);
+ void _save_canvas_item_state(const List<CanvasItem *> &p_canvas_items, bool save_bones = false);
+ void _restore_canvas_item_state(const List<CanvasItem *> &p_canvas_items, bool restore_bones = false);
+ void _commit_canvas_item_state(const List<CanvasItem *> &p_canvas_items, String action_name, bool commit_bones = false);
Vector2 _anchor_to_position(const Control *p_control, Vector2 anchor);
Vector2 _position_to_anchor(const Control *p_control, Vector2 position);
@@ -429,7 +429,7 @@ private:
void _switch_theme_preview(int p_mode);
List<CanvasItem *> _get_edited_canvas_items(bool retrieve_locked = false, bool remove_canvas_item_if_parent_in_selection = true) const;
- Rect2 _get_encompassing_rect_from_list(List<CanvasItem *> p_list);
+ Rect2 _get_encompassing_rect_from_list(const List<CanvasItem *> &p_list);
void _expand_encompassing_rect_using_children(Rect2 &r_rect, const Node *p_node, bool &r_first, const Transform2D &p_parent_xform = Transform2D(), const Transform2D &p_canvas_xform = Transform2D(), bool include_locked_nodes = true);
Rect2 _get_encompassing_rect(const Node *p_node);
@@ -545,7 +545,7 @@ public:
SNAP_DEFAULT = SNAP_GRID | SNAP_GUIDES | SNAP_PIXEL,
};
- Point2 snap_point(Point2 p_target, unsigned int p_modes = SNAP_DEFAULT, unsigned int p_forced_modes = 0, const CanvasItem *p_self_canvas_item = nullptr, List<CanvasItem *> p_other_nodes_exceptions = List<CanvasItem *>());
+ Point2 snap_point(Point2 p_target, unsigned int p_modes = SNAP_DEFAULT, unsigned int p_forced_modes = 0, const CanvasItem *p_self_canvas_item = nullptr, const List<CanvasItem *> &p_other_nodes_exceptions = List<CanvasItem *>());
real_t snap_angle(real_t p_target, real_t p_start = 0) const;
Transform2D get_canvas_transform() const { return transform; }
diff --git a/editor/plugins/gizmos/joint_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/joint_3d_gizmo_plugin.cpp
index 1fce7f5efb..3a8a0cff96 100644
--- a/editor/plugins/gizmos/joint_3d_gizmo_plugin.cpp
+++ b/editor/plugins/gizmos/joint_3d_gizmo_plugin.cpp
@@ -284,7 +284,7 @@ Joint3DGizmoPlugin::Joint3DGizmoPlugin() {
update_timer->set_wait_time(1.0 / 120.0);
update_timer->connect("timeout", callable_mp(this, &Joint3DGizmoPlugin::incremental_update_gizmos));
update_timer->set_autostart(true);
- EditorNode::get_singleton()->call_deferred(SNAME("add_child"), update_timer);
+ callable_mp((Node *)EditorNode::get_singleton(), &Node::add_child).call_deferred(update_timer, false, Node::INTERNAL_MODE_DISABLED);
}
void Joint3DGizmoPlugin::incremental_update_gizmos() {
diff --git a/editor/plugins/lightmap_gi_editor_plugin.cpp b/editor/plugins/lightmap_gi_editor_plugin.cpp
index 3b1b1e47cb..335498dff9 100644
--- a/editor/plugins/lightmap_gi_editor_plugin.cpp
+++ b/editor/plugins/lightmap_gi_editor_plugin.cpp
@@ -105,7 +105,7 @@ void LightmapGIEditorPlugin::_bake_select_file(const String &p_file) {
EditorNode::get_singleton()->show_warning(TTR("Lightmap data is not local to the scene."));
} break;
case LightmapGI::BAKE_ERROR_TEXTURE_SIZE_TOO_SMALL: {
- EditorNode::get_singleton()->show_warning(TTR("Maximum texture size is too small for the lightmap images."));
+ EditorNode::get_singleton()->show_warning(TTR("Maximum texture size is too small for the lightmap images.\nWhile this can be fixed by increasing the maximum texture size, it is recommended you split the scene into more objects instead."));
} break;
case LightmapGI::BAKE_ERROR_LIGHTMAP_TOO_SMALL: {
EditorNode::get_singleton()->show_warning(TTR("Failed creating lightmap images. Make sure all meshes selected to bake have `lightmap_size_hint` value set high enough, and `texel_scale` value of LightmapGI is not too low."));
diff --git a/editor/plugins/node_3d_editor_gizmos.cpp b/editor/plugins/node_3d_editor_gizmos.cpp
index 3bd786c04f..a427d0359d 100644
--- a/editor/plugins/node_3d_editor_gizmos.cpp
+++ b/editor/plugins/node_3d_editor_gizmos.cpp
@@ -825,6 +825,7 @@ void EditorNode3DGizmo::_bind_methods() {
GDVIRTUAL_BIND(_is_handle_highlighted, "id", "secondary");
GDVIRTUAL_BIND(_get_handle_value, "id", "secondary");
+ GDVIRTUAL_BIND(_begin_handle_action, "id", "secondary");
GDVIRTUAL_BIND(_set_handle, "id", "secondary", "camera", "point");
GDVIRTUAL_BIND(_commit_handle, "id", "secondary", "restore", "cancel");
@@ -1045,6 +1046,7 @@ void EditorNode3DGizmoPlugin::_bind_methods() {
GDVIRTUAL_BIND(_is_handle_highlighted, "gizmo", "handle_id", "secondary");
GDVIRTUAL_BIND(_get_handle_value, "gizmo", "handle_id", "secondary");
+ GDVIRTUAL_BIND(_begin_handle_action, "gizmo", "handle_id", "secondary");
GDVIRTUAL_BIND(_set_handle, "gizmo", "handle_id", "secondary", "camera", "screen_pos");
GDVIRTUAL_BIND(_commit_handle, "gizmo", "handle_id", "secondary", "restore", "cancel");
diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp
index 146fd54b6e..e4d24832bf 100644
--- a/editor/plugins/node_3d_editor_plugin.cpp
+++ b/editor/plugins/node_3d_editor_plugin.cpp
@@ -1839,17 +1839,17 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
clicked = ObjectID();
- if ((spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT && b->is_command_or_control_pressed()) || spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_ROTATE) {
+ if (can_select_gizmos && ((spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT && b->is_command_or_control_pressed()) || spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_ROTATE)) {
begin_transform(TRANSFORM_ROTATE, false);
break;
}
- if (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_MOVE) {
+ if (can_select_gizmos && spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_MOVE) {
begin_transform(TRANSFORM_TRANSLATE, false);
break;
}
- if (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SCALE) {
+ if (can_select_gizmos && spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SCALE) {
begin_transform(TRANSFORM_SCALE, false);
break;
}
@@ -2734,11 +2734,11 @@ void Node3DEditorViewport::_notification(int p_what) {
} else {
set_freelook_active(false);
}
- call_deferred(SNAME("update_transform_gizmo_view"));
+ callable_mp(this, &Node3DEditorViewport::update_transform_gizmo_view).call_deferred();
} break;
case NOTIFICATION_RESIZED: {
- call_deferred(SNAME("update_transform_gizmo_view"));
+ callable_mp(this, &Node3DEditorViewport::update_transform_gizmo_view).call_deferred();
} break;
case NOTIFICATION_PROCESS: {
@@ -3355,7 +3355,7 @@ void Node3DEditorViewport::_menu_option(int p_option) {
view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_ORTHOGONAL), false);
orthogonal = false;
auto_orthogonal = false;
- call_deferred(SNAME("update_transform_gizmo_view"));
+ callable_mp(this, &Node3DEditorViewport::update_transform_gizmo_view).call_deferred();
_update_camera(0);
_update_name();
@@ -3365,7 +3365,7 @@ void Node3DEditorViewport::_menu_option(int p_option) {
view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_ORTHOGONAL), true);
orthogonal = true;
auto_orthogonal = false;
- call_deferred(SNAME("update_transform_gizmo_view"));
+ callable_mp(this, &Node3DEditorViewport::update_transform_gizmo_view).call_deferred();
_update_camera(0);
_update_name();
} break;
@@ -3985,8 +3985,6 @@ Dictionary Node3DEditorViewport::get_state() const {
}
void Node3DEditorViewport::_bind_methods() {
- ClassDB::bind_method(D_METHOD("update_transform_gizmo_view"), &Node3DEditorViewport::update_transform_gizmo_view); // Used by call_deferred.
-
ADD_SIGNAL(MethodInfo("toggle_maximize_view", PropertyInfo(Variant::OBJECT, "viewport")));
ADD_SIGNAL(MethodInfo("clicked", PropertyInfo(Variant::OBJECT, "viewport")));
}
@@ -8061,6 +8059,8 @@ void Node3DEditor::_bind_methods() {
ClassDB::bind_method("_clear_subgizmo_selection", &Node3DEditor::_clear_subgizmo_selection);
ClassDB::bind_method("_refresh_menu_icons", &Node3DEditor::_refresh_menu_icons);
+ ClassDB::bind_method("update_all_gizmos", &Node3DEditor::update_all_gizmos);
+
ADD_SIGNAL(MethodInfo("transform_key_request"));
ADD_SIGNAL(MethodInfo("item_lock_status_changed"));
ADD_SIGNAL(MethodInfo("item_group_status_changed"));
diff --git a/editor/plugins/path_2d_editor_plugin.cpp b/editor/plugins/path_2d_editor_plugin.cpp
index 2e65000f9c..6f44dfc755 100644
--- a/editor/plugins/path_2d_editor_plugin.cpp
+++ b/editor/plugins/path_2d_editor_plugin.cpp
@@ -156,16 +156,14 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
// Check for point creation.
if (mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT && ((mb->is_command_or_control_pressed() && mode == MODE_EDIT) || mode == MODE_CREATE)) {
Ref<Curve2D> curve = node->get_curve();
+ curve->add_point(cpoint);
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Point to Curve"));
undo_redo->add_do_method(curve.ptr(), "add_point", cpoint);
- undo_redo->add_undo_method(curve.ptr(), "remove_point", curve->get_point_count());
- undo_redo->add_do_method(canvas_item_editor, "update_viewport");
- undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
- undo_redo->commit_action();
+ undo_redo->add_undo_method(curve.ptr(), "remove_point", curve->get_point_count() - 1);
- action = ACTION_MOVING_POINT;
+ action = ACTION_MOVING_NEW_POINT;
action_point = curve->get_point_count() - 1;
moving_from = curve->get_point_position(action_point);
moving_screen_from = gpoint;
@@ -193,15 +191,15 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
insertion_point = curve->get_point_count() - 2;
}
+ const Vector2 new_point = xform.affine_inverse().xform(gpoint2);
+ curve->add_point(new_point, Vector2(0, 0), Vector2(0, 0), insertion_point + 1);
+
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Split Curve"));
- undo_redo->add_do_method(curve.ptr(), "add_point", xform.affine_inverse().xform(gpoint2), Vector2(0, 0), Vector2(0, 0), insertion_point + 1);
+ undo_redo->add_do_method(curve.ptr(), "add_point", new_point, Vector2(0, 0), Vector2(0, 0), insertion_point + 1);
undo_redo->add_undo_method(curve.ptr(), "remove_point", insertion_point + 1);
- undo_redo->add_do_method(canvas_item_editor, "update_viewport");
- undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
- undo_redo->commit_action();
- action = ACTION_MOVING_POINT;
+ action = ACTION_MOVING_NEW_POINT;
action_point = insertion_point + 1;
moving_from = curve->get_point_position(action_point);
moving_screen_from = gpoint2;
@@ -224,13 +222,16 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
// N/A, handled in above condition.
break;
- case ACTION_MOVING_POINT: {
- undo_redo->create_action(TTR("Move Point in Curve"));
+ case ACTION_MOVING_POINT:
+ case ACTION_MOVING_NEW_POINT: {
+ if (action == ACTION_MOVING_POINT) {
+ undo_redo->create_action(TTR("Move Point in Curve"));
+ undo_redo->add_undo_method(curve.ptr(), "set_point_position", action_point, moving_from);
+ }
undo_redo->add_do_method(curve.ptr(), "set_point_position", action_point, cpoint);
- undo_redo->add_undo_method(curve.ptr(), "set_point_position", action_point, moving_from);
undo_redo->add_do_method(canvas_item_editor, "update_viewport");
undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
- undo_redo->commit_action();
+ undo_redo->commit_action(false);
} break;
@@ -336,7 +337,8 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
// N/A, handled in above condition.
break;
- case ACTION_MOVING_POINT: {
+ case ACTION_MOVING_POINT:
+ case ACTION_MOVING_NEW_POINT: {
curve->set_point_position(action_point, cpoint);
} break;
diff --git a/editor/plugins/path_2d_editor_plugin.h b/editor/plugins/path_2d_editor_plugin.h
index f70c742e42..af9f307cc8 100644
--- a/editor/plugins/path_2d_editor_plugin.h
+++ b/editor/plugins/path_2d_editor_plugin.h
@@ -80,6 +80,7 @@ class Path2DEditor : public HBoxContainer {
enum Action {
ACTION_NONE,
ACTION_MOVING_POINT,
+ ACTION_MOVING_NEW_POINT,
ACTION_MOVING_IN,
ACTION_MOVING_OUT,
};
diff --git a/editor/plugins/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp
index f8e6c71a4c..148ba7d7ca 100644
--- a/editor/plugins/polygon_2d_editor_plugin.cpp
+++ b/editor/plugins/polygon_2d_editor_plugin.cpp
@@ -36,6 +36,7 @@
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
#include "editor/editor_undo_redo_manager.h"
+#include "editor/gui/editor_zoom_widget.h"
#include "editor/plugins/canvas_item_editor_plugin.h"
#include "scene/2d/skeleton_2d.h"
#include "scene/gui/check_box.h"
@@ -96,10 +97,14 @@ void Polygon2DEditor::_notification(int p_what) {
b_snap_grid->set_icon(get_editor_theme_icon(SNAME("Grid")));
b_snap_enable->set_icon(get_editor_theme_icon(SNAME("SnapGrid")));
- uv_icon_zoom->set_texture(get_editor_theme_icon(SNAME("Zoom")));
uv_vscroll->set_anchors_and_offsets_preset(PRESET_RIGHT_WIDE);
uv_hscroll->set_anchors_and_offsets_preset(PRESET_BOTTOM_WIDE);
+ // Avoid scrollbar overlapping.
+ Size2 hmin = uv_hscroll->get_combined_minimum_size();
+ Size2 vmin = uv_vscroll->get_combined_minimum_size();
+ uv_hscroll->set_anchor_and_offset(SIDE_RIGHT, ANCHOR_END, -vmin.width);
+ uv_vscroll->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, -hmin.height);
[[fallthrough]];
}
case NOTIFICATION_THEME_CHANGED: {
@@ -317,6 +322,7 @@ void Polygon2DEditor::_menu_option(int p_option) {
uv_edit->popup_centered_ratio(0.85);
}
_update_bone_list();
+ get_tree()->connect("process_frame", callable_mp(this, &Polygon2DEditor::_center_view), CONNECT_ONE_SHOT);
} break;
case UVEDIT_POLYGON_TO_UV: {
Vector<Vector2> points = node->get_polygon();
@@ -470,7 +476,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
}
Transform2D mtx;
- mtx.columns[2] = -uv_draw_ofs;
+ mtx.columns[2] = -uv_draw_ofs * uv_draw_zoom;
mtx.scale_basis(Vector2(uv_draw_zoom, uv_draw_zoom));
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
@@ -941,36 +947,79 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
uv_edit_draw->queue_redraw();
}
}
+}
- Ref<InputEventMagnifyGesture> magnify_gesture = p_input;
- if (magnify_gesture.is_valid()) {
- uv_zoom->set_value(uv_zoom->get_value() * magnify_gesture->get_factor());
+void Polygon2DEditor::_center_view() {
+ Size2 texture_size;
+ if (node->get_texture().is_valid()) {
+ texture_size = node->get_texture()->get_size();
+ Vector2 zoom_factor = (uv_edit_draw->get_size() - Vector2(1, 1) * 50 * EDSCALE) / texture_size;
+ zoom_widget->set_zoom(MIN(zoom_factor.x, zoom_factor.y));
+ } else {
+ zoom_widget->set_zoom(EDSCALE);
}
+ // Recalculate scroll limits.
+ _update_zoom_and_pan(false);
- Ref<InputEventPanGesture> pan_gesture = p_input;
- if (pan_gesture.is_valid()) {
- uv_hscroll->set_value(uv_hscroll->get_value() + uv_hscroll->get_page() * pan_gesture->get_delta().x / 8);
- uv_vscroll->set_value(uv_vscroll->get_value() + uv_vscroll->get_page() * pan_gesture->get_delta().y / 8);
- }
+ Size2 offset = (texture_size - uv_edit_draw->get_size() / uv_draw_zoom) / 2;
+ uv_hscroll->set_value_no_signal(offset.x);
+ uv_vscroll->set_value_no_signal(offset.y);
+ _update_zoom_and_pan(false);
}
void Polygon2DEditor::_uv_pan_callback(Vector2 p_scroll_vec, Ref<InputEvent> p_event) {
- uv_hscroll->set_value(uv_hscroll->get_value() - p_scroll_vec.x);
- uv_vscroll->set_value(uv_vscroll->get_value() - p_scroll_vec.y);
+ uv_hscroll->set_value_no_signal(uv_hscroll->get_value() - p_scroll_vec.x / uv_draw_zoom);
+ uv_vscroll->set_value_no_signal(uv_vscroll->get_value() - p_scroll_vec.y / uv_draw_zoom);
+ _update_zoom_and_pan(false);
}
void Polygon2DEditor::_uv_zoom_callback(float p_zoom_factor, Vector2 p_origin, Ref<InputEvent> p_event) {
- uv_zoom->set_value(uv_zoom->get_value() * p_zoom_factor);
+ zoom_widget->set_zoom(uv_draw_zoom * p_zoom_factor);
+ uv_draw_ofs += p_origin / uv_draw_zoom - p_origin / zoom_widget->get_zoom();
+ uv_hscroll->set_value_no_signal(uv_draw_ofs.x);
+ uv_vscroll->set_value_no_signal(uv_draw_ofs.y);
+ _update_zoom_and_pan(false);
}
-void Polygon2DEditor::_uv_scroll_changed(real_t) {
- if (updating_uv_scroll) {
- return;
+void Polygon2DEditor::_update_zoom_and_pan(bool p_zoom_at_center) {
+ uv_draw_ofs = Vector2(uv_hscroll->get_value(), uv_vscroll->get_value());
+ real_t previous_zoom = uv_draw_zoom;
+ uv_draw_zoom = zoom_widget->get_zoom();
+ if (p_zoom_at_center) {
+ Vector2 center = uv_edit_draw->get_size() / 2;
+ uv_draw_ofs += center / previous_zoom - center / uv_draw_zoom;
+ }
+
+ Point2 min_corner;
+ Point2 max_corner;
+ if (node->get_texture().is_valid()) {
+ max_corner += node->get_texture()->get_size();
+ }
+
+ Vector<Vector2> points = uv_edit_mode[0]->is_pressed() ? node->get_uv() : node->get_polygon();
+ for (int i = 0; i < points.size(); i++) {
+ min_corner = min_corner.min(points[i]);
+ max_corner = max_corner.max(points[i]);
}
+ Size2 page_size = uv_edit_draw->get_size() / uv_draw_zoom;
+ Vector2 margin = Vector2(50, 50) * EDSCALE / uv_draw_zoom;
+ min_corner -= page_size - margin;
+ max_corner += page_size - margin;
+
+ uv_hscroll->set_block_signals(true);
+ uv_hscroll->set_min(min_corner.x);
+ uv_hscroll->set_max(max_corner.x);
+ uv_hscroll->set_page(page_size.x);
+ uv_hscroll->set_value(uv_draw_ofs.x);
+ uv_hscroll->set_block_signals(false);
+
+ uv_vscroll->set_block_signals(true);
+ uv_vscroll->set_min(min_corner.y);
+ uv_vscroll->set_max(max_corner.y);
+ uv_vscroll->set_page(page_size.y);
+ uv_vscroll->set_value(uv_draw_ofs.y);
+ uv_vscroll->set_block_signals(false);
- uv_draw_ofs.x = uv_hscroll->get_value();
- uv_draw_ofs.y = uv_vscroll->get_value();
- uv_draw_zoom = uv_zoom->get_value();
uv_edit_draw->queue_redraw();
}
@@ -987,7 +1036,7 @@ void Polygon2DEditor::_uv_draw() {
String warning;
Transform2D mtx;
- mtx.columns[2] = -uv_draw_ofs;
+ mtx.columns[2] = -uv_draw_ofs * uv_draw_zoom;
mtx.scale_basis(Vector2(uv_draw_zoom, uv_draw_zoom));
// Draw texture as a background if editing uvs or no uv mapping exist.
@@ -1094,7 +1143,6 @@ void Polygon2DEditor::_uv_draw() {
polygon_fill_color.push_back(pf);
}
Color prev_color = Color(0.5, 0.5, 0.5);
- Rect2 rect;
int uv_draw_max = uvs.size();
@@ -1222,40 +1270,6 @@ void Polygon2DEditor::_uv_draw() {
//draw paint circle
uv_edit_draw->draw_circle(bone_paint_pos, bone_paint_radius->get_value() * EDSCALE, Color(1, 1, 1, 0.1));
}
-
- rect.position = -uv_edit_draw->get_size();
- rect.size = uv_edit_draw->get_size() * 2.0 + base_tex->get_size() * uv_draw_zoom;
-
- updating_uv_scroll = true;
-
- uv_hscroll->set_min(rect.position.x);
- uv_hscroll->set_max(rect.position.x + rect.size.x);
- if (ABS(rect.position.x - (rect.position.x + rect.size.x)) <= uv_edit_draw->get_size().x) {
- uv_hscroll->hide();
- } else {
- uv_hscroll->show();
- uv_hscroll->set_page(uv_edit_draw->get_size().x);
- uv_hscroll->set_value(uv_draw_ofs.x);
- }
-
- uv_vscroll->set_min(rect.position.y);
- uv_vscroll->set_max(rect.position.y + rect.size.y);
- if (ABS(rect.position.y - (rect.position.y + rect.size.y)) <= uv_edit_draw->get_size().y) {
- uv_vscroll->hide();
- } else {
- uv_vscroll->show();
- uv_vscroll->set_page(uv_edit_draw->get_size().y);
- uv_vscroll->set_value(uv_draw_ofs.y);
- }
-
- Size2 hmin = uv_hscroll->get_combined_minimum_size();
- Size2 vmin = uv_vscroll->get_combined_minimum_size();
-
- // Avoid scrollbar overlapping.
- uv_hscroll->set_anchor_and_offset(SIDE_RIGHT, ANCHOR_END, uv_vscroll->is_visible() ? -vmin.width : 0);
- uv_vscroll->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, uv_hscroll->is_visible() ? -hmin.height : 0);
-
- updating_uv_scroll = false;
}
void Polygon2DEditor::_bind_methods() {
@@ -1480,33 +1494,20 @@ Polygon2DEditor::Polygon2DEditor() {
sb_step_y->connect("value_changed", callable_mp(this, &Polygon2DEditor::_set_snap_step_y));
grid_settings_vb->add_margin_child(TTR("Grid Step Y:"), sb_step_y);
- uv_mode_hb->add_child(memnew(VSeparator));
- uv_icon_zoom = memnew(TextureRect);
- uv_icon_zoom->set_stretch_mode(TextureRect::STRETCH_KEEP_CENTERED);
- uv_mode_hb->add_child(uv_icon_zoom);
- uv_zoom = memnew(HSlider);
- uv_zoom->set_min(0.01);
- uv_zoom->set_max(16);
- uv_zoom->set_value(1);
- uv_zoom->set_step(0.01);
- uv_zoom->set_v_size_flags(SIZE_SHRINK_CENTER);
-
- uv_mode_hb->add_child(uv_zoom);
- uv_zoom->set_custom_minimum_size(Size2(80 * EDSCALE, 0));
- uv_zoom_value = memnew(SpinBox);
- uv_zoom->share(uv_zoom_value);
- uv_zoom_value->set_custom_minimum_size(Size2(50, 0));
- uv_mode_hb->add_child(uv_zoom_value);
- uv_zoom->connect("value_changed", callable_mp(this, &Polygon2DEditor::_uv_scroll_changed));
+ zoom_widget = memnew(EditorZoomWidget);
+ uv_edit_draw->add_child(zoom_widget);
+ zoom_widget->set_anchors_and_offsets_preset(Control::PRESET_TOP_LEFT, Control::PRESET_MODE_MINSIZE, 2 * EDSCALE);
+ zoom_widget->connect("zoom_changed", callable_mp(this, &Polygon2DEditor::_update_zoom_and_pan).unbind(1).bind(true));
+ zoom_widget->set_shortcut_context(nullptr);
uv_vscroll = memnew(VScrollBar);
uv_vscroll->set_step(0.001);
uv_edit_draw->add_child(uv_vscroll);
- uv_vscroll->connect("value_changed", callable_mp(this, &Polygon2DEditor::_uv_scroll_changed));
+ uv_vscroll->connect("value_changed", callable_mp(this, &Polygon2DEditor::_update_zoom_and_pan).unbind(1).bind(false));
uv_hscroll = memnew(HScrollBar);
uv_hscroll->set_step(0.001);
uv_edit_draw->add_child(uv_hscroll);
- uv_hscroll->connect("value_changed", callable_mp(this, &Polygon2DEditor::_uv_scroll_changed));
+ uv_hscroll->connect("value_changed", callable_mp(this, &Polygon2DEditor::_update_zoom_and_pan).unbind(1).bind(false));
bone_scroll_main_vb = memnew(VBoxContainer);
bone_scroll_main_vb->hide();
@@ -1535,7 +1536,6 @@ Polygon2DEditor::Polygon2DEditor() {
point_drag_index = -1;
uv_drag = false;
uv_create = false;
- updating_uv_scroll = false;
bone_painting = false;
error = memnew(AcceptDialog);
diff --git a/editor/plugins/polygon_2d_editor_plugin.h b/editor/plugins/polygon_2d_editor_plugin.h
index 8c52984b59..164aa3eccc 100644
--- a/editor/plugins/polygon_2d_editor_plugin.h
+++ b/editor/plugins/polygon_2d_editor_plugin.h
@@ -35,6 +35,7 @@
class AcceptDialog;
class ButtonGroup;
+class EditorZoomWidget;
class HScrollBar;
class HSlider;
class Label;
@@ -85,12 +86,10 @@ class Polygon2DEditor : public AbstractPolygon2DEditor {
Panel *uv_edit_background = nullptr;
Polygon2D *preview_polygon = nullptr;
Control *uv_edit_draw = nullptr;
- HSlider *uv_zoom = nullptr;
- SpinBox *uv_zoom_value = nullptr;
+ EditorZoomWidget *zoom_widget = nullptr;
HScrollBar *uv_hscroll = nullptr;
VScrollBar *uv_vscroll = nullptr;
MenuButton *uv_menu = nullptr;
- TextureRect *uv_icon_zoom = nullptr;
Ref<ViewPanner> uv_panner;
void _uv_pan_callback(Vector2 p_scroll_vec, Ref<InputEvent> p_event);
@@ -129,7 +128,6 @@ class Polygon2DEditor : public AbstractPolygon2DEditor {
Vector<int> polygon_create;
UVMode uv_move_current;
Vector2 uv_drag_from;
- bool updating_uv_scroll;
AcceptDialog *error = nullptr;
@@ -145,7 +143,8 @@ class Polygon2DEditor : public AbstractPolygon2DEditor {
void _cancel_editing();
void _update_polygon_editing_state();
- void _uv_scroll_changed(real_t);
+ void _center_view();
+ void _update_zoom_and_pan(bool p_zoom_at_center);
void _uv_input(const Ref<InputEvent> &p_input);
void _uv_draw();
void _uv_mode(int p_mode);
diff --git a/editor/plugins/root_motion_editor_plugin.cpp b/editor/plugins/root_motion_editor_plugin.cpp
index bc6507155a..b54a2f717d 100644
--- a/editor/plugins/root_motion_editor_plugin.cpp
+++ b/editor/plugins/root_motion_editor_plugin.cpp
@@ -32,6 +32,7 @@
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
+#include "scene/3d/skeleton_3d.h"
#include "scene/animation/animation_mixer.h"
#include "scene/gui/button.h"
#include "scene/gui/dialogs.h"
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index edf0b73356..9a8164a3cf 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -733,7 +733,7 @@ void ScriptEditor::_open_recent_script(int p_idx) {
// clear button
if (p_idx == recent_scripts->get_item_count() - 1) {
EditorSettings::get_singleton()->set_project_metadata("recent_files", "scripts", Array());
- call_deferred(SNAME("_update_recent_scripts"));
+ callable_mp(this, &ScriptEditor::_update_recent_scripts).call_deferred();
return;
}
@@ -1031,7 +1031,7 @@ void ScriptEditor::_scene_saved_callback(const String &p_path) {
void ScriptEditor::trigger_live_script_reload() {
if (!pending_auto_reload && auto_reload_running_scripts) {
- call_deferred(SNAME("_live_auto_reload_running_scripts"));
+ callable_mp(this, &ScriptEditor::_live_auto_reload_running_scripts).call_deferred();
pending_auto_reload = true;
}
}
@@ -1082,7 +1082,7 @@ bool ScriptEditor::_test_script_times_on_disk(Ref<Resource> p_for_script) {
script_editor->reload_scripts();
need_reload = false;
} else {
- disk_changed->call_deferred(SNAME("popup_centered_ratio"), 0.3);
+ callable_mp((Window *)disk_changed, &Window::popup_centered_ratio).call_deferred(0.3);
}
}
@@ -2873,7 +2873,7 @@ void ScriptEditor::_tree_changed() {
}
waiting_update_names = true;
- call_deferred(SNAME("_update_script_names"));
+ callable_mp(this, &ScriptEditor::_update_script_names).call_deferred();
}
void ScriptEditor::_split_dragged(float) {
@@ -3386,7 +3386,6 @@ void ScriptEditor::_help_class_goto(const String &p_desc) {
eh->set_name(cname);
tab_container->add_child(eh);
- _go_to_tab(tab_container->get_tab_count() - 1);
eh->go_to_help(p_desc);
eh->connect("go_to_help", callable_mp(this, &ScriptEditor::_help_class_goto));
_add_recent_script(eh->get_class());
@@ -3394,7 +3393,7 @@ void ScriptEditor::_help_class_goto(const String &p_desc) {
_update_script_names();
_save_layout();
- call_deferred("_help_tab_goto", cname, p_desc);
+ callable_mp(this, &ScriptEditor::_help_tab_goto).call_deferred(cname, p_desc);
}
bool ScriptEditor::_help_tab_goto(const String &p_name, const String &p_desc) {
@@ -3792,18 +3791,7 @@ void ScriptEditor::_filter_methods_text_changed(const String &p_newtext) {
}
void ScriptEditor::_bind_methods() {
- ClassDB::bind_method("_close_docs_tab", &ScriptEditor::_close_docs_tab);
- ClassDB::bind_method("_close_all_tabs", &ScriptEditor::_close_all_tabs);
- ClassDB::bind_method("_close_other_tabs", &ScriptEditor::_close_other_tabs);
- ClassDB::bind_method("_goto_script_line2", &ScriptEditor::_goto_script_line2);
- ClassDB::bind_method("_copy_script_path", &ScriptEditor::_copy_script_path);
-
- ClassDB::bind_method("_help_class_open", &ScriptEditor::_help_class_open);
ClassDB::bind_method("_help_tab_goto", &ScriptEditor::_help_tab_goto);
- ClassDB::bind_method("_live_auto_reload_running_scripts", &ScriptEditor::_live_auto_reload_running_scripts);
- ClassDB::bind_method("_update_members_overview", &ScriptEditor::_update_members_overview);
- ClassDB::bind_method("_update_recent_scripts", &ScriptEditor::_update_recent_scripts);
-
ClassDB::bind_method("get_current_editor", &ScriptEditor::_get_current_editor);
ClassDB::bind_method("get_open_script_editors", &ScriptEditor::_get_open_script_editors);
diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp
index 574b18731e..38f3d865d4 100644
--- a/editor/plugins/script_text_editor.cpp
+++ b/editor/plugins/script_text_editor.cpp
@@ -886,7 +886,7 @@ void ScriptTextEditor::_breakpoint_item_pressed(int p_idx) {
_edit_option(breakpoints_menu->get_item_id(p_idx));
} else {
code_editor->goto_line(breakpoints_menu->get_item_metadata(p_idx));
- code_editor->get_text_editor()->call_deferred(SNAME("center_viewport_to_caret")); //Need to be deferred, because goto uses call_deferred().
+ callable_mp((TextEdit *)code_editor->get_text_editor(), &TextEdit::center_viewport_to_caret).call_deferred(0); // Needs to be deferred, because goto uses call_deferred().
}
}
@@ -1273,27 +1273,27 @@ void ScriptTextEditor::_edit_option(int p_op) {
switch (p_op) {
case EDIT_UNDO: {
tx->undo();
- tx->call_deferred(SNAME("grab_focus"));
+ callable_mp((Control *)tx, &Control::grab_focus).call_deferred();
} break;
case EDIT_REDO: {
tx->redo();
- tx->call_deferred(SNAME("grab_focus"));
+ callable_mp((Control *)tx, &Control::grab_focus).call_deferred();
} break;
case EDIT_CUT: {
tx->cut();
- tx->call_deferred(SNAME("grab_focus"));
+ callable_mp((Control *)tx, &Control::grab_focus).call_deferred();
} break;
case EDIT_COPY: {
tx->copy();
- tx->call_deferred(SNAME("grab_focus"));
+ callable_mp((Control *)tx, &Control::grab_focus).call_deferred();
} break;
case EDIT_PASTE: {
tx->paste();
- tx->call_deferred(SNAME("grab_focus"));
+ callable_mp((Control *)tx, &Control::grab_focus).call_deferred();
} break;
case EDIT_SELECT_ALL: {
tx->select_all();
- tx->call_deferred(SNAME("grab_focus"));
+ callable_mp((Control *)tx, &Control::grab_focus).call_deferred();
} break;
case EDIT_MOVE_LINE_UP: {
code_editor->move_lines_up();
diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp
index 5ee4d4a961..6d6da69405 100644
--- a/editor/plugins/shader_editor_plugin.cpp
+++ b/editor/plugins/shader_editor_plugin.cpp
@@ -602,6 +602,7 @@ void ShaderEditorPlugin::_file_removed(const String &p_removed_file) {
void ShaderEditorPlugin::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_READY: {
+ EditorNode::get_singleton()->connect("resource_saved", callable_mp(this, &ShaderEditorPlugin::_resource_saved), CONNECT_DEFERRED);
EditorNode::get_singleton()->connect("scene_closed", callable_mp(this, &ShaderEditorPlugin::_close_builtin_shaders_from_scene));
FileSystemDock::get_singleton()->connect("file_removed", callable_mp(this, &ShaderEditorPlugin::_file_removed));
} break;
@@ -677,9 +678,6 @@ ShaderEditorPlugin::ShaderEditorPlugin() {
button = EditorNode::get_singleton()->add_bottom_panel_item(TTR("Shader Editor"), window_wrapper);
- // Defer connect because Editor class is not in the binding system yet.
- EditorNode::get_singleton()->call_deferred("connect", "resource_saved", callable_mp(this, &ShaderEditorPlugin::_resource_saved), CONNECT_DEFERRED);
-
shader_create_dialog = memnew(ShaderCreateDialog);
vb->add_child(shader_create_dialog);
shader_create_dialog->connect("shader_created", callable_mp(this, &ShaderEditorPlugin::_shader_created));
diff --git a/editor/plugins/skeleton_3d_editor_plugin.cpp b/editor/plugins/skeleton_3d_editor_plugin.cpp
index 9a709e8dda..c816220bd2 100644
--- a/editor/plugins/skeleton_3d_editor_plugin.cpp
+++ b/editor/plugins/skeleton_3d_editor_plugin.cpp
@@ -837,10 +837,10 @@ void Skeleton3DEditor::_notification(int p_what) {
joint_tree->connect("item_selected", callable_mp(this, &Skeleton3DEditor::_joint_tree_selection_changed));
joint_tree->connect("item_mouse_selected", callable_mp(this, &Skeleton3DEditor::_joint_tree_rmb_select));
#ifdef TOOLS_ENABLED
- skeleton->connect("pose_updated", callable_mp(this, &Skeleton3DEditor::_draw_gizmo));
- skeleton->connect("pose_updated", callable_mp(this, &Skeleton3DEditor::_update_properties));
- skeleton->connect("bone_enabled_changed", callable_mp(this, &Skeleton3DEditor::_bone_enabled_changed));
- skeleton->connect("show_rest_only_changed", callable_mp(this, &Skeleton3DEditor::_update_gizmo_visible));
+ skeleton->connect(SceneStringNames::get_singleton()->pose_updated, callable_mp(this, &Skeleton3DEditor::_draw_gizmo));
+ skeleton->connect(SceneStringNames::get_singleton()->pose_updated, callable_mp(this, &Skeleton3DEditor::_update_properties));
+ skeleton->connect(SceneStringNames::get_singleton()->bone_enabled_changed, callable_mp(this, &Skeleton3DEditor::_bone_enabled_changed));
+ skeleton->connect(SceneStringNames::get_singleton()->show_rest_only_changed, callable_mp(this, &Skeleton3DEditor::_update_gizmo_visible));
#endif
get_tree()->connect("node_removed", callable_mp(this, &Skeleton3DEditor::_node_removed), Object::CONNECT_ONE_SHOT);
@@ -865,10 +865,10 @@ void Skeleton3DEditor::_notification(int p_what) {
if (skeleton) {
select_bone(-1); // Requires that the joint_tree has not been deleted.
#ifdef TOOLS_ENABLED
- skeleton->disconnect("show_rest_only_changed", callable_mp(this, &Skeleton3DEditor::_update_gizmo_visible));
- skeleton->disconnect("bone_enabled_changed", callable_mp(this, &Skeleton3DEditor::_bone_enabled_changed));
- skeleton->disconnect("pose_updated", callable_mp(this, &Skeleton3DEditor::_draw_gizmo));
- skeleton->disconnect("pose_updated", callable_mp(this, &Skeleton3DEditor::_update_properties));
+ skeleton->disconnect(SceneStringNames::get_singleton()->show_rest_only_changed, callable_mp(this, &Skeleton3DEditor::_update_gizmo_visible));
+ skeleton->disconnect(SceneStringNames::get_singleton()->bone_enabled_changed, callable_mp(this, &Skeleton3DEditor::_bone_enabled_changed));
+ skeleton->disconnect(SceneStringNames::get_singleton()->pose_updated, callable_mp(this, &Skeleton3DEditor::_draw_gizmo));
+ skeleton->disconnect(SceneStringNames::get_singleton()->pose_updated, callable_mp(this, &Skeleton3DEditor::_update_properties));
skeleton->set_transform_gizmo_visible(true);
#endif
if (handles_mesh_instance->get_parent()) {
@@ -889,18 +889,6 @@ void Skeleton3DEditor::_node_removed(Node *p_node) {
_update_properties();
}
-void Skeleton3DEditor::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_node_removed"), &Skeleton3DEditor::_node_removed);
- ClassDB::bind_method(D_METHOD("_joint_tree_selection_changed"), &Skeleton3DEditor::_joint_tree_selection_changed);
- ClassDB::bind_method(D_METHOD("_joint_tree_rmb_select"), &Skeleton3DEditor::_joint_tree_rmb_select);
- ClassDB::bind_method(D_METHOD("_update_properties"), &Skeleton3DEditor::_update_properties);
- ClassDB::bind_method(D_METHOD("_on_click_skeleton_option"), &Skeleton3DEditor::_on_click_skeleton_option);
-
- ClassDB::bind_method(D_METHOD("move_skeleton_bone"), &Skeleton3DEditor::move_skeleton_bone);
-
- ClassDB::bind_method(D_METHOD("_draw_gizmo"), &Skeleton3DEditor::_draw_gizmo);
-}
-
void Skeleton3DEditor::edit_mode_toggled(const bool pressed) {
edit_mode = pressed;
_update_gizmo_visible();
diff --git a/editor/plugins/skeleton_3d_editor_plugin.h b/editor/plugins/skeleton_3d_editor_plugin.h
index 3cc7c85492..839061a2fe 100644
--- a/editor/plugins/skeleton_3d_editor_plugin.h
+++ b/editor/plugins/skeleton_3d_editor_plugin.h
@@ -198,7 +198,6 @@ class Skeleton3DEditor : public VBoxContainer {
protected:
void _notification(int p_what);
void _node_removed(Node *p_node);
- static void _bind_methods();
public:
static Skeleton3DEditor *get_singleton() { return singleton; }
diff --git a/editor/plugins/text_editor.cpp b/editor/plugins/text_editor.cpp
index c7945e44f0..475aba0eeb 100644
--- a/editor/plugins/text_editor.cpp
+++ b/editor/plugins/text_editor.cpp
@@ -352,27 +352,27 @@ void TextEditor::_edit_option(int p_op) {
switch (p_op) {
case EDIT_UNDO: {
tx->undo();
- tx->call_deferred(SNAME("grab_focus"));
+ callable_mp((Control *)tx, &Control::grab_focus).call_deferred();
} break;
case EDIT_REDO: {
tx->redo();
- tx->call_deferred(SNAME("grab_focus"));
+ callable_mp((Control *)tx, &Control::grab_focus).call_deferred();
} break;
case EDIT_CUT: {
tx->cut();
- tx->call_deferred(SNAME("grab_focus"));
+ callable_mp((Control *)tx, &Control::grab_focus).call_deferred();
} break;
case EDIT_COPY: {
tx->copy();
- tx->call_deferred(SNAME("grab_focus"));
+ callable_mp((Control *)tx, &Control::grab_focus).call_deferred();
} break;
case EDIT_PASTE: {
tx->paste();
- tx->call_deferred(SNAME("grab_focus"));
+ callable_mp((Control *)tx, &Control::grab_focus).call_deferred();
} break;
case EDIT_SELECT_ALL: {
tx->select_all();
- tx->call_deferred(SNAME("grab_focus"));
+ callable_mp((Control *)tx, &Control::grab_focus).call_deferred();
} break;
case EDIT_MOVE_LINE_UP: {
code_editor->move_lines_up();
diff --git a/editor/plugins/text_shader_editor.cpp b/editor/plugins/text_shader_editor.cpp
index 3a2ddeb94e..e5b9e3854f 100644
--- a/editor/plugins/text_shader_editor.cpp
+++ b/editor/plugins/text_shader_editor.cpp
@@ -170,8 +170,8 @@ void ShaderTextEditor::set_edited_code(const String &p_code) {
get_text_editor()->set_text(p_code);
get_text_editor()->clear_undo_history();
- get_text_editor()->call_deferred(SNAME("set_h_scroll"), 0);
- get_text_editor()->call_deferred(SNAME("set_v_scroll"), 0);
+ callable_mp((TextEdit *)get_text_editor(), &TextEdit::set_h_scroll).call_deferred(0);
+ callable_mp((TextEdit *)get_text_editor(), &TextEdit::set_v_scroll).call_deferred(0);
get_text_editor()->tag_saved_version();
_validate_script();
@@ -719,7 +719,7 @@ void TextShaderEditor::_menu_option(int p_option) {
} break;
}
if (p_option != SEARCH_FIND && p_option != SEARCH_REPLACE && p_option != SEARCH_GOTO_LINE) {
- shader_editor->get_text_editor()->call_deferred(SNAME("grab_focus"));
+ callable_mp((Control *)shader_editor->get_text_editor(), &Control::grab_focus).call_deferred();
}
}
@@ -820,7 +820,7 @@ void TextShaderEditor::_check_for_external_edit() {
if (use_autoreload) {
_reload_shader_include_from_disk();
} else {
- disk_changed->call_deferred(SNAME("popup_centered"));
+ callable_mp((Window *)disk_changed, &Window::popup_centered).call_deferred(Size2i());
}
}
return;
@@ -834,7 +834,7 @@ void TextShaderEditor::_check_for_external_edit() {
if (use_autoreload) {
_reload_shader_from_disk();
} else {
- disk_changed->call_deferred(SNAME("popup_centered"));
+ callable_mp((Window *)disk_changed, &Window::popup_centered).call_deferred(Size2i());
}
}
}
diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp
index bd66e5e9b7..cbe0f115d3 100644
--- a/editor/plugins/theme_editor_plugin.cpp
+++ b/editor/plugins/theme_editor_plugin.cpp
@@ -2374,7 +2374,7 @@ void ThemeTypeEditor::_update_type_list_debounced() {
update_debounce_timer->start();
}
-HashMap<StringName, bool> ThemeTypeEditor::_get_type_items(String p_type_name, void (Theme::*get_list_func)(StringName, List<StringName> *) const, bool include_default) {
+HashMap<StringName, bool> ThemeTypeEditor::_get_type_items(String p_type_name, void (Theme::*get_list_func)(const StringName &, List<StringName> *) const, bool include_default) {
HashMap<StringName, bool> items;
List<StringName> names;
diff --git a/editor/plugins/theme_editor_plugin.h b/editor/plugins/theme_editor_plugin.h
index cf8c5ceb28..8ad262da55 100644
--- a/editor/plugins/theme_editor_plugin.h
+++ b/editor/plugins/theme_editor_plugin.h
@@ -373,7 +373,7 @@ class ThemeTypeEditor : public MarginContainer {
VBoxContainer *_create_item_list(Theme::DataType p_data_type);
void _update_type_list();
void _update_type_list_debounced();
- HashMap<StringName, bool> _get_type_items(String p_type_name, void (Theme::*get_list_func)(StringName, List<StringName> *) const, bool include_default);
+ HashMap<StringName, bool> _get_type_items(String p_type_name, void (Theme::*get_list_func)(const StringName &, List<StringName> *) const, bool include_default);
HBoxContainer *_create_property_control(Theme::DataType p_data_type, String p_item_name, bool p_editable);
void _add_focusable(Control *p_control);
void _update_type_items();
diff --git a/editor/plugins/tiles/tile_data_editors.cpp b/editor/plugins/tiles/tile_data_editors.cpp
index 221833d450..8e4c26bd15 100644
--- a/editor/plugins/tiles/tile_data_editors.cpp
+++ b/editor/plugins/tiles/tile_data_editors.cpp
@@ -53,7 +53,7 @@
void TileDataEditor::_tile_set_changed_plan_update() {
_tile_set_changed_update_needed = true;
- call_deferred(SNAME("_tile_set_changed_deferred_update"));
+ callable_mp(this, &TileDataEditor::_tile_set_changed_deferred_update).call_deferred();
}
void TileDataEditor::_tile_set_changed_deferred_update() {
@@ -80,8 +80,6 @@ TileData *TileDataEditor::_get_tile_data(TileMapCell p_cell) {
}
void TileDataEditor::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_tile_set_changed_deferred_update"), &TileDataEditor::_tile_set_changed_deferred_update);
-
ADD_SIGNAL(MethodInfo("needs_redraw"));
}
@@ -112,16 +110,16 @@ bool DummyObject::_get(const StringName &p_name, Variant &r_ret) const {
return false;
}
-bool DummyObject::has_dummy_property(StringName p_name) {
+bool DummyObject::has_dummy_property(const StringName &p_name) {
return properties.has(p_name);
}
-void DummyObject::add_dummy_property(StringName p_name) {
+void DummyObject::add_dummy_property(const StringName &p_name) {
ERR_FAIL_COND(properties.has(p_name));
properties[p_name] = Variant();
}
-void DummyObject::remove_dummy_property(StringName p_name) {
+void DummyObject::remove_dummy_property(const StringName &p_name) {
ERR_FAIL_COND(!properties.has(p_name));
properties.erase(p_name);
}
@@ -719,11 +717,19 @@ void GenericTilePolygonEditor::set_tile_set(Ref<TileSet> p_tile_set) {
Vector2 zoomed_tile = editor_zoom_widget->get_zoom() * tile_set->get_tile_size();
while (zoomed_tile.y < default_control_y_size) {
editor_zoom_widget->set_zoom_by_increments(6, false);
- zoomed_tile = editor_zoom_widget->get_zoom() * tile_set->get_tile_size();
+ float current_zoom = editor_zoom_widget->get_zoom();
+ zoomed_tile = current_zoom * tile_set->get_tile_size();
+ if (Math::is_equal_approx(current_zoom, editor_zoom_widget->get_max_zoom())) {
+ break;
+ }
}
while (zoomed_tile.y > default_control_y_size) {
editor_zoom_widget->set_zoom_by_increments(-6, false);
- zoomed_tile = editor_zoom_widget->get_zoom() * tile_set->get_tile_size();
+ float current_zoom = editor_zoom_widget->get_zoom();
+ zoomed_tile = current_zoom * tile_set->get_tile_size();
+ if (Math::is_equal_approx(current_zoom, editor_zoom_widget->get_min_zoom())) {
+ break;
+ }
}
editor_zoom_widget->set_zoom_by_increments(-6, false);
_zoom_changed();
@@ -948,7 +954,7 @@ GenericTilePolygonEditor::GenericTilePolygonEditor() {
_set_snap_option(EditorSettings::get_singleton()->get_project_metadata("editor_metadata", "tile_snap_option", SNAP_NONE));
}
-void TileDataDefaultEditor::_property_value_changed(StringName p_property, Variant p_value, StringName p_field) {
+void TileDataDefaultEditor::_property_value_changed(const StringName &p_property, Variant p_value, const StringName &p_field) {
ERR_FAIL_NULL(dummy_object);
dummy_object->set(p_property, p_value);
emit_signal(SNAME("needs_redraw"));
@@ -981,7 +987,7 @@ Variant TileDataDefaultEditor::_get_value(TileSetAtlasSource *p_tile_set_atlas_s
return tile_data->get(property);
}
-void TileDataDefaultEditor::_setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, HashMap<TileMapCell, Variant, TileMapCell> p_previous_values, Variant p_new_value) {
+void TileDataDefaultEditor::_setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, const HashMap<TileMapCell, Variant, TileMapCell> &p_previous_values, Variant p_new_value) {
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
for (const KeyValue<TileMapCell, Variant> &E : p_previous_values) {
Vector2i coords = E.key.get_atlas_coords();
@@ -1455,7 +1461,7 @@ Variant TileDataOcclusionShapeEditor::_get_value(TileSetAtlasSource *p_tile_set_
return tile_data->get_occluder(occlusion_layer);
}
-void TileDataOcclusionShapeEditor::_setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, HashMap<TileMapCell, Variant, TileMapCell> p_previous_values, Variant p_new_value) {
+void TileDataOcclusionShapeEditor::_setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, const HashMap<TileMapCell, Variant, TileMapCell> &p_previous_values, Variant p_new_value) {
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
for (const KeyValue<TileMapCell, Variant> &E : p_previous_values) {
Vector2i coords = E.key.get_atlas_coords();
@@ -1481,11 +1487,11 @@ TileDataOcclusionShapeEditor::TileDataOcclusionShapeEditor() {
add_child(polygon_editor);
}
-void TileDataCollisionEditor::_property_value_changed(StringName p_property, Variant p_value, StringName p_field) {
+void TileDataCollisionEditor::_property_value_changed(const StringName &p_property, Variant p_value, const StringName &p_field) {
dummy_object->set(p_property, p_value);
}
-void TileDataCollisionEditor::_property_selected(StringName p_path, int p_focusable) {
+void TileDataCollisionEditor::_property_selected(const StringName &p_path, int p_focusable) {
// Deselect all other properties
for (KeyValue<StringName, EditorProperty *> &editor : property_editors) {
if (editor.key != p_path) {
@@ -1634,10 +1640,10 @@ Variant TileDataCollisionEditor::_get_value(TileSetAtlasSource *p_tile_set_atlas
return dict;
}
-void TileDataCollisionEditor::_setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, HashMap<TileMapCell, Variant, TileMapCell> p_previous_values, Variant p_new_value) {
+void TileDataCollisionEditor::_setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, const HashMap<TileMapCell, Variant, TileMapCell> &p_previous_values, Variant p_new_value) {
Dictionary new_dict = p_new_value;
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
- for (KeyValue<TileMapCell, Variant> &E : p_previous_values) {
+ for (const KeyValue<TileMapCell, Variant> &E : p_previous_values) {
Vector2i coords = E.key.get_atlas_coords();
Dictionary old_dict = E.value;
@@ -1802,7 +1808,7 @@ void TileDataTerrainsEditor::_update_terrain_selector() {
}
}
-void TileDataTerrainsEditor::_property_value_changed(StringName p_property, Variant p_value, StringName p_field) {
+void TileDataTerrainsEditor::_property_value_changed(const StringName &p_property, Variant p_value, const StringName &p_field) {
Variant old_value = dummy_object->get(p_property);
dummy_object->set(p_property, p_value);
if (p_property == "terrain_set") {
@@ -2871,7 +2877,7 @@ Variant TileDataNavigationEditor::_get_value(TileSetAtlasSource *p_tile_set_atla
return tile_data->get_navigation_polygon(navigation_layer);
}
-void TileDataNavigationEditor::_setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, HashMap<TileMapCell, Variant, TileMapCell> p_previous_values, Variant p_new_value) {
+void TileDataNavigationEditor::_setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, const HashMap<TileMapCell, Variant, TileMapCell> &p_previous_values, Variant p_new_value) {
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
for (const KeyValue<TileMapCell, Variant> &E : p_previous_values) {
Vector2i coords = E.key.get_atlas_coords();
diff --git a/editor/plugins/tiles/tile_data_editors.h b/editor/plugins/tiles/tile_data_editors.h
index 4bba5bb467..27fe4316a0 100644
--- a/editor/plugins/tiles/tile_data_editors.h
+++ b/editor/plugins/tiles/tile_data_editors.h
@@ -82,9 +82,9 @@ protected:
bool _get(const StringName &p_name, Variant &r_ret) const;
public:
- bool has_dummy_property(StringName p_name);
- void add_dummy_property(StringName p_name);
- void remove_dummy_property(StringName p_name);
+ bool has_dummy_property(const StringName &p_name);
+ void add_dummy_property(const StringName &p_name);
+ void remove_dummy_property(const StringName &p_name);
void clear_dummy_properties();
};
@@ -224,7 +224,7 @@ private:
HashMap<TileMapCell, Variant, TileMapCell> drag_modified;
Variant drag_painted_value;
- void _property_value_changed(StringName p_property, Variant p_value, StringName p_field);
+ void _property_value_changed(const StringName &p_property, Variant p_value, const StringName &p_field);
protected:
DummyObject *dummy_object = memnew(DummyObject);
@@ -238,7 +238,7 @@ protected:
virtual void _set_painted_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile);
virtual void _set_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile, Variant p_value);
virtual Variant _get_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile);
- virtual void _setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, HashMap<TileMapCell, Variant, TileMapCell> p_previous_values, Variant p_new_value);
+ virtual void _setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, const HashMap<TileMapCell, Variant, TileMapCell> &p_previous_values, Variant p_new_value);
public:
virtual Control *get_toolbar() override { return toolbar; };
@@ -291,7 +291,7 @@ private:
virtual void _set_painted_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) override;
virtual void _set_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile, Variant p_value) override;
virtual Variant _get_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) override;
- virtual void _setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, HashMap<TileMapCell, Variant, TileMapCell> p_previous_values, Variant p_new_value) override;
+ virtual void _setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, const HashMap<TileMapCell, Variant, TileMapCell> &p_previous_values, Variant p_new_value) override;
protected:
virtual void _tile_set_changed() override;
@@ -316,15 +316,15 @@ class TileDataCollisionEditor : public TileDataDefaultEditor {
DummyObject *dummy_object = memnew(DummyObject);
HashMap<StringName, EditorProperty *> property_editors;
- void _property_value_changed(StringName p_property, Variant p_value, StringName p_field);
- void _property_selected(StringName p_path, int p_focusable);
+ void _property_value_changed(const StringName &p_property, Variant p_value, const StringName &p_field);
+ void _property_selected(const StringName &p_path, int p_focusable);
void _polygons_changed();
virtual Variant _get_painted_value() override;
virtual void _set_painted_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) override;
virtual void _set_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile, Variant p_value) override;
virtual Variant _get_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) override;
- virtual void _setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, HashMap<TileMapCell, Variant, TileMapCell> p_previous_values, Variant p_new_value) override;
+ virtual void _setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, const HashMap<TileMapCell, Variant, TileMapCell> &p_previous_values, Variant p_new_value) override;
protected:
virtual void _tile_set_changed() override;
@@ -368,7 +368,7 @@ private:
EditorPropertyEnum *terrain_set_property_editor = nullptr;
EditorPropertyEnum *terrain_property_editor = nullptr;
- void _property_value_changed(StringName p_property, Variant p_value, StringName p_field);
+ void _property_value_changed(const StringName &p_property, Variant p_value, const StringName &p_field);
void _update_terrain_selector();
@@ -405,7 +405,7 @@ private:
virtual void _set_painted_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) override;
virtual void _set_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile, Variant p_value) override;
virtual Variant _get_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) override;
- virtual void _setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, HashMap<TileMapCell, Variant, TileMapCell> p_previous_values, Variant p_new_value) override;
+ virtual void _setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, const HashMap<TileMapCell, Variant, TileMapCell> &p_previous_values, Variant p_new_value) override;
protected:
virtual void _tile_set_changed() override;
diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
index a3fc6aa5f7..10dc20d24f 100644
--- a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
+++ b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
@@ -507,7 +507,7 @@ void TileSetAtlasSourceEditor::AtlasTileProxyObject::_get_property_list(List<Pro
}
}
-void TileSetAtlasSourceEditor::AtlasTileProxyObject::edit(Ref<TileSetAtlasSource> p_tile_set_atlas_source, RBSet<TileSelection> p_tiles) {
+void TileSetAtlasSourceEditor::AtlasTileProxyObject::edit(Ref<TileSetAtlasSource> p_tile_set_atlas_source, const RBSet<TileSelection> &p_tiles) {
ERR_FAIL_COND(!p_tile_set_atlas_source.is_valid());
ERR_FAIL_COND(p_tiles.is_empty());
for (const TileSelection &E : p_tiles) {
@@ -954,7 +954,7 @@ void TileSetAtlasSourceEditor::_tile_data_editor_dropdown_button_pressed() {
}
void TileSetAtlasSourceEditor::_tile_data_editors_tree_selected() {
- tile_data_editors_popup->call_deferred(SNAME("hide"));
+ callable_mp((Window *)tile_data_editors_popup, &Window::hide).call_deferred();
_update_current_tile_data_editor();
tile_atlas_control->queue_redraw();
tile_atlas_control_unscaled->queue_redraw();
diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.h b/editor/plugins/tiles/tile_set_atlas_source_editor.h
index 7f6bab804d..e1e6a3113c 100644
--- a/editor/plugins/tiles/tile_set_atlas_source_editor.h
+++ b/editor/plugins/tiles/tile_set_atlas_source_editor.h
@@ -105,7 +105,7 @@ public:
RBSet<TileSelection> get_edited_tiles() const { return tiles; };
// Update the proxyed object.
- void edit(Ref<TileSetAtlasSource> p_tile_set_atlas_source, RBSet<TileSelection> p_tiles = RBSet<TileSelection>());
+ void edit(Ref<TileSetAtlasSource> p_tile_set_atlas_source, const RBSet<TileSelection> &p_tiles = RBSet<TileSelection>());
AtlasTileProxyObject(TileSetAtlasSourceEditor *p_tiles_set_atlas_source_editor) {
tiles_set_atlas_source_editor = p_tiles_set_atlas_source_editor;
diff --git a/editor/plugins/tiles/tiles_editor_plugin.cpp b/editor/plugins/tiles/tiles_editor_plugin.cpp
index b96f3f21b8..e7e94fdefa 100644
--- a/editor/plugins/tiles/tiles_editor_plugin.cpp
+++ b/editor/plugins/tiles/tiles_editor_plugin.cpp
@@ -125,7 +125,7 @@ void TilesEditorUtils::_thread() {
tile_map->set_position(-(scale * encompassing_rect.get_center()) + thumbnail_size2 / 2);
// Add the viewport at the last moment to avoid rendering too early.
- EditorNode::get_singleton()->call_deferred("add_child", viewport);
+ callable_mp((Node *)EditorNode::get_singleton(), &Node::add_child).call_deferred(viewport, false, Node::INTERNAL_MODE_DISABLED);
RS::get_singleton()->connect(SNAME("frame_pre_draw"), callable_mp(const_cast<TilesEditorUtils *>(this), &TilesEditorUtils::_preview_frame_started), Object::CONNECT_ONE_SHOT);
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index 5c22e454ab..24b76526c6 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -182,7 +182,7 @@ void VisualShaderGraphPlugin::show_port_preview(VisualShader::Type p_type, int p
}
void VisualShaderGraphPlugin::update_node_deferred(VisualShader::Type p_type, int p_node_id) {
- call_deferred(SNAME("update_node"), p_type, p_node_id);
+ callable_mp(this, &VisualShaderGraphPlugin::update_node).call_deferred(p_type, p_node_id);
}
void VisualShaderGraphPlugin::update_node(VisualShader::Type p_type, int p_node_id) {
@@ -1492,14 +1492,14 @@ void VisualShaderEditor::_update_custom_script(const Ref<Script> &p_script) {
if (!_block_update_options_menu) {
_block_update_options_menu = true;
- call_deferred(SNAME("_update_options_menu_deferred"));
+ callable_mp(this, &VisualShaderEditor::_update_options_menu_deferred);
}
// To prevent rebuilding the shader multiple times when multiple scripts are saved.
if (need_rebuild && !_block_rebuild_shader) {
_block_rebuild_shader = true;
- call_deferred(SNAME("_rebuild_shader_deferred"));
+ callable_mp(this, &VisualShaderEditor::_rebuild_shader_deferred);
}
}
@@ -1581,8 +1581,7 @@ void VisualShaderEditor::_resource_removed(const Ref<Resource> &p_resource) {
if (!pending_custom_scripts_to_delete) {
pending_custom_scripts_to_delete = true;
-
- call_deferred("_resources_removed");
+ callable_mp(this, &VisualShaderEditor::_resources_removed).call_deferred();
}
}
@@ -3322,11 +3321,11 @@ void VisualShaderEditor::_add_node(int p_idx, const Vector<Variant> &p_ops, Stri
}
if (is_curve) {
- graph_plugin->call_deferred(SNAME("update_curve"), id_to_use);
+ callable_mp(graph_plugin.ptr(), &VisualShaderGraphPlugin::update_curve).call_deferred(id_to_use);
}
if (is_curve_xyz) {
- graph_plugin->call_deferred(SNAME("update_curve_xyz"), id_to_use);
+ callable_mp(graph_plugin.ptr(), &VisualShaderGraphPlugin::update_curve_xyz).call_deferred(id_to_use);
}
if (p_resource_path.is_empty()) {
@@ -3466,7 +3465,7 @@ void VisualShaderEditor::_node_dragged(const Vector2 &p_from, const Vector2 &p_t
VisualShader::Type type = get_current_shader_type();
drag_buffer.push_back({ type, p_node, p_from, p_to });
if (!drag_dirty) {
- call_deferred(SNAME("_nodes_dragged"));
+ callable_mp(this, &VisualShaderEditor::_nodes_dragged).call_deferred();
}
drag_dirty = true;
}
@@ -4094,7 +4093,7 @@ void VisualShaderEditor::_show_members_dialog(bool at_mouse_pos, VisualShaderNod
Vector2 difference = (dialog_rect.get_end() - window_rect.get_end()).max(Vector2());
members_dialog->set_position(members_dialog->get_position() - difference);
- node_filter->call_deferred(SNAME("grab_focus")); // Still not visible.
+ callable_mp((Control *)node_filter, &Control::grab_focus).call_deferred(); // Still not visible.
node_filter->select_all();
}
@@ -5187,28 +5186,17 @@ void VisualShaderEditor::_visibility_changed() {
void VisualShaderEditor::_bind_methods() {
ClassDB::bind_method("_update_nodes", &VisualShaderEditor::_update_nodes);
ClassDB::bind_method("_update_graph", &VisualShaderEditor::_update_graph);
- ClassDB::bind_method("_add_node", &VisualShaderEditor::_add_node);
- ClassDB::bind_method("_node_changed", &VisualShaderEditor::_node_changed);
ClassDB::bind_method("_input_select_item", &VisualShaderEditor::_input_select_item);
ClassDB::bind_method("_parameter_ref_select_item", &VisualShaderEditor::_parameter_ref_select_item);
ClassDB::bind_method("_varying_select_item", &VisualShaderEditor::_varying_select_item);
ClassDB::bind_method("_set_node_size", &VisualShaderEditor::_set_node_size);
- ClassDB::bind_method("_clear_copy_buffer", &VisualShaderEditor::_clear_copy_buffer);
ClassDB::bind_method("_update_parameters", &VisualShaderEditor::_update_parameters);
ClassDB::bind_method("_update_varyings", &VisualShaderEditor::_update_varyings);
ClassDB::bind_method("_update_varying_tree", &VisualShaderEditor::_update_varying_tree);
ClassDB::bind_method("_set_mode", &VisualShaderEditor::_set_mode);
- ClassDB::bind_method("_nodes_dragged", &VisualShaderEditor::_nodes_dragged);
- ClassDB::bind_method("_float_constant_selected", &VisualShaderEditor::_float_constant_selected);
ClassDB::bind_method("_update_constant", &VisualShaderEditor::_update_constant);
ClassDB::bind_method("_update_parameter", &VisualShaderEditor::_update_parameter);
- ClassDB::bind_method("_expand_output_port", &VisualShaderEditor::_expand_output_port);
- ClassDB::bind_method("_update_options_menu_deferred", &VisualShaderEditor::_update_options_menu_deferred);
- ClassDB::bind_method("_rebuild_shader_deferred", &VisualShaderEditor::_rebuild_shader_deferred);
- ClassDB::bind_method("_resources_removed", &VisualShaderEditor::_resources_removed);
ClassDB::bind_method("_update_next_previews", &VisualShaderEditor::_update_next_previews);
-
- ClassDB::bind_method("_is_available", &VisualShaderEditor::_is_available);
}
VisualShaderEditor::VisualShaderEditor() {
diff --git a/editor/progress_dialog.cpp b/editor/progress_dialog.cpp
index 366d0cb2fc..c0dfc18072 100644
--- a/editor/progress_dialog.cpp
+++ b/editor/progress_dialog.cpp
@@ -30,7 +30,6 @@
#include "progress_dialog.h"
-#include "core/object/message_queue.h"
#include "core/os/os.h"
#include "editor/editor_interface.h"
#include "editor/editor_node.h"
@@ -97,15 +96,8 @@ void BackgroundProgress::_end_task(const String &p_task) {
tasks.erase(p_task);
}
-void BackgroundProgress::_bind_methods() {
- ClassDB::bind_method("_add_task", &BackgroundProgress::_add_task);
- ClassDB::bind_method("_task_step", &BackgroundProgress::_task_step);
- ClassDB::bind_method("_end_task", &BackgroundProgress::_end_task);
- ClassDB::bind_method("_update", &BackgroundProgress::_update);
-}
-
void BackgroundProgress::add_task(const String &p_task, const String &p_label, int p_steps) {
- MessageQueue::get_singleton()->push_call(this, "_add_task", p_task, p_label, p_steps);
+ callable_mp(this, &BackgroundProgress::_add_task).call_deferred(p_task, p_label, p_steps);
}
void BackgroundProgress::task_step(const String &p_task, int p_step) {
@@ -117,7 +109,7 @@ void BackgroundProgress::task_step(const String &p_task, int p_step) {
}
if (no_updates) {
- MessageQueue::get_singleton()->push_call(this, "_update");
+ callable_mp(this, &BackgroundProgress::_update).call_deferred();
}
{
@@ -127,7 +119,7 @@ void BackgroundProgress::task_step(const String &p_task, int p_step) {
}
void BackgroundProgress::end_task(const String &p_task) {
- MessageQueue::get_singleton()->push_call(this, "_end_task", p_task);
+ callable_mp(this, &BackgroundProgress::_end_task).call_deferred(p_task);
}
////////////////////////////////////////////////
@@ -242,9 +234,6 @@ void ProgressDialog::_cancel_pressed() {
canceled = true;
}
-void ProgressDialog::_bind_methods() {
-}
-
ProgressDialog::ProgressDialog() {
main = memnew(VBoxContainer);
add_child(main);
diff --git a/editor/progress_dialog.h b/editor/progress_dialog.h
index c75c8fac10..74196a28df 100644
--- a/editor/progress_dialog.h
+++ b/editor/progress_dialog.h
@@ -56,8 +56,6 @@ protected:
void _task_step(const String &p_task, int p_step = -1);
void _end_task(const String &p_task);
- static void _bind_methods();
-
public:
void add_task(const String &p_task, const String &p_label, int p_steps);
void task_step(const String &p_task, int p_step = -1);
@@ -89,9 +87,6 @@ class ProgressDialog : public PopupPanel {
void _cancel_pressed();
bool canceled = false;
-protected:
- static void _bind_methods();
-
public:
static ProgressDialog *get_singleton() { return singleton; }
void add_task(const String &p_task, const String &p_label, int p_steps, bool p_can_cancel = false);
diff --git a/editor/project_converter_3_to_4.cpp b/editor/project_converter_3_to_4.cpp
index 2b0f61c1b0..f8161272f6 100644
--- a/editor/project_converter_3_to_4.cpp
+++ b/editor/project_converter_3_to_4.cpp
@@ -2350,7 +2350,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
line = line.replace("OS.is_window_focused", "get_window().has_focus");
}
if (line.contains("OS.move_window_to_foreground")) {
- line = line.replace("OS.move_window_to_foreground", "get_window().move_to_foreground");
+ line = line.replace("OS.move_window_to_foreground", "get_window().grab_focus");
}
if (line.contains("OS.request_attention")) {
line = line.replace("OS.request_attention", "get_window().request_attention");
diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp
index 1c8d55bd8e..c986ce215a 100644
--- a/editor/project_manager.cpp
+++ b/editor/project_manager.cpp
@@ -103,21 +103,25 @@ void ProjectDialog::_set_message(const String &p_msg, MessageType p_type, InputT
}
}
+static bool is_zip_file(Ref<DirAccess> p_d, const String &p_path) {
+ return p_path.ends_with(".zip") && p_d->file_exists(p_path);
+}
+
String ProjectDialog::_test_path() {
Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ const String base_path = project_path->get_text();
String valid_path, valid_install_path;
- if (d->change_dir(project_path->get_text()) == OK) {
- valid_path = project_path->get_text();
- } else if (d->change_dir(project_path->get_text().strip_edges()) == OK) {
- valid_path = project_path->get_text().strip_edges();
- } else if (project_path->get_text().ends_with(".zip")) {
- if (d->file_exists(project_path->get_text())) {
- valid_path = project_path->get_text();
- }
- } else if (project_path->get_text().strip_edges().ends_with(".zip")) {
- if (d->file_exists(project_path->get_text().strip_edges())) {
- valid_path = project_path->get_text().strip_edges();
- }
+ bool is_zip = false;
+ if (d->change_dir(base_path) == OK) {
+ valid_path = base_path;
+ } else if (is_zip_file(d, base_path)) {
+ valid_path = base_path;
+ is_zip = true;
+ } else if (d->change_dir(base_path.strip_edges()) == OK) {
+ valid_path = base_path.strip_edges();
+ } else if (is_zip_file(d, base_path.strip_edges())) {
+ valid_path = base_path.strip_edges();
+ is_zip = true;
}
if (valid_path.is_empty()) {
@@ -126,7 +130,7 @@ String ProjectDialog::_test_path() {
return "";
}
- if (mode == MODE_IMPORT && valid_path.ends_with(".zip")) {
+ if (mode == MODE_IMPORT && is_zip) {
if (d->change_dir(install_path->get_text()) == OK) {
valid_install_path = install_path->get_text();
} else if (d->change_dir(install_path->get_text().strip_edges()) == OK) {
@@ -134,15 +138,15 @@ String ProjectDialog::_test_path() {
}
if (valid_install_path.is_empty()) {
- _set_message(TTR("The path specified doesn't exist."), MESSAGE_ERROR, INSTALL_PATH);
+ _set_message(TTR("The install path specified doesn't exist."), MESSAGE_ERROR, INSTALL_PATH);
get_ok_button()->set_disabled(true);
return "";
}
}
if (mode == MODE_IMPORT || mode == MODE_RENAME) {
- if (!valid_path.is_empty() && !d->file_exists("project.godot")) {
- if (valid_path.ends_with(".zip")) {
+ if (!d->file_exists("project.godot")) {
+ if (is_zip) {
Ref<FileAccess> io_fa;
zlib_filefunc_def io = zipio_create_io(&io_fa);
@@ -197,7 +201,7 @@ String ProjectDialog::_test_path() {
d->list_dir_end();
if (!is_folder_empty) {
- _set_message(TTR("Please choose an empty folder."), MESSAGE_WARNING, INSTALL_PATH);
+ _set_message(TTR("Please choose an empty install folder."), MESSAGE_WARNING, INSTALL_PATH);
get_ok_button()->set_disabled(true);
return "";
}
@@ -209,8 +213,8 @@ String ProjectDialog::_test_path() {
return "";
}
- } else if (valid_path.ends_with("zip")) {
- _set_message(TTR("This directory already contains a Godot project."), MESSAGE_ERROR, INSTALL_PATH);
+ } else if (is_zip) {
+ _set_message(TTR("The install directory already contains a Godot project."), MESSAGE_ERROR, INSTALL_PATH);
get_ok_button()->set_disabled(true);
return "";
}
@@ -252,7 +256,7 @@ String ProjectDialog::_test_path() {
return valid_path;
}
-void ProjectDialog::_path_text_changed(const String &p_path) {
+void ProjectDialog::_update_path(const String &p_path) {
String sp = _test_path();
if (!sp.is_empty()) {
// If the project name is empty or default, infer the project name from the selected folder name
@@ -277,6 +281,21 @@ void ProjectDialog::_path_text_changed(const String &p_path) {
}
}
+void ProjectDialog::_path_text_changed(const String &p_path) {
+ Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ if (mode == MODE_IMPORT && is_zip_file(d, p_path)) {
+ install_path->set_text(p_path.get_base_dir());
+ install_path_container->show();
+ } else if (mode == MODE_IMPORT && is_zip_file(d, p_path.strip_edges())) {
+ install_path->set_text(p_path.strip_edges().get_base_dir());
+ install_path_container->show();
+ } else {
+ install_path_container->hide();
+ }
+
+ _update_path(p_path.simplify_path());
+}
+
void ProjectDialog::_file_selected(const String &p_path) {
// If not already shown.
show_dialog();
@@ -300,11 +319,11 @@ void ProjectDialog::_file_selected(const String &p_path) {
String sp = p.simplify_path();
project_path->set_text(sp);
- _path_text_changed(sp);
+ _update_path(sp);
if (p.ends_with(".zip")) {
- install_path->call_deferred(SNAME("grab_focus"));
+ callable_mp((Control *)install_path, &Control::grab_focus).call_deferred();
} else {
- get_ok_button()->call_deferred(SNAME("grab_focus"));
+ callable_mp((Control *)get_ok_button(), &Control::grab_focus).call_deferred();
}
}
@@ -314,15 +333,15 @@ void ProjectDialog::_path_selected(const String &p_path) {
String sp = p_path.simplify_path();
project_path->set_text(sp);
- _path_text_changed(sp);
- get_ok_button()->call_deferred(SNAME("grab_focus"));
+ _update_path(sp);
+ callable_mp((Control *)get_ok_button(), &Control::grab_focus).call_deferred();
}
void ProjectDialog::_install_path_selected(const String &p_path) {
String sp = p_path.simplify_path();
install_path->set_text(sp);
- _path_text_changed(sp);
- get_ok_button()->call_deferred(SNAME("grab_focus"));
+ _update_path(sp);
+ callable_mp((Control *)get_ok_button(), &Control::grab_focus).call_deferred();
}
void ProjectDialog::_browse_path() {
@@ -359,7 +378,7 @@ void ProjectDialog::_create_folder() {
d->change_dir(project_name_no_edges);
String dir_str = d->get_current_dir();
project_path->set_text(dir_str);
- _path_text_changed(dir_str);
+ _update_path(dir_str);
created_folder_path = d->get_current_dir();
create_dir->set_disabled(true);
} else {
@@ -638,7 +657,7 @@ void ProjectDialog::cancel_pressed() {
_remove_created_folder();
project_path->clear();
- _path_text_changed("");
+ _update_path("");
project_name->clear();
_text_changed("");
@@ -707,7 +726,7 @@ void ProjectDialog::show_dialog() {
_text_changed(cur_name);
}
- project_name->call_deferred(SNAME("grab_focus"));
+ callable_mp((Control *)project_name, &Control::grab_focus).call_deferred();
create_dir->hide();
@@ -754,8 +773,8 @@ void ProjectDialog::show_dialog() {
install_path_container->hide();
renderer_container->show();
default_files_container->show();
- project_name->call_deferred(SNAME("grab_focus"));
- project_name->call_deferred(SNAME("select_all"));
+ callable_mp((Control *)project_name, &Control::grab_focus).call_deferred();
+ callable_mp(project_name, &LineEdit::select_all).call_deferred();
} else if (mode == MODE_INSTALL) {
set_title(TTR("Install Project:") + " " + zip_title);
@@ -968,7 +987,7 @@ ProjectDialog::ProjectDialog() {
project_name->connect("text_changed", callable_mp(this, &ProjectDialog::_text_changed));
project_path->connect("text_changed", callable_mp(this, &ProjectDialog::_path_text_changed));
- install_path->connect("text_changed", callable_mp(this, &ProjectDialog::_path_text_changed));
+ install_path->connect("text_changed", callable_mp(this, &ProjectDialog::_update_path));
fdialog->connect("dir_selected", callable_mp(this, &ProjectDialog::_path_selected));
fdialog->connect("file_selected", callable_mp(this, &ProjectDialog::_file_selected));
fdialog_install->connect("dir_selected", callable_mp(this, &ProjectDialog::_install_path_selected));
diff --git a/editor/project_manager.h b/editor/project_manager.h
index 8a8b2ff99d..7b091050bd 100644
--- a/editor/project_manager.h
+++ b/editor/project_manager.h
@@ -104,6 +104,7 @@ private:
void _set_message(const String &p_msg, MessageType p_type = MESSAGE_SUCCESS, InputType input_type = PROJECT_PATH);
String _test_path();
+ void _update_path(const String &p_path);
void _path_text_changed(const String &p_path);
void _path_selected(const String &p_path);
void _file_selected(const String &p_path);
diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp
index b7a5521ffd..1b0d791ff1 100644
--- a/editor/project_settings_editor.cpp
+++ b/editor/project_settings_editor.cpp
@@ -556,6 +556,8 @@ void ProjectSettingsEditor::_update_action_map_editor() {
}
void ProjectSettingsEditor::_update_theme() {
+ add_button->set_icon(get_editor_theme_icon(SNAME("Add")));
+ del_button->set_icon(get_editor_theme_icon(SNAME("Remove")));
search_box->set_right_icon(get_editor_theme_icon(SNAME("Search")));
restart_close_button->set_icon(get_editor_theme_icon(SNAME("Close")));
restart_container->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree")));
diff --git a/editor/renames_map_3_to_4.cpp b/editor/renames_map_3_to_4.cpp
index 6323aecfda..ba6095db47 100644
--- a/editor/renames_map_3_to_4.cpp
+++ b/editor/renames_map_3_to_4.cpp
@@ -163,6 +163,7 @@ const char *RenamesMap3To4::gdscript_function_renames[][2] = {
// { "_set_name", "get_tracker_name" }, // XRPositionalTracker -- CameraFeed uses this.
// { "_unhandled_input", "_unhandled_key_input" }, // BaseButton, ViewportContainer -- Breaks Node, FileDialog, SubViewportContainer.
+ // { "add_animation", "add_animation_library" }, // AnimationPlayer -- Breaks SpriteFrames (and isn't a correct conversion).
// { "create_gizmo", "_create_gizmo" }, // EditorNode3DGizmoPlugin -- May be used.
// { "get_dependencies", "_get_dependencies" }, // ResourceFormatLoader -- Breaks ResourceLoader.
// { "get_extents", "get_size" }, // BoxShape, RectangleShape -- Breaks Decal, VoxelGI, GPUParticlesCollisionBox, GPUParticlesCollisionSDF, GPUParticlesCollisionHeightField, GPUParticlesAttractorBox, GPUParticlesAttractorVectorField, FogVolume
@@ -214,8 +215,6 @@ const char *RenamesMap3To4::gdscript_function_renames[][2] = {
{ "_set_current", "set_current" }, // Camera2D
{ "_set_editor_description", "set_editor_description" }, // Node
{ "_toplevel_raise_self", "_top_level_raise_self" }, // CanvasItem
- { "_update_wrap_at", "_update_wrap_at_column" }, // TextEdit
- { "add_animation", "add_animation_library" }, // AnimationPlayer
{ "add_cancel", "add_cancel_button" }, // AcceptDialog
{ "add_central_force", "apply_central_force" }, //RigidBody2D
{ "add_child_below_node", "add_sibling" }, // Node
@@ -644,7 +643,6 @@ const char *RenamesMap3To4::csharp_function_renames[][2] = {
{ "_SetPlaying", "SetPlaying" }, // AnimatedSprite3D
{ "_ToplevelRaiseSelf", "_TopLevelRaiseSelf" }, // CanvasItem
{ "_UpdateWrapAt", "_UpdateWrapAtColumn" }, // TextEdit
- { "AddAnimation", "AddAnimationLibrary" }, // AnimationPlayer
{ "AddCancel", "AddCancelButton" }, // AcceptDialog
{ "AddCentralForce", "AddConstantCentralForce" }, //RigidBody2D
{ "AddChildBelowNode", "AddSibling" }, // Node
diff --git a/editor/scene_create_dialog.cpp b/editor/scene_create_dialog.cpp
index 60ad7e5968..be558101cf 100644
--- a/editor/scene_create_dialog.cpp
+++ b/editor/scene_create_dialog.cpp
@@ -65,7 +65,7 @@ void SceneCreateDialog::config(const String &p_dir) {
directory = p_dir;
root_name_edit->set_text("");
scene_name_edit->set_text("");
- scene_name_edit->call_deferred(SNAME("grab_focus"));
+ callable_mp((Control *)scene_name_edit, &Control::grab_focus).call_deferred();
validation_panel->update();
}
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index 3ea96a66cd..6bad5d1c2e 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -29,13 +29,11 @@
/**************************************************************************/
#include "scene_tree_dock.h"
-#include "node_dock.h"
#include "core/config/project_settings.h"
#include "core/input/input.h"
#include "core/io/resource_saver.h"
#include "core/object/class_db.h"
-#include "core/object/message_queue.h"
#include "core/os/keyboard.h"
#include "editor/debugger/editor_debugger_node.h"
#include "editor/editor_feature_profile.h"
@@ -50,6 +48,7 @@
#include "editor/gui/editor_file_dialog.h"
#include "editor/inspector_dock.h"
#include "editor/multi_node_edit.h"
+#include "editor/node_dock.h"
#include "editor/plugins/animation_player_editor_plugin.h"
#include "editor/plugins/canvas_item_editor_plugin.h"
#include "editor/plugins/node_3d_editor_plugin.h"
@@ -1243,7 +1242,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
if (cant_be_set_unique_names.size()) {
String popup_text = TTR("Unique names already used by another node in the scene:");
popup_text += "\n";
- for (StringName name : cant_be_set_unique_names) {
+ for (const StringName &name : cant_be_set_unique_names) {
popup_text += "\n" + String(name);
}
accept->set_text(popup_text);
@@ -1393,7 +1392,7 @@ void SceneTreeDock::_notification(int p_what) {
node_shortcuts_toggle->set_flat(true);
node_shortcuts_toggle->set_icon(get_editor_theme_icon(SNAME("Favorites")));
node_shortcuts_toggle->set_toggle_mode(true);
- node_shortcuts_toggle->set_tooltip_text(TTR("Switch to Favorite Nodes"));
+ node_shortcuts_toggle->set_tooltip_text(TTR("Toggle the display of favorite nodes."));
node_shortcuts_toggle->set_pressed(EDITOR_GET("_use_favorites_root_selection"));
node_shortcuts_toggle->set_anchors_and_offsets_preset(Control::PRESET_CENTER_RIGHT);
node_shortcuts_toggle->connect("pressed", callable_mp(this, &SceneTreeDock::_update_create_root_dialog));
@@ -2320,18 +2319,121 @@ void SceneTreeDock::_toggle_placeholder_from_selection() {
}
}
-void SceneTreeDock::_toggle_editable_children(Node *p_node) {
- if (p_node) {
- bool editable = !EditorNode::get_singleton()->get_edited_scene()->is_editable_instance(p_node);
- EditorNode::get_singleton()->get_edited_scene()->set_editable_instance(p_node, editable);
- if (editable) {
- p_node->set_scene_instance_load_placeholder(false);
+void SceneTreeDock::_reparent_nodes_to_root(Node *p_root, const Array &p_nodes, Node *p_owner) {
+ List<Node *> nodes;
+ for (int i = 0; i < p_nodes.size(); i++) {
+ Node *node = Object::cast_to<Node>(p_nodes[i]);
+ ERR_FAIL_NULL(node);
+ nodes.push_back(node);
+ }
+
+ for (Node *node : nodes) {
+ node->set_owner(p_owner);
+ List<Node *> owned;
+ node->get_owned_by(p_owner, &owned);
+ String original_name = node->get_name();
+ node->reparent(p_root);
+ node->set_name(original_name);
+
+ for (Node *F : owned) {
+ F->set_owner(p_owner);
+ }
+ }
+}
+
+void SceneTreeDock::_reparent_nodes_to_paths_with_transform_and_name(Node *p_root, const Array &p_nodes, const Array &p_paths, const Array &p_transforms, const Array &p_names, Node *p_owner) {
+ ERR_FAIL_COND(p_nodes.size() != p_paths.size());
+ ERR_FAIL_COND(p_nodes.size() != p_transforms.size());
+ ERR_FAIL_COND(p_nodes.size() != p_names.size());
+
+ for (int i = 0; i < p_nodes.size(); i++) {
+ Node *node = Object::cast_to<Node>(p_nodes[i]);
+ ERR_FAIL_NULL(node);
+ const NodePath &np = p_paths[i];
+ Node *parent_node = p_root->get_node_or_null(np);
+ ERR_FAIL_NULL(parent_node);
+
+ List<Node *> owned;
+ node->get_owned_by(p_owner, &owned);
+ node->reparent(parent_node);
+ node->set_name(p_names[i]);
+ Node3D *node_3d = Object::cast_to<Node3D>(node);
+ if (node_3d) {
+ node_3d->set_transform(p_transforms[i]);
+ } else {
+ Node2D *node_2d = Object::cast_to<Node2D>(node);
+ if (node_2d) {
+ node_2d->set_transform(p_transforms[i]);
+ }
}
- Node3DEditor::get_singleton()->update_all_gizmos(p_node);
+ for (Node *F : owned) {
+ F->set_owner(p_owner);
+ }
+ }
+}
+
+void SceneTreeDock::_toggle_editable_children(Node *p_node) {
+ if (!p_node) {
+ return;
+ }
+
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
+
+ undo_redo->create_action(TTR("Toggle Editable Children"));
+
+ bool editable = !EditorNode::get_singleton()->get_edited_scene()->is_editable_instance(p_node);
+
+ undo_redo->add_undo_method(EditorNode::get_singleton()->get_edited_scene(), "set_editable_instance", p_node, !editable);
+ undo_redo->add_do_method(EditorNode::get_singleton()->get_edited_scene(), "set_editable_instance", p_node, editable);
+
+ if (editable) {
+ bool original_scene_instance_load_placeholder = p_node->get_scene_instance_load_placeholder();
+
+ undo_redo->add_undo_method(p_node, "set_scene_instance_load_placeholder", original_scene_instance_load_placeholder);
+ undo_redo->add_do_method(p_node, "set_scene_instance_load_placeholder", false);
+ } else {
+ List<Node *> owned;
+ p_node->get_owned_by(edited_scene, &owned);
+
+ // Get the original paths, transforms, and names for undo.
+ Array owned_nodes_array;
+ Array paths_array;
+ Array transform_array;
+ Array name_array;
+
+ for (Node *owned_node : owned) {
+ if (owned_node != p_node && owned_node != edited_scene && owned_node->get_owner() == edited_scene && owned_node->get_parent()->get_owner() != edited_scene) {
+ owned_nodes_array.push_back(owned_node);
+ paths_array.push_back(p_node->get_path_to(owned_node->get_parent()));
+ name_array.push_back(owned_node->get_name());
+ Node3D *node_3d = Object::cast_to<Node3D>(owned_node);
+ if (node_3d) {
+ transform_array.push_back(node_3d->get_transform());
+ } else {
+ Node2D *node_2d = Object::cast_to<Node2D>(owned_node);
+ if (node_2d) {
+ transform_array.push_back(node_2d->get_transform());
+ } else {
+ transform_array.push_back(Variant());
+ }
+ }
+ }
+ }
- scene_tree->update_tree();
+ if (!owned_nodes_array.is_empty()) {
+ undo_redo->add_undo_method(this, "_reparent_nodes_to_paths_with_transform_and_name", p_node, owned_nodes_array, paths_array, transform_array, name_array, edited_scene);
+ undo_redo->add_do_method(this, "_reparent_nodes_to_root", p_node, owned_nodes_array, edited_scene);
+ }
}
+
+ undo_redo->add_undo_method(Node3DEditor::get_singleton(), "update_all_gizmos", p_node);
+ undo_redo->add_do_method(Node3DEditor::get_singleton(), "update_all_gizmos", p_node);
+
+ undo_redo->add_undo_method(scene_tree, "update_tree");
+ undo_redo->add_do_method(scene_tree, "update_tree");
+
+ undo_redo->commit_action();
}
void SceneTreeDock::_delete_confirm(bool p_cut) {
@@ -3957,6 +4059,8 @@ void SceneTreeDock::_edit_subresource(int p_idx, const PopupMenu *p_from_menu) {
void SceneTreeDock::_bind_methods() {
ClassDB::bind_method(D_METHOD("_set_owners"), &SceneTreeDock::_set_owners);
+ ClassDB::bind_method(D_METHOD("_reparent_nodes_to_root"), &SceneTreeDock::_reparent_nodes_to_root);
+ ClassDB::bind_method(D_METHOD("_reparent_nodes_to_paths_with_transform_and_name"), &SceneTreeDock::_reparent_nodes_to_paths_with_transform_and_name);
ClassDB::bind_method(D_METHOD("_update_script_button"), &SceneTreeDock::_update_script_button);
@@ -3973,7 +4077,7 @@ SceneTreeDock *SceneTreeDock::singleton = nullptr;
void SceneTreeDock::_update_configuration_warning() {
if (singleton) {
- MessageQueue::get_singleton()->push_callable(callable_mp(singleton->scene_tree, &SceneTreeEditor::update_warning));
+ callable_mp(singleton->scene_tree, &SceneTreeEditor::update_warning).call_deferred();
}
}
diff --git a/editor/scene_tree_dock.h b/editor/scene_tree_dock.h
index 0f1d046e4d..e765ef2a6b 100644
--- a/editor/scene_tree_dock.h
+++ b/editor/scene_tree_dock.h
@@ -223,6 +223,9 @@ class SceneTreeDock : public VBoxContainer {
void _delete_dialog_closed();
void _toggle_editable_children_from_selection();
+
+ void _reparent_nodes_to_root(Node *p_root, const Array &p_nodes, Node *p_owner);
+ void _reparent_nodes_to_paths_with_transform_and_name(Node *p_root, const Array &p_nodes, const Array &p_paths, const Array &p_transforms, const Array &p_names, Node *p_owner);
void _toggle_editable_children(Node *p_node);
void _toggle_placeholder_from_selection();
diff --git a/editor/shader_globals_editor.cpp b/editor/shader_globals_editor.cpp
index ead0eeeae3..46f520df45 100644
--- a/editor/shader_globals_editor.cpp
+++ b/editor/shader_globals_editor.cpp
@@ -105,7 +105,6 @@ class ShaderGlobalsEditorInterface : public Object {
protected:
static void _bind_methods() {
- ClassDB::bind_method("_set_var", &ShaderGlobalsEditorInterface::_set_var);
ClassDB::bind_method("_var_changed", &ShaderGlobalsEditorInterface::_var_changed);
ADD_SIGNAL(MethodInfo("var_changed"));
}
@@ -117,7 +116,7 @@ protected:
return false;
}
- call_deferred("_set_var", p_name, p_value, existing);
+ callable_mp(this, &ShaderGlobalsEditorInterface::_set_var).call_deferred(p_name, p_value, existing);
return true;
}
@@ -345,15 +344,29 @@ static Variant create_var(RS::GlobalShaderParameterType p_type) {
}
}
+String ShaderGlobalsEditor::_check_new_variable_name(const String &p_variable_name) {
+ if (p_variable_name.is_empty()) {
+ return TTR("Name cannot be empty.");
+ }
+
+ if (!p_variable_name.is_valid_identifier()) {
+ return TTR("Name must be a valid identifier.");
+ }
+
+ return "";
+}
+
+void ShaderGlobalsEditor::_variable_name_text_changed(const String &p_variable_name) {
+ const String &warning = _check_new_variable_name(p_variable_name.strip_edges());
+ variable_add->set_tooltip_text(warning);
+ variable_add->set_disabled(!warning.is_empty());
+}
+
void ShaderGlobalsEditor::_variable_added() {
String var = variable_name->get_text().strip_edges();
- if (var.is_empty() || !var.is_valid_identifier()) {
- EditorNode::get_singleton()->show_warning(TTR("Please specify a valid shader uniform identifier name."));
- return;
- }
if (RenderingServer::get_singleton()->global_shader_parameter_get(var).get_type() != Variant::NIL) {
- EditorNode::get_singleton()->show_warning(vformat(TTR("Global shader parameter '%s' already exists'"), var));
+ EditorNode::get_singleton()->show_warning(vformat(TTR("Global shader parameter '%s' already exists."), var));
return;
}
@@ -417,6 +430,10 @@ void ShaderGlobalsEditor::_notification(int p_what) {
}
} break;
+ case NOTIFICATION_THEME_CHANGED: {
+ variable_add->set_icon(get_editor_theme_icon(SNAME("Add")));
+ } break;
+
case NOTIFICATION_PREDELETE: {
inspector->edit(nullptr);
} break;
@@ -432,6 +449,9 @@ ShaderGlobalsEditor::ShaderGlobalsEditor() {
add_menu_hb->add_child(memnew(Label(TTR("Name:"))));
variable_name = memnew(LineEdit);
variable_name->set_h_size_flags(SIZE_EXPAND_FILL);
+ variable_name->set_clear_button_enabled(true);
+ variable_name->connect("text_changed", callable_mp(this, &ShaderGlobalsEditor::_variable_name_text_changed));
+
add_menu_hb->add_child(variable_name);
add_menu_hb->add_child(memnew(Label(TTR("Type:"))));
@@ -444,6 +464,7 @@ ShaderGlobalsEditor::ShaderGlobalsEditor() {
}
variable_add = memnew(Button(TTR("Add")));
+ variable_add->set_disabled(true);
add_menu_hb->add_child(variable_add);
variable_add->connect("pressed", callable_mp(this, &ShaderGlobalsEditor::_variable_added));
diff --git a/editor/shader_globals_editor.h b/editor/shader_globals_editor.h
index 590da342d4..fc50564aae 100644
--- a/editor/shader_globals_editor.h
+++ b/editor/shader_globals_editor.h
@@ -49,6 +49,9 @@ class ShaderGlobalsEditor : public VBoxContainer {
OptionButton *variable_type = nullptr;
Button *variable_add = nullptr;
+ String _check_new_variable_name(const String &p_variable_name);
+
+ void _variable_name_text_changed(const String &p_variable_name);
void _variable_added();
void _variable_deleted(const String &p_variable);
void _changed();
diff --git a/editor/surface_upgrade_tool.cpp b/editor/surface_upgrade_tool.cpp
index 78ebe43c96..d914303b4e 100644
--- a/editor/surface_upgrade_tool.cpp
+++ b/editor/surface_upgrade_tool.cpp
@@ -106,7 +106,7 @@ void SurfaceUpgradeTool::prepare_upgrade() {
EditorSettings::get_singleton()->set_project_metadata("surface_upgrade_tool", "resave_paths", resave_paths);
// Delay to avoid deadlocks, since this dialog can be triggered by loading a scene.
- MessageQueue::get_singleton()->push_callable(callable_mp(EditorNode::get_singleton(), &EditorNode::restart_editor));
+ callable_mp(EditorNode::get_singleton(), &EditorNode::restart_editor).call_deferred();
}
// Ensure that the warnings and popups are skipped.
diff --git a/editor/window_wrapper.cpp b/editor/window_wrapper.cpp
index 2d89e4df46..aec4005ce5 100644
--- a/editor/window_wrapper.cpp
+++ b/editor/window_wrapper.cpp
@@ -74,7 +74,7 @@ class ShortcutBin : public Node {
};
Rect2 WindowWrapper::_get_default_window_rect() const {
- // Assume that the control rect is the desidered one for the window.
+ // Assume that the control rect is the desired one for the window.
return wrapped_control->get_screen_rect();
}
diff --git a/main/main.cpp b/main/main.cpp
index 4dcd92bcff..b50def9cec 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -1615,16 +1615,12 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
}
// Initialize WorkerThreadPool.
- {
+ if (editor || project_manager) {
+ WorkerThreadPool::get_singleton()->init(-1, 0.75);
+ } else {
int worker_threads = GLOBAL_GET("threading/worker_pool/max_threads");
- bool low_priority_use_system_threads = GLOBAL_GET("threading/worker_pool/use_system_threads_for_low_priority_tasks");
- float low_property_ratio = GLOBAL_GET("threading/worker_pool/low_priority_thread_ratio");
-
- if (editor || project_manager) {
- WorkerThreadPool::get_singleton()->init();
- } else {
- WorkerThreadPool::get_singleton()->init(worker_threads, low_priority_use_system_threads, low_property_ratio);
- }
+ float low_priority_ratio = GLOBAL_GET("threading/worker_pool/low_priority_thread_ratio");
+ WorkerThreadPool::get_singleton()->init(worker_threads, low_priority_ratio);
}
#ifdef TOOLS_ENABLED
diff --git a/main/performance.cpp b/main/performance.cpp
index e24a3673b9..b5f1a45b9a 100644
--- a/main/performance.cpp
+++ b/main/performance.cpp
@@ -30,7 +30,6 @@
#include "performance.h"
-#include "core/object/message_queue.h"
#include "core/os/os.h"
#include "core/variant/typed_array.h"
#include "scene/main/node.h"
diff --git a/misc/dist/macos_template.app/Contents/Info.plist b/misc/dist/macos_template.app/Contents/Info.plist
index 40966d2ced..78bb559c0e 100644
--- a/misc/dist/macos_template.app/Contents/Info.plist
+++ b/misc/dist/macos_template.app/Contents/Info.plist
@@ -58,5 +58,6 @@ $usage_descriptions
</dict>
<key>NSHighResolutionCapable</key>
$highres
+$additional_plist_content
</dict>
</plist>
diff --git a/misc/extension_api_validation/4.2-stable.expected b/misc/extension_api_validation/4.2-stable.expected
index 70358c683f..2c52144896 100644
--- a/misc/extension_api_validation/4.2-stable.expected
+++ b/misc/extension_api_validation/4.2-stable.expected
@@ -21,3 +21,33 @@ GH-85393
Validate extension JSON: Error: Field 'classes/PhysicsShapeQueryParameters3D/properties/motion': type changed value in new API, from "Vector2" to "Vector3".
The type was registered wrongly, this was a bug.
+
+
+GH-86687
+--------
+Validate extension JSON: Error: Field 'classes/AnimationMixer/methods/_post_process_key_value/arguments/3': type changed value in new API, from "Object" to "int".
+
+Exposing the pointer was dangerous and it must be changed to avoid crash. Compatibility methods registered.
+
+
+GH-84976
+--------
+Validate extension JSON: Error: Field 'classes/RenderingDevice/enums/FinalAction/values/FINAL_ACTION_CONTINUE': value changed value in new API, from 2.0 to 0.
+Validate extension JSON: Error: Field 'classes/RenderingDevice/enums/FinalAction/values/FINAL_ACTION_MAX': value changed value in new API, from 3.0 to 2.
+Validate extension JSON: Error: Field 'classes/RenderingDevice/enums/InitialAction/values/INITIAL_ACTION_CLEAR': value changed value in new API, from 0.0 to 1.
+Validate extension JSON: Error: Field 'classes/RenderingDevice/enums/InitialAction/values/INITIAL_ACTION_CLEAR_REGION_CONTINUE': value changed value in new API, from 2.0 to 1.
+Validate extension JSON: Error: Field 'classes/RenderingDevice/enums/InitialAction/values/INITIAL_ACTION_CONTINUE': value changed value in new API, from 5.0 to 0.
+Validate extension JSON: Error: Field 'classes/RenderingDevice/enums/InitialAction/values/INITIAL_ACTION_DROP': value changed value in new API, from 4.0 to 2.
+Validate extension JSON: Error: Field 'classes/RenderingDevice/enums/InitialAction/values/INITIAL_ACTION_KEEP': value changed value in new API, from 3.0 to 0.
+Validate extension JSON: Error: Field 'classes/RenderingDevice/enums/InitialAction/values/INITIAL_ACTION_MAX': value changed value in new API, from 6.0 to 3.
+Validate extension JSON: Error: Field 'classes/RenderingDevice/methods/buffer_clear/arguments': size changed value in new API, from 4 to 3.
+Validate extension JSON: Error: Field 'classes/RenderingDevice/methods/buffer_update/arguments': size changed value in new API, from 5 to 4.
+Validate extension JSON: Error: Field 'classes/RenderingDevice/methods/draw_list_begin/arguments': size changed value in new API, from 10 to 9.
+Validate extension JSON: Error: Field 'classes/RenderingDevice/methods/texture_clear/arguments': size changed value in new API, from 7 to 6.
+Validate extension JSON: Error: Field 'classes/RenderingDevice/methods/texture_copy/arguments': size changed value in new API, from 10 to 9.
+Validate extension JSON: Error: Field 'classes/RenderingDevice/methods/texture_resolve_multisample/arguments': size changed value in new API, from 3 to 2.
+Validate extension JSON: Error: Field 'classes/RenderingDevice/methods/texture_update/arguments': size changed value in new API, from 4 to 3.
+
+Barrier arguments have been removed from all relevant functions as they're no longer required.
+Draw and compute list overlap no longer needs to be specified.
+Initial and final actions have been simplified into fewer options.
diff --git a/modules/SCsub b/modules/SCsub
index fcc01e2c1b..7c9946170f 100644
--- a/modules/SCsub
+++ b/modules/SCsub
@@ -7,6 +7,9 @@ Import("env")
env_modules = env.Clone()
+# Allow modules to detect if they are being built as a module.
+env_modules.Append(CPPDEFINES=["GODOT_MODULE"])
+
Export("env_modules")
# Header with MODULE_*_ENABLED defines.
diff --git a/modules/basis_universal/register_types.cpp b/modules/basis_universal/register_types.cpp
index 7c0bc4ac82..f538fc6676 100644
--- a/modules/basis_universal/register_types.cpp
+++ b/modules/basis_universal/register_types.cpp
@@ -221,7 +221,7 @@ static Ref<Image> basis_universal_unpacker_ptr(const uint8_t *p_data, int p_size
imgfmt = Image::FORMAT_DXT5_RA_AS_RG;
} else if (RS::get_singleton()->has_os_feature("etc2")) {
format = basist::transcoder_texture_format::cTFETC2; // get this from renderer
- imgfmt = Image::FORMAT_ETC2_RGBA8;
+ imgfmt = Image::FORMAT_ETC2_RA_AS_RG;
} else {
//opengl most likely, bad for normal maps, nothing to do about this.
format = basist::transcoder_texture_format::cTFRGBA32;
diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp
index 6082b468f7..1de76c60b5 100644
--- a/modules/csg/csg_shape.cpp
+++ b/modules/csg/csg_shape.cpp
@@ -150,13 +150,13 @@ float CSGShape3D::get_snap() const {
void CSGShape3D::_make_dirty(bool p_parent_removing) {
if ((p_parent_removing || is_root_shape()) && !dirty) {
- call_deferred(SNAME("_update_shape")); // Must be deferred; otherwise, is_root_shape() will use the previous parent
+ callable_mp(this, &CSGShape3D::_update_shape).call_deferred(); // Must be deferred; otherwise, is_root_shape() will use the previous parent.
}
if (!is_root_shape()) {
parent_shape->_make_dirty();
} else if (!dirty) {
- call_deferred(SNAME("_update_shape"));
+ callable_mp(this, &CSGShape3D::_update_shape).call_deferred();
}
dirty = true;
diff --git a/modules/gdscript/README.md b/modules/gdscript/README.md
new file mode 100644
index 0000000000..30685e672c
--- /dev/null
+++ b/modules/gdscript/README.md
@@ -0,0 +1,139 @@
+# Basic GDScript module architecture
+This provides some basic information in how GDScript is implemented and integrates with the rest of the engine. You can learn more about GDScript in the [documentation](https://docs.godotengine.org/en/latest/tutorials/scripting/gdscript/index.html). It describes the syntax and user facing systems and concepts, and can be used as a reference for what user expectations are.
+
+
+## General design
+
+GDScript is:
+
+1. A [gradually typed](https://en.wikipedia.org/wiki/Gradual_typing) language. Type hints are optional and help with static analysis and performance. However, typed code must easily interoperate with untyped code.
+2. A tightly designed language. Features are added because they are _needed_, and not because they can be added or are interesting to develop.
+3. Primarily an interpreted scripting language: it is compiled to GDScript byte code and interpreted in a GDScript virtual machine. It is meant to be easy to use and develop gameplay in. It is not meant for CPU-intensive algorithms or data processing, and is not optimized for it. For that, [C#](https://docs.godotengine.org/en/stable/tutorials/scripting/c_sharp/c_sharp_basics.html) or [GDExtension](https://docs.godotengine.org/en/stable/tutorials/scripting/gdextension/what_is_gdextension.html) may be used.
+
+
+## Integration into Godot
+
+GDScript is integrated into Godot as a module. Since modules are optional, this means that Godot may be built without GDScript and work perfectly fine without it!
+
+The GDScript module interfaces with Godot's codebase by inheriting from the engine's scripting-related classes. New languages inherit from [`ScriptLanguage`](/core/object/script_language.h), and are registered in Godot's [`ScriptServer`](/core/object/script_language.h). Scripts, referring to a file containing code, are represented in the engine by the `Script` class. Instances of that script, which are used at runtime when actually executing the code, inherit from [`ScriptInstance`](/core/object/script_instance.h).
+
+To access Godot's internal classes, GDScript uses [`ClassDB`](/core/object/class_db.h). `ClassDB` is where Godot registers classes, methods and properties that it wants exposed to its scripting system. This is how GDScript understands that `Node2D` is a class it can use, and that it has a `get_parent()` method.
+
+[Built-in GDScript methods](https://docs.godotengine.org/en/latest/classes/class_@gdscript.html#methods) are defined and exported by [`GDScriptUtilityFunctions`](gdscript_utility_functions.h), whereas [global scope methods](https://docs.godotengine.org/en/latest/classes/class_%2540globalscope.html) are registered in [`Variant::_register_variant_utility_functions()`](/core/variant/variant_utility.cpp).
+
+
+## Compilation
+
+Scripts can be at different stages of compilation. The process isn't entirely linear, but consists of this general order: tokenizing, parsing, analyzing, and finally compiling. This process is the same for scripts in the editor and scripts in an exported game. Scripts are stored as text files in both cases, and the compilation process must happen in full before the bytecode can be passed to the virtual machine and run.
+
+The main class of the GDScript module is the [`GDScript`](gdscript.h) class, which represents a class defined in GDScript. Each `.gd` file is called a _class file_ because it implicitly defines a class in GDScript, and thus results in an associated `GDScript` object. However, GDScript classes may define [_inner classes_](https://docs.godotengine.org/en/stable/tutorials/scripting/gdscript/gdscript_basics.html#inner-classes), and those are also represented by further `GDScript` objects, even though they are not in files of their own.
+
+The `GDScript` class contains all the information related to the corresponding GDScript class: its name and path, its members like variables, functions, symbols, signals, implicit methods like initializers, etc. This is the main class that the compilation step deals with.
+
+A secondary class is `GDScriptInstance`, defined in the same file, containing _runtime_ information for an instance of a `GDScript`, and is more related to the execution of a script by the virtual machine.
+
+
+### Loading source code
+
+This mostly happens by calling `GDScript::load_source_code()` on a `GDScript` object. Parsing only requires a `String`, so it is entirely possible to parse a script without a `GDScript` object!
+
+
+### Tokenizing (see [`GDScriptTokenizer`](gdscript_tokenizer.h))
+
+Tokenizing is the process of converting the source code `String` into a sequence of tokens, which represent language constructs (such as `for` or `if`), identifiers, literals, etc. This happens almost exclusively during the parsing process, which asks for the next token in order to make sense of the source code. The tokenizer is only used outside of the parsing process in very rare exceptions.
+
+
+### Parsing (see [`GDScriptParser`](gdscript_parser.h))
+
+The parser takes a sequence of tokens and builds [the abstract syntax tree (AST)](https://en.wikipedia.org/wiki/Abstract_syntax_tree) of the GDScript program. The AST is used in the analyzing and compilation steps, and the source code `String` and sequence of tokens are discarded. The AST-building process finds syntax errors in a GDScript program and reports them to the user.
+
+The parser class also defines all the possible nodes of the AST as subtypes of `GDScriptParser::Node`, not to be confused with Godot's scene tree `Node`. For example, `GDScriptParser::IfNode` has two children nodes, one for the code in the `if` block, and one for the code in the `else` block. A `GDScriptParser::FunctionNode` contains children nodes for its name, parameters, return type, body, etc. The parser also defines typechecking data structures like `GDScriptParser::Datatype`.
+
+The parser was [intentionally designed](https://godotengine.org/article/gdscript-progress-report-writing-new-parser/#less-lookahead) with a look-ahead of a single token. This means that the parser only has access to the current token and the previous token (or, if you prefer, the current token and the next token). This parsing limitation ensures that GDScript will remain syntactically simple and accessible, and that the parsing process cannot become overly complex.
+
+
+### Analysis and typechecking (see [`GDScriptAnalyzer`](gdscript_analyzer.h))
+
+The analyzer takes in the AST of a program and verifies that "everything checks out". For example, when analyzing a method call with three parameters, it will check whether the function definition also contains three parameters. If the code is typed, it will check that argument and parameter types are compatible.
+
+There are two types of functions in the analyzer: `reduce` functions and `resolve` functions. Their parameters always include the AST node that they are attempting to reduce or resolve.
+- The `reduce` functions work on GDScript expressions, which return values, and thus their main goal is to populate the `GDScriptParser::Datatype` of the underlying AST node. The datatype is then used to typecheck code that depends on this expression, and gives the compiler necessary information to generate appropriate, safe, and optimized bytecode.
+For example, function calls are handled with `reduce_call()`, which must figure out what function is being called and check that the passed arguments match the function's parameters. The type of the underlying `CallNode` will be the return type of the function.
+Another example is `reduce_identifier()`, which does _a lot_ of work: given the string of its `IdentifierNode`, it must figure out what that identifier refers to. It could be a local variable, class name, global or class function, function parameter, class or superclass member, or any number of other things. It has to check many different places to find this information!
+A secondary goal of the `reduce` functions is to perform [constant folding](https://en.wikipedia.org/wiki/Constant_folding): to determine whether an expression is constant, and if it is, compute its _reduced value_ at this time so it does not need to be computed over and over at runtime!
+- The resolve functions work on AST nodes that represent statements, and don't necessarily have values. Their goal is to do work related to program control flow, resolve their child AST nodes, deal with scoping, etc. One of the simplest examples is `resolve_if()`, which reduces the `if` condition, then resolves the `if` body and `else` body if it exists.
+The `resolve_for()` function does more work than simply resolving its code block. With `for i in range(10)`, for example, it must also declare and type the new variable `i` within the scope of its code block, as well as make sure `range(10)` is iterable, among other things.
+To understand classes and inheritance without introducing cyclic dependency problems that would come from immediate full class code analysis, the analyzer often asks only for class _interfaces_: it needs to know what member variables and methods exist as well as their types, but no more.
+This is done through `resolve_class_interface()`, which populates `ClassNode`'s `Datatype` with that information. It first checks for superclass information with `resolve_class_inheritance()`, then populates its member information by calling `resolve_class_member()` on each member. Since this step is only about the class _interface_, methods are resolved with `resolve_function_signature()`, which gets all relevant typing information without resolving the function body!
+The remaining steps of resolution, including member variable initialization code, method code, etc, can happen at a later time.
+
+In fully untyped code, very little static analysis is possible. For example, the analyzer cannot know whether `my_var.some_member` exists when it does not know the type of `my_var`. Therefore, it cannot emit a warning or error because `some_member` _could_ exist - or it could not. The analyzer must trust the programmer. If an error does occur, it will be at runtime.
+However, GDScript is gradually typed, so all of these analyses must work when parts of the code are typed and others untyped. Static analysis in a gradually typed language is a best-effort situation: suppose there is a typed variable `var x : int`, and an untyped `var y = "some string"`. We can obviously tell this isn't going to work, but the analyzer will accept the assignment `x = y` without warnings or errors: it only knows that `y` is untyped and can therefore be anything, including the `int` that `x` expects. It must once again trust the programmer to have written code that works. In this instance, the code will error at runtime.
+In both these cases, the analyzer handles the uncertainty of untyped code by calling `mark_node_unsafe()` on the respective AST node. This means it didn't have enough information to know whether the code was fully safe or necessarily wrong. Lines with unsafe AST nodes are represented by grey line numbers in the GDScript editor. Green line numbers indicate a line of code without any unsafe nodes.
+
+This analysis step is also where dependencies are introduced and that information stored for use later. If class `A` extends class `B` or contains a member with type `B` from some other script file, then the analyzer will attempt to load that second script. If `B` contains references to `A`, then a _cyclic_ dependency is introduced. This is OK in many cases, but impossible to resolve in others.
+
+Clearly, the analyzer is where a lot of the "magic" happens! It determines what constitutes proper code that can actually be compiled, and provides as many safety guarantees as possible with the typing information it is provided with. The more typed the code, the safer and more optimized it will be!
+
+
+#### Cyclic dependencies and member resolution
+
+Cyclic dependencies from inheritance (`A extends B, B extends A`) are not supported in any programming language. Other cyclic dependencies are supported, such as `A extends B` and `B` uses, contains, or preloads, members of type `A`.
+
+To see why cyclic dependencies are complicated, suppose there is one between classes `A <-> B`. Partially through the analysis of `A`, we will need information about `B`, and therefore trigger its analysis. However, the analysis of `B` will eventually need information from `A`, which is incomplete because we never finished analyzing it. This would result in members not being found when they actually exist!
+
+GDScript supports cyclic dependencies due to a few features of the analyzer:
+
+1. Class interface resolution: when analyzing code of class `A` that depends on some other class `B`, we don't need to resolve the _code_ of `B` (its member initializers, function code, etc). We only need to know what members and methods the class has, as well as their types. These are the only things one class can use to work with, or _interface_ with, another. Because of inheritance, a class's interface depends on its superclass as well, so recursive interface resolution is needed. More details can be found in `GDScriptAnalyzer::resolve_class_interface()`.
+2. Out of order member resolution: the analyzer may not even need an entire class interface to be resolved in order to figure out a specific type! For example, if class `A` contains code that references `B.is_alive`, then the analyzer doesn't need to immediately resolve `B`'s entire interface. It may simply check whether `is_alive` exists in `B`, and reduce it for its type information, on-demand.
+A fundamental cyclic dependency problem occurs when the types of two different member variables are mutually dependent. This is commonly checked by a pattern that declares a temporary datatype with `GDScriptParser::DataType resolving_datatype;`, followed by `resolving_datatype.kind = GDScriptParser::DataType::RESOLVING;`. If the analyzer attempts to resolve a member on-demand that is already tagged as resolving, then a cyclic dependency problem has been found and can be reported.
+
+
+### Compiling (see [`GDScriptCompiler`](gdscript_compiler.h))
+
+Compiling is the final step in making a GDScript executable in the [virtual machine](gdscript_vm.h) (VM). The compiler takes a `GDScript` object and an AST, and uses another class, [`GDScriptByteCodeGenerator`](gdscript_byte_codegen.h), to generate bytecode corresponding to the class. In doing this, it creates the objects that the VM understands how to run, like [`GDScriptFunction`](gdscript_function.h), and completes a few extra tasks needed for compilation, such as populating runtime class member information.
+
+Importantly, the compilation process of a class, specifically the `GDScriptCompiler::_compile_class()` method, _cannot_ depend on information obtained by calling `GDScriptCompiler::_compile_class()` on another class, for the same cyclic dependency reasons explained in the previous section.
+Any information that can only be obtained or populated during the compilation step, when `GDScript` objects become available, must be handled before `GDScriptCompiler::_compile_class()` is called. This process is centralized in `GDScriptCompiler::_prepare_compilation()` which works as the compile-time equivalent of `GDScriptAnalyzer::resolve_class_interface()`: it populates a `GDScript`'s "interface" exclusively with information from the analysis step, and without processing other external classes. This information may then be referenced by other classes without introducing problematic cycles.
+
+The more typing information a GDScript has, the more optimized the compiled bytecode can be. For example, if `my_var` is untyped, the bytecode for `my_var.some_member` will need to go through several layers of indirection to figure out the type of `my_var` at runtime, and from there determine how to obtain `some_member`. This varies depending on whether `my_var` is a dictionary, a script, or a native class. If the type of `my_var` was known at compile time, the bytecode can directly call the type-specific method for obtaining a member.
+Similar optimizations are possible for `my_var.some_func()`. With untyped GDScript, the VM will need to resolve `my_var`'s type at runtime, then, depending on the type, use different methods to resolve the function and call it. When the function is fully resolved during static analysis, native function pointers or GDScript function objects can be compiled into the bytecode and directly called by the VM, removing several layers of indirection.
+
+Typed code is safer code and faster code!
+
+
+## Loading scripts
+
+GDScripts can be loaded in a couple of different ways. The main method, used almost everywhere in the engine, is to load scripts through the `ResourceLoader` singleton. In this way, GDScripts are resources like any others: `ResourceLoader::load()` will simply reroute to `ResourceFormatLoaderGDScript::load()`, found in `gdscript.h/cpp`(gdscript.h). This generates a GDScript object which is compiled and ready to use.
+
+The other method is to manually load the source code, then pass it to a parser, then to an analyzer and then to a compiler. The previous approach does this behind the scenes, alongside some smart caching of scripts and other functionalities. It is used in the [GDScript test runner infrastructure](tests/gdscript_test_runner.h).
+
+
+### Full and shallow scripts
+
+The `ResourceFormatLoaderGDScript::load()` method simply calls `GDScriptCache::get_full_script()`. The [`GDScriptCache`](gdscript_cache.h) is, as it sounds, a cache for GDScripts. Its two main methods, `get_shallow_script()` and `get_full_script()`, get and cache, respectively, scripts that have been merely parsed, and scripts which have been statically analyzed and fully compiled. Another internal class, `GDScriptParserRef`, found in the same file, provides even more granularity over the different steps of the parsing process, and is used extensively in the analyzer.
+
+Shallow, or "just parsed" scripts, provide information such as defined classes, class members, and so forth. This is sufficient for many purposes, like obtaining a class interface or checking whether a member exists on a specific class. Full scripts, on the other hand, have been analyzed and compiled and are ready to use.
+
+The distinction between full and shallow scripts is very important, as shallow scripts cannot create cyclic dependency problems, whereas full scripts can. The analyzer, for example, never asks for full scripts. Choosing when to request a shallow vs a full script is an important but subtle decision.
+
+In practice, full scripts are simply scripts where `GDScript::reload()` has been called. This critical function is the primary way in which scripts get compiled in Godot, and essentially does all the compilation steps covered so far in order. Whenever a script is loaded, or updated and reloaded in Godot, it will end up going through `GDScript::reload()`, except in very rare circumstances like the test runner. It is an excellent place to start reading and understanding the GDScript module!
+
+
+## Special types of scripts
+
+Certain types of GDScripts behave slightly differently. For example, autoloads are loaded with `ResourceLoader::load()` during `Main::start()`, very soon after Godot is launched. Many systems aren't initialized at that time, so error reporting is often significantly reduced and may not even show up in the editor.
+
+Tool scripts, declared with the `@tool` annotation on a GDScript file, run in the editor itself as opposed to just when the game is launched. This leads to a significant increase in complexity, as many things that can be changed in the editor may affect a currently executing tool script.
+
+
+## Other
+
+There are many other classes in the GDScript module. Here is a brief overview of some of them:
+
+- Declaration of GDScript warnings in [`GDScriptWarning`](gdscript_warning.h).
+- [`GDScriptFunction`](gdscript_function.h), which represents an executable GDScript function. The relevant file contains both static as well as runtime information.
+- The [virtual machine](gdscript_vm.cpp) is essentially defined as calling `GDScriptFunction::call()`.
+- Editor-related functions can be found in parts of `GDScriptLanguage`, originally declared in [`gdscript.h`](gdscript.h) but defined in [`gdscript_editor.cpp`](gdscript_editor.cpp). Code highlighting can be found in [`GDScriptSyntaxHighlighter`](editor/gdscript_highlighter.h).
+- GDScript decompilation is found in [`gdscript_disassembler.cpp`](gdscript_disassembler.h), defined as `GDScriptFunction::disassemble()`.
+- Documentation generation from GDScript comments in [`GDScriptDocGen`](editor/gdscript_docgen.h) \ No newline at end of file
diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h
index 3ff8f757cf..7b0e2136ed 100644
--- a/modules/gdscript/gdscript.h
+++ b/modules/gdscript/gdscript.h
@@ -540,7 +540,7 @@ public:
virtual void get_string_delimiters(List<String> *p_delimiters) const override;
virtual bool is_using_templates() override;
virtual Ref<Script> make_template(const String &p_template, const String &p_class_name, const String &p_base_class_name) const override;
- virtual Vector<ScriptTemplate> get_built_in_templates(StringName p_object) override;
+ virtual Vector<ScriptTemplate> get_built_in_templates(const StringName &p_object) override;
virtual bool validate(const String &p_script, const String &p_path = "", List<String> *r_functions = nullptr, List<ScriptLanguage::ScriptError> *r_errors = nullptr, List<ScriptLanguage::Warning> *r_warnings = nullptr, HashSet<int> *r_safe_lines = nullptr) const override;
virtual Script *create_script() const override;
#ifndef DISABLE_DEPRECATED
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index b245df15a6..3fd5b3f519 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -845,7 +845,7 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type
return result;
}
-void GDScriptAnalyzer::resolve_class_member(GDScriptParser::ClassNode *p_class, StringName p_name, const GDScriptParser::Node *p_source) {
+void GDScriptAnalyzer::resolve_class_member(GDScriptParser::ClassNode *p_class, const StringName &p_name, const GDScriptParser::Node *p_source) {
ERR_FAIL_COND(!p_class->has_member(p_name));
resolve_class_member(p_class, p_class->members_indices[p_name], p_source);
}
diff --git a/modules/gdscript/gdscript_analyzer.h b/modules/gdscript/gdscript_analyzer.h
index ec155706df..4ed476a3df 100644
--- a/modules/gdscript/gdscript_analyzer.h
+++ b/modules/gdscript/gdscript_analyzer.h
@@ -62,7 +62,7 @@ class GDScriptAnalyzer {
void decide_suite_type(GDScriptParser::Node *p_suite, GDScriptParser::Node *p_statement);
void resolve_annotation(GDScriptParser::AnnotationNode *p_annotation);
- void resolve_class_member(GDScriptParser::ClassNode *p_class, StringName p_name, const GDScriptParser::Node *p_source = nullptr);
+ void resolve_class_member(GDScriptParser::ClassNode *p_class, const StringName &p_name, const GDScriptParser::Node *p_source = nullptr);
void resolve_class_member(GDScriptParser::ClassNode *p_class, int p_index, const GDScriptParser::Node *p_source = nullptr);
void resolve_class_interface(GDScriptParser::ClassNode *p_class, const GDScriptParser::Node *p_source = nullptr);
void resolve_class_interface(GDScriptParser::ClassNode *p_class, bool p_recursive);
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index b8fd5de4fd..9ad2ba1914 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -104,7 +104,7 @@ Ref<Script> GDScriptLanguage::make_template(const String &p_template, const Stri
return scr;
}
-Vector<ScriptLanguage::ScriptTemplate> GDScriptLanguage::get_built_in_templates(StringName p_object) {
+Vector<ScriptLanguage::ScriptTemplate> GDScriptLanguage::get_built_in_templates(const StringName &p_object) {
Vector<ScriptLanguage::ScriptTemplate> templates;
#ifdef TOOLS_ENABLED
for (int i = 0; i < TEMPLATES_ARRAY_SIZE; i++) {
@@ -537,7 +537,7 @@ struct GDScriptCompletionIdentifier {
// appears. For example, if you are completing code in a class that inherits Node2D, a property found on Node2D
// will have a "better" (lower) location "score" than a property that is found on CanvasItem.
-static int _get_property_location(StringName p_class, StringName p_property) {
+static int _get_property_location(const StringName &p_class, const StringName &p_property) {
if (!ClassDB::has_property(p_class, p_property)) {
return ScriptLanguage::LOCATION_OTHER;
}
@@ -552,7 +552,7 @@ static int _get_property_location(StringName p_class, StringName p_property) {
return depth | ScriptLanguage::LOCATION_PARENT_MASK;
}
-static int _get_constant_location(StringName p_class, StringName p_constant) {
+static int _get_constant_location(const StringName &p_class, const StringName &p_constant) {
if (!ClassDB::has_integer_constant(p_class, p_constant)) {
return ScriptLanguage::LOCATION_OTHER;
}
@@ -567,7 +567,7 @@ static int _get_constant_location(StringName p_class, StringName p_constant) {
return depth | ScriptLanguage::LOCATION_PARENT_MASK;
}
-static int _get_signal_location(StringName p_class, StringName p_signal) {
+static int _get_signal_location(const StringName &p_class, const StringName &p_signal) {
if (!ClassDB::has_signal(p_class, p_signal)) {
return ScriptLanguage::LOCATION_OTHER;
}
@@ -582,7 +582,7 @@ static int _get_signal_location(StringName p_class, StringName p_signal) {
return depth | ScriptLanguage::LOCATION_PARENT_MASK;
}
-static int _get_method_location(StringName p_class, StringName p_method) {
+static int _get_method_location(const StringName &p_class, const StringName &p_method) {
if (!ClassDB::has_method(p_class, p_method)) {
return ScriptLanguage::LOCATION_OTHER;
}
@@ -597,7 +597,7 @@ static int _get_method_location(StringName p_class, StringName p_method) {
return depth | ScriptLanguage::LOCATION_PARENT_MASK;
}
-static int _get_enum_constant_location(StringName p_class, StringName p_enum_constant) {
+static int _get_enum_constant_location(const StringName &p_class, const StringName &p_enum_constant) {
if (!ClassDB::get_integer_constant_enum(p_class, p_enum_constant)) {
return ScriptLanguage::LOCATION_OTHER;
}
diff --git a/modules/gdscript/language_server/gdscript_text_document.cpp b/modules/gdscript/language_server/gdscript_text_document.cpp
index 0b1371851b..95b3be2811 100644
--- a/modules/gdscript/language_server/gdscript_text_document.cpp
+++ b/modules/gdscript/language_server/gdscript_text_document.cpp
@@ -456,7 +456,7 @@ Variant GDScriptTextDocument::declaration(const Dictionary &p_params) {
id = "class_global:" + symbol->native_class + ":" + symbol->name;
break;
}
- call_deferred(SNAME("show_native_symbol_in_editor"), id);
+ callable_mp(this, &GDScriptTextDocument::show_native_symbol_in_editor).call_deferred(id);
} else {
notify_client_show_symbol(symbol);
}
diff --git a/modules/gdscript/tests/gdscript_test_runner.cpp b/modules/gdscript/tests/gdscript_test_runner.cpp
index 361ca276bb..4d93a6fc18 100644
--- a/modules/gdscript/tests/gdscript_test_runner.cpp
+++ b/modules/gdscript/tests/gdscript_test_runner.cpp
@@ -266,7 +266,7 @@ bool GDScriptTestRunner::make_tests_for_dir(const String &p_dir) {
while (!next.is_empty()) {
if (dir->current_is_dir()) {
- if (next == "." || next == "..") {
+ if (next == "." || next == ".." || next == "completion" || next == "lsp") {
next = dir->get_next();
continue;
}
diff --git a/modules/gdscript/tests/scripts/completion/get_node/get_node_member_annotated.cfg b/modules/gdscript/tests/scripts/completion/get_node/get_node_member_annotated.cfg
new file mode 100644
index 0000000000..4edee46039
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/get_node_member_annotated.cfg
@@ -0,0 +1,4 @@
+[output]
+expected=[
+ {"display": "autoplay"},
+]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/get_node_member_annotated.gd b/modules/gdscript/tests/scripts/completion/get_node/get_node_member_annotated.gd
new file mode 100644
index 0000000000..d41bbb970c
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/get_node_member_annotated.gd
@@ -0,0 +1,6 @@
+extends Node
+
+var test: AnimationPlayer = $AnimationPlayer
+
+func _ready():
+ test.➡
diff --git a/modules/gdscript/tests/scripts/lsp/class.notest.gd b/modules/gdscript/tests/scripts/lsp/class.gd
index 53d0b14d72..53d0b14d72 100644
--- a/modules/gdscript/tests/scripts/lsp/class.notest.gd
+++ b/modules/gdscript/tests/scripts/lsp/class.gd
diff --git a/modules/gdscript/tests/scripts/lsp/enums.notest.gd b/modules/gdscript/tests/scripts/lsp/enums.gd
index 38b9ec110a..38b9ec110a 100644
--- a/modules/gdscript/tests/scripts/lsp/enums.notest.gd
+++ b/modules/gdscript/tests/scripts/lsp/enums.gd
diff --git a/modules/gdscript/tests/scripts/lsp/indentation.notest.gd b/modules/gdscript/tests/scripts/lsp/indentation.gd
index c25d73a719..c25d73a719 100644
--- a/modules/gdscript/tests/scripts/lsp/indentation.notest.gd
+++ b/modules/gdscript/tests/scripts/lsp/indentation.gd
diff --git a/modules/gdscript/tests/scripts/lsp/lambdas.notest.gd b/modules/gdscript/tests/scripts/lsp/lambdas.gd
index 6f5d468eea..6f5d468eea 100644
--- a/modules/gdscript/tests/scripts/lsp/lambdas.notest.gd
+++ b/modules/gdscript/tests/scripts/lsp/lambdas.gd
diff --git a/modules/gdscript/tests/scripts/lsp/local_variables.notest.gd b/modules/gdscript/tests/scripts/lsp/local_variables.gd
index b6cc46f7da..b6cc46f7da 100644
--- a/modules/gdscript/tests/scripts/lsp/local_variables.notest.gd
+++ b/modules/gdscript/tests/scripts/lsp/local_variables.gd
diff --git a/modules/gdscript/tests/scripts/lsp/properties.notest.gd b/modules/gdscript/tests/scripts/lsp/properties.gd
index 8dfaee2e5b..8dfaee2e5b 100644
--- a/modules/gdscript/tests/scripts/lsp/properties.notest.gd
+++ b/modules/gdscript/tests/scripts/lsp/properties.gd
diff --git a/modules/gdscript/tests/scripts/lsp/scopes.notest.gd b/modules/gdscript/tests/scripts/lsp/scopes.gd
index 20b8fb9bd7..20b8fb9bd7 100644
--- a/modules/gdscript/tests/scripts/lsp/scopes.notest.gd
+++ b/modules/gdscript/tests/scripts/lsp/scopes.gd
diff --git a/modules/gdscript/tests/scripts/lsp/shadowing_initializer.notest.gd b/modules/gdscript/tests/scripts/lsp/shadowing_initializer.gd
index 338000fa0e..338000fa0e 100644
--- a/modules/gdscript/tests/scripts/lsp/shadowing_initializer.notest.gd
+++ b/modules/gdscript/tests/scripts/lsp/shadowing_initializer.gd
diff --git a/modules/gdscript/tests/scripts/project.godot b/modules/gdscript/tests/scripts/project.godot
index 25b49c0abd..c500ef443d 100644
--- a/modules/gdscript/tests/scripts/project.godot
+++ b/modules/gdscript/tests/scripts/project.godot
@@ -3,7 +3,7 @@
; It also helps for opening Godot to edit the scripts, but please don't
; let the editor changes be saved.
-config_version=4
+config_version=5
[application]
diff --git a/modules/gdscript/tests/test_completion.h b/modules/gdscript/tests/test_completion.h
new file mode 100644
index 0000000000..abc34bd4bf
--- /dev/null
+++ b/modules/gdscript/tests/test_completion.h
@@ -0,0 +1,199 @@
+/**************************************************************************/
+/* test_completion.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef TEST_COMPLETION_H
+#define TEST_COMPLETION_H
+
+#ifdef TOOLS_ENABLED
+
+#include "core/io/config_file.h"
+#include "core/io/dir_access.h"
+#include "core/io/file_access.h"
+#include "core/object/script_language.h"
+#include "core/variant/dictionary.h"
+#include "core/variant/variant.h"
+#include "gdscript_test_runner.h"
+#include "modules/modules_enabled.gen.h" // For mono.
+#include "scene/resources/packed_scene.h"
+
+#include "../gdscript.h"
+#include "tests/test_macros.h"
+
+#include "editor/editor_settings.h"
+#include "scene/theme/theme_db.h"
+
+namespace GDScriptTests {
+
+static bool match_option(const Dictionary p_expected, const ScriptLanguage::CodeCompletionOption p_got) {
+ if (p_expected.get("display", p_got.display) != p_got.display) {
+ return false;
+ }
+ if (p_expected.get("insert_text", p_got.insert_text) != p_got.insert_text) {
+ return false;
+ }
+ if (p_expected.get("kind", p_got.kind) != Variant(p_got.kind)) {
+ return false;
+ }
+ if (p_expected.get("location", p_got.location) != Variant(p_got.location)) {
+ return false;
+ }
+ return true;
+}
+
+static void to_dict_list(Variant p_variant, List<Dictionary> &p_list) {
+ ERR_FAIL_COND(!p_variant.is_array());
+
+ Array arr = p_variant;
+ for (int i = 0; i < arr.size(); i++) {
+ if (arr[i].get_type() == Variant::DICTIONARY) {
+ p_list.push_back(arr[i]);
+ }
+ }
+}
+
+static void test_directory(const String &p_dir) {
+ Error err = OK;
+ Ref<DirAccess> dir = DirAccess::open(p_dir, &err);
+
+ if (err != OK) {
+ FAIL("Invalid test directory.");
+ return;
+ }
+
+ String path = dir->get_current_dir();
+
+ dir->list_dir_begin();
+ String next = dir->get_next();
+
+ while (!next.is_empty()) {
+ if (dir->current_is_dir()) {
+ if (next == "." || next == "..") {
+ next = dir->get_next();
+ continue;
+ }
+ test_directory(path.path_join(next));
+ } else if (next.ends_with(".gd") && !next.ends_with(".notest.gd")) {
+ Ref<FileAccess> acc = FileAccess::open(path.path_join(next), FileAccess::READ, &err);
+
+ if (err != OK) {
+ next = dir->get_next();
+ continue;
+ }
+
+ String code = acc->get_as_utf8_string();
+ // For ease of reading ➡ (0x27A1) acts as sentinel char instead of 0xFFFF in the files.
+ code = code.replace_first(String::chr(0x27A1), String::chr(0xFFFF));
+ // Require pointer sentinel char in scripts.
+ CHECK(code.find_char(0xFFFF) != -1);
+
+ ConfigFile conf;
+ if (conf.load(path.path_join(next.get_basename() + ".cfg")) != OK) {
+ FAIL("No config file found.");
+ }
+
+#ifndef MODULE_MONO_ENABLED
+ if (conf.get_value("input", "cs", false)) {
+ next = dir->get_next();
+ continue;
+ }
+#endif
+
+ EditorSettings::get_singleton()->set_setting("text_editor/completion/use_single_quotes", conf.get_value("input", "use_single_quotes", false));
+
+ List<Dictionary> include;
+ to_dict_list(conf.get_value("result", "include", Array()), include);
+
+ List<Dictionary> exclude;
+ to_dict_list(conf.get_value("result", "exclude", Array()), exclude);
+
+ List<ScriptLanguage::CodeCompletionOption> options;
+ String call_hint;
+ bool forced;
+
+ Node *owner = nullptr;
+ if (dir->file_exists(next.get_basename() + ".tscn")) {
+ String project_path = "res://completion";
+ Ref<PackedScene> scene = ResourceLoader::load(project_path.path_join(next.get_basename() + ".tscn"), "PackedScene");
+ if (scene.is_valid()) {
+ owner = scene->instantiate();
+ }
+ }
+
+ GDScriptLanguage::get_singleton()->complete_code(code, path.path_join(next), owner, &options, forced, call_hint);
+ String contains_excluded;
+ for (ScriptLanguage::CodeCompletionOption &option : options) {
+ for (const Dictionary &E : exclude) {
+ if (match_option(E, option)) {
+ contains_excluded = option.display;
+ break;
+ }
+ }
+ if (!contains_excluded.is_empty()) {
+ break;
+ }
+
+ for (const Dictionary &E : include) {
+ if (match_option(E, option)) {
+ include.erase(E);
+ break;
+ }
+ }
+ }
+ CHECK_MESSAGE(contains_excluded.is_empty(), "Autocompletion suggests illegal option '", contains_excluded, "' for '", path.path_join(next), "'.");
+ CHECK(include.is_empty());
+
+ String expected_call_hint = conf.get_value("result", "call_hint", call_hint);
+ bool expected_forced = conf.get_value("result", "forced", forced);
+
+ CHECK(expected_call_hint == call_hint);
+ CHECK(expected_forced == forced);
+
+ if (owner) {
+ memdelete(owner);
+ }
+ }
+ next = dir->get_next();
+ }
+}
+
+TEST_SUITE("[Modules][GDScript][Completion]") {
+ TEST_CASE("[Editor] Check suggestion list") {
+ // Set all editor settings that code completion relies on.
+ EditorSettings::get_singleton()->set_setting("text_editor/completion/use_single_quotes", false);
+ init_language("modules/gdscript/tests/scripts");
+
+ test_directory("modules/gdscript/tests/scripts/completion");
+ }
+}
+} // namespace GDScriptTests
+
+#endif
+
+#endif // TEST_COMPLETION_H
diff --git a/modules/gdscript/tests/test_lsp.h b/modules/gdscript/tests/test_lsp.h
index e57df00e2d..6192272f80 100644
--- a/modules/gdscript/tests/test_lsp.h
+++ b/modules/gdscript/tests/test_lsp.h
@@ -76,7 +76,7 @@ namespace GDScriptTests {
// LSP GDScript test scripts are located inside project of other GDScript tests:
// Cannot reset `ProjectSettings` (singleton) -> Cannot load another workspace and resources in there.
// -> Reuse GDScript test project. LSP specific scripts are then placed inside `lsp` folder.
-// Access via `res://lsp/my_script.notest.gd`.
+// Access via `res://lsp/my_script.gd`.
const String root = "modules/gdscript/tests/scripts/";
/*
@@ -394,7 +394,7 @@ func f():
Ref<GDScriptWorkspace> workspace = GDScriptLanguageProtocol::get_singleton()->get_workspace();
{
- String path = "res://lsp/local_variables.notest.gd";
+ String path = "res://lsp/local_variables.gd";
assert_no_errors_in(path);
String uri = workspace->get_file_uri(path);
Vector<InlineTestData> all_test_data = read_tests(path);
@@ -413,7 +413,7 @@ func f():
}
SUBCASE("Can get correct ranges for indented variables") {
- String path = "res://lsp/indentation.notest.gd";
+ String path = "res://lsp/indentation.gd";
assert_no_errors_in(path);
String uri = workspace->get_file_uri(path);
Vector<InlineTestData> all_test_data = read_tests(path);
@@ -421,7 +421,7 @@ func f():
}
SUBCASE("Can get correct ranges for scopes") {
- String path = "res://lsp/scopes.notest.gd";
+ String path = "res://lsp/scopes.gd";
assert_no_errors_in(path);
String uri = workspace->get_file_uri(path);
Vector<InlineTestData> all_test_data = read_tests(path);
@@ -429,7 +429,7 @@ func f():
}
SUBCASE("Can get correct ranges for lambda") {
- String path = "res://lsp/lambdas.notest.gd";
+ String path = "res://lsp/lambdas.gd";
assert_no_errors_in(path);
String uri = workspace->get_file_uri(path);
Vector<InlineTestData> all_test_data = read_tests(path);
@@ -437,7 +437,7 @@ func f():
}
SUBCASE("Can get correct ranges for inner class") {
- String path = "res://lsp/class.notest.gd";
+ String path = "res://lsp/class.gd";
assert_no_errors_in(path);
String uri = workspace->get_file_uri(path);
Vector<InlineTestData> all_test_data = read_tests(path);
@@ -445,7 +445,7 @@ func f():
}
SUBCASE("Can get correct ranges for inner class") {
- String path = "res://lsp/enums.notest.gd";
+ String path = "res://lsp/enums.gd";
assert_no_errors_in(path);
String uri = workspace->get_file_uri(path);
Vector<InlineTestData> all_test_data = read_tests(path);
@@ -453,7 +453,7 @@ func f():
}
SUBCASE("Can get correct ranges for shadowing & shadowed variables") {
- String path = "res://lsp/shadowing_initializer.notest.gd";
+ String path = "res://lsp/shadowing_initializer.gd";
assert_no_errors_in(path);
String uri = workspace->get_file_uri(path);
Vector<InlineTestData> all_test_data = read_tests(path);
@@ -461,7 +461,7 @@ func f():
}
SUBCASE("Can get correct ranges for properties and getter/setter") {
- String path = "res://lsp/properties.notest.gd";
+ String path = "res://lsp/properties.gd";
assert_no_errors_in(path);
String uri = workspace->get_file_uri(path);
Vector<InlineTestData> all_test_data = read_tests(path);
diff --git a/modules/glslang/config.py b/modules/glslang/config.py
index d22f9454ed..1169776a73 100644
--- a/modules/glslang/config.py
+++ b/modules/glslang/config.py
@@ -1,5 +1,7 @@
def can_build(env, platform):
- return True
+ # glslang is only needed when Vulkan or Direct3D 12-based renderers are available,
+ # as OpenGL doesn't use glslang.
+ return env["vulkan"] or env["d3d12"]
def configure(env):
diff --git a/modules/gltf/editor/editor_scene_importer_blend.cpp b/modules/gltf/editor/editor_scene_importer_blend.cpp
index 9587604e56..24dab16b90 100644
--- a/modules/gltf/editor/editor_scene_importer_blend.cpp
+++ b/modules/gltf/editor/editor_scene_importer_blend.cpp
@@ -134,7 +134,19 @@ Node *EditorSceneFormatImporterBlend::import_scene(const String &p_path, uint32_
// Get global paths for source and sink.
// Escape paths to be valid Python strings to embed in the script.
- const String source_global = ProjectSettings::get_singleton()->globalize_path(p_path).c_escape();
+ String source_global = ProjectSettings::get_singleton()->globalize_path(p_path);
+
+#ifdef WINDOWS_ENABLED
+ // On Windows, when using a network share path, the above will return a path starting with "//"
+ // which once handed to Blender will be treated like a relative path. So we need to replace the
+ // first two characters with "\\" to make it absolute again.
+ if (source_global.is_network_share_path()) {
+ source_global = "\\\\" + source_global.substr(2);
+ }
+#endif
+
+ source_global = source_global.c_escape();
+
const String blend_basename = p_path.get_file().get_basename();
const String sink = ProjectSettings::get_singleton()->get_imported_files_path().path_join(
vformat("%s-%s.gltf", blend_basename, p_path.md5_text()));
diff --git a/modules/gltf/extensions/gltf_document_extension.h b/modules/gltf/extensions/gltf_document_extension.h
index 512b7aba91..761dff725c 100644
--- a/modules/gltf/extensions/gltf_document_extension.h
+++ b/modules/gltf/extensions/gltf_document_extension.h
@@ -33,6 +33,8 @@
#include "../gltf_state.h"
+#include "scene/3d/node_3d.h"
+
class GLTFDocumentExtension : public Resource {
GDCLASS(GLTFDocumentExtension, Resource);
diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp
index 0b491ce1d6..8a60df85cf 100644
--- a/modules/gltf/gltf_document.cpp
+++ b/modules/gltf/gltf_document.cpp
@@ -5049,7 +5049,7 @@ Error GLTFDocument::_serialize_animations(Ref<GLTFState> p_state) {
AnimationPlayer *animation_player = p_state->animation_players[player_i];
List<StringName> animations;
animation_player->get_animation_list(&animations);
- for (StringName animation_name : animations) {
+ for (const StringName &animation_name : animations) {
_convert_animation(p_state, animation_player, animation_name);
}
}
@@ -6288,6 +6288,9 @@ void GLTFDocument::_import_animation(Ref<GLTFState> p_state, AnimationPlayer *p_
animation->add_track(Animation::TYPE_POSITION_3D);
animation->track_set_path(position_idx, transform_node_path);
animation->track_set_imported(position_idx, true); //helps merging later
+ if (track.position_track.interpolation == GLTFAnimation::INTERP_STEP) {
+ animation->track_set_interpolation_type(position_idx, Animation::InterpolationType::INTERPOLATION_NEAREST);
+ }
base_idx++;
}
}
@@ -6310,6 +6313,9 @@ void GLTFDocument::_import_animation(Ref<GLTFState> p_state, AnimationPlayer *p_
animation->add_track(Animation::TYPE_ROTATION_3D);
animation->track_set_path(rotation_idx, transform_node_path);
animation->track_set_imported(rotation_idx, true); //helps merging later
+ if (track.rotation_track.interpolation == GLTFAnimation::INTERP_STEP) {
+ animation->track_set_interpolation_type(rotation_idx, Animation::InterpolationType::INTERPOLATION_NEAREST);
+ }
base_idx++;
}
}
@@ -6332,6 +6338,9 @@ void GLTFDocument::_import_animation(Ref<GLTFState> p_state, AnimationPlayer *p_
animation->add_track(Animation::TYPE_SCALE_3D);
animation->track_set_path(scale_idx, transform_node_path);
animation->track_set_imported(scale_idx, true); //helps merging later
+ if (track.scale_track.interpolation == GLTFAnimation::INTERP_STEP) {
+ animation->track_set_interpolation_type(scale_idx, Animation::InterpolationType::INTERPOLATION_NEAREST);
+ }
base_idx++;
}
}
diff --git a/modules/gltf/structures/gltf_skeleton.h b/modules/gltf/structures/gltf_skeleton.h
index 72a4a06e5c..b2f2dcb2a2 100644
--- a/modules/gltf/structures/gltf_skeleton.h
+++ b/modules/gltf/structures/gltf_skeleton.h
@@ -82,7 +82,7 @@ public:
//RBMap<int32_t, GLTFNodeIndex> get_godot_bone_node() {
// return this->godot_bone_node;
//}
- //void set_godot_bone_node(RBMap<int32_t, GLTFNodeIndex> p_godot_bone_node) {
+ //void set_godot_bone_node(const RBMap<int32_t, GLTFNodeIndex> &p_godot_bone_node) {
// this->godot_bone_node = p_godot_bone_node;
//}
Dictionary get_godot_bone_node();
diff --git a/modules/gltf/structures/gltf_skin.h b/modules/gltf/structures/gltf_skin.h
index 164cabfe12..cd5f2d9ca2 100644
--- a/modules/gltf/structures/gltf_skin.h
+++ b/modules/gltf/structures/gltf_skin.h
@@ -34,6 +34,7 @@
#include "../gltf_defines.h"
#include "core/io/resource.h"
+#include "scene/resources/skin.h"
template <typename T>
class TypedArray;
diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp
index 6f493f48e3..e3475b3959 100644
--- a/modules/gridmap/grid_map.cpp
+++ b/modules/gridmap/grid_map.cpp
@@ -32,7 +32,6 @@
#include "core/core_string_names.h"
#include "core/io/marshalls.h"
-#include "core/object/message_queue.h"
#include "scene/3d/light_3d.h"
#include "scene/resources/mesh_library.h"
#include "scene/resources/physics_material.h"
@@ -975,7 +974,7 @@ void GridMap::_queue_octants_dirty() {
return;
}
- MessageQueue::get_singleton()->push_call(this, "_update_octants_callback");
+ callable_mp(this, &GridMap::_update_octants_callback).call_deferred();
awaiting_update = true;
}
@@ -1082,7 +1081,6 @@ void GridMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("local_to_map", "local_position"), &GridMap::local_to_map);
ClassDB::bind_method(D_METHOD("map_to_local", "map_position"), &GridMap::map_to_local);
- ClassDB::bind_method(D_METHOD("_update_octants_callback"), &GridMap::_update_octants_callback);
#ifndef DISABLE_DEPRECATED
ClassDB::bind_method(D_METHOD("resource_changed", "resource"), &GridMap::resource_changed);
#endif
diff --git a/modules/lightmapper_rd/lightmapper_rd.cpp b/modules/lightmapper_rd/lightmapper_rd.cpp
index 5c2c3f96de..4746ffb79b 100644
--- a/modules/lightmapper_rd/lightmapper_rd.cpp
+++ b/modules/lightmapper_rd/lightmapper_rd.cpp
@@ -703,7 +703,7 @@ void LightmapperRD::_raster_geometry(RenderingDevice *rd, Size2i atlas_size, int
raster_push_constant.uv_offset[0] = -0.5f / float(atlas_size.x);
raster_push_constant.uv_offset[1] = -0.5f / float(atlas_size.y);
- RD::DrawListID draw_list = rd->draw_list_begin(framebuffers[i], RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors);
+ RD::DrawListID draw_list = rd->draw_list_begin(framebuffers[i], RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors);
//draw opaque
rd->draw_list_bind_render_pipeline(draw_list, raster_pipeline);
rd->draw_list_bind_uniform_set(draw_list, raster_base_uniform, 0);
@@ -1863,7 +1863,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
seams_push_constant.slice = uint32_t(i * subslices + k);
seams_push_constant.debug = debug;
- RD::DrawListID draw_list = rd->draw_list_begin(framebuffers[i], RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors);
+ RD::DrawListID draw_list = rd->draw_list_begin(framebuffers[i], RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors);
rd->draw_list_bind_uniform_set(draw_list, raster_base_uniform, 0);
rd->draw_list_bind_uniform_set(draw_list, blendseams_raster_uniform, 1);
diff --git a/modules/lightmapper_rd/lm_compute.glsl b/modules/lightmapper_rd/lm_compute.glsl
index a2a480043a..21e039396d 100644
--- a/modules/lightmapper_rd/lm_compute.glsl
+++ b/modules/lightmapper_rd/lm_compute.glsl
@@ -264,7 +264,16 @@ uint trace_ray(vec3 p_from, vec3 p_to, bool p_any_hit, out float r_distance, out
break;
}
- bvec3 mask = lessThanEqual(side.xyz, min(side.yzx, side.zxy));
+ // There should be only one axis updated at a time for DDA to work properly.
+ bvec3 mask = bvec3(true, false, false);
+ float m = side.x;
+ if (side.y < m) {
+ m = side.y;
+ mask = bvec3(false, true, false);
+ }
+ if (side.z < m) {
+ mask = bvec3(false, false, true);
+ }
side += vec3(mask) * delta;
icell += ivec3(vec3(mask)) * step;
iters++;
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index 175e213579..ac6977504a 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -371,7 +371,7 @@ Ref<Script> CSharpLanguage::make_template(const String &p_template, const String
return scr;
}
-Vector<ScriptLanguage::ScriptTemplate> CSharpLanguage::get_built_in_templates(StringName p_object) {
+Vector<ScriptLanguage::ScriptTemplate> CSharpLanguage::get_built_in_templates(const StringName &p_object) {
Vector<ScriptLanguage::ScriptTemplate> templates;
#ifdef TOOLS_ENABLED
for (int i = 0; i < TEMPLATES_ARRAY_SIZE; i++) {
@@ -2365,6 +2365,8 @@ void CSharpScript::update_script_class_info(Ref<CSharpScript> p_script) {
MethodInfo mi;
mi.name = name;
+ mi.return_val = PropertyInfo::from_dict(method_info_dict["return_val"]);
+
Array params = method_info_dict["params"];
for (int j = 0; j < params.size(); j++) {
diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h
index 401f5c62e5..41e8d63be1 100644
--- a/modules/mono/csharp_script.h
+++ b/modules/mono/csharp_script.h
@@ -423,7 +423,7 @@ public:
void get_string_delimiters(List<String> *p_delimiters) const override;
bool is_using_templates() override;
virtual Ref<Script> make_template(const String &p_template, const String &p_class_name, const String &p_base_class_name) const override;
- virtual Vector<ScriptTemplate> get_built_in_templates(StringName p_object) override;
+ virtual Vector<ScriptTemplate> get_built_in_templates(const StringName &p_object) override;
/* TODO */ bool validate(const String &p_script, const String &p_path, List<String> *r_functions,
List<ScriptLanguage::ScriptError> *r_errors = nullptr, List<ScriptLanguage::Warning> *r_warnings = nullptr, HashSet<int> *r_safe_lines = nullptr) const override {
return true;
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs
index 147ef852b3..1113629fef 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs
@@ -146,7 +146,7 @@ namespace Godot.SourceGenerators
DiagnosticSeverity.Error,
isEnabledByDefault: true,
description,
- helpLinkUri: string.Format(_helpLinkFormat, "GD1003")),
+ helpLinkUri: string.Format(_helpLinkFormat, "GD0103")),
location,
location?.SourceTree?.FilePath));
}
diff --git a/modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotTools.BuildLogger.csproj b/modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotTools.BuildLogger.csproj
index 9e36497b06..d0972f1eae 100644
--- a/modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotTools.BuildLogger.csproj
+++ b/modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotTools.BuildLogger.csproj
@@ -1,8 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<ProjectGuid>{6CE9A984-37B1-4F8A-8FE9-609F05F071B3}</ProjectGuid>
- <TargetFramework>netstandard2.0</TargetFramework>
- <LangVersion>7.2</LangVersion>
+ <TargetFramework>net6.0</TargetFramework>
+ <LangVersion>10</LangVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Build.Framework" Version="15.1.548" ExcludeAssets="runtime" />
diff --git a/modules/mono/editor/GodotTools/GodotTools.IdeMessaging.CLI/GodotTools.IdeMessaging.CLI.csproj b/modules/mono/editor/GodotTools/GodotTools.IdeMessaging.CLI/GodotTools.IdeMessaging.CLI.csproj
index d2132115f3..eb6ac8bafc 100644
--- a/modules/mono/editor/GodotTools/GodotTools.IdeMessaging.CLI/GodotTools.IdeMessaging.CLI.csproj
+++ b/modules/mono/editor/GodotTools/GodotTools.IdeMessaging.CLI/GodotTools.IdeMessaging.CLI.csproj
@@ -2,13 +2,10 @@
<PropertyGroup>
<ProjectGuid>{B06C2951-C8E3-4F28-80B2-717CF327EB19}</ProjectGuid>
<OutputType>Exe</OutputType>
- <TargetFramework>net472</TargetFramework>
- <LangVersion>7.2</LangVersion>
+ <TargetFramework>net6.0</TargetFramework>
+ <LangVersion>10</LangVersion>
</PropertyGroup>
<ItemGroup>
- <Reference Include="System" />
- </ItemGroup>
- <ItemGroup>
<ProjectReference Include="..\GodotTools.IdeMessaging\GodotTools.IdeMessaging.csproj" />
</ItemGroup>
<ItemGroup>
diff --git a/modules/mono/editor/GodotTools/GodotTools.OpenVisualStudio/GodotTools.OpenVisualStudio.csproj b/modules/mono/editor/GodotTools/GodotTools.OpenVisualStudio/GodotTools.OpenVisualStudio.csproj
index c05096bdcc..22778f21cb 100644
--- a/modules/mono/editor/GodotTools/GodotTools.OpenVisualStudio/GodotTools.OpenVisualStudio.csproj
+++ b/modules/mono/editor/GodotTools/GodotTools.OpenVisualStudio/GodotTools.OpenVisualStudio.csproj
@@ -1,12 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
- <PropertyGroup>
- <ProjectGuid>{EAFFF236-FA96-4A4D-BD23-0E51EF988277}</ProjectGuid>
- <OutputType>Exe</OutputType>
- <TargetFramework>net472</TargetFramework>
- <LangVersion>7.2</LangVersion>
- </PropertyGroup>
- <ItemGroup>
- <PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.0" PrivateAssets="All" />
- <PackageReference Include="EnvDTE" Version="8.0.2" />
- </ItemGroup>
+ <PropertyGroup>
+ <ProjectGuid>{EAFFF236-FA96-4A4D-BD23-0E51EF988277}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <TargetFramework>net6.0-windows</TargetFramework>
+ <LangVersion>10</LangVersion>
+ </PropertyGroup>
+ <PropertyGroup Condition="Exists('$(SolutionDir)/../../../../bin/GodotSharp/Api/Debug/GodotSharp.dll') And ('$(GodotPlatform)' == 'windows' Or ('$(GodotPlatform)' == '' And '$(OS)' == 'Windows_NT'))">
+ <OutputPath>$(SolutionDir)/../../../../bin/GodotSharp/Tools</OutputPath>
+ <AppendTargetFrameworkToOutputPath>False</AppendTargetFrameworkToOutputPath>
+ </PropertyGroup>
+ <ItemGroup>
+ <PackageReference Include="EnvDTE" Version="17.8.37221" />
+ </ItemGroup>
</Project>
diff --git a/modules/mono/editor/GodotTools/GodotTools.OpenVisualStudio/Program.cs b/modules/mono/editor/GodotTools/GodotTools.OpenVisualStudio/Program.cs
index cc0deb6cc0..8e8eaa79b8 100644
--- a/modules/mono/editor/GodotTools/GodotTools.OpenVisualStudio/Program.cs
+++ b/modules/mono/editor/GodotTools/GodotTools.OpenVisualStudio/Program.cs
@@ -129,7 +129,7 @@ namespace GodotTools.OpenVisualStudio
{
var mainWindow = dte.MainWindow;
mainWindow.Activate();
- SetForegroundWindow(new IntPtr(mainWindow.HWnd));
+ SetForegroundWindow(mainWindow.HWnd);
MessageFilter.Revoke();
}
diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj b/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj
index 56ae37b4dd..b5567ea3c7 100644
--- a/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj
+++ b/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj
@@ -28,7 +28,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="JetBrains.Annotations" Version="2019.1.3.0" ExcludeAssets="runtime" PrivateAssets="all" />
- <PackageReference Include="JetBrains.Rider.PathLocator" Version="1.0.4" />
+ <PackageReference Include="JetBrains.Rider.PathLocator" Version="1.0.8" />
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.0" PrivateAssets="All" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<Reference Include="GodotSharp">
@@ -49,7 +49,5 @@
<ProjectReference Include="..\GodotTools.IdeMessaging\GodotTools.IdeMessaging.csproj" />
<ProjectReference Include="..\GodotTools.ProjectEditor\GodotTools.ProjectEditor.csproj" />
<ProjectReference Include="..\GodotTools.Core\GodotTools.Core.csproj" />
- <!-- Include it if this is an SCons build targeting Windows, or if it's not an SCons build but we're on Windows -->
- <ProjectReference Include="..\GodotTools.OpenVisualStudio\GodotTools.OpenVisualStudio.csproj" Condition=" '$(GodotPlatform)' == 'windows' Or ( '$(GodotPlatform)' == '' And '$(OS)' == 'Windows_NT' ) " />
</ItemGroup>
</Project>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs
index a087b20308..968afa664b 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs
@@ -662,6 +662,19 @@ namespace Godot.Bridge
methodInfo.Add("name", method.Name);
+ var returnVal = new Collections.Dictionary()
+ {
+ { "name", method.ReturnVal.Name },
+ { "type", (int)method.ReturnVal.Type },
+ { "usage", (int)method.ReturnVal.Usage }
+ };
+ if (method.ReturnVal.ClassName != null)
+ {
+ returnVal["class_name"] = method.ReturnVal.ClassName;
+ }
+
+ methodInfo.Add("return_val", returnVal);
+
var methodParams = new Collections.Array();
if (method.Arguments != null)
diff --git a/modules/multiplayer/scene_replication_interface.cpp b/modules/multiplayer/scene_replication_interface.cpp
index c95e4ff9c9..31307e648d 100644
--- a/modules/multiplayer/scene_replication_interface.cpp
+++ b/modules/multiplayer/scene_replication_interface.cpp
@@ -707,7 +707,7 @@ MultiplayerSynchronizer *SceneReplicationInterface::_find_synchronizer(int p_pee
return sync;
}
-void SceneReplicationInterface::_send_delta(int p_peer, const HashSet<ObjectID> p_synchronizers, uint64_t p_usec, const HashMap<ObjectID, uint64_t> p_last_watch_usecs) {
+void SceneReplicationInterface::_send_delta(int p_peer, const HashSet<ObjectID> &p_synchronizers, uint64_t p_usec, const HashMap<ObjectID, uint64_t> &p_last_watch_usecs) {
MAKE_ROOM(/* header */ 1 + /* element */ 4 + 8 + 4 + delta_mtu);
uint8_t *ptr = packet_cache.ptrw();
ptr[0] = SceneMultiplayer::NETWORK_COMMAND_SYNC | (1 << SceneMultiplayer::CMD_FLAG_0_SHIFT);
@@ -799,7 +799,7 @@ Error SceneReplicationInterface::on_delta_receive(int p_from, const uint8_t *p_b
return OK;
}
-void SceneReplicationInterface::_send_sync(int p_peer, const HashSet<ObjectID> p_synchronizers, uint16_t p_sync_net_time, uint64_t p_usec) {
+void SceneReplicationInterface::_send_sync(int p_peer, const HashSet<ObjectID> &p_synchronizers, uint16_t p_sync_net_time, uint64_t p_usec) {
MAKE_ROOM(/* header */ 3 + /* element */ 4 + 4 + sync_mtu);
uint8_t *ptr = packet_cache.ptrw();
ptr[0] = SceneMultiplayer::NETWORK_COMMAND_SYNC;
diff --git a/modules/multiplayer/scene_replication_interface.h b/modules/multiplayer/scene_replication_interface.h
index 3b3ec6a9ef..31211bb108 100644
--- a/modules/multiplayer/scene_replication_interface.h
+++ b/modules/multiplayer/scene_replication_interface.h
@@ -101,8 +101,8 @@ private:
bool _verify_synchronizer(int p_peer, MultiplayerSynchronizer *p_sync, uint32_t &r_net_id);
MultiplayerSynchronizer *_find_synchronizer(int p_peer, uint32_t p_net_ida);
- void _send_sync(int p_peer, const HashSet<ObjectID> p_synchronizers, uint16_t p_sync_net_time, uint64_t p_usec);
- void _send_delta(int p_peer, const HashSet<ObjectID> p_synchronizers, uint64_t p_usec, const HashMap<ObjectID, uint64_t> p_last_watch_usecs);
+ void _send_sync(int p_peer, const HashSet<ObjectID> &p_synchronizers, uint16_t p_sync_net_time, uint64_t p_usec);
+ void _send_delta(int p_peer, const HashSet<ObjectID> &p_synchronizers, uint64_t p_usec, const HashMap<ObjectID, uint64_t> &p_last_watch_usecs);
Error _make_spawn_packet(Node *p_node, MultiplayerSpawner *p_spawner, int &r_len);
Error _make_despawn_packet(Node *p_node, int &r_len);
Error _send_raw(const uint8_t *p_buffer, int p_size, int p_peer, bool p_reliable);
diff --git a/modules/navigation/nav_agent.cpp b/modules/navigation/nav_agent.cpp
index cb219ac6c0..5a87ff6c4b 100644
--- a/modules/navigation/nav_agent.cpp
+++ b/modules/navigation/nav_agent.cpp
@@ -326,7 +326,7 @@ const Dictionary NavAgent::get_avoidance_data() const {
_avoidance_data["new_velocity"] = Vector3(rvo_agent_3d.newVelocity_.x(), rvo_agent_3d.newVelocity_.y(), rvo_agent_3d.newVelocity_.z());
_avoidance_data["velocity"] = Vector3(rvo_agent_3d.velocity_.x(), rvo_agent_3d.velocity_.y(), rvo_agent_3d.velocity_.z());
_avoidance_data["position"] = Vector3(rvo_agent_3d.position_.x(), rvo_agent_3d.position_.y(), rvo_agent_3d.position_.z());
- _avoidance_data["prefered_velocity"] = Vector3(rvo_agent_3d.prefVelocity_.x(), rvo_agent_3d.prefVelocity_.y(), rvo_agent_3d.prefVelocity_.z());
+ _avoidance_data["preferred_velocity"] = Vector3(rvo_agent_3d.prefVelocity_.x(), rvo_agent_3d.prefVelocity_.y(), rvo_agent_3d.prefVelocity_.z());
_avoidance_data["radius"] = float(rvo_agent_3d.radius_);
_avoidance_data["time_horizon_agents"] = float(rvo_agent_3d.timeHorizon_);
_avoidance_data["time_horizon_obstacles"] = 0.0;
@@ -341,7 +341,7 @@ const Dictionary NavAgent::get_avoidance_data() const {
_avoidance_data["new_velocity"] = Vector3(rvo_agent_2d.newVelocity_.x(), 0.0, rvo_agent_2d.newVelocity_.y());
_avoidance_data["velocity"] = Vector3(rvo_agent_2d.velocity_.x(), 0.0, rvo_agent_2d.velocity_.y());
_avoidance_data["position"] = Vector3(rvo_agent_2d.position_.x(), 0.0, rvo_agent_2d.position_.y());
- _avoidance_data["prefered_velocity"] = Vector3(rvo_agent_2d.prefVelocity_.x(), 0.0, rvo_agent_2d.prefVelocity_.y());
+ _avoidance_data["preferred_velocity"] = Vector3(rvo_agent_2d.prefVelocity_.x(), 0.0, rvo_agent_2d.prefVelocity_.y());
_avoidance_data["radius"] = float(rvo_agent_2d.radius_);
_avoidance_data["time_horizon_agents"] = float(rvo_agent_2d.timeHorizon_);
_avoidance_data["time_horizon_obstacles"] = float(rvo_agent_2d.timeHorizonObst_);
diff --git a/modules/noise/noise_texture_2d.cpp b/modules/noise/noise_texture_2d.cpp
index 1b0c5cb9e3..0443fec4a0 100644
--- a/modules/noise/noise_texture_2d.cpp
+++ b/modules/noise/noise_texture_2d.cpp
@@ -49,10 +49,6 @@ NoiseTexture2D::~NoiseTexture2D() {
}
void NoiseTexture2D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_update_texture"), &NoiseTexture2D::_update_texture);
- ClassDB::bind_method(D_METHOD("_generate_texture"), &NoiseTexture2D::_generate_texture);
- ClassDB::bind_method(D_METHOD("_thread_done", "image"), &NoiseTexture2D::_thread_done);
-
ClassDB::bind_method(D_METHOD("set_width", "width"), &NoiseTexture2D::set_width);
ClassDB::bind_method(D_METHOD("set_height", "height"), &NoiseTexture2D::set_height);
@@ -138,7 +134,7 @@ void NoiseTexture2D::_thread_done(const Ref<Image> &p_image) {
void NoiseTexture2D::_thread_function(void *p_ud) {
NoiseTexture2D *tex = static_cast<NoiseTexture2D *>(p_ud);
- tex->call_deferred(SNAME("_thread_done"), tex->_generate_texture());
+ callable_mp(tex, &NoiseTexture2D::_thread_done).call_deferred(tex->_generate_texture());
}
void NoiseTexture2D::_queue_update() {
@@ -147,7 +143,7 @@ void NoiseTexture2D::_queue_update() {
}
update_queued = true;
- call_deferred(SNAME("_update_texture"));
+ callable_mp(this, &NoiseTexture2D::_update_texture).call_deferred();
}
Ref<Image> NoiseTexture2D::_generate_texture() {
diff --git a/modules/noise/noise_texture_3d.cpp b/modules/noise/noise_texture_3d.cpp
index 33e257a5c2..f2e01b0612 100644
--- a/modules/noise/noise_texture_3d.cpp
+++ b/modules/noise/noise_texture_3d.cpp
@@ -49,10 +49,6 @@ NoiseTexture3D::~NoiseTexture3D() {
}
void NoiseTexture3D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_update_texture"), &NoiseTexture3D::_update_texture);
- ClassDB::bind_method(D_METHOD("_generate_texture"), &NoiseTexture3D::_generate_texture);
- ClassDB::bind_method(D_METHOD("_thread_done", "image"), &NoiseTexture3D::_thread_done);
-
ClassDB::bind_method(D_METHOD("set_width", "width"), &NoiseTexture3D::set_width);
ClassDB::bind_method(D_METHOD("set_height", "height"), &NoiseTexture3D::set_height);
ClassDB::bind_method(D_METHOD("set_depth", "depth"), &NoiseTexture3D::set_depth);
@@ -126,7 +122,7 @@ void NoiseTexture3D::_thread_done(const TypedArray<Image> &p_data) {
void NoiseTexture3D::_thread_function(void *p_ud) {
NoiseTexture3D *tex = static_cast<NoiseTexture3D *>(p_ud);
- tex->call_deferred(SNAME("_thread_done"), tex->_generate_texture());
+ callable_mp(tex, &NoiseTexture3D::_thread_done).call_deferred(tex->_generate_texture());
}
void NoiseTexture3D::_queue_update() {
@@ -135,7 +131,7 @@ void NoiseTexture3D::_queue_update() {
}
update_queued = true;
- call_deferred(SNAME("_update_texture"));
+ callable_mp(this, &NoiseTexture3D::_update_texture).call_deferred();
}
TypedArray<Image> NoiseTexture3D::_generate_texture() {
diff --git a/modules/openxr/SCsub b/modules/openxr/SCsub
index c64b6de78c..4cf810f905 100644
--- a/modules/openxr/SCsub
+++ b/modules/openxr/SCsub
@@ -120,6 +120,7 @@ env_openxr.add_source_files(module_obj, "extensions/openxr_wmr_controller_extens
env_openxr.add_source_files(module_obj, "extensions/openxr_ml2_controller_extension.cpp")
env_openxr.add_source_files(module_obj, "extensions/openxr_extension_wrapper_extension.cpp")
env_openxr.add_source_files(module_obj, "extensions/openxr_api_extension.cpp")
+env_openxr.add_source_files(module_obj, "extensions/openxr_meta_controller_extension.cpp")
env.modules_sources += module_obj
diff --git a/modules/openxr/action_map/openxr_interaction_profile_metadata.cpp b/modules/openxr/action_map/openxr_interaction_profile_metadata.cpp
index df607b0def..75cfb095bb 100644
--- a/modules/openxr/action_map/openxr_interaction_profile_metadata.cpp
+++ b/modules/openxr/action_map/openxr_interaction_profile_metadata.cpp
@@ -360,6 +360,9 @@ void OpenXRInteractionProfileMetadata::_register_core_metadata() {
register_io_path("/interaction_profiles/oculus/touch_controller", "Thumbstick click", "/user/hand/right", "/user/hand/right/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
register_io_path("/interaction_profiles/oculus/touch_controller", "Thumbstick touch", "/user/hand/right", "/user/hand/right/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/oculus/touch_controller", "Thumbrest touch", "/user/hand/left", "/user/hand/left/input/thumbrest/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/oculus/touch_controller", "Thumbrest touch", "/user/hand/right", "/user/hand/right/input/thumbrest/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
register_io_path("/interaction_profiles/oculus/touch_controller", "Haptic output", "/user/hand/left", "/user/hand/left/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
register_io_path("/interaction_profiles/oculus/touch_controller", "Haptic output", "/user/hand/right", "/user/hand/right/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
diff --git a/modules/openxr/doc_classes/OpenXRHand.xml b/modules/openxr/doc_classes/OpenXRHand.xml
index cc7766507f..eb7decd30d 100644
--- a/modules/openxr/doc_classes/OpenXRHand.xml
+++ b/modules/openxr/doc_classes/OpenXRHand.xml
@@ -1,10 +1,12 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="OpenXRHand" inherits="Node3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
- Node supporting finger tracking in OpenXR.
+ Node supporting hand and finger tracking in OpenXR.
</brief_description>
<description>
- This node enables OpenXR's hand tracking functionality. The node should be a child node of an [XROrigin3D] node, tracking will update its position to where the player's actual hand is positioned. This node also updates the skeleton of a properly skinned hand model. The hand mesh should be a child node of this node.
+ This node enables OpenXR's hand tracking functionality. The node should be a child node of an [XROrigin3D] node, tracking will update its position to the player's tracked hand Palm joint location (the center of the middle finger's metacarpal bone). This node also updates the skeleton of a properly skinned hand or avatar model.
+ If the skeleton is a hand (one of the hand bones is the root node of the skeleton), then the skeleton will be placed relative to the hand palm location and the hand mesh and skeleton should be children of the OpenXRHand node.
+ If the hand bones are part of a full skeleton, then the root of the hand will keep its location with the assumption that IK is used to position the hand and arm.
</description>
<tutorials>
</tutorials>
@@ -18,6 +20,9 @@
<member name="motion_range" type="int" setter="set_motion_range" getter="get_motion_range" enum="OpenXRHand.MotionRange" default="0">
Set the motion range (if supported) limiting the hand motion.
</member>
+ <member name="skeleton_rig" type="int" setter="set_skeleton_rig" getter="get_skeleton_rig" enum="OpenXRHand.SkeletonRig" default="0">
+ Set the type of skeleton rig the [member hand_skeleton] is compliant with.
+ </member>
</members>
<constants>
<constant name="HAND_LEFT" value="0" enum="Hands">
@@ -38,5 +43,14 @@
<constant name="MOTION_RANGE_MAX" value="2" enum="MotionRange">
Maximum supported motion ranges.
</constant>
+ <constant name="SKELETON_RIG_OPENXR" value="0" enum="SkeletonRig">
+ An OpenXR compliant skeleton.
+ </constant>
+ <constant name="SKELETON_RIG_HUMANOID" value="1" enum="SkeletonRig">
+ A [SkeletonProfileHumanoid] compliant skeleton.
+ </constant>
+ <constant name="SKELETON_RIG_MAX" value="2" enum="SkeletonRig">
+ Maximum supported hands.
+ </constant>
</constants>
</class>
diff --git a/modules/openxr/doc_classes/OpenXRInterface.xml b/modules/openxr/doc_classes/OpenXRInterface.xml
index 666d20d7e7..caaaeb90ff 100644
--- a/modules/openxr/doc_classes/OpenXRInterface.xml
+++ b/modules/openxr/doc_classes/OpenXRInterface.xml
@@ -71,6 +71,13 @@
If handtracking is enabled, returns the rotation of a joint ([param joint]) of a hand ([param hand]) as provided by OpenXR.
</description>
</method>
+ <method name="get_hand_tracking_source" qualifiers="const">
+ <return type="int" enum="OpenXRInterface.HandTrackedSource" />
+ <param index="0" name="hand" type="int" enum="OpenXRInterface.Hand" />
+ <description>
+ If handtracking is enabled and hand tracking source is supported, gets the source of the hand tracking data for [param hand].
+ </description>
+ </method>
<method name="get_motion_range" qualifiers="const">
<return type="int" enum="OpenXRInterface.HandMotionRange" />
<param index="0" name="hand" type="int" enum="OpenXRInterface.Hand" />
@@ -177,10 +184,25 @@
Maximum value for the hand enum.
</constant>
<constant name="HAND_MOTION_RANGE_UNOBSTRUCTED" value="0" enum="HandMotionRange">
+ Full hand range, if user closes their hands, we make a full fist.
</constant>
<constant name="HAND_MOTION_RANGE_CONFORM_TO_CONTROLLER" value="1" enum="HandMotionRange">
+ Conform to controller, if user closes their hands, the tracked data conforms to the shape of the controller.
</constant>
<constant name="HAND_MOTION_RANGE_MAX" value="2" enum="HandMotionRange">
+ Maximum value for the motion range enum.
+ </constant>
+ <constant name="HAND_TRACKED_SOURCE_UNKNOWN" value="0" enum="HandTrackedSource">
+ The source of hand tracking data is unknown (the extension is likely unsupported).
+ </constant>
+ <constant name="HAND_TRACKED_SOURCE_UNOBSTRUCTED" value="1" enum="HandTrackedSource">
+ The source of hand tracking is unobstructed, this means that an accurate method of hand tracking is used, e.g. optical hand tracking, data gloves, etc.
+ </constant>
+ <constant name="HAND_TRACKED_SOURCE_CONTROLLER" value="2" enum="HandTrackedSource">
+ The source of hand tracking is a controller, bone positions are inferred from controller inputs.
+ </constant>
+ <constant name="HAND_TRACKED_SOURCE_MAX" value="3" enum="HandTrackedSource">
+ Maximum value for the hand tracked source enum.
</constant>
<constant name="HAND_JOINT_PALM" value="0" enum="HandJoints">
Palm joint.
diff --git a/modules/openxr/editor/openxr_action_map_editor.cpp b/modules/openxr/editor/openxr_action_map_editor.cpp
index 64e07eff21..dacf284046 100644
--- a/modules/openxr/editor/openxr_action_map_editor.cpp
+++ b/modules/openxr/editor/openxr_action_map_editor.cpp
@@ -43,7 +43,6 @@ void OpenXRActionMapEditor::_bind_methods() {
ClassDB::bind_method("_add_interaction_profile_editor", &OpenXRActionMapEditor::_add_interaction_profile_editor);
ClassDB::bind_method(D_METHOD("_add_action_set", "name"), &OpenXRActionMapEditor::_add_action_set);
- ClassDB::bind_method(D_METHOD("_set_focus_on_action_set", "action_set"), &OpenXRActionMapEditor::_set_focus_on_action_set);
ClassDB::bind_method(D_METHOD("_remove_action_set", "name"), &OpenXRActionMapEditor::_remove_action_set);
ClassDB::bind_method(D_METHOD("_do_add_action_set_editor", "action_set_editor"), &OpenXRActionMapEditor::_do_add_action_set_editor);
@@ -175,7 +174,7 @@ void OpenXRActionMapEditor::_on_add_action_set() {
// Make sure our action set is the current tab
tabs->set_current_tab(0);
- call_deferred("_set_focus_on_action_set", new_action_set_editor);
+ callable_mp(this, &OpenXRActionMapEditor::_set_focus_on_action_set).call_deferred(new_action_set_editor);
}
void OpenXRActionMapEditor::_set_focus_on_action_set(OpenXRActionSetEditor *p_action_set_editor) {
diff --git a/modules/openxr/extensions/openxr_hand_tracking_extension.cpp b/modules/openxr/extensions/openxr_hand_tracking_extension.cpp
index 0d667b56c6..04fc4bf890 100644
--- a/modules/openxr/extensions/openxr_hand_tracking_extension.cpp
+++ b/modules/openxr/extensions/openxr_hand_tracking_extension.cpp
@@ -60,6 +60,7 @@ HashMap<String, bool *> OpenXRHandTrackingExtension::get_requested_extensions()
request_extensions[XR_EXT_HAND_TRACKING_EXTENSION_NAME] = &hand_tracking_ext;
request_extensions[XR_EXT_HAND_JOINTS_MOTION_RANGE_EXTENSION_NAME] = &hand_motion_range_ext;
+ request_extensions[XR_EXT_HAND_TRACKING_DATA_SOURCE_EXTENSION_NAME] = &hand_tracking_source_ext;
return request_extensions;
}
@@ -137,20 +138,32 @@ void OpenXRHandTrackingExtension::on_process() {
for (int i = 0; i < OPENXR_MAX_TRACKED_HANDS; i++) {
if (hand_trackers[i].hand_tracker == XR_NULL_HANDLE) {
- XrHandTrackerCreateInfoEXT createInfo = {
+ void *next_pointer = nullptr;
+
+ // Originally not all XR runtimes supported hand tracking data sourced both from controllers and normal hand tracking.
+ // With this extension we can indicate we accept input from both sources so hand tracking data is consistently provided
+ // on runtimes that support this.
+ XrHandTrackingDataSourceEXT data_sources[2] = { XR_HAND_TRACKING_DATA_SOURCE_UNOBSTRUCTED_EXT, XR_HAND_TRACKING_DATA_SOURCE_CONTROLLER_EXT };
+ XrHandTrackingDataSourceInfoEXT data_source_info = { XR_TYPE_HAND_TRACKING_DATA_SOURCE_INFO_EXT, next_pointer, 2, data_sources };
+ if (hand_tracking_source_ext) {
+ // If supported include this info
+ next_pointer = &data_source_info;
+ }
+
+ XrHandTrackerCreateInfoEXT create_info = {
XR_TYPE_HAND_TRACKER_CREATE_INFO_EXT, // type
- nullptr, // next
+ next_pointer, // next
i == 0 ? XR_HAND_LEFT_EXT : XR_HAND_RIGHT_EXT, // hand
XR_HAND_JOINT_SET_DEFAULT_EXT, // handJointSet
};
- result = xrCreateHandTrackerEXT(OpenXRAPI::get_singleton()->get_session(), &createInfo, &hand_trackers[i].hand_tracker);
+ result = xrCreateHandTrackerEXT(OpenXRAPI::get_singleton()->get_session(), &create_info, &hand_trackers[i].hand_tracker);
if (XR_FAILED(result)) {
// not successful? then we do nothing.
print_line("OpenXR: Failed to obtain hand tracking information [", OpenXRAPI::get_singleton()->get_error_string(result), "]");
hand_trackers[i].is_initialized = false;
} else {
- void *next_pointer = nullptr;
+ next_pointer = nullptr;
hand_trackers[i].velocities.type = XR_TYPE_HAND_JOINT_VELOCITIES_EXT;
hand_trackers[i].velocities.next = next_pointer;
@@ -158,6 +171,14 @@ void OpenXRHandTrackingExtension::on_process() {
hand_trackers[i].velocities.jointVelocities = hand_trackers[i].joint_velocities;
next_pointer = &hand_trackers[i].velocities;
+ if (hand_tracking_source_ext) {
+ hand_trackers[i].data_source.type = XR_TYPE_HAND_TRACKING_DATA_SOURCE_STATE_EXT;
+ hand_trackers[i].data_source.next = next_pointer;
+ hand_trackers[i].data_source.isActive = false;
+ hand_trackers[i].data_source.dataSource = XrHandTrackingDataSourceEXT(0);
+ next_pointer = &hand_trackers[i].data_source;
+ }
+
hand_trackers[i].locations.type = XR_TYPE_HAND_JOINT_LOCATIONS_EXT;
hand_trackers[i].locations.next = next_pointer;
hand_trackers[i].locations.isActive = false;
@@ -171,14 +192,9 @@ void OpenXRHandTrackingExtension::on_process() {
if (hand_trackers[i].is_initialized) {
void *next_pointer = nullptr;
- XrHandJointsMotionRangeInfoEXT motionRangeInfo;
-
+ XrHandJointsMotionRangeInfoEXT motion_range_info = { XR_TYPE_HAND_JOINTS_MOTION_RANGE_INFO_EXT, next_pointer, hand_trackers[i].motion_range };
if (hand_motion_range_ext) {
- motionRangeInfo.type = XR_TYPE_HAND_JOINTS_MOTION_RANGE_INFO_EXT;
- motionRangeInfo.next = next_pointer;
- motionRangeInfo.handJointsMotionRange = hand_trackers[i].motion_range;
-
- next_pointer = &motionRangeInfo;
+ next_pointer = &motion_range_info;
}
XrHandJointsLocateInfoEXT locateInfo = {
@@ -240,6 +256,25 @@ XrHandJointsMotionRangeEXT OpenXRHandTrackingExtension::get_motion_range(HandTra
return hand_trackers[p_hand].motion_range;
}
+OpenXRHandTrackingExtension::HandTrackedSource OpenXRHandTrackingExtension::get_hand_tracking_source(HandTrackedHands p_hand) const {
+ ERR_FAIL_UNSIGNED_INDEX_V(p_hand, OPENXR_MAX_TRACKED_HANDS, OPENXR_SOURCE_UNKNOWN);
+
+ if (hand_tracking_source_ext && hand_trackers[p_hand].data_source.isActive) {
+ switch (hand_trackers[p_hand].data_source.dataSource) {
+ case XR_HAND_TRACKING_DATA_SOURCE_UNOBSTRUCTED_EXT:
+ return OPENXR_SOURCE_UNOBSTRUCTED;
+
+ case XR_HAND_TRACKING_DATA_SOURCE_CONTROLLER_EXT:
+ return OPENXR_SOURCE_CONTROLLER;
+
+ default:
+ return OPENXR_SOURCE_UNKNOWN;
+ }
+ }
+
+ return OPENXR_SOURCE_UNKNOWN;
+}
+
void OpenXRHandTrackingExtension::set_motion_range(HandTrackedHands p_hand, XrHandJointsMotionRangeEXT p_motion_range) {
ERR_FAIL_UNSIGNED_INDEX(p_hand, OPENXR_MAX_TRACKED_HANDS);
hand_trackers[p_hand].motion_range = p_motion_range;
diff --git a/modules/openxr/extensions/openxr_hand_tracking_extension.h b/modules/openxr/extensions/openxr_hand_tracking_extension.h
index f9b26fd604..967538b377 100644
--- a/modules/openxr/extensions/openxr_hand_tracking_extension.h
+++ b/modules/openxr/extensions/openxr_hand_tracking_extension.h
@@ -43,9 +43,17 @@ public:
OPENXR_MAX_TRACKED_HANDS
};
+ enum HandTrackedSource {
+ OPENXR_SOURCE_UNKNOWN,
+ OPENXR_SOURCE_UNOBSTRUCTED,
+ OPENXR_SOURCE_CONTROLLER,
+ OPENXR_SOURCE_MAX
+ };
+
struct HandTracker {
bool is_initialized = false;
XrHandJointsMotionRangeEXT motion_range = XR_HAND_JOINTS_MOTION_RANGE_UNOBSTRUCTED_EXT;
+ HandTrackedSource source = OPENXR_SOURCE_UNKNOWN;
XrHandTrackerEXT hand_tracker = XR_NULL_HANDLE;
XrHandJointLocationEXT joint_locations[XR_HAND_JOINT_COUNT_EXT];
@@ -53,6 +61,7 @@ public:
XrHandJointVelocitiesEXT velocities;
XrHandJointLocationsEXT locations;
+ XrHandTrackingDataSourceStateEXT data_source;
};
static OpenXRHandTrackingExtension *get_singleton();
@@ -77,6 +86,8 @@ public:
XrHandJointsMotionRangeEXT get_motion_range(HandTrackedHands p_hand) const;
void set_motion_range(HandTrackedHands p_hand, XrHandJointsMotionRangeEXT p_motion_range);
+ HandTrackedSource get_hand_tracking_source(HandTrackedHands p_hand) const;
+
XrSpaceLocationFlags get_hand_joint_location_flags(HandTrackedHands p_hand, XrHandJointEXT p_joint) const;
Quaternion get_hand_joint_rotation(HandTrackedHands p_hand, XrHandJointEXT p_joint) const;
Vector3 get_hand_joint_position(HandTrackedHands p_hand, XrHandJointEXT p_joint) const;
@@ -96,6 +107,7 @@ private:
// related extensions
bool hand_tracking_ext = false;
bool hand_motion_range_ext = false;
+ bool hand_tracking_source_ext = false;
// functions
void cleanup_hand_tracking();
diff --git a/modules/openxr/extensions/openxr_meta_controller_extension.cpp b/modules/openxr/extensions/openxr_meta_controller_extension.cpp
new file mode 100644
index 0000000000..72dc74bf64
--- /dev/null
+++ b/modules/openxr/extensions/openxr_meta_controller_extension.cpp
@@ -0,0 +1,184 @@
+/**************************************************************************/
+/* openxr_meta_controller_extension.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#include "openxr_meta_controller_extension.h"
+
+#include "../action_map/openxr_interaction_profile_metadata.h"
+
+HashMap<String, bool *> OpenXRMetaControllerExtension::get_requested_extensions() {
+ HashMap<String, bool *> request_extensions;
+
+ request_extensions[XR_FB_TOUCH_CONTROLLER_PROXIMITY_EXTENSION_NAME] = &available[META_TOUCH_PROXIMITY];
+ request_extensions[XR_FB_TOUCH_CONTROLLER_PRO_EXTENSION_NAME] = &available[META_TOUCH_PRO];
+ request_extensions[XR_META_TOUCH_CONTROLLER_PLUS_EXTENSION_NAME] = &available[META_TOUCH_PLUS];
+
+ return request_extensions;
+}
+
+bool OpenXRMetaControllerExtension::is_available(MetaControllers p_type) {
+ return available[p_type];
+}
+
+void OpenXRMetaControllerExtension::on_register_metadata() {
+ OpenXRInteractionProfileMetadata *metadata = OpenXRInteractionProfileMetadata::get_singleton();
+ ERR_FAIL_NULL(metadata);
+
+ // Note, we register controllers regardless if they are supported on the current hardware.
+
+ // Normal touch controller is part of the core spec, but we do have some extensions.
+ metadata->register_io_path("/interaction_profiles/oculus/touch_controller", "Trigger proximity", "/user/hand/left", "/user/hand/left/input/trigger/proximity_fb ", "XR_FB_touch_controller_proximity", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path("/interaction_profiles/oculus/touch_controller", "Trigger proximity", "/user/hand/right", "/user/hand/right/input/trigger/proximity_fb ", "XR_FB_touch_controller_proximity", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ metadata->register_io_path("/interaction_profiles/oculus/touch_controller", "Thumb proximity", "/user/hand/left", "/user/hand/left/input/thumb_fb/proximity_fb ", "XR_FB_touch_controller_proximity", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path("/interaction_profiles/oculus/touch_controller", "Thumb proximity", "/user/hand/right", "/user/hand/right/input/thumb_fb/proximity_fb ", "XR_FB_touch_controller_proximity", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ // Touch controller pro (Quest Pro)
+ metadata->register_interaction_profile("Touch controller pro", "/interaction_profiles/facebook/touch_controller_pro", "XR_FB_touch_controller_pro");
+ metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Grip pose", "/user/hand/left", "/user/hand/left/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Grip pose", "/user/hand/right", "/user/hand/right/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Aim pose", "/user/hand/left", "/user/hand/left/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Aim pose", "/user/hand/right", "/user/hand/right/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Palm pose", "/user/hand/left", "/user/hand/left/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
+ metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Palm pose", "/user/hand/right", "/user/hand/right/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
+
+ metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Menu click", "/user/hand/left", "/user/hand/left/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "System click", "/user/hand/right", "/user/hand/right/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "X click", "/user/hand/left", "/user/hand/left/input/x/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "X touch", "/user/hand/left", "/user/hand/left/input/x/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Y click", "/user/hand/left", "/user/hand/left/input/y/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Y touch", "/user/hand/left", "/user/hand/left/input/y/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "A click", "/user/hand/right", "/user/hand/right/input/a/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "A touch", "/user/hand/right", "/user/hand/right/input/a/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "B click", "/user/hand/right", "/user/hand/right/input/b/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "B touch", "/user/hand/right", "/user/hand/right/input/b/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Trigger", "/user/hand/left", "/user/hand/left/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Trigger touch", "/user/hand/left", "/user/hand/left/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Trigger proximity", "/user/hand/left", "/user/hand/left/input/trigger/proximity_fb", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Trigger curl", "/user/hand/left", "/user/hand/left/input/trigger/curl_fb", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Trigger slide", "/user/hand/left", "/user/hand/left/input/trigger/slide_fb", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Trigger force", "/user/hand/left", "/user/hand/left/input/trigger/force", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Trigger", "/user/hand/right", "/user/hand/right/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Trigger touch", "/user/hand/right", "/user/hand/right/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Trigger proximity", "/user/hand/right", "/user/hand/right/input/trigger/proximity_fb", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Trigger curl", "/user/hand/right", "/user/hand/right/input/trigger/curl_fb", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Trigger slide", "/user/hand/right", "/user/hand/right/input/trigger/slide_fb", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Trigger force", "/user/hand/right", "/user/hand/right/input/trigger/force", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+
+ metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Squeeze", "/user/hand/left", "/user/hand/left/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Squeeze", "/user/hand/right", "/user/hand/right/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+
+ metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumb proximity", "/user/hand/left", "/user/hand/left/input/thumb_fb/proximity_fb", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumb proximity", "/user/hand/right", "/user/hand/right/input/thumb_fb/proximity_fb", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumbstick", "/user/hand/left", "/user/hand/left/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
+ metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumbstick X", "/user/hand/left", "/user/hand/left/input/thumbstick/x", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumbstick Y", "/user/hand/left", "/user/hand/left/input/thumbstick/y", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumbstick click", "/user/hand/left", "/user/hand/left/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumbstick touch", "/user/hand/left", "/user/hand/left/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumbstick", "/user/hand/right", "/user/hand/right/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
+ metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumbstick X", "/user/hand/right", "/user/hand/right/input/thumbstick/x", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumbstick Y", "/user/hand/right", "/user/hand/right/input/thumbstick/y", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumbstick click", "/user/hand/right", "/user/hand/right/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumbstick touch", "/user/hand/right", "/user/hand/right/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumbrest touch", "/user/hand/left", "/user/hand/left/input/thumbrest/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumbrest force", "/user/hand/left", "/user/hand/left/input/thumbrest/force", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumbrest touch", "/user/hand/right", "/user/hand/right/input/thumbrest/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumbrest force", "/user/hand/right", "/user/hand/right/input/thumbrest/force", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+
+ metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Stylus force", "/user/hand/left", "/user/hand/left/input/stylus_fb/force", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Stylus force", "/user/hand/right", "/user/hand/right/input/stylus_fb/force", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+
+ metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Haptic output", "/user/hand/left", "/user/hand/left/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+ metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Haptic trigger output", "/user/hand/left", "/user/hand/left/output/haptic_trigger_fb", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+ metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Haptic thumb output", "/user/hand/left", "/user/hand/left/output/haptic_thumb_fb", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+ metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Haptic output", "/user/hand/right", "/user/hand/right/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+ metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Haptic trigger output", "/user/hand/right", "/user/hand/right/output/haptic_trigger_fb", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+ metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Haptic thumb output", "/user/hand/right", "/user/hand/right/output/haptic_thumb_fb", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+
+ // Touch controller plus (Quest 3)
+ metadata->register_interaction_profile("Touch controller plus", "/interaction_profiles/meta/touch_controller_plus", "XR_META_touch_controller_plus");
+ metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Grip pose", "/user/hand/left", "/user/hand/left/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Grip pose", "/user/hand/right", "/user/hand/right/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Aim pose", "/user/hand/left", "/user/hand/left/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Aim pose", "/user/hand/right", "/user/hand/right/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Palm pose", "/user/hand/left", "/user/hand/left/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
+ metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Palm pose", "/user/hand/right", "/user/hand/right/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
+
+ metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Menu click", "/user/hand/left", "/user/hand/left/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "System click", "/user/hand/right", "/user/hand/right/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "X click", "/user/hand/left", "/user/hand/left/input/x/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "X touch", "/user/hand/left", "/user/hand/left/input/x/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Y click", "/user/hand/left", "/user/hand/left/input/y/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Y touch", "/user/hand/left", "/user/hand/left/input/y/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "A click", "/user/hand/right", "/user/hand/right/input/a/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "A touch", "/user/hand/right", "/user/hand/right/input/a/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "B click", "/user/hand/right", "/user/hand/right/input/b/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "B touch", "/user/hand/right", "/user/hand/right/input/b/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Trigger", "/user/hand/left", "/user/hand/left/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Trigger touch", "/user/hand/left", "/user/hand/left/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Trigger proximity", "/user/hand/left", "/user/hand/left/input/trigger/proximity_meta", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Trigger curl", "/user/hand/left", "/user/hand/left/input/trigger/curl_meta", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Trigger slide", "/user/hand/left", "/user/hand/left/input/trigger/slide_meta", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Trigger force", "/user/hand/left", "/user/hand/left/input/trigger/force", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Trigger", "/user/hand/right", "/user/hand/right/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Trigger touch", "/user/hand/right", "/user/hand/right/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Trigger proximity", "/user/hand/right", "/user/hand/right/input/trigger/proximity_meta", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Trigger curl", "/user/hand/right", "/user/hand/right/input/trigger/curl_meta", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Trigger slide", "/user/hand/right", "/user/hand/right/input/trigger/slide_meta", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Trigger force", "/user/hand/right", "/user/hand/right/input/trigger/force", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+
+ metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Squeeze", "/user/hand/left", "/user/hand/left/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Squeeze", "/user/hand/right", "/user/hand/right/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+
+ metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Thumb proximity", "/user/hand/left", "/user/hand/left/input/thumb_meta/proximity_meta", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Thumb proximity", "/user/hand/right", "/user/hand/right/input/thumb_meta/proximity_meta", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Thumbstick", "/user/hand/left", "/user/hand/left/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
+ metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Thumbstick X", "/user/hand/left", "/user/hand/left/input/thumbstick/x", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Thumbstick Y", "/user/hand/left", "/user/hand/left/input/thumbstick/y", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Thumbstick click", "/user/hand/left", "/user/hand/left/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Thumbstick touch", "/user/hand/left", "/user/hand/left/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Thumbstick", "/user/hand/right", "/user/hand/right/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
+ metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Thumbstick X", "/user/hand/right", "/user/hand/right/input/thumbstick/x", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Thumbstick Y", "/user/hand/right", "/user/hand/right/input/thumbstick/y", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Thumbstick click", "/user/hand/right", "/user/hand/right/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Thumbstick touch", "/user/hand/right", "/user/hand/right/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Thumbrest touch", "/user/hand/left", "/user/hand/left/input/thumbrest/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Thumbrest touch", "/user/hand/right", "/user/hand/right/input/thumbrest/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Haptic output", "/user/hand/left", "/user/hand/left/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+ metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Haptic output", "/user/hand/right", "/user/hand/right/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+}
diff --git a/modules/openxr/extensions/openxr_meta_controller_extension.h b/modules/openxr/extensions/openxr_meta_controller_extension.h
new file mode 100644
index 0000000000..7a60d2a0b9
--- /dev/null
+++ b/modules/openxr/extensions/openxr_meta_controller_extension.h
@@ -0,0 +1,55 @@
+/**************************************************************************/
+/* openxr_meta_controller_extension.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef OPENXR_META_CONTROLLER_EXTENSION_H
+#define OPENXR_META_CONTROLLER_EXTENSION_H
+
+#include "openxr_extension_wrapper.h"
+
+class OpenXRMetaControllerExtension : public OpenXRExtensionWrapper {
+public:
+ enum MetaControllers {
+ META_TOUCH_PROXIMITY, // Proximity extensions for normal touch controllers
+ META_TOUCH_PRO, // Touch controller for the Quest Pro
+ META_TOUCH_PLUS, // Touch controller for the Quest Plus
+ META_MAX_CONTROLLERS
+ };
+
+ virtual HashMap<String, bool *> get_requested_extensions() override;
+
+ bool is_available(MetaControllers p_type);
+
+ virtual void on_register_metadata() override;
+
+private:
+ bool available[META_MAX_CONTROLLERS] = { false, false, false };
+};
+
+#endif // OPENXR_META_CONTROLLER_EXTENSION_H
diff --git a/modules/openxr/openxr_interface.cpp b/modules/openxr/openxr_interface.cpp
index 66f8192c9e..ceeb1b0278 100644
--- a/modules/openxr/openxr_interface.cpp
+++ b/modules/openxr/openxr_interface.cpp
@@ -77,6 +77,8 @@ void OpenXRInterface::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_motion_range", "hand", "motion_range"), &OpenXRInterface::set_motion_range);
ClassDB::bind_method(D_METHOD("get_motion_range", "hand"), &OpenXRInterface::get_motion_range);
+ ClassDB::bind_method(D_METHOD("get_hand_tracking_source", "hand"), &OpenXRInterface::get_hand_tracking_source);
+
ClassDB::bind_method(D_METHOD("get_hand_joint_flags", "hand", "joint"), &OpenXRInterface::get_hand_joint_flags);
ClassDB::bind_method(D_METHOD("get_hand_joint_rotation", "hand", "joint"), &OpenXRInterface::get_hand_joint_rotation);
@@ -97,6 +99,11 @@ void OpenXRInterface::_bind_methods() {
BIND_ENUM_CONSTANT(HAND_MOTION_RANGE_CONFORM_TO_CONTROLLER);
BIND_ENUM_CONSTANT(HAND_MOTION_RANGE_MAX);
+ BIND_ENUM_CONSTANT(HAND_TRACKED_SOURCE_UNKNOWN);
+ BIND_ENUM_CONSTANT(HAND_TRACKED_SOURCE_UNOBSTRUCTED);
+ BIND_ENUM_CONSTANT(HAND_TRACKED_SOURCE_CONTROLLER);
+ BIND_ENUM_CONSTANT(HAND_TRACKED_SOURCE_MAX);
+
BIND_ENUM_CONSTANT(HAND_JOINT_PALM);
BIND_ENUM_CONSTANT(HAND_JOINT_WRIST);
BIND_ENUM_CONSTANT(HAND_JOINT_THUMB_METACARPAL);
@@ -1269,6 +1276,27 @@ OpenXRInterface::HandMotionRange OpenXRInterface::get_motion_range(const Hand p_
return HAND_MOTION_RANGE_MAX;
}
+OpenXRInterface::HandTrackedSource OpenXRInterface::get_hand_tracking_source(const Hand p_hand) const {
+ ERR_FAIL_INDEX_V(p_hand, HAND_MAX, HAND_TRACKED_SOURCE_UNKNOWN);
+
+ OpenXRHandTrackingExtension *hand_tracking_ext = OpenXRHandTrackingExtension::get_singleton();
+ if (hand_tracking_ext && hand_tracking_ext->get_active()) {
+ OpenXRHandTrackingExtension::HandTrackedSource source = hand_tracking_ext->get_hand_tracking_source(OpenXRHandTrackingExtension::HandTrackedHands(p_hand));
+ switch (source) {
+ case OpenXRHandTrackingExtension::OPENXR_SOURCE_UNOBSTRUCTED:
+ return HAND_TRACKED_SOURCE_UNOBSTRUCTED;
+ case OpenXRHandTrackingExtension::OPENXR_SOURCE_CONTROLLER:
+ return HAND_TRACKED_SOURCE_CONTROLLER;
+ case OpenXRHandTrackingExtension::OPENXR_SOURCE_UNKNOWN:
+ return HAND_TRACKED_SOURCE_UNKNOWN;
+ default:
+ ERR_FAIL_V_MSG(HAND_TRACKED_SOURCE_UNKNOWN, "Unknown hand tracking source returned by OpenXR");
+ }
+ }
+
+ return HAND_TRACKED_SOURCE_UNKNOWN;
+}
+
BitField<OpenXRInterface::HandJointFlags> OpenXRInterface::get_hand_joint_flags(Hand p_hand, HandJoints p_joint) const {
BitField<OpenXRInterface::HandJointFlags> bits;
diff --git a/modules/openxr/openxr_interface.h b/modules/openxr/openxr_interface.h
index 489d0845ba..ca95fdf04d 100644
--- a/modules/openxr/openxr_interface.h
+++ b/modules/openxr/openxr_interface.h
@@ -194,6 +194,15 @@ public:
void set_motion_range(const Hand p_hand, const HandMotionRange p_motion_range);
HandMotionRange get_motion_range(const Hand p_hand) const;
+ enum HandTrackedSource {
+ HAND_TRACKED_SOURCE_UNKNOWN,
+ HAND_TRACKED_SOURCE_UNOBSTRUCTED,
+ HAND_TRACKED_SOURCE_CONTROLLER,
+ HAND_TRACKED_SOURCE_MAX
+ };
+
+ HandTrackedSource get_hand_tracking_source(const Hand p_hand) const;
+
enum HandJoints {
HAND_JOINT_PALM = 0,
HAND_JOINT_WRIST = 1,
@@ -248,6 +257,7 @@ public:
VARIANT_ENUM_CAST(OpenXRInterface::Hand)
VARIANT_ENUM_CAST(OpenXRInterface::HandMotionRange)
+VARIANT_ENUM_CAST(OpenXRInterface::HandTrackedSource)
VARIANT_ENUM_CAST(OpenXRInterface::HandJoints)
VARIANT_BITFIELD_CAST(OpenXRInterface::HandJointFlags)
diff --git a/modules/openxr/register_types.cpp b/modules/openxr/register_types.cpp
index 544932bdeb..5cc793dca3 100644
--- a/modules/openxr/register_types.cpp
+++ b/modules/openxr/register_types.cpp
@@ -49,6 +49,7 @@
#include "extensions/openxr_htc_controller_extension.h"
#include "extensions/openxr_htc_vive_tracker_extension.h"
#include "extensions/openxr_huawei_controller_extension.h"
+#include "extensions/openxr_meta_controller_extension.h"
#include "extensions/openxr_ml2_controller_extension.h"
#include "extensions/openxr_palm_pose_extension.h"
#include "extensions/openxr_pico_controller_extension.h"
@@ -115,6 +116,7 @@ void initialize_openxr_module(ModuleInitializationLevel p_level) {
OpenXRAPI::register_extension_wrapper(memnew(OpenXRDisplayRefreshRateExtension));
OpenXRAPI::register_extension_wrapper(memnew(OpenXRWMRControllerExtension));
OpenXRAPI::register_extension_wrapper(memnew(OpenXRML2ControllerExtension));
+ OpenXRAPI::register_extension_wrapper(memnew(OpenXRMetaControllerExtension));
// register gated extensions
if (GLOBAL_GET("xr/openxr/extensions/eye_gaze_interaction") && (!OS::get_singleton()->has_feature("mobile") || OS::get_singleton()->has_feature(XR_EXT_EYE_GAZE_INTERACTION_EXTENSION_NAME))) {
diff --git a/modules/openxr/scene/openxr_hand.cpp b/modules/openxr/scene/openxr_hand.cpp
index c48fac8055..8ce33b55c3 100644
--- a/modules/openxr/scene/openxr_hand.cpp
+++ b/modules/openxr/scene/openxr_hand.cpp
@@ -46,9 +46,13 @@ void OpenXRHand::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_motion_range", "motion_range"), &OpenXRHand::set_motion_range);
ClassDB::bind_method(D_METHOD("get_motion_range"), &OpenXRHand::get_motion_range);
+ ClassDB::bind_method(D_METHOD("set_skeleton_rig", "skeleton_rig"), &OpenXRHand::set_skeleton_rig);
+ ClassDB::bind_method(D_METHOD("get_skeleton_rig"), &OpenXRHand::get_skeleton_rig);
+
ADD_PROPERTY(PropertyInfo(Variant::INT, "hand", PROPERTY_HINT_ENUM, "Left,Right"), "set_hand", "get_hand");
ADD_PROPERTY(PropertyInfo(Variant::INT, "motion_range", PROPERTY_HINT_ENUM, "Unobstructed,Conform to controller"), "set_motion_range", "get_motion_range");
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "hand_skeleton", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Skeleton3D"), "set_hand_skeleton", "get_hand_skeleton");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "skeleton_rig", PROPERTY_HINT_ENUM, "OpenXR,Humanoid"), "set_skeleton_rig", "get_skeleton_rig");
BIND_ENUM_CONSTANT(HAND_LEFT);
BIND_ENUM_CONSTANT(HAND_RIGHT);
@@ -57,6 +61,10 @@ void OpenXRHand::_bind_methods() {
BIND_ENUM_CONSTANT(MOTION_RANGE_UNOBSTRUCTED);
BIND_ENUM_CONSTANT(MOTION_RANGE_CONFORM_TO_CONTROLLER);
BIND_ENUM_CONSTANT(MOTION_RANGE_MAX);
+
+ BIND_ENUM_CONSTANT(SKELETON_RIG_OPENXR);
+ BIND_ENUM_CONSTANT(SKELETON_RIG_HUMANOID);
+ BIND_ENUM_CONSTANT(SKELETON_RIG_MAX);
}
OpenXRHand::OpenXRHand() {
@@ -64,7 +72,7 @@ OpenXRHand::OpenXRHand() {
hand_tracking_ext = OpenXRHandTrackingExtension::get_singleton();
}
-void OpenXRHand::set_hand(const Hands p_hand) {
+void OpenXRHand::set_hand(Hands p_hand) {
ERR_FAIL_INDEX(p_hand, HAND_MAX);
hand = p_hand;
@@ -80,7 +88,7 @@ void OpenXRHand::set_hand_skeleton(const NodePath &p_hand_skeleton) {
// TODO if inside tree call _get_bones()
}
-void OpenXRHand::set_motion_range(const MotionRange p_motion_range) {
+void OpenXRHand::set_motion_range(MotionRange p_motion_range) {
ERR_FAIL_INDEX(p_motion_range, MOTION_RANGE_MAX);
motion_range = p_motion_range;
@@ -116,6 +124,16 @@ void OpenXRHand::_set_motion_range() {
hand_tracking_ext->set_motion_range(OpenXRHandTrackingExtension::HandTrackedHands(hand), xr_motion_range);
}
+void OpenXRHand::set_skeleton_rig(SkeletonRig p_skeleton_rig) {
+ ERR_FAIL_INDEX(p_skeleton_rig, SKELETON_RIG_MAX);
+
+ skeleton_rig = p_skeleton_rig;
+}
+
+OpenXRHand::SkeletonRig OpenXRHand::get_skeleton_rig() const {
+ return skeleton_rig;
+}
+
Skeleton3D *OpenXRHand::get_skeleton() {
if (!has_node(hand_skeleton)) {
return nullptr;
@@ -130,39 +148,81 @@ Skeleton3D *OpenXRHand::get_skeleton() {
return skeleton;
}
-void OpenXRHand::_get_bones() {
- const char *bone_names[XR_HAND_JOINT_COUNT_EXT] = {
- "Palm",
- "Wrist",
- "Thumb_Metacarpal",
- "Thumb_Proximal",
- "Thumb_Distal",
- "Thumb_Tip",
- "Index_Metacarpal",
- "Index_Proximal",
- "Index_Intermediate",
- "Index_Distal",
- "Index_Tip",
- "Middle_Metacarpal",
- "Middle_Proximal",
- "Middle_Intermediate",
- "Middle_Distal",
- "Middle_Tip",
- "Ring_Metacarpal",
- "Ring_Proximal",
- "Ring_Intermediate",
- "Ring_Distal",
- "Ring_Tip",
- "Little_Metacarpal",
- "Little_Proximal",
- "Little_Intermediate",
- "Little_Distal",
- "Little_Tip",
+void OpenXRHand::_get_joint_data() {
+ // Table of bone names for different rig types.
+ static const String bone_names[SKELETON_RIG_MAX][XR_HAND_JOINT_COUNT_EXT] = {
+ // SKELETON_RIG_OPENXR bone names.
+ {
+ "Palm",
+ "Wrist",
+ "Thumb_Metacarpal",
+ "Thumb_Proximal",
+ "Thumb_Distal",
+ "Thumb_Tip",
+ "Index_Metacarpal",
+ "Index_Proximal",
+ "Index_Intermediate",
+ "Index_Distal",
+ "Index_Tip",
+ "Middle_Metacarpal",
+ "Middle_Proximal",
+ "Middle_Intermediate",
+ "Middle_Distal",
+ "Middle_Tip",
+ "Ring_Metacarpal",
+ "Ring_Proximal",
+ "Ring_Intermediate",
+ "Ring_Distal",
+ "Ring_Tip",
+ "Little_Metacarpal",
+ "Little_Proximal",
+ "Little_Intermediate",
+ "Little_Distal",
+ "Little_Tip" },
+
+ // SKELETON_RIG_HUMANOID bone names.
+ {
+ "Palm",
+ "Hand",
+ "ThumbMetacarpal",
+ "ThumbProximal",
+ "ThumbDistal",
+ "ThumbTip",
+ "IndexMetacarpal",
+ "IndexProximal",
+ "IndexIntermediate",
+ "IndexDistal",
+ "IndexTip",
+ "MiddleMetacarpal",
+ "MiddleProximal",
+ "MiddleIntermediate",
+ "MiddleDistal",
+ "MiddleTip",
+ "RingMetacarpal",
+ "RingProximal",
+ "RingIntermediate",
+ "RingDistal",
+ "RingTip",
+ "LittleMetacarpal",
+ "LittleProximal",
+ "LittleIntermediate",
+ "LittleDistal",
+ "LittleTip" }
+ };
+
+ // Table of bone name formats for different rig types and left/right hands.
+ static const String bone_name_formats[SKELETON_RIG_MAX][2] = {
+ // SKELETON_RIG_OPENXR bone name format.
+ { "<bone>_L", "<bone>_R" },
+
+ // SKELETON_RIG_HUMANOID bone name format.
+ { "Left<bone>", "Right<bone>" }
};
// reset JIC
for (int i = 0; i < XR_HAND_JOINT_COUNT_EXT; i++) {
- bones[i] = -1;
+ joints[i].bone = -1;
+ joints[i].parent_joint = -1;
}
Skeleton3D *skeleton = get_skeleton();
@@ -170,20 +230,46 @@ void OpenXRHand::_get_bones() {
return;
}
- // We cast to spatials which should allow us to use any subclass of that.
+ // Find the skeleton-bones associated with each OpenXR joint.
+ int bones[XR_HAND_JOINT_COUNT_EXT];
for (int i = 0; i < XR_HAND_JOINT_COUNT_EXT; i++) {
- String bone_name = bone_names[i];
- if (hand == 0) {
- bone_name += String("_L");
- } else {
- bone_name += String("_R");
- }
+ // Construct the expected bone name.
+ String bone_name = bone_name_formats[skeleton_rig][hand].replace("<bone>", bone_names[skeleton_rig][i]);
+ // Find the skeleton bone.
bones[i] = skeleton->find_bone(bone_name);
if (bones[i] == -1) {
print_line("Couldn't obtain bone for", bone_name);
}
}
+
+ // Assemble the OpenXR joint relationship to the available skeleton bones.
+ for (int i = 0; i < XR_HAND_JOINT_COUNT_EXT; i++) {
+ // Get the skeleton bone (skip if not found).
+ const int bone = bones[i];
+ if (bone == -1) {
+ continue;
+ }
+
+ // Find the parent skeleton-bone.
+ const int parent_bone = skeleton->get_bone_parent(bone);
+ if (parent_bone == -1) {
+ // If no parent skeleton-bone exists then drive this relative to palm joint.
+ joints[i].bone = bone;
+ joints[i].parent_joint = XR_HAND_JOINT_PALM_EXT;
+ continue;
+ }
+
+ // Find the OpenXR joint associated with the parent skeleton-bone.
+ for (int j = 0; j < XR_HAND_JOINT_COUNT_EXT; ++j) {
+ if (bones[j] == parent_bone) {
+ // If a parent joint is found then drive this bone relative to it.
+ joints[i].bone = bone;
+ joints[i].parent_joint = j;
+ break;
+ }
+ }
+ }
}
void OpenXRHand::_update_skeleton() {
@@ -198,12 +284,25 @@ void OpenXRHand::_update_skeleton() {
return;
}
+ // Table of bone adjustments for different rig types
+ static const Quaternion bone_adjustments[SKELETON_RIG_MAX] = {
+ // SKELETON_RIG_OPENXR bone adjustment. This is an identity quaternion
+ // because the incoming quaternions are already in OpenXR format.
+ Quaternion(),
+
+ // SKELETON_RIG_HUMANOID bone adjustment. This rotation performs:
+ // OpenXR Z+ -> Godot Humanoid Y- (Back along the bone)
+ // OpenXR Y+ -> Godot Humanoid Z- (Out the back of the hand)
+ Quaternion(0.0, -Math_SQRT12, Math_SQRT12, 0.0),
+ };
+
// we cache our transforms so we can quickly calculate local transforms
XRPose::TrackingConfidence confidences[XR_HAND_JOINT_COUNT_EXT];
Quaternion quaternions[XR_HAND_JOINT_COUNT_EXT];
Quaternion inv_quaternions[XR_HAND_JOINT_COUNT_EXT];
Vector3 positions[XR_HAND_JOINT_COUNT_EXT];
+ const Quaternion &rig_adjustment = bone_adjustments[skeleton_rig];
const OpenXRHandTrackingExtension::HandTracker *hand_tracker = hand_tracking_ext->get_hand_tracker(OpenXRHandTrackingExtension::HandTrackedHands(hand));
const float ws = XRServer::get_singleton()->get_world_scale();
@@ -218,7 +317,7 @@ void OpenXRHand::_update_skeleton() {
if (location.locationFlags & XR_SPACE_LOCATION_ORIENTATION_VALID_BIT) {
if (pose.orientation.x != 0 || pose.orientation.y != 0 || pose.orientation.z != 0 || pose.orientation.w != 0) {
- quaternions[i] = Quaternion(pose.orientation.x, pose.orientation.y, pose.orientation.z, pose.orientation.w);
+ quaternions[i] = Quaternion(pose.orientation.x, pose.orientation.y, pose.orientation.z, pose.orientation.w) * rig_adjustment;
inv_quaternions[i] = quaternions[i].inverse();
if (location.locationFlags & XR_SPACE_LOCATION_POSITION_VALID_BIT) {
@@ -234,40 +333,25 @@ void OpenXRHand::_update_skeleton() {
}
if (confidences[XR_HAND_JOINT_PALM_EXT] != XRPose::XR_TRACKING_CONFIDENCE_NONE) {
- // now update our skeleton
- for (int i = 0; i < XR_HAND_JOINT_COUNT_EXT; i++) {
- if (bones[i] != -1) {
- int bone = bones[i];
- int parent = skeleton->get_bone_parent(bone);
-
- // Get our target quaternion
- Quaternion q = quaternions[i];
+ // Iterate over all the OpenXR joints.
+ for (int joint = 0; joint < XR_HAND_JOINT_COUNT_EXT; joint++) {
+ // Get the skeleton bone (skip if none).
+ const int bone = joints[joint].bone;
+ if (bone == -1) {
+ continue;
+ }
- // Get our target position
- Vector3 p = positions[i];
+ // Calculate the relative relationship to the parent bone joint.
+ const int parent_joint = joints[joint].parent_joint;
+ const Quaternion q = inv_quaternions[parent_joint] * quaternions[joint];
+ const Vector3 p = inv_quaternions[parent_joint].xform(positions[joint] - positions[parent_joint]);
- // get local translation, parent should already be processed
- if (parent == -1) {
- // use our palm location here, that is what we are tracking
- q = inv_quaternions[XR_HAND_JOINT_PALM_EXT] * q;
- p = inv_quaternions[XR_HAND_JOINT_PALM_EXT].xform(p - positions[XR_HAND_JOINT_PALM_EXT]);
- } else {
- int found = false;
- for (int b = 0; b < XR_HAND_JOINT_COUNT_EXT && !found; b++) {
- if (bones[b] == parent) {
- q = inv_quaternions[b] * q;
- p = inv_quaternions[b].xform(p - positions[b]);
- found = true;
- }
- }
- }
-
- // and set our pose
- skeleton->set_bone_pose_position(bones[i], p);
- skeleton->set_bone_pose_rotation(bones[i], q);
- }
+ // and set our pose
+ skeleton->set_bone_pose_position(joints[joint].bone, p);
+ skeleton->set_bone_pose_rotation(joints[joint].bone, q);
}
+ // Transform the OpenXRHand to the skeleton pose.
Transform3D t;
t.basis = Basis(quaternions[XR_HAND_JOINT_PALM_EXT]);
t.origin = positions[XR_HAND_JOINT_PALM_EXT];
@@ -288,7 +372,7 @@ void OpenXRHand::_update_skeleton() {
void OpenXRHand::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
- _get_bones();
+ _get_joint_data();
set_process_internal(true);
} break;
@@ -297,7 +381,8 @@ void OpenXRHand::_notification(int p_what) {
// reset
for (int i = 0; i < XR_HAND_JOINT_COUNT_EXT; i++) {
- bones[i] = -1;
+ joints[i].bone = -1;
+ joints[i].parent_joint = -1;
}
} break;
case NOTIFICATION_INTERNAL_PROCESS: {
diff --git a/modules/openxr/scene/openxr_hand.h b/modules/openxr/scene/openxr_hand.h
index edfb474ac7..14eb893bcc 100644
--- a/modules/openxr/scene/openxr_hand.h
+++ b/modules/openxr/scene/openxr_hand.h
@@ -55,20 +55,32 @@ public:
MOTION_RANGE_MAX
};
+ enum SkeletonRig {
+ SKELETON_RIG_OPENXR,
+ SKELETON_RIG_HUMANOID,
+ SKELETON_RIG_MAX
+ };
+
private:
+ struct JointData {
+ int bone = -1;
+ int parent_joint = -1;
+ };
+
OpenXRAPI *openxr_api = nullptr;
OpenXRHandTrackingExtension *hand_tracking_ext = nullptr;
Hands hand = HAND_LEFT;
MotionRange motion_range = MOTION_RANGE_UNOBSTRUCTED;
NodePath hand_skeleton;
+ SkeletonRig skeleton_rig = SKELETON_RIG_OPENXR;
- int64_t bones[XR_HAND_JOINT_COUNT_EXT];
+ JointData joints[XR_HAND_JOINT_COUNT_EXT];
void _set_motion_range();
Skeleton3D *get_skeleton();
- void _get_bones();
+ void _get_joint_data();
void _update_skeleton();
protected:
@@ -77,19 +89,23 @@ protected:
public:
OpenXRHand();
- void set_hand(const Hands p_hand);
+ void set_hand(Hands p_hand);
Hands get_hand() const;
- void set_motion_range(const MotionRange p_motion_range);
+ void set_motion_range(MotionRange p_motion_range);
MotionRange get_motion_range() const;
void set_hand_skeleton(const NodePath &p_hand_skeleton);
NodePath get_hand_skeleton() const;
+ void set_skeleton_rig(SkeletonRig p_skeleton_rig);
+ SkeletonRig get_skeleton_rig() const;
+
void _notification(int p_what);
};
VARIANT_ENUM_CAST(OpenXRHand::Hands)
VARIANT_ENUM_CAST(OpenXRHand::MotionRange)
+VARIANT_ENUM_CAST(OpenXRHand::SkeletonRig)
#endif // OPENXR_HAND_H
diff --git a/modules/regex/regex.cpp b/modules/regex/regex.cpp
index 704c107f20..d49578d2a9 100644
--- a/modules/regex/regex.cpp
+++ b/modules/regex/regex.cpp
@@ -270,16 +270,18 @@ Ref<RegExMatch> RegEx::search(const String &p_subject, int p_offset, int p_end)
TypedArray<RegExMatch> RegEx::search_all(const String &p_subject, int p_offset, int p_end) const {
ERR_FAIL_COND_V_MSG(p_offset < 0, Array(), "RegEx search offset must be >= 0");
- int last_end = -1;
+ int last_end = 0;
TypedArray<RegExMatch> result;
Ref<RegExMatch> match = search(p_subject, p_offset, p_end);
+
while (match.is_valid()) {
- if (last_end == match->get_end(0)) {
- break;
+ last_end = match->get_end(0);
+ if (match->get_start(0) == last_end) {
+ last_end++;
}
+
result.push_back(match);
- last_end = match->get_end(0);
- match = search(p_subject, match->get_end(0), p_end);
+ match = search(p_subject, last_end, p_end);
}
return result;
}
diff --git a/modules/regex/tests/test_regex.h b/modules/regex/tests/test_regex.h
index 3e4d769377..0b401da831 100644
--- a/modules/regex/tests/test_regex.h
+++ b/modules/regex/tests/test_regex.h
@@ -164,7 +164,7 @@ TEST_CASE("[RegEx] Uninitialized use") {
ERR_PRINT_ON
}
-TEST_CASE("[RegEx] Empty Pattern") {
+TEST_CASE("[RegEx] Empty pattern") {
const String s = "Godot";
RegEx re;
@@ -222,6 +222,143 @@ TEST_CASE("[RegEx] Match start and end positions") {
CHECK(match->get_start("vowel") == 2);
CHECK(match->get_end("vowel") == 3);
}
+
+TEST_CASE("[RegEx] Asterisk search all") {
+ const String s = "Godot Engine";
+
+ RegEx re("o*");
+ REQUIRE(re.is_valid());
+ Ref<RegExMatch> match;
+ const Array all_results = re.search_all(s);
+ CHECK(all_results.size() == 13);
+
+ match = all_results[0];
+ CHECK(match->get_string(0) == "");
+ match = all_results[1];
+ CHECK(match->get_string(0) == "o");
+ match = all_results[2];
+ CHECK(match->get_string(0) == "");
+ match = all_results[3];
+ CHECK(match->get_string(0) == "o");
+
+ for (int i = 4; i < 13; i++) {
+ match = all_results[i];
+ CHECK(match->get_string(0) == "");
+ }
+}
+
+TEST_CASE("[RegEx] Simple lookahead") {
+ const String s = "Godot Engine";
+
+ RegEx re("o(?=t)");
+ REQUIRE(re.is_valid());
+ Ref<RegExMatch> match = re.search(s);
+ REQUIRE(match != nullptr);
+ CHECK(match->get_start(0) == 3);
+ CHECK(match->get_end(0) == 4);
+}
+
+TEST_CASE("[RegEx] Lookahead groups empty matches") {
+ const String s = "12";
+
+ RegEx re("(?=(\\d+))");
+ REQUIRE(re.is_valid());
+ Ref<RegExMatch> match = re.search(s);
+ CHECK(match->get_string(0) == "");
+ CHECK(match->get_string(1) == "12");
+
+ const Array all_results = re.search_all(s);
+ CHECK(all_results.size() == 2);
+
+ match = all_results[0];
+ REQUIRE(match != nullptr);
+ CHECK(match->get_string(0) == String(""));
+ CHECK(match->get_string(1) == String("12"));
+
+ match = all_results[1];
+ REQUIRE(match != nullptr);
+ CHECK(match->get_string(0) == String(""));
+ CHECK(match->get_string(1) == String("2"));
+}
+
+TEST_CASE("[RegEx] Simple lookbehind") {
+ const String s = "Godot Engine";
+
+ RegEx re("(?<=d)o");
+ REQUIRE(re.is_valid());
+ Ref<RegExMatch> match = re.search(s);
+ REQUIRE(match != nullptr);
+ CHECK(match->get_start(0) == 3);
+ CHECK(match->get_end(0) == 4);
+}
+
+TEST_CASE("[RegEx] Simple lookbehind search all") {
+ const String s = "ababbaabab";
+
+ RegEx re("(?<=a)b");
+ REQUIRE(re.is_valid());
+ const Array all_results = re.search_all(s);
+ CHECK(all_results.size() == 4);
+
+ Ref<RegExMatch> match = all_results[0];
+ REQUIRE(match != nullptr);
+ CHECK(match->get_start(0) == 1);
+ CHECK(match->get_end(0) == 2);
+
+ match = all_results[1];
+ REQUIRE(match != nullptr);
+ CHECK(match->get_start(0) == 3);
+ CHECK(match->get_end(0) == 4);
+
+ match = all_results[2];
+ REQUIRE(match != nullptr);
+ CHECK(match->get_start(0) == 7);
+ CHECK(match->get_end(0) == 8);
+
+ match = all_results[3];
+ REQUIRE(match != nullptr);
+ CHECK(match->get_start(0) == 9);
+ CHECK(match->get_end(0) == 10);
+}
+
+TEST_CASE("[RegEx] Lookbehind groups empty matches") {
+ const String s = "abaaabab";
+
+ RegEx re("(?<=(b))");
+ REQUIRE(re.is_valid());
+ Ref<RegExMatch> match;
+
+ const Array all_results = re.search_all(s);
+ CHECK(all_results.size() == 3);
+
+ match = all_results[0];
+ REQUIRE(match != nullptr);
+ CHECK(match->get_start(0) == 2);
+ CHECK(match->get_end(0) == 2);
+ CHECK(match->get_start(1) == 1);
+ CHECK(match->get_end(1) == 2);
+ CHECK(match->get_string(0) == String(""));
+ CHECK(match->get_string(1) == String("b"));
+
+ match = all_results[1];
+ REQUIRE(match != nullptr);
+ CHECK(match->get_start(0) == 6);
+ CHECK(match->get_end(0) == 6);
+ CHECK(match->get_start(1) == 5);
+ CHECK(match->get_end(1) == 6);
+ CHECK(match->get_string(0) == String(""));
+ CHECK(match->get_string(1) == String("b"));
+
+ match = all_results[2];
+ REQUIRE(match != nullptr);
+ CHECK(match->get_start(0) == 8);
+ CHECK(match->get_end(0) == 8);
+ CHECK(match->get_start(1) == 7);
+ CHECK(match->get_end(1) == 8);
+ CHECK(match->get_string(0) == String(""));
+ CHECK(match->get_string(1) == String("b"));
+}
+
} // namespace TestRegEx
#endif // TEST_REGEX_H
diff --git a/modules/svg/SCsub b/modules/svg/SCsub
index d0c6250b11..ff0c3c9141 100644
--- a/modules/svg/SCsub
+++ b/modules/svg/SCsub
@@ -43,6 +43,8 @@ thirdparty_sources = [
"src/renderer/tvgShape.cpp",
"src/renderer/tvgSwCanvas.cpp",
"src/renderer/tvgTaskScheduler.cpp",
+ "src/renderer/tvgText.cpp",
+ # "src/renderer/tvgWgCanvas.cpp",
# renderer sw_engine
"src/renderer/sw_engine/tvgSwFill.cpp",
"src/renderer/sw_engine/tvgSwImage.cpp",
diff --git a/modules/text_server_adv/gdextension_build/SConstruct b/modules/text_server_adv/gdextension_build/SConstruct
index f6d3b24cee..cd4331b60e 100644
--- a/modules/text_server_adv/gdextension_build/SConstruct
+++ b/modules/text_server_adv/gdextension_build/SConstruct
@@ -74,6 +74,8 @@ if env["thorvg_enabled"] and env["freetype_enabled"]:
"src/renderer/tvgShape.cpp",
"src/renderer/tvgSwCanvas.cpp",
"src/renderer/tvgTaskScheduler.cpp",
+ "src/renderer/tvgText.cpp",
+ # "src/renderer/tvgWgCanvas.cpp",
# renderer sw_engine
"src/renderer/sw_engine/tvgSwFill.cpp",
"src/renderer/sw_engine/tvgSwImage.cpp",
diff --git a/modules/text_server_adv/register_types.h b/modules/text_server_adv/register_types.h
index c11765048d..477e030e03 100644
--- a/modules/text_server_adv/register_types.h
+++ b/modules/text_server_adv/register_types.h
@@ -34,7 +34,7 @@
#ifdef GDEXTENSION
#include <godot_cpp/core/class_db.hpp>
using namespace godot;
-#else
+#elif defined(GODOT_MODULE)
#include "modules/register_module_types.h"
#endif
diff --git a/modules/text_server_adv/script_iterator.h b/modules/text_server_adv/script_iterator.h
index 164fdec784..f7876d6cbc 100644
--- a/modules/text_server_adv/script_iterator.h
+++ b/modules/text_server_adv/script_iterator.h
@@ -40,7 +40,7 @@
using namespace godot;
-#else
+#elif defined(GODOT_MODULE)
// Headers for building as built-in module.
#include "core/string/ustring.h"
diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp
index bcc7bff909..19f302423c 100644
--- a/modules/text_server_adv/text_server_adv.cpp
+++ b/modules/text_server_adv/text_server_adv.cpp
@@ -44,7 +44,7 @@ using namespace godot;
#define GLOBAL_GET(m_var) ProjectSettings::get_singleton()->get_setting_with_override(m_var)
-#else
+#elif defined(GODOT_MODULE)
// Headers for building as built-in module.
#include "core/config/project_settings.h"
@@ -370,7 +370,7 @@ bool TextServerAdvanced::_has_feature(Feature p_feature) const {
String TextServerAdvanced::_get_name() const {
#ifdef GDEXTENSION
return "ICU / HarfBuzz / Graphite (GDExtension)";
-#else
+#elif defined(GODOT_MODULE)
return "ICU / HarfBuzz / Graphite (Built-in)";
#endif
}
@@ -4852,7 +4852,7 @@ RID TextServerAdvanced::_find_sys_font_for_text(const RID &p_fdef, const String
#ifdef GDEXTENSION
for (int fb = 0; fb < fallback_font_name.size(); fb++) {
const String &E = fallback_font_name[fb];
-#else
+#elif defined(GODOT_MODULE)
for (const String &E : fallback_font_name) {
#endif
SystemFontKey key = SystemFontKey(E, font_style & TextServer::FONT_ITALIC, font_weight, font_stretch, p_fdef, this);
@@ -6757,7 +6757,7 @@ String TextServerAdvanced::_strip_diacritics(const String &p_string) const {
if (u_getCombiningClass(normalized_string[i]) == 0) {
#ifdef GDEXTENSION
result = result + String::chr(normalized_string[i]);
-#else
+#elif defined(GODOT_MODULE)
result = result + normalized_string[i];
#endif
}
diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h
index e5d0ab3105..0b5fe47b8b 100644
--- a/modules/text_server_adv/text_server_adv.h
+++ b/modules/text_server_adv/text_server_adv.h
@@ -78,7 +78,7 @@
using namespace godot;
-#else
+#elif defined(GODOT_MODULE)
// Headers for building as built-in module.
#include "core/extension/ext_wrappers.gen.inc"
diff --git a/modules/text_server_adv/thorvg_bounds_iterator.cpp b/modules/text_server_adv/thorvg_bounds_iterator.cpp
index 807f356b83..d273eef97f 100644
--- a/modules/text_server_adv/thorvg_bounds_iterator.cpp
+++ b/modules/text_server_adv/thorvg_bounds_iterator.cpp
@@ -35,7 +35,7 @@
using namespace godot;
-#else
+#elif defined(GODOT_MODULE)
// Headers for building as built-in module.
#include "core/typedefs.h"
diff --git a/modules/text_server_adv/thorvg_bounds_iterator.h b/modules/text_server_adv/thorvg_bounds_iterator.h
index a44cbb99a7..afa2c13764 100644
--- a/modules/text_server_adv/thorvg_bounds_iterator.h
+++ b/modules/text_server_adv/thorvg_bounds_iterator.h
@@ -39,7 +39,7 @@
using namespace godot;
-#else
+#elif defined(GODOT_MODULE)
// Headers for building as built-in module.
#include "core/typedefs.h"
diff --git a/modules/text_server_adv/thorvg_svg_in_ot.cpp b/modules/text_server_adv/thorvg_svg_in_ot.cpp
index 828f8d7d56..136ccf3aaf 100644
--- a/modules/text_server_adv/thorvg_svg_in_ot.cpp
+++ b/modules/text_server_adv/thorvg_svg_in_ot.cpp
@@ -38,7 +38,7 @@
using namespace godot;
-#else
+#elif defined(GODOT_MODULE)
// Headers for building as built-in module.
#include "core/error/error_macros.h"
diff --git a/modules/text_server_adv/thorvg_svg_in_ot.h b/modules/text_server_adv/thorvg_svg_in_ot.h
index 034fffb5e6..ce048674fd 100644
--- a/modules/text_server_adv/thorvg_svg_in_ot.h
+++ b/modules/text_server_adv/thorvg_svg_in_ot.h
@@ -40,7 +40,7 @@
using namespace godot;
-#else
+#elif defined(GODOT_MODULE)
// Headers for building as built-in module.
#include "core/os/mutex.h"
diff --git a/modules/text_server_fb/gdextension_build/SConstruct b/modules/text_server_fb/gdextension_build/SConstruct
index 0d2fbd97fd..0efced0bfc 100644
--- a/modules/text_server_fb/gdextension_build/SConstruct
+++ b/modules/text_server_fb/gdextension_build/SConstruct
@@ -69,6 +69,8 @@ if env["thorvg_enabled"] and env["freetype_enabled"]:
"src/renderer/tvgShape.cpp",
"src/renderer/tvgSwCanvas.cpp",
"src/renderer/tvgTaskScheduler.cpp",
+ "src/renderer/tvgText.cpp",
+ # "src/renderer/tvgWgCanvas.cpp",
# renderer sw_engine
"src/renderer/sw_engine/tvgSwFill.cpp",
"src/renderer/sw_engine/tvgSwImage.cpp",
diff --git a/modules/text_server_fb/register_types.h b/modules/text_server_fb/register_types.h
index 97bc06a8f7..0933ea83c5 100644
--- a/modules/text_server_fb/register_types.h
+++ b/modules/text_server_fb/register_types.h
@@ -34,7 +34,7 @@
#ifdef GDEXTENSION
#include <godot_cpp/core/class_db.hpp>
using namespace godot;
-#else
+#elif defined(GODOT_MODULE)
#include "modules/register_module_types.h"
#endif
diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp
index 8fc7694aa4..0b486b7d7b 100644
--- a/modules/text_server_fb/text_server_fb.cpp
+++ b/modules/text_server_fb/text_server_fb.cpp
@@ -44,7 +44,7 @@ using namespace godot;
#define GLOBAL_GET(m_var) ProjectSettings::get_singleton()->get_setting_with_override(m_var)
-#else
+#elif defined(GODOT_MODULE)
// Headers for building as built-in module.
#include "core/config/project_settings.h"
@@ -95,7 +95,7 @@ bool TextServerFallback::_has_feature(Feature p_feature) const {
String TextServerFallback::_get_name() const {
#ifdef GDEXTENSION
return "Fallback (GDExtension)";
-#else
+#elif defined(GODOT_MODULE)
return "Fallback (Built-in)";
#endif
}
@@ -3654,7 +3654,7 @@ RID TextServerFallback::_find_sys_font_for_text(const RID &p_fdef, const String
#ifdef GDEXTENSION
for (int fb = 0; fb < fallback_font_name.size(); fb++) {
const String &E = fallback_font_name[fb];
-#else
+#elif defined(GODOT_MODULE)
for (const String &E : fallback_font_name) {
#endif
SystemFontKey key = SystemFontKey(E, font_style & TextServer::FONT_ITALIC, font_weight, font_stretch, p_fdef, this);
diff --git a/modules/text_server_fb/text_server_fb.h b/modules/text_server_fb/text_server_fb.h
index 68e0cbff6c..2bb3724858 100644
--- a/modules/text_server_fb/text_server_fb.h
+++ b/modules/text_server_fb/text_server_fb.h
@@ -76,7 +76,7 @@
using namespace godot;
-#else
+#elif defined(GODOT_MODULE)
// Headers for building as built-in module.
#include "core/extension/ext_wrappers.gen.inc"
diff --git a/modules/text_server_fb/thorvg_bounds_iterator.cpp b/modules/text_server_fb/thorvg_bounds_iterator.cpp
index 807f356b83..d273eef97f 100644
--- a/modules/text_server_fb/thorvg_bounds_iterator.cpp
+++ b/modules/text_server_fb/thorvg_bounds_iterator.cpp
@@ -35,7 +35,7 @@
using namespace godot;
-#else
+#elif defined(GODOT_MODULE)
// Headers for building as built-in module.
#include "core/typedefs.h"
diff --git a/modules/text_server_fb/thorvg_bounds_iterator.h b/modules/text_server_fb/thorvg_bounds_iterator.h
index a44cbb99a7..afa2c13764 100644
--- a/modules/text_server_fb/thorvg_bounds_iterator.h
+++ b/modules/text_server_fb/thorvg_bounds_iterator.h
@@ -39,7 +39,7 @@
using namespace godot;
-#else
+#elif defined(GODOT_MODULE)
// Headers for building as built-in module.
#include "core/typedefs.h"
diff --git a/modules/text_server_fb/thorvg_svg_in_ot.cpp b/modules/text_server_fb/thorvg_svg_in_ot.cpp
index 7c8fedabc8..1ad33a88d4 100644
--- a/modules/text_server_fb/thorvg_svg_in_ot.cpp
+++ b/modules/text_server_fb/thorvg_svg_in_ot.cpp
@@ -38,7 +38,7 @@
using namespace godot;
-#else
+#elif defined(GODOT_MODULE)
// Headers for building as built-in module.
#include "core/error/error_macros.h"
diff --git a/modules/text_server_fb/thorvg_svg_in_ot.h b/modules/text_server_fb/thorvg_svg_in_ot.h
index 034fffb5e6..ce048674fd 100644
--- a/modules/text_server_fb/thorvg_svg_in_ot.h
+++ b/modules/text_server_fb/thorvg_svg_in_ot.h
@@ -40,7 +40,7 @@
using namespace godot;
-#else
+#elif defined(GODOT_MODULE)
// Headers for building as built-in module.
#include "core/os/mutex.h"
diff --git a/modules/zip/zip_packer.cpp b/modules/zip/zip_packer.cpp
index e67c65d4d1..e96d9da7a9 100644
--- a/modules/zip/zip_packer.cpp
+++ b/modules/zip/zip_packer.cpp
@@ -88,7 +88,7 @@ Error ZIPPacker::start_file(const String &p_path) {
Z_DEFAULT_STRATEGY,
nullptr,
0,
- 0x0314, // "version made by", 0x03 - Unix, 0x14 - ZIP specification version 2.0, required to store Unix file permissions.
+ 0, // "version made by", indicates the compatibility of the file attribute information (the `external_fa` field above).
1 << 11); // Bit 11 is the language encoding flag. When set, filename and comment fields must be encoded using UTF-8.
return err == ZIP_OK ? OK : FAILED;
}
diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp
index ee1ec2790d..e276048d40 100644
--- a/platform/android/export/export.cpp
+++ b/platform/android/export/export.cpp
@@ -48,6 +48,7 @@ void register_android_exporter() {
EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/android/debug_keystore", PROPERTY_HINT_GLOBAL_FILE, "*.keystore,*.jks"));
EDITOR_DEF("export/android/debug_keystore_user", "androiddebugkey");
EDITOR_DEF("export/android/debug_keystore_pass", "android");
+ EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/android/debug_keystore_pass", PROPERTY_HINT_PASSWORD));
EDITOR_DEF("export/android/force_system_user", false);
EDITOR_DEF("export/android/shutdown_adb_on_exit", true);
diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp
index 2bdf3073c9..762e5a8323 100644
--- a/platform/android/export/export_plugin.cpp
+++ b/platform/android/export/export_plugin.cpp
@@ -1823,10 +1823,10 @@ void EditorExportPlatformAndroid::get_export_options(List<ExportOption> *r_optio
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/debug", PROPERTY_HINT_GLOBAL_FILE, "*.keystore,*.jks", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/debug_user", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/debug_password", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/debug_password", PROPERTY_HINT_PASSWORD, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/release", PROPERTY_HINT_GLOBAL_FILE, "*.keystore,*.jks", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/release_user", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/release_password", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/release_password", PROPERTY_HINT_PASSWORD, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "version/code", PROPERTY_HINT_RANGE, "1,4096,1,or_greater"), 1));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "version/name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Leave empty to use project version"), ""));
diff --git a/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt b/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt
index 0d7017ae71..caf64bc933 100644
--- a/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt
+++ b/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt
@@ -91,6 +91,10 @@ open class GodotEditor : GodotActivity() {
private val commandLineParams = ArrayList<String>()
override fun onCreate(savedInstanceState: Bundle?) {
+ // We exclude certain permissions from the set we request at startup, as they'll be
+ // requested on demand based on use-cases.
+ PermissionsUtil.requestManifestPermissions(this, setOf(Manifest.permission.RECORD_AUDIO))
+
val params = intent.getStringArrayExtra(EXTRA_COMMAND_LINE_PARAMS)
Log.d(TAG, "Received parameters ${params.contentToString()}")
updateCommandLineParams(params)
diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotActivity.kt b/platform/android/java/lib/src/org/godotengine/godot/GodotActivity.kt
index a60f6e997e..e01c5481d5 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/GodotActivity.kt
+++ b/platform/android/java/lib/src/org/godotengine/godot/GodotActivity.kt
@@ -30,7 +30,6 @@
package org.godotengine.godot
-import android.Manifest
import android.app.Activity
import android.content.Intent
import android.content.pm.PackageManager
@@ -65,10 +64,6 @@ abstract class GodotActivity : FragmentActivity(), GodotHost {
private set
override fun onCreate(savedInstanceState: Bundle?) {
- // We exclude certain permissions from the set we request at startup, as they'll be
- // requested on demand based on use-cases.
- PermissionsUtil.requestManifestPermissions(this, setOf(Manifest.permission.RECORD_AUDIO))
-
super.onCreate(savedInstanceState)
setContentView(R.layout.godot_app_layout)
@@ -156,7 +151,8 @@ abstract class GodotActivity : FragmentActivity(), GodotHost {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
godotFragment?.onRequestPermissionsResult(requestCode, permissions, grantResults)
- if (requestCode == PermissionsUtil.REQUEST_ALL_PERMISSION_REQ_CODE) {
+ // Logging the result of permission requests
+ if (requestCode == PermissionsUtil.REQUEST_ALL_PERMISSION_REQ_CODE || requestCode == PermissionsUtil.REQUEST_SINGLE_PERMISSION_REQ_CODE) {
Log.d(TAG, "Received permissions request result..")
for (i in permissions.indices) {
val permissionGranted = grantResults[i] == PackageManager.PERMISSION_GRANTED
diff --git a/platform/android/java/lib/src/org/godotengine/godot/utils/PermissionsUtil.java b/platform/android/java/lib/src/org/godotengine/godot/utils/PermissionsUtil.java
index 9a82204467..737b4ac20b 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/utils/PermissionsUtil.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/utils/PermissionsUtil.java
@@ -56,9 +56,9 @@ import java.util.Set;
public final class PermissionsUtil {
private static final String TAG = PermissionsUtil.class.getSimpleName();
- static final int REQUEST_RECORD_AUDIO_PERMISSION = 1;
- static final int REQUEST_CAMERA_PERMISSION = 2;
- static final int REQUEST_VIBRATE_PERMISSION = 3;
+ public static final int REQUEST_RECORD_AUDIO_PERMISSION = 1;
+ public static final int REQUEST_CAMERA_PERMISSION = 2;
+ public static final int REQUEST_VIBRATE_PERMISSION = 3;
public static final int REQUEST_ALL_PERMISSION_REQ_CODE = 1001;
public static final int REQUEST_SINGLE_PERMISSION_REQ_CODE = 1002;
public static final int REQUEST_MANAGE_EXTERNAL_STORAGE_REQ_CODE = 2002;
@@ -70,7 +70,7 @@ public final class PermissionsUtil {
* Request a dangerous permission. name must be specified in <a href="https://github.com/aosp-mirror/platform_frameworks_base/blob/master/core/res/AndroidManifest.xml">this</a>
* @param permissionName the name of the requested permission.
* @param activity the caller activity for this method.
- * @return true/false. "true" if permission was granted otherwise returns "false".
+ * @return true/false. "true" if permission is already granted, "false" if a permission request was dispatched.
*/
public static boolean requestPermission(String permissionName, Activity activity) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
@@ -124,7 +124,7 @@ public final class PermissionsUtil {
/**
* Request dangerous permissions which are defined in the Android manifest file from the user.
* @param activity the caller activity for this method.
- * @return true/false. "true" if all permissions were granted otherwise returns "false".
+ * @return true/false. "true" if all permissions were already granted, returns "false" if permissions requests were dispatched.
*/
public static boolean requestManifestPermissions(Activity activity) {
return requestManifestPermissions(activity, null);
@@ -134,7 +134,7 @@ public final class PermissionsUtil {
* Request dangerous permissions which are defined in the Android manifest file from the user.
* @param activity the caller activity for this method.
* @param excludes Set of permissions to exclude from the request
- * @return true/false. "true" if all permissions were granted otherwise returns "false".
+ * @return true/false. "true" if all permissions were already granted, returns "false" if permissions requests were dispatched.
*/
public static boolean requestManifestPermissions(Activity activity, @Nullable Set<String> excludes) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
@@ -235,7 +235,7 @@ public final class PermissionsUtil {
/**
* Check if the given permission is in the AndroidManifest.xml file.
* @param context the caller context for this method.
- * @param permission the permession to look for in the manifest file.
+ * @param permission the permission to look for in the manifest file.
* @return "true" if the permission is in the manifest file of the activity, "false" otherwise.
*/
public static boolean hasManifestPermission(Context context, String permission) {
diff --git a/platform/android/java_godot_lib_jni.cpp b/platform/android/java_godot_lib_jni.cpp
index 50075ed3f5..08e792cc04 100644
--- a/platform/android/java_godot_lib_jni.cpp
+++ b/platform/android/java_godot_lib_jni.cpp
@@ -484,7 +484,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_calldeferred(JNIEnv *
env->DeleteLocalRef(jobj);
}
- MessageQueue::get_singleton()->push_callp(obj, str_method, argptrs, count);
+ Callable(obj, str_method).call_deferredp(argptrs, count);
}
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_requestPermissionResult(JNIEnv *env, jclass clazz, jstring p_permission, jboolean p_result) {
diff --git a/platform/android/java_godot_wrapper.cpp b/platform/android/java_godot_wrapper.cpp
index 4e401e633e..3c950bb1b1 100644
--- a/platform/android/java_godot_wrapper.cpp
+++ b/platform/android/java_godot_wrapper.cpp
@@ -334,7 +334,7 @@ void GodotJavaWrapper::vibrate(int p_duration_ms) {
}
}
-int GodotJavaWrapper::create_new_godot_instance(List<String> args) {
+int GodotJavaWrapper::create_new_godot_instance(const List<String> &args) {
if (_create_new_godot_instance) {
JNIEnv *env = get_jni_env();
ERR_FAIL_NULL_V(env, 0);
diff --git a/platform/android/java_godot_wrapper.h b/platform/android/java_godot_wrapper.h
index 52043c6027..93998021a9 100644
--- a/platform/android/java_godot_wrapper.h
+++ b/platform/android/java_godot_wrapper.h
@@ -104,7 +104,7 @@ public:
void init_input_devices();
void vibrate(int p_duration_ms);
String get_input_fallback_mapping();
- int create_new_godot_instance(List<String> args);
+ int create_new_godot_instance(const List<String> &args);
void begin_benchmark_measure(const String &p_context, const String &p_label);
void end_benchmark_measure(const String &p_context, const String &p_label);
void dump_benchmark(const String &benchmark_file);
diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp
index 35d4222152..0d82bec75d 100644
--- a/platform/android/os_android.cpp
+++ b/platform/android/os_android.cpp
@@ -170,8 +170,6 @@ Error OS_Android::open_dynamic_library(const String p_path, void *&p_library_han
so_file_exists = false;
}
- ERR_FAIL_COND_V(!FileAccess::exists(path), ERR_FILE_NOT_FOUND);
-
p_library_handle = dlopen(path.utf8().get_data(), RTLD_NOW);
if (!p_library_handle && so_file_exists) {
// The library may be on the sdcard and thus inaccessible. Try to copy it to the internal
diff --git a/platform/ios/SCsub b/platform/ios/SCsub
index 18ba6617af..30d4216464 100644
--- a/platform/ios/SCsub
+++ b/platform/ios/SCsub
@@ -20,6 +20,7 @@ ios_lib = [
"device_metrics.m",
"keyboard_input_view.mm",
"key_mapping_ios.mm",
+ "ios_terminal_logger.mm",
]
env_ios = env.Clone()
diff --git a/platform/ios/doc_classes/EditorExportPlatformIOS.xml b/platform/ios/doc_classes/EditorExportPlatformIOS.xml
index 588b20669b..35ef6d6a78 100644
--- a/platform/ios/doc_classes/EditorExportPlatformIOS.xml
+++ b/platform/ios/doc_classes/EditorExportPlatformIOS.xml
@@ -10,6 +10,13 @@
<link title="iOS plugins documentation index">$DOCS_URL/tutorials/platform/ios/index.html</link>
</tutorials>
<members>
+ <member name="application/additional_plist_content" type="String" setter="" getter="">
+ Additional data added to the root [code]&lt;dict&gt;[/code] section of the [url=https://developer.apple.com/documentation/bundleresources/information_property_list]Info.plist[/url] file. The value should be an XML section with pairs of key-value elements, e.g.:
+ [codeblock]
+ &lt;key&gt;key_name&lt;/key&gt;
+ &lt;string&gt;value&lt;/string&gt;
+ [/codeblock]
+ </member>
<member name="application/app_store_team_id" type="String" setter="" getter="">
Apple Team ID, unique 10-character string. To locate your Team ID check "Membership details" section in your Apple developer account dashboard, or "Organizational Unit" of your code signing certificate. See [url=https://developer.apple.com/help/account/manage-your-team/locate-your-team-id]Locate your Team ID[/url].
</member>
diff --git a/platform/ios/export/export_plugin.cpp b/platform/ios/export/export_plugin.cpp
index 5be4d21411..6943f0c637 100644
--- a/platform/ios/export/export_plugin.cpp
+++ b/platform/ios/export/export_plugin.cpp
@@ -34,6 +34,7 @@
#include "run_icon_svg.gen.h"
#include "core/io/json.h"
+#include "core/io/plist.h"
#include "core/string/translation.h"
#include "editor/editor_node.h"
#include "editor/editor_paths.h"
@@ -154,6 +155,8 @@ void EditorExportPlatformIOS::get_export_options(List<ExportOption> *r_options)
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/min_ios_version"), "12.0"));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/additional_plist_content", PROPERTY_HINT_MULTILINE_TEXT), ""));
+
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/icon_interpolation", PROPERTY_HINT_ENUM, "Nearest neighbor,Bilinear,Cubic,Trilinear,Lanczos"), 4));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "application/export_project_only"), false));
@@ -231,8 +234,8 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_
};
String dbg_sign_id = p_preset->get("application/code_sign_identity_debug").operator String().is_empty() ? "iPhone Developer" : p_preset->get("application/code_sign_identity_debug");
String rel_sign_id = p_preset->get("application/code_sign_identity_release").operator String().is_empty() ? "iPhone Distribution" : p_preset->get("application/code_sign_identity_release");
- bool dbg_manual = !p_preset->get_or_env("application/provisioning_profile_uuid_debug", ENV_IOS_PROFILE_UUID_DEBUG).operator String().is_empty() || (dbg_sign_id != "iPhone Developer");
- bool rel_manual = !p_preset->get_or_env("application/provisioning_profile_uuid_release", ENV_IOS_PROFILE_UUID_RELEASE).operator String().is_empty() || (rel_sign_id != "iPhone Distribution");
+ bool dbg_manual = !p_preset->get_or_env("application/provisioning_profile_uuid_debug", ENV_IOS_PROFILE_UUID_DEBUG).operator String().is_empty() || (dbg_sign_id != "iPhone Developer" && dbg_sign_id != "iPhone Distribution");
+ bool rel_manual = !p_preset->get_or_env("application/provisioning_profile_uuid_release", ENV_IOS_PROFILE_UUID_RELEASE).operator String().is_empty() || (rel_sign_id != "iPhone Developer" && rel_sign_id != "iPhone Distribution");
String str;
String strnew;
str.parse_utf8((const char *)pfile.ptr(), pfile.size());
@@ -865,7 +868,183 @@ struct ExportLibsData {
String dest_dir;
};
-void EditorExportPlatformIOS::_add_assets_to_project(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &p_project_data, const Vector<IOSExportAsset> &p_additional_assets) {
+void EditorExportPlatformIOS::_check_xcframework_content(const String &p_path, int &r_total_libs, int &r_static_libs, int &r_dylibs, int &r_frameworks) const {
+ Ref<PList> plist;
+ plist.instantiate();
+ plist->load_file(p_path.path_join("Info.plist"));
+ Ref<PListNode> root_node = plist->get_root();
+ if (root_node.is_null()) {
+ return;
+ }
+ Dictionary root = root_node->get_value();
+ if (!root.has("AvailableLibraries")) {
+ return;
+ }
+ Ref<PListNode> libs_node = root["AvailableLibraries"];
+ if (libs_node.is_null()) {
+ return;
+ }
+ Array libs = libs_node->get_value();
+ r_total_libs = libs.size();
+ for (int j = 0; j < libs.size(); j++) {
+ Ref<PListNode> lib_node = libs[j];
+ if (lib_node.is_null()) {
+ return;
+ }
+ Dictionary lib = lib_node->get_value();
+ if (lib.has("BinaryPath")) {
+ Ref<PListNode> path_node = lib["BinaryPath"];
+ if (path_node.is_valid()) {
+ String path = path_node->get_value();
+ if (path.ends_with(".a")) {
+ r_static_libs++;
+ }
+ if (path.ends_with(".dylib")) {
+ r_dylibs++;
+ }
+ if (path.ends_with(".framework")) {
+ r_frameworks++;
+ }
+ }
+ }
+ }
+}
+
+Error EditorExportPlatformIOS::_convert_to_framework(const String &p_source, const String &p_destination, const String &p_id) const {
+ print_line("Converting to .framework", p_source, " -> ", p_destination);
+
+ Ref<DirAccess> da = DirAccess::create_for_path(p_source);
+ if (da.is_null()) {
+ return ERR_CANT_OPEN;
+ }
+
+ Ref<DirAccess> filesystem_da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ if (filesystem_da.is_null()) {
+ return ERR_CANT_OPEN;
+ }
+
+ if (!filesystem_da->dir_exists(p_destination)) {
+ Error make_dir_err = filesystem_da->make_dir_recursive(p_destination);
+ if (make_dir_err) {
+ return make_dir_err;
+ }
+ }
+
+ String asset = p_source.ends_with("/") ? p_source.left(p_source.length() - 1) : p_source;
+ if (asset.ends_with(".xcframework")) {
+ Ref<PList> plist;
+ plist.instantiate();
+ plist->load_file(p_source.path_join("Info.plist"));
+ Ref<PListNode> root_node = plist->get_root();
+ if (root_node.is_null()) {
+ return ERR_CANT_OPEN;
+ }
+ Dictionary root = root_node->get_value();
+ if (!root.has("AvailableLibraries")) {
+ return ERR_CANT_OPEN;
+ }
+ Ref<PListNode> libs_node = root["AvailableLibraries"];
+ if (libs_node.is_null()) {
+ return ERR_CANT_OPEN;
+ }
+ Array libs = libs_node->get_value();
+ for (int j = 0; j < libs.size(); j++) {
+ Ref<PListNode> lib_node = libs[j];
+ if (lib_node.is_null()) {
+ return ERR_CANT_OPEN;
+ }
+ Dictionary lib = lib_node->get_value();
+ if (lib.has("BinaryPath") && lib.has("LibraryPath") && lib.has("LibraryIdentifier")) {
+ Ref<PListNode> bpath_node = lib["BinaryPath"];
+ Ref<PListNode> lpath_node = lib["LibraryPath"];
+ Ref<PListNode> lid_node = lib["LibraryIdentifier"];
+ if (bpath_node.is_valid() && lpath_node.is_valid() && lid_node.is_valid()) {
+ String binary_path = bpath_node->get_value();
+ String library_identifier = lid_node->get_value();
+
+ String file_name = binary_path.get_basename().get_file();
+ String framework_name = file_name + ".framework";
+
+ bpath_node->data_string = framework_name.utf8();
+ lpath_node->data_string = framework_name.utf8();
+ if (!filesystem_da->dir_exists(p_destination.path_join(library_identifier))) {
+ filesystem_da->make_dir_recursive(p_destination.path_join(library_identifier));
+ }
+ _convert_to_framework(p_source.path_join(library_identifier).path_join(binary_path), p_destination.path_join(library_identifier).path_join(framework_name), p_id);
+ if (lib.has("DebugSymbolsPath")) {
+ Ref<PListNode> dpath_node = lib["DebugSymbolsPath"];
+ if (dpath_node.is_valid()) {
+ String dpath = dpath_node->get_value();
+ if (da->dir_exists(p_source.path_join(library_identifier).path_join(dpath))) {
+ da->copy_dir(p_source.path_join(library_identifier).path_join(dpath), p_destination.path_join(library_identifier).path_join("dSYMs"));
+ }
+ }
+ }
+ }
+ }
+ }
+ String info_plist = plist->save_text();
+
+ Ref<FileAccess> f = FileAccess::open(p_destination.path_join("Info.plist"), FileAccess::WRITE);
+ if (f.is_valid()) {
+ f->store_string(info_plist);
+ }
+ } else {
+ String file_name = p_destination.get_basename().get_file();
+ String framework_name = file_name + ".framework";
+
+ da->copy(p_source, p_destination.path_join(file_name));
+
+ // Performing `install_name_tool -id @rpath/{name}.framework/{name} ./{name}` on dylib
+ {
+ List<String> install_name_args;
+ install_name_args.push_back("-id");
+ install_name_args.push_back(String("@rpath").path_join(framework_name).path_join(file_name));
+ install_name_args.push_back(p_destination.path_join(file_name));
+
+ OS::get_singleton()->execute("install_name_tool", install_name_args);
+ }
+
+ // Creating Info.plist
+ {
+ String info_plist_format = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"
+ "<plist version=\"1.0\">\n"
+ " <dict>\n"
+ " <key>CFBundleShortVersionString</key>\n"
+ " <string>1.0</string>\n"
+ " <key>CFBundleIdentifier</key>\n"
+ " <string>$id.framework.$name</string>\n"
+ " <key>CFBundleName</key>\n"
+ " <string>$name</string>\n"
+ " <key>CFBundleExecutable</key>\n"
+ " <string>$name</string>\n"
+ " <key>DTPlatformName</key>\n"
+ " <string>iphoneos</string>\n"
+ " <key>CFBundleInfoDictionaryVersion</key>\n"
+ " <string>6.0</string>\n"
+ " <key>CFBundleVersion</key>\n"
+ " <string>1</string>\n"
+ " <key>CFBundlePackageType</key>\n"
+ " <string>FMWK</string>\n"
+ " <key>MinimumOSVersion</key>\n"
+ " <string>12.0</string>\n"
+ " </dict>\n"
+ "</plist>";
+
+ String info_plist = info_plist_format.replace("$id", p_id).replace("$name", file_name);
+
+ Ref<FileAccess> f = FileAccess::open(p_destination.path_join("Info.plist"), FileAccess::WRITE);
+ if (f.is_valid()) {
+ f->store_string(info_plist);
+ }
+ }
+ }
+
+ return OK;
+}
+
+void EditorExportPlatformIOS::_add_assets_to_project(const String &p_out_dir, const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &p_project_data, const Vector<IOSExportAsset> &p_additional_assets) {
// that is just a random number, we just need Godot IDs not to clash with
// existing IDs in the project.
PbxId current_id = { 0x58938401, 0, 0 };
@@ -890,7 +1069,12 @@ void EditorExportPlatformIOS::_add_assets_to_project(const Ref<EditorExportPrese
String type;
if (asset.exported_path.ends_with(".framework")) {
- if (asset.should_embed) {
+ int total_libs = 0;
+ int static_libs = 0;
+ int dylibs = 0;
+ int frameworks = 0;
+ _check_xcframework_content(p_out_dir.path_join(asset.exported_path), total_libs, static_libs, dylibs, frameworks);
+ if (asset.should_embed && (static_libs != total_libs)) {
additional_asset_info_format += "$framework_id = {isa = PBXBuildFile; fileRef = $ref_id; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };\n";
framework_id = (++current_id).str();
pbx_embeded_frameworks += framework_id + ",\n";
@@ -953,12 +1137,12 @@ void EditorExportPlatformIOS::_add_assets_to_project(const Ref<EditorExportPrese
}
}
-Error EditorExportPlatformIOS::_copy_asset(const String &p_out_dir, const String &p_asset, const String *p_custom_file_name, bool p_is_framework, bool p_should_embed, Vector<IOSExportAsset> &r_exported_assets) {
+Error EditorExportPlatformIOS::_copy_asset(const Ref<EditorExportPreset> &p_preset, const String &p_out_dir, const String &p_asset, const String *p_custom_file_name, bool p_is_framework, bool p_should_embed, Vector<IOSExportAsset> &r_exported_assets) {
String binary_name = p_out_dir.get_file().get_basename();
Ref<DirAccess> da = DirAccess::create_for_path(p_asset);
if (da.is_null()) {
- ERR_FAIL_V_MSG(ERR_CANT_CREATE, "Can't create directory: " + p_asset + ".");
+ ERR_FAIL_V_MSG(ERR_CANT_CREATE, "Can't open directory: " + p_asset + ".");
}
bool file_exists = da->file_exists(p_asset);
bool dir_exists = da->dir_exists(p_asset);
@@ -972,7 +1156,8 @@ Error EditorExportPlatformIOS::_copy_asset(const String &p_out_dir, const String
String destination;
String asset_path;
- bool create_framework = false;
+ Ref<DirAccess> filesystem_da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ ERR_FAIL_COND_V_MSG(filesystem_da.is_null(), ERR_CANT_CREATE, "Cannot create DirAccess for path '" + p_out_dir + "'.");
if (p_is_framework && asset.ends_with(".dylib")) {
// For iOS we need to turn .dylib into .framework
@@ -992,10 +1177,23 @@ Error EditorExportPlatformIOS::_copy_asset(const String &p_out_dir, const String
asset_path = asset_path.path_join(framework_name);
destination_dir = p_out_dir.path_join(asset_path);
destination = destination_dir.path_join(file_name);
- create_framework = true;
- } else if (p_is_framework && (asset.ends_with(".framework") || asset.ends_with(".xcframework"))) {
- asset_path = String("dylibs").path_join(base_dir);
+ // Convert to framework and copy.
+ Error err = _convert_to_framework(p_asset, destination, p_preset->get("application/bundle_identifier"));
+ if (err) {
+ return err;
+ }
+ } else if (p_is_framework && asset.ends_with(".xcframework")) {
+ // For iOS we need to turn .dylib inside .xcframework
+ // into .framework to be able to send application to AppStore
+
+ int total_libs = 0;
+ int static_libs = 0;
+ int dylibs = 0;
+ int frameworks = 0;
+ _check_xcframework_content(p_asset, total_libs, static_libs, dylibs, frameworks);
+
+ asset_path = String("dylibs").path_join(base_dir);
String file_name;
if (!p_custom_file_name) {
@@ -1007,8 +1205,29 @@ Error EditorExportPlatformIOS::_copy_asset(const String &p_out_dir, const String
asset_path = asset_path.path_join(file_name);
destination_dir = p_out_dir.path_join(asset_path);
destination = destination_dir;
- } else {
- asset_path = base_dir;
+
+ if (dylibs > 0) {
+ // Convert to framework and copy.
+ Error err = _convert_to_framework(p_asset, destination, p_preset->get("application/bundle_identifier"));
+ if (err) {
+ return err;
+ }
+ } else {
+ // Copy as is.
+ if (!filesystem_da->dir_exists(destination_dir)) {
+ Error make_dir_err = filesystem_da->make_dir_recursive(destination_dir);
+ if (make_dir_err) {
+ return make_dir_err;
+ }
+ }
+ Error err = dir_exists ? da->copy_dir(p_asset, destination) : da->copy(p_asset, destination);
+ if (err) {
+ return err;
+ }
+ }
+ } else if (p_is_framework && asset.ends_with(".framework")) {
+ // Framework.
+ asset_path = String("dylibs").path_join(base_dir);
String file_name;
@@ -1018,99 +1237,67 @@ Error EditorExportPlatformIOS::_copy_asset(const String &p_out_dir, const String
file_name = *p_custom_file_name;
}
- destination_dir = p_out_dir.path_join(asset_path);
asset_path = asset_path.path_join(file_name);
- destination = p_out_dir.path_join(asset_path);
- }
-
- Ref<DirAccess> filesystem_da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
- ERR_FAIL_COND_V_MSG(filesystem_da.is_null(), ERR_CANT_CREATE, "Cannot create DirAccess for path '" + p_out_dir + "'.");
+ destination_dir = p_out_dir.path_join(asset_path);
+ destination = destination_dir;
- if (!filesystem_da->dir_exists(destination_dir)) {
- Error make_dir_err = filesystem_da->make_dir_recursive(destination_dir);
- if (make_dir_err) {
- return make_dir_err;
+ // Copy as is.
+ if (!filesystem_da->dir_exists(destination_dir)) {
+ Error make_dir_err = filesystem_da->make_dir_recursive(destination_dir);
+ if (make_dir_err) {
+ return make_dir_err;
+ }
}
- }
-
- Error err = dir_exists ? da->copy_dir(p_asset, destination) : da->copy(p_asset, destination);
- if (err) {
- return err;
- }
- if (asset_path.ends_with("/")) {
- asset_path = asset_path.left(asset_path.length() - 1);
- }
- IOSExportAsset exported_asset = { binary_name.path_join(asset_path), p_is_framework, p_should_embed };
- r_exported_assets.push_back(exported_asset);
+ Error err = dir_exists ? da->copy_dir(p_asset, destination) : da->copy(p_asset, destination);
+ if (err) {
+ return err;
+ }
+ } else {
+ // Unknown resource.
+ asset_path = base_dir;
- if (create_framework) {
String file_name;
if (!p_custom_file_name) {
- file_name = p_asset.get_basename().get_file();
+ file_name = p_asset.get_file();
} else {
file_name = *p_custom_file_name;
}
- String framework_name = file_name + ".framework";
-
- // Performing `install_name_tool -id @rpath/{name}.framework/{name} ./{name}` on dylib
- {
- List<String> install_name_args;
- install_name_args.push_back("-id");
- install_name_args.push_back(String("@rpath").path_join(framework_name).path_join(file_name));
- install_name_args.push_back(destination);
-
- OS::get_singleton()->execute("install_name_tool", install_name_args);
- }
-
- // Creating Info.plist
- {
- String info_plist_format = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
- "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"
- "<plist version=\"1.0\">\n"
- "<dict>\n"
- "<key>CFBundleShortVersionString</key>\n"
- "<string>1.0</string>\n"
- "<key>CFBundleIdentifier</key>\n"
- "<string>com.gdextension.framework.$name</string>\n"
- "<key>CFBundleName</key>\n"
- "<string>$name</string>\n"
- "<key>CFBundleExecutable</key>\n"
- "<string>$name</string>\n"
- "<key>DTPlatformName</key>\n"
- "<string>iphoneos</string>\n"
- "<key>CFBundleInfoDictionaryVersion</key>\n"
- "<string>6.0</string>\n"
- "<key>CFBundleVersion</key>\n"
- "<string>1</string>\n"
- "<key>CFBundlePackageType</key>\n"
- "<string>FMWK</string>\n"
- "<key>MinimumOSVersion</key>\n"
- "<string>10.0</string>\n"
- "</dict>\n"
- "</plist>";
-
- String info_plist = info_plist_format.replace("$name", file_name);
+ destination_dir = p_out_dir.path_join(asset_path);
+ asset_path = asset_path.path_join(file_name);
+ destination = p_out_dir.path_join(asset_path);
- Ref<FileAccess> f = FileAccess::open(destination_dir.path_join("Info.plist"), FileAccess::WRITE);
- if (f.is_valid()) {
- f->store_string(info_plist);
+ // Copy as is.
+ if (!filesystem_da->dir_exists(destination_dir)) {
+ Error make_dir_err = filesystem_da->make_dir_recursive(destination_dir);
+ if (make_dir_err) {
+ return make_dir_err;
}
}
+ Error err = dir_exists ? da->copy_dir(p_asset, destination) : da->copy(p_asset, destination);
+ if (err) {
+ return err;
+ }
+ }
+
+ if (asset_path.ends_with("/")) {
+ asset_path = asset_path.left(asset_path.length() - 1);
}
+ IOSExportAsset exported_asset = { binary_name.path_join(asset_path), p_is_framework, p_should_embed };
+ r_exported_assets.push_back(exported_asset);
return OK;
}
-Error EditorExportPlatformIOS::_export_additional_assets(const String &p_out_dir, const Vector<String> &p_assets, bool p_is_framework, bool p_should_embed, Vector<IOSExportAsset> &r_exported_assets) {
+Error EditorExportPlatformIOS::_export_additional_assets(const Ref<EditorExportPreset> &p_preset, const String &p_out_dir, const Vector<String> &p_assets, bool p_is_framework, bool p_should_embed, Vector<IOSExportAsset> &r_exported_assets) {
for (int f_idx = 0; f_idx < p_assets.size(); ++f_idx) {
const String &asset = p_assets[f_idx];
if (asset.begins_with("res://")) {
- Error err = _copy_asset(p_out_dir, asset, nullptr, p_is_framework, p_should_embed, r_exported_assets);
+ Error err = _copy_asset(p_preset, p_out_dir, asset, nullptr, p_is_framework, p_should_embed, r_exported_assets);
ERR_FAIL_COND_V(err != OK, err);
} else if (ProjectSettings::get_singleton()->localize_path(asset).begins_with("res://")) {
- Error err = _copy_asset(p_out_dir, ProjectSettings::get_singleton()->localize_path(asset), nullptr, p_is_framework, p_should_embed, r_exported_assets);
+ Error err = _copy_asset(p_preset, p_out_dir, ProjectSettings::get_singleton()->localize_path(asset), nullptr, p_is_framework, p_should_embed, r_exported_assets);
ERR_FAIL_COND_V(err != OK, err);
} else {
// either SDK-builtin or already a part of the export template
@@ -1122,26 +1309,26 @@ Error EditorExportPlatformIOS::_export_additional_assets(const String &p_out_dir
return OK;
}
-Error EditorExportPlatformIOS::_export_additional_assets(const String &p_out_dir, const Vector<SharedObject> &p_libraries, Vector<IOSExportAsset> &r_exported_assets) {
+Error EditorExportPlatformIOS::_export_additional_assets(const Ref<EditorExportPreset> &p_preset, const String &p_out_dir, const Vector<SharedObject> &p_libraries, Vector<IOSExportAsset> &r_exported_assets) {
Vector<Ref<EditorExportPlugin>> export_plugins = EditorExport::get_singleton()->get_export_plugins();
for (int i = 0; i < export_plugins.size(); i++) {
Vector<String> linked_frameworks = export_plugins[i]->get_ios_frameworks();
- Error err = _export_additional_assets(p_out_dir, linked_frameworks, true, false, r_exported_assets);
+ Error err = _export_additional_assets(p_preset, p_out_dir, linked_frameworks, true, false, r_exported_assets);
ERR_FAIL_COND_V(err, err);
Vector<String> embedded_frameworks = export_plugins[i]->get_ios_embedded_frameworks();
- err = _export_additional_assets(p_out_dir, embedded_frameworks, true, true, r_exported_assets);
+ err = _export_additional_assets(p_preset, p_out_dir, embedded_frameworks, true, true, r_exported_assets);
ERR_FAIL_COND_V(err, err);
Vector<String> project_static_libs = export_plugins[i]->get_ios_project_static_libs();
for (int j = 0; j < project_static_libs.size(); j++) {
project_static_libs.write[j] = project_static_libs[j].get_file(); // Only the file name as it's copied to the project
}
- err = _export_additional_assets(p_out_dir, project_static_libs, true, false, r_exported_assets);
+ err = _export_additional_assets(p_preset, p_out_dir, project_static_libs, true, false, r_exported_assets);
ERR_FAIL_COND_V(err, err);
Vector<String> ios_bundle_files = export_plugins[i]->get_ios_bundle_files();
- err = _export_additional_assets(p_out_dir, ios_bundle_files, false, false, r_exported_assets);
+ err = _export_additional_assets(p_preset, p_out_dir, ios_bundle_files, false, false, r_exported_assets);
ERR_FAIL_COND_V(err, err);
}
@@ -1149,7 +1336,7 @@ Error EditorExportPlatformIOS::_export_additional_assets(const String &p_out_dir
for (int i = 0; i < p_libraries.size(); ++i) {
library_paths.push_back(p_libraries[i].path);
}
- Error err = _export_additional_assets(p_out_dir, library_paths, true, true, r_exported_assets);
+ Error err = _export_additional_assets(p_preset, p_out_dir, library_paths, true, true, r_exported_assets);
ERR_FAIL_COND_V(err, err);
return OK;
@@ -1194,7 +1381,7 @@ Error EditorExportPlatformIOS::_export_ios_plugins(const Ref<EditorExportPreset>
String plugin_binary_result_file = plugin.binary.get_file();
// We shouldn't embed .xcframework that contains static libraries.
// Static libraries are not embedded anyway.
- err = _copy_asset(dest_dir, plugin_main_binary, &plugin_binary_result_file, true, false, r_exported_assets);
+ err = _copy_asset(p_preset, dest_dir, plugin_main_binary, &plugin_binary_result_file, true, false, r_exported_assets);
ERR_FAIL_COND_V(err != OK, err);
// Adding dependencies.
@@ -1319,15 +1506,15 @@ Error EditorExportPlatformIOS::_export_ios_plugins(const Ref<EditorExportPreset>
// Export files
{
// Export linked plugin dependency
- err = _export_additional_assets(dest_dir, plugin_linked_dependencies, true, false, r_exported_assets);
+ err = _export_additional_assets(p_preset, dest_dir, plugin_linked_dependencies, true, false, r_exported_assets);
ERR_FAIL_COND_V(err != OK, err);
// Export embedded plugin dependency
- err = _export_additional_assets(dest_dir, plugin_embedded_dependencies, true, true, r_exported_assets);
+ err = _export_additional_assets(p_preset, dest_dir, plugin_embedded_dependencies, true, true, r_exported_assets);
ERR_FAIL_COND_V(err != OK, err);
// Export plugin files
- err = _export_additional_assets(dest_dir, plugin_files, false, false, r_exported_assets);
+ err = _export_additional_assets(p_preset, dest_dir, plugin_files, false, false, r_exported_assets);
ERR_FAIL_COND_V(err != OK, err);
}
@@ -1498,6 +1685,8 @@ Error EditorExportPlatformIOS::_export_project_helper(const Ref<EditorExportPres
false
};
+ config_data.plist_content += p_preset->get("application/additional_plist_content").operator String() + "\n";
+
Vector<IOSExportAsset> assets;
Ref<DirAccess> tmp_app_path = DirAccess::create_for_path(dest_dir);
@@ -1724,8 +1913,8 @@ Error EditorExportPlatformIOS::_export_project_helper(const Ref<EditorExportPres
}
print_line("Exporting additional assets");
- _export_additional_assets(binary_dir, libraries, assets);
- _add_assets_to_project(p_preset, project_file_data, assets);
+ _export_additional_assets(p_preset, binary_dir, libraries, assets);
+ _add_assets_to_project(dest_dir, p_preset, project_file_data, assets);
String project_file_name = binary_dir + ".xcodeproj/project.pbxproj";
{
Ref<FileAccess> f = FileAccess::open(project_file_name, FileAccess::WRITE);
@@ -1867,6 +2056,26 @@ bool EditorExportPlatformIOS::has_valid_export_configuration(const Ref<EditorExp
valid = dvalid || rvalid;
r_missing_templates = !valid;
+ const String &additional_plist_content = p_preset->get("application/additional_plist_content");
+ if (!additional_plist_content.is_empty()) {
+ const String &plist = vformat("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">"
+ "<plist version=\"1.0\">"
+ "<dict>\n"
+ "%s\n"
+ "</dict>\n"
+ "</plist>\n",
+ additional_plist_content);
+
+ String plist_err;
+ Ref<PList> plist_parser;
+ plist_parser.instantiate();
+ if (!plist_parser->load_string(plist, plist_err)) {
+ err += TTR("Invalid additional PList content: ") + plist_err + "\n";
+ valid = false;
+ }
+ }
+
if (!err.is_empty()) {
r_error = err;
}
diff --git a/platform/ios/export/export_plugin.h b/platform/ios/export/export_plugin.h
index 1f926c4d14..edbe566dab 100644
--- a/platform/ios/export/export_plugin.h
+++ b/platform/ios/export/export_plugin.h
@@ -133,10 +133,13 @@ class EditorExportPlatformIOS : public EditorExportPlatform {
Vector<ExportArchitecture> _get_supported_architectures() const;
Vector<String> _get_preset_architectures(const Ref<EditorExportPreset> &p_preset) const;
- void _add_assets_to_project(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &p_project_data, const Vector<IOSExportAsset> &p_additional_assets);
- Error _export_additional_assets(const String &p_out_dir, const Vector<String> &p_assets, bool p_is_framework, bool p_should_embed, Vector<IOSExportAsset> &r_exported_assets);
- Error _copy_asset(const String &p_out_dir, const String &p_asset, const String *p_custom_file_name, bool p_is_framework, bool p_should_embed, Vector<IOSExportAsset> &r_exported_assets);
- Error _export_additional_assets(const String &p_out_dir, const Vector<SharedObject> &p_libraries, Vector<IOSExportAsset> &r_exported_assets);
+ void _check_xcframework_content(const String &p_path, int &r_total_libs, int &r_static_libs, int &r_dylibs, int &r_frameworks) const;
+ Error _convert_to_framework(const String &p_source, const String &p_destination, const String &p_id) const;
+
+ void _add_assets_to_project(const String &p_out_dir, const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &p_project_data, const Vector<IOSExportAsset> &p_additional_assets);
+ Error _export_additional_assets(const Ref<EditorExportPreset> &p_preset, const String &p_out_dir, const Vector<String> &p_assets, bool p_is_framework, bool p_should_embed, Vector<IOSExportAsset> &r_exported_assets);
+ Error _copy_asset(const Ref<EditorExportPreset> &p_preset, const String &p_out_dir, const String &p_asset, const String *p_custom_file_name, bool p_is_framework, bool p_should_embed, Vector<IOSExportAsset> &r_exported_assets);
+ Error _export_additional_assets(const Ref<EditorExportPreset> &p_preset, const String &p_out_dir, const Vector<SharedObject> &p_libraries, Vector<IOSExportAsset> &r_exported_assets);
Error _export_ios_plugins(const Ref<EditorExportPreset> &p_preset, IOSConfigData &p_config_data, const String &dest_dir, Vector<IOSExportAsset> &r_exported_assets, bool p_debug);
Error _export_project_helper(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags, bool p_simulator, bool p_oneclick);
diff --git a/platform/ios/ios_terminal_logger.h b/platform/ios/ios_terminal_logger.h
new file mode 100644
index 0000000000..7f0bc37a07
--- /dev/null
+++ b/platform/ios/ios_terminal_logger.h
@@ -0,0 +1,45 @@
+/**************************************************************************/
+/* ios_terminal_logger.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef IOS_TERMINAL_LOGGER_H
+#define IOS_TERMINAL_LOGGER_H
+
+#ifdef IOS_ENABLED
+
+#include "core/io/logger.h"
+
+class IOSTerminalLogger : public StdLogger {
+public:
+ virtual void log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, bool p_editor_notify = false, ErrorType p_type = ERR_ERROR) override;
+};
+
+#endif // IOS_ENABLED
+
+#endif // IOS_TERMINAL_LOGGER_H
diff --git a/platform/ios/ios_terminal_logger.mm b/platform/ios/ios_terminal_logger.mm
new file mode 100644
index 0000000000..b4c9821cdc
--- /dev/null
+++ b/platform/ios/ios_terminal_logger.mm
@@ -0,0 +1,74 @@
+/**************************************************************************/
+/* ios_terminal_logger.mm */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#include "ios_terminal_logger.h"
+
+#ifdef IOS_ENABLED
+
+#include <os/log.h>
+
+void IOSTerminalLogger::log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, bool p_editor_notify, ErrorType p_type) {
+ if (!should_log(true)) {
+ return;
+ }
+
+ const char *err_details;
+ if (p_rationale && p_rationale[0]) {
+ err_details = p_rationale;
+ } else {
+ err_details = p_code;
+ }
+
+ switch (p_type) {
+ case ERR_WARNING:
+ os_log_info(OS_LOG_DEFAULT,
+ "WARNING: %{public}s\nat: %{public}s (%{public}s:%i)",
+ err_details, p_function, p_file, p_line);
+ break;
+ case ERR_SCRIPT:
+ os_log_error(OS_LOG_DEFAULT,
+ "SCRIPT ERROR: %{public}s\nat: %{public}s (%{public}s:%i)",
+ err_details, p_function, p_file, p_line);
+ break;
+ case ERR_SHADER:
+ os_log_error(OS_LOG_DEFAULT,
+ "SHADER ERROR: %{public}s\nat: %{public}s (%{public}s:%i)",
+ err_details, p_function, p_file, p_line);
+ break;
+ case ERR_ERROR:
+ default:
+ os_log_error(OS_LOG_DEFAULT,
+ "ERROR: %{public}s\nat: %{public}s (%{public}s:%i)",
+ err_details, p_function, p_file, p_line);
+ break;
+ }
+}
+
+#endif // IOS_ENABLED
diff --git a/platform/ios/os_ios.mm b/platform/ios/os_ios.mm
index 80f1f4a5c2..6ac21fa9c8 100644
--- a/platform/ios/os_ios.mm
+++ b/platform/ios/os_ios.mm
@@ -35,6 +35,7 @@
#import "app_delegate.h"
#import "display_server_ios.h"
#import "godot_view.h"
+#import "ios_terminal_logger.h"
#import "view_controller.h"
#include "core/config/project_settings.h"
@@ -105,12 +106,7 @@ OS_IOS::OS_IOS() {
main_loop = nullptr;
Vector<Logger *> loggers;
- loggers.push_back(memnew(SyslogLogger));
-#ifdef DEBUG_ENABLED
- // it seems iOS app's stdout/stderr is only obtainable if you launch it from
- // Xcode
- loggers.push_back(memnew(StdLogger));
-#endif
+ loggers.push_back(memnew(IOSTerminalLogger));
_set_logger(memnew(CompositeLogger(loggers)));
AudioDriverManager::add_driver(&audio_driver);
diff --git a/platform/linuxbsd/x11/display_server_x11.cpp b/platform/linuxbsd/x11/display_server_x11.cpp
index 1434342bbc..d8a81266d0 100644
--- a/platform/linuxbsd/x11/display_server_x11.cpp
+++ b/platform/linuxbsd/x11/display_server_x11.cpp
@@ -2891,10 +2891,15 @@ void DisplayServerX11::window_move_to_foreground(WindowID p_window) {
XFlush(x11_display);
}
+DisplayServerX11::WindowID DisplayServerX11::get_focused_window() const {
+ return last_focused_window;
+}
+
bool DisplayServerX11::window_is_focused(WindowID p_window) const {
_THREAD_SAFE_METHOD_
ERR_FAIL_COND_V(!windows.has(p_window), false);
+
const WindowData &wd = windows[p_window];
return wd.focused;
@@ -3875,7 +3880,7 @@ void DisplayServerX11::_xim_preedit_draw_callback(::XIM xim, ::XPointer client_d
ds->im_selection = Point2i();
}
- OS_Unix::get_singleton()->get_main_loop()->call_deferred(SNAME("notification"), MainLoop::NOTIFICATION_OS_IME_UPDATE);
+ callable_mp((Object *)OS_Unix::get_singleton()->get_main_loop(), &Object::notification).call_deferred(MainLoop::NOTIFICATION_OS_IME_UPDATE, false);
}
}
diff --git a/platform/linuxbsd/x11/display_server_x11.h b/platform/linuxbsd/x11/display_server_x11.h
index ac2c7843f6..378d8bb407 100644
--- a/platform/linuxbsd/x11/display_server_x11.h
+++ b/platform/linuxbsd/x11/display_server_x11.h
@@ -491,6 +491,8 @@ public:
virtual void window_move_to_foreground(WindowID p_window = MAIN_WINDOW_ID) override;
virtual bool window_is_focused(WindowID p_window = MAIN_WINDOW_ID) const override;
+ virtual WindowID get_focused_window() const override;
+
virtual bool window_can_draw(WindowID p_window = MAIN_WINDOW_ID) const override;
virtual bool can_any_window_draw() const override;
diff --git a/platform/macos/display_server_macos.h b/platform/macos/display_server_macos.h
index f8fd0f93ef..cc343a6d64 100644
--- a/platform/macos/display_server_macos.h
+++ b/platform/macos/display_server_macos.h
@@ -428,6 +428,8 @@ public:
virtual void window_move_to_foreground(WindowID p_window = MAIN_WINDOW_ID) override;
virtual bool window_is_focused(WindowID p_window = MAIN_WINDOW_ID) const override;
+ virtual WindowID get_focused_window() const override;
+
virtual bool window_can_draw(WindowID p_window = MAIN_WINDOW_ID) const override;
virtual bool can_any_window_draw() const override;
diff --git a/platform/macos/display_server_macos.mm b/platform/macos/display_server_macos.mm
index bd92b7d472..378688f78a 100644
--- a/platform/macos/display_server_macos.mm
+++ b/platform/macos/display_server_macos.mm
@@ -3723,6 +3723,10 @@ bool DisplayServerMacOS::window_is_focused(WindowID p_window) const {
return wd.focused;
}
+DisplayServerMacOS::WindowID DisplayServerMacOS::get_focused_window() const {
+ return last_focused_window;
+}
+
bool DisplayServerMacOS::window_can_draw(WindowID p_window) const {
return windows[p_window].is_visible;
}
diff --git a/platform/macos/doc_classes/EditorExportPlatformMacOS.xml b/platform/macos/doc_classes/EditorExportPlatformMacOS.xml
index 85fefe65c0..506b0dffb8 100644
--- a/platform/macos/doc_classes/EditorExportPlatformMacOS.xml
+++ b/platform/macos/doc_classes/EditorExportPlatformMacOS.xml
@@ -10,6 +10,13 @@
<link title="Running Godot apps on macOS">$DOCS_URL/tutorials//export/running_on_macos.html</link>
</tutorials>
<members>
+ <member name="application/additional_plist_content" type="String" setter="" getter="">
+ Additional data added to the root [code]&lt;dict&gt;[/code] section of the [url=https://developer.apple.com/documentation/bundleresources/information_property_list]Info.plist[/url] file. The value should be an XML section with pairs of key-value elements, e.g.:
+ [codeblock]
+ &lt;key&gt;key_name&lt;/key&gt;
+ &lt;string&gt;value&lt;/string&gt;
+ [/codeblock]
+ </member>
<member name="application/app_category" type="String" setter="" getter="">
Application category for the App Store.
</member>
diff --git a/platform/macos/export/codesign.cpp b/platform/macos/export/codesign.cpp
index 2b8898e6a1..082c0abea7 100644
--- a/platform/macos/export/codesign.cpp
+++ b/platform/macos/export/codesign.cpp
@@ -32,8 +32,8 @@
#include "lipo.h"
#include "macho.h"
-#include "plist.h"
+#include "core/io/plist.h"
#include "core/os/os.h"
#include "editor/editor_paths.h"
#include "editor/editor_settings.h"
diff --git a/platform/macos/export/codesign.h b/platform/macos/export/codesign.h
index 3e61751a96..49d53b376e 100644
--- a/platform/macos/export/codesign.h
+++ b/platform/macos/export/codesign.h
@@ -41,11 +41,10 @@
// - Requirements code generator is not implemented (only hard-coded requirements for the ad-hoc signing is supported).
// - RFC5652/CMS blob generation is not implemented, supports ad-hoc signing only.
-#include "plist.h"
-
#include "core/crypto/crypto_core.h"
#include "core/io/dir_access.h"
#include "core/io/file_access.h"
+#include "core/io/plist.h"
#include "core/object/ref_counted.h"
#include "modules/modules_enabled.gen.h" // For regex.
diff --git a/platform/macos/export/export_plugin.cpp b/platform/macos/export/export_plugin.cpp
index 6e750d0a16..c347082010 100644
--- a/platform/macos/export/export_plugin.cpp
+++ b/platform/macos/export/export_plugin.cpp
@@ -37,6 +37,7 @@
#include "run_icon_svg.gen.h"
#include "core/io/image_loader.h"
+#include "core/io/plist.h"
#include "core/string/translation.h"
#include "drivers/png/png_driver_common.h"
#include "editor/editor_node.h"
@@ -388,6 +389,8 @@ void EditorExportPlatformMacOS::get_export_options(List<ExportOption> *r_options
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/export_angle", PROPERTY_HINT_ENUM, "Auto,Yes,No"), 0, true));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "display/high_res"), true));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/additional_plist_content", PROPERTY_HINT_MULTILINE_TEXT), ""));
+
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "xcode/platform_build"), "14C18"));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "xcode/sdk_version"), "13.1"));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "xcode/sdk_build"), "22C55"));
@@ -672,6 +675,8 @@ void EditorExportPlatformMacOS::_fix_plist(const Ref<EditorExportPreset> &p_pres
strnew += lines[i].replace("$min_version", p_preset->get("application/min_macos_version")) + "\n";
} else if (lines[i].find("$highres") != -1) {
strnew += lines[i].replace("$highres", p_preset->get("display/high_res") ? "\t<true/>" : "\t<false/>") + "\n";
+ } else if (lines[i].find("$additional_plist_content") != -1) {
+ strnew += lines[i].replace("$additional_plist_content", p_preset->get("application/additional_plist_content")) + "\n";
} else if (lines[i].find("$platfbuild") != -1) {
strnew += lines[i].replace("$platfbuild", p_preset->get("xcode/platform_build")) + "\n";
} else if (lines[i].find("$sdkver") != -1) {
@@ -2095,6 +2100,26 @@ bool EditorExportPlatformMacOS::has_valid_project_configuration(const Ref<Editor
};
}
+ const String &additional_plist_content = p_preset->get("application/additional_plist_content");
+ if (!additional_plist_content.is_empty()) {
+ const String &plist = vformat("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">"
+ "<plist version=\"1.0\">"
+ "<dict>\n"
+ "%s\n"
+ "</dict>\n"
+ "</plist>\n",
+ additional_plist_content);
+
+ String plist_err;
+ Ref<PList> plist_parser;
+ plist_parser.instantiate();
+ if (!plist_parser->load_string(plist, plist_err)) {
+ err += TTR("Invalid additional PList content: ") + plist_err + "\n";
+ valid = false;
+ }
+ }
+
List<ExportOption> options;
get_export_options(&options);
for (const EditorExportPlatform::ExportOption &E : options) {
diff --git a/platform/web/export/export_plugin.cpp b/platform/web/export/export_plugin.cpp
index a70812cf5b..ee170280e2 100644
--- a/platform/web/export/export_plugin.cpp
+++ b/platform/web/export/export_plugin.cpp
@@ -112,7 +112,7 @@ Error EditorExportPlatformWeb::_write_or_error(const uint8_t *p_content, int p_s
return OK;
}
-void EditorExportPlatformWeb::_replace_strings(HashMap<String, String> p_replaces, Vector<uint8_t> &r_template) {
+void EditorExportPlatformWeb::_replace_strings(const HashMap<String, String> &p_replaces, Vector<uint8_t> &r_template) {
String str_template = String::utf8(reinterpret_cast<const char *>(r_template.ptr()), r_template.size());
String out;
Vector<String> lines = str_template.split("\n");
diff --git a/platform/web/export/export_plugin.h b/platform/web/export/export_plugin.h
index 887000ac45..9bb82d472e 100644
--- a/platform/web/export/export_plugin.h
+++ b/platform/web/export/export_plugin.h
@@ -90,7 +90,7 @@ class EditorExportPlatformWeb : public EditorExportPlatform {
}
Error _extract_template(const String &p_template, const String &p_dir, const String &p_name, bool pwa);
- void _replace_strings(HashMap<String, String> p_replaces, Vector<uint8_t> &r_template);
+ void _replace_strings(const HashMap<String, String> &p_replaces, Vector<uint8_t> &r_template);
void _fix_html(Vector<uint8_t> &p_html, const Ref<EditorExportPreset> &p_preset, const String &p_name, bool p_debug, int p_flags, const Vector<SharedObject> p_shared_objects, const Dictionary &p_file_sizes);
Error _add_manifest_icon(const String &p_path, const String &p_icon, int p_size, Array &r_arr);
Error _build_pwa(const Ref<EditorExportPreset> &p_preset, const String p_path, const Vector<SharedObject> &p_shared_objects);
diff --git a/platform/windows/SCsub b/platform/windows/SCsub
index 0549e408a7..1cfbc33ef8 100644
--- a/platform/windows/SCsub
+++ b/platform/windows/SCsub
@@ -3,6 +3,7 @@
Import("env")
import os
+from pathlib import Path
from platform_methods import run_in_subprocess
import platform_windows_builders
@@ -25,6 +26,19 @@ common_win_wrap = [
"console_wrapper_windows.cpp",
]
+
+def arrange_program_clean(prog):
+ """
+ Given an SCons program, arrange for output files SCons doesn't know about
+ to be cleaned when SCons is called with --clean
+ """
+ extensions_to_clean = [".ilk", ".exp", ".pdb", ".lib"]
+ for program in prog:
+ executable_stem = Path(program.name).stem
+ extra_files_to_clean = [f"#bin/{executable_stem}{extension}" for extension in extensions_to_clean]
+ Clean(prog, extra_files_to_clean)
+
+
res_file = "godot_res.rc"
res_target = "godot_res" + env["OBJSUFFIX"]
res_obj = env.RES(res_target, res_file)
@@ -32,6 +46,7 @@ res_obj = env.RES(res_target, res_file)
sources = common_win + res_obj
prog = env.add_program("#bin/godot", sources, PROGSUFFIX=env["PROGSUFFIX"])
+arrange_program_clean(prog)
# Build console wrapper app.
if env["windows_subsystem"] == "gui":
@@ -48,6 +63,7 @@ if env["windows_subsystem"] == "gui":
env_wrap.Append(LIBS=["version"])
prog_wrap = env_wrap.add_program("#bin/godot", common_win_wrap + res_wrap_obj, PROGSUFFIX=env["PROGSUFFIX_WRAP"])
+ arrange_program_clean(prog_wrap)
env_wrap.Depends(prog_wrap, prog)
# Microsoft Visual Studio Project Generation
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index a6c2cd7313..b56954ae81 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -1948,6 +1948,10 @@ bool DisplayServerWindows::window_is_focused(WindowID p_window) const {
return wd.window_focused;
}
+DisplayServerWindows::WindowID DisplayServerWindows::get_focused_window() const {
+ return last_focused_window;
+}
+
bool DisplayServerWindows::window_can_draw(WindowID p_window) const {
_THREAD_SAFE_METHOD_
diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h
index 29c2460c10..2668e14540 100644
--- a/platform/windows/display_server_windows.h
+++ b/platform/windows/display_server_windows.h
@@ -611,6 +611,8 @@ public:
virtual void window_move_to_foreground(WindowID p_window = MAIN_WINDOW_ID) override;
virtual bool window_is_focused(WindowID p_window = MAIN_WINDOW_ID) const override;
+ virtual WindowID get_focused_window() const override;
+
virtual bool window_can_draw(WindowID p_window = MAIN_WINDOW_ID) const override;
virtual bool can_any_window_draw() const override;
diff --git a/platform/windows/vulkan_context_win.h b/platform/windows/vulkan_context_win.h
index 29ab1d45c3..770a59de9e 100644
--- a/platform/windows/vulkan_context_win.h
+++ b/platform/windows/vulkan_context_win.h
@@ -39,7 +39,7 @@
#include <windows.h>
class VulkanContextWindows : public VulkanContext {
- virtual const char *_get_platform_surface_extension() const;
+ virtual const char *_get_platform_surface_extension() const override final;
public:
struct WindowPlatformData {
diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp
index 0f5fa6543e..08baa7e387 100644
--- a/scene/2d/camera_2d.cpp
+++ b/scene/2d/camera_2d.cpp
@@ -229,7 +229,7 @@ void Camera2D::_notification(int p_what) {
} break;
case NOTIFICATION_TRANSFORM_CHANGED: {
- if (!is_processing_internal() && !is_physics_processing_internal()) {
+ if (!position_smoothing_enabled || _is_editing_in_editor()) {
_update_scroll();
}
} break;
diff --git a/scene/2d/collision_object_2d.cpp b/scene/2d/collision_object_2d.cpp
index 2fbe4eb409..4e5852984b 100644
--- a/scene/2d/collision_object_2d.cpp
+++ b/scene/2d/collision_object_2d.cpp
@@ -523,30 +523,22 @@ void CollisionObject2D::_input_event_call(Viewport *p_viewport, const Ref<InputE
}
void CollisionObject2D::_mouse_enter() {
- if (get_script_instance()) {
- get_script_instance()->call(SceneStringNames::get_singleton()->_mouse_enter);
- }
+ GDVIRTUAL_CALL(_mouse_enter);
emit_signal(SceneStringNames::get_singleton()->mouse_entered);
}
void CollisionObject2D::_mouse_exit() {
- if (get_script_instance()) {
- get_script_instance()->call(SceneStringNames::get_singleton()->_mouse_exit);
- }
+ GDVIRTUAL_CALL(_mouse_exit);
emit_signal(SceneStringNames::get_singleton()->mouse_exited);
}
void CollisionObject2D::_mouse_shape_enter(int p_shape) {
- if (get_script_instance()) {
- get_script_instance()->call(SceneStringNames::get_singleton()->_mouse_shape_enter, p_shape);
- }
+ GDVIRTUAL_CALL(_mouse_shape_enter, p_shape);
emit_signal(SceneStringNames::get_singleton()->mouse_shape_entered, p_shape);
}
void CollisionObject2D::_mouse_shape_exit(int p_shape) {
- if (get_script_instance()) {
- get_script_instance()->call(SceneStringNames::get_singleton()->_mouse_shape_exit, p_shape);
- }
+ GDVIRTUAL_CALL(_mouse_shape_exit, p_shape);
emit_signal(SceneStringNames::get_singleton()->mouse_shape_exited, p_shape);
}
diff --git a/scene/2d/gpu_particles_2d.cpp b/scene/2d/gpu_particles_2d.cpp
index ee33ff88d4..71da9cc520 100644
--- a/scene/2d/gpu_particles_2d.cpp
+++ b/scene/2d/gpu_particles_2d.cpp
@@ -712,12 +712,15 @@ void GPUParticles2D::_notification(int p_what) {
} break;
case NOTIFICATION_INTERNAL_PROCESS: {
- RS::get_singleton()->particles_set_emitter_velocity(particles,
- Vector3((get_global_position() - previous_position).x,
- (get_global_position() - previous_position).y,
- 0.0) /
- get_process_delta_time());
+ const Vector3 velocity = Vector3((get_global_position() - previous_position).x, (get_global_position() - previous_position).y, 0.0) /
+ get_process_delta_time();
+
+ if (velocity != previous_velocity) {
+ RS::get_singleton()->particles_set_emitter_velocity(particles, velocity);
+ previous_velocity = velocity;
+ }
previous_position = get_global_position();
+
if (one_shot) {
time += get_process_delta_time();
if (time > emission_time) {
diff --git a/scene/2d/gpu_particles_2d.h b/scene/2d/gpu_particles_2d.h
index 40831cd30e..58996b0327 100644
--- a/scene/2d/gpu_particles_2d.h
+++ b/scene/2d/gpu_particles_2d.h
@@ -64,6 +64,7 @@ private:
bool fractional_delta = false;
bool interpolate = true;
float interp_to_end_factor = 0;
+ Vector3 previous_velocity;
Vector2 previous_position;
#ifdef TOOLS_ENABLED
bool show_visibility_rect = false;
diff --git a/scene/2d/light_2d.cpp b/scene/2d/light_2d.cpp
index 15b638ed92..c03786caef 100644
--- a/scene/2d/light_2d.cpp
+++ b/scene/2d/light_2d.cpp
@@ -425,6 +425,17 @@ real_t PointLight2D::get_texture_scale() const {
return _scale;
}
+#ifndef DISABLE_DEPRECATED
+bool PointLight2D::_set(const StringName &p_name, const Variant &p_value) {
+ if (p_name == "mode" && p_value.is_num()) { // Compatibility with Godot 3.x.
+ set_blend_mode((BlendMode)(int)p_value);
+ return true;
+ }
+
+ return false;
+}
+#endif // DISABLE_DEPRECATED
+
void PointLight2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_texture", "texture"), &PointLight2D::set_texture);
ClassDB::bind_method(D_METHOD("get_texture"), &PointLight2D::get_texture);
diff --git a/scene/2d/light_2d.h b/scene/2d/light_2d.h
index 6a454a421e..3c1171deae 100644
--- a/scene/2d/light_2d.h
+++ b/scene/2d/light_2d.h
@@ -146,6 +146,9 @@ private:
Vector2 texture_offset;
protected:
+#ifndef DISABLE_DEPRECATED
+ bool _set(const StringName &p_name, const Variant &p_value);
+#endif // DISABLE_DEPRECATED
static void _bind_methods();
public:
diff --git a/scene/2d/navigation_region_2d.cpp b/scene/2d/navigation_region_2d.cpp
index 8e4b6bfa19..00c0912690 100644
--- a/scene/2d/navigation_region_2d.cpp
+++ b/scene/2d/navigation_region_2d.cpp
@@ -245,7 +245,7 @@ void NavigationRegion2D::bake_navigation_polygon(bool p_on_thread) {
void NavigationRegion2D::_bake_finished(Ref<NavigationPolygon> p_navigation_polygon) {
if (!Thread::is_main_thread()) {
- call_deferred(SNAME("_bake_finished"), p_navigation_polygon);
+ callable_mp(this, &NavigationRegion2D::_bake_finished).call_deferred(p_navigation_polygon);
return;
}
diff --git a/scene/2d/polygon_2d.cpp b/scene/2d/polygon_2d.cpp
index ee186de5f1..4266060466 100644
--- a/scene/2d/polygon_2d.cpp
+++ b/scene/2d/polygon_2d.cpp
@@ -375,14 +375,14 @@ void Polygon2D::_notification(int p_what) {
// Compute transform between mesh and skeleton for runtime AABB compute.
const Transform2D mesh_transform = get_global_transform();
const Transform2D skeleton_transform = skeleton_node->get_global_transform();
- const Transform2D mesh_to_sk2d = mesh_transform * skeleton_transform.affine_inverse();
+ const Transform2D mesh_to_sk2d = skeleton_transform.affine_inverse() * mesh_transform;
// Convert 2d transform to 3d.
sd.mesh_to_skeleton_xform.basis.rows[0][0] = mesh_to_sk2d.columns[0][0];
- sd.mesh_to_skeleton_xform.basis.rows[0][1] = mesh_to_sk2d.columns[0][1];
+ sd.mesh_to_skeleton_xform.basis.rows[1][0] = mesh_to_sk2d.columns[0][1];
sd.mesh_to_skeleton_xform.origin.x = mesh_to_sk2d.get_origin().x;
- sd.mesh_to_skeleton_xform.basis.rows[1][0] = mesh_to_sk2d.columns[1][0];
+ sd.mesh_to_skeleton_xform.basis.rows[0][1] = mesh_to_sk2d.columns[1][0];
sd.mesh_to_skeleton_xform.basis.rows[1][1] = mesh_to_sk2d.columns[1][1];
sd.mesh_to_skeleton_xform.origin.y = mesh_to_sk2d.get_origin().y;
}
diff --git a/scene/2d/skeleton_2d.cpp b/scene/2d/skeleton_2d.cpp
index 527bbaf956..69e0414855 100644
--- a/scene/2d/skeleton_2d.cpp
+++ b/scene/2d/skeleton_2d.cpp
@@ -433,29 +433,23 @@ PackedStringArray Bone2D::get_configuration_warnings() const {
}
void Bone2D::calculate_length_and_rotation() {
- // if there is at least a single child Bone2D node, we can calculate
+ // If there is at least a single child Bone2D node, we can calculate
// the length and direction. We will always just use the first Bone2D for this.
- bool calculated = false;
int child_count = get_child_count();
- if (child_count > 0) {
- for (int i = 0; i < child_count; i++) {
- Bone2D *child = Object::cast_to<Bone2D>(get_child(i));
- if (child) {
- Vector2 child_local_pos = to_local(child->get_global_position());
- length = child_local_pos.length();
- bone_angle = child_local_pos.normalized().angle();
- calculated = true;
- break;
- }
+ Transform2D global_inv = get_global_transform().affine_inverse();
+
+ for (int i = 0; i < child_count; i++) {
+ Bone2D *child = Object::cast_to<Bone2D>(get_child(i));
+ if (child) {
+ Vector2 child_local_pos = global_inv.xform(child->get_global_position());
+ length = child_local_pos.length();
+ bone_angle = child_local_pos.angle();
+ return; // Finished!
}
}
- if (calculated) {
- return; // Finished!
- } else {
- WARN_PRINT("No Bone2D children of node " + get_name() + ". Cannot calculate bone length or angle reliably.\nUsing transform rotation for bone angle");
- bone_angle = get_transform().get_rotation();
- return;
- }
+
+ WARN_PRINT("No Bone2D children of node " + get_name() + ". Cannot calculate bone length or angle reliably.\nUsing transform rotation for bone angle.");
+ bone_angle = get_transform().get_rotation();
}
void Bone2D::set_autocalculate_length_and_angle(bool p_autocalculate) {
@@ -555,7 +549,7 @@ void Skeleton2D::_make_bone_setup_dirty() {
}
bone_setup_dirty = true;
if (is_inside_tree()) {
- call_deferred(SNAME("_update_bone_setup"));
+ callable_mp(this, &Skeleton2D::_update_bone_setup).call_deferred();
}
}
@@ -593,7 +587,7 @@ void Skeleton2D::_make_transform_dirty() {
}
transform_dirty = true;
if (is_inside_tree()) {
- call_deferred(SNAME("_update_transform"));
+ callable_mp(this, &Skeleton2D::_update_transform).call_deferred();
}
}
@@ -764,9 +758,6 @@ void Skeleton2D::execute_modifications(real_t p_delta, int p_execution_mode) {
}
void Skeleton2D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_update_bone_setup"), &Skeleton2D::_update_bone_setup);
- ClassDB::bind_method(D_METHOD("_update_transform"), &Skeleton2D::_update_transform);
-
ClassDB::bind_method(D_METHOD("get_bone_count"), &Skeleton2D::get_bone_count);
ClassDB::bind_method(D_METHOD("get_bone", "idx"), &Skeleton2D::get_bone);
diff --git a/scene/2d/tile_map_layer.cpp b/scene/2d/tile_map_layer.cpp
index c35a53867c..4ef47ba174 100644
--- a/scene/2d/tile_map_layer.cpp
+++ b/scene/2d/tile_map_layer.cpp
@@ -500,7 +500,7 @@ void TileMapLayer::_rendering_quadrants_update_cell(CellData &r_cell_data, SelfL
quadrant_coords = Vector2i(
coords.x > 0 ? coords.x / quad_size : (coords.x - (quad_size - 1)) / quad_size,
coords.y > 0 ? coords.y / quad_size : (coords.y - (quad_size - 1)) / quad_size);
- canvas_items_position = quad_size * quadrant_coords;
+ canvas_items_position = tile_map_node->map_to_local(quad_size * quadrant_coords);
}
Ref<RenderingQuadrant> rendering_quadrant;
diff --git a/scene/2d/tile_map_layer.h b/scene/2d/tile_map_layer.h
index 8db34d8aae..3125fcb488 100644
--- a/scene/2d/tile_map_layer.h
+++ b/scene/2d/tile_map_layer.h
@@ -173,14 +173,6 @@ public:
SelfList<DebugQuadrant> dirty_quadrant_list_element;
- // For those, copy everything but SelfList elements.
- DebugQuadrant(const DebugQuadrant &p_other) :
- dirty_quadrant_list_element(this) {
- quadrant_coords = p_other.quadrant_coords;
- cells = p_other.cells;
- canvas_item = p_other.canvas_item;
- }
-
DebugQuadrant() :
dirty_quadrant_list_element(this) {
}
@@ -213,14 +205,6 @@ public:
SelfList<RenderingQuadrant> dirty_quadrant_list_element;
- // For those, copy everything but SelfList elements.
- RenderingQuadrant(const RenderingQuadrant &p_other) :
- dirty_quadrant_list_element(this) {
- quadrant_coords = p_other.quadrant_coords;
- cells = p_other.cells;
- canvas_items = p_other.canvas_items;
- }
-
RenderingQuadrant() :
dirty_quadrant_list_element(this) {
}
diff --git a/scene/3d/bone_attachment_3d.cpp b/scene/3d/bone_attachment_3d.cpp
index 45de9b907c..5683fb7306 100644
--- a/scene/3d/bone_attachment_3d.cpp
+++ b/scene/3d/bone_attachment_3d.cpp
@@ -150,7 +150,7 @@ void BoneAttachment3D::_check_bind() {
if (bone_idx != -1) {
sk->connect(SNAME("bone_pose_changed"), callable_mp(this, &BoneAttachment3D::on_bone_pose_update));
bound = true;
- call_deferred(SNAME("on_bone_pose_update"), bone_idx);
+ callable_mp(this, &BoneAttachment3D::on_bone_pose_update).call_deferred(bone_idx);
}
}
}
diff --git a/scene/3d/collision_object_3d.cpp b/scene/3d/collision_object_3d.cpp
index 4562ecfb5f..97b1e282ad 100644
--- a/scene/3d/collision_object_3d.cpp
+++ b/scene/3d/collision_object_3d.cpp
@@ -295,16 +295,12 @@ void CollisionObject3D::_input_event_call(Camera3D *p_camera, const Ref<InputEve
}
void CollisionObject3D::_mouse_enter() {
- if (get_script_instance()) {
- get_script_instance()->call(SceneStringNames::get_singleton()->_mouse_enter);
- }
+ GDVIRTUAL_CALL(_mouse_enter);
emit_signal(SceneStringNames::get_singleton()->mouse_entered);
}
void CollisionObject3D::_mouse_exit() {
- if (get_script_instance()) {
- get_script_instance()->call(SceneStringNames::get_singleton()->_mouse_exit);
- }
+ GDVIRTUAL_CALL(_mouse_exit);
emit_signal(SceneStringNames::get_singleton()->mouse_exited);
}
diff --git a/scene/3d/gpu_particles_3d.cpp b/scene/3d/gpu_particles_3d.cpp
index fc84b3308e..dfb039d709 100644
--- a/scene/3d/gpu_particles_3d.cpp
+++ b/scene/3d/gpu_particles_3d.cpp
@@ -460,7 +460,12 @@ void GPUParticles3D::_notification(int p_what) {
// Use internal process when emitting and one_shot is on so that when
// the shot ends the editor can properly update.
case NOTIFICATION_INTERNAL_PROCESS: {
- RS::get_singleton()->particles_set_emitter_velocity(particles, (get_global_position() - previous_position) / get_process_delta_time());
+ const Vector3 velocity = (get_global_position() - previous_position) / get_process_delta_time();
+
+ if (velocity != previous_velocity) {
+ RS::get_singleton()->particles_set_emitter_velocity(particles, velocity);
+ previous_velocity = velocity;
+ }
previous_position = get_global_position();
if (one_shot) {
diff --git a/scene/3d/gpu_particles_3d.h b/scene/3d/gpu_particles_3d.h
index ae9349817c..0c9f2c1378 100644
--- a/scene/3d/gpu_particles_3d.h
+++ b/scene/3d/gpu_particles_3d.h
@@ -95,6 +95,7 @@ private:
double emission_time = 0.0;
double active_time = 0.0;
float interp_to_end_factor = 0;
+ Vector3 previous_velocity;
Vector3 previous_position;
void _attach_sub_emitter();
diff --git a/scene/3d/navigation_region_3d.cpp b/scene/3d/navigation_region_3d.cpp
index 94c0a2279a..fa5c8f820d 100644
--- a/scene/3d/navigation_region_3d.cpp
+++ b/scene/3d/navigation_region_3d.cpp
@@ -258,7 +258,7 @@ void NavigationRegion3D::bake_navigation_mesh(bool p_on_thread) {
void NavigationRegion3D::_bake_finished(Ref<NavigationMesh> p_navigation_mesh) {
if (!Thread::is_main_thread()) {
- call_deferred(SNAME("_bake_finished"), p_navigation_mesh);
+ callable_mp(this, &NavigationRegion3D::_bake_finished).call_deferred(p_navigation_mesh);
return;
}
@@ -308,7 +308,6 @@ void NavigationRegion3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_travel_cost"), &NavigationRegion3D::get_travel_cost);
ClassDB::bind_method(D_METHOD("bake_navigation_mesh", "on_thread"), &NavigationRegion3D::bake_navigation_mesh, DEFVAL(true));
- ClassDB::bind_method(D_METHOD("_bake_finished", "navigation_mesh"), &NavigationRegion3D::_bake_finished);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "navigation_mesh", PROPERTY_HINT_RESOURCE_TYPE, "NavigationMesh"), "set_navigation_mesh", "get_navigation_mesh");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled");
diff --git a/scene/3d/node_3d.cpp b/scene/3d/node_3d.cpp
index cb8279d534..c4d1e6bef7 100644
--- a/scene/3d/node_3d.cpp
+++ b/scene/3d/node_3d.cpp
@@ -30,7 +30,6 @@
#include "node_3d.h"
-#include "core/object/message_queue.h"
#include "scene/3d/visual_instance_3d.h"
#include "scene/main/viewport.h"
#include "scene/property_utils.h"
@@ -124,7 +123,7 @@ void Node3D::_propagate_transform_changed(Node3D *p_origin) {
get_tree()->xform_change_list.add(&xform_change);
} else {
// This should very rarely happen, but if it does at least make sure the notification is received eventually.
- MessageQueue::get_singleton()->push_callable(callable_mp(this, &Node3D::_propagate_transform_changed_deferred));
+ callable_mp(this, &Node3D::_propagate_transform_changed_deferred).call_deferred();
}
}
_set_dirty_bits(DIRTY_GLOBAL_TRANSFORM);
@@ -568,7 +567,7 @@ void Node3D::update_gizmos() {
return;
}
data.gizmos_dirty = true;
- MessageQueue::get_singleton()->push_callable(callable_mp(this, &Node3D::_update_gizmos));
+ callable_mp(this, &Node3D::_update_gizmos).call_deferred();
#endif
}
diff --git a/scene/3d/skeleton_3d.cpp b/scene/3d/skeleton_3d.cpp
index 445c1003b5..ec5f8187a9 100644
--- a/scene/3d/skeleton_3d.cpp
+++ b/scene/3d/skeleton_3d.cpp
@@ -30,7 +30,6 @@
#include "skeleton_3d.h"
-#include "core/object/message_queue.h"
#include "core/variant/type_info.h"
#include "scene/3d/physics_body_3d.h"
#include "scene/resources/surface_tool.h"
diff --git a/scene/3d/soft_body_3d.cpp b/scene/3d/soft_body_3d.cpp
index db2c0e1387..3f1878f30f 100644
--- a/scene/3d/soft_body_3d.cpp
+++ b/scene/3d/soft_body_3d.cpp
@@ -416,8 +416,8 @@ void SoftBody3D::_draw_soft_mesh() {
/// Necessary in order to render the mesh correctly (Soft body nodes are in global space)
simulation_started = true;
- call_deferred(SNAME("set_as_top_level"), true);
- call_deferred(SNAME("set_transform"), Transform3D());
+ callable_mp((Node3D *)this, &Node3D::set_as_top_level).call_deferred(true);
+ callable_mp((Node3D *)this, &Node3D::set_transform).call_deferred(Transform3D());
}
_update_physics_server();
diff --git a/scene/3d/visual_instance_3d.cpp b/scene/3d/visual_instance_3d.cpp
index 33f865382d..503c39ae3e 100644
--- a/scene/3d/visual_instance_3d.cpp
+++ b/scene/3d/visual_instance_3d.cpp
@@ -250,7 +250,7 @@ GeometryInstance3D::VisibilityRangeFadeMode GeometryInstance3D::get_visibility_r
return visibility_range_fade_mode;
}
-const StringName *GeometryInstance3D::_instance_uniform_get_remap(const StringName p_name) const {
+const StringName *GeometryInstance3D::_instance_uniform_get_remap(const StringName &p_name) const {
StringName *r = instance_shader_parameter_property_remap.getptr(p_name);
if (!r) {
String s = p_name;
diff --git a/scene/3d/visual_instance_3d.h b/scene/3d/visual_instance_3d.h
index ef0f7966e2..59ede26ac1 100644
--- a/scene/3d/visual_instance_3d.h
+++ b/scene/3d/visual_instance_3d.h
@@ -135,7 +135,7 @@ private:
GIMode gi_mode = GI_MODE_STATIC;
bool ignore_occlusion_culling = false;
- const StringName *_instance_uniform_get_remap(const StringName p_name) const;
+ const StringName *_instance_uniform_get_remap(const StringName &p_name) const;
protected:
bool _set(const StringName &p_name, const Variant &p_value);
diff --git a/scene/3d/xr_nodes.cpp b/scene/3d/xr_nodes.cpp
index c12e78eddc..70e32c1a31 100644
--- a/scene/3d/xr_nodes.cpp
+++ b/scene/3d/xr_nodes.cpp
@@ -58,13 +58,13 @@ void XRCamera3D::_unbind_tracker() {
tracker.unref();
}
-void XRCamera3D::_changed_tracker(const StringName p_tracker_name, int p_tracker_type) {
+void XRCamera3D::_changed_tracker(const StringName &p_tracker_name, int p_tracker_type) {
if (p_tracker_name == tracker_name) {
_bind_tracker();
}
}
-void XRCamera3D::_removed_tracker(const StringName p_tracker_name, int p_tracker_type) {
+void XRCamera3D::_removed_tracker(const StringName &p_tracker_name, int p_tracker_type) {
if (p_tracker_name == tracker_name) {
_unbind_tracker();
}
@@ -258,7 +258,7 @@ void XRNode3D::_validate_property(PropertyInfo &p_property) const {
}
}
-void XRNode3D::set_tracker(const StringName p_tracker_name) {
+void XRNode3D::set_tracker(const StringName &p_tracker_name) {
if (tracker.is_valid() && tracker->get_tracker_name() == p_tracker_name) {
// didn't change
return;
@@ -282,7 +282,7 @@ StringName XRNode3D::get_tracker() const {
return tracker_name;
}
-void XRNode3D::set_pose_name(const StringName p_pose_name) {
+void XRNode3D::set_pose_name(const StringName &p_pose_name) {
pose_name = p_pose_name;
// Update pose if we are bound to a tracker with a valid pose
@@ -363,7 +363,7 @@ void XRNode3D::_unbind_tracker() {
}
}
-void XRNode3D::_changed_tracker(const StringName p_tracker_name, int p_tracker_type) {
+void XRNode3D::_changed_tracker(const StringName &p_tracker_name, int p_tracker_type) {
if (tracker_name == p_tracker_name) {
// just in case unref our current tracker
_unbind_tracker();
@@ -373,7 +373,7 @@ void XRNode3D::_changed_tracker(const StringName p_tracker_name, int p_tracker_t
}
}
-void XRNode3D::_removed_tracker(const StringName p_tracker_name, int p_tracker_type) {
+void XRNode3D::_removed_tracker(const StringName &p_tracker_name, int p_tracker_type) {
if (tracker_name == p_tracker_name) {
// unref our tracker, it's no longer available
_unbind_tracker();
diff --git a/scene/3d/xr_nodes.h b/scene/3d/xr_nodes.h
index 185a6361d3..ad52cf113d 100644
--- a/scene/3d/xr_nodes.h
+++ b/scene/3d/xr_nodes.h
@@ -50,8 +50,8 @@ protected:
void _bind_tracker();
void _unbind_tracker();
- void _changed_tracker(const StringName p_tracker_name, int p_tracker_type);
- void _removed_tracker(const StringName p_tracker_name, int p_tracker_type);
+ void _changed_tracker(const StringName &p_tracker_name, int p_tracker_type);
+ void _removed_tracker(const StringName &p_tracker_name, int p_tracker_type);
void _pose_changed(const Ref<XRPose> &p_pose);
public:
@@ -87,8 +87,8 @@ protected:
virtual void _bind_tracker();
virtual void _unbind_tracker();
- void _changed_tracker(const StringName p_tracker_name, int p_tracker_type);
- void _removed_tracker(const StringName p_tracker_name, int p_tracker_type);
+ void _changed_tracker(const StringName &p_tracker_name, int p_tracker_type);
+ void _removed_tracker(const StringName &p_tracker_name, int p_tracker_type);
void _pose_changed(const Ref<XRPose> &p_pose);
void _pose_lost_tracking(const Ref<XRPose> &p_pose);
@@ -96,10 +96,10 @@ protected:
public:
void _validate_property(PropertyInfo &p_property) const;
- void set_tracker(const StringName p_tracker_name);
+ void set_tracker(const StringName &p_tracker_name);
StringName get_tracker() const;
- void set_pose_name(const StringName p_pose);
+ void set_pose_name(const StringName &p_pose);
StringName get_pose_name() const;
bool get_is_active() const;
diff --git a/scene/animation/animation_blend_space_2d.cpp b/scene/animation/animation_blend_space_2d.cpp
index 37c360b8f8..dbec2be0ba 100644
--- a/scene/animation/animation_blend_space_2d.cpp
+++ b/scene/animation/animation_blend_space_2d.cpp
@@ -332,7 +332,7 @@ void AnimationNodeBlendSpace2D::_queue_auto_triangles() {
}
trianges_dirty = true;
- call_deferred(SNAME("_update_triangles"));
+ callable_mp(this, &AnimationNodeBlendSpace2D::_update_triangles).call_deferred();
}
void AnimationNodeBlendSpace2D::_update_triangles() {
@@ -689,8 +689,6 @@ void AnimationNodeBlendSpace2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_use_sync", "enable"), &AnimationNodeBlendSpace2D::set_use_sync);
ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeBlendSpace2D::is_using_sync);
- ClassDB::bind_method(D_METHOD("_update_triangles"), &AnimationNodeBlendSpace2D::_update_triangles);
-
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_triangles", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_auto_triangles", "get_auto_triangles");
for (int i = 0; i < MAX_BLEND_POINTS; i++) {
diff --git a/scene/animation/animation_mixer.compat.inc b/scene/animation/animation_mixer.compat.inc
new file mode 100644
index 0000000000..09c7d7a977
--- /dev/null
+++ b/scene/animation/animation_mixer.compat.inc
@@ -0,0 +1,44 @@
+/**************************************************************************/
+/* animation_mixer.compat.inc */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef DISABLE_DEPRECATED
+
+Variant AnimationMixer::_post_process_key_value_bind_compat_86687(const Ref<Animation> &p_anim, int p_track, Variant p_value, Object *p_object, int p_object_idx) {
+ if (!p_object) {
+ return Variant();
+ }
+ return _post_process_key_value(p_anim, p_track, p_value, p_object->get_instance_id(), p_object_idx);
+}
+
+void AnimationMixer::_bind_compatibility_methods() {
+ ClassDB::bind_compatibility_method(D_METHOD("_post_process_key_value_bind_compat", "animation", "track", "value", "object", "object_idx"), &AnimationMixer::_post_process_key_value_bind_compat_86687);
+}
+
+#endif // DISABLE_DEPRECATED
diff --git a/scene/animation/animation_mixer.cpp b/scene/animation/animation_mixer.cpp
index 2338c305de..2adb3695a7 100644
--- a/scene/animation/animation_mixer.cpp
+++ b/scene/animation/animation_mixer.cpp
@@ -29,8 +29,12 @@
/**************************************************************************/
#include "animation_mixer.h"
+#include "animation_mixer.compat.inc"
#include "core/config/engine.h"
+#include "scene/3d/mesh_instance_3d.h"
+#include "scene/3d/node_3d.h"
+#include "scene/3d/skeleton_3d.h"
#include "scene/animation/animation_player.h"
#include "scene/resources/animation.h"
#include "scene/scene_string_names.h"
@@ -543,7 +547,7 @@ void AnimationMixer::_clear_caches() {
_init_root_motion_cache();
_clear_audio_streams();
_clear_playing_caches();
- for (KeyValue<NodePath, TrackCache *> &K : track_cache) {
+ for (KeyValue<Animation::TypeHash, TrackCache *> &K : track_cache) {
memdelete(K.value);
}
track_cache.clear();
@@ -562,8 +566,9 @@ void AnimationMixer::_clear_audio_streams() {
void AnimationMixer::_clear_playing_caches() {
for (const TrackCache *E : playing_caches) {
- if (ObjectDB::get_instance(E->object_id)) {
- E->object->call(SNAME("stop"), true);
+ Object *t_obj = ObjectDB::get_instance(E->object_id);
+ if (t_obj) {
+ t_obj->call(SNAME("stop"), true);
}
}
playing_caches.clear();
@@ -606,23 +611,20 @@ bool AnimationMixer::_update_caches() {
Ref<Animation> anim = get_animation(E);
for (int i = 0; i < anim->get_track_count(); i++) {
NodePath path = anim->track_get_path(i);
- Animation::TrackType track_type = anim->track_get_type(i);
-
- Animation::TrackType track_cache_type = track_type;
- if (track_cache_type == Animation::TYPE_POSITION_3D || track_cache_type == Animation::TYPE_ROTATION_3D || track_cache_type == Animation::TYPE_SCALE_3D) {
- track_cache_type = Animation::TYPE_POSITION_3D; // Reference them as position3D tracks, even if they modify rotation or scale.
- }
+ Animation::TypeHash thash = anim->track_get_type_hash(i);
+ Animation::TrackType track_src_type = anim->track_get_type(i);
+ Animation::TrackType track_cache_type = Animation::get_cache_type(track_src_type);
TrackCache *track = nullptr;
- if (track_cache.has(path)) {
- track = track_cache.get(path);
+ if (track_cache.has(thash)) {
+ track = track_cache.get(thash);
}
// If not valid, delete track.
if (track && (track->type != track_cache_type || ObjectDB::get_instance(track->object_id) == nullptr)) {
playing_caches.erase(track);
memdelete(track);
- track_cache.erase(path);
+ track_cache.erase(thash);
track = nullptr;
}
@@ -636,7 +638,8 @@ bool AnimationMixer::_update_caches() {
continue;
}
- switch (track_type) {
+ switch (track_src_type) {
+ case Animation::TYPE_BEZIER:
case Animation::TYPE_VALUE: {
// If a value track without a key is cached first, the initial value cannot be determined.
// It is a corner case, but which may cause problems with blending.
@@ -645,16 +648,20 @@ bool AnimationMixer::_update_caches() {
TrackCacheValue *track_value = memnew(TrackCacheValue);
if (resource.is_valid()) {
- track_value->object = resource.ptr();
+ track_value->object_id = resource->get_instance_id();
} else {
- track_value->object = child;
+ track_value->object_id = child->get_instance_id();
}
- track_value->is_continuous = anim->value_track_get_update_mode(i) != Animation::UPDATE_DISCRETE;
- track_value->is_using_angle = anim->track_get_interpolation_type(i) == Animation::INTERPOLATION_LINEAR_ANGLE || anim->track_get_interpolation_type(i) == Animation::INTERPOLATION_CUBIC_ANGLE;
+ if (track_src_type == Animation::TYPE_VALUE) {
+ track_value->is_continuous = anim->value_track_get_update_mode(i) != Animation::UPDATE_DISCRETE;
+ track_value->is_using_angle = anim->track_get_interpolation_type(i) == Animation::INTERPOLATION_LINEAR_ANGLE || anim->track_get_interpolation_type(i) == Animation::INTERPOLATION_CUBIC_ANGLE;
+ } else {
+ track_value->is_continuous = true;
+ track_value->is_using_angle = false;
+ }
track_value->subpath = leftover_path;
- track_value->object_id = track_value->object->get_instance_id();
track = track_value;
@@ -663,9 +670,9 @@ bool AnimationMixer::_update_caches() {
// If there is a Reset Animation, it takes precedence by overwriting.
if (has_reset_anim) {
- int rt = reset_anim->find_track(path, track_type);
+ int rt = reset_anim->find_track(path, track_src_type);
if (rt >= 0 && reset_anim->track_get_key_count(rt) > 0) {
- track_value->init_value = reset_anim->track_get_key_value(rt, 0);
+ track_value->init_value = track_src_type == Animation::TYPE_VALUE ? reset_anim->track_get_key_value(rt, 0) : (reset_anim->track_get_key_value(rt, 0).operator Array())[0];
}
}
@@ -684,14 +691,12 @@ bool AnimationMixer::_update_caches() {
TrackCacheTransform *track_xform = memnew(TrackCacheTransform);
track_xform->type = Animation::TYPE_POSITION_3D;
- track_xform->node_3d = node_3d;
- track_xform->skeleton = nullptr;
track_xform->bone_idx = -1;
bool has_rest = false;
- if (path.get_subname_count() == 1 && Object::cast_to<Skeleton3D>(node_3d)) {
- Skeleton3D *sk = Object::cast_to<Skeleton3D>(node_3d);
- track_xform->skeleton = sk;
+ Skeleton3D *sk = Object::cast_to<Skeleton3D>(node_3d);
+ if (sk && path.get_subname_count() == 1) {
+ track_xform->skeleton_id = sk->get_instance_id();
int bone_idx = sk->find_bone(path.get_subname(0));
if (bone_idx != -1) {
has_rest = true;
@@ -703,12 +708,11 @@ bool AnimationMixer::_update_caches() {
}
}
- track_xform->object = node_3d;
- track_xform->object_id = track_xform->object->get_instance_id();
+ track_xform->object_id = node_3d->get_instance_id();
track = track_xform;
- switch (track_type) {
+ switch (track_src_type) {
case Animation::TYPE_POSITION_3D: {
track_xform->loc_used = true;
} break;
@@ -724,9 +728,9 @@ bool AnimationMixer::_update_caches() {
// For non Skeleton3D bone animation.
if (has_reset_anim && !has_rest) {
- int rt = reset_anim->find_track(path, track_type);
+ int rt = reset_anim->find_track(path, track_src_type);
if (rt >= 0 && reset_anim->track_get_key_count(rt) > 0) {
- switch (track_type) {
+ switch (track_src_type) {
case Animation::TYPE_POSITION_3D: {
track_xform->init_loc = reset_anim->track_get_key_value(rt, 0);
} break;
@@ -765,15 +769,12 @@ bool AnimationMixer::_update_caches() {
TrackCacheBlendShape *track_bshape = memnew(TrackCacheBlendShape);
- track_bshape->mesh_3d = mesh_3d;
track_bshape->shape_index = blend_shape_idx;
-
- track_bshape->object = mesh_3d;
track_bshape->object_id = mesh_3d->get_instance_id();
track = track_bshape;
if (has_reset_anim) {
- int rt = reset_anim->find_track(path, track_type);
+ int rt = reset_anim->find_track(path, track_src_type);
if (rt >= 0 && reset_anim->track_get_key_count(rt) > 0) {
track_bshape->init_value = reset_anim->track_get_key_value(rt, 0);
}
@@ -784,43 +785,18 @@ bool AnimationMixer::_update_caches() {
TrackCacheMethod *track_method = memnew(TrackCacheMethod);
if (resource.is_valid()) {
- track_method->object = resource.ptr();
+ track_method->object_id = resource->get_instance_id();
} else {
- track_method->object = child;
+ track_method->object_id = child->get_instance_id();
}
- track_method->object_id = track_method->object->get_instance_id();
-
track = track_method;
} break;
- case Animation::TYPE_BEZIER: {
- TrackCacheBezier *track_bezier = memnew(TrackCacheBezier);
-
- if (resource.is_valid()) {
- track_bezier->object = resource.ptr();
- } else {
- track_bezier->object = child;
- }
-
- track_bezier->subpath = leftover_path;
- track_bezier->object_id = track_bezier->object->get_instance_id();
-
- track = track_bezier;
-
- if (has_reset_anim) {
- int rt = reset_anim->find_track(path, track_type);
- if (rt >= 0 && reset_anim->track_get_key_count(rt) > 0) {
- track_bezier->init_value = (reset_anim->track_get_key_value(rt, 0).operator Array())[0];
- }
- }
-
- } break;
case Animation::TYPE_AUDIO: {
TrackCacheAudio *track_audio = memnew(TrackCacheAudio);
- track_audio->object = child;
- track_audio->object_id = track_audio->object->get_instance_id();
+ track_audio->object_id = child->get_instance_id();
track_audio->audio_stream.instantiate();
track_audio->audio_stream->set_polyphony(audio_max_polyphony);
@@ -830,8 +806,7 @@ bool AnimationMixer::_update_caches() {
case Animation::TYPE_ANIMATION: {
TrackCacheAnimation *track_animation = memnew(TrackCacheAnimation);
- track_animation->object = child;
- track_animation->object_id = track_animation->object->get_instance_id();
+ track_animation->object_id = child->get_instance_id();
track = track_animation;
@@ -841,8 +816,8 @@ bool AnimationMixer::_update_caches() {
continue;
}
}
-
- track_cache[path] = track;
+ track->path = path;
+ track_cache[thash] = track;
} else if (track_cache_type == Animation::TYPE_POSITION_3D) {
TrackCacheTransform *track_xform = static_cast<TrackCacheTransform *>(track);
if (track->setup_pass != setup_pass) {
@@ -850,7 +825,7 @@ bool AnimationMixer::_update_caches() {
track_xform->rot_used = false;
track_xform->scale_used = false;
}
- switch (track_type) {
+ switch (track_src_type) {
case Animation::TYPE_POSITION_3D: {
track_xform->loc_used = true;
} break;
@@ -868,8 +843,13 @@ bool AnimationMixer::_update_caches() {
TrackCacheValue *track_value = static_cast<TrackCacheValue *>(track);
bool was_continuous = track_value->is_continuous;
bool was_using_angle = track_value->is_using_angle;
- track_value->is_continuous |= anim->value_track_get_update_mode(i) != Animation::UPDATE_DISCRETE;
- track_value->is_using_angle |= anim->track_get_interpolation_type(i) == Animation::INTERPOLATION_LINEAR_ANGLE || anim->track_get_interpolation_type(i) == Animation::INTERPOLATION_CUBIC_ANGLE;
+
+ if (track_src_type == Animation::TYPE_VALUE) {
+ track_value->is_continuous |= anim->value_track_get_update_mode(i) != Animation::UPDATE_DISCRETE;
+ track_value->is_using_angle |= anim->track_get_interpolation_type(i) == Animation::INTERPOLATION_LINEAR_ANGLE || anim->track_get_interpolation_type(i) == Animation::INTERPOLATION_CUBIC_ANGLE;
+ } else {
+ track_value->is_continuous |= true;
+ }
// TODO: Currently, misc type cannot be blended.
// In the future, it should have a separate blend weight, just as bool is converted to 0 and 1.
@@ -898,27 +878,26 @@ bool AnimationMixer::_update_caches() {
}
}
- List<NodePath> to_delete;
+ List<Animation::TypeHash> to_delete;
- for (const KeyValue<NodePath, TrackCache *> &K : track_cache) {
- TrackCache *tc = track_cache[K.key];
- if (tc->setup_pass != setup_pass) {
+ for (const KeyValue<Animation::TypeHash, TrackCache *> &K : track_cache) {
+ if (K.value->setup_pass != setup_pass) {
to_delete.push_back(K.key);
}
}
while (to_delete.front()) {
- NodePath np = to_delete.front()->get();
- memdelete(track_cache[np]);
- track_cache.erase(np);
+ Animation::TypeHash thash = to_delete.front()->get();
+ memdelete(track_cache[thash]);
+ track_cache.erase(thash);
to_delete.pop_front();
}
track_map.clear();
int idx = 0;
- for (const KeyValue<NodePath, TrackCache *> &K : track_cache) {
- track_map[K.key] = idx;
+ for (const KeyValue<Animation::TypeHash, TrackCache *> &K : track_cache) {
+ track_map[K.value->path] = idx;
idx++;
}
@@ -944,28 +923,30 @@ void AnimationMixer::_process_animation(double p_delta, bool p_update_only) {
clear_animation_instances();
}
-Variant AnimationMixer::post_process_key_value(const Ref<Animation> &p_anim, int p_track, Variant p_value, const Object *p_object, int p_object_idx) {
+Variant AnimationMixer::post_process_key_value(const Ref<Animation> &p_anim, int p_track, Variant p_value, ObjectID p_object_id, int p_object_sub_idx) {
Variant res;
- if (GDVIRTUAL_CALL(_post_process_key_value, p_anim, p_track, p_value, const_cast<Object *>(p_object), p_object_idx, res)) {
+ if (GDVIRTUAL_CALL(_post_process_key_value, p_anim, p_track, p_value, p_object_id, p_object_sub_idx, res)) {
return res;
}
- return _post_process_key_value(p_anim, p_track, p_value, p_object, p_object_idx);
+ return _post_process_key_value(p_anim, p_track, p_value, p_object_id, p_object_sub_idx);
}
-Variant AnimationMixer::_post_process_key_value(const Ref<Animation> &p_anim, int p_track, Variant p_value, const Object *p_object, int p_object_idx) {
- switch (p_anim->track_get_type(p_track)) {
+Variant AnimationMixer::_post_process_key_value(const Ref<Animation> &p_anim, int p_track, Variant p_value, ObjectID p_object_id, int p_object_sub_idx) {
#ifndef _3D_DISABLED
+ switch (p_anim->track_get_type(p_track)) {
case Animation::TYPE_POSITION_3D: {
- if (p_object_idx >= 0) {
- const Skeleton3D *skel = Object::cast_to<Skeleton3D>(p_object);
- return Vector3(p_value) * skel->get_motion_scale();
+ if (p_object_sub_idx >= 0) {
+ Skeleton3D *skel = Object::cast_to<Skeleton3D>(ObjectDB::get_instance(p_object_id));
+ if (skel) {
+ return Vector3(p_value) * skel->get_motion_scale();
+ }
}
return p_value;
} break;
-#endif // _3D_DISABLED
default: {
} break;
}
+#endif // _3D_DISABLED
return p_value;
}
@@ -985,7 +966,7 @@ void AnimationMixer::_blend_init() {
}
// Init all value/transform/blend/bezier tracks that track_cache has.
- for (const KeyValue<NodePath, TrackCache *> &K : track_cache) {
+ for (const KeyValue<Animation::TypeHash, TrackCache *> &K : track_cache) {
TrackCache *track = K.value;
track->total_weight = 0.0;
@@ -1011,10 +992,6 @@ void AnimationMixer::_blend_init() {
t->value = Animation::cast_to_blendwise(t->init_value);
t->element_size = t->init_value.is_string() ? (real_t)(t->init_value.operator String()).length() : 0;
} break;
- case Animation::TYPE_BEZIER: {
- TrackCacheBezier *t = static_cast<TrackCacheBezier *>(track);
- t->value = t->init_value;
- } break;
case Animation::TYPE_AUDIO: {
TrackCacheAudio *t = static_cast<TrackCacheAudio *>(track);
for (KeyValue<ObjectID, PlayingAudioTrackInfo> &L : t->playing_streams) {
@@ -1046,12 +1023,12 @@ void AnimationMixer::_blend_calc_total_weight() {
if (!a->track_is_enabled(i)) {
continue;
}
- NodePath path = a->track_get_path(i);
- if (!track_cache.has(path)) {
+ Animation::TypeHash thash = a->track_get_type_hash(i);
+ if (!track_cache.has(thash)) {
continue; // No path, but avoid error spamming.
}
- TrackCache *track = track_cache[path];
- int blend_idx = track_map[path];
+ TrackCache *track = track_cache[thash];
+ int blend_idx = track_map[track->path];
if (processed_indices.has(blend_idx)) {
continue; // There is the case different track type with same path... Is there more faster iterating way than has()?
}
@@ -1086,13 +1063,13 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
if (!a->track_is_enabled(i)) {
continue;
}
- NodePath path = a->track_get_path(i);
- if (!track_cache.has(path)) {
+ Animation::TypeHash thash = a->track_get_type_hash(i);
+ if (!track_cache.has(thash)) {
continue; // No path, but avoid error spamming.
}
- TrackCache *track = track_cache[path];
- ERR_CONTINUE(!track_map.has(path));
- int blend_idx = track_map[path];
+ TrackCache *track = track_cache[thash];
+ ERR_CONTINUE(!track_map.has(track->path));
+ int blend_idx = track_map[track->path];
ERR_CONTINUE(blend_idx < 0 || blend_idx >= track_count);
real_t blend = blend_idx < track_weights.size() ? track_weights[blend_idx] * weight : weight;
if (!deterministic) {
@@ -1104,11 +1081,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
blend = blend / track->total_weight;
}
Animation::TrackType ttype = a->track_get_type(i);
- if (ttype != Animation::TYPE_POSITION_3D && ttype != Animation::TYPE_ROTATION_3D && ttype != Animation::TYPE_SCALE_3D && track->type != ttype) {
- // Broken animation, but avoid error spamming.
- continue;
- }
- track->root_motion = root_motion_track == path;
+ track->root_motion = root_motion_track == a->track_get_path(i);
switch (ttype) {
case Animation::TYPE_POSITION_3D: {
#ifndef _3D_DISABLED
@@ -1158,9 +1131,9 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
if (err != OK) {
continue;
}
- loc[0] = post_process_key_value(a, i, loc[0], t->object, t->bone_idx);
+ loc[0] = post_process_key_value(a, i, loc[0], t->object_id, t->bone_idx);
a->try_position_track_interpolate(i, (double)a->get_length(), &loc[1]);
- loc[1] = post_process_key_value(a, i, loc[1], t->object, t->bone_idx);
+ loc[1] = post_process_key_value(a, i, loc[1], t->object_id, t->bone_idx);
root_motion_cache.loc += (loc[1] - loc[0]) * blend;
prev_time = 0;
}
@@ -1170,9 +1143,9 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
if (err != OK) {
continue;
}
- loc[0] = post_process_key_value(a, i, loc[0], t->object, t->bone_idx);
+ loc[0] = post_process_key_value(a, i, loc[0], t->object_id, t->bone_idx);
a->try_position_track_interpolate(i, 0, &loc[1]);
- loc[1] = post_process_key_value(a, i, loc[1], t->object, t->bone_idx);
+ loc[1] = post_process_key_value(a, i, loc[1], t->object_id, t->bone_idx);
root_motion_cache.loc += (loc[1] - loc[0]) * blend;
prev_time = (double)a->get_length();
}
@@ -1181,9 +1154,9 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
if (err != OK) {
continue;
}
- loc[0] = post_process_key_value(a, i, loc[0], t->object, t->bone_idx);
+ loc[0] = post_process_key_value(a, i, loc[0], t->object_id, t->bone_idx);
a->try_position_track_interpolate(i, time, &loc[1]);
- loc[1] = post_process_key_value(a, i, loc[1], t->object, t->bone_idx);
+ loc[1] = post_process_key_value(a, i, loc[1], t->object_id, t->bone_idx);
root_motion_cache.loc += (loc[1] - loc[0]) * blend;
prev_time = !backward ? 0 : (double)a->get_length();
}
@@ -1193,7 +1166,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
if (err != OK) {
continue;
}
- loc = post_process_key_value(a, i, loc, t->object, t->bone_idx);
+ loc = post_process_key_value(a, i, loc, t->object_id, t->bone_idx);
t->loc += (loc - t->init_loc) * blend;
}
#endif // _3D_DISABLED
@@ -1246,9 +1219,9 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
if (err != OK) {
continue;
}
- rot[0] = post_process_key_value(a, i, rot[0], t->object, t->bone_idx);
+ rot[0] = post_process_key_value(a, i, rot[0], t->object_id, t->bone_idx);
a->try_rotation_track_interpolate(i, (double)a->get_length(), &rot[1]);
- rot[1] = post_process_key_value(a, i, rot[1], t->object, t->bone_idx);
+ rot[1] = post_process_key_value(a, i, rot[1], t->object_id, t->bone_idx);
root_motion_cache.rot = (root_motion_cache.rot * Quaternion().slerp(rot[0].inverse() * rot[1], blend)).normalized();
prev_time = 0;
}
@@ -1258,7 +1231,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
if (err != OK) {
continue;
}
- rot[0] = post_process_key_value(a, i, rot[0], t->object, t->bone_idx);
+ rot[0] = post_process_key_value(a, i, rot[0], t->object_id, t->bone_idx);
a->try_rotation_track_interpolate(i, 0, &rot[1]);
root_motion_cache.rot = (root_motion_cache.rot * Quaternion().slerp(rot[0].inverse() * rot[1], blend)).normalized();
prev_time = (double)a->get_length();
@@ -1268,9 +1241,9 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
if (err != OK) {
continue;
}
- rot[0] = post_process_key_value(a, i, rot[0], t->object, t->bone_idx);
+ rot[0] = post_process_key_value(a, i, rot[0], t->object_id, t->bone_idx);
a->try_rotation_track_interpolate(i, time, &rot[1]);
- rot[1] = post_process_key_value(a, i, rot[1], t->object, t->bone_idx);
+ rot[1] = post_process_key_value(a, i, rot[1], t->object_id, t->bone_idx);
root_motion_cache.rot = (root_motion_cache.rot * Quaternion().slerp(rot[0].inverse() * rot[1], blend)).normalized();
prev_time = !backward ? 0 : (double)a->get_length();
}
@@ -1280,7 +1253,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
if (err != OK) {
continue;
}
- rot = post_process_key_value(a, i, rot, t->object, t->bone_idx);
+ rot = post_process_key_value(a, i, rot, t->object_id, t->bone_idx);
t->rot = (t->rot * Quaternion().slerp(t->init_rot.inverse() * rot, blend)).normalized();
}
#endif // _3D_DISABLED
@@ -1333,10 +1306,10 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
if (err != OK) {
continue;
}
- scale[0] = post_process_key_value(a, i, scale[0], t->object, t->bone_idx);
+ scale[0] = post_process_key_value(a, i, scale[0], t->object_id, t->bone_idx);
a->try_scale_track_interpolate(i, (double)a->get_length(), &scale[1]);
root_motion_cache.scale += (scale[1] - scale[0]) * blend;
- scale[1] = post_process_key_value(a, i, scale[1], t->object, t->bone_idx);
+ scale[1] = post_process_key_value(a, i, scale[1], t->object_id, t->bone_idx);
prev_time = 0;
}
} else {
@@ -1345,9 +1318,9 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
if (err != OK) {
continue;
}
- scale[0] = post_process_key_value(a, i, scale[0], t->object, t->bone_idx);
+ scale[0] = post_process_key_value(a, i, scale[0], t->object_id, t->bone_idx);
a->try_scale_track_interpolate(i, 0, &scale[1]);
- scale[1] = post_process_key_value(a, i, scale[1], t->object, t->bone_idx);
+ scale[1] = post_process_key_value(a, i, scale[1], t->object_id, t->bone_idx);
root_motion_cache.scale += (scale[1] - scale[0]) * blend;
prev_time = (double)a->get_length();
}
@@ -1356,9 +1329,9 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
if (err != OK) {
continue;
}
- scale[0] = post_process_key_value(a, i, scale[0], t->object, t->bone_idx);
+ scale[0] = post_process_key_value(a, i, scale[0], t->object_id, t->bone_idx);
a->try_scale_track_interpolate(i, time, &scale[1]);
- scale[1] = post_process_key_value(a, i, scale[1], t->object, t->bone_idx);
+ scale[1] = post_process_key_value(a, i, scale[1], t->object_id, t->bone_idx);
root_motion_cache.scale += (scale[1] - scale[0]) * blend;
prev_time = !backward ? 0 : (double)a->get_length();
}
@@ -1368,7 +1341,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
if (err != OK) {
continue;
}
- scale = post_process_key_value(a, i, scale, t->object, t->bone_idx);
+ scale = post_process_key_value(a, i, scale, t->object_id, t->bone_idx);
t->scale += (scale - t->init_scale) * blend;
}
#endif // _3D_DISABLED
@@ -1385,18 +1358,19 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
if (err != OK) {
continue;
}
- value = post_process_key_value(a, i, value, t->object, t->shape_index);
+ value = post_process_key_value(a, i, value, t->object_id, t->shape_index);
t->value += (value - t->init_value) * blend;
#endif // _3D_DISABLED
} break;
+ case Animation::TYPE_BEZIER:
case Animation::TYPE_VALUE: {
if (Math::is_zero_approx(blend)) {
continue; // Nothing to blend.
}
TrackCacheValue *t = static_cast<TrackCacheValue *>(track);
if (t->is_continuous) {
- Variant value = a->value_track_interpolate(i, time);
- value = post_process_key_value(a, i, value, t->object);
+ Variant value = ttype == Animation::TYPE_VALUE ? a->value_track_interpolate(i, time) : Variant(a->bezier_track_interpolate(i, time));
+ value = post_process_key_value(a, i, value, t->object_id);
if (value == Variant()) {
continue;
}
@@ -1436,15 +1410,21 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
continue;
}
Variant value = a->track_get_key_value(i, idx);
- value = post_process_key_value(a, i, value, t->object);
- t->object->set_indexed(t->subpath, value);
+ value = post_process_key_value(a, i, value, t->object_id);
+ Object *t_obj = ObjectDB::get_instance(t->object_id);
+ if (t_obj) {
+ t_obj->set_indexed(t->subpath, value);
+ }
} else {
List<int> indices;
a->track_get_key_indices_in_range(i, time, delta, &indices, looped_flag);
for (int &F : indices) {
Variant value = a->track_get_key_value(i, F);
- value = post_process_key_value(a, i, value, t->object);
- t->object->set_indexed(t->subpath, value);
+ value = post_process_key_value(a, i, value, t->object_id);
+ Object *t_obj = ObjectDB::get_instance(t->object_id);
+ if (t_obj) {
+ t_obj->set_indexed(t->subpath, value);
+ }
}
}
}
@@ -1466,31 +1446,23 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
}
StringName method = a->method_track_get_name(i, idx);
Vector<Variant> params = a->method_track_get_params(i, idx);
- _call_object(t->object, method, params, callback_mode_method == ANIMATION_CALLBACK_MODE_METHOD_DEFERRED);
+ _call_object(t->object_id, method, params, callback_mode_method == ANIMATION_CALLBACK_MODE_METHOD_DEFERRED);
} else {
List<int> indices;
a->track_get_key_indices_in_range(i, time, delta, &indices, looped_flag);
for (int &F : indices) {
StringName method = a->method_track_get_name(i, F);
Vector<Variant> params = a->method_track_get_params(i, F);
- _call_object(t->object, method, params, callback_mode_method == ANIMATION_CALLBACK_MODE_METHOD_DEFERRED);
+ _call_object(t->object_id, method, params, callback_mode_method == ANIMATION_CALLBACK_MODE_METHOD_DEFERRED);
}
}
} break;
- case Animation::TYPE_BEZIER: {
- if (Math::is_zero_approx(blend)) {
- continue; // Nothing to blend.
- }
- TrackCacheBezier *t = static_cast<TrackCacheBezier *>(track);
- real_t bezier = a->bezier_track_interpolate(i, time);
- bezier = post_process_key_value(a, i, bezier, t->object);
- t->value += (bezier - t->init_value) * blend;
- } break;
case Animation::TYPE_AUDIO: {
// The end of audio should be observed even if the blend value is 0, build up the information and store to the cache for that.
TrackCacheAudio *t = static_cast<TrackCacheAudio *>(track);
- Node *asp = Object::cast_to<Node>(t->object);
- if (!asp) {
+ Object *t_obj = ObjectDB::get_instance(t->object_id);
+ Node *asp = t_obj ? Object::cast_to<Node>(t_obj) : nullptr;
+ if (!t_obj || !asp) {
t->playing_streams.clear();
continue;
}
@@ -1540,22 +1512,22 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
if (seeked) {
start_ofs += time - a->track_get_key_time(i, idx);
}
- if (t->object->call(SNAME("get_stream")) != t->audio_stream) {
- t->object->call(SNAME("set_stream"), t->audio_stream);
+ if (t_obj->call(SNAME("get_stream")) != t->audio_stream) {
+ t_obj->call(SNAME("set_stream"), t->audio_stream);
t->audio_stream_playback.unref();
if (!playing_audio_stream_players.has(asp)) {
playing_audio_stream_players.push_back(asp);
}
}
- if (!t->object->call(SNAME("is_playing"))) {
- t->object->call(SNAME("play"));
+ if (!t_obj->call(SNAME("is_playing"))) {
+ t_obj->call(SNAME("play"));
}
- if (!t->object->call(SNAME("has_stream_playback"))) {
+ if (!t_obj->call(SNAME("has_stream_playback"))) {
t->audio_stream_playback.unref();
continue;
}
if (t->audio_stream_playback.is_null()) {
- t->audio_stream_playback = t->object->call(SNAME("get_stream_playback"));
+ t->audio_stream_playback = t_obj->call(SNAME("get_stream_playback"));
}
PlayingAudioStreamInfo pasi;
pasi.index = t->audio_stream_playback->play_stream(stream, start_ofs);
@@ -1573,7 +1545,11 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
continue;
}
TrackCacheAnimation *t = static_cast<TrackCacheAnimation *>(track);
- AnimationPlayer *player2 = Object::cast_to<AnimationPlayer>(t->object);
+ Object *t_obj = ObjectDB::get_instance(t->object_id);
+ if (!t_obj) {
+ continue;
+ }
+ AnimationPlayer *player2 = Object::cast_to<AnimationPlayer>(t_obj);
if (!player2) {
continue;
}
@@ -1640,7 +1616,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
void AnimationMixer::_blend_apply() {
// Finally, set the tracks.
- for (const KeyValue<NodePath, TrackCache *> &K : track_cache) {
+ for (const KeyValue<Animation::TypeHash, TrackCache *> &K : track_cache) {
TrackCache *track = K.value;
if (!deterministic && Math::is_zero_approx(track->total_weight)) {
continue;
@@ -1657,26 +1633,34 @@ void AnimationMixer::_blend_apply() {
root_motion_position_accumulator = t->loc;
root_motion_rotation_accumulator = t->rot;
root_motion_scale_accumulator = t->scale;
- } else if (t->skeleton && t->bone_idx >= 0) {
+ } else if (t->skeleton_id.is_valid() && t->bone_idx >= 0) {
+ Skeleton3D *t_skeleton = Object::cast_to<Skeleton3D>(ObjectDB::get_instance(t->skeleton_id));
+ if (!t_skeleton) {
+ return;
+ }
if (t->loc_used) {
- t->skeleton->set_bone_pose_position(t->bone_idx, t->loc);
+ t_skeleton->set_bone_pose_position(t->bone_idx, t->loc);
}
if (t->rot_used) {
- t->skeleton->set_bone_pose_rotation(t->bone_idx, t->rot);
+ t_skeleton->set_bone_pose_rotation(t->bone_idx, t->rot);
}
if (t->scale_used) {
- t->skeleton->set_bone_pose_scale(t->bone_idx, t->scale);
+ t_skeleton->set_bone_pose_scale(t->bone_idx, t->scale);
}
- } else if (!t->skeleton) {
+ } else if (!t->skeleton_id.is_valid()) {
+ Node3D *t_node_3d = Object::cast_to<Node3D>(ObjectDB::get_instance(t->object_id));
+ if (!t_node_3d) {
+ return;
+ }
if (t->loc_used) {
- t->node_3d->set_position(t->loc);
+ t_node_3d->set_position(t->loc);
}
if (t->rot_used) {
- t->node_3d->set_rotation(t->rot.get_euler());
+ t_node_3d->set_rotation(t->rot.get_euler());
}
if (t->scale_used) {
- t->node_3d->set_scale(t->scale);
+ t_node_3d->set_scale(t->scale);
}
}
#endif // _3D_DISABLED
@@ -1685,8 +1669,9 @@ void AnimationMixer::_blend_apply() {
#ifndef _3D_DISABLED
TrackCacheBlendShape *t = static_cast<TrackCacheBlendShape *>(track);
- if (t->mesh_3d) {
- t->mesh_3d->set_blend_shape_value(t->shape_index, t->value);
+ MeshInstance3D *t_mesh_3d = Object::cast_to<MeshInstance3D>(ObjectDB::get_instance(t->object_id));
+ if (t_mesh_3d) {
+ t_mesh_3d->set_blend_shape_value(t->shape_index, t->value);
}
#endif // _3D_DISABLED
} break;
@@ -1710,19 +1695,12 @@ void AnimationMixer::_blend_apply() {
}
}
- // t->object isn't safe here, get instance from id (GH-85365).
- Object *obj = ObjectDB::get_instance(t->object_id);
- if (obj) {
- obj->set_indexed(t->subpath, Animation::cast_from_blendwise(t->value, t->init_value.get_type()));
+ Object *t_obj = ObjectDB::get_instance(t->object_id);
+ if (t_obj) {
+ t_obj->set_indexed(t->subpath, Animation::cast_from_blendwise(t->value, t->init_value.get_type()));
}
} break;
- case Animation::TYPE_BEZIER: {
- TrackCacheBezier *t = static_cast<TrackCacheBezier *>(track);
-
- t->object->set_indexed(t->subpath, t->value);
-
- } break;
case Animation::TYPE_AUDIO: {
TrackCacheAudio *t = static_cast<TrackCacheAudio *>(track);
@@ -1787,7 +1765,7 @@ void AnimationMixer::_blend_apply() {
}
}
-void AnimationMixer::_call_object(Object *p_object, const StringName &p_method, const Vector<Variant> &p_params, bool p_deferred) {
+void AnimationMixer::_call_object(ObjectID p_object_id, const StringName &p_method, const Vector<Variant> &p_params, bool p_deferred) {
// Separate function to use alloca() more efficiently
const Variant **argptrs = (const Variant **)alloca(sizeof(Variant *) * p_params.size());
const Variant *args = p_params.ptr();
@@ -1795,11 +1773,15 @@ void AnimationMixer::_call_object(Object *p_object, const StringName &p_method,
for (uint32_t i = 0; i < argcount; i++) {
argptrs[i] = &args[i];
}
+ Object *t_obj = ObjectDB::get_instance(p_object_id);
+ if (!t_obj) {
+ return;
+ }
if (p_deferred) {
- MessageQueue::get_singleton()->push_callp(p_object, p_method, argptrs, argcount);
+ Callable(t_obj, p_method).call_deferredp(argptrs, argcount);
} else {
Callable::CallError ce;
- p_object->callp(p_method, argptrs, argcount, ce);
+ t_obj->callp(p_method, argptrs, argcount, ce);
}
}
@@ -1879,7 +1861,7 @@ bool AnimationMixer::can_apply_reset() const {
}
void AnimationMixer::_build_backup_track_cache() {
- for (const KeyValue<NodePath, TrackCache *> &K : track_cache) {
+ for (const KeyValue<Animation::TypeHash, TrackCache *> &K : track_cache) {
TrackCache *track = K.value;
track->total_weight = 1.0;
switch (track->type) {
@@ -1888,25 +1870,33 @@ void AnimationMixer::_build_backup_track_cache() {
TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track);
if (t->root_motion) {
// Do nothing.
- } else if (t->skeleton && t->bone_idx >= 0) {
+ } else if (t->skeleton_id.is_valid() && t->bone_idx >= 0) {
+ Skeleton3D *t_skeleton = Object::cast_to<Skeleton3D>(ObjectDB::get_instance(t->skeleton_id));
+ if (!t_skeleton) {
+ return;
+ }
if (t->loc_used) {
- t->loc = t->skeleton->get_bone_pose_position(t->bone_idx);
+ t->loc = t_skeleton->get_bone_pose_position(t->bone_idx);
}
if (t->rot_used) {
- t->rot = t->skeleton->get_bone_pose_rotation(t->bone_idx);
+ t->rot = t_skeleton->get_bone_pose_rotation(t->bone_idx);
}
if (t->scale_used) {
- t->scale = t->skeleton->get_bone_pose_scale(t->bone_idx);
+ t->scale = t_skeleton->get_bone_pose_scale(t->bone_idx);
+ }
+ } else if (!t->skeleton_id.is_valid()) {
+ Node3D *t_node_3d = Object::cast_to<Node3D>(ObjectDB::get_instance(t->object_id));
+ if (!t_node_3d) {
+ return;
}
- } else if (!t->skeleton) {
if (t->loc_used) {
- t->loc = t->node_3d->get_position();
+ t->loc = t_node_3d->get_position();
}
if (t->rot_used) {
- t->rot = t->node_3d->get_quaternion();
+ t->rot = t_node_3d->get_quaternion();
}
if (t->scale_used) {
- t->scale = t->node_3d->get_scale();
+ t->scale = t_node_3d->get_scale();
}
}
#endif // _3D_DISABLED
@@ -1914,25 +1904,28 @@ void AnimationMixer::_build_backup_track_cache() {
case Animation::TYPE_BLEND_SHAPE: {
#ifndef _3D_DISABLED
TrackCacheBlendShape *t = static_cast<TrackCacheBlendShape *>(track);
- if (t->mesh_3d) {
- t->value = t->mesh_3d->get_blend_shape_value(t->shape_index);
+ MeshInstance3D *t_mesh_3d = Object::cast_to<MeshInstance3D>(ObjectDB::get_instance(t->object_id));
+ if (t_mesh_3d) {
+ t->value = t_mesh_3d->get_blend_shape_value(t->shape_index);
}
#endif // _3D_DISABLED
} break;
case Animation::TYPE_VALUE: {
TrackCacheValue *t = static_cast<TrackCacheValue *>(track);
- t->value = t->object->get_indexed(t->subpath);
+ Object *t_obj = ObjectDB::get_instance(t->object_id);
+ if (t_obj) {
+ t->value = t_obj->get_indexed(t->subpath);
+ }
t->is_continuous = true;
} break;
- case Animation::TYPE_BEZIER: {
- TrackCacheBezier *t = static_cast<TrackCacheBezier *>(track);
- t->value = t->object->get_indexed(t->subpath);
- } break;
case Animation::TYPE_AUDIO: {
TrackCacheAudio *t = static_cast<TrackCacheAudio *>(track);
- Node *asp = Object::cast_to<Node>(t->object);
- if (asp) {
- t->object->call(SNAME("set_stream"), Ref<AudioStream>());
+ Object *t_obj = ObjectDB::get_instance(t->object_id);
+ if (t_obj) {
+ Node *asp = Object::cast_to<Node>(t_obj);
+ if (asp) {
+ asp->call(SNAME("set_stream"), Ref<AudioStream>());
+ }
}
} break;
default: {
@@ -1989,7 +1982,7 @@ void AnimationMixer::restore(const Ref<AnimatedValuesBackup> &p_backup) {
ERR_FAIL_COND(p_backup.is_null());
track_cache = p_backup->get_data();
_blend_apply();
- track_cache = HashMap<NodePath, AnimationMixer::TrackCache *>();
+ track_cache = HashMap<Animation::TypeHash, AnimationMixer::TrackCache *>();
cache_valid = false;
}
@@ -2120,7 +2113,7 @@ void AnimationMixer::_bind_methods() {
/* ---- Blending processor ---- */
ClassDB::bind_method(D_METHOD("clear_caches"), &AnimationMixer::clear_caches);
ClassDB::bind_method(D_METHOD("advance", "delta"), &AnimationMixer::advance);
- GDVIRTUAL_BIND(_post_process_key_value, "animation", "track", "value", "object", "object_idx");
+ GDVIRTUAL_BIND(_post_process_key_value, "animation", "track", "value", "object_id", "object_sub_idx");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "active"), "set_active", "is_active");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "deterministic"), "set_deterministic", "is_deterministic");
@@ -2166,10 +2159,10 @@ AnimationMixer::AnimationMixer() {
AnimationMixer::~AnimationMixer() {
}
-void AnimatedValuesBackup::set_data(const HashMap<NodePath, AnimationMixer::TrackCache *> p_data) {
+void AnimatedValuesBackup::set_data(const HashMap<Animation::TypeHash, AnimationMixer::TrackCache *> p_data) {
clear_data();
- for (const KeyValue<NodePath, AnimationMixer::TrackCache *> &E : p_data) {
+ for (const KeyValue<Animation::TypeHash, AnimationMixer::TrackCache *> &E : p_data) {
AnimationMixer::TrackCache *track = get_cache_copy(E.value);
if (!track) {
continue; // Some types of tracks do not get a copy and must be ignored.
@@ -2179,9 +2172,9 @@ void AnimatedValuesBackup::set_data(const HashMap<NodePath, AnimationMixer::Trac
}
}
-HashMap<NodePath, AnimationMixer::TrackCache *> AnimatedValuesBackup::get_data() const {
- HashMap<NodePath, AnimationMixer::TrackCache *> ret;
- for (const KeyValue<NodePath, AnimationMixer::TrackCache *> &E : data) {
+HashMap<Animation::TypeHash, AnimationMixer::TrackCache *> AnimatedValuesBackup::get_data() const {
+ HashMap<Animation::TypeHash, AnimationMixer::TrackCache *> ret;
+ for (const KeyValue<Animation::TypeHash, AnimationMixer::TrackCache *> &E : data) {
AnimationMixer::TrackCache *track = get_cache_copy(E.value);
ERR_CONTINUE(!track); // Backup shouldn't contain tracks that cannot be copied, this is a mistake.
@@ -2191,7 +2184,7 @@ HashMap<NodePath, AnimationMixer::TrackCache *> AnimatedValuesBackup::get_data()
}
void AnimatedValuesBackup::clear_data() {
- for (KeyValue<NodePath, AnimationMixer::TrackCache *> &K : data) {
+ for (KeyValue<Animation::TypeHash, AnimationMixer::TrackCache *> &K : data) {
memdelete(K.value);
}
data.clear();
@@ -2199,6 +2192,7 @@ void AnimatedValuesBackup::clear_data() {
AnimationMixer::TrackCache *AnimatedValuesBackup::get_cache_copy(AnimationMixer::TrackCache *p_cache) const {
switch (p_cache->type) {
+ case Animation::TYPE_BEZIER:
case Animation::TYPE_VALUE: {
AnimationMixer::TrackCacheValue *src = static_cast<AnimationMixer::TrackCacheValue *>(p_cache);
AnimationMixer::TrackCacheValue *tc = memnew(AnimationMixer::TrackCacheValue(*src));
@@ -2219,12 +2213,6 @@ AnimationMixer::TrackCache *AnimatedValuesBackup::get_cache_copy(AnimationMixer:
return tc;
}
- case Animation::TYPE_BEZIER: {
- AnimationMixer::TrackCacheBezier *src = static_cast<AnimationMixer::TrackCacheBezier *>(p_cache);
- AnimationMixer::TrackCacheBezier *tc = memnew(AnimationMixer::TrackCacheBezier(*src));
- return tc;
- }
-
case Animation::TYPE_AUDIO: {
AnimationMixer::TrackCacheAudio *src = static_cast<AnimationMixer::TrackCacheAudio *>(p_cache);
AnimationMixer::TrackCacheAudio *tc = memnew(AnimationMixer::TrackCacheAudio(*src));
diff --git a/scene/animation/animation_mixer.h b/scene/animation/animation_mixer.h
index ffa6dc2e55..098c2c3b86 100644
--- a/scene/animation/animation_mixer.h
+++ b/scene/animation/animation_mixer.h
@@ -31,9 +31,7 @@
#ifndef ANIMATION_MIXER_H
#define ANIMATION_MIXER_H
-#include "scene/3d/mesh_instance_3d.h"
-#include "scene/3d/node_3d.h"
-#include "scene/3d/skeleton_3d.h"
+#include "scene/main/node.h"
#include "scene/resources/animation.h"
#include "scene/resources/animation_library.h"
#include "scene/resources/audio_stream_polyphonic.h"
@@ -138,7 +136,7 @@ protected:
bool root_motion = false;
uint64_t setup_pass = 0;
Animation::TrackType type = Animation::TrackType::TYPE_ANIMATION;
- Object *object = nullptr;
+ NodePath path;
ObjectID object_id;
real_t total_weight = 0.0;
@@ -147,7 +145,6 @@ protected:
root_motion(p_other.root_motion),
setup_pass(p_other.setup_pass),
type(p_other.type),
- object(p_other.object),
object_id(p_other.object_id),
total_weight(p_other.total_weight) {}
@@ -156,8 +153,7 @@ protected:
struct TrackCacheTransform : public TrackCache {
#ifndef _3D_DISABLED
- Node3D *node_3d = nullptr;
- Skeleton3D *skeleton = nullptr;
+ ObjectID skeleton_id;
#endif // _3D_DISABLED
int bone_idx = -1;
bool loc_used = false;
@@ -173,8 +169,7 @@ protected:
TrackCacheTransform(const TrackCacheTransform &p_other) :
TrackCache(p_other),
#ifndef _3D_DISABLED
- node_3d(p_other.node_3d),
- skeleton(p_other.skeleton),
+ skeleton_id(p_other.skeleton_id),
#endif
bone_idx(p_other.bone_idx),
loc_used(p_other.loc_used),
@@ -201,14 +196,12 @@ protected:
};
struct TrackCacheBlendShape : public TrackCache {
- MeshInstance3D *mesh_3d = nullptr;
float init_value = 0;
float value = 0;
int shape_index = -1;
TrackCacheBlendShape(const TrackCacheBlendShape &p_other) :
TrackCache(p_other),
- mesh_3d(p_other.mesh_3d),
init_value(p_other.init_value),
value(p_other.value),
shape_index(p_other.shape_index) {}
@@ -247,23 +240,6 @@ protected:
~TrackCacheMethod() {}
};
- struct TrackCacheBezier : public TrackCache {
- real_t init_value = 0.0;
- real_t value = 0.0;
- Vector<StringName> subpath;
-
- TrackCacheBezier(const TrackCacheBezier &p_other) :
- TrackCache(p_other),
- init_value(p_other.init_value),
- value(p_other.value),
- subpath(p_other.subpath) {}
-
- TrackCacheBezier() {
- type = Animation::TYPE_BEZIER;
- }
- ~TrackCacheBezier() {}
- };
-
// Audio stream information for each audio stream placed on the track.
struct PlayingAudioStreamInfo {
AudioStreamPlaybackPolyphonic::ID index = -1; // ID retrieved from AudioStreamPlaybackPolyphonic.
@@ -309,7 +285,7 @@ protected:
};
RootMotionCache root_motion_cache;
- HashMap<NodePath, TrackCache *> track_cache;
+ HashMap<Animation::TypeHash, TrackCache *> track_cache;
HashSet<TrackCache *> playing_caches;
Vector<Node *> playing_audio_stream_players;
@@ -352,9 +328,9 @@ protected:
/* ---- Blending processor ---- */
virtual void _process_animation(double p_delta, bool p_update_only = false);
- virtual Variant _post_process_key_value(const Ref<Animation> &p_anim, int p_track, Variant p_value, const Object *p_object, int p_object_idx = -1);
- Variant post_process_key_value(const Ref<Animation> &p_anim, int p_track, Variant p_value, const Object *p_object, int p_object_idx = -1);
- GDVIRTUAL5RC(Variant, _post_process_key_value, Ref<Animation>, int, Variant, Object *, int);
+ virtual Variant _post_process_key_value(const Ref<Animation> &p_anim, int p_track, Variant p_value, ObjectID p_object_id, int p_object_sub_idx = -1);
+ Variant post_process_key_value(const Ref<Animation> &p_anim, int p_track, Variant p_value, ObjectID p_object_id, int p_object_sub_idx = -1);
+ GDVIRTUAL5RC(Variant, _post_process_key_value, Ref<Animation>, int, Variant, ObjectID, int);
void _blend_init();
virtual bool _blend_pre_process(double p_delta, int p_track_count, const HashMap<NodePath, int> &p_track_map);
@@ -362,7 +338,13 @@ protected:
void _blend_process(double p_delta, bool p_update_only = false);
void _blend_apply();
virtual void _blend_post_process();
- void _call_object(Object *p_object, const StringName &p_method, const Vector<Variant> &p_params, bool p_deferred);
+ void _call_object(ObjectID p_object_id, const StringName &p_method, const Vector<Variant> &p_params, bool p_deferred);
+
+#ifndef DISABLE_DEPRECATED
+ virtual Variant _post_process_key_value_bind_compat_86687(const Ref<Animation> &p_anim, int p_track, Variant p_value, Object *p_object, int p_object_idx = -1);
+
+ static void _bind_compatibility_methods();
+#endif // DISABLE_DEPRECATED
public:
/* ---- Data lists ---- */
@@ -444,11 +426,11 @@ public:
class AnimatedValuesBackup : public RefCounted {
GDCLASS(AnimatedValuesBackup, RefCounted);
- HashMap<NodePath, AnimationMixer::TrackCache *> data;
+ HashMap<Animation::TypeHash, AnimationMixer::TrackCache *> data;
public:
- void set_data(const HashMap<NodePath, AnimationMixer::TrackCache *> p_data);
- HashMap<NodePath, AnimationMixer::TrackCache *> get_data() const;
+ void set_data(const HashMap<Animation::TypeHash, AnimationMixer::TrackCache *> p_data);
+ HashMap<Animation::TypeHash, AnimationMixer::TrackCache *> get_data() const;
void clear_data();
AnimationMixer::TrackCache *get_cache_copy(AnimationMixer::TrackCache *p_cache) const;
diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp
index da0687dd70..17fbc68973 100644
--- a/scene/animation/animation_tree.cpp
+++ b/scene/animation/animation_tree.cpp
@@ -619,7 +619,7 @@ void AnimationTree::_tree_changed() {
return;
}
- call_deferred(SNAME("_update_properties"));
+ callable_mp(this, &AnimationTree::_update_properties).call_deferred();
properties_dirty = true;
}
@@ -886,8 +886,6 @@ void AnimationTree::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_animation_player", "path"), &AnimationTree::set_animation_player);
ClassDB::bind_method(D_METHOD("get_animation_player"), &AnimationTree::get_animation_player);
- ClassDB::bind_method(D_METHOD("_update_properties"), &AnimationTree::_update_properties);
-
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "tree_root", PROPERTY_HINT_RESOURCE_TYPE, "AnimationRootNode"), "set_tree_root", "get_tree_root");
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "advance_expression_base_node", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Node"), "set_advance_expression_base_node", "get_advance_expression_base_node");
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "anim_player", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "AnimationPlayer"), "set_animation_player", "get_animation_player");
diff --git a/scene/animation/root_motion_view.cpp b/scene/animation/root_motion_view.cpp
index 645850015b..fd520dadd6 100644
--- a/scene/animation/root_motion_view.cpp
+++ b/scene/animation/root_motion_view.cpp
@@ -28,6 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
+#ifndef _3D_DISABLED
+
#include "root_motion_view.h"
#include "scene/animation/animation_tree.h"
@@ -203,3 +205,5 @@ RootMotionView::RootMotionView() {
RootMotionView::~RootMotionView() {
set_base(RID());
}
+
+#endif // _3D_DISABLED
diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp
index 98e340d7fc..9d24595916 100644
--- a/scene/gui/color_picker.cpp
+++ b/scene/gui/color_picker.cpp
@@ -219,7 +219,7 @@ void ColorPicker::finish_shaders() {
}
void ColorPicker::set_focus_on_line_edit() {
- c_text->call_deferred(SNAME("grab_focus"));
+ callable_mp((Control *)c_text, &Control::grab_focus).call_deferred();
}
void ColorPicker::_update_controls() {
@@ -557,6 +557,24 @@ void ColorPicker::_html_submitted(const String &p_html) {
}
Color new_color = Color::from_string(p_html.strip_edges(), color);
+ String html_no_prefix = p_html.strip_edges().trim_prefix("#");
+ if (html_no_prefix.is_valid_hex_number(false)) {
+ // Convert invalid HTML color codes that software like Figma supports.
+ if (html_no_prefix.length() == 1) {
+ // Turn `#1` into `#111111`.
+ html_no_prefix = html_no_prefix.repeat(6);
+ } else if (html_no_prefix.length() == 2) {
+ // Turn `#12` into `#121212`.
+ html_no_prefix = html_no_prefix.repeat(3);
+ } else if (html_no_prefix.length() == 5) {
+ // Turn `#12345` into `#11223344`.
+ html_no_prefix = html_no_prefix.left(4);
+ } else if (html_no_prefix.length() == 7) {
+ // Turn `#1234567` into `#123456`.
+ html_no_prefix = html_no_prefix.left(6);
+ }
+ }
+ new_color = Color::from_string(html_no_prefix, new_color);
if (!is_editing_alpha()) {
new_color.a = color.a;
diff --git a/scene/gui/container.cpp b/scene/gui/container.cpp
index 4e23db4cae..c6e66c95c6 100644
--- a/scene/gui/container.cpp
+++ b/scene/gui/container.cpp
@@ -30,7 +30,6 @@
#include "container.h"
-#include "core/object/message_queue.h"
#include "scene/scene_string_names.h"
void Container::_child_minsize_changed() {
@@ -138,7 +137,7 @@ void Container::queue_sort() {
return;
}
- MessageQueue::get_singleton()->push_callable(callable_mp(this, &Container::_sort_children));
+ callable_mp(this, &Container::_sort_children).call_deferred();
pending_sort = true;
}
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index a211227990..349102fafb 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -33,7 +33,6 @@
#include "container.h"
#include "core/config/project_settings.h"
#include "core/math/geometry_2d.h"
-#include "core/object/message_queue.h"
#include "core/os/keyboard.h"
#include "core/os/os.h"
#include "core/string/print_string.h"
@@ -1631,7 +1630,7 @@ void Control::update_minimum_size() {
}
data.updating_last_minimum_size = true;
- MessageQueue::get_singleton()->push_callable(callable_mp(this, &Control::_update_minimum_size));
+ callable_mp(this, &Control::_update_minimum_size).call_deferred();
}
void Control::set_block_minimum_size_adjust(bool p_block) {
diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp
index 3e827e76dc..8339d34f83 100644
--- a/scene/gui/dialogs.cpp
+++ b/scene/gui/dialogs.cpp
@@ -129,7 +129,7 @@ void AcceptDialog::_cancel_pressed() {
parent_visible = nullptr;
}
- call_deferred(SNAME("hide"));
+ callable_mp((Window *)this, &Window::hide).call_deferred();
emit_signal(SNAME("canceled"));
diff --git a/scene/gui/graph_edit_arranger.cpp b/scene/gui/graph_edit_arranger.cpp
index 345421db31..29c3056b3b 100644
--- a/scene/gui/graph_edit_arranger.cpp
+++ b/scene/gui/graph_edit_arranger.cpp
@@ -421,7 +421,7 @@ void GraphEditArranger::_calculate_inner_shifts(Dictionary &r_inner_shifts, cons
}
}
-float GraphEditArranger::_calculate_threshold(StringName p_v, StringName p_w, const Dictionary &r_node_names, const HashMap<int, Vector<StringName>> &r_layers, const Dictionary &r_root, const Dictionary &r_align, const Dictionary &r_inner_shift, real_t p_current_threshold, const HashMap<StringName, Vector2> &r_node_positions) {
+float GraphEditArranger::_calculate_threshold(const StringName &p_v, const StringName &p_w, const Dictionary &r_node_names, const HashMap<int, Vector<StringName>> &r_layers, const Dictionary &r_root, const Dictionary &r_align, const Dictionary &r_inner_shift, real_t p_current_threshold, const HashMap<StringName, Vector2> &r_node_positions) {
#define MAX_ORDER 2147483647
#define ORDER(node, layers) \
for (unsigned int i = 0; i < layers.size(); i++) { \
@@ -503,7 +503,7 @@ float GraphEditArranger::_calculate_threshold(StringName p_v, StringName p_w, co
return threshold;
}
-void GraphEditArranger::_place_block(StringName p_v, float p_delta, const HashMap<int, Vector<StringName>> &r_layers, const Dictionary &r_root, const Dictionary &r_align, const Dictionary &r_node_name, const Dictionary &r_inner_shift, Dictionary &r_sink, Dictionary &r_shift, HashMap<StringName, Vector2> &r_node_positions) {
+void GraphEditArranger::_place_block(const StringName &p_v, float p_delta, const HashMap<int, Vector<StringName>> &r_layers, const Dictionary &r_root, const Dictionary &r_align, const Dictionary &r_node_name, const Dictionary &r_inner_shift, Dictionary &r_sink, Dictionary &r_shift, HashMap<StringName, Vector2> &r_node_positions) {
#define PRED(node, layers) \
for (unsigned int i = 0; i < layers.size(); i++) { \
int index = layers[i].find(node); \
diff --git a/scene/gui/graph_edit_arranger.h b/scene/gui/graph_edit_arranger.h
index e79944e5dd..925b58d428 100644
--- a/scene/gui/graph_edit_arranger.h
+++ b/scene/gui/graph_edit_arranger.h
@@ -54,8 +54,8 @@ class GraphEditArranger : public RefCounted {
void _horizontal_alignment(Dictionary &r_root, Dictionary &r_align, const HashMap<int, Vector<StringName>> &r_layers, const HashMap<StringName, HashSet<StringName>> &r_upper_neighbours, const HashSet<StringName> &r_selected_nodes);
void _crossing_minimisation(HashMap<int, Vector<StringName>> &r_layers, const HashMap<StringName, HashSet<StringName>> &r_upper_neighbours);
void _calculate_inner_shifts(Dictionary &r_inner_shifts, const Dictionary &r_root, const Dictionary &r_node_names, const Dictionary &r_align, const HashSet<StringName> &r_block_heads, const HashMap<StringName, Pair<int, int>> &r_port_info);
- float _calculate_threshold(StringName p_v, StringName p_w, const Dictionary &r_node_names, const HashMap<int, Vector<StringName>> &r_layers, const Dictionary &r_root, const Dictionary &r_align, const Dictionary &r_inner_shift, real_t p_current_threshold, const HashMap<StringName, Vector2> &r_node_positions);
- void _place_block(StringName p_v, float p_delta, const HashMap<int, Vector<StringName>> &r_layers, const Dictionary &r_root, const Dictionary &r_align, const Dictionary &r_node_name, const Dictionary &r_inner_shift, Dictionary &r_sink, Dictionary &r_shift, HashMap<StringName, Vector2> &r_node_positions);
+ float _calculate_threshold(const StringName &p_v, const StringName &p_w, const Dictionary &r_node_names, const HashMap<int, Vector<StringName>> &r_layers, const Dictionary &r_root, const Dictionary &r_align, const Dictionary &r_inner_shift, real_t p_current_threshold, const HashMap<StringName, Vector2> &r_node_positions);
+ void _place_block(const StringName &p_v, float p_delta, const HashMap<int, Vector<StringName>> &r_layers, const Dictionary &r_root, const Dictionary &r_align, const Dictionary &r_node_name, const Dictionary &r_inner_shift, Dictionary &r_sink, Dictionary &r_shift, HashMap<StringName, Vector2> &r_node_positions);
public:
void arrange_nodes();
diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp
index 3b1c1a153f..1b960a9b62 100644
--- a/scene/gui/graph_node.cpp
+++ b/scene/gui/graph_node.cpp
@@ -482,6 +482,27 @@ Color GraphNode::get_slot_color_left(int p_slot_index) const {
return slot_table[p_slot_index].color_left;
}
+void GraphNode::set_slot_custom_icon_left(int p_slot_index, const Ref<Texture2D> &p_custom_icon) {
+ ERR_FAIL_COND_MSG(!slot_table.has(p_slot_index), vformat("Cannot set custom_port_icon_left for the slot with index '%d' because it hasn't been enabled.", p_slot_index));
+
+ if (slot_table[p_slot_index].custom_port_icon_left == p_custom_icon) {
+ return;
+ }
+
+ slot_table[p_slot_index].custom_port_icon_left = p_custom_icon;
+ queue_redraw();
+ port_pos_dirty = true;
+
+ emit_signal(SNAME("slot_updated"), p_slot_index);
+}
+
+Ref<Texture2D> GraphNode::get_slot_custom_icon_left(int p_slot_index) const {
+ if (!slot_table.has(p_slot_index)) {
+ return Ref<Texture2D>();
+ }
+ return slot_table[p_slot_index].custom_port_icon_left;
+}
+
bool GraphNode::is_slot_enabled_right(int p_slot_index) const {
if (!slot_table.has(p_slot_index)) {
return false;
@@ -545,6 +566,27 @@ Color GraphNode::get_slot_color_right(int p_slot_index) const {
return slot_table[p_slot_index].color_right;
}
+void GraphNode::set_slot_custom_icon_right(int p_slot_index, const Ref<Texture2D> &p_custom_icon) {
+ ERR_FAIL_COND_MSG(!slot_table.has(p_slot_index), vformat("Cannot set custom_port_icon_right for the slot with index '%d' because it hasn't been enabled.", p_slot_index));
+
+ if (slot_table[p_slot_index].custom_port_icon_right == p_custom_icon) {
+ return;
+ }
+
+ slot_table[p_slot_index].custom_port_icon_right = p_custom_icon;
+ queue_redraw();
+ port_pos_dirty = true;
+
+ emit_signal(SNAME("slot_updated"), p_slot_index);
+}
+
+Ref<Texture2D> GraphNode::get_slot_custom_icon_right(int p_slot_index) const {
+ if (!slot_table.has(p_slot_index)) {
+ return Ref<Texture2D>();
+ }
+ return slot_table[p_slot_index].custom_port_icon_right;
+}
+
bool GraphNode::is_slot_draw_stylebox(int p_slot_index) const {
if (!slot_table.has(p_slot_index)) {
return false;
@@ -797,6 +839,9 @@ void GraphNode::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_slot_color_left", "slot_index", "color"), &GraphNode::set_slot_color_left);
ClassDB::bind_method(D_METHOD("get_slot_color_left", "slot_index"), &GraphNode::get_slot_color_left);
+ ClassDB::bind_method(D_METHOD("set_slot_custom_icon_left", "slot_index", "custom_icon"), &GraphNode::set_slot_custom_icon_left);
+ ClassDB::bind_method(D_METHOD("get_slot_custom_icon_left", "slot_index"), &GraphNode::get_slot_custom_icon_left);
+
ClassDB::bind_method(D_METHOD("is_slot_enabled_right", "slot_index"), &GraphNode::is_slot_enabled_right);
ClassDB::bind_method(D_METHOD("set_slot_enabled_right", "slot_index", "enable"), &GraphNode::set_slot_enabled_right);
@@ -806,6 +851,9 @@ void GraphNode::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_slot_color_right", "slot_index", "color"), &GraphNode::set_slot_color_right);
ClassDB::bind_method(D_METHOD("get_slot_color_right", "slot_index"), &GraphNode::get_slot_color_right);
+ ClassDB::bind_method(D_METHOD("set_slot_custom_icon_right", "slot_index", "custom_icon"), &GraphNode::set_slot_custom_icon_right);
+ ClassDB::bind_method(D_METHOD("get_slot_custom_icon_right", "slot_index"), &GraphNode::get_slot_custom_icon_right);
+
ClassDB::bind_method(D_METHOD("is_slot_draw_stylebox", "slot_index"), &GraphNode::is_slot_draw_stylebox);
ClassDB::bind_method(D_METHOD("set_slot_draw_stylebox", "slot_index", "enable"), &GraphNode::set_slot_draw_stylebox);
diff --git a/scene/gui/graph_node.h b/scene/gui/graph_node.h
index 04ca9e7cb4..a0610b37fb 100644
--- a/scene/gui/graph_node.h
+++ b/scene/gui/graph_node.h
@@ -129,6 +129,9 @@ public:
void set_slot_color_left(int p_slot_index, const Color &p_color);
Color get_slot_color_left(int p_slot_index) const;
+ void set_slot_custom_icon_left(int p_slot_index, const Ref<Texture2D> &p_custom_icon);
+ Ref<Texture2D> get_slot_custom_icon_left(int p_slot_index) const;
+
bool is_slot_enabled_right(int p_slot_index) const;
void set_slot_enabled_right(int p_slot_index, bool p_enable);
@@ -138,6 +141,9 @@ public:
void set_slot_color_right(int p_slot_index, const Color &p_color);
Color get_slot_color_right(int p_slot_index) const;
+ void set_slot_custom_icon_right(int p_slot_index, const Ref<Texture2D> &p_custom_icon);
+ Ref<Texture2D> get_slot_custom_icon_right(int p_slot_index) const;
+
bool is_slot_draw_stylebox(int p_slot_index) const;
void set_slot_draw_stylebox(int p_slot_index, bool p_enable);
diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp
index 7d34358af2..d11c4813b2 100644
--- a/scene/gui/line_edit.cpp
+++ b/scene/gui/line_edit.cpp
@@ -31,7 +31,6 @@
#include "line_edit.h"
#include "core/input/input_map.h"
-#include "core/object/message_queue.h"
#include "core/os/keyboard.h"
#include "core/os/os.h"
#include "core/string/print_string.h"
@@ -270,7 +269,7 @@ void LineEdit::gui_input(const Ref<InputEvent> &p_event) {
if (!text_changed_dirty) {
if (is_inside_tree()) {
- MessageQueue::get_singleton()->push_call(this, "_text_changed");
+ callable_mp(this, &LineEdit::_text_changed).call_deferred();
}
text_changed_dirty = true;
}
@@ -714,7 +713,7 @@ void LineEdit::drop_data(const Point2 &p_point, const Variant &p_data) {
select(caret_column_tmp, caret_column);
if (!text_changed_dirty) {
if (is_inside_tree()) {
- MessageQueue::get_singleton()->push_call(this, "_text_changed");
+ callable_mp(this, &LineEdit::_text_changed).call_deferred();
}
text_changed_dirty = true;
}
@@ -1190,7 +1189,7 @@ void LineEdit::paste_text() {
if (!text_changed_dirty) {
if (is_inside_tree() && text.length() != prev_len) {
- MessageQueue::get_singleton()->push_call(this, "_text_changed");
+ callable_mp(this, &LineEdit::_text_changed).call_deferred();
}
text_changed_dirty = true;
}
@@ -1504,7 +1503,7 @@ void LineEdit::delete_text(int p_from_column, int p_to_column) {
if (!text_changed_dirty) {
if (is_inside_tree()) {
- MessageQueue::get_singleton()->push_call(this, "_text_changed");
+ callable_mp(this, &LineEdit::_text_changed).call_deferred();
}
text_changed_dirty = true;
}
@@ -2512,8 +2511,6 @@ void LineEdit::_validate_property(PropertyInfo &p_property) const {
}
void LineEdit::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_text_changed"), &LineEdit::_text_changed);
-
ClassDB::bind_method(D_METHOD("set_horizontal_alignment", "alignment"), &LineEdit::set_horizontal_alignment);
ClassDB::bind_method(D_METHOD("get_horizontal_alignment"), &LineEdit::get_horizontal_alignment);
diff --git a/scene/gui/popup.cpp b/scene/gui/popup.cpp
index 8369bedda9..0c5a882044 100644
--- a/scene/gui/popup.cpp
+++ b/scene/gui/popup.cpp
@@ -123,7 +123,7 @@ void Popup::_close_pressed() {
_deinitialize_visible_parents();
- call_deferred(SNAME("hide"));
+ callable_mp((Window *)this, &Window::hide).call_deferred();
}
void Popup::_post_popup() {
diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp
index 8af05bd205..1923322c22 100644
--- a/scene/gui/popup_menu.cpp
+++ b/scene/gui/popup_menu.cpp
@@ -287,8 +287,7 @@ int PopupMenu::_get_items_total_height() const {
items_total_height += _get_item_height(i) + theme_cache.v_separation;
}
- // Subtract a separator which is not needed for the last item.
- return items_total_height - theme_cache.v_separation;
+ return items_total_height;
}
int PopupMenu::_get_mouse_over(const Point2 &p_over) const {
@@ -297,14 +296,14 @@ int PopupMenu::_get_mouse_over(const Point2 &p_over) const {
}
// Accounts for margin in the margin container
- Point2 ofs = theme_cache.panel_style->get_offset() + Point2(0, theme_cache.v_separation / 2);
+ Point2 ofs = theme_cache.panel_style->get_offset();
if (ofs.y > p_over.y) {
return -1;
}
for (int i = 0; i < items.size(); i++) {
- ofs.y += i > 0 ? theme_cache.v_separation : (float)theme_cache.v_separation / 2;
+ ofs.y += theme_cache.v_separation;
ofs.y += _get_item_height(i);
@@ -794,9 +793,7 @@ void PopupMenu::_draw_items() {
}
}
- Color icon_color(1, 1, 1, items[i].disabled && !items[i].separator ? 0.5 : 1);
-
- icon_color *= items[i].icon_modulate;
+ Color icon_color = items[i].icon_modulate;
// For non-separator items, add some padding for the content.
if (!items[i].separator) {
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index 2d5a32dfdd..c5d1a6cd3c 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -2805,7 +2805,7 @@ void RichTextLabel::_thread_function(void *p_userdata) {
set_current_thread_safe_for_nodes(true);
_process_line_caches();
updating.store(false);
- call_deferred(SNAME("thread_end"));
+ callable_mp(this, &RichTextLabel::_thread_end).call_deferred();
}
void RichTextLabel::_thread_end() {
@@ -5945,8 +5945,6 @@ void RichTextLabel::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_menu_visible"), &RichTextLabel::is_menu_visible);
ClassDB::bind_method(D_METHOD("menu_option", "option"), &RichTextLabel::menu_option);
- ClassDB::bind_method(D_METHOD("_thread_end"), &RichTextLabel::_thread_end);
-
#ifndef DISABLE_DEPRECATED
ClassDB::bind_compatibility_method(D_METHOD("push_font", "font", "font_size"), &RichTextLabel::push_font);
ClassDB::bind_compatibility_method(D_METHOD("set_table_column_expand", "column", "expand", "ratio"), &RichTextLabel::set_table_column_expand);
diff --git a/scene/gui/scroll_container.cpp b/scene/gui/scroll_container.cpp
index b4e28a1f1b..89d308de3f 100644
--- a/scene/gui/scroll_container.cpp
+++ b/scene/gui/scroll_container.cpp
@@ -346,7 +346,7 @@ void ScrollContainer::_notification(int p_what) {
case NOTIFICATION_LAYOUT_DIRECTION_CHANGED:
case NOTIFICATION_TRANSLATION_CHANGED: {
_updating_scrollbars = true;
- call_deferred(SNAME("_update_scrollbar_position"));
+ callable_mp(this, &ScrollContainer::_update_scrollbar_position).call_deferred();
} break;
case NOTIFICATION_READY: {
@@ -573,8 +573,6 @@ VScrollBar *ScrollContainer::get_v_scroll_bar() {
}
void ScrollContainer::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_update_scrollbar_position"), &ScrollContainer::_update_scrollbar_position);
-
ClassDB::bind_method(D_METHOD("set_h_scroll", "value"), &ScrollContainer::set_h_scroll);
ClassDB::bind_method(D_METHOD("get_h_scroll"), &ScrollContainer::get_h_scroll);
diff --git a/scene/gui/spin_box.cpp b/scene/gui/spin_box.cpp
index bd549a6e4a..d482495ca0 100644
--- a/scene/gui/spin_box.cpp
+++ b/scene/gui/spin_box.cpp
@@ -280,8 +280,8 @@ void SpinBox::_notification(int p_what) {
} break;
case NOTIFICATION_THEME_CHANGED: {
- call_deferred(SNAME("update_minimum_size"));
- get_line_edit()->call_deferred(SNAME("update_minimum_size"));
+ callable_mp((Control *)this, &Control::update_minimum_size).call_deferred();
+ callable_mp((Control *)get_line_edit(), &Control::update_minimum_size).call_deferred();
} break;
case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: {
diff --git a/scene/gui/tab_bar.cpp b/scene/gui/tab_bar.cpp
index 718ccccc2c..c153f8bd7d 100644
--- a/scene/gui/tab_bar.cpp
+++ b/scene/gui/tab_bar.cpp
@@ -30,7 +30,6 @@
#include "tab_bar.h"
-#include "core/object/message_queue.h"
#include "core/string/translation.h"
#include "scene/gui/box_container.h"
#include "scene/gui/label.h"
@@ -516,7 +515,13 @@ void TabBar::_draw_tab(Ref<StyleBox> &p_tab_style, Color &p_font_color, int p_in
bool rtl = is_layout_rtl();
Rect2 sb_rect = Rect2(p_x, 0, tabs[p_index].size_cache, get_size().height);
+ if (tab_style_v_flip) {
+ draw_set_transform(Point2(0.0, p_tab_style->get_draw_rect(sb_rect).size.y), 0.0, Size2(1.0, -1.0));
+ }
p_tab_style->draw(ci, sb_rect);
+ if (tab_style_v_flip) {
+ draw_set_transform(Point2(), 0.0, Size2(1.0, 1.0));
+ }
if (p_focus) {
Ref<StyleBox> focus_style = theme_cache.tab_focus_style;
focus_style->draw(ci, sb_rect);
@@ -1367,6 +1372,10 @@ bool TabBar::get_clip_tabs() const {
return clip_tabs;
}
+void TabBar::set_tab_style_v_flip(bool p_tab_style_v_flip) {
+ tab_style_v_flip = p_tab_style_v_flip;
+}
+
void TabBar::move_tab(int p_from, int p_to) {
if (p_from == p_to) {
return;
diff --git a/scene/gui/tab_bar.h b/scene/gui/tab_bar.h
index 28e3411f3d..9674187fb3 100644
--- a/scene/gui/tab_bar.h
+++ b/scene/gui/tab_bar.h
@@ -91,6 +91,7 @@ private:
bool clip_tabs = true;
int rb_hover = -1;
bool rb_pressing = false;
+ bool tab_style_v_flip = false;
bool select_with_rmb = false;
@@ -210,6 +211,8 @@ public:
void set_clip_tabs(bool p_clip_tabs);
bool get_clip_tabs() const;
+ void set_tab_style_v_flip(bool p_tab_style_v_flip);
+
void move_tab(int p_from, int p_to);
void set_tab_close_display_policy(CloseButtonDisplayPolicy p_policy);
diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp
index 0f461f4865..ef01d9ec5d 100644
--- a/scene/gui/tab_container.cpp
+++ b/scene/gui/tab_container.cpp
@@ -35,7 +35,7 @@
#include "scene/gui/texture_rect.h"
#include "scene/theme/theme_db.h"
-int TabContainer::_get_top_margin() const {
+int TabContainer::_get_tab_height() const {
int height = 0;
if (tabs_visible && get_tab_count() > 0) {
height = tab_bar->get_minimum_size().height;
@@ -54,31 +54,33 @@ void TabContainer::gui_input(const Ref<InputEvent> &p_event) {
if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
Point2 pos = mb->get_position();
Size2 size = get_size();
+ real_t content_height = size.height - _get_tab_height();
// Click must be on tabs in the tab header area.
- if (pos.y > _get_top_margin()) {
+ if (tabs_position == POSITION_TOP && pos.y > _get_tab_height()) {
+ return;
+ }
+ if (tabs_position == POSITION_BOTTOM && pos.y < content_height) {
return;
}
// Handle menu button.
- if (is_layout_rtl()) {
- if (popup && pos.x < theme_cache.menu_icon->get_width()) {
- emit_signal(SNAME("pre_popup_pressed"));
-
- Vector2 popup_pos = get_screen_position();
- popup_pos.y += theme_cache.menu_icon->get_height();
-
- popup->set_position(popup_pos);
- popup->popup();
- return;
- }
- } else {
- if (popup && pos.x > size.width - theme_cache.menu_icon->get_width()) {
+ if (popup) {
+ if (is_layout_rtl() ? pos.x < theme_cache.menu_icon->get_width() : pos.x > size.width - theme_cache.menu_icon->get_width()) {
emit_signal(SNAME("pre_popup_pressed"));
Vector2 popup_pos = get_screen_position();
- popup_pos.x += size.width - popup->get_size().width;
- popup_pos.y += theme_cache.menu_icon->get_height();
+ if (!is_layout_rtl()) {
+ popup_pos.x += size.width - popup->get_size().width;
+ }
+ popup_pos.y += _get_tab_height() / 2.0;
+ if (tabs_position == POSITION_BOTTOM) {
+ popup_pos.y += content_height;
+ popup_pos.y -= popup->get_size().height;
+ popup_pos.y -= theme_cache.menu_icon->get_height() / 2.0;
+ } else {
+ popup_pos.y += theme_cache.menu_icon->get_height() / 2.0;
+ }
popup->set_position(popup_pos);
popup->popup();
@@ -94,7 +96,14 @@ void TabContainer::gui_input(const Ref<InputEvent> &p_event) {
Size2 size = get_size();
// Mouse must be on tabs in the tab header area.
- if (pos.y > _get_top_margin()) {
+ if (tabs_position == POSITION_TOP && pos.y > _get_tab_height()) {
+ if (menu_hovered) {
+ menu_hovered = false;
+ queue_redraw();
+ }
+ return;
+ }
+ if (tabs_position == POSITION_BOTTOM && pos.y < size.height - _get_tab_height()) {
if (menu_hovered) {
menu_hovered = false;
queue_redraw();
@@ -165,21 +174,22 @@ void TabContainer::_notification(int p_what) {
return;
}
- int header_height = _get_top_margin();
+ int header_height = _get_tab_height();
+ int header_voffset = int(tabs_position == POSITION_BOTTOM) * (size.height - header_height);
// Draw background for the tabbar.
- theme_cache.tabbar_style->draw(canvas, Rect2(0, 0, size.width, header_height));
+ theme_cache.tabbar_style->draw(canvas, Rect2(0, header_voffset, size.width, header_height));
// Draw the background for the tab's content.
- theme_cache.panel_style->draw(canvas, Rect2(0, header_height, size.width, size.height - header_height));
+ theme_cache.panel_style->draw(canvas, Rect2(0, int(tabs_position == POSITION_TOP) * header_height, size.width, size.height - header_height));
// Draw the popup menu.
if (get_popup()) {
int x = is_layout_rtl() ? 0 : get_size().width - theme_cache.menu_icon->get_width();
if (menu_hovered) {
- theme_cache.menu_hl_icon->draw(get_canvas_item(), Point2(x, (header_height - theme_cache.menu_hl_icon->get_height()) / 2));
+ theme_cache.menu_hl_icon->draw(get_canvas_item(), Point2(x, header_voffset + (header_height - theme_cache.menu_hl_icon->get_height()) / 2));
} else {
- theme_cache.menu_icon->draw(get_canvas_item(), Point2(x, (header_height - theme_cache.menu_icon->get_height()) / 2));
+ theme_cache.menu_icon->draw(get_canvas_item(), Point2(x, header_voffset + (header_height - theme_cache.menu_icon->get_height()) / 2));
}
}
} break;
@@ -243,6 +253,12 @@ void TabContainer::_repaint() {
Vector<Control *> controls = _get_tab_controls();
int current = get_current_tab();
+ if (tabs_position == POSITION_BOTTOM) {
+ tab_bar->set_anchors_and_offsets_preset(PRESET_BOTTOM_WIDE);
+ } else {
+ tab_bar->set_anchors_and_offsets_preset(PRESET_TOP_WIDE);
+ }
+
for (int i = 0; i < controls.size(); i++) {
Control *c = controls[i];
@@ -251,7 +267,11 @@ void TabContainer::_repaint() {
c->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
if (tabs_visible) {
- c->set_offset(SIDE_TOP, _get_top_margin());
+ if (tabs_position == POSITION_BOTTOM) {
+ c->set_offset(SIDE_BOTTOM, -_get_tab_height());
+ } else {
+ c->set_offset(SIDE_TOP, _get_tab_height());
+ }
}
c->set_offset(SIDE_TOP, c->get_offset(SIDE_TOP) + theme_cache.panel_style->get_margin(SIDE_TOP));
@@ -263,6 +283,7 @@ void TabContainer::_repaint() {
}
}
+ _update_margins();
update_minimum_size();
}
@@ -609,6 +630,23 @@ TabBar::AlignmentMode TabContainer::get_tab_alignment() const {
return tab_bar->get_tab_alignment();
}
+void TabContainer::set_tabs_position(TabPosition p_tabs_position) {
+ ERR_FAIL_INDEX(p_tabs_position, POSITION_MAX);
+ if (p_tabs_position == tabs_position) {
+ return;
+ }
+ tabs_position = p_tabs_position;
+
+ tab_bar->set_tab_style_v_flip(tabs_position == POSITION_BOTTOM);
+
+ callable_mp(this, &TabContainer::_repaint).call_deferred();
+ queue_redraw();
+}
+
+TabContainer::TabPosition TabContainer::get_tabs_position() const {
+ return tabs_position;
+}
+
void TabContainer::set_tab_focus_mode(Control::FocusMode p_focus_mode) {
tab_bar->set_focus_mode(p_focus_mode);
}
@@ -633,18 +671,8 @@ void TabContainer::set_tabs_visible(bool p_visible) {
tabs_visible = p_visible;
tab_bar->set_visible(tabs_visible);
- Vector<Control *> controls = _get_tab_controls();
- for (int i = 0; i < controls.size(); i++) {
- Control *c = controls[i];
- if (tabs_visible) {
- c->set_offset(SIDE_TOP, _get_top_margin());
- } else {
- c->set_offset(SIDE_TOP, 0);
- }
- }
-
+ callable_mp(this, &TabContainer::_repaint).call_deferred();
queue_redraw();
- update_minimum_size();
}
bool TabContainer::are_tabs_visible() const {
@@ -890,6 +918,8 @@ void TabContainer::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_tab_control", "tab_idx"), &TabContainer::get_tab_control);
ClassDB::bind_method(D_METHOD("set_tab_alignment", "alignment"), &TabContainer::set_tab_alignment);
ClassDB::bind_method(D_METHOD("get_tab_alignment"), &TabContainer::get_tab_alignment);
+ ClassDB::bind_method(D_METHOD("set_tabs_position", "tabs_position"), &TabContainer::set_tabs_position);
+ ClassDB::bind_method(D_METHOD("get_tabs_position"), &TabContainer::get_tabs_position);
ClassDB::bind_method(D_METHOD("set_clip_tabs", "clip_tabs"), &TabContainer::set_clip_tabs);
ClassDB::bind_method(D_METHOD("get_clip_tabs"), &TabContainer::get_clip_tabs);
ClassDB::bind_method(D_METHOD("set_tabs_visible", "visible"), &TabContainer::set_tabs_visible);
@@ -931,6 +961,7 @@ void TabContainer::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "tab_alignment", PROPERTY_HINT_ENUM, "Left,Center,Right"), "set_tab_alignment", "get_tab_alignment");
ADD_PROPERTY(PropertyInfo(Variant::INT, "current_tab", PROPERTY_HINT_RANGE, "-1,4096,1"), "set_current_tab", "get_current_tab");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "tabs_position", PROPERTY_HINT_ENUM, "Top,Bottom"), "set_tabs_position", "get_tabs_position");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_tabs"), "set_clip_tabs", "get_clip_tabs");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "tabs_visible"), "set_tabs_visible", "are_tabs_visible");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "all_tabs_in_front"), "set_all_tabs_in_front", "is_all_tabs_in_front");
@@ -939,6 +970,10 @@ void TabContainer::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_hidden_tabs_for_min_size"), "set_use_hidden_tabs_for_min_size", "get_use_hidden_tabs_for_min_size");
ADD_PROPERTY(PropertyInfo(Variant::INT, "tab_focus_mode", PROPERTY_HINT_ENUM, "None,Click,All"), "set_tab_focus_mode", "get_tab_focus_mode");
+ BIND_ENUM_CONSTANT(POSITION_TOP);
+ BIND_ENUM_CONSTANT(POSITION_BOTTOM);
+ BIND_ENUM_CONSTANT(POSITION_MAX);
+
BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, TabContainer, side_margin);
BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, TabContainer, panel_style, "panel");
diff --git a/scene/gui/tab_container.h b/scene/gui/tab_container.h
index 450143cd0c..0c645b4598 100644
--- a/scene/gui/tab_container.h
+++ b/scene/gui/tab_container.h
@@ -38,9 +38,18 @@
class TabContainer : public Container {
GDCLASS(TabContainer, Container);
+public:
+ enum TabPosition {
+ POSITION_TOP,
+ POSITION_BOTTOM,
+ POSITION_MAX,
+ };
+
+private:
TabBar *tab_bar = nullptr;
bool tabs_visible = true;
bool all_tabs_in_front = false;
+ TabPosition tabs_position = POSITION_TOP;
bool menu_hovered = false;
mutable ObjectID popup_obj_id;
bool use_hidden_tabs_for_min_size = false;
@@ -86,7 +95,7 @@ class TabContainer : public Container {
int tab_font_size;
} theme_cache;
- int _get_top_margin() const;
+ int _get_tab_height() const;
Vector<Control *> _get_tab_controls() const;
void _on_theme_changed();
void _repaint();
@@ -124,6 +133,9 @@ public:
void set_tab_alignment(TabBar::AlignmentMode p_alignment);
TabBar::AlignmentMode get_tab_alignment() const;
+ void set_tabs_position(TabPosition p_tab_position);
+ TabPosition get_tabs_position() const;
+
void set_tab_focus_mode(FocusMode p_focus_mode);
FocusMode get_tab_focus_mode() const;
@@ -185,4 +197,6 @@ public:
TabContainer();
};
+VARIANT_ENUM_CAST(TabContainer::TabPosition);
+
#endif // TAB_CONTAINER_H
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index fe35669311..540c999131 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -33,7 +33,6 @@
#include "core/config/project_settings.h"
#include "core/input/input.h"
#include "core/input/input_map.h"
-#include "core/object/message_queue.h"
#include "core/object/script_language.h"
#include "core/os/keyboard.h"
#include "core/os/os.h"
@@ -428,10 +427,10 @@ void TextEdit::_notification(int p_what) {
case NOTIFICATION_ENTER_TREE: {
_update_caches();
if (caret_pos_dirty) {
- MessageQueue::get_singleton()->push_call(this, "_emit_caret_changed");
+ callable_mp(this, &TextEdit::_emit_caret_changed).call_deferred();
}
if (text_changed_dirty) {
- MessageQueue::get_singleton()->push_call(this, "_text_changed_emit");
+ callable_mp(this, &TextEdit::_text_changed_emit).call_deferred();
}
_update_wrap_at_column(true);
} break;
@@ -443,8 +442,8 @@ void TextEdit::_notification(int p_what) {
case NOTIFICATION_VISIBILITY_CHANGED: {
if (is_visible()) {
- call_deferred(SNAME("_update_scrollbars"));
- call_deferred(SNAME("_update_wrap_at_column"));
+ callable_mp(this, &TextEdit::_update_scrollbars).call_deferred();
+ callable_mp(this, &TextEdit::_update_wrap_at_column).call_deferred(false);
}
} break;
@@ -4008,7 +4007,7 @@ void TextEdit::undo() {
if (dirty_carets && !caret_pos_dirty) {
if (is_inside_tree()) {
- MessageQueue::get_singleton()->push_call(this, "_emit_caret_changed");
+ callable_mp(this, &TextEdit::_emit_caret_changed).call_deferred();
}
caret_pos_dirty = true;
}
@@ -4063,7 +4062,7 @@ void TextEdit::redo() {
if (dirty_carets && !caret_pos_dirty) {
if (is_inside_tree()) {
- MessageQueue::get_singleton()->push_call(this, "_emit_caret_changed");
+ callable_mp(this, &TextEdit::_emit_caret_changed).call_deferred();
}
caret_pos_dirty = true;
}
@@ -4869,7 +4868,7 @@ void TextEdit::set_caret_line(int p_line, bool p_adjust_viewport, bool p_can_be_
if (caret_moved && !caret_pos_dirty) {
if (is_inside_tree()) {
- MessageQueue::get_singleton()->push_call(this, "_emit_caret_changed");
+ callable_mp(this, &TextEdit::_emit_caret_changed).call_deferred();
}
caret_pos_dirty = true;
}
@@ -4900,7 +4899,7 @@ void TextEdit::set_caret_column(int p_col, bool p_adjust_viewport, int p_caret)
if (caret_moved && !caret_pos_dirty) {
if (is_inside_tree()) {
- MessageQueue::get_singleton()->push_call(this, "_emit_caret_changed");
+ callable_mp(this, &TextEdit::_emit_caret_changed).call_deferred();
}
caret_pos_dirty = true;
}
@@ -6027,10 +6026,6 @@ Color TextEdit::get_font_color() const {
}
void TextEdit::_bind_methods() {
- /* Internal. */
-
- ClassDB::bind_method(D_METHOD("_text_changed_emit"), &TextEdit::_text_changed_emit);
-
/* Text */
// Text properties
ClassDB::bind_method(D_METHOD("has_ime_text"), &TextEdit::has_ime_text);
@@ -6201,9 +6196,6 @@ void TextEdit::_bind_methods() {
BIND_ENUM_CONSTANT(CARET_TYPE_LINE);
BIND_ENUM_CONSTANT(CARET_TYPE_BLOCK);
- // Internal.
- ClassDB::bind_method(D_METHOD("_emit_caret_changed"), &TextEdit::_emit_caret_changed);
-
ClassDB::bind_method(D_METHOD("set_caret_type", "type"), &TextEdit::set_caret_type);
ClassDB::bind_method(D_METHOD("get_caret_type"), &TextEdit::get_caret_type);
@@ -6291,9 +6283,6 @@ void TextEdit::_bind_methods() {
BIND_ENUM_CONSTANT(LINE_WRAPPING_NONE);
BIND_ENUM_CONSTANT(LINE_WRAPPING_BOUNDARY);
- // Internal.
- ClassDB::bind_method(D_METHOD("_update_wrap_at_column", "force"), &TextEdit::_update_wrap_at_column, DEFVAL(false));
-
ClassDB::bind_method(D_METHOD("set_line_wrapping_mode", "mode"), &TextEdit::set_line_wrapping_mode);
ClassDB::bind_method(D_METHOD("get_line_wrapping_mode"), &TextEdit::get_line_wrapping_mode);
@@ -7827,7 +7816,7 @@ void TextEdit::_base_insert_text(int p_line, int p_char, const String &p_text, i
if (!text_changed_dirty && !setting_text) {
if (is_inside_tree()) {
- MessageQueue::get_singleton()->push_call(this, "_text_changed_emit");
+ callable_mp(this, &TextEdit::_text_changed_emit).call_deferred();
}
text_changed_dirty = true;
}
@@ -7873,7 +7862,7 @@ void TextEdit::_base_remove_text(int p_from_line, int p_from_column, int p_to_li
if (!text_changed_dirty && !setting_text) {
if (is_inside_tree()) {
- MessageQueue::get_singleton()->push_call(this, "_text_changed_emit");
+ callable_mp(this, &TextEdit::_text_changed_emit).call_deferred();
}
text_changed_dirty = true;
}
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index 6936bcb441..c67c3cd98d 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -4784,7 +4784,7 @@ void Tree::ensure_cursor_is_visible() {
if (cell_h > screen_h) { // Screen size is too small, maybe it was not resized yet.
v_scroll->set_value(y_offset);
} else if (y_offset + cell_h > v_scroll->get_value() + screen_h) {
- v_scroll->call_deferred(SNAME("set_value"), y_offset - screen_h + cell_h);
+ callable_mp((Range *)v_scroll, &Range::set_value).call_deferred(y_offset - screen_h + cell_h);
} else if (y_offset < v_scroll->get_value()) {
v_scroll->set_value(y_offset);
}
@@ -4802,7 +4802,7 @@ void Tree::ensure_cursor_is_visible() {
if (cell_w > screen_w) {
h_scroll->set_value(x_offset);
} else if (x_offset + cell_w > h_scroll->get_value() + screen_w) {
- h_scroll->call_deferred(SNAME("set_value"), x_offset - screen_w + cell_w);
+ callable_mp((Range *)h_scroll, &Range::set_value).call_deferred(x_offset - screen_w + cell_w);
} else if (x_offset < h_scroll->get_value()) {
h_scroll->set_value(x_offset);
}
diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp
index 4ee81e5cb0..a35ee17868 100644
--- a/scene/main/canvas_item.cpp
+++ b/scene/main/canvas_item.cpp
@@ -30,7 +30,6 @@
#include "canvas_item.h"
-#include "core/object/message_queue.h"
#include "scene/2d/canvas_group.h"
#include "scene/main/canvas_layer.h"
#include "scene/main/window.h"
@@ -407,7 +406,7 @@ void CanvasItem::queue_redraw() {
pending_update = true;
- MessageQueue::get_singleton()->push_callable(callable_mp(this, &CanvasItem::_redraw_callback));
+ callable_mp(this, &CanvasItem::_redraw_callback).call_deferred();
}
void CanvasItem::move_to_front() {
@@ -904,7 +903,7 @@ void CanvasItem::_notify_transform(CanvasItem *p_node) {
get_tree()->xform_change_list.add(&p_node->xform_change);
} else {
// Should be rare, but still needs to be handled.
- MessageQueue::get_singleton()->push_callable(callable_mp(p_node, &CanvasItem::_notify_transform_deferred));
+ callable_mp(p_node, &CanvasItem::_notify_transform_deferred).call_deferred();
}
}
}
diff --git a/scene/main/http_request.cpp b/scene/main/http_request.cpp
index ddc694f894..1972e62659 100644
--- a/scene/main/http_request.cpp
+++ b/scene/main/http_request.cpp
@@ -472,7 +472,7 @@ bool HTTPRequest::_update_connection() {
}
void HTTPRequest::_defer_done(int p_status, int p_code, const PackedStringArray &p_headers, const PackedByteArray &p_data) {
- call_deferred(SNAME("_request_done"), p_status, p_code, p_headers, p_data);
+ callable_mp(this, &HTTPRequest::_request_done).call_deferred(p_status, p_code, p_headers, p_data);
}
void HTTPRequest::_request_done(int p_status, int p_code, const PackedStringArray &p_headers, const PackedByteArray &p_data) {
@@ -621,8 +621,6 @@ void HTTPRequest::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_downloaded_bytes"), &HTTPRequest::get_downloaded_bytes);
ClassDB::bind_method(D_METHOD("get_body_size"), &HTTPRequest::get_body_size);
- ClassDB::bind_method(D_METHOD("_request_done"), &HTTPRequest::_request_done);
-
ClassDB::bind_method(D_METHOD("set_timeout", "timeout"), &HTTPRequest::set_timeout);
ClassDB::bind_method(D_METHOD("get_timeout"), &HTTPRequest::get_timeout);
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index dac0b64853..a6b7ca8188 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -1736,8 +1736,40 @@ void Node::reparent(Node *p_parent, bool p_keep_global_transform) {
return;
}
+ bool preserve_owner = data.owner && (data.owner == p_parent || data.owner->is_ancestor_of(p_parent));
+ Node *owner_temp = data.owner;
+ LocalVector<Node *> common_parents;
+
+ // If the new parent is related to the owner, find all children of the reparented node who have the same owner so that we can reassign them.
+ if (preserve_owner) {
+ LocalVector<Node *> to_visit;
+
+ to_visit.push_back(this);
+ common_parents.push_back(this);
+
+ while (to_visit.size() > 0) {
+ Node *check = to_visit[to_visit.size() - 1];
+ to_visit.resize(to_visit.size() - 1);
+
+ for (int i = 0; i < check->get_child_count(); i++) {
+ Node *child = check->get_child(i, false);
+ to_visit.push_back(child);
+ if (child->data.owner == owner_temp) {
+ common_parents.push_back(child);
+ }
+ }
+ }
+ }
+
data.parent->remove_child(this);
p_parent->add_child(this);
+
+ // Reassign the old owner to those found nodes.
+ if (preserve_owner) {
+ for (Node *E : common_parents) {
+ E->set_owner(owner_temp);
+ }
+ }
}
Node *Node::get_parent() const {
@@ -1925,7 +1957,7 @@ void Node::set_owner(Node *p_owner) {
return;
}
- Node *check = this->get_parent();
+ Node *check = get_parent();
bool owner_valid = false;
while (check) {
@@ -3065,7 +3097,7 @@ static void _add_nodes_to_options(const Node *p_base, const Node *p_node, List<S
void Node::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const {
String pf = p_function;
- if (p_idx == 0 && (pf == "has_node" || pf == "get_node")) {
+ if (p_idx == 0 && (pf == "has_node" || pf == "get_node" || pf == "get_node_or_null")) {
_add_nodes_to_options(this, this, r_options);
} else if (p_idx == 0 && (pf == "add_to_group" || pf == "remove_from_group" || pf == "is_in_group")) {
HashMap<StringName, String> global_groups = ProjectSettings::get_singleton()->get_global_groups_list();
diff --git a/scene/main/node.h b/scene/main/node.h
index cd1c31d784..8130c61a34 100644
--- a/scene/main/node.h
+++ b/scene/main/node.h
@@ -558,7 +558,9 @@ public:
_FORCE_INLINE_ bool is_readable_from_caller_thread() const {
if (current_process_thread_group == nullptr) {
// No thread processing.
- return is_current_thread_safe_for_nodes();
+ // Only accessible if node is outside the scene tree
+ // or access will happen from a node-safe thread.
+ return !data.inside_tree || is_current_thread_safe_for_nodes();
} else {
// Thread processing.
return true;
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index 745b4e652c..fe02d97586 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -32,7 +32,6 @@
#include "core/config/project_settings.h"
#include "core/debugger/engine_debugger.h"
-#include "core/object/message_queue.h"
#include "core/string/translation.h"
#include "core/templates/pair.h"
#include "core/templates/sort_array.h"
@@ -1054,7 +1053,7 @@ void Viewport::canvas_parent_mark_dirty(Node *p_node) {
bool request_update = gui.canvas_parents_with_dirty_order.is_empty();
gui.canvas_parents_with_dirty_order.insert(p_node->get_instance_id());
if (request_update) {
- MessageQueue::get_singleton()->push_callable(callable_mp(this, &Viewport::_process_dirty_canvas_parent_orders));
+ callable_mp(this, &Viewport::_process_dirty_canvas_parent_orders).call_deferred();
}
}
@@ -2700,7 +2699,7 @@ void Viewport::_cleanup_mouseover_colliders(bool p_clean_all_frames, bool p_paus
void Viewport::_gui_grab_click_focus(Control *p_control) {
gui.mouse_click_grabber = p_control;
- call_deferred(SNAME("_post_gui_grab_click_focus"));
+ callable_mp(this, &Viewport::_post_gui_grab_click_focus).call_deferred();
}
void Viewport::_post_gui_grab_click_focus() {
@@ -2748,7 +2747,7 @@ void Viewport::_post_gui_grab_click_focus() {
mb->set_button_index(MouseButton(i + 1));
mb->set_pressed(true);
mb->set_device(InputEvent::DEVICE_ID_INTERNAL);
- MessageQueue::get_singleton()->push_callable(callable_mp(gui.mouse_focus, &Control::_call_gui_input), mb);
+ callable_mp(gui.mouse_focus, &Control::_call_gui_input).call_deferred(mb);
}
}
}
@@ -4627,7 +4626,6 @@ void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_input_disabled"), &Viewport::is_input_disabled);
ClassDB::bind_method(D_METHOD("_gui_remove_focus_for_window"), &Viewport::_gui_remove_focus_for_window);
- ClassDB::bind_method(D_METHOD("_post_gui_grab_click_focus"), &Viewport::_post_gui_grab_click_focus);
ClassDB::bind_method(D_METHOD("set_positional_shadow_atlas_size", "size"), &Viewport::set_positional_shadow_atlas_size);
ClassDB::bind_method(D_METHOD("get_positional_shadow_atlas_size"), &Viewport::get_positional_shadow_atlas_size);
diff --git a/scene/main/window.cpp b/scene/main/window.cpp
index a6cb5f4526..70b70b8928 100644
--- a/scene/main/window.cpp
+++ b/scene/main/window.cpp
@@ -520,15 +520,12 @@ void Window::request_attention() {
}
}
+#ifndef DISABLE_DEPRECATED
void Window::move_to_foreground() {
- ERR_MAIN_THREAD_GUARD;
- if (embedder) {
- embedder->_sub_window_grab_focus(this);
-
- } else if (window_id != DisplayServer::INVALID_WINDOW_ID) {
- DisplayServer::get_singleton()->window_move_to_foreground(window_id);
- }
+ WARN_DEPRECATED_MSG(R"*(The "move_to_foreground()" method is deprecated, use "grab_focus()" instead.)*");
+ grab_focus();
}
+#endif // DISABLE_DEPRECATED
bool Window::can_draw() const {
ERR_READ_THREAD_GUARD_V(false);
@@ -573,6 +570,10 @@ bool Window::is_in_edited_scene_root() const {
void Window::_make_window() {
ERR_FAIL_COND(window_id != DisplayServer::INVALID_WINDOW_ID);
+ if (transient && transient_to_focused) {
+ _make_transient();
+ }
+
uint32_t f = 0;
for (int i = 0; i < FLAG_MAX; i++) {
if (flags[i]) {
@@ -665,6 +666,10 @@ void Window::_clear_window() {
_update_viewport_size();
RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_DISABLED);
+
+ if (transient && transient_to_focused) {
+ _clear_transient();
+ }
}
void Window::_rect_changed_callback(const Rect2i &p_callback) {
@@ -864,18 +869,29 @@ void Window::_make_transient() {
return;
}
//find transient parent
- Viewport *vp = get_parent()->get_viewport();
+
Window *window = nullptr;
- while (vp) {
- window = Object::cast_to<Window>(vp);
- if (window) {
- break;
- }
- if (!vp->get_parent()) {
- break;
+
+ if (!is_embedded() && transient_to_focused) {
+ DisplayServer::WindowID focused_window_id = DisplayServer::get_singleton()->get_focused_window();
+ if (focused_window_id != DisplayServer::INVALID_WINDOW_ID) {
+ window = Object::cast_to<Window>(ObjectDB::get_instance(DisplayServer::get_singleton()->window_get_attached_instance_id(focused_window_id)));
}
+ }
- vp = vp->get_parent()->get_viewport();
+ if (!window) {
+ Viewport *vp = get_parent()->get_viewport();
+ while (vp) {
+ window = Object::cast_to<Window>(vp);
+ if (window) {
+ break;
+ }
+ if (!vp->get_parent()) {
+ break;
+ }
+
+ vp = vp->get_parent()->get_viewport();
+ }
}
if (window) {
@@ -919,17 +935,32 @@ void Window::set_transient(bool p_transient) {
}
if (transient) {
- _make_transient();
+ if (!transient_to_focused) {
+ _make_transient();
+ }
} else {
_clear_transient();
}
}
bool Window::is_transient() const {
- ERR_READ_THREAD_GUARD_V(false);
return transient;
}
+void Window::set_transient_to_focused(bool p_transient_to_focused) {
+ ERR_MAIN_THREAD_GUARD;
+ if (transient_to_focused == p_transient_to_focused) {
+ return;
+ }
+
+ transient_to_focused = p_transient_to_focused;
+}
+
+bool Window::is_transient_to_focused() const {
+ ERR_READ_THREAD_GUARD_V(false);
+ return transient_to_focused;
+}
+
void Window::set_exclusive(bool p_exclusive) {
ERR_MAIN_THREAD_GUARD;
if (exclusive == p_exclusive) {
@@ -1262,7 +1293,7 @@ void Window::_notification(int p_what) {
}
}
- if (transient) {
+ if (transient && !transient_to_focused) {
_make_transient();
}
if (visible) {
@@ -1516,7 +1547,7 @@ void Window::child_controls_changed() {
}
updating_child_controls = true;
- call_deferred(SNAME("_update_child_controls"));
+ callable_mp(this, &Window::_update_child_controls).call_deferred();
}
void Window::_update_child_controls() {
@@ -1997,7 +2028,7 @@ void Window::_update_theme_item_cache() {
// Updating without a delay can cause a lot of lag.
if (!wrap_controls) {
updating_embedded_window = true;
- call_deferred(SNAME("_update_embedded_window"));
+ callable_mp(this, &Window::_update_embedded_window).call_deferred();
} else {
child_controls_changed();
}
@@ -2745,7 +2776,9 @@ void Window::_bind_methods() {
ClassDB::bind_method(D_METHOD("request_attention"), &Window::request_attention);
+#ifndef DISABLE_DEPRECATED
ClassDB::bind_method(D_METHOD("move_to_foreground"), &Window::move_to_foreground);
+#endif // DISABLE_DEPRECATED
ClassDB::bind_method(D_METHOD("set_visible", "visible"), &Window::set_visible);
ClassDB::bind_method(D_METHOD("is_visible"), &Window::is_visible);
@@ -2756,6 +2789,9 @@ void Window::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_transient", "transient"), &Window::set_transient);
ClassDB::bind_method(D_METHOD("is_transient"), &Window::is_transient);
+ ClassDB::bind_method(D_METHOD("set_transient_to_focused", "enable"), &Window::set_transient_to_focused);
+ ClassDB::bind_method(D_METHOD("is_transient_to_focused"), &Window::is_transient_to_focused);
+
ClassDB::bind_method(D_METHOD("set_exclusive", "exclusive"), &Window::set_exclusive);
ClassDB::bind_method(D_METHOD("is_exclusive"), &Window::is_exclusive);
@@ -2800,9 +2836,6 @@ void Window::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_wrapping_controls"), &Window::is_wrapping_controls);
ClassDB::bind_method(D_METHOD("child_controls_changed"), &Window::child_controls_changed);
- ClassDB::bind_method(D_METHOD("_update_child_controls"), &Window::_update_child_controls);
- ClassDB::bind_method(D_METHOD("_update_embedded_window"), &Window::_update_embedded_window);
-
ClassDB::bind_method(D_METHOD("set_theme", "theme"), &Window::set_theme);
ClassDB::bind_method(D_METHOD("get_theme"), &Window::get_theme);
@@ -2887,6 +2920,7 @@ void Window::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "visible"), "set_visible", "is_visible");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "wrap_controls"), "set_wrap_controls", "is_wrapping_controls");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "transient"), "set_transient", "is_transient");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "transient_to_focused"), "set_transient_to_focused", "is_transient_to_focused");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "exclusive"), "set_exclusive", "is_exclusive");
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "unresizable"), "set_flag", "get_flag", FLAG_RESIZE_DISABLED);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "borderless"), "set_flag", "get_flag", FLAG_BORDERLESS);
diff --git a/scene/main/window.h b/scene/main/window.h
index 5f5b99ff51..4ae535848a 100644
--- a/scene/main/window.h
+++ b/scene/main/window.h
@@ -127,6 +127,7 @@ private:
bool use_font_oversampling = false;
bool transient = false;
+ bool transient_to_focused = false;
bool exclusive = false;
bool wrap_controls = false;
bool updating_child_controls = false;
@@ -301,7 +302,9 @@ public:
bool is_maximize_allowed() const;
void request_attention();
+#ifndef DISABLE_DEPRECATED
void move_to_foreground();
+#endif // DISABLE_DEPRECATED
virtual void set_visible(bool p_visible);
bool is_visible() const;
@@ -314,6 +317,9 @@ public:
void set_transient(bool p_transient);
bool is_transient() const;
+ void set_transient_to_focused(bool p_transient_to_focused);
+ bool is_transient_to_focused() const;
+
void set_exclusive(bool p_exclusive);
bool is_exclusive() const;
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index baaa78f9f2..111d6447a0 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -78,7 +78,6 @@
#include "scene/animation/animation_node_state_machine.h"
#include "scene/animation/animation_player.h"
#include "scene/animation/animation_tree.h"
-#include "scene/animation/root_motion_view.h"
#include "scene/animation/tween.h"
#include "scene/audio/audio_stream_player.h"
#include "scene/debugger/scene_debugger.h"
@@ -273,6 +272,7 @@
#include "scene/3d/voxel_gi.h"
#include "scene/3d/world_environment.h"
#include "scene/3d/xr_nodes.h"
+#include "scene/animation/root_motion_view.h"
#include "scene/resources/environment.h"
#include "scene/resources/fog_material.h"
#include "scene/resources/importer_mesh.h"
diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp
index 1ab11cfdf0..e503c79bed 100644
--- a/scene/resources/animation.cpp
+++ b/scene/resources/animation.cpp
@@ -979,6 +979,7 @@ Animation::TrackType Animation::track_get_type(int p_track) const {
void Animation::track_set_path(int p_track, const NodePath &p_path) {
ERR_FAIL_INDEX(p_track, tracks.size());
tracks[p_track]->path = p_path;
+ _track_update_hash(p_track);
emit_changed();
}
@@ -996,6 +997,27 @@ int Animation::find_track(const NodePath &p_path, const TrackType p_type) const
return -1;
};
+Animation::TrackType Animation::get_cache_type(TrackType p_type) {
+ if (p_type == Animation::TYPE_BEZIER) {
+ return Animation::TYPE_VALUE;
+ }
+ if (p_type == Animation::TYPE_ROTATION_3D || p_type == Animation::TYPE_SCALE_3D) {
+ return Animation::TYPE_POSITION_3D; // Reference them as position3D tracks, even if they modify rotation or scale.
+ }
+ return p_type;
+}
+
+void Animation::_track_update_hash(int p_track) {
+ NodePath track_path = tracks[p_track]->path;
+ TrackType track_cache_type = get_cache_type(tracks[p_track]->type);
+ tracks[p_track]->thash = StringName(String(track_path.get_concatenated_names()) + String(track_path.get_concatenated_subnames()) + itos(track_cache_type)).hash();
+}
+
+Animation::TypeHash Animation::track_get_type_hash(int p_track) const {
+ ERR_FAIL_INDEX_V(p_track, tracks.size(), 0);
+ return tracks[p_track]->thash;
+}
+
void Animation::track_set_interpolation_type(int p_track, InterpolationType p_interp) {
ERR_FAIL_INDEX(p_track, tracks.size());
tracks[p_track]->interpolation = p_interp;
diff --git a/scene/resources/animation.h b/scene/resources/animation.h
index 54a78fffa4..6c31bbcd29 100644
--- a/scene/resources/animation.h
+++ b/scene/resources/animation.h
@@ -41,6 +41,8 @@ class Animation : public Resource {
RES_BASE_EXTENSION("anim");
public:
+ typedef uint32_t TypeHash;
+
enum TrackType {
TYPE_VALUE, ///< Set a value in a property, can be interpolated.
TYPE_POSITION_3D, ///< Position 3D track
@@ -104,7 +106,8 @@ private:
TrackType type = TrackType::TYPE_ANIMATION;
InterpolationType interpolation = INTERPOLATION_LINEAR;
bool loop_wrap = true;
- NodePath path; // path to something
+ NodePath path; // Path to something.
+ TypeHash thash = 0; // Hash by Path + SubPath + TrackType.
bool imported = false;
bool enabled = true;
Track() {}
@@ -268,6 +271,8 @@ private:
real_t step = 0.1;
LoopMode loop_mode = LOOP_NONE;
+ void _track_update_hash(int p_track);
+
/* Animation compression page format (version 1):
*
* Animation uses bitwidth based compression separated into small pages. The intention is that pages fit easily in the cache, so decoding is cache efficient.
@@ -386,6 +391,8 @@ public:
NodePath track_get_path(int p_track) const;
int find_track(const NodePath &p_path, const TrackType p_type) const;
+ TypeHash track_get_type_hash(int p_track) const;
+
void track_move_up(int p_track);
void track_move_down(int p_track);
void track_move_to(int p_track, int p_to_index);
@@ -504,6 +511,8 @@ public:
static Variant interpolate_variant(const Variant &a, const Variant &b, float c, bool p_snap_array_element = false);
static Variant cubic_interpolate_in_time_variant(const Variant &pre_a, const Variant &a, const Variant &b, const Variant &post_b, float c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t, bool p_snap_array_element = false);
+ static TrackType get_cache_type(TrackType p_type);
+
Animation();
~Animation();
};
diff --git a/scene/resources/bone_map.cpp b/scene/resources/bone_map.cpp
index 5363b8ec79..97e3af726a 100644
--- a/scene/resources/bone_map.cpp
+++ b/scene/resources/bone_map.cpp
@@ -77,22 +77,22 @@ void BoneMap::set_profile(const Ref<SkeletonProfile> &p_profile) {
notify_property_list_changed();
}
-StringName BoneMap::get_skeleton_bone_name(StringName p_profile_bone_name) const {
+StringName BoneMap::get_skeleton_bone_name(const StringName &p_profile_bone_name) const {
ERR_FAIL_COND_V(!bone_map.has(p_profile_bone_name), StringName());
return bone_map.get(p_profile_bone_name);
}
-void BoneMap::_set_skeleton_bone_name(StringName p_profile_bone_name, const StringName p_skeleton_bone_name) {
+void BoneMap::_set_skeleton_bone_name(const StringName &p_profile_bone_name, const StringName &p_skeleton_bone_name) {
ERR_FAIL_COND(!bone_map.has(p_profile_bone_name));
bone_map.insert(p_profile_bone_name, p_skeleton_bone_name);
}
-void BoneMap::set_skeleton_bone_name(StringName p_profile_bone_name, const StringName p_skeleton_bone_name) {
+void BoneMap::set_skeleton_bone_name(const StringName &p_profile_bone_name, const StringName &p_skeleton_bone_name) {
_set_skeleton_bone_name(p_profile_bone_name, p_skeleton_bone_name);
emit_signal("bone_map_updated");
}
-StringName BoneMap::find_profile_bone_name(StringName p_skeleton_bone_name) const {
+StringName BoneMap::find_profile_bone_name(const StringName &p_skeleton_bone_name) const {
StringName profile_bone_name;
HashMap<StringName, StringName>::ConstIterator E = bone_map.begin();
while (E) {
@@ -105,7 +105,7 @@ StringName BoneMap::find_profile_bone_name(StringName p_skeleton_bone_name) cons
return profile_bone_name;
}
-int BoneMap::get_skeleton_bone_name_count(const StringName p_skeleton_bone_name) const {
+int BoneMap::get_skeleton_bone_name_count(const StringName &p_skeleton_bone_name) const {
int count = 0;
HashMap<StringName, StringName>::ConstIterator E = bone_map.begin();
while (E) {
diff --git a/scene/resources/bone_map.h b/scene/resources/bone_map.h
index 983a3b7b5a..fbd2f92dee 100644
--- a/scene/resources/bone_map.h
+++ b/scene/resources/bone_map.h
@@ -53,13 +53,13 @@ public:
Ref<SkeletonProfile> get_profile() const;
void set_profile(const Ref<SkeletonProfile> &p_profile);
- int get_skeleton_bone_name_count(const StringName p_skeleton_bone_name) const;
+ int get_skeleton_bone_name_count(const StringName &p_skeleton_bone_name) const;
- StringName get_skeleton_bone_name(StringName p_profile_bone_name) const;
- void set_skeleton_bone_name(StringName p_profile_bone_name, const StringName p_skeleton_bone_name);
- void _set_skeleton_bone_name(StringName p_profile_bone_name, const StringName p_skeleton_bone_name); // Avoid to emit signal for editor.
+ StringName get_skeleton_bone_name(const StringName &p_profile_bone_name) const;
+ void set_skeleton_bone_name(const StringName &p_profile_bone_name, const StringName &p_skeleton_bone_name);
+ void _set_skeleton_bone_name(const StringName &p_profile_bone_name, const StringName &p_skeleton_bone_name); // Avoid to emit signal for editor.
- StringName find_profile_bone_name(StringName p_skeleton_bone_name) const;
+ StringName find_profile_bone_name(const StringName &p_skeleton_bone_name) const;
BoneMap();
~BoneMap();
diff --git a/scene/resources/compressed_texture.h b/scene/resources/compressed_texture.h
index 932109617f..5297d79cfe 100644
--- a/scene/resources/compressed_texture.h
+++ b/scene/resources/compressed_texture.h
@@ -40,7 +40,6 @@ class CompressedTexture2D : public Texture2D {
public:
enum DataFormat {
- DATA_FORMAT_UNDEFINED,
DATA_FORMAT_IMAGE,
DATA_FORMAT_PNG,
DATA_FORMAT_WEBP,
diff --git a/scene/resources/curve_texture.cpp b/scene/resources/curve_texture.cpp
index 3578b46308..488a527bbb 100644
--- a/scene/resources/curve_texture.cpp
+++ b/scene/resources/curve_texture.cpp
@@ -41,8 +41,6 @@ void CurveTexture::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_texture_mode", "texture_mode"), &CurveTexture::set_texture_mode);
ClassDB::bind_method(D_METHOD("get_texture_mode"), &CurveTexture::get_texture_mode);
- ClassDB::bind_method(D_METHOD("_update"), &CurveTexture::_update);
-
ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,4096,suffix:px"), "set_width", "get_width");
ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_mode", PROPERTY_HINT_ENUM, "RGB,Red"), "set_texture_mode", "get_texture_mode");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve", "get_curve");
@@ -190,8 +188,6 @@ void CurveXYZTexture::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_curve_z", "curve"), &CurveXYZTexture::set_curve_z);
ClassDB::bind_method(D_METHOD("get_curve_z"), &CurveXYZTexture::get_curve_z);
- ClassDB::bind_method(D_METHOD("_update"), &CurveXYZTexture::_update);
-
ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,4096,suffix:px"), "set_width", "get_width");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve_x", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve_x", "get_curve_x");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve_y", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve_y", "get_curve_y");
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index dba4e4eb34..74b1157e5f 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -1947,7 +1947,7 @@ Ref<Texture2D> BaseMaterial3D::get_texture(TextureParam p_param) const {
return textures[p_param];
}
-Ref<Texture2D> BaseMaterial3D::get_texture_by_name(StringName p_name) const {
+Ref<Texture2D> BaseMaterial3D::get_texture_by_name(const StringName &p_name) const {
for (int i = 0; i < (int)BaseMaterial3D::TEXTURE_MAX; i++) {
TextureParam param = TextureParam(i);
if (p_name == shader_names->texture_names[param]) {
diff --git a/scene/resources/material.h b/scene/resources/material.h
index 1c698cb104..06522e6470 100644
--- a/scene/resources/material.h
+++ b/scene/resources/material.h
@@ -682,7 +682,7 @@ public:
void set_texture(TextureParam p_param, const Ref<Texture2D> &p_texture);
Ref<Texture2D> get_texture(TextureParam p_param) const;
// Used only for shader material conversion
- Ref<Texture2D> get_texture_by_name(StringName p_name) const;
+ Ref<Texture2D> get_texture_by_name(const StringName &p_name) const;
void set_texture_filter(TextureFilter p_filter);
TextureFilter get_texture_filter() const;
diff --git a/scene/resources/navigation_mesh.cpp b/scene/resources/navigation_mesh.cpp
index 82b5c6257c..dd2e7ef268 100644
--- a/scene/resources/navigation_mesh.cpp
+++ b/scene/resources/navigation_mesh.cpp
@@ -127,7 +127,7 @@ NavigationMesh::SourceGeometryMode NavigationMesh::get_source_geometry_mode() co
return source_geometry_mode;
}
-void NavigationMesh::set_source_group_name(StringName p_group_name) {
+void NavigationMesh::set_source_group_name(const StringName &p_group_name) {
source_group_name = p_group_name;
}
diff --git a/scene/resources/navigation_mesh.h b/scene/resources/navigation_mesh.h
index 8b9b810038..cb8880eb94 100644
--- a/scene/resources/navigation_mesh.h
+++ b/scene/resources/navigation_mesh.h
@@ -122,7 +122,7 @@ public:
void set_source_geometry_mode(SourceGeometryMode p_geometry_mode);
SourceGeometryMode get_source_geometry_mode() const;
- void set_source_group_name(StringName p_group_name);
+ void set_source_group_name(const StringName &p_group_name);
StringName get_source_group_name() const;
void set_cell_size(float p_value);
diff --git a/scene/resources/navigation_polygon.cpp b/scene/resources/navigation_polygon.cpp
index 52840eaa65..2770cb0b87 100644
--- a/scene/resources/navigation_polygon.cpp
+++ b/scene/resources/navigation_polygon.cpp
@@ -393,7 +393,7 @@ NavigationPolygon::SourceGeometryMode NavigationPolygon::get_source_geometry_mod
return source_geometry_mode;
}
-void NavigationPolygon::set_source_geometry_group_name(StringName p_group_name) {
+void NavigationPolygon::set_source_geometry_group_name(const StringName &p_group_name) {
source_geometry_group_name = p_group_name;
}
diff --git a/scene/resources/navigation_polygon.h b/scene/resources/navigation_polygon.h
index 4a6a97e2e7..e589ad6dce 100644
--- a/scene/resources/navigation_polygon.h
+++ b/scene/resources/navigation_polygon.h
@@ -127,7 +127,7 @@ public:
void set_source_geometry_mode(SourceGeometryMode p_geometry_mode);
SourceGeometryMode get_source_geometry_mode() const;
- void set_source_geometry_group_name(StringName p_group_name);
+ void set_source_geometry_group_name(const StringName &p_group_name);
StringName get_source_geometry_group_name() const;
void set_agent_radius(real_t p_value);
diff --git a/scene/resources/portable_compressed_texture.cpp b/scene/resources/portable_compressed_texture.cpp
index a67f32f67e..918b5c0b41 100644
--- a/scene/resources/portable_compressed_texture.cpp
+++ b/scene/resources/portable_compressed_texture.cpp
@@ -33,7 +33,6 @@
#include "core/config/project_settings.h"
#include "core/io/marshalls.h"
#include "scene/resources/bit_map.h"
-#include "scene/resources/compressed_texture.h"
void PortableCompressedTexture2D::_set_data(const Vector<uint8_t> &p_data) {
if (p_data.size() == 0) {
@@ -44,7 +43,7 @@ void PortableCompressedTexture2D::_set_data(const Vector<uint8_t> &p_data) {
uint32_t data_size = p_data.size();
ERR_FAIL_COND(data_size < 20);
compression_mode = CompressionMode(decode_uint16(data));
- CompressedTexture2D::DataFormat data_format = CompressedTexture2D::DataFormat(decode_uint16(data + 2));
+ DataFormat data_format = DataFormat(decode_uint16(data + 2));
format = Image::Format(decode_uint32(data + 4));
uint32_t mipmap_count = decode_uint32(data + 8);
size.width = decode_uint32(data + 12);
@@ -60,11 +59,11 @@ void PortableCompressedTexture2D::_set_data(const Vector<uint8_t> &p_data) {
case COMPRESSION_MODE_LOSSLESS:
case COMPRESSION_MODE_LOSSY: {
ImageMemLoadFunc loader_func;
- if (data_format == CompressedTexture2D::DATA_FORMAT_UNDEFINED) {
+ if (data_format == DATA_FORMAT_UNDEFINED) {
loader_func = nullptr;
- } else if (data_format == CompressedTexture2D::DATA_FORMAT_PNG) {
+ } else if (data_format == DATA_FORMAT_PNG) {
loader_func = Image::_png_mem_unpacker_func;
- } else if (data_format == CompressedTexture2D::DATA_FORMAT_WEBP) {
+ } else if (data_format == DATA_FORMAT_WEBP) {
loader_func = Image::_webp_mem_loader_func;
} else {
ERR_FAIL();
@@ -76,7 +75,7 @@ void PortableCompressedTexture2D::_set_data(const Vector<uint8_t> &p_data) {
uint32_t mipsize = decode_uint32(data);
data += 4;
data_size -= 4;
- ERR_FAIL_COND(mipsize < data_size);
+ ERR_FAIL_COND(mipsize > data_size);
Ref<Image> img = loader_func == nullptr
? memnew(Image(data, data_size))
: Ref<Image>(loader_func(data, data_size));
@@ -90,7 +89,7 @@ void PortableCompressedTexture2D::_set_data(const Vector<uint8_t> &p_data) {
data_size -= mipsize;
}
- image = Ref<Image>(memnew(Image(size.width, size.height, mipmap_count > 1, format, image_data)));
+ image = Ref<Image>(memnew(Image(size.width, size.height, mipmaps, format, image_data)));
} break;
case COMPRESSION_MODE_BASIS_UNIVERSAL: {
@@ -101,7 +100,7 @@ void PortableCompressedTexture2D::_set_data(const Vector<uint8_t> &p_data) {
case COMPRESSION_MODE_S3TC:
case COMPRESSION_MODE_ETC2:
case COMPRESSION_MODE_BPTC: {
- image = Ref<Image>(memnew(Image(size.width, size.height, mipmap_count > 1, format, p_data.slice(20))));
+ image = Ref<Image>(memnew(Image(size.width, size.height, mipmaps, format, p_data.slice(20))));
} break;
}
ERR_FAIL_COND(image.is_null());
@@ -139,7 +138,7 @@ void PortableCompressedTexture2D::create_from_image(const Ref<Image> &p_image, C
buffer.resize(20);
encode_uint16(p_compression_mode, buffer.ptrw());
- encode_uint16(CompressedTexture2D::DATA_FORMAT_UNDEFINED, buffer.ptrw() + 2);
+ encode_uint16(DATA_FORMAT_UNDEFINED, buffer.ptrw() + 2);
encode_uint32(p_image->get_format(), buffer.ptrw() + 4);
encode_uint32(p_image->get_mipmap_count() + 1, buffer.ptrw() + 8);
encode_uint32(p_image->get_width(), buffer.ptrw() + 12);
@@ -155,14 +154,14 @@ void PortableCompressedTexture2D::create_from_image(const Ref<Image> &p_image, C
Vector<uint8_t> data;
if (p_compression_mode == COMPRESSION_MODE_LOSSY) {
data = Image::webp_lossy_packer(p_image->get_image_from_mipmap(i), p_lossy_quality);
- encode_uint16(CompressedTexture2D::DATA_FORMAT_WEBP, buffer.ptrw() + 2);
+ encode_uint16(DATA_FORMAT_WEBP, buffer.ptrw() + 2);
} else {
if (use_webp) {
data = Image::webp_lossless_packer(p_image->get_image_from_mipmap(i));
- encode_uint16(CompressedTexture2D::DATA_FORMAT_WEBP, buffer.ptrw() + 2);
+ encode_uint16(DATA_FORMAT_WEBP, buffer.ptrw() + 2);
} else {
data = Image::png_packer(p_image->get_image_from_mipmap(i));
- encode_uint16(CompressedTexture2D::DATA_FORMAT_PNG, buffer.ptrw() + 2);
+ encode_uint16(DATA_FORMAT_PNG, buffer.ptrw() + 2);
}
}
int data_len = data.size();
@@ -172,7 +171,7 @@ void PortableCompressedTexture2D::create_from_image(const Ref<Image> &p_image, C
}
} break;
case COMPRESSION_MODE_BASIS_UNIVERSAL: {
- encode_uint16(CompressedTexture2D::DATA_FORMAT_BASIS_UNIVERSAL, buffer.ptrw() + 2);
+ encode_uint16(DATA_FORMAT_BASIS_UNIVERSAL, buffer.ptrw() + 2);
Image::UsedChannels uc = p_image->detect_used_channels(p_normal_map ? Image::COMPRESS_SOURCE_NORMAL : Image::COMPRESS_SOURCE_GENERIC);
Vector<uint8_t> budata = Image::basis_universal_packer(p_image, uc);
buffer.append_array(budata);
@@ -181,7 +180,7 @@ void PortableCompressedTexture2D::create_from_image(const Ref<Image> &p_image, C
case COMPRESSION_MODE_S3TC:
case COMPRESSION_MODE_ETC2:
case COMPRESSION_MODE_BPTC: {
- encode_uint16(CompressedTexture2D::DATA_FORMAT_IMAGE, buffer.ptrw() + 2);
+ encode_uint16(DATA_FORMAT_IMAGE, buffer.ptrw() + 2);
Ref<Image> copy = p_image->duplicate();
switch (p_compression_mode) {
case COMPRESSION_MODE_S3TC:
diff --git a/scene/resources/portable_compressed_texture.h b/scene/resources/portable_compressed_texture.h
index 86d80e39f7..3103c2daba 100644
--- a/scene/resources/portable_compressed_texture.h
+++ b/scene/resources/portable_compressed_texture.h
@@ -39,6 +39,14 @@ class PortableCompressedTexture2D : public Texture2D {
GDCLASS(PortableCompressedTexture2D, Texture2D);
public:
+ enum DataFormat {
+ DATA_FORMAT_UNDEFINED,
+ DATA_FORMAT_IMAGE,
+ DATA_FORMAT_PNG,
+ DATA_FORMAT_WEBP,
+ DATA_FORMAT_BASIS_UNIVERSAL,
+ };
+
enum CompressionMode {
COMPRESSION_MODE_LOSSLESS,
COMPRESSION_MODE_LOSSY,
diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp
index 8ad9eec25f..eb28c9e601 100644
--- a/scene/resources/primitive_meshes.cpp
+++ b/scene/resources/primitive_meshes.cpp
@@ -232,8 +232,6 @@ RID PrimitiveMesh::get_rid() const {
}
void PrimitiveMesh::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_update"), &PrimitiveMesh::_update);
-
ClassDB::bind_method(D_METHOD("set_material", "material"), &PrimitiveMesh::set_material);
ClassDB::bind_method(D_METHOD("get_material"), &PrimitiveMesh::get_material);
@@ -1478,15 +1476,15 @@ void PrismMesh::_create_mesh_array(Array &p_arr) const {
thisrow = point;
prevrow = 0;
for (j = 0; j <= (subdivide_h + 1); j++) {
- float scale = (y - start_pos.y) / size.y;
+ float scale = j / (subdivide_h + 1.0);
float scaled_size_x = size.x * scale;
float start_x = start_pos.x + (1.0 - scale) * size.x * left_to_right;
float offset_front = (1.0 - scale) * onethird * left_to_right;
float offset_back = (1.0 - scale) * onethird * (1.0 - left_to_right);
float v = j;
- float v2 = j / (subdivide_h + 1.0);
- v /= (2.0 * (subdivide_h + 1.0));
+ float v2 = scale;
+ v /= 2.0 * (subdivide_h + 1.0);
x = 0.0;
for (i = 0; i <= (subdivide_w + 1); i++) {
@@ -1568,16 +1566,16 @@ void PrismMesh::_create_mesh_array(Array &p_arr) const {
thisrow = point;
prevrow = 0;
for (j = 0; j <= (subdivide_h + 1); j++) {
- float v = j;
- float v2 = j / (subdivide_h + 1.0);
- v /= (2.0 * (subdivide_h + 1.0));
-
float left, right;
- float scale = (y - start_pos.y) / size.y;
+ float scale = j / (subdivide_h + 1.0);
left = start_pos.x + (size.x * (1.0 - scale) * left_to_right);
right = left + (size.x * scale);
+ float v = j;
+ float v2 = scale;
+ v /= 2.0 * (subdivide_h + 1.0);
+
z = start_pos.z;
for (i = 0; i <= (subdivide_d + 1); i++) {
float u = i;
@@ -3342,7 +3340,6 @@ void TextMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_uppercase", "enable"), &TextMesh::set_uppercase);
ClassDB::bind_method(D_METHOD("is_uppercase"), &TextMesh::is_uppercase);
- ClassDB::bind_method(D_METHOD("_font_changed"), &TextMesh::_font_changed);
ClassDB::bind_method(D_METHOD("_request_update"), &TextMesh::_request_update);
ADD_GROUP("Text", "");
@@ -3446,14 +3443,16 @@ void TextMesh::_font_changed() {
void TextMesh::set_font(const Ref<Font> &p_font) {
if (font_override != p_font) {
+ const Callable font_changed = callable_mp(this, &TextMesh::_font_changed);
+
if (font_override.is_valid()) {
- font_override->disconnect_changed(Callable(this, "_font_changed"));
+ font_override->disconnect_changed(font_changed);
}
font_override = p_font;
dirty_font = true;
dirty_cache = true;
if (font_override.is_valid()) {
- font_override->connect_changed(Callable(this, "_font_changed"));
+ font_override->connect_changed(font_changed);
}
_request_update();
}
diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp
index 29cd9f648d..a97ff5054d 100644
--- a/scene/resources/resource_format_text.cpp
+++ b/scene/resources/resource_format_text.cpp
@@ -2289,10 +2289,10 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const Ref<Reso
}
String connstr = "[connection";
- connstr += " signal=\"" + String(state->get_connection_signal(i)) + "\"";
- connstr += " from=\"" + String(state->get_connection_source(i).simplified()) + "\"";
- connstr += " to=\"" + String(state->get_connection_target(i).simplified()) + "\"";
- connstr += " method=\"" + String(state->get_connection_method(i)) + "\"";
+ connstr += " signal=\"" + String(state->get_connection_signal(i)).c_escape() + "\"";
+ connstr += " from=\"" + String(state->get_connection_source(i).simplified()).c_escape() + "\"";
+ connstr += " to=\"" + String(state->get_connection_target(i).simplified()).c_escape() + "\"";
+ connstr += " method=\"" + String(state->get_connection_method(i)).c_escape() + "\"";
int flags = state->get_connection_flags(i);
if (flags != Object::CONNECT_PERSIST) {
connstr += " flags=" + itos(flags);
@@ -2319,7 +2319,7 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const Ref<Reso
if (i == 0) {
f->store_line("");
}
- f->store_line("[editable path=\"" + editable_instances[i].operator String() + "\"]");
+ f->store_line("[editable path=\"" + editable_instances[i].operator String().c_escape() + "\"]");
}
}
diff --git a/scene/resources/skeleton_profile.cpp b/scene/resources/skeleton_profile.cpp
index da4b1f7311..24ed480289 100644
--- a/scene/resources/skeleton_profile.cpp
+++ b/scene/resources/skeleton_profile.cpp
@@ -180,7 +180,7 @@ StringName SkeletonProfile::get_root_bone() {
return root_bone;
}
-void SkeletonProfile::set_root_bone(StringName p_bone_name) {
+void SkeletonProfile::set_root_bone(const StringName &p_bone_name) {
if (is_read_only) {
return;
}
@@ -191,7 +191,7 @@ StringName SkeletonProfile::get_scale_base_bone() {
return scale_base_bone;
}
-void SkeletonProfile::set_scale_base_bone(StringName p_bone_name) {
+void SkeletonProfile::set_scale_base_bone(const StringName &p_bone_name) {
if (is_read_only) {
return;
}
@@ -217,7 +217,7 @@ StringName SkeletonProfile::get_group_name(int p_group_idx) const {
return groups[p_group_idx].group_name;
}
-void SkeletonProfile::set_group_name(int p_group_idx, const StringName p_group_name) {
+void SkeletonProfile::set_group_name(int p_group_idx, const StringName &p_group_name) {
if (is_read_only) {
return;
}
@@ -254,7 +254,7 @@ void SkeletonProfile::set_bone_size(int p_size) {
notify_property_list_changed();
}
-int SkeletonProfile::find_bone(StringName p_bone_name) const {
+int SkeletonProfile::find_bone(const StringName &p_bone_name) const {
if (p_bone_name == StringName()) {
return -1;
}
@@ -271,7 +271,7 @@ StringName SkeletonProfile::get_bone_name(int p_bone_idx) const {
return bones[p_bone_idx].bone_name;
}
-void SkeletonProfile::set_bone_name(int p_bone_idx, const StringName p_bone_name) {
+void SkeletonProfile::set_bone_name(int p_bone_idx, const StringName &p_bone_name) {
if (is_read_only) {
return;
}
@@ -285,7 +285,7 @@ StringName SkeletonProfile::get_bone_parent(int p_bone_idx) const {
return bones[p_bone_idx].bone_parent;
}
-void SkeletonProfile::set_bone_parent(int p_bone_idx, const StringName p_bone_parent) {
+void SkeletonProfile::set_bone_parent(int p_bone_idx, const StringName &p_bone_parent) {
if (is_read_only) {
return;
}
@@ -314,7 +314,7 @@ StringName SkeletonProfile::get_bone_tail(int p_bone_idx) const {
return bones[p_bone_idx].bone_tail;
}
-void SkeletonProfile::set_bone_tail(int p_bone_idx, const StringName p_bone_tail) {
+void SkeletonProfile::set_bone_tail(int p_bone_idx, const StringName &p_bone_tail) {
if (is_read_only) {
return;
}
@@ -356,7 +356,7 @@ StringName SkeletonProfile::get_group(int p_bone_idx) const {
return bones[p_bone_idx].group;
}
-void SkeletonProfile::set_group(int p_bone_idx, const StringName p_group) {
+void SkeletonProfile::set_group(int p_bone_idx, const StringName &p_group) {
if (is_read_only) {
return;
}
@@ -379,7 +379,7 @@ void SkeletonProfile::set_require(int p_bone_idx, const bool p_require) {
emit_signal("profile_updated");
}
-bool SkeletonProfile::has_bone(StringName p_bone_name) {
+bool SkeletonProfile::has_bone(const StringName &p_bone_name) {
bool is_found = false;
for (int i = 0; i < bones.size(); i++) {
if (bones[i].bone_name == p_bone_name) {
diff --git a/scene/resources/skeleton_profile.h b/scene/resources/skeleton_profile.h
index 418a051976..143f495c61 100644
--- a/scene/resources/skeleton_profile.h
+++ b/scene/resources/skeleton_profile.h
@@ -78,16 +78,16 @@ protected:
public:
StringName get_root_bone();
- void set_root_bone(StringName p_bone_name);
+ void set_root_bone(const StringName &p_bone_name);
StringName get_scale_base_bone();
- void set_scale_base_bone(StringName p_bone_name);
+ void set_scale_base_bone(const StringName &p_bone_name);
int get_group_size();
void set_group_size(int p_size);
StringName get_group_name(int p_group_idx) const;
- void set_group_name(int p_group_idx, const StringName p_group_name);
+ void set_group_name(int p_group_idx, const StringName &p_group_name);
Ref<Texture2D> get_texture(int p_group_idx) const;
void set_texture(int p_group_idx, const Ref<Texture2D> &p_texture);
@@ -95,19 +95,19 @@ public:
int get_bone_size();
void set_bone_size(int p_size);
- int find_bone(const StringName p_bone_name) const;
+ int find_bone(const StringName &p_bone_name) const;
StringName get_bone_name(int p_bone_idx) const;
- void set_bone_name(int p_bone_idx, const StringName p_bone_name);
+ void set_bone_name(int p_bone_idx, const StringName &p_bone_name);
StringName get_bone_parent(int p_bone_idx) const;
- void set_bone_parent(int p_bone_idx, const StringName p_bone_parent);
+ void set_bone_parent(int p_bone_idx, const StringName &p_bone_parent);
TailDirection get_tail_direction(int p_bone_idx) const;
void set_tail_direction(int p_bone_idx, const TailDirection p_tail_direction);
StringName get_bone_tail(int p_bone_idx) const;
- void set_bone_tail(int p_bone_idx, const StringName p_bone_tail);
+ void set_bone_tail(int p_bone_idx, const StringName &p_bone_tail);
Transform3D get_reference_pose(int p_bone_idx) const;
void set_reference_pose(int p_bone_idx, const Transform3D p_reference_pose);
@@ -116,12 +116,12 @@ public:
void set_handle_offset(int p_bone_idx, const Vector2 p_handle_offset);
StringName get_group(int p_bone_idx) const;
- void set_group(int p_bone_idx, const StringName p_group);
+ void set_group(int p_bone_idx, const StringName &p_group);
bool is_require(int p_bone_idx) const;
void set_require(int p_bone_idx, const bool p_require);
- bool has_bone(StringName p_bone_name);
+ bool has_bone(const StringName &p_bone_name);
SkeletonProfile();
~SkeletonProfile();
diff --git a/scene/resources/theme.cpp b/scene/resources/theme.cpp
index d57a0f6b38..b6cd6f6dfe 100644
--- a/scene/resources/theme.cpp
+++ b/scene/resources/theme.cpp
@@ -322,7 +322,7 @@ void Theme::clear_icon(const StringName &p_name, const StringName &p_theme_type)
_emit_theme_changed(true);
}
-void Theme::get_icon_list(StringName p_theme_type, List<StringName> *p_list) const {
+void Theme::get_icon_list(const StringName &p_theme_type, List<StringName> *p_list) const {
ERR_FAIL_NULL(p_list);
if (!icon_map.has(p_theme_type)) {
@@ -432,7 +432,7 @@ void Theme::clear_stylebox(const StringName &p_name, const StringName &p_theme_t
_emit_theme_changed(true);
}
-void Theme::get_stylebox_list(StringName p_theme_type, List<StringName> *p_list) const {
+void Theme::get_stylebox_list(const StringName &p_theme_type, List<StringName> *p_list) const {
ERR_FAIL_NULL(p_list);
if (!style_map.has(p_theme_type)) {
@@ -544,7 +544,7 @@ void Theme::clear_font(const StringName &p_name, const StringName &p_theme_type)
_emit_theme_changed(true);
}
-void Theme::get_font_list(StringName p_theme_type, List<StringName> *p_list) const {
+void Theme::get_font_list(const StringName &p_theme_type, List<StringName> *p_list) const {
ERR_FAIL_NULL(p_list);
if (!font_map.has(p_theme_type)) {
@@ -643,7 +643,7 @@ void Theme::clear_font_size(const StringName &p_name, const StringName &p_theme_
_emit_theme_changed(true);
}
-void Theme::get_font_size_list(StringName p_theme_type, List<StringName> *p_list) const {
+void Theme::get_font_size_list(const StringName &p_theme_type, List<StringName> *p_list) const {
ERR_FAIL_NULL(p_list);
if (!font_size_map.has(p_theme_type)) {
@@ -729,7 +729,7 @@ void Theme::clear_color(const StringName &p_name, const StringName &p_theme_type
_emit_theme_changed(true);
}
-void Theme::get_color_list(StringName p_theme_type, List<StringName> *p_list) const {
+void Theme::get_color_list(const StringName &p_theme_type, List<StringName> *p_list) const {
ERR_FAIL_NULL(p_list);
if (!color_map.has(p_theme_type)) {
@@ -815,7 +815,7 @@ void Theme::clear_constant(const StringName &p_name, const StringName &p_theme_t
_emit_theme_changed(true);
}
-void Theme::get_constant_list(StringName p_theme_type, List<StringName> *p_list) const {
+void Theme::get_constant_list(const StringName &p_theme_type, List<StringName> *p_list) const {
ERR_FAIL_NULL(p_list);
if (!constant_map.has(p_theme_type)) {
@@ -1009,7 +1009,7 @@ void Theme::clear_theme_item(DataType p_data_type, const StringName &p_name, con
}
}
-void Theme::get_theme_item_list(DataType p_data_type, StringName p_theme_type, List<StringName> *p_list) const {
+void Theme::get_theme_item_list(DataType p_data_type, const StringName &p_theme_type, List<StringName> *p_list) const {
switch (p_data_type) {
case DATA_TYPE_COLOR:
get_color_list(p_theme_type, p_list);
@@ -1613,6 +1613,17 @@ void Theme::merge_with(const Ref<Theme> &p_other) {
}
}
+ // Defaults.
+ if (p_other->has_default_font()) {
+ set_default_font(p_other->default_font);
+ }
+ if (p_other->has_default_font_size()) {
+ set_default_font_size(p_other->default_font_size);
+ }
+ if (p_other->has_default_base_scale()) {
+ set_default_base_scale(p_other->default_base_scale);
+ }
+
_unfreeze_and_propagate_changes();
}
diff --git a/scene/resources/theme.h b/scene/resources/theme.h
index b26b5b5e84..73f1167c29 100644
--- a/scene/resources/theme.h
+++ b/scene/resources/theme.h
@@ -136,7 +136,7 @@ public:
bool has_icon_nocheck(const StringName &p_name, const StringName &p_theme_type) const;
void rename_icon(const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type);
void clear_icon(const StringName &p_name, const StringName &p_theme_type);
- void get_icon_list(StringName p_theme_type, List<StringName> *p_list) const;
+ void get_icon_list(const StringName &p_theme_type, List<StringName> *p_list) const;
void add_icon_type(const StringName &p_theme_type);
void remove_icon_type(const StringName &p_theme_type);
void get_icon_type_list(List<StringName> *p_list) const;
@@ -147,7 +147,7 @@ public:
bool has_stylebox_nocheck(const StringName &p_name, const StringName &p_theme_type) const;
void rename_stylebox(const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type);
void clear_stylebox(const StringName &p_name, const StringName &p_theme_type);
- void get_stylebox_list(StringName p_theme_type, List<StringName> *p_list) const;
+ void get_stylebox_list(const StringName &p_theme_type, List<StringName> *p_list) const;
void add_stylebox_type(const StringName &p_theme_type);
void remove_stylebox_type(const StringName &p_theme_type);
void get_stylebox_type_list(List<StringName> *p_list) const;
@@ -158,7 +158,7 @@ public:
bool has_font_nocheck(const StringName &p_name, const StringName &p_theme_type) const;
void rename_font(const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type);
void clear_font(const StringName &p_name, const StringName &p_theme_type);
- void get_font_list(StringName p_theme_type, List<StringName> *p_list) const;
+ void get_font_list(const StringName &p_theme_type, List<StringName> *p_list) const;
void add_font_type(const StringName &p_theme_type);
void remove_font_type(const StringName &p_theme_type);
void get_font_type_list(List<StringName> *p_list) const;
@@ -169,7 +169,7 @@ public:
bool has_font_size_nocheck(const StringName &p_name, const StringName &p_theme_type) const;
void rename_font_size(const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type);
void clear_font_size(const StringName &p_name, const StringName &p_theme_type);
- void get_font_size_list(StringName p_theme_type, List<StringName> *p_list) const;
+ void get_font_size_list(const StringName &p_theme_type, List<StringName> *p_list) const;
void add_font_size_type(const StringName &p_theme_type);
void remove_font_size_type(const StringName &p_theme_type);
void get_font_size_type_list(List<StringName> *p_list) const;
@@ -180,7 +180,7 @@ public:
bool has_color_nocheck(const StringName &p_name, const StringName &p_theme_type) const;
void rename_color(const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type);
void clear_color(const StringName &p_name, const StringName &p_theme_type);
- void get_color_list(StringName p_theme_type, List<StringName> *p_list) const;
+ void get_color_list(const StringName &p_theme_type, List<StringName> *p_list) const;
void add_color_type(const StringName &p_theme_type);
void remove_color_type(const StringName &p_theme_type);
void get_color_type_list(List<StringName> *p_list) const;
@@ -191,7 +191,7 @@ public:
bool has_constant_nocheck(const StringName &p_name, const StringName &p_theme_type) const;
void rename_constant(const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type);
void clear_constant(const StringName &p_name, const StringName &p_theme_type);
- void get_constant_list(StringName p_theme_type, List<StringName> *p_list) const;
+ void get_constant_list(const StringName &p_theme_type, List<StringName> *p_list) const;
void add_constant_type(const StringName &p_theme_type);
void remove_constant_type(const StringName &p_theme_type);
void get_constant_type_list(List<StringName> *p_list) const;
@@ -202,7 +202,7 @@ public:
bool has_theme_item_nocheck(DataType p_data_type, const StringName &p_name, const StringName &p_theme_type) const;
void rename_theme_item(DataType p_data_type, const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type);
void clear_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_theme_type);
- void get_theme_item_list(DataType p_data_type, StringName p_theme_type, List<StringName> *p_list) const;
+ void get_theme_item_list(DataType p_data_type, const StringName &p_theme_type, List<StringName> *p_list) const;
void add_theme_item_type(DataType p_data_type, const StringName &p_theme_type);
void remove_theme_item_type(DataType p_data_type, const StringName &p_theme_type);
void get_theme_item_type_list(DataType p_data_type, List<StringName> *p_list) const;
diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp
index 2de7cce5c7..a99102e847 100644
--- a/scene/resources/tile_set.cpp
+++ b/scene/resources/tile_set.cpp
@@ -4675,7 +4675,6 @@ void TileSetAtlasSource::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_tile_texture_region", "atlas_coords", "frame"), &TileSetAtlasSource::get_tile_texture_region, DEFVAL(0));
// Getters for texture and tile region (padded or not)
- ClassDB::bind_method(D_METHOD("_update_padded_texture"), &TileSetAtlasSource::_update_padded_texture);
ClassDB::bind_method(D_METHOD("get_runtime_texture"), &TileSetAtlasSource::get_runtime_texture);
ClassDB::bind_method(D_METHOD("get_runtime_tile_texture_region", "atlas_coords", "frame"), &TileSetAtlasSource::get_runtime_tile_texture_region);
@@ -4761,7 +4760,7 @@ void TileSetAtlasSource::_create_coords_mapping_cache(Vector2i p_atlas_coords) {
void TileSetAtlasSource::_queue_update_padded_texture() {
padded_texture_needs_update = true;
- call_deferred(SNAME("_update_padded_texture"));
+ callable_mp(this, &TileSetAtlasSource::_update_padded_texture).call_deferred();
}
Ref<ImageTexture> TileSetAtlasSource::_create_padded_image_texture(const Ref<Texture2D> &p_source) {
diff --git a/scene/theme/default_theme.cpp b/scene/theme/default_theme.cpp
index d1b854246b..2a1894e690 100644
--- a/scene/theme/default_theme.cpp
+++ b/scene/theme/default_theme.cpp
@@ -299,13 +299,13 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_stylebox("focus", "CheckBox", cbx_focus);
theme->set_icon("checked", "CheckBox", icons["checked"]);
- theme->set_icon("checked_disabled", "CheckBox", icons["checked"]);
+ theme->set_icon("checked_disabled", "CheckBox", icons["checked_disabled"]);
theme->set_icon("unchecked", "CheckBox", icons["unchecked"]);
- theme->set_icon("unchecked_disabled", "CheckBox", icons["unchecked"]);
+ theme->set_icon("unchecked_disabled", "CheckBox", icons["unchecked_disabled"]);
theme->set_icon("radio_checked", "CheckBox", icons["radio_checked"]);
- theme->set_icon("radio_checked_disabled", "CheckBox", icons["radio_checked"]);
+ theme->set_icon("radio_checked_disabled", "CheckBox", icons["radio_checked_disabled"]);
theme->set_icon("radio_unchecked", "CheckBox", icons["radio_unchecked"]);
- theme->set_icon("radio_unchecked_disabled", "CheckBox", icons["radio_unchecked"]);
+ theme->set_icon("radio_unchecked_disabled", "CheckBox", icons["radio_unchecked_disabled"]);
theme->set_font("font", "CheckBox", Ref<Font>());
theme->set_font_size("font_size", "CheckBox", -1);
@@ -685,13 +685,13 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_stylebox("labeled_separator_right", "PopupMenu", separator_horizontal);
theme->set_icon("checked", "PopupMenu", icons["checked"]);
- theme->set_icon("checked_disabled", "PopupMenu", icons["checked"]);
+ theme->set_icon("checked_disabled", "PopupMenu", icons["checked_disabled"]);
theme->set_icon("unchecked", "PopupMenu", icons["unchecked"]);
- theme->set_icon("unchecked_disabled", "PopupMenu", icons["unchecked"]);
+ theme->set_icon("unchecked_disabled", "PopupMenu", icons["unchecked_disabled"]);
theme->set_icon("radio_checked", "PopupMenu", icons["radio_checked"]);
- theme->set_icon("radio_checked_disabled", "PopupMenu", icons["radio_checked"]);
+ theme->set_icon("radio_checked_disabled", "PopupMenu", icons["radio_checked_disabled"]);
theme->set_icon("radio_unchecked", "PopupMenu", icons["radio_unchecked"]);
- theme->set_icon("radio_unchecked_disabled", "PopupMenu", icons["radio_unchecked"]);
+ theme->set_icon("radio_unchecked_disabled", "PopupMenu", icons["radio_unchecked_disabled"]);
theme->set_icon("submenu", "PopupMenu", icons["popup_menu_arrow_right"]);
theme->set_icon("submenu_mirrored", "PopupMenu", icons["popup_menu_arrow_left"]);
diff --git a/scene/theme/theme_owner.cpp b/scene/theme/theme_owner.cpp
index 2852a64e39..b559c8c58d 100644
--- a/scene/theme/theme_owner.cpp
+++ b/scene/theme/theme_owner.cpp
@@ -249,7 +249,7 @@ void ThemeOwner::get_theme_type_dependencies(const Node *p_for_node, const Strin
ThemeDB::get_singleton()->get_native_type_dependencies(p_theme_type, r_list);
}
-Variant ThemeOwner::get_theme_item_in_types(Theme::DataType p_data_type, const StringName &p_name, List<StringName> p_theme_types) {
+Variant ThemeOwner::get_theme_item_in_types(Theme::DataType p_data_type, const StringName &p_name, const List<StringName> &p_theme_types) {
ERR_FAIL_COND_V_MSG(p_theme_types.size() == 0, Variant(), "At least one theme type must be specified.");
// First, look through each control or window node in the branch, until no valid parent can be found.
@@ -285,7 +285,7 @@ Variant ThemeOwner::get_theme_item_in_types(Theme::DataType p_data_type, const S
return global_context->get_fallback_theme()->get_theme_item(p_data_type, p_name, StringName());
}
-bool ThemeOwner::has_theme_item_in_types(Theme::DataType p_data_type, const StringName &p_name, List<StringName> p_theme_types) {
+bool ThemeOwner::has_theme_item_in_types(Theme::DataType p_data_type, const StringName &p_name, const List<StringName> &p_theme_types) {
ERR_FAIL_COND_V_MSG(p_theme_types.size() == 0, false, "At least one theme type must be specified.");
// First, look through each control or window node in the branch, until no valid parent can be found.
diff --git a/scene/theme/theme_owner.h b/scene/theme/theme_owner.h
index 4923ccb00b..7e19279c2a 100644
--- a/scene/theme/theme_owner.h
+++ b/scene/theme/theme_owner.h
@@ -71,8 +71,8 @@ public:
void get_theme_type_dependencies(const Node *p_for_node, const StringName &p_theme_type, List<StringName> *r_list) const;
- Variant get_theme_item_in_types(Theme::DataType p_data_type, const StringName &p_name, List<StringName> p_theme_types);
- bool has_theme_item_in_types(Theme::DataType p_data_type, const StringName &p_name, List<StringName> p_theme_types);
+ Variant get_theme_item_in_types(Theme::DataType p_data_type, const StringName &p_name, const List<StringName> &p_theme_types);
+ bool has_theme_item_in_types(Theme::DataType p_data_type, const StringName &p_name, const List<StringName> &p_theme_types);
float get_theme_default_base_scale();
Ref<Font> get_theme_default_font();
diff --git a/servers/audio_server.cpp b/servers/audio_server.cpp
index 026bc6675a..86bdd13c80 100644
--- a/servers/audio_server.cpp
+++ b/servers/audio_server.cpp
@@ -1120,7 +1120,7 @@ float AudioServer::get_playback_speed_scale() const {
return playback_speed_scale;
}
-void AudioServer::start_playback_stream(Ref<AudioStreamPlayback> p_playback, StringName p_bus, Vector<AudioFrame> p_volume_db_vector, float p_start_time, float p_pitch_scale) {
+void AudioServer::start_playback_stream(Ref<AudioStreamPlayback> p_playback, const StringName &p_bus, Vector<AudioFrame> p_volume_db_vector, float p_start_time, float p_pitch_scale) {
ERR_FAIL_COND(p_playback.is_null());
HashMap<StringName, Vector<AudioFrame>> map;
@@ -1129,7 +1129,7 @@ void AudioServer::start_playback_stream(Ref<AudioStreamPlayback> p_playback, Str
start_playback_stream(p_playback, map, p_start_time, p_pitch_scale);
}
-void AudioServer::start_playback_stream(Ref<AudioStreamPlayback> p_playback, HashMap<StringName, Vector<AudioFrame>> p_bus_volumes, float p_start_time, float p_pitch_scale, float p_highshelf_gain, float p_attenuation_cutoff_hz) {
+void AudioServer::start_playback_stream(Ref<AudioStreamPlayback> p_playback, const HashMap<StringName, Vector<AudioFrame>> &p_bus_volumes, float p_start_time, float p_pitch_scale, float p_highshelf_gain, float p_attenuation_cutoff_hz) {
ERR_FAIL_COND(p_playback.is_null());
AudioStreamPlaybackListNode *playback_node = new AudioStreamPlaybackListNode();
@@ -1188,7 +1188,7 @@ void AudioServer::stop_playback_stream(Ref<AudioStreamPlayback> p_playback) {
} while (!playback_node->state.compare_exchange_strong(old_state, new_state));
}
-void AudioServer::set_playback_bus_exclusive(Ref<AudioStreamPlayback> p_playback, StringName p_bus, Vector<AudioFrame> p_volumes) {
+void AudioServer::set_playback_bus_exclusive(Ref<AudioStreamPlayback> p_playback, const StringName &p_bus, Vector<AudioFrame> p_volumes) {
ERR_FAIL_COND(p_volumes.size() != MAX_CHANNELS_PER_BUS);
HashMap<StringName, Vector<AudioFrame>> map;
@@ -1197,7 +1197,7 @@ void AudioServer::set_playback_bus_exclusive(Ref<AudioStreamPlayback> p_playback
set_playback_bus_volumes_linear(p_playback, map);
}
-void AudioServer::set_playback_bus_volumes_linear(Ref<AudioStreamPlayback> p_playback, HashMap<StringName, Vector<AudioFrame>> p_bus_volumes) {
+void AudioServer::set_playback_bus_volumes_linear(Ref<AudioStreamPlayback> p_playback, const HashMap<StringName, Vector<AudioFrame>> &p_bus_volumes) {
ERR_FAIL_COND(p_bus_volumes.size() > MAX_BUSES_PER_PLAYBACK);
AudioStreamPlaybackListNode *playback_node = _find_playback_list_node(p_playback);
diff --git a/servers/audio_server.h b/servers/audio_server.h
index 9ffa95bc00..4606299c47 100644
--- a/servers/audio_server.h
+++ b/servers/audio_server.h
@@ -372,13 +372,13 @@ public:
float get_playback_speed_scale() const;
// Convenience method.
- void start_playback_stream(Ref<AudioStreamPlayback> p_playback, StringName p_bus, Vector<AudioFrame> p_volume_db_vector, float p_start_time = 0, float p_pitch_scale = 1);
+ void start_playback_stream(Ref<AudioStreamPlayback> p_playback, const StringName &p_bus, Vector<AudioFrame> p_volume_db_vector, float p_start_time = 0, float p_pitch_scale = 1);
// Expose all parameters.
- void start_playback_stream(Ref<AudioStreamPlayback> p_playback, HashMap<StringName, Vector<AudioFrame>> p_bus_volumes, float p_start_time = 0, float p_pitch_scale = 1, float p_highshelf_gain = 0, float p_attenuation_cutoff_hz = 0);
+ void start_playback_stream(Ref<AudioStreamPlayback> p_playback, const HashMap<StringName, Vector<AudioFrame>> &p_bus_volumes, float p_start_time = 0, float p_pitch_scale = 1, float p_highshelf_gain = 0, float p_attenuation_cutoff_hz = 0);
void stop_playback_stream(Ref<AudioStreamPlayback> p_playback);
- void set_playback_bus_exclusive(Ref<AudioStreamPlayback> p_playback, StringName p_bus, Vector<AudioFrame> p_volumes);
- void set_playback_bus_volumes_linear(Ref<AudioStreamPlayback> p_playback, HashMap<StringName, Vector<AudioFrame>> p_bus_volumes);
+ void set_playback_bus_exclusive(Ref<AudioStreamPlayback> p_playback, const StringName &p_bus, Vector<AudioFrame> p_volumes);
+ void set_playback_bus_volumes_linear(Ref<AudioStreamPlayback> p_playback, const HashMap<StringName, Vector<AudioFrame>> &p_bus_volumes);
void set_playback_all_bus_volumes_linear(Ref<AudioStreamPlayback> p_playback, Vector<AudioFrame> p_volumes);
void set_playback_pitch_scale(Ref<AudioStreamPlayback> p_playback, float p_pitch_scale);
void set_playback_paused(Ref<AudioStreamPlayback> p_playback, bool p_paused);
diff --git a/servers/display_server.cpp b/servers/display_server.cpp
index bb28bc0eb8..a587f72d02 100644
--- a/servers/display_server.cpp
+++ b/servers/display_server.cpp
@@ -596,6 +596,10 @@ DisplayServer::VSyncMode DisplayServer::window_get_vsync_mode(WindowID p_window)
return VSyncMode::VSYNC_ENABLED;
}
+DisplayServer::WindowID DisplayServer::get_focused_window() const {
+ return MAIN_WINDOW_ID; // Proper value for single windows.
+}
+
void DisplayServer::set_context(Context p_context) {
}
diff --git a/servers/display_server.h b/servers/display_server.h
index 4450677f71..92a4a4a699 100644
--- a/servers/display_server.h
+++ b/servers/display_server.h
@@ -436,6 +436,8 @@ public:
virtual void window_move_to_foreground(WindowID p_window = MAIN_WINDOW_ID) = 0;
virtual bool window_is_focused(WindowID p_window = MAIN_WINDOW_ID) const = 0;
+ virtual WindowID get_focused_window() const;
+
virtual void window_set_window_buttons_offset(const Vector2i &p_offset, WindowID p_window = MAIN_WINDOW_ID) {}
virtual Vector3i window_get_safe_title_margins(WindowID p_window = MAIN_WINDOW_ID) const { return Vector3i(); }
diff --git a/servers/navigation_server_3d.cpp b/servers/navigation_server_3d.cpp
index 21e1ccaa72..412b12e145 100644
--- a/servers/navigation_server_3d.cpp
+++ b/servers/navigation_server_3d.cpp
@@ -286,7 +286,7 @@ void NavigationServer3D::set_debug_enabled(bool p_enabled) {
debug_enabled = p_enabled;
if (debug_dirty) {
- call_deferred("_emit_navigation_debug_changed_signal");
+ callable_mp(this, &NavigationServer3D::_emit_navigation_debug_changed_signal).call_deferred();
}
#endif // DEBUG_ENABLED
}
@@ -693,7 +693,7 @@ Color NavigationServer3D::get_debug_navigation_agent_path_color() const {
void NavigationServer3D::set_debug_navigation_enable_edge_connections(const bool p_value) {
debug_navigation_enable_edge_connections = p_value;
navigation_debug_dirty = true;
- call_deferred("_emit_navigation_debug_changed_signal");
+ callable_mp(this, &NavigationServer3D::_emit_navigation_debug_changed_signal).call_deferred();
}
bool NavigationServer3D::get_debug_navigation_enable_edge_connections() const {
@@ -714,7 +714,7 @@ bool NavigationServer3D::get_debug_navigation_enable_edge_connections_xray() con
void NavigationServer3D::set_debug_navigation_enable_edge_lines(const bool p_value) {
debug_navigation_enable_edge_lines = p_value;
navigation_debug_dirty = true;
- call_deferred("_emit_navigation_debug_changed_signal");
+ callable_mp(this, &NavigationServer3D::_emit_navigation_debug_changed_signal).call_deferred();
}
bool NavigationServer3D::get_debug_navigation_enable_edge_lines() const {
@@ -735,7 +735,7 @@ bool NavigationServer3D::get_debug_navigation_enable_edge_lines_xray() const {
void NavigationServer3D::set_debug_navigation_enable_geometry_face_random_color(const bool p_value) {
debug_navigation_enable_geometry_face_random_color = p_value;
navigation_debug_dirty = true;
- call_deferred("_emit_navigation_debug_changed_signal");
+ callable_mp(this, &NavigationServer3D::_emit_navigation_debug_changed_signal).call_deferred();
}
bool NavigationServer3D::get_debug_navigation_enable_geometry_face_random_color() const {
@@ -745,7 +745,7 @@ bool NavigationServer3D::get_debug_navigation_enable_geometry_face_random_color(
void NavigationServer3D::set_debug_navigation_enable_link_connections(const bool p_value) {
debug_navigation_enable_link_connections = p_value;
navigation_debug_dirty = true;
- call_deferred("_emit_navigation_debug_changed_signal");
+ callable_mp(this, &NavigationServer3D::_emit_navigation_debug_changed_signal).call_deferred();
}
bool NavigationServer3D::get_debug_navigation_enable_link_connections() const {
@@ -766,7 +766,7 @@ bool NavigationServer3D::get_debug_navigation_enable_link_connections_xray() con
void NavigationServer3D::set_debug_navigation_avoidance_enable_agents_radius(const bool p_value) {
debug_navigation_avoidance_enable_agents_radius = p_value;
avoidance_debug_dirty = true;
- call_deferred("_emit_avoidance_debug_changed_signal");
+ callable_mp(this, &NavigationServer3D::_emit_avoidance_debug_changed_signal).call_deferred();
}
bool NavigationServer3D::get_debug_navigation_avoidance_enable_agents_radius() const {
@@ -776,7 +776,7 @@ bool NavigationServer3D::get_debug_navigation_avoidance_enable_agents_radius() c
void NavigationServer3D::set_debug_navigation_avoidance_enable_obstacles_radius(const bool p_value) {
debug_navigation_avoidance_enable_obstacles_radius = p_value;
avoidance_debug_dirty = true;
- call_deferred("_emit_avoidance_debug_changed_signal");
+ callable_mp(this, &NavigationServer3D::_emit_avoidance_debug_changed_signal).call_deferred();
}
bool NavigationServer3D::get_debug_navigation_avoidance_enable_obstacles_radius() const {
@@ -786,7 +786,7 @@ bool NavigationServer3D::get_debug_navigation_avoidance_enable_obstacles_radius(
void NavigationServer3D::set_debug_navigation_avoidance_enable_obstacles_static(const bool p_value) {
debug_navigation_avoidance_enable_obstacles_static = p_value;
avoidance_debug_dirty = true;
- call_deferred("_emit_avoidance_debug_changed_signal");
+ callable_mp(this, &NavigationServer3D::_emit_avoidance_debug_changed_signal).call_deferred();
}
bool NavigationServer3D::get_debug_navigation_avoidance_enable_obstacles_static() const {
@@ -867,7 +867,7 @@ void NavigationServer3D::set_debug_navigation_enable_agent_paths(const bool p_va
debug_navigation_enable_agent_paths = p_value;
if (debug_dirty) {
- call_deferred("_emit_navigation_debug_changed_signal");
+ callable_mp(this, &NavigationServer3D::_emit_navigation_debug_changed_signal).call_deferred();
}
}
@@ -892,7 +892,7 @@ bool NavigationServer3D::get_debug_navigation_enable_agent_paths_xray() const {
void NavigationServer3D::set_debug_navigation_enabled(bool p_enabled) {
debug_navigation_enabled = p_enabled;
navigation_debug_dirty = true;
- call_deferred("_emit_navigation_debug_changed_signal");
+ callable_mp(this, &NavigationServer3D::_emit_navigation_debug_changed_signal).call_deferred();
}
bool NavigationServer3D::get_debug_navigation_enabled() const {
@@ -902,7 +902,7 @@ bool NavigationServer3D::get_debug_navigation_enabled() const {
void NavigationServer3D::set_debug_avoidance_enabled(bool p_enabled) {
debug_avoidance_enabled = p_enabled;
avoidance_debug_dirty = true;
- call_deferred("_emit_avoidance_debug_changed_signal");
+ callable_mp(this, &NavigationServer3D::_emit_avoidance_debug_changed_signal).call_deferred();
}
bool NavigationServer3D::get_debug_avoidance_enabled() const {
diff --git a/servers/rendering/dummy/rasterizer_dummy.h b/servers/rendering/dummy/rasterizer_dummy.h
index 179c41f286..929c661009 100644
--- a/servers/rendering/dummy/rasterizer_dummy.h
+++ b/servers/rendering/dummy/rasterizer_dummy.h
@@ -89,6 +89,8 @@ public:
void prepare_for_blitting_render_targets() override {}
void blit_render_targets_to_screen(int p_screen, const BlitToScreen *p_render_targets, int p_amount) override {}
+ void end_viewport(bool p_swap_buffers) override {}
+
void end_frame(bool p_swap_buffers) override {
if (p_swap_buffers) {
DisplayServer::get_singleton()->swap_buffers();
diff --git a/servers/rendering/renderer_canvas_cull.cpp b/servers/rendering/renderer_canvas_cull.cpp
index d21a985a60..caeac5cd95 100644
--- a/servers/rendering/renderer_canvas_cull.cpp
+++ b/servers/rendering/renderer_canvas_cull.cpp
@@ -2165,6 +2165,30 @@ bool RendererCanvasCull::free(RID p_rid) {
return true;
}
+template <class T>
+void RendererCanvasCull::_free_rids(T &p_owner, const char *p_type) {
+ List<RID> owned;
+ p_owner.get_owned_list(&owned);
+ if (owned.size()) {
+ if (owned.size() == 1) {
+ WARN_PRINT(vformat("1 RID of type \"%s\" was leaked.", p_type));
+ } else {
+ WARN_PRINT(vformat("%d RIDs of type \"%s\" were leaked.", owned.size(), p_type));
+ }
+ for (const RID &E : owned) {
+ free(E);
+ }
+ }
+}
+
+void RendererCanvasCull::finalize() {
+ _free_rids(canvas_owner, "Canvas");
+ _free_rids(canvas_item_owner, "CanvasItem");
+ _free_rids(canvas_light_owner, "CanvasLight");
+ _free_rids(canvas_light_occluder_owner, "CanvasLightOccluder");
+ _free_rids(canvas_light_occluder_polygon_owner, "CanvasLightOccluderPolygon");
+}
+
RendererCanvasCull::RendererCanvasCull() {
z_list = (RendererCanvasRender::Item **)memalloc(z_range * sizeof(RendererCanvasRender::Item *));
z_last_list = (RendererCanvasRender::Item **)memalloc(z_range * sizeof(RendererCanvasRender::Item *));
diff --git a/servers/rendering/renderer_canvas_cull.h b/servers/rendering/renderer_canvas_cull.h
index ae0f29f10e..de61e28204 100644
--- a/servers/rendering/renderer_canvas_cull.h
+++ b/servers/rendering/renderer_canvas_cull.h
@@ -170,6 +170,9 @@ public:
RID_Owner<Item, true> canvas_item_owner;
RID_Owner<RendererCanvasRender::Light, true> canvas_light_owner;
+ template <class T>
+ void _free_rids(T &p_owner, const char *p_type);
+
bool disable_scale;
bool sdf_used = false;
bool snapping_2d_transforms_to_pixel = false;
@@ -329,6 +332,9 @@ public:
Rect2 _debug_canvas_item_get_rect(RID p_item);
bool free(RID p_rid);
+
+ void finalize();
+
RendererCanvasCull();
~RendererCanvasCull();
};
diff --git a/servers/rendering/renderer_canvas_render.cpp b/servers/rendering/renderer_canvas_render.cpp
index af0ec621e5..6eb7bab9c9 100644
--- a/servers/rendering/renderer_canvas_render.cpp
+++ b/servers/rendering/renderer_canvas_render.cpp
@@ -31,6 +31,8 @@
#include "renderer_canvas_render.h"
#include "servers/rendering/rendering_server_globals.h"
+RendererCanvasRender *RendererCanvasRender::singleton = nullptr;
+
const Rect2 &RendererCanvasRender::Item::get_rect() const {
if (custom_rect || (!rect_dirty && !update_when_visible && skeleton == RID())) {
return rect;
diff --git a/servers/rendering/renderer_compositor.cpp b/servers/rendering/renderer_compositor.cpp
index a6083fe70d..c36da51e50 100644
--- a/servers/rendering/renderer_compositor.cpp
+++ b/servers/rendering/renderer_compositor.cpp
@@ -31,8 +31,6 @@
#include "renderer_compositor.h"
#include "core/config/project_settings.h"
-#include "core/os/os.h"
-#include "core/string/print_string.h"
#include "servers/xr_server.h"
RendererCompositor *RendererCompositor::singleton = nullptr;
@@ -57,5 +55,3 @@ RendererCompositor::RendererCompositor() {
xr_enabled = XRServer::get_xr_mode() == XRServer::XRMODE_ON;
}
}
-
-RendererCanvasRender *RendererCanvasRender::singleton = nullptr;
diff --git a/servers/rendering/renderer_compositor.h b/servers/rendering/renderer_compositor.h
index ff7792741c..13767a3875 100644
--- a/servers/rendering/renderer_compositor.h
+++ b/servers/rendering/renderer_compositor.h
@@ -99,6 +99,7 @@ public:
virtual void prepare_for_blitting_render_targets() = 0;
virtual void blit_render_targets_to_screen(DisplayServer::WindowID p_screen, const BlitToScreen *p_render_targets, int p_amount) = 0;
+ virtual void end_viewport(bool p_swap_buffers) = 0;
virtual void end_frame(bool p_swap_buffers) = 0;
virtual void finalize() = 0;
virtual uint64_t get_frame_number() const = 0;
diff --git a/servers/rendering/renderer_rd/api_context_rd.h b/servers/rendering/renderer_rd/api_context_rd.h
index 22167be3c1..fd3be80605 100644
--- a/servers/rendering/renderer_rd/api_context_rd.h
+++ b/servers/rendering/renderer_rd/api_context_rd.h
@@ -58,16 +58,12 @@ public:
virtual void set_setup_buffer(RDD::CommandBufferID p_command_buffer) = 0;
virtual void append_command_buffer(RDD::CommandBufferID p_command_buffer) = 0;
- virtual void flush(bool p_flush_setup = false, bool p_flush_pending = false) = 0;
+ virtual void flush(bool p_flush_setup = false, bool p_flush_pending = false, bool p_sync = true) = 0;
virtual Error prepare_buffers(RDD::CommandBufferID p_command_buffer) = 0;
virtual void postpare_buffers(RDD::CommandBufferID p_command_buffer) = 0;
virtual Error swap_buffers() = 0;
virtual Error initialize() = 0;
- virtual void command_begin_label(RDD::CommandBufferID p_command_buffer, String p_label_name, const Color &p_color) = 0;
- virtual void command_insert_label(RDD::CommandBufferID p_command_buffer, String p_label_name, const Color &p_color) = 0;
- virtual void command_end_label(RDD::CommandBufferID p_command_buffer) = 0;
-
virtual String get_device_vendor_name() const = 0;
virtual String get_device_name() const = 0;
virtual RDD::DeviceType get_device_type() const = 0;
@@ -78,6 +74,7 @@ public:
virtual DisplayServer::VSyncMode get_vsync_mode(DisplayServer::WindowID p_window = 0) const = 0;
virtual RenderingDeviceDriver *get_driver(RID p_local_device = RID()) = 0;
+ virtual bool is_debug_utils_enabled() const = 0;
virtual ~ApiContextRD();
};
diff --git a/servers/rendering/renderer_rd/cluster_builder_rd.cpp b/servers/rendering/renderer_rd/cluster_builder_rd.cpp
index 0d1721039c..e661fd9217 100644
--- a/servers/rendering/renderer_rd/cluster_builder_rd.cpp
+++ b/servers/rendering/renderer_rd/cluster_builder_rd.cpp
@@ -420,11 +420,11 @@ void ClusterBuilderRD::bake_cluster() {
RD::get_singleton()->draw_command_begin_label("Bake Light Cluster");
// Clear cluster buffer.
- RD::get_singleton()->buffer_clear(cluster_buffer, 0, cluster_buffer_size, RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_COMPUTE);
+ RD::get_singleton()->buffer_clear(cluster_buffer, 0, cluster_buffer_size);
if (render_element_count > 0) {
// Clear render buffer.
- RD::get_singleton()->buffer_clear(cluster_render_buffer, 0, cluster_render_buffer_size, RD::BARRIER_MASK_RASTER);
+ RD::get_singleton()->buffer_clear(cluster_render_buffer, 0, cluster_render_buffer_size);
{ // Fill state uniform.
@@ -439,18 +439,18 @@ void ClusterBuilderRD::bake_cluster() {
state.cluster_depth_offset = (render_element_max / 32);
state.cluster_data_size = state.cluster_depth_offset + render_element_max;
- RD::get_singleton()->buffer_update(state_uniform, 0, sizeof(StateUniform), &state, RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_COMPUTE);
+ RD::get_singleton()->buffer_update(state_uniform, 0, sizeof(StateUniform), &state);
}
// Update instances.
- RD::get_singleton()->buffer_update(element_buffer, 0, sizeof(RenderElementData) * render_element_count, render_elements, RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_COMPUTE);
+ RD::get_singleton()->buffer_update(element_buffer, 0, sizeof(RenderElementData) * render_element_count, render_elements);
RENDER_TIMESTAMP("Render 3D Cluster Elements");
// Render elements.
{
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD);
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD);
ClusterBuilderSharedDataRD::ClusterRender::PushConstant push_constant = {};
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, shared->cluster_render.shader_pipelines[use_msaa ? ClusterBuilderSharedDataRD::ClusterRender::PIPELINE_MSAA : ClusterBuilderSharedDataRD::ClusterRender::PIPELINE_NORMAL]);
@@ -488,7 +488,7 @@ void ClusterBuilderRD::bake_cluster() {
RD::get_singleton()->draw_list_draw(draw_list, true, instances);
i += instances;
}
- RD::get_singleton()->draw_list_end(RD::BARRIER_MASK_COMPUTE);
+ RD::get_singleton()->draw_list_end();
}
// Store elements.
RENDER_TIMESTAMP("Pack 3D Cluster Elements");
@@ -513,10 +513,8 @@ void ClusterBuilderRD::bake_cluster() {
RD::get_singleton()->compute_list_dispatch_threads(compute_list, cluster_screen_size.x, cluster_screen_size.y, 1);
- RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_COMPUTE);
+ RD::get_singleton()->compute_list_end();
}
- } else {
- RD::get_singleton()->barrier(RD::BARRIER_MASK_TRANSFER, RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_COMPUTE);
}
RENDER_TIMESTAMP("< Bake 3D Cluster");
RD::get_singleton()->draw_command_end_label();
diff --git a/servers/rendering/renderer_rd/effects/bokeh_dof.cpp b/servers/rendering/renderer_rd/effects/bokeh_dof.cpp
index cc5031823e..e6262c83e2 100644
--- a/servers/rendering/renderer_rd/effects/bokeh_dof.cpp
+++ b/servers/rendering/renderer_rd/effects/bokeh_dof.cpp
@@ -356,7 +356,7 @@ void BokehDOF::bokeh_dof_raster(const BokehBuffers &p_buffers, RID p_camera_attr
ERR_FAIL_COND(shader.is_null());
RID framebuffer = p_buffers.base_weight_fb;
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, bokeh.raster_pipelines[BOKEH_GEN_BLUR_SIZE].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(framebuffer)));
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_depth_texture), 0);
@@ -388,7 +388,7 @@ void BokehDOF::bokeh_dof_raster(const BokehBuffers &p_buffers, RID p_camera_attr
RID framebuffer = bokeh.push_constant.half_size ? p_buffers.half_fb[0] : p_buffers.secondary_fb;
// Pass 1
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, bokeh.raster_pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(framebuffer)));
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_base_texture), 0);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 1, u_weight_texture0), 1);
@@ -412,7 +412,7 @@ void BokehDOF::bokeh_dof_raster(const BokehBuffers &p_buffers, RID p_camera_attr
RD::Uniform texture = bokeh.push_constant.half_size ? u_half_texture0 : u_secondary_texture;
RD::Uniform weight = bokeh.push_constant.half_size ? u_weight_texture2 : u_weight_texture1;
- draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
+ draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, bokeh.raster_pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(framebuffer)));
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, texture), 0);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 1, weight), 1);
@@ -430,7 +430,7 @@ void BokehDOF::bokeh_dof_raster(const BokehBuffers &p_buffers, RID p_camera_attr
framebuffer = p_buffers.base_fb;
- draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
+ draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, bokeh.raster_pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(framebuffer)));
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_half_texture1), 0);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 1, u_weight_texture3), 1);
@@ -463,7 +463,7 @@ void BokehDOF::bokeh_dof_raster(const BokehBuffers &p_buffers, RID p_camera_attr
RID framebuffer = bokeh.push_constant.half_size ? p_buffers.half_fb[0] : p_buffers.secondary_fb;
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, bokeh.raster_pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(framebuffer)));
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_base_texture), 0);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 1, u_weight_texture0), 1);
@@ -481,7 +481,7 @@ void BokehDOF::bokeh_dof_raster(const BokehBuffers &p_buffers, RID p_camera_attr
framebuffer = p_buffers.base_fb;
- draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
+ draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, bokeh.raster_pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(framebuffer)));
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_half_texture0), 0);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 1, u_weight_texture2), 1);
diff --git a/servers/rendering/renderer_rd/effects/copy_effects.cpp b/servers/rendering/renderer_rd/effects/copy_effects.cpp
index bb584beb52..fd6409d6bf 100644
--- a/servers/rendering/renderer_rd/effects/copy_effects.cpp
+++ b/servers/rendering/renderer_rd/effects/copy_effects.cpp
@@ -583,7 +583,7 @@ void CopyEffects::copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffe
RID shader = copy_to_fb.shader.version_get_shader(copy_to_fb.shader_version, mode);
ERR_FAIL_COND(shader.is_null());
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, p_rect);
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, p_rect);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, copy_to_fb.pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer)));
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_rd_texture), 0);
if (p_secondary.is_valid()) {
@@ -650,7 +650,7 @@ void CopyEffects::copy_raster(RID p_source_texture, RID p_dest_framebuffer) {
ERR_FAIL_COND(shader.is_null());
// Just copy it back (we use our blur raster shader here)..
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur_raster.pipelines[BLUR_MODE_COPY].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer)));
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_texture), 0);
RD::get_singleton()->draw_list_bind_index_array(draw_list, material_storage->get_quad_index_array());
@@ -724,7 +724,7 @@ void CopyEffects::gaussian_blur_raster(RID p_source_rd_texture, RID p_dest_textu
RID shader = blur_raster.shader.version_get_shader(blur_raster.shader_version, blur_mode);
ERR_FAIL_COND(shader.is_null());
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(dest_framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur_raster.pipelines[blur_mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(dest_framebuffer)));
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_rd_texture), 0);
@@ -826,7 +826,7 @@ void CopyEffects::gaussian_glow_raster(RID p_source_rd_texture, RID p_half_textu
ERR_FAIL_COND(shader.is_null());
//HORIZONTAL
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(half_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(half_framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur_raster.pipelines[blur_mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(half_framebuffer)));
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_rd_texture), 0);
if (p_auto_exposure.is_valid() && p_first_pass) {
@@ -846,7 +846,7 @@ void CopyEffects::gaussian_glow_raster(RID p_source_rd_texture, RID p_half_textu
ERR_FAIL_COND(shader.is_null());
//VERTICAL
- draw_list = RD::get_singleton()->draw_list_begin(dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
+ draw_list = RD::get_singleton()->draw_list_begin(dest_framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur_raster.pipelines[blur_mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(dest_framebuffer)));
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_half_texture), 0);
@@ -916,7 +916,7 @@ void CopyEffects::make_mipmap_raster(RID p_source_rd_texture, RID p_dest_texture
RID shader = blur_raster.shader.version_get_shader(blur_raster.shader_version, mode);
ERR_FAIL_COND(shader.is_null());
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(dest_framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur_raster.pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(dest_framebuffer)));
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_rd_texture), 0);
RD::get_singleton()->draw_list_bind_index_array(draw_list, material_storage->get_quad_index_array());
@@ -982,7 +982,7 @@ void CopyEffects::set_color_raster(RID p_dest_texture, const Color &p_color, con
RID shader = copy_to_fb.shader.version_get_shader(copy_to_fb.shader_version, mode);
ERR_FAIL_COND(shader.is_null());
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, p_region);
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(dest_framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, p_region);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, copy_to_fb.pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(dest_framebuffer)));
RD::get_singleton()->draw_list_bind_index_array(draw_list, material_storage->get_quad_index_array());
RD::get_singleton()->draw_list_set_push_constant(draw_list, &copy_to_fb.push_constant, sizeof(CopyToFbPushConstant));
@@ -990,7 +990,7 @@ void CopyEffects::set_color_raster(RID p_dest_texture, const Color &p_color, con
RD::get_singleton()->draw_list_end();
}
-void CopyEffects::copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dst_framebuffer, const Rect2 &p_rect, const Vector2 &p_dst_size, float p_z_near, float p_z_far, bool p_dp_flip, BitField<RD::BarrierMask> p_post_barrier) {
+void CopyEffects::copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dst_framebuffer, const Rect2 &p_rect, const Vector2 &p_dst_size, float p_z_near, float p_z_far, bool p_dp_flip) {
UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
ERR_FAIL_NULL(uniform_set_cache);
MaterialStorage *material_storage = MaterialStorage::get_singleton();
@@ -1015,14 +1015,14 @@ void CopyEffects::copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dst_framebuf
RID shader = cube_to_dp.shader.version_get_shader(cube_to_dp.shader_version, 0);
ERR_FAIL_COND(shader.is_null());
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dst_framebuffer, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ);
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dst_framebuffer, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, cube_to_dp.pipeline.get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dst_framebuffer)));
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_rd_texture), 0);
RD::get_singleton()->draw_list_bind_index_array(draw_list, material_storage->get_quad_index_array());
RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(CopyToDPPushConstant));
RD::get_singleton()->draw_list_draw(draw_list, true);
- RD::get_singleton()->draw_list_end(p_post_barrier);
+ RD::get_singleton()->draw_list_end();
}
void CopyEffects::cubemap_downsample(RID p_source_cubemap, RID p_dest_cubemap, const Size2i &p_size) {
@@ -1080,7 +1080,7 @@ void CopyEffects::cubemap_downsample_raster(RID p_source_cubemap, RID p_dest_fra
RID shader = cubemap_downsampler.raster_shader.version_get_shader(cubemap_downsampler.shader_version, 0);
ERR_FAIL_COND(shader.is_null());
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, cubemap_downsampler.raster_pipeline.get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer)));
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_cubemap), 0);
@@ -1159,7 +1159,7 @@ void CopyEffects::cubemap_filter_raster(RID p_source_cubemap, RID p_dest_framebu
RID shader = filter.raster_shader.version_get_shader(filter.shader_version, mode);
ERR_FAIL_COND(shader.is_null());
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, filter.raster_pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer)));
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_cubemap), 0);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, filter.uniform_set, 1);
@@ -1237,7 +1237,7 @@ void CopyEffects::cubemap_roughness_raster(RID p_source_rd_texture, RID p_dest_f
RID shader = roughness.raster_shader.version_get_shader(roughness.shader_version, 0);
ERR_FAIL_COND(shader.is_null());
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, roughness.raster_pipeline.get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer)));
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_rd_texture), 0);
@@ -1257,7 +1257,7 @@ void CopyEffects::merge_specular(RID p_dest_framebuffer, RID p_specular, RID p_b
RD::get_singleton()->draw_command_begin_label("Merge specular");
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, Vector<Color>());
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, Vector<Color>());
int mode;
if (p_reflection.is_valid()) {
diff --git a/servers/rendering/renderer_rd/effects/copy_effects.h b/servers/rendering/renderer_rd/effects/copy_effects.h
index 60272a2eab..d18971a676 100644
--- a/servers/rendering/renderer_rd/effects/copy_effects.h
+++ b/servers/rendering/renderer_rd/effects/copy_effects.h
@@ -345,7 +345,7 @@ public:
void set_color(RID p_dest_texture, const Color &p_color, const Rect2i &p_region, bool p_8bit_dst = false);
void set_color_raster(RID p_dest_texture, const Color &p_color, const Rect2i &p_region);
- void copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dst_framebuffer, const Rect2 &p_rect, const Vector2 &p_dst_size, float p_z_near, float p_z_far, bool p_dp_flip, BitField<RD::BarrierMask> p_post_barrier = RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_TRANSFER);
+ void copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dst_framebuffer, const Rect2 &p_rect, const Vector2 &p_dst_size, float p_z_near, float p_z_far, bool p_dp_flip);
void cubemap_downsample(RID p_source_cubemap, RID p_dest_cubemap, const Size2i &p_size);
void cubemap_downsample_raster(RID p_source_cubemap, RID p_dest_framebuffer, uint32_t p_face_id, const Size2i &p_size);
void cubemap_filter(RID p_source_cubemap, Vector<RID> p_dest_cubemap, bool p_use_array);
diff --git a/servers/rendering/renderer_rd/effects/debug_effects.cpp b/servers/rendering/renderer_rd/effects/debug_effects.cpp
index 3033d42375..a57a65fd5a 100644
--- a/servers/rendering/renderer_rd/effects/debug_effects.cpp
+++ b/servers/rendering/renderer_rd/effects/debug_effects.cpp
@@ -282,7 +282,7 @@ void DebugEffects::draw_shadow_frustum(RID p_light, const Projection &p_cam_proj
// And draw our frustum.
RD::FramebufferFormatID fb_format_id = RD::get_singleton()->framebuffer_get_format(p_dest_fb);
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_fb, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, rect);
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_fb, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, rect);
RID pipeline = shadow_frustum.pipelines[SFP_TRANSPARENT].get_render_pipeline(frustum.vertex_format, fb_format_id);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, pipeline);
@@ -326,7 +326,7 @@ void DebugEffects::draw_shadow_frustum(RID p_light, const Projection &p_cam_proj
rect.size.x *= atlas_rect_norm.size.x;
rect.size.y *= atlas_rect_norm.size.y;
- draw_list = RD::get_singleton()->draw_list_begin(p_dest_fb, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, rect);
+ draw_list = RD::get_singleton()->draw_list_begin(p_dest_fb, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, rect);
pipeline = shadow_frustum.pipelines[SFP_TRANSPARENT].get_render_pipeline(frustum.vertex_format, fb_format_id);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, pipeline);
@@ -351,7 +351,7 @@ void DebugEffects::draw_motion_vectors(RID p_velocity, RID p_depth, RID p_dest_f
RD::Uniform u_source_velocity(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_velocity }));
RD::Uniform u_source_depth(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 1, Vector<RID>({ default_sampler, p_depth }));
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_fb, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD);
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_fb, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, motion_vectors.pipeline.get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_fb), false, RD::get_singleton()->draw_list_get_current_pass()));
Projection reprojection = p_previous_projection.flipped_y() * p_previous_transform.affine_inverse() * p_current_transform * p_current_projection.flipped_y().inverse();
diff --git a/servers/rendering/renderer_rd/effects/fsr.cpp b/servers/rendering/renderer_rd/effects/fsr.cpp
index 0c51adf9ee..5599a5a162 100644
--- a/servers/rendering/renderer_rd/effects/fsr.cpp
+++ b/servers/rendering/renderer_rd/effects/fsr.cpp
@@ -124,5 +124,5 @@ void FSR::fsr_upscale(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_source_r
RD::get_singleton()->compute_list_dispatch(compute_list, dispatch_x, dispatch_y, 1);
- RD::get_singleton()->compute_list_end(compute_list);
+ RD::get_singleton()->compute_list_end();
}
diff --git a/servers/rendering/renderer_rd/effects/fsr2.cpp b/servers/rendering/renderer_rd/effects/fsr2.cpp
index 0c38989304..bebbf51d51 100644
--- a/servers/rendering/renderer_rd/effects/fsr2.cpp
+++ b/servers/rendering/renderer_rd/effects/fsr2.cpp
@@ -377,10 +377,7 @@ static FfxErrorCode execute_gpu_job_copy_rd(FSR2Context::Scratch &p_scratch, con
ERR_FAIL_COND_V(dst_desc.type == FFX_RESOURCE_TYPE_BUFFER, FFX_ERROR_INVALID_ARGUMENT);
for (uint32_t mip_level = 0; mip_level < src_desc.mipCount; mip_level++) {
- // Only push the barriers on the last copy.
- // FIXME: This could be optimized if RenderingDevice was able to copy multiple mip levels in a single command.
- BitField<RD::BarrierMask> post_barrier = (mip_level == (src_desc.mipCount - 1)) ? RD::BARRIER_MASK_ALL_BARRIERS : RD::BARRIER_MASK_NO_BARRIER;
- RD::get_singleton()->texture_copy(src, dst, Vector3(0, 0, 0), Vector3(0, 0, 0), Vector3(src_desc.width, src_desc.height, src_desc.depth), mip_level, mip_level, 0, 0, post_barrier);
+ RD::get_singleton()->texture_copy(src, dst, Vector3(0, 0, 0), Vector3(0, 0, 0), Vector3(src_desc.width, src_desc.height, src_desc.depth), mip_level, mip_level, 0, 0);
}
return FFX_OK;
@@ -435,8 +432,7 @@ static FfxErrorCode execute_gpu_job_compute_rd(FSR2Context::Scratch &p_scratch,
RID buffer_rid = p_scratch.ubo_ring_buffer[p_scratch.ubo_ring_buffer_index];
p_scratch.ubo_ring_buffer_index = (p_scratch.ubo_ring_buffer_index + 1) % FSR2_UBO_RING_BUFFER_SIZE;
- BitField<RD::BarrierMask> post_barrier = (i == (p_job.pipeline.constCount - 1)) ? RD::BARRIER_MASK_ALL_BARRIERS : RD::BARRIER_MASK_NO_BARRIER;
- RD::get_singleton()->buffer_update(buffer_rid, 0, p_job.cbs[i].uint32Size * sizeof(uint32_t), p_job.cbs[i].data, post_barrier);
+ RD::get_singleton()->buffer_update(buffer_rid, 0, p_job.cbs[i].uint32Size * sizeof(uint32_t), p_job.cbs[i].data);
RD::Uniform buffer_uniform(RD::UNIFORM_TYPE_UNIFORM_BUFFER, p_job.pipeline.cbResourceBindings[i].slotIndex, buffer_rid);
compute_uniforms.push_back(buffer_uniform);
@@ -566,7 +562,6 @@ FSR2Effect::FSR2Effect() {
FfxResourceBinding{ 2, 0, L"r_dilatedDepth" },
FfxResourceBinding{ 3, 0, L"r_reactive_mask" },
FfxResourceBinding{ 4, 0, L"r_transparency_and_composition_mask" },
- FfxResourceBinding{ 5, 0, L"r_prepared_input_color" },
FfxResourceBinding{ 6, 0, L"r_previous_dilated_motion_vectors" },
FfxResourceBinding{ 7, 0, L"r_input_motion_vectors" },
FfxResourceBinding{ 8, 0, L"r_input_color_jittered" },
diff --git a/servers/rendering/renderer_rd/effects/luminance.cpp b/servers/rendering/renderer_rd/effects/luminance.cpp
index 3aa5f5706e..61b2248b5c 100644
--- a/servers/rendering/renderer_rd/effects/luminance.cpp
+++ b/servers/rendering/renderer_rd/effects/luminance.cpp
@@ -184,7 +184,7 @@ void Luminance::luminance_reduction(RID p_source_texture, const Size2i p_source_
RD::Uniform u_source_texture(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, i == 0 ? p_source_texture : p_luminance_buffers->reduce[i - 1] }));
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, luminance_reduce_raster.pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(framebuffer)));
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_texture), 0);
if (final) {
diff --git a/servers/rendering/renderer_rd/effects/resolve.cpp b/servers/rendering/renderer_rd/effects/resolve.cpp
index 18671d06e1..feb0e6ed1e 100644
--- a/servers/rendering/renderer_rd/effects/resolve.cpp
+++ b/servers/rendering/renderer_rd/effects/resolve.cpp
@@ -54,7 +54,7 @@ Resolve::~Resolve() {
resolve.shader.version_free(resolve.shader_version);
}
-void Resolve::resolve_gi(RID p_source_depth, RID p_source_normal_roughness, RID p_source_voxel_gi, RID p_dest_depth, RID p_dest_normal_roughness, RID p_dest_voxel_gi, Vector2i p_screen_size, int p_samples, uint32_t p_barrier) {
+void Resolve::resolve_gi(RID p_source_depth, RID p_source_normal_roughness, RID p_source_voxel_gi, RID p_dest_depth, RID p_dest_normal_roughness, RID p_dest_voxel_gi, Vector2i p_screen_size, int p_samples) {
UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
ERR_FAIL_NULL(uniform_set_cache);
MaterialStorage *material_storage = MaterialStorage::get_singleton();
@@ -93,10 +93,10 @@ void Resolve::resolve_gi(RID p_source_depth, RID p_source_normal_roughness, RID
RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_screen_size.x, p_screen_size.y, 1);
- RD::get_singleton()->compute_list_end(p_barrier);
+ RD::get_singleton()->compute_list_end();
}
-void Resolve::resolve_depth(RID p_source_depth, RID p_dest_depth, Vector2i p_screen_size, int p_samples, uint32_t p_barrier) {
+void Resolve::resolve_depth(RID p_source_depth, RID p_dest_depth, Vector2i p_screen_size, int p_samples) {
UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
ERR_FAIL_NULL(uniform_set_cache);
MaterialStorage *material_storage = MaterialStorage::get_singleton();
@@ -126,5 +126,5 @@ void Resolve::resolve_depth(RID p_source_depth, RID p_dest_depth, Vector2i p_scr
RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_screen_size.x, p_screen_size.y, 1);
- RD::get_singleton()->compute_list_end(p_barrier);
+ RD::get_singleton()->compute_list_end();
}
diff --git a/servers/rendering/renderer_rd/effects/resolve.h b/servers/rendering/renderer_rd/effects/resolve.h
index fcc1021904..14477f90e4 100644
--- a/servers/rendering/renderer_rd/effects/resolve.h
+++ b/servers/rendering/renderer_rd/effects/resolve.h
@@ -65,8 +65,8 @@ public:
Resolve();
~Resolve();
- void resolve_gi(RID p_source_depth, RID p_source_normal_roughness, RID p_source_voxel_gi, RID p_dest_depth, RID p_dest_normal_roughness, RID p_dest_voxel_gi, Vector2i p_screen_size, int p_samples, uint32_t p_barrier = RD::BARRIER_MASK_ALL_BARRIERS);
- void resolve_depth(RID p_source_depth, RID p_dest_depth, Vector2i p_screen_size, int p_samples, uint32_t p_barrier = RD::BARRIER_MASK_ALL_BARRIERS);
+ void resolve_gi(RID p_source_depth, RID p_source_normal_roughness, RID p_source_voxel_gi, RID p_dest_depth, RID p_dest_normal_roughness, RID p_dest_voxel_gi, Vector2i p_screen_size, int p_samples);
+ void resolve_depth(RID p_source_depth, RID p_dest_depth, Vector2i p_screen_size, int p_samples);
};
} // namespace RendererRD
diff --git a/servers/rendering/renderer_rd/effects/ss_effects.cpp b/servers/rendering/renderer_rd/effects/ss_effects.cpp
index 628edc0127..46fb0a75d6 100644
--- a/servers/rendering/renderer_rd/effects/ss_effects.cpp
+++ b/servers/rendering/renderer_rd/effects/ss_effects.cpp
@@ -525,7 +525,7 @@ void SSEffects::downsample_depth(Ref<RenderSceneBuffersRD> p_render_buffers, uin
RD::get_singleton()->compute_list_add_barrier(compute_list);
RD::get_singleton()->draw_command_end_label();
- RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_COMPUTE);
+ RD::get_singleton()->compute_list_end();
ss_effects.used_full_mips_last_frame = use_full_mips;
ss_effects.used_half_size_last_frame = use_half_size;
@@ -950,10 +950,10 @@ void SSEffects::screen_space_indirect_lighting(Ref<RenderSceneBuffersRD> p_rende
RD::get_singleton()->draw_command_end_label(); // SSIL
- RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_TRANSFER); // Zeroing importance_map_load_counter depends on us.
+ RD::get_singleton()->compute_list_end();
int zero[1] = { 0 };
- RD::get_singleton()->buffer_update(ssil.importance_map_load_counter, 0, sizeof(uint32_t), &zero, 0); //no barrier
+ RD::get_singleton()->buffer_update(ssil.importance_map_load_counter, 0, sizeof(uint32_t), &zero);
}
/* SSAO */
@@ -1332,10 +1332,10 @@ void SSEffects::generate_ssao(Ref<RenderSceneBuffersRD> p_render_buffers, SSAORe
RD::get_singleton()->draw_command_end_label(); // Interleave
}
RD::get_singleton()->draw_command_end_label(); //SSAO
- RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_TRANSFER); // Zeroing importance_map_load_counter depends on us.
+ RD::get_singleton()->compute_list_end();
int zero[1] = { 0 };
- RD::get_singleton()->buffer_update(ssao.importance_map_load_counter, 0, sizeof(uint32_t), &zero, 0); //no barrier
+ RD::get_singleton()->buffer_update(ssao.importance_map_load_counter, 0, sizeof(uint32_t), &zero);
}
/* Screen Space Reflection */
@@ -1394,7 +1394,7 @@ void SSEffects::screen_space_reflection(Ref<RenderSceneBuffersRD> p_render_buffe
scene_data.eye_offset[v][3] = 0.0;
}
- RD::get_singleton()->buffer_update(ssr.ubo, 0, sizeof(ScreenSpaceReflectionSceneData), &scene_data, RD::BARRIER_MASK_COMPUTE);
+ RD::get_singleton()->buffer_update(ssr.ubo, 0, sizeof(ScreenSpaceReflectionSceneData), &scene_data);
}
uint32_t pipeline_specialization = 0;
diff --git a/servers/rendering/renderer_rd/effects/tone_mapper.cpp b/servers/rendering/renderer_rd/effects/tone_mapper.cpp
index 48c6511408..ee0b6adb4d 100644
--- a/servers/rendering/renderer_rd/effects/tone_mapper.cpp
+++ b/servers/rendering/renderer_rd/effects/tone_mapper.cpp
@@ -166,7 +166,7 @@ void ToneMapper::tonemapper(RID p_source_color, RID p_dst_framebuffer, const Ton
RID shader = tonemap.shader.version_get_shader(tonemap.shader_version, mode);
ERR_FAIL_COND(shader.is_null());
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dst_framebuffer, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD);
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dst_framebuffer, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, tonemap.pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dst_framebuffer), false, RD::get_singleton()->draw_list_get_current_pass()));
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_color), 0);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 1, u_exposure_texture), 1);
diff --git a/servers/rendering/renderer_rd/effects/vrs.cpp b/servers/rendering/renderer_rd/effects/vrs.cpp
index 63c99facdd..41a6b2d622 100644
--- a/servers/rendering/renderer_rd/effects/vrs.cpp
+++ b/servers/rendering/renderer_rd/effects/vrs.cpp
@@ -82,7 +82,7 @@ void VRS::copy_vrs(RID p_source_rd_texture, RID p_dest_framebuffer, bool p_multi
RID shader = vrs_shader.shader.version_get_shader(vrs_shader.shader_version, mode);
ERR_FAIL_COND(shader.is_null());
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD, Vector<Color>());
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, Vector<Color>());
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, vrs_shader.pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer)));
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_rd_texture), 0);
// RD::get_singleton()->draw_list_set_push_constant(draw_list, &vrs_shader.push_constant, sizeof(VRSPushConstant));
diff --git a/servers/rendering/renderer_rd/environment/fog.cpp b/servers/rendering/renderer_rd/environment/fog.cpp
index 2befb194f7..78ab6f3650 100644
--- a/servers/rendering/renderer_rd/environment/fog.cpp
+++ b/servers/rendering/renderer_rd/environment/fog.cpp
@@ -570,7 +570,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
RendererRD::MaterialStorage::store_transform(to_prev_cam_view, params.to_prev_view);
RendererRD::MaterialStorage::store_transform(p_cam_transform, params.transform);
- RD::get_singleton()->buffer_update(volumetric_fog.volume_ubo, 0, sizeof(VolumetricFogShader::VolumeUBO), &params, RD::BARRIER_MASK_COMPUTE);
+ RD::get_singleton()->buffer_update(volumetric_fog.volume_ubo, 0, sizeof(VolumetricFogShader::VolumeUBO), &params);
if (fog->fog_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(fog->fog_uniform_set)) {
Vector<RD::Uniform> uniforms;
@@ -1086,7 +1086,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
RD::get_singleton()->draw_command_begin_label("Render Volumetric Fog");
RENDER_TIMESTAMP("Render Fog");
- RD::get_singleton()->buffer_update(volumetric_fog.params_ubo, 0, sizeof(VolumetricFogShader::ParamsUBO), &params, RD::BARRIER_MASK_COMPUTE);
+ RD::get_singleton()->buffer_update(volumetric_fog.params_ubo, 0, sizeof(VolumetricFogShader::ParamsUBO), &params);
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
@@ -1140,7 +1140,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, fog->gi_dependent_sets.process_uniform_set, 0);
RD::get_singleton()->compute_list_dispatch_threads(compute_list, fog->width, fog->height, 1);
- RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_RASTER);
+ RD::get_singleton()->compute_list_end();
RENDER_TIMESTAMP("< Volumetric Fog");
RD::get_singleton()->draw_command_end_label();
diff --git a/servers/rendering/renderer_rd/environment/gi.cpp b/servers/rendering/renderer_rd/environment/gi.cpp
index d968736037..6da828df45 100644
--- a/servers/rendering/renderer_rd/environment/gi.cpp
+++ b/servers/rendering/renderer_rd/environment/gi.cpp
@@ -583,7 +583,8 @@ void GI::SDFGI::create(RID p_env, const Vector3 &p_world_position, uint32_t p_re
/* Buffers */
cascade.solid_cell_buffer = RD::get_singleton()->storage_buffer_create(sizeof(SDFGI::Cascade::SolidCell) * solid_cell_count);
- cascade.solid_cell_dispatch_buffer = RD::get_singleton()->storage_buffer_create(sizeof(uint32_t) * 4, Vector<uint8_t>(), RD::STORAGE_BUFFER_USAGE_DISPATCH_INDIRECT);
+ cascade.solid_cell_dispatch_buffer_storage = RD::get_singleton()->storage_buffer_create(sizeof(uint32_t) * 4, Vector<uint8_t>());
+ cascade.solid_cell_dispatch_buffer_call = RD::get_singleton()->storage_buffer_create(sizeof(uint32_t) * 4, Vector<uint8_t>(), RD::STORAGE_BUFFER_USAGE_DISPATCH_INDIRECT);
cascade.lights_buffer = RD::get_singleton()->storage_buffer_create(sizeof(SDFGIShader::Light) * MAX(SDFGI::MAX_STATIC_LIGHTS, SDFGI::MAX_DYNAMIC_LIGHTS));
{
Vector<RD::Uniform> uniforms;
@@ -650,7 +651,7 @@ void GI::SDFGI::create(RID p_env, const Vector3 &p_world_position, uint32_t p_re
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.binding = 10;
- u.append_id(cascade.solid_cell_dispatch_buffer);
+ u.append_id(cascade.solid_cell_dispatch_buffer_storage);
uniforms.push_back(u);
}
{
@@ -698,7 +699,7 @@ void GI::SDFGI::create(RID p_env, const Vector3 &p_world_position, uint32_t p_re
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.binding = 5;
- u.append_id(cascade.solid_cell_dispatch_buffer);
+ u.append_id(cascade.solid_cell_dispatch_buffer_storage);
uniforms.push_back(u);
}
{
@@ -761,7 +762,7 @@ void GI::SDFGI::create(RID p_env, const Vector3 &p_world_position, uint32_t p_re
RD::Uniform u;
u.binding = 3;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.append_id(cascade.solid_cell_dispatch_buffer);
+ u.append_id(cascade.solid_cell_dispatch_buffer_storage);
uniforms.push_back(u);
}
{
@@ -1129,7 +1130,8 @@ GI::SDFGI::~SDFGI() {
RD::get_singleton()->free(c.light_aniso_0_tex);
RD::get_singleton()->free(c.light_aniso_1_tex);
RD::get_singleton()->free(c.sdf_tex);
- RD::get_singleton()->free(c.solid_cell_dispatch_buffer);
+ RD::get_singleton()->free(c.solid_cell_dispatch_buffer_storage);
+ RD::get_singleton()->free(c.solid_cell_dispatch_buffer_call);
RD::get_singleton()->free(c.solid_cell_buffer);
RD::get_singleton()->free(c.lightprobe_history_tex);
RD::get_singleton()->free(c.lightprobe_average_tex);
@@ -1238,6 +1240,10 @@ void GI::SDFGI::update(RID p_env, const Vector3 &p_world_position) {
void GI::SDFGI::update_light() {
RD::get_singleton()->draw_command_begin_label("SDFGI Update dynamic Light");
+ for (uint32_t i = 0; i < cascades.size(); i++) {
+ RD::get_singleton()->buffer_copy(cascades[i].solid_cell_dispatch_buffer_storage, cascades[i].solid_cell_dispatch_buffer_call, 0, 0, sizeof(uint32_t) * 4);
+ }
+
/* Update dynamic light */
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
@@ -1276,9 +1282,9 @@ void GI::SDFGI::update_light() {
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, cascade.sdf_direct_light_dynamic_uniform_set, 0);
RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDFGIShader::DirectLightPushConstant));
- RD::get_singleton()->compute_list_dispatch_indirect(compute_list, cascade.solid_cell_dispatch_buffer, 0);
+ RD::get_singleton()->compute_list_dispatch_indirect(compute_list, cascade.solid_cell_dispatch_buffer_call, 0);
}
- RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_COMPUTE);
+ RD::get_singleton()->compute_list_end();
RD::get_singleton()->draw_command_end_label();
}
@@ -1351,7 +1357,7 @@ void GI::SDFGI::update_probes(RID p_env, SkyRD::Sky *p_sky) {
render_pass++;
- RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(true);
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.integrate_pipeline[SDFGIShader::INTEGRATE_MODE_PROCESS]);
int32_t probe_divisor = cascade_size / SDFGI::PROBE_DIVISOR;
@@ -1368,14 +1374,11 @@ void GI::SDFGI::update_probes(RID p_env, SkyRD::Sky *p_sky) {
RD::get_singleton()->compute_list_dispatch_threads(compute_list, probe_axis_count * probe_axis_count, probe_axis_count, 1);
}
- //end later after raster to avoid barriering on layout changes
- //RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_NO_BARRIER);
-
+ RD::get_singleton()->compute_list_end();
RD::get_singleton()->draw_command_end_label();
}
void GI::SDFGI::store_probes() {
- RD::get_singleton()->barrier(RD::BARRIER_MASK_COMPUTE, RD::BARRIER_MASK_COMPUTE);
RD::get_singleton()->draw_command_begin_label("SDFGI Store Probes");
SDFGIShader::IntegratePushConstant push_constant;
@@ -1414,7 +1417,7 @@ void GI::SDFGI::store_probes() {
RD::get_singleton()->compute_list_dispatch_threads(compute_list, probe_axis_count * probe_axis_count * SDFGI::LIGHTPROBE_OCT_SIZE, probe_axis_count * SDFGI::LIGHTPROBE_OCT_SIZE, 1);
}
- RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_COMPUTE);
+ RD::get_singleton()->compute_list_end();
RD::get_singleton()->draw_command_end_label();
}
@@ -1493,7 +1496,7 @@ void GI::SDFGI::update_cascades() {
cascade_data[i].pad = 0;
}
- RD::get_singleton()->buffer_update(cascades_ubo, 0, sizeof(SDFGI::Cascade::UBO) * SDFGI::MAX_CASCADES, cascade_data, RD::BARRIER_MASK_COMPUTE);
+ RD::get_singleton()->buffer_update(cascades_ubo, 0, sizeof(SDFGI::Cascade::UBO) * SDFGI::MAX_CASCADES, cascade_data);
}
void GI::SDFGI::debug_draw(uint32_t p_view_count, const Projection *p_projections, const Transform3D &p_transform, int p_width, int p_height, RID p_render_target, RID p_texture, const Vector<RID> &p_texture_views) {
@@ -1636,7 +1639,7 @@ void GI::SDFGI::debug_draw(uint32_t p_view_count, const Projection *p_projection
copy_effects->copy_to_fb_rect(p_texture, texture_storage->render_target_get_rd_framebuffer(p_render_target), Rect2i(Point2i(), rtsize), true, false, false, false, RID(), p_view_count > 1);
}
-void GI::SDFGI::debug_probes(RID p_framebuffer, const uint32_t p_view_count, const Projection *p_camera_with_transforms, bool p_will_continue_color, bool p_will_continue_depth) {
+void GI::SDFGI::debug_probes(RID p_framebuffer, const uint32_t p_view_count, const Projection *p_camera_with_transforms) {
RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton();
// setup scene data
@@ -1651,7 +1654,7 @@ void GI::SDFGI::debug_probes(RID p_framebuffer, const uint32_t p_view_count, con
RendererRD::MaterialStorage::store_camera(p_camera_with_transforms[v], scene_data.projection[v]);
}
- RD::get_singleton()->buffer_update(debug_probes_scene_data_ubo, 0, sizeof(SDFGIShader::DebugProbesSceneData), &scene_data, RD::BARRIER_MASK_RASTER);
+ RD::get_singleton()->buffer_update(debug_probes_scene_data_ubo, 0, sizeof(SDFGIShader::DebugProbesSceneData), &scene_data);
}
// setup push constant
@@ -1718,7 +1721,7 @@ void GI::SDFGI::debug_probes(RID p_framebuffer, const uint32_t p_view_count, con
SDFGIShader::ProbeDebugMode mode = p_view_count > 1 ? SDFGIShader::PROBE_DEBUG_PROBES_MULTIVIEW : SDFGIShader::PROBE_DEBUG_PROBES;
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CONTINUE, p_will_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, p_will_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ);
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE);
RD::get_singleton()->draw_command_begin_label("Debug SDFGI");
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, gi->sdfgi_shader.debug_probes_pipeline[mode].get_render_pipeline(RD::INVALID_FORMAT_ID, RD::get_singleton()->framebuffer_get_format(p_framebuffer)));
@@ -1861,7 +1864,7 @@ void GI::SDFGI::pre_process_gi(const Transform3D &p_transform, RenderDataRD *p_r
}
}
- RD::get_singleton()->buffer_update(gi->sdfgi_ubo, 0, sizeof(SDFGIData), &sdfgi_data, RD::BARRIER_MASK_COMPUTE);
+ RD::get_singleton()->buffer_update(gi->sdfgi_ubo, 0, sizeof(SDFGIData), &sdfgi_data);
/* Update dynamic lights in SDFGI cascades */
@@ -1983,7 +1986,7 @@ void GI::SDFGI::pre_process_gi(const Transform3D &p_transform, RenderDataRD *p_r
}
if (idx > 0) {
- RD::get_singleton()->buffer_update(cascade.lights_buffer, 0, idx * sizeof(SDFGIShader::Light), lights, RD::BARRIER_MASK_COMPUTE);
+ RD::get_singleton()->buffer_update(cascade.lights_buffer, 0, idx * sizeof(SDFGIShader::Light), lights);
}
cascade_dynamic_light_count[i] = idx;
@@ -2046,6 +2049,8 @@ void GI::SDFGI::render_region(Ref<RenderSceneBuffersRD> p_render_buffers, int p_
push_constant.cascade = cascade;
if (cascades[cascade].dirty_regions != SDFGI::Cascade::DIRTY_ALL) {
+ RD::get_singleton()->buffer_copy(cascades[cascade].solid_cell_dispatch_buffer_storage, cascades[cascade].solid_cell_dispatch_buffer_call, 0, 0, sizeof(uint32_t) * 4);
+
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
//must pre scroll existing data because not all is dirty
@@ -2053,7 +2058,7 @@ void GI::SDFGI::render_region(Ref<RenderSceneBuffersRD> p_render_buffers, int p_
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, cascades[cascade].scroll_uniform_set, 0);
RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDFGIShader::PreprocessPushConstant));
- RD::get_singleton()->compute_list_dispatch_indirect(compute_list, cascades[cascade].solid_cell_dispatch_buffer, 0);
+ RD::get_singleton()->compute_list_dispatch_indirect(compute_list, cascades[cascade].solid_cell_dispatch_buffer_call, 0);
// no barrier do all together
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.preprocess_pipeline[SDFGIShader::PRE_PROCESS_SCROLL_OCCLUSION]);
@@ -2142,7 +2147,7 @@ void GI::SDFGI::render_region(Ref<RenderSceneBuffersRD> p_render_buffers, int p_
//clear dispatch indirect data
uint32_t dispatch_indirct_data[4] = { 0, 0, 0, 0 };
- RD::get_singleton()->buffer_update(cascades[cascade].solid_cell_dispatch_buffer, 0, sizeof(uint32_t) * 4, dispatch_indirct_data);
+ RD::get_singleton()->buffer_update(cascades[cascade].solid_cell_dispatch_buffer_storage, 0, sizeof(uint32_t) * 4, dispatch_indirct_data);
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
@@ -2451,6 +2456,15 @@ void GI::SDFGI::render_static_lights(RenderDataRD *p_render_data, Ref<RenderScen
}
}
+ for (uint32_t i = 0; i < p_cascade_count; i++) {
+ ERR_CONTINUE(p_cascade_indices[i] >= cascades.size());
+
+ SDFGI::Cascade &cc = cascades[p_cascade_indices[i]];
+ if (light_count[i] > 0) {
+ RD::get_singleton()->buffer_copy(cc.solid_cell_dispatch_buffer_storage, cc.solid_cell_dispatch_buffer_call, 0, 0, sizeof(uint32_t) * 4);
+ }
+ }
+
/* Static Lights */
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
@@ -2482,7 +2496,7 @@ void GI::SDFGI::render_static_lights(RenderDataRD *p_render_data, Ref<RenderScen
if (dl_push_constant.light_count > 0) {
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, cc.sdf_direct_light_static_uniform_set, 0);
RD::get_singleton()->compute_list_set_push_constant(compute_list, &dl_push_constant, sizeof(SDFGIShader::DirectLightPushConstant));
- RD::get_singleton()->compute_list_dispatch_indirect(compute_list, cc.solid_cell_dispatch_buffer, 0);
+ RD::get_singleton()->compute_list_dispatch_indirect(compute_list, cc.solid_cell_dispatch_buffer_call, 0);
}
}
@@ -3716,7 +3730,7 @@ void GI::setup_voxel_gi_instances(RenderDataRD *p_render_data, Ref<RenderSceneBu
if (p_voxel_gi_instances.size() > 0) {
RD::get_singleton()->draw_command_begin_label("VoxelGIs Setup");
- RD::get_singleton()->buffer_update(voxel_gi_buffer, 0, sizeof(VoxelGIData) * MIN((uint64_t)MAX_VOXEL_GI_INSTANCES, p_voxel_gi_instances.size()), voxel_gi_data, RD::BARRIER_MASK_COMPUTE);
+ RD::get_singleton()->buffer_update(voxel_gi_buffer, 0, sizeof(VoxelGIData) * MIN((uint64_t)MAX_VOXEL_GI_INSTANCES, p_voxel_gi_instances.size()), voxel_gi_data);
RD::get_singleton()->draw_command_end_label();
}
@@ -3804,11 +3818,11 @@ void GI::process_gi(Ref<RenderSceneBuffersRD> p_render_buffers, const RID *p_nor
scene_data.screen_size[0] = internal_size.x;
scene_data.screen_size[1] = internal_size.y;
- RD::get_singleton()->buffer_update(rbgi->scene_data_ubo, 0, sizeof(SceneData), &scene_data, RD::BARRIER_MASK_COMPUTE);
+ RD::get_singleton()->buffer_update(rbgi->scene_data_ubo, 0, sizeof(SceneData), &scene_data);
}
// Now compute the contents of our buffers.
- RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(true);
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
// Render each eye separately.
// We need to look into whether we can make our compute shader use Multiview but not sure that works or makes a difference..
@@ -4038,8 +4052,7 @@ void GI::process_gi(Ref<RenderSceneBuffersRD> p_render_buffers, const RID *p_nor
}
}
- //do barrier later to allow oeverlap
- //RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_NO_BARRIER); //no barriers, let other compute, raster and transfer happen at the same time
+ RD::get_singleton()->compute_list_end();
RD::get_singleton()->draw_command_end_label();
}
diff --git a/servers/rendering/renderer_rd/environment/gi.h b/servers/rendering/renderer_rd/environment/gi.h
index c46d4cbd25..011493f1f6 100644
--- a/servers/rendering/renderer_rd/environment/gi.h
+++ b/servers/rendering/renderer_rd/environment/gi.h
@@ -584,7 +584,9 @@ public:
uint32_t static_light_aniso;
};
- RID solid_cell_dispatch_buffer; //buffer for indirect compute dispatch
+ // Buffers for indirect compute dispatch.
+ RID solid_cell_dispatch_buffer_storage;
+ RID solid_cell_dispatch_buffer_call;
RID solid_cell_buffer;
RID lightprobe_history_tex;
@@ -686,7 +688,7 @@ public:
void update_cascades();
void debug_draw(uint32_t p_view_count, const Projection *p_projections, const Transform3D &p_transform, int p_width, int p_height, RID p_render_target, RID p_texture, const Vector<RID> &p_texture_views);
- void debug_probes(RID p_framebuffer, const uint32_t p_view_count, const Projection *p_camera_with_transforms, bool p_will_continue_color, bool p_will_continue_depth);
+ void debug_probes(RID p_framebuffer, const uint32_t p_view_count, const Projection *p_camera_with_transforms);
void pre_process_gi(const Transform3D &p_transform, RenderDataRD *p_render_data);
void render_region(Ref<RenderSceneBuffersRD> p_render_buffers, int p_region, const PagedArray<RenderGeometryInstance *> &p_instances, float p_exposure_normalization);
diff --git a/servers/rendering/renderer_rd/environment/sky.cpp b/servers/rendering/renderer_rd/environment/sky.cpp
index ba72ab3b08..41609dc74d 100644
--- a/servers/rendering/renderer_rd/environment/sky.cpp
+++ b/servers/rendering/renderer_rd/environment/sky.cpp
@@ -1307,7 +1307,7 @@ void SkyRD::update_radiance_buffers(Ref<RenderSceneBuffersRD> p_render_buffers,
Basis local_view = Basis::looking_at(view_normals[i], view_up[i]);
RID texture_uniform_set = sky->get_textures(SKY_TEXTURE_SET_CUBEMAP_QUARTER_RES, sky_shader.default_shader_rd, p_render_buffers);
- cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[2].framebuffers[i], RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
+ cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[2].framebuffers[i], RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD);
_render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[2].framebuffers[i], pipeline, material->uniform_set, texture_uniform_set, cm, local_view, p_global_pos, p_luminance_multiplier);
RD::get_singleton()->draw_list_end();
}
@@ -1328,7 +1328,7 @@ void SkyRD::update_radiance_buffers(Ref<RenderSceneBuffersRD> p_render_buffers,
Basis local_view = Basis::looking_at(view_normals[i], view_up[i]);
RID texture_uniform_set = sky->get_textures(SKY_TEXTURE_SET_CUBEMAP_HALF_RES, sky_shader.default_shader_rd, p_render_buffers);
- cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[1].framebuffers[i], RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
+ cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[1].framebuffers[i], RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD);
_render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[1].framebuffers[i], pipeline, material->uniform_set, texture_uniform_set, cm, local_view, p_global_pos, p_luminance_multiplier);
RD::get_singleton()->draw_list_end();
}
@@ -1345,7 +1345,7 @@ void SkyRD::update_radiance_buffers(Ref<RenderSceneBuffersRD> p_render_buffers,
Basis local_view = Basis::looking_at(view_normals[i], view_up[i]);
RID texture_uniform_set = sky->get_textures(SKY_TEXTURE_SET_CUBEMAP, sky_shader.default_shader_rd, p_render_buffers);
- cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[0].framebuffers[i], RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
+ cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[0].framebuffers[i], RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD);
_render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[0].framebuffers[i], pipeline, material->uniform_set, texture_uniform_set, cm, local_view, p_global_pos, p_luminance_multiplier);
RD::get_singleton()->draw_list_end();
}
@@ -1469,7 +1469,7 @@ void SkyRD::update_res_buffers(Ref<RenderSceneBuffersRD> p_render_buffers, RID p
Vector<Color> clear_colors;
clear_colors.push_back(Color(0.0, 0.0, 0.0));
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors);
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors);
_render_sky(draw_list, p_time, framebuffer, pipeline, material->uniform_set, texture_uniform_set, projection, sky_transform, sky_scene_state.cam_transform.origin, p_luminance_multiplier);
RD::get_singleton()->draw_list_end();
}
@@ -1488,7 +1488,7 @@ void SkyRD::update_res_buffers(Ref<RenderSceneBuffersRD> p_render_buffers, RID p
Vector<Color> clear_colors;
clear_colors.push_back(Color(0.0, 0.0, 0.0));
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors);
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors);
_render_sky(draw_list, p_time, framebuffer, pipeline, material->uniform_set, texture_uniform_set, projection, sky_transform, sky_scene_state.cam_transform.origin, p_luminance_multiplier);
RD::get_singleton()->draw_list_end();
}
diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
index 76e814e1ee..0c0062662a 100644
--- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
@@ -576,31 +576,13 @@ void RenderForwardClustered::_render_list(RenderingDevice::DrawListID p_draw_lis
}
}
-void RenderForwardClustered::_render_list_thread_function(uint32_t p_thread, RenderListParameters *p_params) {
- uint32_t render_total = p_params->element_count;
- uint32_t total_threads = WorkerThreadPool::get_singleton()->get_thread_count();
- uint32_t render_from = p_thread * render_total / total_threads;
- uint32_t render_to = (p_thread + 1 == total_threads) ? render_total : ((p_thread + 1) * render_total / total_threads);
- _render_list(thread_draw_lists[p_thread], p_params->framebuffer_format, p_params, render_from, render_to);
-}
-
-void RenderForwardClustered::_render_list_with_threads(RenderListParameters *p_params, RID p_framebuffer, RD::InitialAction p_initial_color_action, RD::FinalAction p_final_color_action, RD::InitialAction p_initial_depth_action, RD::FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const Vector<RID> &p_storage_textures) {
+void RenderForwardClustered::_render_list_with_draw_list(RenderListParameters *p_params, RID p_framebuffer, RD::InitialAction p_initial_color_action, RD::FinalAction p_final_color_action, RD::InitialAction p_initial_depth_action, RD::FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region) {
RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(p_framebuffer);
p_params->framebuffer_format = fb_format;
- if ((uint32_t)p_params->element_count > render_list_thread_threshold && false) { // secondary command buffers need more testing at this time
- //multi threaded
- thread_draw_lists.resize(WorkerThreadPool::get_singleton()->get_thread_count());
- RD::get_singleton()->draw_list_begin_split(p_framebuffer, thread_draw_lists.size(), thread_draw_lists.ptr(), p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, p_region, p_storage_textures);
- WorkerThreadPool::GroupID group_task = WorkerThreadPool::get_singleton()->add_template_group_task(this, &RenderForwardClustered::_render_list_thread_function, p_params, thread_draw_lists.size(), -1, true, SNAME("ForwardClusteredRenderList"));
- WorkerThreadPool::get_singleton()->wait_for_group_task_completion(group_task);
- RD::get_singleton()->draw_list_end(p_params->barrier);
- } else {
- //single threaded
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, p_region, p_storage_textures);
- _render_list(draw_list, fb_format, p_params, 0, p_params->element_count);
- RD::get_singleton()->draw_list_end(p_params->barrier);
- }
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, p_region);
+ _render_list(draw_list, fb_format, p_params, 0, p_params->element_count);
+ RD::get_singleton()->draw_list_end();
}
void RenderForwardClustered::_setup_environment(const RenderDataRD *p_render_data, bool p_no_fog, const Size2i &p_screen_size, bool p_flip_y, const Color &p_default_bg_color, bool p_opaque_render_buffers, bool p_apply_alpha_multiplier, bool p_pancake_shadows, int p_index) {
@@ -683,7 +665,7 @@ void RenderForwardClustered::_setup_environment(const RenderDataRD *p_render_dat
}
}
- RD::get_singleton()->buffer_update(scene_state.implementation_uniform_buffers[p_index], 0, sizeof(SceneState::UBO), &scene_state.ubo, RD::BARRIER_MASK_RASTER);
+ RD::get_singleton()->buffer_update(scene_state.implementation_uniform_buffers[p_index], 0, sizeof(SceneState::UBO), &scene_state.ubo);
}
void RenderForwardClustered::_update_instance_data_buffer(RenderListType p_render_list) {
@@ -696,7 +678,7 @@ void RenderForwardClustered::_update_instance_data_buffer(RenderListType p_rende
scene_state.instance_buffer[p_render_list] = RD::get_singleton()->storage_buffer_create(new_size * sizeof(SceneState::InstanceData));
scene_state.instance_buffer_size[p_render_list] = new_size;
}
- RD::get_singleton()->buffer_update(scene_state.instance_buffer[p_render_list], 0, sizeof(SceneState::InstanceData) * scene_state.instance_data[p_render_list].size(), scene_state.instance_data[p_render_list].ptr(), RD::BARRIER_MASK_RASTER);
+ RD::get_singleton()->buffer_update(scene_state.instance_buffer[p_render_list], 0, sizeof(SceneState::InstanceData) * scene_state.instance_data[p_render_list].size(), scene_state.instance_data[p_render_list].ptr());
}
}
void RenderForwardClustered::_fill_instance_data(RenderListType p_render_list, int *p_render_info, uint32_t p_offset, int32_t p_max_elements, bool p_update_buffer) {
@@ -1097,7 +1079,7 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con
}
if (p_render_list == RENDER_LIST_OPAQUE && lightmap_captures_used) {
- RD::get_singleton()->buffer_update(scene_state.lightmap_capture_buffer, 0, sizeof(LightmapCaptureData) * lightmap_captures_used, scene_state.lightmap_captures, RD::BARRIER_MASK_RASTER);
+ RD::get_singleton()->buffer_update(scene_state.lightmap_capture_buffer, 0, sizeof(LightmapCaptureData) * lightmap_captures_used, scene_state.lightmap_captures);
}
}
@@ -1135,7 +1117,7 @@ void RenderForwardClustered::_setup_lightmaps(const RenderDataRD *p_render_data,
scene_state.lightmaps_used++;
}
if (scene_state.lightmaps_used > 0) {
- RD::get_singleton()->buffer_update(scene_state.lightmap_buffer, 0, sizeof(LightmapData) * scene_state.lightmaps_used, scene_state.lightmaps, RD::BARRIER_MASK_RASTER);
+ RD::get_singleton()->buffer_update(scene_state.lightmap_buffer, 0, sizeof(LightmapData) * scene_state.lightmaps_used, scene_state.lightmaps);
}
}
@@ -1427,7 +1409,7 @@ void RenderForwardClustered::_pre_opaque_render(RenderDataRD *p_render_data, boo
if (p_render_data->directional_shadows.size()) {
//open the pass for directional shadows
light_storage->update_directional_shadow_atlas();
- RD::get_singleton()->draw_list_begin(light_storage->direction_shadow_get_fb(), RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_CONTINUE);
+ RD::get_singleton()->draw_list_begin(light_storage->direction_shadow_get_fb(), RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE);
RD::get_singleton()->draw_list_end();
}
}
@@ -1461,18 +1443,12 @@ void RenderForwardClustered::_pre_opaque_render(RenderDataRD *p_render_data, boo
_render_shadow_process();
}
- //start GI
if (render_gi) {
gi.process_gi(rb, p_normal_roughness_slices, p_voxel_gi_buffer, p_render_data->environment, p_render_data->scene_data->view_count, p_render_data->scene_data->view_projection, p_render_data->scene_data->view_eye_offset, p_render_data->scene_data->cam_transform, *p_render_data->voxel_gi_instances);
}
- //Do shadow rendering (in parallel with GI)
if (render_shadows) {
- _render_shadow_end(RD::BARRIER_MASK_NO_BARRIER);
- }
-
- if (render_gi) {
- RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_NO_BARRIER); //use a later barrier
+ _render_shadow_end();
}
if (rb_data.is_valid() && ss_effects) {
@@ -1496,9 +1472,6 @@ void RenderForwardClustered::_pre_opaque_render(RenderDataRD *p_render_data, boo
}
}
- //full barrier here, we need raster, transfer and compute and it depends from the previous work
- RD::get_singleton()->barrier(RD::BARRIER_MASK_ALL_BARRIERS, RD::BARRIER_MASK_ALL_BARRIERS);
-
if (current_cluster_builder) {
// Note: when rendering stereoscopic (multiview) we are using our combined frustum projection to create
// our cluster data. We use reprojection in the shader to adjust for our left/right eye.
@@ -1814,7 +1787,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
float sky_energy_multiplier = 1.0 / _render_buffers_get_luminance_multiplier();
Color clear_color;
- bool keep_color = false;
+ bool load_color = false;
if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_OVERDRAW) {
clear_color = Color(0, 0, 0, 1); //in overdraw mode, BG should always be black
@@ -1857,10 +1830,10 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
bool convert_to_linear = !RendererRD::TextureStorage::get_singleton()->render_target_is_using_hdr(rb->get_render_target());
copy_effects->copy_to_fb_rect(texture, color_only_framebuffer, Rect2i(), false, false, false, false, RID(), false, false, convert_to_linear);
}
- keep_color = true;
+ load_color = true;
} break;
case RS::ENV_BG_KEEP: {
- keep_color = true;
+ load_color = true;
} break;
case RS::ENV_BG_CAMERA_FEED: {
} break;
@@ -1912,7 +1885,6 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
bool depth_pre_pass = bool(GLOBAL_GET("rendering/driver/depth_prepass/enable")) && depth_framebuffer.is_valid();
bool using_ssao = depth_pre_pass && !is_reflection_probe && p_render_data->environment.is_valid() && environment_get_ssao_enabled(p_render_data->environment);
- bool continue_depth = false;
if (depth_pre_pass) { //depth pre pass
bool needs_pre_resolve = _needs_post_prepass_render(p_render_data, using_sdfgi || using_voxelgi);
@@ -1923,7 +1895,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
}
if (needs_pre_resolve) {
//pre clear the depth framebuffer, as AMD (and maybe others?) use compute for it, and barrier other compute shaders.
- RD::get_singleton()->draw_list_begin(depth_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_CONTINUE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_CONTINUE, depth_pass_clear);
+ RD::get_singleton()->draw_list_begin(depth_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, depth_pass_clear);
RD::get_singleton()->draw_list_end();
//start compute processes here, so they run at the same time as depth pre-pass
_post_prepass_render(p_render_data, using_sdfgi || using_voxelgi);
@@ -1935,21 +1907,14 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
bool finish_depth = using_ssao || using_ssil || using_sdfgi || using_voxelgi;
RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, depth_pass_mode, 0, rb_data.is_null(), p_render_data->directional_light_soft_shadows, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->scene_data->lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, p_render_data->scene_data->view_count);
- _render_list_with_threads(&render_list_params, depth_framebuffer, needs_pre_resolve ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, needs_pre_resolve ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_CLEAR, finish_depth ? RD::FINAL_ACTION_READ : RD::FINAL_ACTION_CONTINUE, needs_pre_resolve ? Vector<Color>() : depth_pass_clear);
+ _render_list_with_draw_list(&render_list_params, depth_framebuffer, needs_pre_resolve ? RD::INITIAL_ACTION_LOAD : RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, needs_pre_resolve ? RD::INITIAL_ACTION_LOAD : RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, needs_pre_resolve ? Vector<Color>() : depth_pass_clear);
RD::get_singleton()->draw_command_end_label();
- if (needs_pre_resolve) {
- _pre_resolve_render(p_render_data, using_sdfgi || using_voxelgi);
- }
-
if (rb->get_msaa_3d() != RS::VIEWPORT_MSAA_DISABLED) {
RENDER_TIMESTAMP("Resolve Depth Pre-Pass (MSAA)");
RD::get_singleton()->draw_command_begin_label("Resolve Depth Pre-Pass (MSAA)");
if (depth_pass_mode == PASS_MODE_DEPTH_NORMAL_ROUGHNESS || depth_pass_mode == PASS_MODE_DEPTH_NORMAL_ROUGHNESS_VOXEL_GI) {
- if (needs_pre_resolve) {
- RD::get_singleton()->barrier(RD::BARRIER_MASK_RASTER, RD::BARRIER_MASK_COMPUTE);
- }
for (uint32_t v = 0; v < rb->get_view_count(); v++) {
resolve_effects->resolve_gi(rb->get_depth_msaa(v), rb_data->get_normal_roughness_msaa(v), using_voxelgi ? rb_data->get_voxelgi_msaa(v) : RID(), rb->get_depth_texture(v), rb_data->get_normal_roughness(v), using_voxelgi ? rb_data->get_voxelgi(v) : RID(), rb->get_internal_size(), texture_multisamples[rb->get_msaa_3d()]);
}
@@ -1960,8 +1925,6 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
}
RD::get_singleton()->draw_command_end_label();
}
-
- continue_depth = !finish_depth;
}
RID normal_roughness_views[RendererSceneRender::MAX_RENDER_VIEWS];
@@ -1990,10 +1953,6 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
{
bool render_motion_pass = !render_list[RENDER_LIST_MOTION].elements.is_empty();
- bool will_continue_color = (can_continue_color || draw_sky || draw_sky_fog_only || debug_voxelgis || debug_sdfgi_probes);
- bool will_continue_depth = (can_continue_depth || draw_sky || draw_sky_fog_only || debug_voxelgis || debug_sdfgi_probes);
- RD::FinalAction final_color_action = will_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ;
- RD::FinalAction final_depth_action = will_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ;
{
Vector<Color> c;
@@ -2014,7 +1973,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
uint32_t opaque_color_pass_flags = using_motion_pass ? (color_pass_flags & ~COLOR_PASS_FLAG_MOTION_VECTORS) : color_pass_flags;
RID opaque_framebuffer = using_motion_pass ? rb_data->get_color_pass_fb(opaque_color_pass_flags) : color_framebuffer;
RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, PASS_MODE_COLOR, opaque_color_pass_flags, rb_data.is_null(), p_render_data->directional_light_soft_shadows, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->scene_data->lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, p_render_data->scene_data->view_count);
- _render_list_with_threads(&render_list_params, opaque_framebuffer, keep_color ? RD::INITIAL_ACTION_KEEP : RD::INITIAL_ACTION_CLEAR, render_motion_pass ? RD::FINAL_ACTION_CONTINUE : final_color_action, depth_pre_pass ? (continue_depth ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP) : RD::INITIAL_ACTION_CLEAR, render_motion_pass ? RD::FINAL_ACTION_CONTINUE : final_depth_action, c, 1.0, 0);
+ _render_list_with_draw_list(&render_list_params, opaque_framebuffer, load_color ? RD::INITIAL_ACTION_LOAD : RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, depth_pre_pass ? RD::INITIAL_ACTION_LOAD : RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, c, 1.0, 0);
}
RD::get_singleton()->draw_command_end_label();
@@ -2022,7 +1981,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
if (using_motion_pass) {
Vector<Color> motion_vector_clear_colors;
motion_vector_clear_colors.push_back(Color(-1, -1, 0, 0));
- RD::get_singleton()->draw_list_begin(rb_data->get_velocity_only_fb(), RD::INITIAL_ACTION_CLEAR, render_motion_pass ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, RD::FINAL_ACTION_CONTINUE, motion_vector_clear_colors);
+ RD::get_singleton()->draw_list_begin(rb_data->get_velocity_only_fb(), RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, motion_vector_clear_colors);
RD::get_singleton()->draw_list_end();
}
@@ -2034,33 +1993,17 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_MOTION, p_render_data, radiance_texture, samplers, true);
RenderListParameters render_list_params(render_list[RENDER_LIST_MOTION].elements.ptr(), render_list[RENDER_LIST_MOTION].element_info.ptr(), render_list[RENDER_LIST_MOTION].elements.size(), reverse_cull, PASS_MODE_COLOR, color_pass_flags, rb_data.is_null(), p_render_data->directional_light_soft_shadows, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->scene_data->lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, p_render_data->scene_data->view_count);
- _render_list_with_threads(&render_list_params, color_framebuffer, RD::INITIAL_ACTION_CONTINUE, final_color_action, RD::INITIAL_ACTION_CONTINUE, final_depth_action);
+ _render_list_with_draw_list(&render_list_params, color_framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE);
RD::get_singleton()->draw_command_end_label();
-
- if (will_continue_color) {
- // Close the motion vectors framebuffer as it'll no longer be used.
- RD::get_singleton()->draw_list_begin(rb_data->get_velocity_only_fb(), RD::INITIAL_ACTION_CONTINUE, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, RD::FINAL_ACTION_CONTINUE);
- RD::get_singleton()->draw_list_end();
- }
- }
-
- if (will_continue_color && using_separate_specular) {
- // Close the specular framebuffer as it'll no longer be used.
- RD::get_singleton()->draw_list_begin(rb_data->get_specular_only_fb(), RD::INITIAL_ACTION_CONTINUE, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, RD::FINAL_ACTION_CONTINUE);
- RD::get_singleton()->draw_list_end();
}
}
if (debug_voxelgis) {
- //debug voxelgis
- bool will_continue_color = (can_continue_color || draw_sky || draw_sky_fog_only);
- bool will_continue_depth = (can_continue_depth || draw_sky || draw_sky_fog_only);
-
Projection dc;
dc.set_depth_correction(true);
Projection cm = (dc * p_render_data->scene_data->cam_projection) * Projection(p_render_data->scene_data->cam_transform.affine_inverse());
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(color_only_framebuffer, RD::INITIAL_ACTION_CONTINUE, will_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, will_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ);
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(color_only_framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE);
RD::get_singleton()->draw_command_begin_label("Debug VoxelGIs");
for (int i = 0; i < (int)p_render_data->voxel_gi_instances->size(); i++) {
gi.debug_voxel_gi((*p_render_data->voxel_gi_instances)[i], draw_list, color_only_framebuffer, cm, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_VOXEL_GI_LIGHTING, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_VOXEL_GI_EMISSION, 1.0);
@@ -2070,24 +2013,20 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
}
if (debug_sdfgi_probes) {
- //debug sdfgi
- bool will_continue_color = (can_continue_color || draw_sky || draw_sky_fog_only);
- bool will_continue_depth = (can_continue_depth || draw_sky || draw_sky_fog_only);
-
Projection dc;
dc.set_depth_correction(true);
Projection cms[RendererSceneRender::MAX_RENDER_VIEWS];
for (uint32_t v = 0; v < p_render_data->scene_data->view_count; v++) {
cms[v] = (dc * p_render_data->scene_data->view_projection[v]) * Projection(p_render_data->scene_data->cam_transform.affine_inverse());
}
- _debug_sdfgi_probes(rb, color_only_framebuffer, p_render_data->scene_data->view_count, cms, will_continue_color, will_continue_depth);
+ _debug_sdfgi_probes(rb, color_only_framebuffer, p_render_data->scene_data->view_count, cms);
}
if (draw_sky || draw_sky_fog_only) {
RENDER_TIMESTAMP("Render Sky");
RD::get_singleton()->draw_command_begin_label("Draw Sky");
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(color_only_framebuffer, RD::INITIAL_ACTION_CONTINUE, can_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, can_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ);
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(color_only_framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE);
sky.draw_sky(draw_list, rb, p_render_data->environment, color_only_framebuffer, time, sky_energy_multiplier);
@@ -2146,7 +2085,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
RENDER_TIMESTAMP("Clear Separate Specular (Canvas Background Mode)");
Vector<Color> blank_clear_color;
blank_clear_color.push_back(Color(0.0, 0.0, 0.0));
- RD::get_singleton()->draw_list_begin(rb_data->get_specular_only_fb(), RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, blank_clear_color);
+ RD::get_singleton()->draw_list_begin(rb_data->get_specular_only_fb(), RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD, blank_clear_color);
RD::get_singleton()->draw_list_end();
}
@@ -2187,7 +2126,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
RID alpha_framebuffer = rb_data.is_valid() ? rb_data->get_color_pass_fb(transparent_color_pass_flags) : color_only_framebuffer;
RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), false, PASS_MODE_COLOR, transparent_color_pass_flags, rb_data.is_null(), p_render_data->directional_light_soft_shadows, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->scene_data->lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, p_render_data->scene_data->view_count);
- _render_list_with_threads(&render_list_params, alpha_framebuffer, can_continue_color ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, can_continue_depth ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ);
+ _render_list_with_draw_list(&render_list_params, alpha_framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE);
}
RD::get_singleton()->draw_command_end_label();
@@ -2226,7 +2165,9 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
exposure = luminance->get_current_luminance_buffer(rb);
}
+ RD::get_singleton()->draw_command_begin_label("FSR2");
RENDER_TIMESTAMP("FSR2");
+
for (uint32_t v = 0; v < rb->get_view_count(); v++) {
real_t fov = p_render_data->scene_data->cam_projection.get_fov();
real_t aspect = p_render_data->scene_data->cam_projection.get_aspect();
@@ -2257,9 +2198,13 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
fsr2_effect->upscale(params);
}
+
+ RD::get_singleton()->draw_command_end_label();
} else if (using_taa) {
+ RD::get_singleton()->draw_command_begin_label("TAA");
RENDER_TIMESTAMP("TAA");
taa->process(rb, _render_buffers_get_color_format(), p_render_data->scene_data->z_near, p_render_data->scene_data->z_far);
+ RD::get_singleton()->draw_command_end_label();
}
}
@@ -2571,8 +2516,7 @@ void RenderForwardClustered::_render_shadow_append(RID p_framebuffer, const Page
shadow_pass.lod_distance_multiplier = scene_data.lod_distance_multiplier;
shadow_pass.framebuffer = p_framebuffer;
- shadow_pass.initial_depth_action = p_begin ? (p_clear_region ? RD::INITIAL_ACTION_CLEAR_REGION : RD::INITIAL_ACTION_CLEAR) : (p_clear_region ? RD::INITIAL_ACTION_CLEAR_REGION_CONTINUE : RD::INITIAL_ACTION_CONTINUE);
- shadow_pass.final_depth_action = p_end ? RD::FINAL_ACTION_READ : RD::FINAL_ACTION_CONTINUE;
+ shadow_pass.initial_depth_action = p_begin ? RD::INITIAL_ACTION_CLEAR : (p_clear_region ? RD::INITIAL_ACTION_CLEAR : RD::INITIAL_ACTION_LOAD);
shadow_pass.rect = p_rect;
scene_state.shadow_passes.push_back(shadow_pass);
@@ -2591,17 +2535,14 @@ void RenderForwardClustered::_render_shadow_process() {
RD::get_singleton()->draw_command_end_label();
}
-void RenderForwardClustered::_render_shadow_end(uint32_t p_barrier) {
+void RenderForwardClustered::_render_shadow_end() {
RD::get_singleton()->draw_command_begin_label("Shadow Render");
for (SceneState::ShadowPass &shadow_pass : scene_state.shadow_passes) {
- RenderListParameters render_list_parameters(render_list[RENDER_LIST_SECONDARY].elements.ptr() + shadow_pass.element_from, render_list[RENDER_LIST_SECONDARY].element_info.ptr() + shadow_pass.element_from, shadow_pass.element_count, shadow_pass.flip_cull, shadow_pass.pass_mode, 0, true, false, shadow_pass.rp_uniform_set, false, Vector2(), shadow_pass.lod_distance_multiplier, shadow_pass.screen_mesh_lod_threshold, 1, shadow_pass.element_from, RD::BARRIER_MASK_NO_BARRIER);
- _render_list_with_threads(&render_list_parameters, shadow_pass.framebuffer, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, shadow_pass.initial_depth_action, shadow_pass.final_depth_action, Vector<Color>(), 1.0, 0, shadow_pass.rect);
+ RenderListParameters render_list_parameters(render_list[RENDER_LIST_SECONDARY].elements.ptr() + shadow_pass.element_from, render_list[RENDER_LIST_SECONDARY].element_info.ptr() + shadow_pass.element_from, shadow_pass.element_count, shadow_pass.flip_cull, shadow_pass.pass_mode, 0, true, false, shadow_pass.rp_uniform_set, false, Vector2(), shadow_pass.lod_distance_multiplier, shadow_pass.screen_mesh_lod_threshold, 1, shadow_pass.element_from);
+ _render_list_with_draw_list(&render_list_parameters, shadow_pass.framebuffer, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD, shadow_pass.initial_depth_action, RD::FINAL_ACTION_STORE, Vector<Color>(), 1.0, 0, shadow_pass.rect);
}
- if (p_barrier != RD::BARRIER_MASK_NO_BARRIER) {
- RD::get_singleton()->barrier(RD::BARRIER_MASK_RASTER, p_barrier);
- }
RD::get_singleton()->draw_command_end_label();
}
@@ -2644,7 +2585,7 @@ void RenderForwardClustered::_render_particle_collider_heightfield(RID p_fb, con
{
//regular forward for now
RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), false, pass_mode, 0, true, false, rp_uniform_set);
- _render_list_with_threads(&render_list_params, p_fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ);
+ _render_list_with_draw_list(&render_list_params, p_fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE);
}
RD::get_singleton()->draw_command_end_label();
}
@@ -2697,7 +2638,7 @@ void RenderForwardClustered::_render_material(const Transform3D &p_cam_transform
Color(0, 0, 0, 0)
};
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, clear, 1.0, 0, p_region);
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, clear, 1.0, 0, p_region);
_render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), &render_list_params, 0, render_list_params.element_count);
RD::get_singleton()->draw_list_end();
}
@@ -2747,7 +2688,7 @@ void RenderForwardClustered::_render_uv2(const PagedArray<RenderGeometryInstance
Color(0, 0, 0, 0),
Color(0, 0, 0, 0)
};
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, clear, 1.0, 0, p_region);
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, clear, 1.0, 0, p_region);
const int uv_offset_count = 9;
static const Vector2 uv_offsets[uv_offset_count] = {
@@ -2803,13 +2744,6 @@ void RenderForwardClustered::_render_sdfgi(Ref<RenderSceneBuffersRD> p_render_bu
Vector3 half_size = p_bounds.size * 0.5;
Vector3 center = p_bounds.position + half_size;
- Vector<RID> sbs = {
- p_albedo_texture,
- p_emission_texture,
- p_emission_aniso_texture,
- p_geom_facing_texture
- };
-
//print_line("re-render " + p_from + " - " + p_size + " bounds " + p_bounds);
for (int i = 0; i < 3; i++) {
scene_state.ubo.sdf_offset[i] = p_from[i];
@@ -2860,7 +2794,7 @@ void RenderForwardClustered::_render_sdfgi(Ref<RenderSceneBuffersRD> p_render_bu
}
RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), true, pass_mode, 0, true, false, rp_uniform_set, false);
- _render_list_with_threads(&render_list_params, E->value, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, Rect2(), sbs);
+ _render_list_with_draw_list(&render_list_params, E->value, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, Rect2());
}
RD::get_singleton()->draw_command_end_label();
@@ -4280,8 +4214,6 @@ RenderForwardClustered::RenderForwardClustered() {
best_fit_normal.shader.version_free(best_fit_normal.shader_version);
}
- render_list_thread_threshold = GLOBAL_GET("rendering/limits/forward_renderer/threaded_render_minimum_instances");
-
_update_shader_quality_settings();
resolve_effects = memnew(RendererRD::Resolve());
diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
index 5ff3d9f52a..5af213bc02 100644
--- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
@@ -209,10 +209,9 @@ class RenderForwardClustered : public RendererSceneRenderRD {
float screen_mesh_lod_threshold = 0.0;
RD::FramebufferFormatID framebuffer_format = 0;
uint32_t element_offset = 0;
- uint32_t barrier = RD::BARRIER_MASK_ALL_BARRIERS;
bool use_directional_soft_shadow = false;
- RenderListParameters(GeometryInstanceSurfaceDataCache **p_elements, RenderElementInfo *p_element_info, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, uint32_t p_color_pass_flags, bool p_no_gi, bool p_use_directional_soft_shadows, RID p_render_pass_uniform_set, bool p_force_wireframe = false, const Vector2 &p_uv_offset = Vector2(), float p_lod_distance_multiplier = 0.0, float p_screen_mesh_lod_threshold = 0.0, uint32_t p_view_count = 1, uint32_t p_element_offset = 0, uint32_t p_barrier = RD::BARRIER_MASK_ALL_BARRIERS) {
+ RenderListParameters(GeometryInstanceSurfaceDataCache **p_elements, RenderElementInfo *p_element_info, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, uint32_t p_color_pass_flags, bool p_no_gi, bool p_use_directional_soft_shadows, RID p_render_pass_uniform_set, bool p_force_wireframe = false, const Vector2 &p_uv_offset = Vector2(), float p_lod_distance_multiplier = 0.0, float p_screen_mesh_lod_threshold = 0.0, uint32_t p_view_count = 1, uint32_t p_element_offset = 0) {
elements = p_elements;
element_info = p_element_info;
element_count = p_element_count;
@@ -227,7 +226,6 @@ class RenderForwardClustered : public RendererSceneRenderRD {
lod_distance_multiplier = p_lod_distance_multiplier;
screen_mesh_lod_threshold = p_screen_mesh_lod_threshold;
element_offset = p_element_offset;
- barrier = p_barrier;
use_directional_soft_shadow = p_use_directional_soft_shadows;
}
};
@@ -352,7 +350,6 @@ class RenderForwardClustered : public RendererSceneRenderRD {
RID framebuffer;
RD::InitialAction initial_depth_action;
- RD::FinalAction final_depth_action;
Rect2i rect;
};
@@ -378,14 +375,8 @@ class RenderForwardClustered : public RendererSceneRenderRD {
template <PassMode p_pass_mode, uint32_t p_color_pass_flags = 0>
_FORCE_INLINE_ void _render_list_template(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element);
-
void _render_list(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element);
-
- LocalVector<RD::DrawListID> thread_draw_lists;
- void _render_list_thread_function(uint32_t p_thread, RenderListParameters *p_params);
- void _render_list_with_threads(RenderListParameters *p_params, RID p_framebuffer, RD::InitialAction p_initial_color_action, RD::FinalAction p_final_color_action, RD::InitialAction p_initial_depth_action, RD::FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2(), const Vector<RID> &p_storage_textures = Vector<RID>());
-
- uint32_t render_list_thread_threshold = 500;
+ void _render_list_with_draw_list(RenderListParameters *p_params, RID p_framebuffer, RD::InitialAction p_initial_color_action, RD::FinalAction p_final_color_action, RD::InitialAction p_initial_depth_action, RD::FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2());
void _update_instance_data_buffer(RenderListType p_render_list);
void _fill_instance_data(RenderListType p_render_list, int *p_render_info = nullptr, uint32_t p_offset = 0, int32_t p_max_elements = -1, bool p_update_buffer = true);
@@ -604,7 +595,7 @@ class RenderForwardClustered : public RendererSceneRenderRD {
void _render_shadow_begin();
void _render_shadow_append(RID p_framebuffer, const PagedArray<RenderGeometryInstance *> &p_instances, const Projection &p_projection, const Transform3D &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_reverse_cull_face, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_mesh_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true, RenderingMethod::RenderInfo *p_render_info = nullptr, const Size2i &p_viewport_size = Size2i(1, 1));
void _render_shadow_process();
- void _render_shadow_end(uint32_t p_barrier = RD::BARRIER_MASK_ALL_BARRIERS);
+ void _render_shadow_end();
/* Render Scene */
void _process_ssao(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_environment, const RID *p_normal_buffers, const Projection *p_projections);
diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
index bba1f62023..86852ce020 100644
--- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
@@ -446,7 +446,7 @@ void SceneShaderForwardClustered::MaterialData::set_next_pass(RID p_pass) {
bool SceneShaderForwardClustered::MaterialData::update_parameters(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
SceneShaderForwardClustered *shader_singleton = (SceneShaderForwardClustered *)SceneShaderForwardClustered::singleton;
- return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, shader_singleton->shader.version_get_shader(shader_data->version, 0), RenderForwardClustered::MATERIAL_UNIFORM_SET, true, true, RD::BARRIER_MASK_RASTER);
+ return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, shader_singleton->shader.version_get_shader(shader_data->version, 0), RenderForwardClustered::MATERIAL_UNIFORM_SET, true, true);
}
SceneShaderForwardClustered::MaterialData::~MaterialData() {
diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
index b7d7105daa..da04e6f938 100644
--- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
+++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
@@ -596,7 +596,7 @@ void RenderForwardMobile::_setup_lightmaps(const RenderDataRD *p_render_data, co
scene_state.lightmaps_used++;
}
if (scene_state.lightmaps_used > 0) {
- RD::get_singleton()->buffer_update(scene_state.lightmap_buffer, 0, sizeof(LightmapData) * scene_state.lightmaps_used, scene_state.lightmaps, RD::BARRIER_MASK_RASTER);
+ RD::get_singleton()->buffer_update(scene_state.lightmap_buffer, 0, sizeof(LightmapData) * scene_state.lightmaps_used, scene_state.lightmaps);
}
}
@@ -631,7 +631,7 @@ void RenderForwardMobile::_pre_opaque_render(RenderDataRD *p_render_data) {
if (p_render_data->directional_shadows.size()) {
//open the pass for directional shadows
light_storage->update_directional_shadow_atlas();
- RD::get_singleton()->draw_list_begin(light_storage->direction_shadow_get_fb(), RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_CONTINUE);
+ RD::get_singleton()->draw_list_begin(light_storage->direction_shadow_get_fb(), RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE);
RD::get_singleton()->draw_list_end();
}
}
@@ -655,11 +655,8 @@ void RenderForwardMobile::_pre_opaque_render(RenderDataRD *p_render_data) {
_render_shadow_process();
- _render_shadow_end(RD::BARRIER_MASK_NO_BARRIER);
+ _render_shadow_end();
}
-
- //full barrier here, we need raster, transfer and compute and it depends from the previous work
- RD::get_singleton()->barrier(RD::BARRIER_MASK_ALL_BARRIERS, RD::BARRIER_MASK_ALL_BARRIERS);
}
void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color &p_default_bg_color) {
@@ -811,7 +808,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
float sky_energy_multiplier = inverse_luminance_multiplier;
Color clear_color = p_default_bg_color;
- bool keep_color = false;
+ bool load_color = false;
bool copy_canvas = false;
if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_OVERDRAW) {
@@ -855,7 +852,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
}
} break;
case RS::ENV_BG_KEEP: {
- keep_color = true;
+ load_color = true;
} break;
case RS::ENV_BG_CAMERA_FEED: {
} break;
@@ -955,6 +952,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
if (rb_data.is_valid()) {
cc.a = 0; // For transparent viewport backgrounds.
}
+
c.push_back(cc); // Our render buffer.
if (rb_data.is_valid()) {
if (p_render_data->render_buffers->get_msaa_3d() != RS::VIEWPORT_MSAA_DISABLED) {
@@ -966,7 +964,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
}
}
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, keep_color ? RD::INITIAL_ACTION_KEEP : RD::INITIAL_ACTION_CLEAR, merge_transparent_pass ? RD::FINAL_ACTION_READ : RD::FINAL_ACTION_CONTINUE, RD::INITIAL_ACTION_CLEAR, merge_transparent_pass ? RD::FINAL_ACTION_READ : RD::FINAL_ACTION_CONTINUE, c, 1.0, 0);
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, load_color ? RD::INITIAL_ACTION_LOAD : RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, c, 1.0, 0);
RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(framebuffer);
if (copy_canvas) {
@@ -1026,12 +1024,12 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
RD::get_singleton()->draw_command_end_label(); // Render 3D Pass / Render Reflection Probe Pass
- RD::get_singleton()->draw_list_end(RD::BARRIER_MASK_ALL_BARRIERS);
+ RD::get_singleton()->draw_list_end();
} else {
// We're done with our subpasses so end our container pass
// note, if MSAA is used we should get an automatic resolve here
- RD::get_singleton()->draw_list_end(RD::BARRIER_MASK_ALL_BARRIERS);
+ RD::get_singleton()->draw_list_end();
RD::get_singleton()->draw_command_end_label(); // Render 3D Pass / Render Reflection Probe Pass
@@ -1062,9 +1060,9 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
render_list_params.framebuffer_format = fb_format;
render_list_params.subpass = RD::get_singleton()->draw_list_get_current_pass(); // Should now always be 0.
- draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ);
+ draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE);
_render_list(draw_list, fb_format, &render_list_params, 0, render_list_params.element_count);
- RD::get_singleton()->draw_list_end(RD::BARRIER_MASK_ALL_BARRIERS);
+ RD::get_singleton()->draw_list_end();
RD::get_singleton()->draw_command_end_label(); // Render Transparent Pass
}
@@ -1248,15 +1246,15 @@ void RenderForwardMobile::_render_shadow_pass(RID p_light, RID p_shadow_atlas, i
_render_shadow_append(render_fb, p_instances, light_projection, light_transform, zfar, 0, 0, false, false, use_pancake, p_camera_plane, p_lod_distance_multiplier, p_screen_mesh_lod_threshold, Rect2(), false, true, true, true, p_render_info);
if (finalize_cubemap) {
_render_shadow_process();
- _render_shadow_end(RD::BARRIER_MASK_FRAGMENT);
+ _render_shadow_end();
// reblit
Rect2 atlas_rect_norm = atlas_rect;
atlas_rect_norm.position /= float(atlas_size);
atlas_rect_norm.size /= float(atlas_size);
- copy_effects->copy_cubemap_to_dp(render_texture, atlas_fb, atlas_rect_norm, atlas_rect.size, light_projection.get_z_near(), light_projection.get_z_far(), false, RD::BARRIER_MASK_NO_BARRIER);
+ copy_effects->copy_cubemap_to_dp(render_texture, atlas_fb, atlas_rect_norm, atlas_rect.size, light_projection.get_z_near(), light_projection.get_z_far(), false);
atlas_rect_norm.position += Vector2(dual_paraboloid_offset) * atlas_rect_norm.size;
- copy_effects->copy_cubemap_to_dp(render_texture, atlas_fb, atlas_rect_norm, atlas_rect.size, light_projection.get_z_near(), light_projection.get_z_far(), true, RD::BARRIER_MASK_NO_BARRIER);
+ copy_effects->copy_cubemap_to_dp(render_texture, atlas_fb, atlas_rect_norm, atlas_rect.size, light_projection.get_z_near(), light_projection.get_z_far(), true);
//restore transform so it can be properly used
light_storage->light_instance_set_shadow_transform(p_light, Projection(), light_storage->light_instance_get_base_transform(p_light), zfar, 0, 0, 0);
@@ -1337,8 +1335,7 @@ void RenderForwardMobile::_render_shadow_append(RID p_framebuffer, const PagedAr
shadow_pass.lod_distance_multiplier = scene_data.lod_distance_multiplier;
shadow_pass.framebuffer = p_framebuffer;
- shadow_pass.initial_depth_action = p_begin ? (p_clear_region ? RD::INITIAL_ACTION_CLEAR_REGION : RD::INITIAL_ACTION_CLEAR) : (p_clear_region ? RD::INITIAL_ACTION_CLEAR_REGION_CONTINUE : RD::INITIAL_ACTION_CONTINUE);
- shadow_pass.final_depth_action = p_end ? RD::FINAL_ACTION_READ : RD::FINAL_ACTION_CONTINUE;
+ shadow_pass.initial_depth_action = p_begin ? RD::INITIAL_ACTION_CLEAR : (p_clear_region ? RD::INITIAL_ACTION_CLEAR : RD::INITIAL_ACTION_LOAD);
shadow_pass.rect = p_rect;
scene_state.shadow_passes.push_back(shadow_pass);
@@ -1357,17 +1354,14 @@ void RenderForwardMobile::_render_shadow_process() {
RD::get_singleton()->draw_command_end_label();
}
-void RenderForwardMobile::_render_shadow_end(uint32_t p_barrier) {
+void RenderForwardMobile::_render_shadow_end() {
RD::get_singleton()->draw_command_begin_label("Shadow Render");
for (SceneState::ShadowPass &shadow_pass : scene_state.shadow_passes) {
- RenderListParameters render_list_parameters(render_list[RENDER_LIST_SECONDARY].elements.ptr() + shadow_pass.element_from, render_list[RENDER_LIST_SECONDARY].element_info.ptr() + shadow_pass.element_from, shadow_pass.element_count, shadow_pass.flip_cull, shadow_pass.pass_mode, shadow_pass.rp_uniform_set, 0, false, Vector2(), shadow_pass.lod_distance_multiplier, shadow_pass.screen_mesh_lod_threshold, 1, shadow_pass.element_from, RD::BARRIER_MASK_NO_BARRIER);
- _render_list_with_threads(&render_list_parameters, shadow_pass.framebuffer, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, shadow_pass.initial_depth_action, shadow_pass.final_depth_action, Vector<Color>(), 1.0, 0, shadow_pass.rect);
+ RenderListParameters render_list_parameters(render_list[RENDER_LIST_SECONDARY].elements.ptr() + shadow_pass.element_from, render_list[RENDER_LIST_SECONDARY].element_info.ptr() + shadow_pass.element_from, shadow_pass.element_count, shadow_pass.flip_cull, shadow_pass.pass_mode, shadow_pass.rp_uniform_set, 0, false, Vector2(), shadow_pass.lod_distance_multiplier, shadow_pass.screen_mesh_lod_threshold, 1, shadow_pass.element_from);
+ _render_list_with_draw_list(&render_list_parameters, shadow_pass.framebuffer, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD, shadow_pass.initial_depth_action, RD::FINAL_ACTION_STORE, Vector<Color>(), 1.0, 0, shadow_pass.rect);
}
- if (p_barrier != RD::BARRIER_MASK_NO_BARRIER) {
- RD::get_singleton()->barrier(RD::BARRIER_MASK_FRAGMENT, p_barrier);
- }
RD::get_singleton()->draw_command_end_label();
}
@@ -1416,7 +1410,7 @@ void RenderForwardMobile::_render_material(const Transform3D &p_cam_transform, c
Color(0, 0, 0, 0),
Color(0, 0, 0, 0)
};
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, clear, 1.0, 0, p_region);
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, clear, 1.0, 0, p_region);
_render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), &render_list_params, 0, render_list_params.element_count);
RD::get_singleton()->draw_list_end();
}
@@ -1462,7 +1456,7 @@ void RenderForwardMobile::_render_uv2(const PagedArray<RenderGeometryInstance *>
Color(0, 0, 0, 0)
};
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, clear, 1.0, 0, p_region);
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, clear, 1.0, 0, p_region);
const int uv_offset_count = 9;
static const Vector2 uv_offsets[uv_offset_count] = {
@@ -1535,7 +1529,7 @@ void RenderForwardMobile::_render_particle_collider_heightfield(RID p_fb, const
{
//regular forward for now
RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), false, pass_mode, rp_uniform_set, 0);
- _render_list_with_threads(&render_list_params, p_fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ);
+ _render_list_with_draw_list(&render_list_params, p_fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE);
}
RD::get_singleton()->draw_command_end_label();
}
@@ -1672,7 +1666,7 @@ void RenderForwardMobile::_update_instance_data_buffer(RenderListType p_render_l
scene_state.instance_buffer[p_render_list] = RD::get_singleton()->storage_buffer_create(new_size * sizeof(SceneState::InstanceData));
scene_state.instance_buffer_size[p_render_list] = new_size;
}
- RD::get_singleton()->buffer_update(scene_state.instance_buffer[p_render_list], 0, sizeof(SceneState::InstanceData) * scene_state.instance_data[p_render_list].size(), scene_state.instance_data[p_render_list].ptr(), RD::BARRIER_MASK_RASTER);
+ RD::get_singleton()->buffer_update(scene_state.instance_buffer[p_render_list], 0, sizeof(SceneState::InstanceData) * scene_state.instance_data[p_render_list].size(), scene_state.instance_data[p_render_list].ptr());
}
}
@@ -1991,32 +1985,13 @@ void RenderForwardMobile::_render_list(RenderingDevice::DrawListID p_draw_list,
}
}
-void RenderForwardMobile::_render_list_thread_function(uint32_t p_thread, RenderListParameters *p_params) {
- uint32_t render_total = p_params->element_count;
- uint32_t total_threads = WorkerThreadPool::get_singleton()->get_thread_count();
- uint32_t render_from = p_thread * render_total / total_threads;
- uint32_t render_to = (p_thread + 1 == total_threads) ? render_total : ((p_thread + 1) * render_total / total_threads);
- _render_list(thread_draw_lists[p_thread], p_params->framebuffer_format, p_params, render_from, render_to);
-}
-
-void RenderForwardMobile::_render_list_with_threads(RenderListParameters *p_params, RID p_framebuffer, RD::InitialAction p_initial_color_action, RD::FinalAction p_final_color_action, RD::InitialAction p_initial_depth_action, RD::FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const Vector<RID> &p_storage_textures) {
+void RenderForwardMobile::_render_list_with_draw_list(RenderListParameters *p_params, RID p_framebuffer, RD::InitialAction p_initial_color_action, RD::FinalAction p_final_color_action, RD::InitialAction p_initial_depth_action, RD::FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region) {
RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(p_framebuffer);
p_params->framebuffer_format = fb_format;
- if ((uint32_t)p_params->element_count > render_list_thread_threshold && false) { // secondary command buffers need more testing at this time
- //multi threaded
- thread_draw_lists.resize(WorkerThreadPool::get_singleton()->get_thread_count());
- RD::get_singleton()->draw_list_begin_split(p_framebuffer, thread_draw_lists.size(), thread_draw_lists.ptr(), p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, p_region, p_storage_textures);
- WorkerThreadPool::GroupID group_task = WorkerThreadPool::get_singleton()->add_template_group_task(this, &RenderForwardMobile::_render_list_thread_function, p_params, thread_draw_lists.size(), -1, true, SNAME("ForwardMobileRenderSubpass"));
- WorkerThreadPool::get_singleton()->wait_for_group_task_completion(group_task);
-
- RD::get_singleton()->draw_list_end(p_params->barrier);
- } else {
- //single threaded
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, p_region, p_storage_textures);
- _render_list(draw_list, fb_format, p_params, 0, p_params->element_count);
- RD::get_singleton()->draw_list_end(p_params->barrier);
- }
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, p_region);
+ _render_list(draw_list, fb_format, p_params, 0, p_params->element_count);
+ RD::get_singleton()->draw_list_end();
}
template <RenderForwardMobile::PassMode p_pass_mode>
@@ -2813,9 +2788,6 @@ RenderForwardMobile::RenderForwardMobile() {
scene_shader.init(defines);
- // !BAS! maybe we need a mobile version of this setting?
- render_list_thread_threshold = GLOBAL_GET("rendering/limits/forward_renderer/threaded_render_minimum_instances");
-
_update_shader_quality_settings();
}
diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h
index da96ca2124..f1f6bb3db4 100644
--- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h
+++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h
@@ -155,10 +155,9 @@ private:
float screen_mesh_lod_threshold = 0.0;
RD::FramebufferFormatID framebuffer_format = 0;
uint32_t element_offset = 0;
- uint32_t barrier = RD::BARRIER_MASK_ALL_BARRIERS;
uint32_t subpass = 0;
- RenderListParameters(GeometryInstanceSurfaceDataCache **p_elements, RenderElementInfo *p_element_info, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, RID p_render_pass_uniform_set, uint32_t p_spec_constant_base_flags = 0, bool p_force_wireframe = false, const Vector2 &p_uv_offset = Vector2(), float p_lod_distance_multiplier = 0.0, float p_screen_mesh_lod_threshold = 0.0, uint32_t p_view_count = 1, uint32_t p_element_offset = 0, uint32_t p_barrier = RD::BARRIER_MASK_ALL_BARRIERS) {
+ RenderListParameters(GeometryInstanceSurfaceDataCache **p_elements, RenderElementInfo *p_element_info, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, RID p_render_pass_uniform_set, uint32_t p_spec_constant_base_flags = 0, bool p_force_wireframe = false, const Vector2 &p_uv_offset = Vector2(), float p_lod_distance_multiplier = 0.0, float p_screen_mesh_lod_threshold = 0.0, uint32_t p_view_count = 1, uint32_t p_element_offset = 0) {
elements = p_elements;
element_info = p_element_info;
element_count = p_element_count;
@@ -172,7 +171,6 @@ private:
lod_distance_multiplier = p_lod_distance_multiplier;
screen_mesh_lod_threshold = p_screen_mesh_lod_threshold;
element_offset = p_element_offset;
- barrier = p_barrier;
spec_constant_base_flags = p_spec_constant_base_flags;
}
};
@@ -183,7 +181,7 @@ private:
void _render_shadow_begin();
void _render_shadow_append(RID p_framebuffer, const PagedArray<RenderGeometryInstance *> &p_instances, const Projection &p_projection, const Transform3D &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_mesh_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true, RenderingMethod::RenderInfo *p_render_info = nullptr);
void _render_shadow_process();
- void _render_shadow_end(uint32_t p_barrier = RD::BARRIER_MASK_ALL_BARRIERS);
+ void _render_shadow_end();
/* Render Scene */
@@ -277,7 +275,6 @@ private:
RID framebuffer;
RD::InitialAction initial_depth_action;
- RD::FinalAction final_depth_action;
Rect2i rect;
};
@@ -351,14 +348,8 @@ private:
template <PassMode p_pass_mode>
_FORCE_INLINE_ void _render_list_template(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element);
-
void _render_list(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element);
-
- LocalVector<RD::DrawListID> thread_draw_lists;
- void _render_list_thread_function(uint32_t p_thread, RenderListParameters *p_params);
- void _render_list_with_threads(RenderListParameters *p_params, RID p_framebuffer, RD::InitialAction p_initial_color_action, RD::FinalAction p_final_color_action, RD::InitialAction p_initial_depth_action, RD::FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2(), const Vector<RID> &p_storage_textures = Vector<RID>());
-
- uint32_t render_list_thread_threshold = 500;
+ void _render_list_with_draw_list(RenderListParameters *p_params, RID p_framebuffer, RD::InitialAction p_initial_color_action, RD::FinalAction p_final_color_action, RD::InitialAction p_initial_depth_action, RD::FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2());
RenderList render_list[RENDER_LIST_MAX];
diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp
index f1cec0e07c..043cdbc8e5 100644
--- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp
+++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp
@@ -398,7 +398,7 @@ void SceneShaderForwardMobile::MaterialData::set_next_pass(RID p_pass) {
bool SceneShaderForwardMobile::MaterialData::update_parameters(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
SceneShaderForwardMobile *shader_singleton = (SceneShaderForwardMobile *)SceneShaderForwardMobile::singleton;
- return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, shader_singleton->shader.version_get_shader(shader_data->version, 0), RenderForwardMobile::MATERIAL_UNIFORM_SET, true, true, RD::BARRIER_MASK_RASTER);
+ return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, shader_singleton->shader.version_get_shader(shader_data->version, 0), RenderForwardMobile::MATERIAL_UNIFORM_SET, true, true);
}
SceneShaderForwardMobile::MaterialData::~MaterialData() {
diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
index 657628111a..283b3ee09a 100644
--- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
@@ -1177,7 +1177,7 @@ void RendererCanvasRenderRD::_render_items(RID p_to_render_target, int p_item_co
RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(framebuffer);
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, clear ? RD::INITIAL_ACTION_CLEAR : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD, clear_colors);
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, clear ? RD::INITIAL_ACTION_CLEAR : RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, clear_colors);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, fb_uniform_set, BASE_UNIFORM_SET);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, state.default_transforms_uniform_set, TRANSFORMS_UNIFORM_SET);
@@ -1721,8 +1721,7 @@ void RendererCanvasRenderRD::light_update_shadow(RID p_rid, int p_shadow_index,
//light.basis.scale(Vector3(to_light.elements[0].length(),to_light.elements[1].length(),1));
Rect2i rect((state.shadow_texture_size / 4) * i, p_shadow_index * 2, (state.shadow_texture_size / 4), 2);
- RD::InitialAction initial_action = i == 0 ? RD::INITIAL_ACTION_CLEAR_REGION : RD::INITIAL_ACTION_CLEAR_REGION_CONTINUE;
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(state.shadow_fb, initial_action, i != 3 ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, initial_action, RD::FINAL_ACTION_DISCARD, cc, 1.0, 0, rect);
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(state.shadow_fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, cc, 1.0, 0, rect);
Projection projection;
{
@@ -1811,7 +1810,7 @@ void RendererCanvasRenderRD::light_update_directional_shadow(RID p_rid, int p_sh
cc.push_back(Color(1, 1, 1, 1));
Rect2i rect(0, p_shadow_index * 2, state.shadow_texture_size, 2);
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(state.shadow_fb, RD::INITIAL_ACTION_CLEAR_REGION, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR_REGION, RD::FINAL_ACTION_DISCARD, cc, 1.0, 0, rect);
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(state.shadow_fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, cc, 1.0, 0, rect);
Projection projection;
projection.set_orthogonal(-half_size, half_size, -0.5, 0.5, 0.0, distance);
@@ -1881,7 +1880,7 @@ void RendererCanvasRenderRD::render_sdf(RID p_render_target, LightOccluderInstan
Vector<Color> cc;
cc.push_back(Color(0, 0, 0, 0));
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, cc);
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, cc);
Projection projection;
@@ -2371,8 +2370,8 @@ RendererRD::MaterialStorage::ShaderData *RendererCanvasRenderRD::_create_shader_
bool RendererCanvasRenderRD::CanvasMaterialData::update_parameters(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
RendererCanvasRenderRD *canvas_singleton = static_cast<RendererCanvasRenderRD *>(RendererCanvasRender::singleton);
- bool uniform_set_changed = update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, canvas_singleton->shader.canvas_shader.version_get_shader(shader_data->version, 0), MATERIAL_UNIFORM_SET, true, false, RD::BARRIER_MASK_ALL_BARRIERS);
- bool uniform_set_srgb_changed = update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set_srgb, canvas_singleton->shader.canvas_shader.version_get_shader(shader_data->version, 0), MATERIAL_UNIFORM_SET, false, false, RD::BARRIER_MASK_ALL_BARRIERS);
+ bool uniform_set_changed = update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, canvas_singleton->shader.canvas_shader.version_get_shader(shader_data->version, 0), MATERIAL_UNIFORM_SET, true, false);
+ bool uniform_set_srgb_changed = update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set_srgb, canvas_singleton->shader.canvas_shader.version_get_shader(shader_data->version, 0), MATERIAL_UNIFORM_SET, false, false);
return uniform_set_changed || uniform_set_srgb_changed;
}
diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.h b/servers/rendering/renderer_rd/renderer_compositor_rd.h
index 705fb9e8e5..9b073821c2 100644
--- a/servers/rendering/renderer_rd/renderer_compositor_rd.h
+++ b/servers/rendering/renderer_rd/renderer_compositor_rd.h
@@ -123,6 +123,7 @@ public:
void prepare_for_blitting_render_targets();
void blit_render_targets_to_screen(DisplayServer::WindowID p_screen, const BlitToScreen *p_render_targets, int p_amount);
+ void end_viewport(bool p_swap_buffers) {}
void end_frame(bool p_swap_buffers);
void finalize();
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
index 30c9b97aa4..3b05431f4a 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
@@ -220,7 +220,7 @@ void RendererSceneRenderRD::voxel_gi_update(RID p_probe, bool p_update_light_ins
gi.voxel_gi_update(p_probe, p_update_light_instances, p_light_instances, p_dynamic_objects);
}
-void RendererSceneRenderRD::_debug_sdfgi_probes(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_framebuffer, const uint32_t p_view_count, const Projection *p_camera_with_transforms, bool p_will_continue_color, bool p_will_continue_depth) {
+void RendererSceneRenderRD::_debug_sdfgi_probes(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_framebuffer, const uint32_t p_view_count, const Projection *p_camera_with_transforms) {
ERR_FAIL_COND(p_render_buffers.is_null());
if (!p_render_buffers->has_custom_data(RB_SCOPE_SDFGI)) {
@@ -229,7 +229,7 @@ void RendererSceneRenderRD::_debug_sdfgi_probes(Ref<RenderSceneBuffersRD> p_rend
Ref<RendererRD::GI::SDFGI> sdfgi = p_render_buffers->get_custom_data(RB_SCOPE_SDFGI);
- sdfgi->debug_probes(p_framebuffer, p_view_count, p_camera_with_transforms, p_will_continue_color, p_will_continue_depth);
+ sdfgi->debug_probes(p_framebuffer, p_view_count, p_camera_with_transforms);
}
////////////////////////////////
@@ -987,14 +987,6 @@ void RendererSceneRenderRD::_post_prepass_render(RenderDataRD *p_render_data, bo
}
}
-void RendererSceneRenderRD::_pre_resolve_render(RenderDataRD *p_render_data, bool p_use_gi) {
- if (p_render_data->render_buffers.is_valid()) {
- if (p_use_gi) {
- RD::get_singleton()->compute_list_end();
- }
- }
-}
-
void RendererSceneRenderRD::render_scene(const Ref<RenderSceneBuffers> &p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray<RenderGeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_attributes, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data, RenderingMethod::RenderInfo *r_render_info) {
RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h
index 211d191039..4811ae3b44 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.h
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h
@@ -137,14 +137,13 @@ protected:
virtual void _render_sdfgi(Ref<RenderSceneBuffersRD> p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, const PagedArray<RenderGeometryInstance *> &p_instances, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture, float p_exposure_normalization) = 0;
virtual void _render_particle_collider_heightfield(RID p_fb, const Transform3D &p_cam_transform, const Projection &p_cam_projection, const PagedArray<RenderGeometryInstance *> &p_instances) = 0;
- void _debug_sdfgi_probes(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_framebuffer, uint32_t p_view_count, const Projection *p_camera_with_transforms, bool p_will_continue_color, bool p_will_continue_depth);
+ void _debug_sdfgi_probes(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_framebuffer, uint32_t p_view_count, const Projection *p_camera_with_transforms);
virtual RID _render_buffers_get_normal_texture(Ref<RenderSceneBuffersRD> p_render_buffers) = 0;
virtual RID _render_buffers_get_velocity_texture(Ref<RenderSceneBuffersRD> p_render_buffers) = 0;
bool _needs_post_prepass_render(RenderDataRD *p_render_data, bool p_use_gi);
void _post_prepass_render(RenderDataRD *p_render_data, bool p_use_gi);
- void _pre_resolve_render(RenderDataRD *p_render_data, bool p_use_gi);
void _render_buffers_copy_screen_texture(const RenderDataRD *p_render_data);
void _render_buffers_copy_depth_texture(const RenderDataRD *p_render_data);
diff --git a/servers/rendering/renderer_rd/shaders/effects/fsr2/SCsub b/servers/rendering/renderer_rd/shaders/effects/fsr2/SCsub
index f06a2d86e2..5b8bbc343b 100644
--- a/servers/rendering/renderer_rd/shaders/effects/fsr2/SCsub
+++ b/servers/rendering/renderer_rd/shaders/effects/fsr2/SCsub
@@ -6,6 +6,11 @@ if "RD_GLSL" in env["BUILDERS"]:
# find all include files
gl_include_files = [str(f) for f in Glob("*_inc.glsl")] + [str(f) for f in Glob("../*_inc.glsl")]
+ # Add all FSR2 shader and header files.
+ fsr2_dir = "#thirdparty/amd-fsr2/shaders"
+ gl_include_files += [str(f) for f in Glob(fsr2_dir + "/*.h")]
+ gl_include_files += [str(f) for f in Glob(fsr2_dir + "/*.glsl")]
+
# find all shader code(all glsl files excluding our include files)
glsl_files = [str(f) for f in Glob("*.glsl") if str(f) not in gl_include_files]
diff --git a/servers/rendering/renderer_rd/shaders/effects/specular_merge.glsl b/servers/rendering/renderer_rd/shaders/effects/specular_merge.glsl
index db710b7cdd..e87f644bb0 100644
--- a/servers/rendering/renderer_rd/shaders/effects/specular_merge.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/specular_merge.glsl
@@ -30,7 +30,7 @@ void main() {
vec2 base_arr[3] = vec2[](vec2(-1.0, -1.0), vec2(-1.0, 3.0), vec2(3.0, -1.0));
gl_Position = vec4(base_arr[gl_VertexIndex], 0.0, 1.0);
uv_interp.xy = clamp(gl_Position.xy, vec2(0.0, 0.0), vec2(1.0, 1.0)) * 2.0; // saturate(x) * 2.0
-#ifdef MULTIVIEW
+#ifdef USE_MULTIVIEW
uv_interp.z = ViewIndex;
#endif
}
diff --git a/servers/rendering/renderer_rd/storage_rd/light_storage.cpp b/servers/rendering/renderer_rd/storage_rd/light_storage.cpp
index 5f4bf6c8ed..21c6425a87 100644
--- a/servers/rendering/renderer_rd/storage_rd/light_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/light_storage.cpp
@@ -996,15 +996,15 @@ void LightStorage::update_light_buffers(RenderDataRD *p_render_data, const Paged
//update without barriers
if (omni_light_count) {
- RD::get_singleton()->buffer_update(omni_light_buffer, 0, sizeof(LightData) * omni_light_count, omni_lights, RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_COMPUTE);
+ RD::get_singleton()->buffer_update(omni_light_buffer, 0, sizeof(LightData) * omni_light_count, omni_lights);
}
if (spot_light_count) {
- RD::get_singleton()->buffer_update(spot_light_buffer, 0, sizeof(LightData) * spot_light_count, spot_lights, RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_COMPUTE);
+ RD::get_singleton()->buffer_update(spot_light_buffer, 0, sizeof(LightData) * spot_light_count, spot_lights);
}
if (r_directional_light_count) {
- RD::get_singleton()->buffer_update(directional_light_buffer, 0, sizeof(DirectionalLightData) * r_directional_light_count, directional_lights, RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_COMPUTE);
+ RD::get_singleton()->buffer_update(directional_light_buffer, 0, sizeof(DirectionalLightData) * r_directional_light_count, directional_lights);
}
}
@@ -1722,7 +1722,7 @@ void LightStorage::update_reflection_probe_buffer(RenderDataRD *p_render_data, c
}
if (reflection_count) {
- RD::get_singleton()->buffer_update(reflection_buffer, 0, reflection_count * sizeof(ReflectionData), reflections, RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_COMPUTE);
+ RD::get_singleton()->buffer_update(reflection_buffer, 0, reflection_count * sizeof(ReflectionData), reflections);
}
}
diff --git a/servers/rendering/renderer_rd/storage_rd/material_storage.cpp b/servers/rendering/renderer_rd/storage_rd/material_storage.cpp
index 2e8c9d7f8e..1c3076b128 100644
--- a/servers/rendering/renderer_rd/storage_rd/material_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/material_storage.cpp
@@ -986,7 +986,7 @@ void MaterialStorage::MaterialData::free_parameters_uniform_set(RID p_uniform_se
}
}
-bool MaterialStorage::MaterialData::update_parameters_uniform_set(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty, const HashMap<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const Vector<ShaderCompiler::GeneratedCode::Texture> &p_texture_uniforms, const HashMap<StringName, HashMap<int, RID>> &p_default_texture_params, uint32_t p_ubo_size, RID &uniform_set, RID p_shader, uint32_t p_shader_uniform_set, bool p_use_linear_color, bool p_3d_material, uint32_t p_barrier) {
+bool MaterialStorage::MaterialData::update_parameters_uniform_set(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty, const HashMap<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const Vector<ShaderCompiler::GeneratedCode::Texture> &p_texture_uniforms, const HashMap<StringName, HashMap<int, RID>> &p_default_texture_params, uint32_t p_ubo_size, RID &uniform_set, RID p_shader, uint32_t p_shader_uniform_set, bool p_use_linear_color, bool p_3d_material) {
if ((uint32_t)ubo_data.size() != p_ubo_size) {
p_uniform_dirty = true;
if (uniform_buffer.is_valid()) {
@@ -1011,7 +1011,7 @@ bool MaterialStorage::MaterialData::update_parameters_uniform_set(const HashMap<
//check whether buffer changed
if (p_uniform_dirty && ubo_data.size()) {
update_uniform_buffer(p_uniforms, p_uniform_offsets, p_parameters, ubo_data.ptrw(), ubo_data.size(), p_use_linear_color);
- RD::get_singleton()->buffer_update(uniform_buffer, 0, ubo_data.size(), ubo_data.ptrw(), p_barrier);
+ RD::get_singleton()->buffer_update(uniform_buffer, 0, ubo_data.size(), ubo_data.ptrw());
}
uint32_t tex_uniform_count = 0U;
diff --git a/servers/rendering/renderer_rd/storage_rd/material_storage.h b/servers/rendering/renderer_rd/storage_rd/material_storage.h
index 403fd286b4..fe769a778d 100644
--- a/servers/rendering/renderer_rd/storage_rd/material_storage.h
+++ b/servers/rendering/renderer_rd/storage_rd/material_storage.h
@@ -87,7 +87,7 @@ public:
virtual ~MaterialData();
//to be used internally by update_parameters, in the most common configuration of material parameters
- bool update_parameters_uniform_set(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty, const HashMap<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const Vector<ShaderCompiler::GeneratedCode::Texture> &p_texture_uniforms, const HashMap<StringName, HashMap<int, RID>> &p_default_texture_params, uint32_t p_ubo_size, RID &r_uniform_set, RID p_shader, uint32_t p_shader_uniform_set, bool p_use_linear_color, bool p_3d_material, uint32_t p_barrier = RD::BARRIER_MASK_ALL_BARRIERS);
+ bool update_parameters_uniform_set(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty, const HashMap<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const Vector<ShaderCompiler::GeneratedCode::Texture> &p_texture_uniforms, const HashMap<StringName, HashMap<int, RID>> &p_default_texture_params, uint32_t p_ubo_size, RID &r_uniform_set, RID p_shader, uint32_t p_shader_uniform_set, bool p_use_linear_color, bool p_3d_material);
void free_parameters_uniform_set(RID p_uniform_set);
private:
diff --git a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp
index 876bdf5c71..b97ce2d006 100644
--- a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp
@@ -657,7 +657,8 @@ AABB MeshStorage::mesh_get_aabb(RID p_mesh, RID p_skeleton) {
Skeleton *skeleton = skeleton_owner.get_or_null(p_skeleton);
- if (!skeleton || skeleton->size == 0 || mesh->skeleton_aabb_version == skeleton->version) {
+ // A mesh can be shared by multiple skeletons and we need to avoid using the AABB from a different skeleton.
+ if (!skeleton || skeleton->size == 0 || (mesh->skeleton_aabb_version == skeleton->version && mesh->skeleton_aabb_rid == p_skeleton)) {
return mesh->aabb;
}
@@ -763,6 +764,7 @@ AABB MeshStorage::mesh_get_aabb(RID p_mesh, RID p_skeleton) {
mesh->aabb = aabb;
mesh->skeleton_aabb_version = skeleton->version;
+ mesh->skeleton_aabb_rid = p_skeleton;
return aabb;
}
@@ -1456,8 +1458,7 @@ void MeshStorage::_multimesh_enable_motion_vectors(MultiMesh *multimesh) {
if (multimesh->buffer_set && multimesh->data_cache.is_empty()) {
// If the buffer was set but there's no data cached in the CPU, we copy the buffer directly on the GPU.
- RD::get_singleton()->barrier();
- RD::get_singleton()->buffer_copy(multimesh->buffer, new_buffer, 0, 0, buffer_size, RD::BARRIER_MASK_NO_BARRIER);
+ RD::get_singleton()->buffer_copy(multimesh->buffer, new_buffer, 0, 0, buffer_size);
RD::get_singleton()->buffer_copy(multimesh->buffer, new_buffer, 0, buffer_size, buffer_size);
} else if (!multimesh->data_cache.is_empty()) {
// Simply upload the data cached in the CPU, which should already be doubled in size.
@@ -2035,10 +2036,9 @@ void MeshStorage::_update_dirty_multimeshes() {
uint32_t offset = i * region_size;
uint32_t size = multimesh->stride_cache * (uint32_t)multimesh->instances * (uint32_t)sizeof(float);
uint32_t region_start_index = multimesh->stride_cache * MULTIMESH_DIRTY_REGION_SIZE * i;
- RD::get_singleton()->buffer_update(multimesh->buffer, buffer_offset * sizeof(float) + offset, MIN(region_size, size - offset), &data[region_start_index], RD::BARRIER_MASK_NO_BARRIER);
+ RD::get_singleton()->buffer_update(multimesh->buffer, buffer_offset * sizeof(float) + offset, MIN(region_size, size - offset), &data[region_start_index]);
}
}
- RD::get_singleton()->barrier(RD::BARRIER_MASK_NO_BARRIER, RD::BARRIER_MASK_ALL_BARRIERS);
}
memcpy(multimesh->previous_data_cache_dirty_regions, multimesh->data_cache_dirty_regions, data_cache_dirty_region_count * sizeof(bool));
diff --git a/servers/rendering/renderer_rd/storage_rd/mesh_storage.h b/servers/rendering/renderer_rd/storage_rd/mesh_storage.h
index 0fc1a6f320..a1e2ffcf7e 100644
--- a/servers/rendering/renderer_rd/storage_rd/mesh_storage.h
+++ b/servers/rendering/renderer_rd/storage_rd/mesh_storage.h
@@ -153,6 +153,7 @@ private:
AABB aabb;
AABB custom_aabb;
uint64_t skeleton_aabb_version = 0;
+ RID skeleton_aabb_rid;
Vector<RID> material_cache;
diff --git a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp
index 3d3cb585ac..a854e78f53 100644
--- a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp
@@ -307,6 +307,11 @@ void ParticlesStorage::_particles_free_data(Particles *particles) {
particles->emission_storage_buffer = RID();
}
+ if (particles->unused_storage_buffer.is_valid()) {
+ RD::get_singleton()->free(particles->unused_storage_buffer);
+ particles->unused_storage_buffer = RID();
+ }
+
if (RD::get_singleton()->uniform_set_is_valid(particles->particles_material_uniform_set)) {
//will need to be re-created
RD::get_singleton()->free(particles->particles_material_uniform_set);
@@ -530,6 +535,12 @@ void ParticlesStorage::_particles_allocate_emission_buffer(Particles *particles)
}
}
+void ParticlesStorage::_particles_ensure_unused_buffer(Particles *particles) {
+ if (particles->unused_storage_buffer.is_null()) {
+ particles->unused_storage_buffer = RD::get_singleton()->storage_buffer_create(sizeof(uint32_t) * 4);
+ }
+}
+
void ParticlesStorage::particles_set_subemitter(RID p_particles, RID p_subemitter_particles) {
Particles *particles = particles_owner.get_or_null(p_particles);
ERR_FAIL_NULL(particles);
@@ -757,7 +768,8 @@ void ParticlesStorage::_particles_process(Particles *p_particles, double p_delta
if (p_particles->emission_storage_buffer.is_valid()) {
u.append_id(p_particles->emission_storage_buffer);
} else {
- u.append_id(MeshStorage::get_singleton()->get_default_rd_storage_buffer());
+ _particles_ensure_unused_buffer(p_particles);
+ u.append_id(p_particles->unused_storage_buffer);
}
uniforms.push_back(u);
}
@@ -772,7 +784,8 @@ void ParticlesStorage::_particles_process(Particles *p_particles, double p_delta
}
u.append_id(sub_emitter->emission_storage_buffer);
} else {
- u.append_id(MeshStorage::get_singleton()->get_default_rd_storage_buffer());
+ _particles_ensure_unused_buffer(p_particles);
+ u.append_id(p_particles->unused_storage_buffer);
}
uniforms.push_back(u);
}
@@ -1463,7 +1476,8 @@ void ParticlesStorage::update_particles() {
if (particles->trail_bind_pose_buffer.is_valid()) {
u.append_id(particles->trail_bind_pose_buffer);
} else {
- u.append_id(MeshStorage::get_singleton()->get_default_rd_storage_buffer());
+ _particles_ensure_unused_buffer(particles);
+ u.append_id(particles->unused_storage_buffer);
}
uniforms.push_back(u);
}
diff --git a/servers/rendering/renderer_rd/storage_rd/particles_storage.h b/servers/rendering/renderer_rd/storage_rd/particles_storage.h
index a28d7b4154..33f44f3045 100644
--- a/servers/rendering/renderer_rd/storage_rd/particles_storage.h
+++ b/servers/rendering/renderer_rd/storage_rd/particles_storage.h
@@ -247,6 +247,8 @@ private:
ParticleEmissionBuffer *emission_buffer = nullptr;
RID emission_storage_buffer;
+ RID unused_storage_buffer;
+
HashSet<RID> collisions;
Dependency dependency;
@@ -263,6 +265,7 @@ private:
void _particles_process(Particles *p_particles, double p_delta);
void _particles_allocate_emission_buffer(Particles *particles);
+ void _particles_ensure_unused_buffer(Particles *particles);
void _particles_free_data(Particles *particles);
void _particles_update_buffers(Particles *particles);
diff --git a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp
index 6a99eb4108..c338dd0377 100644
--- a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp
@@ -151,6 +151,14 @@ void RenderSceneBuffersRD::configure(const RenderSceneBuffersConfiguration *p_co
// cleanout any old buffers we had.
cleanup();
+ // At least one of these is required to be supported.
+ RenderingDeviceCommons::DataFormat preferred_format[2] = { RD::DATA_FORMAT_D24_UNORM_S8_UINT, RD::DATA_FORMAT_D32_SFLOAT_S8_UINT };
+ if (can_be_storage) {
+ // Prefer higher precision on desktop.
+ preferred_format[0] = RD::DATA_FORMAT_D32_SFLOAT_S8_UINT;
+ preferred_format[1] = RD::DATA_FORMAT_D24_UNORM_S8_UINT;
+ }
+
// create our 3D render buffers
{
// Create our color buffer(s)
@@ -174,7 +182,7 @@ void RenderSceneBuffersRD::configure(const RenderSceneBuffersConfiguration *p_co
if (msaa_3d == RS::VIEWPORT_MSAA_DISABLED) {
usage_bits |= RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
- format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D24_UNORM_S8_UINT, usage_bits) ? RD::DATA_FORMAT_D24_UNORM_S8_UINT : RD::DATA_FORMAT_D32_SFLOAT_S8_UINT;
+ format = RD::get_singleton()->texture_is_format_supported_for_usage(preferred_format[0], usage_bits) ? preferred_format[0] : preferred_format[1];
} else {
format = RD::DATA_FORMAT_R32_SFLOAT;
usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | (can_be_storage ? RD::TEXTURE_USAGE_STORAGE_BIT : 0);
@@ -202,7 +210,7 @@ void RenderSceneBuffersRD::configure(const RenderSceneBuffersConfiguration *p_co
create_texture(RB_SCOPE_BUFFERS, RB_TEX_COLOR_MSAA, format, usage_bits, texture_samples);
usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
- format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D24_UNORM_S8_UINT, usage_bits) ? RD::DATA_FORMAT_D24_UNORM_S8_UINT : RD::DATA_FORMAT_D32_SFLOAT_S8_UINT;
+ format = RD::get_singleton()->texture_is_format_supported_for_usage(preferred_format[0], usage_bits) ? preferred_format[0] : preferred_format[1];
create_texture(RB_SCOPE_BUFFERS, RB_TEX_DEPTH_MSAA, format, usage_bits, texture_samples);
}
@@ -330,7 +338,7 @@ RID RenderSceneBuffersRD::create_texture_from_format(const StringName &p_context
return named_texture.texture;
}
-RID RenderSceneBuffersRD::_create_texture_view(const StringName &p_context, const StringName &p_texture_name, const StringName p_view_name, const Ref<RDTextureView> p_view) {
+RID RenderSceneBuffersRD::_create_texture_view(const StringName &p_context, const StringName &p_texture_name, const StringName &p_view_name, const Ref<RDTextureView> p_view) {
RD::TextureView texture_view;
if (p_view.is_valid()) { // only use when supplied, else default.
texture_view = p_view->base;
@@ -339,7 +347,7 @@ RID RenderSceneBuffersRD::_create_texture_view(const StringName &p_context, cons
return create_texture_view(p_context, p_texture_name, p_view_name, texture_view);
}
-RID RenderSceneBuffersRD::create_texture_view(const StringName &p_context, const StringName &p_texture_name, const StringName p_view_name, RD::TextureView p_view) {
+RID RenderSceneBuffersRD::create_texture_view(const StringName &p_context, const StringName &p_texture_name, const StringName &p_view_name, RD::TextureView p_view) {
NTKey view_key(p_context, p_view_name);
// check if this is a known texture
diff --git a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h
index b2946e6bbc..5b8a74de83 100644
--- a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h
+++ b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h
@@ -106,7 +106,7 @@ private:
}
NTKey() {}
- NTKey(const StringName p_context, const StringName p_texture_name) {
+ NTKey(const StringName &p_context, const StringName &p_texture_name) {
context = p_context;
buffer_name = p_texture_name;
}
@@ -196,7 +196,7 @@ public:
bool has_texture(const StringName &p_context, const StringName &p_texture_name) const;
RID create_texture(const StringName &p_context, const StringName &p_texture_name, const RD::DataFormat p_data_format, const uint32_t p_usage_bits, const RD::TextureSamples p_texture_samples = RD::TEXTURE_SAMPLES_1, const Size2i p_size = Size2i(0, 0), const uint32_t p_layers = 0, const uint32_t p_mipmaps = 1, bool p_unique = true);
RID create_texture_from_format(const StringName &p_context, const StringName &p_texture_name, const RD::TextureFormat &p_texture_format, RD::TextureView p_view = RD::TextureView(), bool p_unique = true);
- RID create_texture_view(const StringName &p_context, const StringName &p_texture_name, const StringName p_view_name, RD::TextureView p_view = RD::TextureView());
+ RID create_texture_view(const StringName &p_context, const StringName &p_texture_name, const StringName &p_view_name, RD::TextureView p_view = RD::TextureView());
RID get_texture(const StringName &p_context, const StringName &p_texture_name) const;
const RD::TextureFormat get_texture_format(const StringName &p_context, const StringName &p_texture_name) const;
RID get_texture_slice(const StringName &p_context, const StringName &p_texture_name, const uint32_t p_layer, const uint32_t p_mipmap, const uint32_t p_layers = 1, const uint32_t p_mipmaps = 1);
@@ -310,7 +310,7 @@ public:
private:
RID _create_texture_from_format(const StringName &p_context, const StringName &p_texture_name, const Ref<RDTextureFormat> &p_texture_format, const Ref<RDTextureView> &p_view = Ref<RDTextureView>(), bool p_unique = true);
- RID _create_texture_view(const StringName &p_context, const StringName &p_texture_name, const StringName p_view_name, const Ref<RDTextureView> p_view = Ref<RDTextureView>());
+ RID _create_texture_view(const StringName &p_context, const StringName &p_texture_name, const StringName &p_view_name, const Ref<RDTextureView> p_view = Ref<RDTextureView>());
Ref<RDTextureFormat> _get_texture_format(const StringName &p_context, const StringName &p_texture_name) const;
RID _get_texture_slice_view(const StringName &p_context, const StringName &p_texture_name, const uint32_t p_layer, const uint32_t p_mipmap, const uint32_t p_layers = 1, const uint32_t p_mipmaps = 1, const Ref<RDTextureView> p_view = Ref<RDTextureView>());
diff --git a/servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.cpp b/servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.cpp
index 40891f9a63..f2231664fa 100644
--- a/servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.cpp
@@ -252,7 +252,7 @@ void RenderSceneDataRD::update_ubo(RID p_uniform_buffer, RS::ViewportDebugDraw p
}
uniform_buffer = p_uniform_buffer;
- RD::get_singleton()->buffer_update(uniform_buffer, 0, sizeof(UBODATA), &ubo, RD::BARRIER_MASK_RASTER);
+ RD::get_singleton()->buffer_update(uniform_buffer, 0, sizeof(UBODATA), &ubo);
}
RID RenderSceneDataRD::get_uniform_buffer() {
diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
index 380e325ffa..d8baf260f9 100644
--- a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
@@ -2703,7 +2703,7 @@ void TextureStorage::update_decal_atlas() {
Vector<Color> cc;
cc.push_back(clear_color);
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(mm.fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, cc);
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(mm.fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD, cc);
for (const KeyValue<RID, DecalAtlas::Texture> &E : decal_atlas.textures) {
DecalAtlas::Texture *t = decal_atlas.textures.getptr(E.key);
@@ -2981,7 +2981,7 @@ void TextureStorage::update_decal_buffer(const PagedArray<RID> &p_decals, const
}
if (decal_count > 0) {
- RD::get_singleton()->buffer_update(decal_buffer, 0, sizeof(DecalData) * decal_count, decals, RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_COMPUTE);
+ RD::get_singleton()->buffer_update(decal_buffer, 0, sizeof(DecalData) * decal_count, decals);
}
}
@@ -3384,7 +3384,7 @@ void TextureStorage::render_target_do_msaa_resolve(RID p_render_target) {
if (!rt->msaa_needs_resolve) {
return;
}
- RD::get_singleton()->draw_list_begin(rt->get_framebuffer(), RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
+ RD::get_singleton()->draw_list_begin(rt->get_framebuffer(), RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD);
RD::get_singleton()->draw_list_end();
rt->msaa_needs_resolve = false;
}
@@ -3501,7 +3501,7 @@ void TextureStorage::render_target_do_clear_request(RID p_render_target) {
}
Vector<Color> clear_colors;
clear_colors.push_back(rt->use_hdr ? rt->clear_color.srgb_to_linear() : rt->clear_color);
- RD::get_singleton()->draw_list_begin(rt->get_framebuffer(), RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD, clear_colors);
+ RD::get_singleton()->draw_list_begin(rt->get_framebuffer(), RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, clear_colors);
RD::get_singleton()->draw_list_end();
rt->clear_requested = false;
rt->msaa_needs_resolve = false;
diff --git a/servers/rendering/renderer_viewport.cpp b/servers/rendering/renderer_viewport.cpp
index 97e9694fe1..7a2415442d 100644
--- a/servers/rendering/renderer_viewport.cpp
+++ b/servers/rendering/renderer_viewport.cpp
@@ -754,7 +754,6 @@ void RendererViewport::draw_viewports(bool p_swap_buffers) {
if (blits.size() > 0) {
RSG::rasterizer->blit_render_targets_to_screen(vp->viewport_to_screen, blits.ptr(), blits.size());
}
- RSG::rasterizer->end_frame(true);
} else if (blits.size() > 0) {
if (!blit_to_screen_list.has(vp->viewport_to_screen)) {
blit_to_screen_list[vp->viewport_to_screen] = Vector<BlitToScreen>();
@@ -764,6 +763,7 @@ void RendererViewport::draw_viewports(bool p_swap_buffers) {
blit_to_screen_list[vp->viewport_to_screen].push_back(blits[b]);
}
}
+ RSG::rasterizer->end_viewport(p_swap_buffers && blits.size() > 0);
}
}
} else {
@@ -793,10 +793,10 @@ void RendererViewport::draw_viewports(bool p_swap_buffers) {
Vector<BlitToScreen> blit_to_screen_vec;
blit_to_screen_vec.push_back(blit);
RSG::rasterizer->blit_render_targets_to_screen(vp->viewport_to_screen, blit_to_screen_vec.ptr(), 1);
- RSG::rasterizer->end_frame(true);
} else {
blit_to_screen_list[vp->viewport_to_screen].push_back(blit);
}
+ RSG::rasterizer->end_viewport(p_swap_buffers);
}
}
@@ -823,8 +823,8 @@ void RendererViewport::draw_viewports(bool p_swap_buffers) {
RENDER_TIMESTAMP("< Render Viewports");
- if (p_swap_buffers) {
- //this needs to be called to make screen swapping more efficient
+ if (p_swap_buffers && !blit_to_screen_list.is_empty()) {
+ // This needs to be called to make screen swapping more efficient.
RSG::rasterizer->prepare_for_blitting_render_targets();
for (const KeyValue<int, Vector<BlitToScreen>> &E : blit_to_screen_list) {
diff --git a/servers/rendering/rendering_device.compat.inc b/servers/rendering/rendering_device.compat.inc
index 8e7beda6f3..edc08e972d 100644
--- a/servers/rendering/rendering_device.compat.inc
+++ b/servers/rendering/rendering_device.compat.inc
@@ -34,39 +34,87 @@ RID RenderingDevice::_shader_create_from_bytecode_bind_compat_79606(const Vector
return shader_create_from_bytecode(p_shader_binary, RID());
}
-BitField<RenderingDevice::BarrierMask> RenderingDevice::_convert_barrier_mask_81356(BitField<BarrierMask> p_old_barrier) {
- if (p_old_barrier == 7) {
- return BARRIER_MASK_ALL_BARRIERS;
- } else if (p_old_barrier == 16) {
- return BARRIER_MASK_NO_BARRIER;
- }
+void RenderingDevice::_draw_list_end_bind_compat_81356(BitField<BarrierMask> p_post_barrier) {
+ draw_list_end();
+}
- BitField<BarrierMask> new_barrier;
- if (p_old_barrier & 1) {
- new_barrier.set_flag(BARRIER_MASK_VERTEX);
- }
- if (p_old_barrier & 2) {
- new_barrier.set_flag(BARRIER_MASK_FRAGMENT);
- }
- if (p_old_barrier & 4) {
- new_barrier.set_flag(BARRIER_MASK_COMPUTE);
+void RenderingDevice::_compute_list_end_bind_compat_81356(BitField<BarrierMask> p_post_barrier) {
+ compute_list_end();
+}
+
+void RenderingDevice::_barrier_bind_compat_81356(BitField<BarrierMask> p_from, BitField<BarrierMask> p_to) {
+ // Does nothing.
+}
+
+void RenderingDevice::_draw_list_end_bind_compat_84976(BitField<BarrierMask> p_post_barrier) {
+ draw_list_end();
+}
+
+void RenderingDevice::_compute_list_end_bind_compat_84976(BitField<BarrierMask> p_post_barrier) {
+ compute_list_end();
+}
+
+RenderingDevice::InitialAction RenderingDevice::_convert_initial_action_84976(InitialAction p_old_initial_action) {
+ switch (uint32_t(p_old_initial_action)) {
+ case 0: // INITIAL_ACTION_CLEAR
+ return INITIAL_ACTION_CLEAR;
+ case 1: // INITIAL_ACTION_CLEAR_REGION
+ case 2: // INITIAL_ACTION_CLEAR_REGION_CONTINUE
+ return INITIAL_ACTION_CLEAR;
+ case 3: // INITIAL_ACTION_KEEP
+ return INITIAL_ACTION_LOAD;
+ case 4: // INITIAL_ACTION_DROP
+ return INITIAL_ACTION_DISCARD;
+ case 5: // INITIAL_ACTION_CONTINUE
+ return INITIAL_ACTION_LOAD;
+ default:
+ return INITIAL_ACTION_LOAD;
}
- if (p_old_barrier & 8) {
- new_barrier.set_flag(BARRIER_MASK_TRANSFER);
+}
+
+RenderingDevice::FinalAction RenderingDevice::_convert_final_action_84976(FinalAction p_old_final_action) {
+ switch (uint32_t(p_old_final_action)) {
+ case 0: // FINAL_ACTION_READ
+ return FINAL_ACTION_STORE;
+ case 1: // FINAL_ACTION_DISCARD
+ return FINAL_ACTION_DISCARD;
+ case 2: // FINAL_ACTION_CONTINUE
+ return FINAL_ACTION_STORE;
+ default:
+ return FINAL_ACTION_STORE;
}
- return new_barrier;
}
-void RenderingDevice::_draw_list_end_bind_compat_81356(BitField<BarrierMask> p_post_barrier) {
- draw_list_end(_convert_barrier_mask_81356(p_post_barrier));
+RenderingDevice::DrawListID RenderingDevice::_draw_list_begin_bind_compat_84976(RID p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const TypedArray<RID> &p_storage_textures) {
+ return draw_list_begin(p_framebuffer, _convert_initial_action_84976(p_initial_color_action), _convert_final_action_84976(p_final_color_action), _convert_initial_action_84976(p_initial_depth_action), _convert_final_action_84976(p_final_depth_action), p_clear_color_values, p_clear_depth, p_clear_stencil, p_region);
}
-void RenderingDevice::_compute_list_end_bind_compat_81356(BitField<BarrierMask> p_post_barrier) {
- compute_list_end(_convert_barrier_mask_81356(p_post_barrier));
+RenderingDevice::ComputeListID RenderingDevice::_compute_list_begin_bind_compat_84976(bool p_allow_draw_overlap) {
+ return compute_list_begin();
}
-void RenderingDevice::_barrier_bind_compat_81356(BitField<BarrierMask> p_from, BitField<BarrierMask> p_to) {
- barrier(_convert_barrier_mask_81356(p_from), _convert_barrier_mask_81356(p_to));
+Error RenderingDevice::_buffer_update_bind_compat_84976(RID p_buffer, uint32_t p_offset, uint32_t p_size, const Vector<uint8_t> &p_data, BitField<BarrierMask> p_post_barrier) {
+ return _buffer_update_bind(p_buffer, p_offset, p_size, p_data);
+}
+
+Error RenderingDevice::_buffer_clear_bind_compat_84976(RID p_buffer, uint32_t p_offset, uint32_t p_size, BitField<BarrierMask> p_post_barrier) {
+ return buffer_clear(p_buffer, p_offset, p_size);
+}
+
+Error RenderingDevice::_texture_update_bind_compat_84976(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, BitField<BarrierMask> p_post_barrier) {
+ return texture_update(p_texture, p_layer, p_data);
+}
+
+Error RenderingDevice::_texture_copy_bind_compat_84976(RID p_from_texture, RID p_to_texture, const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_size, uint32_t p_src_mipmap, uint32_t p_dst_mipmap, uint32_t p_src_layer, uint32_t p_dst_layer, BitField<BarrierMask> p_post_barrier) {
+ return texture_copy(p_from_texture, p_to_texture, p_from, p_to, p_size, p_src_mipmap, p_dst_mipmap, p_src_layer, p_dst_layer);
+}
+
+Error RenderingDevice::_texture_clear_bind_compat_84976(RID p_texture, const Color &p_color, uint32_t p_base_mipmap, uint32_t p_mipmaps, uint32_t p_base_layer, uint32_t p_layers, BitField<BarrierMask> p_post_barrier) {
+ return texture_clear(p_texture, p_color, p_base_mipmap, p_mipmaps, p_base_layer, p_layers);
+}
+
+Error RenderingDevice::_texture_resolve_multisample_bind_compat_84976(RID p_from_texture, RID p_to_texture, BitField<BarrierMask> p_post_barrier) {
+ return texture_resolve_multisample(p_from_texture, p_to_texture);
}
void RenderingDevice::_bind_compatibility_methods() {
@@ -74,6 +122,16 @@ void RenderingDevice::_bind_compatibility_methods() {
ClassDB::bind_compatibility_method(D_METHOD("draw_list_end", "post_barrier"), &RenderingDevice::_draw_list_end_bind_compat_81356, DEFVAL(7));
ClassDB::bind_compatibility_method(D_METHOD("compute_list_end", "post_barrier"), &RenderingDevice::_compute_list_end_bind_compat_81356, DEFVAL(7));
ClassDB::bind_compatibility_method(D_METHOD("barrier", "from", "to"), &RenderingDevice::_barrier_bind_compat_81356, DEFVAL(7), DEFVAL(7));
+ ClassDB::bind_compatibility_method(D_METHOD("draw_list_end", "post_barrier"), &RenderingDevice::_draw_list_end_bind_compat_84976, DEFVAL(0x7FFF));
+ ClassDB::bind_compatibility_method(D_METHOD("compute_list_end", "post_barrier"), &RenderingDevice::_compute_list_end_bind_compat_84976, DEFVAL(0x7FFF));
+ ClassDB::bind_compatibility_method(D_METHOD("draw_list_begin", "framebuffer", "initial_color_action", "final_color_action", "initial_depth_action", "final_depth_action", "clear_color_values", "clear_depth", "clear_stencil", "region", "storage_textures"), &RenderingDevice::_draw_list_begin_bind_compat_84976, DEFVAL(Vector<Color>()), DEFVAL(1.0), DEFVAL(0), DEFVAL(Rect2()), DEFVAL(TypedArray<RID>()));
+ ClassDB::bind_compatibility_method(D_METHOD("compute_list_begin", "allow_draw_overlap"), &RenderingDevice::_compute_list_begin_bind_compat_84976, DEFVAL(false));
+ ClassDB::bind_compatibility_method(D_METHOD("buffer_update", "buffer", "offset", "size_bytes", "data", "post_barrier"), &RenderingDevice::_buffer_update_bind_compat_84976, DEFVAL(0x7FFF));
+ ClassDB::bind_compatibility_method(D_METHOD("buffer_clear", "buffer", "offset", "size_bytes", "post_barrier"), &RenderingDevice::_buffer_clear_bind_compat_84976, DEFVAL(0x7FFF));
+ ClassDB::bind_compatibility_method(D_METHOD("texture_update", "texture", "layer", "data", "post_barrier"), &RenderingDevice::_texture_update_bind_compat_84976, DEFVAL(0x7FFF));
+ ClassDB::bind_compatibility_method(D_METHOD("texture_copy", "from_texture", "to_texture", "from_pos", "to_pos", "size", "src_mipmap", "dst_mipmap", "src_layer", "dst_layer", "post_barrier"), &RenderingDevice::_texture_copy_bind_compat_84976, DEFVAL(0x7FFF));
+ ClassDB::bind_compatibility_method(D_METHOD("texture_clear", "texture", "color", "base_mipmap", "mipmap_count", "base_layer", "layer_count", "post_barrier"), &RenderingDevice::_texture_clear_bind_compat_84976, DEFVAL(0x7FFF));
+ ClassDB::bind_compatibility_method(D_METHOD("texture_resolve_multisample", "from_texture", "to_texture", "post_barrier"), &RenderingDevice::_texture_resolve_multisample_bind_compat_84976, DEFVAL(0x7FFF));
}
#endif
diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp
index 30bf47a096..8e03796d33 100644
--- a/servers/rendering/rendering_device.cpp
+++ b/servers/rendering/rendering_device.cpp
@@ -37,7 +37,26 @@
#include "core/io/dir_access.h"
#include "servers/rendering/renderer_rd/api_context_rd.h"
-//#define FORCE_FULL_BARRIER
+// When true, the command graph will attempt to reorder the rendering commands submitted by the user based on the dependencies detected from
+// the commands automatically. This should improve rendering performance in most scenarios at the cost of some extra CPU overhead.
+//
+// This behavior can be disabled if it's suspected that the graph is not detecting dependencies correctly and more control over the order of
+// the commands is desired (e.g. debugging).
+
+#define RENDER_GRAPH_REORDER 1
+
+// Synchronization barriers are issued between the graph's levels only with the necessary amount of detail to achieve the correct result. If
+// it's suspected that the graph is not doing this correctly, full barriers can be issued instead that will block all types of operations
+// between the synchronization levels. This setting will have a very negative impact on performance when enabled, so it's only intended for
+// debugging purposes.
+
+#define RENDER_GRAPH_FULL_BARRIERS 0
+
+// The command graph can automatically issue secondary command buffers and record them on background threads when they reach an arbitrary
+// size threshold. This can be very beneficial towards reducing the time the main thread takes to record all the rendering commands. However,
+// this setting is not enabled by default as it's been shown to cause some strange issues with certain IHVs that have yet to be understood.
+
+#define SECONDARY_COMMAND_BUFFERS_PER_FRAME 0
RenderingDevice *RenderingDevice::singleton = nullptr;
@@ -131,127 +150,23 @@ RID RenderingDevice::shader_create_from_spirv(const Vector<ShaderStageSPIRVData>
return shader_create_from_bytecode(bytecode);
}
-/******************/
-/**** BARRIERS ****/
-/******************/
-
-void RenderingDevice::_full_barrier(bool p_sync_with_draw) {
- // Used for debug.
-
- RDD::MemoryBarrier mb;
- mb.src_access = (RDD::BARRIER_ACCESS_INDIRECT_COMMAND_READ_BIT |
- RDD::BARRIER_ACCESS_INDEX_READ_BIT |
- RDD::BARRIER_ACCESS_VERTEX_ATTRIBUTE_READ_BIT |
- RDD::BARRIER_ACCESS_UNIFORM_READ_BIT |
- RDD::BARRIER_ACCESS_INPUT_ATTACHMENT_READ_BIT |
- RDD::BARRIER_ACCESS_SHADER_READ_BIT |
- RDD::BARRIER_ACCESS_SHADER_WRITE_BIT |
- RDD::BARRIER_ACCESS_COLOR_ATTACHMENT_READ_BIT |
- RDD::BARRIER_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
- RDD::BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
- RDD::BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
- RDD::BARRIER_ACCESS_TRANSFER_READ_BIT |
- RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT |
- RDD::BARRIER_ACCESS_HOST_READ_BIT |
- RDD::BARRIER_ACCESS_HOST_WRITE_BIT);
- mb.dst_access = (RDD::BARRIER_ACCESS_INDIRECT_COMMAND_READ_BIT |
- RDD::BARRIER_ACCESS_INDEX_READ_BIT |
- RDD::BARRIER_ACCESS_VERTEX_ATTRIBUTE_READ_BIT |
- RDD::BARRIER_ACCESS_UNIFORM_READ_BIT |
- RDD::BARRIER_ACCESS_INPUT_ATTACHMENT_READ_BIT |
- RDD::BARRIER_ACCESS_SHADER_READ_BIT |
- RDD::BARRIER_ACCESS_SHADER_WRITE_BIT |
- RDD::BARRIER_ACCESS_COLOR_ATTACHMENT_READ_BIT |
- RDD::BARRIER_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
- RDD::BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
- RDD::BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
- RDD::BARRIER_ACCESS_TRANSFER_READ_BIT |
- RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT |
- RDD::BARRIER_ACCESS_HOST_READ_BIT |
- RDD::BARRIER_ACCESS_HOST_WRITE_BIT);
-
- RDD::CommandBufferID cmd_buffer = p_sync_with_draw ? frames[frame].draw_command_buffer : frames[frame].setup_command_buffer;
- driver->command_pipeline_barrier(cmd_buffer, RDD::PIPELINE_STAGE_ALL_COMMANDS_BIT, RDD::PIPELINE_STAGE_ALL_COMMANDS_BIT, mb, {}, {});
-}
-
/***************************/
/**** BUFFER MANAGEMENT ****/
/***************************/
-RenderingDevice::Buffer *RenderingDevice::_get_buffer_from_owner(RID p_buffer, BitField<RDD::PipelineStageBits> &r_stages, BitField<RDD::BarrierAccessBits> &r_access, BitField<BarrierMask> p_post_barrier) {
+RenderingDevice::Buffer *RenderingDevice::_get_buffer_from_owner(RID p_buffer) {
Buffer *buffer = nullptr;
- r_stages.clear();
- r_access.clear();
if (vertex_buffer_owner.owns(p_buffer)) {
buffer = vertex_buffer_owner.get_or_null(p_buffer);
-
- r_stages.set_flag(RDD::PIPELINE_STAGE_VERTEX_INPUT_BIT);
- r_access.set_flag(RDD::BARRIER_ACCESS_VERTEX_ATTRIBUTE_READ_BIT);
- if (buffer->usage & RDD::BUFFER_USAGE_STORAGE_BIT) {
- if (p_post_barrier.has_flag(BARRIER_MASK_VERTEX)) {
- r_access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
- r_stages.set_flag(RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT);
- }
- if (p_post_barrier.has_flag(BARRIER_MASK_FRAGMENT)) {
- r_access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
- r_stages.set_flag(RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
- }
- if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) {
- r_access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
- r_stages.set_flag(RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT);
- }
- }
} else if (index_buffer_owner.owns(p_buffer)) {
- r_stages.set_flag(RDD::PIPELINE_STAGE_VERTEX_INPUT_BIT);
- r_access.set_flag(RDD::BARRIER_ACCESS_INDEX_READ_BIT);
buffer = index_buffer_owner.get_or_null(p_buffer);
} else if (uniform_buffer_owner.owns(p_buffer)) {
- if (p_post_barrier.has_flag(BARRIER_MASK_VERTEX)) {
- r_stages.set_flag(RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT);
- }
- if (p_post_barrier.has_flag(BARRIER_MASK_FRAGMENT)) {
- r_stages.set_flag(RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
- }
- if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) {
- r_stages.set_flag(RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT);
- }
- r_access.set_flag(RDD::BARRIER_ACCESS_UNIFORM_READ_BIT);
buffer = uniform_buffer_owner.get_or_null(p_buffer);
} else if (texture_buffer_owner.owns(p_buffer)) {
- if (p_post_barrier.has_flag(BARRIER_MASK_VERTEX)) {
- r_stages.set_flag(RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT);
- r_access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT);
- }
- if (p_post_barrier.has_flag(BARRIER_MASK_FRAGMENT)) {
- r_stages.set_flag(RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
- r_access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT);
- }
- if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) {
- r_stages.set_flag(RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT);
- r_access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT);
- }
-
- // FIXME: Broken.
+ DEV_ASSERT(false && "FIXME: Broken.");
//buffer = texture_buffer_owner.get_or_null(p_buffer)->buffer;
} else if (storage_buffer_owner.owns(p_buffer)) {
buffer = storage_buffer_owner.get_or_null(p_buffer);
- if (p_post_barrier.has_flag(BARRIER_MASK_VERTEX)) {
- r_stages.set_flag(RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT);
- r_access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
- }
- if (p_post_barrier.has_flag(BARRIER_MASK_FRAGMENT)) {
- r_stages.set_flag(RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
- r_access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
- }
- if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) {
- r_stages.set_flag(RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT);
- r_access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
- }
-
- if (buffer->usage.has_flag(RDD::BUFFER_USAGE_INDIRECT_BIT)) {
- r_stages.set_flag(RDD::PIPELINE_STAGE_DRAW_INDIRECT_BIT);
- r_access.set_flag(RDD::BARRIER_ACCESS_INDIRECT_COMMAND_READ_BIT);
- }
}
return buffer;
}
@@ -269,10 +184,11 @@ Error RenderingDevice::_insert_staging_block() {
return OK;
}
-Error RenderingDevice::_staging_buffer_allocate(uint32_t p_amount, uint32_t p_required_align, uint32_t &r_alloc_offset, uint32_t &r_alloc_size, bool p_can_segment) {
+Error RenderingDevice::_staging_buffer_allocate(uint32_t p_amount, uint32_t p_required_align, uint32_t &r_alloc_offset, uint32_t &r_alloc_size, StagingRequiredAction &r_required_action, bool p_can_segment) {
// Determine a block to use.
r_alloc_size = p_amount;
+ r_required_action = STAGING_REQUIRED_ACTION_NONE;
while (true) {
r_alloc_offset = 0;
@@ -324,23 +240,7 @@ Error RenderingDevice::_staging_buffer_allocate(uint32_t p_amount, uint32_t p_re
// and this frame is not even done.
// If this is the main thread, it means the user is likely loading a lot of resources at once,.
// Otherwise, the thread should just be blocked until the next frame (currently unimplemented).
-
- if (false) { // Separate thread from render.
-
- //block_until_next_frame()
- continue;
- } else {
- // Flush EVERYTHING including setup commands. IF not immediate, also need to flush the draw commands.
- _flush(true);
-
- // Clear the whole staging buffer.
- for (int i = 0; i < staging_buffer_blocks.size(); i++) {
- staging_buffer_blocks.write[i].frame_used = 0;
- staging_buffer_blocks.write[i].fill_amount = 0;
- }
- // Claim current.
- staging_buffer_blocks.write[staging_buffer_current].frame_used = frames_drawn;
- }
+ r_required_action = STAGING_REQUIRED_ACTION_FLUSH_CURRENT;
}
} else {
@@ -368,28 +268,7 @@ Error RenderingDevice::_staging_buffer_allocate(uint32_t p_amount, uint32_t p_re
// Let's flush older frames.
// The logic here is that if a game is loading a lot of data from the main thread, it will need to be stalled anyway.
// If loading from a separate thread, we can block that thread until next frame when more room is made (not currently implemented, though).
-
- if (false) {
- // Separate thread from render.
- //block_until_next_frame()
- continue; // And try again.
- } else {
- _flush(false);
-
- for (int i = 0; i < staging_buffer_blocks.size(); i++) {
- // Clear all blocks but the ones from this frame.
- int block_idx = (i + staging_buffer_current) % staging_buffer_blocks.size();
- if (staging_buffer_blocks[block_idx].frame_used == frames_drawn) {
- break; // Ok, we reached something from this frame, abort.
- }
-
- staging_buffer_blocks.write[block_idx].frame_used = 0;
- staging_buffer_blocks.write[block_idx].fill_amount = 0;
- }
-
- // Claim for current frame.
- staging_buffer_blocks.write[staging_buffer_current].frame_used = frames_drawn;
- }
+ r_required_action = STAGING_REQUIRED_ACTION_FLUSH_OLDER;
}
}
@@ -402,20 +281,78 @@ Error RenderingDevice::_staging_buffer_allocate(uint32_t p_amount, uint32_t p_re
return OK;
}
-Error RenderingDevice::_buffer_update(Buffer *p_buffer, size_t p_offset, const uint8_t *p_data, size_t p_data_size, bool p_use_draw_command_buffer, uint32_t p_required_align) {
+void RenderingDevice::_staging_buffer_execute_required_action(StagingRequiredAction p_required_action) {
+ switch (p_required_action) {
+ case STAGING_REQUIRED_ACTION_NONE: {
+ // Do nothing.
+ } break;
+ case STAGING_REQUIRED_ACTION_FLUSH_CURRENT: {
+ // Flush EVERYTHING including setup commands. IF not immediate, also need to flush the draw commands.
+ _flush(true);
+
+ // Clear the whole staging buffer.
+ for (int i = 0; i < staging_buffer_blocks.size(); i++) {
+ staging_buffer_blocks.write[i].frame_used = 0;
+ staging_buffer_blocks.write[i].fill_amount = 0;
+ }
+
+ // Claim for current frame.
+ staging_buffer_blocks.write[staging_buffer_current].frame_used = frames_drawn;
+ } break;
+ case STAGING_REQUIRED_ACTION_FLUSH_OLDER: {
+ _flush(false);
+
+ for (int i = 0; i < staging_buffer_blocks.size(); i++) {
+ // Clear all blocks but the ones from this frame.
+ int block_idx = (i + staging_buffer_current) % staging_buffer_blocks.size();
+ if (staging_buffer_blocks[block_idx].frame_used == frames_drawn) {
+ break; // Ok, we reached something from this frame, abort.
+ }
+
+ staging_buffer_blocks.write[block_idx].frame_used = 0;
+ staging_buffer_blocks.write[block_idx].fill_amount = 0;
+ }
+
+ // Claim for current frame.
+ staging_buffer_blocks.write[staging_buffer_current].frame_used = frames_drawn;
+ } break;
+ default: {
+ DEV_ASSERT(false && "Unknown required action.");
+ } break;
+ }
+}
+
+Error RenderingDevice::_buffer_update(Buffer *p_buffer, RID p_buffer_id, size_t p_offset, const uint8_t *p_data, size_t p_data_size, bool p_use_draw_queue, uint32_t p_required_align) {
// Submitting may get chunked for various reasons, so convert this to a task.
size_t to_submit = p_data_size;
size_t submit_from = 0;
+ thread_local LocalVector<RDG::RecordedBufferCopy> command_buffer_copies_vector;
+ command_buffer_copies_vector.clear();
+
while (to_submit > 0) {
uint32_t block_write_offset;
uint32_t block_write_amount;
+ StagingRequiredAction required_action;
- Error err = _staging_buffer_allocate(MIN(to_submit, staging_buffer_block_size), p_required_align, block_write_offset, block_write_amount);
+ Error err = _staging_buffer_allocate(MIN(to_submit, staging_buffer_block_size), p_required_align, block_write_offset, block_write_amount, required_action);
if (err) {
return err;
}
+ if (p_use_draw_queue && !command_buffer_copies_vector.is_empty() && required_action == STAGING_REQUIRED_ACTION_FLUSH_CURRENT) {
+ if (_buffer_make_mutable(p_buffer, p_buffer_id)) {
+ // The buffer must be mutable to be used as a copy destination.
+ draw_graph.add_synchronization();
+ }
+
+ // If we're using the draw queue and the staging buffer requires flushing everything, we submit the command early and clear the current vector.
+ draw_graph.add_buffer_update(p_buffer->driver_id, p_buffer->draw_tracker, command_buffer_copies_vector);
+ command_buffer_copies_vector.clear();
+ }
+
+ _staging_buffer_execute_required_action(required_action);
+
// Map staging buffer (It's CPU and coherent).
uint8_t *data_ptr = driver->buffer_map(staging_buffer_blocks[staging_buffer_current].driver_id);
ERR_FAIL_NULL_V(data_ptr, ERR_CANT_CREATE);
@@ -427,12 +364,19 @@ Error RenderingDevice::_buffer_update(Buffer *p_buffer, size_t p_offset, const u
driver->buffer_unmap(staging_buffer_blocks[staging_buffer_current].driver_id);
// Insert a command to copy this.
-
RDD::BufferCopyRegion region;
region.src_offset = block_write_offset;
region.dst_offset = submit_from + p_offset;
region.size = block_write_amount;
- driver->command_copy_buffer(p_use_draw_command_buffer ? frames[frame].draw_command_buffer : frames[frame].setup_command_buffer, staging_buffer_blocks[staging_buffer_current].driver_id, p_buffer->driver_id, region);
+
+ if (p_use_draw_queue) {
+ RDG::RecordedBufferCopy buffer_copy;
+ buffer_copy.source = staging_buffer_blocks[staging_buffer_current].driver_id;
+ buffer_copy.region = region;
+ command_buffer_copies_vector.push_back(buffer_copy);
+ } else {
+ driver->command_copy_buffer(frames[frame].setup_command_buffer, staging_buffer_blocks[staging_buffer_current].driver_id, p_buffer->driver_id, region);
+ }
staging_buffer_blocks.write[staging_buffer_current].fill_amount = block_write_offset + block_write_amount;
@@ -440,10 +384,19 @@ Error RenderingDevice::_buffer_update(Buffer *p_buffer, size_t p_offset, const u
submit_from += block_write_amount;
}
+ if (p_use_draw_queue && !command_buffer_copies_vector.is_empty()) {
+ if (_buffer_make_mutable(p_buffer, p_buffer_id)) {
+ // The buffer must be mutable to be used as a copy destination.
+ draw_graph.add_synchronization();
+ }
+
+ draw_graph.add_buffer_update(p_buffer->driver_id, p_buffer->draw_tracker, command_buffer_copies_vector);
+ }
+
return OK;
}
-Error RenderingDevice::buffer_copy(RID p_src_buffer, RID p_dst_buffer, uint32_t p_src_offset, uint32_t p_dst_offset, uint32_t p_size, BitField<BarrierMask> p_post_barrier) {
+Error RenderingDevice::buffer_copy(RID p_src_buffer, RID p_dst_buffer, uint32_t p_src_offset, uint32_t p_dst_offset, uint32_t p_size) {
_THREAD_SAFE_METHOD_
ERR_FAIL_COND_V_MSG(draw_list, ERR_INVALID_PARAMETER,
@@ -451,25 +404,12 @@ Error RenderingDevice::buffer_copy(RID p_src_buffer, RID p_dst_buffer, uint32_t
ERR_FAIL_COND_V_MSG(compute_list, ERR_INVALID_PARAMETER,
"Copying buffers is forbidden during creation of a compute list");
- // This method assumes the barriers have been pushed prior to being called, therefore no barriers are pushed
- // for the source or destination buffers before performing the copy. These masks are effectively ignored.
- BitField<RDD::PipelineStageBits> src_stages;
- BitField<RDD::BarrierAccessBits> src_access;
- Buffer *src_buffer = _get_buffer_from_owner(p_src_buffer, src_stages, src_access, BARRIER_MASK_NO_BARRIER);
+ Buffer *src_buffer = _get_buffer_from_owner(p_src_buffer);
if (!src_buffer) {
ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Source buffer argument is not a valid buffer of any type.");
}
- BitField<RDD::PipelineStageBits> dst_stages;
- BitField<RDD::BarrierAccessBits> dst_access;
- if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) {
- // If the post barrier mask defines it, we indicate the destination buffer will require a barrier with these flags set
- // after the copy command is queued.
- dst_stages.set_flag(RDD::PIPELINE_STAGE_TRANSFER_BIT);
- dst_access.set_flag(RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT);
- }
-
- Buffer *dst_buffer = _get_buffer_from_owner(p_dst_buffer, dst_stages, dst_access, p_post_barrier);
+ Buffer *dst_buffer = _get_buffer_from_owner(p_dst_buffer);
if (!dst_buffer) {
ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Destination buffer argument is not a valid buffer of any type.");
}
@@ -483,31 +423,18 @@ Error RenderingDevice::buffer_copy(RID p_src_buffer, RID p_dst_buffer, uint32_t
region.src_offset = p_src_offset;
region.dst_offset = p_dst_offset;
region.size = p_size;
- driver->command_copy_buffer(frames[frame].draw_command_buffer, src_buffer->driver_id, dst_buffer->driver_id, region);
-#ifdef FORCE_FULL_BARRIER
- _full_barrier(true);
-#else
- if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS) && p_post_barrier != RD::BARRIER_MASK_NO_BARRIER) {
- if (dst_stages.is_empty()) {
- dst_stages = RDD::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
- }
-
- // As indicated by the post barrier mask, push a new barrier.
- RDD::BufferBarrier bb;
- bb.buffer = dst_buffer->driver_id;
- bb.src_access = RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT;
- bb.dst_access = dst_access;
- bb.offset = p_dst_offset;
- bb.size = p_size;
- driver->command_pipeline_barrier(frames[frame].draw_command_buffer, RDD::PIPELINE_STAGE_TRANSFER_BIT, dst_stages, {}, bb, {});
+ if (_buffer_make_mutable(dst_buffer, p_dst_buffer)) {
+ // The destination buffer must be mutable to be used as a copy destination.
+ draw_graph.add_synchronization();
}
-#endif
+
+ draw_graph.add_buffer_copy(src_buffer->driver_id, src_buffer->draw_tracker, dst_buffer->driver_id, dst_buffer->draw_tracker, region);
return OK;
}
-Error RenderingDevice::buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data, BitField<BarrierMask> p_post_barrier) {
+Error RenderingDevice::buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data) {
_THREAD_SAFE_METHOD_
ERR_FAIL_COND_V_MSG(draw_list, ERR_INVALID_PARAMETER,
@@ -515,14 +442,7 @@ Error RenderingDevice::buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p
ERR_FAIL_COND_V_MSG(compute_list, ERR_INVALID_PARAMETER,
"Updating buffers is forbidden during creation of a compute list");
- BitField<RDD::PipelineStageBits> dst_stages;
- BitField<RDD::BarrierAccessBits> dst_access;
- if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) {
- // Protect subsequent updates.
- dst_stages.set_flag(RDD::PIPELINE_STAGE_TRANSFER_BIT);
- dst_access.set_flag(RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT);
- }
- Buffer *buffer = _get_buffer_from_owner(p_buffer, dst_stages, dst_access, p_post_barrier);
+ Buffer *buffer = _get_buffer_from_owner(p_buffer);
if (!buffer) {
ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Buffer argument is not a valid buffer of any type.");
}
@@ -530,33 +450,10 @@ Error RenderingDevice::buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p
ERR_FAIL_COND_V_MSG(p_offset + p_size > buffer->size, ERR_INVALID_PARAMETER,
"Attempted to write buffer (" + itos((p_offset + p_size) - buffer->size) + " bytes) past the end.");
- Error err = _buffer_update(buffer, p_offset, (uint8_t *)p_data, p_size, true);
- if (err) {
- return err;
- }
-
-#ifdef FORCE_FULL_BARRIER
- _full_barrier(true);
-#else
- if (dst_stages.is_empty()) {
- dst_stages.set_flag(RDD::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT);
- }
-
- if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS) && p_post_barrier != RD::BARRIER_MASK_NO_BARRIER) {
- RDD::BufferBarrier bb;
- bb.buffer = buffer->driver_id;
- bb.src_access = RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT;
- bb.dst_access = dst_access;
- bb.offset = p_offset;
- bb.size = p_size;
- driver->command_pipeline_barrier(frames[frame].draw_command_buffer, RDD::PIPELINE_STAGE_TRANSFER_BIT, dst_stages, {}, bb, {});
- }
-
-#endif
- return err;
+ return _buffer_update(buffer, p_buffer, p_offset, (uint8_t *)p_data, p_size, true);
}
-Error RenderingDevice::buffer_clear(RID p_buffer, uint32_t p_offset, uint32_t p_size, BitField<BarrierMask> p_post_barrier) {
+Error RenderingDevice::buffer_clear(RID p_buffer, uint32_t p_offset, uint32_t p_size) {
_THREAD_SAFE_METHOD_
ERR_FAIL_COND_V_MSG((p_size % 4) != 0, ERR_INVALID_PARAMETER,
@@ -566,15 +463,7 @@ Error RenderingDevice::buffer_clear(RID p_buffer, uint32_t p_offset, uint32_t p_
ERR_FAIL_COND_V_MSG(compute_list, ERR_INVALID_PARAMETER,
"Updating buffers is forbidden during creation of a compute list");
- BitField<RDD::PipelineStageBits> dst_stages;
- BitField<RDD::BarrierAccessBits> dst_access;
- if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) {
- // Protect subsequent updates.
- dst_stages.set_flag(RDD::PIPELINE_STAGE_TRANSFER_BIT);
- dst_access.set_flag(RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT);
- }
-
- Buffer *buffer = _get_buffer_from_owner(p_buffer, dst_stages, dst_access, p_post_barrier);
+ Buffer *buffer = _get_buffer_from_owner(p_buffer);
if (!buffer) {
ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Buffer argument is not a valid buffer of any type.");
}
@@ -582,51 +471,24 @@ Error RenderingDevice::buffer_clear(RID p_buffer, uint32_t p_offset, uint32_t p_
ERR_FAIL_COND_V_MSG(p_offset + p_size > buffer->size, ERR_INVALID_PARAMETER,
"Attempted to write buffer (" + itos((p_offset + p_size) - buffer->size) + " bytes) past the end.");
- driver->command_clear_buffer(frames[frame].draw_command_buffer, buffer->driver_id, p_offset, p_size);
-
-#ifdef FORCE_FULL_BARRIER
- _full_barrier(true);
-#else
- if (dst_stages.is_empty()) {
- dst_stages.set_flag(RDD::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT);
+ if (_buffer_make_mutable(buffer, p_buffer)) {
+ // The destination buffer must be mutable to be used as a clear destination.
+ draw_graph.add_synchronization();
}
- if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {
- RDD::BufferBarrier bb;
- bb.buffer = buffer->driver_id;
- bb.src_access = RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT;
- bb.dst_access = dst_access;
- bb.offset = p_offset;
- bb.size = p_size;
- driver->command_pipeline_barrier(frames[frame].draw_command_buffer, RDD::PIPELINE_STAGE_TRANSFER_BIT, dst_stages, {}, bb, {});
- }
+ draw_graph.add_buffer_clear(buffer->driver_id, buffer->draw_tracker, p_offset, p_size);
-#endif
return OK;
}
Vector<uint8_t> RenderingDevice::buffer_get_data(RID p_buffer, uint32_t p_offset, uint32_t p_size) {
_THREAD_SAFE_METHOD_
- // It could be this buffer was just created.
- BitField<RDD::PipelineStageBits> src_stages = RDD::PIPELINE_STAGE_TRANSFER_BIT;
- BitField<RDD::BarrierAccessBits> src_access = RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT;
- // Get the vulkan buffer and the potential stage/access possible.
- Buffer *buffer = _get_buffer_from_owner(p_buffer, src_stages, src_access, BARRIER_MASK_ALL_BARRIERS);
+ Buffer *buffer = _get_buffer_from_owner(p_buffer);
if (!buffer) {
ERR_FAIL_V_MSG(Vector<uint8_t>(), "Buffer is either invalid or this type of buffer can't be retrieved. Only Index and Vertex buffers allow retrieving.");
}
- if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {
- // Make sure no one is using the buffer -- the "true" gets us to the same command buffer as below.
- RDD::BufferBarrier bb;
- bb.buffer = buffer->driver_id;
- bb.src_access = src_access;
- bb.dst_access = RDD::BARRIER_ACCESS_TRANSFER_READ_BIT;
- bb.size = buffer->size;
- driver->command_pipeline_barrier(frames[frame].draw_command_buffer, src_stages, RDD::PIPELINE_STAGE_TRANSFER_BIT, {}, bb, {});
- }
-
// Size of buffer to retrieve.
if (!p_size) {
p_size = buffer->size;
@@ -641,7 +503,9 @@ Vector<uint8_t> RenderingDevice::buffer_get_data(RID p_buffer, uint32_t p_offset
RDD::BufferCopyRegion region;
region.src_offset = p_offset;
region.size = p_size;
- driver->command_copy_buffer(frames[frame].draw_command_buffer, buffer->driver_id, tmp_buffer, region);
+
+ draw_graph.add_buffer_get_data(buffer->driver_id, buffer->draw_tracker, tmp_buffer, region);
+
// Flush everything so memory can be safely mapped.
_flush(true);
@@ -676,23 +540,21 @@ RID RenderingDevice::storage_buffer_create(uint32_t p_size_bytes, const Vector<u
buffer.driver_id = driver->buffer_create(buffer.size, buffer.usage, RDD::MEMORY_ALLOCATION_TYPE_GPU);
ERR_FAIL_COND_V(!buffer.driver_id, RID());
+ // Storage buffers are assumed to be mutable.
+ buffer.draw_tracker = RDG::resource_tracker_create();
+ buffer.draw_tracker->buffer_driver_id = buffer.driver_id;
+
if (p_data.size()) {
- uint64_t data_size = p_data.size();
- const uint8_t *r = p_data.ptr();
- _buffer_update(&buffer, 0, r, data_size);
- if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {
- RDD::BufferBarrier bb;
- bb.buffer = buffer.driver_id;
- bb.src_access = RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT;
- bb.dst_access = (RDD::BARRIER_ACCESS_SHADER_READ_BIT | RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
- bb.size = data_size;
- driver->command_pipeline_barrier(frames[frame].setup_command_buffer, RDD::PIPELINE_STAGE_TRANSFER_BIT, RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT | RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT | RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT, {}, bb, {});
- }
+ _buffer_update(&buffer, RID(), 0, p_data.ptr(), p_data.size());
}
buffer_memory += buffer.size;
- return storage_buffer_owner.make_rid(buffer);
+ RID id = storage_buffer_owner.make_rid(buffer);
+#ifdef DEV_ENABLED
+ set_resource_name(id, "RID:" + itos(id.get_id()));
+#endif
+ return id;
}
RID RenderingDevice::texture_buffer_create(uint32_t p_size_elements, DataFormat p_format, const Vector<uint8_t> &p_data) {
@@ -710,6 +572,12 @@ RID RenderingDevice::texture_buffer_create(uint32_t p_size_elements, DataFormat
texture_buffer.driver_id = driver->buffer_create(size_bytes, usage, RDD::MEMORY_ALLOCATION_TYPE_GPU);
ERR_FAIL_COND_V(!texture_buffer.driver_id, RID());
+ // Texture buffers are assumed to be immutable unless they don't have initial data.
+ if (p_data.is_empty()) {
+ texture_buffer.draw_tracker = RDG::resource_tracker_create();
+ texture_buffer.draw_tracker->buffer_driver_id = texture_buffer.driver_id;
+ }
+
bool ok = driver->buffer_set_texel_format(texture_buffer.driver_id, p_format);
if (!ok) {
driver->buffer_free(texture_buffer.driver_id);
@@ -717,15 +585,7 @@ RID RenderingDevice::texture_buffer_create(uint32_t p_size_elements, DataFormat
}
if (p_data.size()) {
- _buffer_update(&texture_buffer, 0, p_data.ptr(), p_data.size());
- if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {
- RDD::BufferBarrier bb;
- bb.buffer = texture_buffer.driver_id;
- bb.src_access = RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT;
- bb.dst_access = RDD::BARRIER_ACCESS_SHADER_READ_BIT;
- bb.size = size_bytes;
- driver->command_pipeline_barrier(frames[frame].setup_command_buffer, RDD::PIPELINE_STAGE_TRANSFER_BIT, (RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT | RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT | RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT), {}, bb, {});
- }
+ _buffer_update(&texture_buffer, RID(), 0, p_data.ptr(), p_data.size());
}
buffer_memory += size_bytes;
@@ -787,10 +647,8 @@ RID RenderingDevice::texture_create(const TextureFormat &p_format, const Texture
ERR_FAIL_COND_V_MSG(required_mipmaps < format.mipmaps, RID(),
"Too many mipmaps requested for texture format and dimensions (" + itos(format.mipmaps) + "), maximum allowed: (" + itos(required_mipmaps) + ").");
+ uint32_t forced_usage_bits = 0;
if (p_data.size()) {
- ERR_FAIL_COND_V_MSG(!(format.usage_bits & TEXTURE_USAGE_CAN_UPDATE_BIT), RID(),
- "Texture needs the TEXTURE_USAGE_CAN_UPDATE_BIT usage flag in order to be updated at initialization or later");
-
ERR_FAIL_COND_V_MSG(p_data.size() != (int)format.array_layers, RID(),
"Default supplied data for image format is of invalid length (" + itos(p_data.size()) + "), should be (" + itos(format.array_layers) + ").");
@@ -799,6 +657,10 @@ RID RenderingDevice::texture_create(const TextureFormat &p_format, const Texture
ERR_FAIL_COND_V_MSG((uint32_t)p_data[i].size() != required_size, RID(),
"Data for slice index " + itos(i) + " (mapped to layer " + itos(i) + ") differs in size (supplied: " + itos(p_data[i].size()) + ") than what is required by the format (" + itos(required_size) + ").");
}
+
+ if (!(format.usage_bits & TEXTURE_USAGE_CAN_UPDATE_BIT)) {
+ forced_usage_bits = TEXTURE_USAGE_CAN_UPDATE_BIT;
+ }
}
{
@@ -849,7 +711,7 @@ RID RenderingDevice::texture_create(const TextureFormat &p_format, const Texture
// Create.
Texture texture;
-
+ format.usage_bits |= forced_usage_bits;
texture.driver_id = driver->texture_create(format, tv);
ERR_FAIL_COND_V(!texture.driver_id, RID());
texture.type = format.texture_type;
@@ -862,26 +724,10 @@ RID RenderingDevice::texture_create(const TextureFormat &p_format, const Texture
texture.base_mipmap = 0;
texture.base_layer = 0;
texture.is_resolve_buffer = format.is_resolve_buffer;
- texture.usage_flags = format.usage_bits;
+ texture.usage_flags = format.usage_bits & ~forced_usage_bits;
texture.samples = format.samples;
texture.allowed_shared_formats = format.shareable_formats;
-
- // Set base layout based on usage priority.
-
- if ((format.usage_bits & TEXTURE_USAGE_SAMPLING_BIT)) {
- // First priority, readable.
- texture.layout = RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
- } else if ((format.usage_bits & TEXTURE_USAGE_STORAGE_BIT)) {
- // Second priority, storage.
- texture.layout = RDD::TEXTURE_LAYOUT_GENERAL;
- } else if ((format.usage_bits & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT)) {
- // Third priority, color or depth.
- texture.layout = RDD::TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
- } else if ((format.usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
- texture.layout = RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
- } else {
- texture.layout = RDD::TEXTURE_LAYOUT_GENERAL;
- }
+ texture.has_initial_data = !p_data.is_empty();
if ((format.usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
texture.read_aspect_flags.set_flag(RDD::TEXTURE_ASPECT_DEPTH_BIT);
@@ -896,18 +742,10 @@ RID RenderingDevice::texture_create(const TextureFormat &p_format, const Texture
texture.bound = false;
- // Barrier to set layout.
- if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {
- RDD::TextureBarrier tb;
- tb.texture = texture.driver_id;
- tb.dst_access = RDD::BARRIER_ACCESS_SHADER_READ_BIT;
- tb.prev_layout = RDD::TEXTURE_LAYOUT_UNDEFINED;
- tb.next_layout = texture.layout;
- tb.subresources.aspect = texture.barrier_aspect_flags;
- tb.subresources.mipmap_count = format.mipmaps;
- tb.subresources.layer_count = format.array_layers;
-
- driver->command_pipeline_barrier(frames[frame].setup_command_buffer, RDD::PIPELINE_STAGE_TOP_OF_PIPE_BIT, RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT | RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT | RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT, {}, {}, tb);
+ // Textures are only assumed to be immutable if they have initial data and none of the other bits that indicate write usage are enabled.
+ bool texture_mutable_by_default = texture.usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_STORAGE_BIT | TEXTURE_USAGE_STORAGE_ATOMIC_BIT | TEXTURE_USAGE_VRS_ATTACHMENT_BIT);
+ if (p_data.is_empty() || texture_mutable_by_default) {
+ _texture_make_mutable(&texture, RID());
}
texture_memory += driver->texture_get_allocation_size(texture.driver_id);
@@ -919,9 +757,15 @@ RID RenderingDevice::texture_create(const TextureFormat &p_format, const Texture
if (p_data.size()) {
for (uint32_t i = 0; i < p_format.array_layers; i++) {
- _texture_update(id, i, p_data[i], BARRIER_MASK_ALL_BARRIERS, true);
+ _texture_update(id, i, p_data[i], true, false);
+ }
+
+ if (texture.draw_tracker != nullptr) {
+ // Draw tracker can assume the texture will be in transfer destination.
+ texture.draw_tracker->usage = RDG::RESOURCE_USAGE_TRANSFER_TO;
}
}
+
return id;
}
@@ -959,6 +803,12 @@ RID RenderingDevice::texture_create_shared(const TextureView &p_view, RID p_with
texture.driver_id = driver->texture_create_shared(texture.driver_id, tv);
ERR_FAIL_COND_V(!texture.driver_id, RID());
+ texture.slice_trackers.clear();
+
+ if (texture.draw_tracker != nullptr) {
+ texture.draw_tracker->reference_count++;
+ }
+
texture.owner = p_with_texture;
RID id = texture_owner.make_rid(texture);
#ifdef DEV_ENABLED
@@ -988,23 +838,6 @@ RID RenderingDevice::texture_create_from_extension(TextureType p_type, DataForma
texture.allowed_shared_formats.push_back(RD::DATA_FORMAT_R8G8B8A8_UNORM);
texture.allowed_shared_formats.push_back(RD::DATA_FORMAT_R8G8B8A8_SRGB);
- // Set base layout based on usage priority.
-
- if (p_usage.has_flag(TEXTURE_USAGE_SAMPLING_BIT)) {
- // First priority, readable.
- texture.layout = RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
- } else if (p_usage.has_flag(TEXTURE_USAGE_STORAGE_BIT)) {
- // Second priority, storage.
- texture.layout = RDD::TEXTURE_LAYOUT_GENERAL;
- } else if (p_usage.has_flag(TEXTURE_USAGE_COLOR_ATTACHMENT_BIT)) {
- // Third priority, color or depth.
- texture.layout = RDD::TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
- } else if (p_usage.has_flag(TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
- texture.layout = RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
- } else {
- texture.layout = RDD::TEXTURE_LAYOUT_GENERAL;
- }
-
if (p_usage.has_flag(TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
texture.read_aspect_flags.set_flag(RDD::TEXTURE_ASPECT_DEPTH_BIT);
texture.barrier_aspect_flags.set_flag(RDD::TEXTURE_ASPECT_DEPTH_BIT);
@@ -1019,19 +852,7 @@ RID RenderingDevice::texture_create_from_extension(TextureType p_type, DataForma
texture.driver_id = driver->texture_create_from_extension(p_image, p_type, p_format, p_layers, (texture.usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT));
ERR_FAIL_COND_V(!texture.driver_id, RID());
- // Barrier to set layout.
- if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {
- RDD::TextureBarrier tb;
- tb.texture = texture.driver_id;
- tb.dst_access = RDD::BARRIER_ACCESS_SHADER_READ_BIT;
- tb.prev_layout = RDD::TEXTURE_LAYOUT_UNDEFINED;
- tb.next_layout = texture.layout;
- tb.subresources.aspect = texture.barrier_aspect_flags;
- tb.subresources.mipmap_count = texture.mipmaps;
- tb.subresources.layer_count = texture.layers;
-
- driver->command_pipeline_barrier(frames[frame].setup_command_buffer, RDD::PIPELINE_STAGE_TOP_OF_PIPE_BIT, RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT, {}, {}, tb);
- }
+ _texture_make_mutable(&texture, RID());
RID id = texture_owner.make_rid(texture);
#ifdef DEV_ENABLED
@@ -1081,6 +902,7 @@ RID RenderingDevice::texture_create_shared_from_slice(const TextureView &p_view,
}
Texture texture = *src_texture;
+
get_image_format_required_size(texture.format, texture.width, texture.height, texture.depth, p_mipmap + 1, &texture.width, &texture.height);
texture.mipmaps = p_mipmaps;
texture.layers = slice_layers;
@@ -1118,7 +940,17 @@ RID RenderingDevice::texture_create_shared_from_slice(const TextureView &p_view,
texture.driver_id = driver->texture_create_shared_from_slice(src_texture->driver_id, tv, p_slice_type, p_layer, slice_layers, p_mipmap, p_mipmaps);
ERR_FAIL_COND_V(!texture.driver_id, RID());
+ const Rect2i slice_rect(p_mipmap, p_layer, p_mipmaps, slice_layers);
texture.owner = p_with_texture;
+ texture.slice_type = p_slice_type;
+ texture.slice_rect = slice_rect;
+
+ // If parent is mutable, make slice mutable by default.
+ if (src_texture->draw_tracker != nullptr) {
+ texture.draw_tracker = nullptr;
+ _texture_make_mutable(&texture, RID());
+ }
+
RID id = texture_owner.make_rid(texture);
#ifdef DEV_ENABLED
set_resource_name(id, "RID:" + itos(id.get_id()));
@@ -1128,8 +960,8 @@ RID RenderingDevice::texture_create_shared_from_slice(const TextureView &p_view,
return id;
}
-Error RenderingDevice::texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, BitField<BarrierMask> p_post_barrier) {
- return _texture_update(p_texture, p_layer, p_data, p_post_barrier, false);
+Error RenderingDevice::texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data) {
+ return _texture_update(p_texture, p_layer, p_data, false, true);
}
static _ALWAYS_INLINE_ void _copy_region(uint8_t const *__restrict p_src, uint8_t *__restrict p_dst, uint32_t p_src_x, uint32_t p_src_y, uint32_t p_src_w, uint32_t p_src_h, uint32_t p_src_full_w, uint32_t p_dst_pitch, uint32_t p_unit_size) {
@@ -1148,7 +980,7 @@ static _ALWAYS_INLINE_ void _copy_region(uint8_t const *__restrict p_src, uint8_
}
}
-Error RenderingDevice::_texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, BitField<BarrierMask> p_post_barrier, bool p_use_setup_queue) {
+Error RenderingDevice::_texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, bool p_use_setup_queue, bool p_validate_can_update) {
_THREAD_SAFE_METHOD_
ERR_FAIL_COND_V_MSG((draw_list || compute_list) && !p_use_setup_queue, ERR_INVALID_PARAMETER,
@@ -1166,7 +998,7 @@ Error RenderingDevice::_texture_update(RID p_texture, uint32_t p_layer, const Ve
ERR_FAIL_COND_V_MSG(texture->bound, ERR_CANT_ACQUIRE_RESOURCE,
"Texture can't be updated while a draw list that uses it as part of a framebuffer is being created. Ensure the draw list is finalized (and that the color/depth texture using it is not set to `RenderingDevice.FINAL_ACTION_CONTINUE`) to update this texture.");
- ERR_FAIL_COND_V_MSG(!(texture->usage_flags & TEXTURE_USAGE_CAN_UPDATE_BIT), ERR_INVALID_PARAMETER,
+ ERR_FAIL_COND_V_MSG(p_validate_can_update && !(texture->usage_flags & TEXTURE_USAGE_CAN_UPDATE_BIT), ERR_INVALID_PARAMETER,
"Texture requires the `RenderingDevice.TEXTURE_USAGE_CAN_UPDATE_BIT` to be set to be updatable.");
uint32_t layer_count = texture->layers;
@@ -1191,21 +1023,22 @@ Error RenderingDevice::_texture_update(RID p_texture, uint32_t p_layer, const Ve
const uint8_t *r = p_data.ptr();
- RDD::CommandBufferID command_buffer = p_use_setup_queue ? frames[frame].setup_command_buffer : frames[frame].draw_command_buffer;
+ thread_local LocalVector<RDG::RecordedBufferToTextureCopy> command_buffer_to_texture_copies_vector;
+ command_buffer_to_texture_copies_vector.clear();
- // Barrier to transfer.
- if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {
+ if (p_use_setup_queue && driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {
+ // When using the setup queue directly, we transition the texture to the optimal layout.
RDD::TextureBarrier tb;
tb.texture = texture->driver_id;
tb.dst_access = RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT;
- tb.prev_layout = texture->layout;
+ tb.prev_layout = RDD::TEXTURE_LAYOUT_UNDEFINED;
tb.next_layout = RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL;
tb.subresources.aspect = texture->barrier_aspect_flags;
tb.subresources.mipmap_count = texture->mipmaps;
tb.subresources.base_layer = p_layer;
tb.subresources.layer_count = 1;
- driver->command_pipeline_barrier(command_buffer, RDD::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, RDD::PIPELINE_STAGE_TRANSFER_BIT, {}, {}, tb);
+ driver->command_pipeline_barrier(frames[frame].setup_command_buffer, RDD::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, RDD::PIPELINE_STAGE_TRANSFER_BIT, {}, {}, tb);
}
uint32_t mipmap_offset = 0;
@@ -1240,12 +1073,26 @@ Error RenderingDevice::_texture_update(RID p_texture, uint32_t p_layer, const Ve
uint32_t pitch_step = driver->api_trait_get(RDD::API_TRAIT_TEXTURE_DATA_ROW_PITCH_STEP);
region_pitch = STEPIFY(region_pitch, pitch_step);
uint32_t to_allocate = region_pitch * region_h;
-
uint32_t alloc_offset = 0, alloc_size = 0;
- Error err = _staging_buffer_allocate(to_allocate, required_align, alloc_offset, alloc_size, false);
+ StagingRequiredAction required_action;
+ Error err = _staging_buffer_allocate(to_allocate, required_align, alloc_offset, alloc_size, required_action, false);
ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
- uint8_t *write_ptr = nullptr;
+ if (!p_use_setup_queue && !command_buffer_to_texture_copies_vector.is_empty() && required_action == STAGING_REQUIRED_ACTION_FLUSH_CURRENT) {
+ if (_texture_make_mutable(texture, p_texture)) {
+ // The texture must be mutable to be used as a copy destination.
+ draw_graph.add_synchronization();
+ }
+
+ // If we're using the draw queue and the staging buffer requires flushing everything, we submit the command early and clear the current vector.
+ draw_graph.add_texture_update(texture->driver_id, texture->draw_tracker, command_buffer_to_texture_copies_vector);
+ command_buffer_to_texture_copies_vector.clear();
+ }
+
+ _staging_buffer_execute_required_action(required_action);
+
+ uint8_t *write_ptr;
+
{ // Map.
uint8_t *data_ptr = driver->buffer_map(staging_buffer_blocks[staging_buffer_current].driver_id);
ERR_FAIL_NULL_V(data_ptr, ERR_CANT_CREATE);
@@ -1288,7 +1135,14 @@ Error RenderingDevice::_texture_update(RID p_texture, uint32_t p_layer, const Ve
copy_region.texture_offset = Vector3i(x, y, z);
copy_region.texture_region_size = Vector3i(region_logic_w, region_logic_h, 1);
- driver->command_copy_buffer_to_texture(command_buffer, staging_buffer_blocks[staging_buffer_current].driver_id, texture->driver_id, RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL, copy_region);
+ if (p_use_setup_queue) {
+ driver->command_copy_buffer_to_texture(frames[frame].setup_command_buffer, staging_buffer_blocks[staging_buffer_current].driver_id, texture->driver_id, RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL, copy_region);
+ } else {
+ RDG::RecordedBufferToTextureCopy buffer_to_texture_copy;
+ buffer_to_texture_copy.from_buffer = staging_buffer_blocks[staging_buffer_current].driver_id;
+ buffer_to_texture_copy.region = copy_region;
+ command_buffer_to_texture_copies_vector.push_back(buffer_to_texture_copy);
+ }
staging_buffer_blocks.write[staging_buffer_current].fill_amount = alloc_offset + alloc_size;
}
@@ -1300,50 +1154,25 @@ Error RenderingDevice::_texture_update(RID p_texture, uint32_t p_layer, const Ve
logic_height = MAX(1u, logic_height >> 1);
}
- // Barrier to restore layout.
- if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {
- BitField<RDD::PipelineStageBits> stages;
- BitField<RDD::BarrierAccessBits> access;
- if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) {
- stages.set_flag(RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT);
- access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
- }
- if (p_post_barrier.has_flag(BARRIER_MASK_VERTEX)) {
- stages.set_flag(RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT);
- access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
- }
- if (p_post_barrier.has_flag(BARRIER_MASK_FRAGMENT)) {
- stages.set_flag(RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
- access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
- }
- if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) {
- stages.set_flag(RDD::PIPELINE_STAGE_TRANSFER_BIT);
- access.set_flag(RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT);
- }
-
- if (stages.is_empty()) {
- stages.set_flag(RDD::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT);
- }
-
+ if (p_use_setup_queue && (texture->draw_tracker == nullptr) && driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {
+ // If the texture does not have a tracker, it means it must be transitioned to the sampling state.
RDD::TextureBarrier tb;
tb.texture = texture->driver_id;
tb.src_access = RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT;
- tb.dst_access = access;
tb.prev_layout = RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL;
- tb.next_layout = texture->layout;
+ tb.next_layout = RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
tb.subresources.aspect = texture->barrier_aspect_flags;
tb.subresources.mipmap_count = texture->mipmaps;
tb.subresources.base_layer = p_layer;
tb.subresources.layer_count = 1;
-
- driver->command_pipeline_barrier(command_buffer, RDD::PIPELINE_STAGE_TRANSFER_BIT, stages, {}, {}, tb);
-
- if (texture->used_in_frame != frames_drawn) {
- texture->used_in_raster = false;
- texture->used_in_compute = false;
- texture->used_in_frame = frames_drawn;
+ driver->command_pipeline_barrier(frames[frame].setup_command_buffer, RDD::PIPELINE_STAGE_TRANSFER_BIT, RDD::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, {}, {}, tb);
+ } else if (!p_use_setup_queue && !command_buffer_to_texture_copies_vector.is_empty()) {
+ if (_texture_make_mutable(texture, p_texture)) {
+ // The texture must be mutable to be used as a copy destination.
+ draw_graph.add_synchronization();
}
- texture->used_in_transfer = true;
+
+ draw_graph.add_texture_update(texture->driver_id, texture->draw_tracker, command_buffer_to_texture_copies_vector);
}
return OK;
@@ -1455,103 +1284,71 @@ Vector<uint8_t> RenderingDevice::texture_get_data(RID p_texture, uint32_t p_laye
RDD::BufferID tmp_buffer = driver->buffer_create(work_buffer_size, RDD::BUFFER_USAGE_TRANSFER_TO_BIT, RDD::MEMORY_ALLOCATION_TYPE_CPU);
ERR_FAIL_COND_V(!tmp_buffer, Vector<uint8_t>());
- RDD::CommandBufferID command_buffer = frames[frame].draw_command_buffer; // Makes more sense to retrieve.
-
- // Pre-copy barrier.
- if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {
- RDD::TextureBarrier tb;
- tb.texture = tex->driver_id;
- tb.dst_access = RDD::BARRIER_ACCESS_TRANSFER_READ_BIT;
- tb.prev_layout = tex->layout;
- tb.next_layout = RDD::TEXTURE_LAYOUT_TRANSFER_SRC_OPTIMAL;
- tb.subresources.aspect = tex->barrier_aspect_flags;
- tb.subresources.mipmap_count = tex->mipmaps;
- tb.subresources.base_layer = p_layer;
- tb.subresources.layer_count = 1;
-
- driver->command_pipeline_barrier(command_buffer, RDD::PIPELINE_STAGE_TOP_OF_PIPE_BIT, RDD::PIPELINE_STAGE_TRANSFER_BIT, {}, {}, tb);
- }
+ thread_local LocalVector<RDD::BufferTextureCopyRegion> command_buffer_texture_copy_regions_vector;
+ command_buffer_texture_copy_regions_vector.clear();
- {
- uint32_t w = tex->width;
- uint32_t h = tex->height;
- uint32_t d = tex->depth;
- for (uint32_t i = 0; i < tex->mipmaps; i++) {
- RDD::BufferTextureCopyRegion copy_region;
- copy_region.buffer_offset = mip_layouts[i].offset;
- copy_region.texture_subresources.aspect = tex->read_aspect_flags;
- copy_region.texture_subresources.mipmap = i;
- copy_region.texture_subresources.base_layer = p_layer;
- copy_region.texture_subresources.layer_count = 1;
- copy_region.texture_region_size.x = w;
- copy_region.texture_region_size.y = h;
- copy_region.texture_region_size.z = d;
- driver->command_copy_texture_to_buffer(command_buffer, tex->driver_id, RDD::TEXTURE_LAYOUT_TRANSFER_SRC_OPTIMAL, tmp_buffer, copy_region);
-
- w = MAX(1u, w >> 1);
- h = MAX(1u, h >> 1);
- d = MAX(1u, d >> 1);
- }
+ uint32_t w = tex->width;
+ uint32_t h = tex->height;
+ uint32_t d = tex->depth;
+ for (uint32_t i = 0; i < tex->mipmaps; i++) {
+ RDD::BufferTextureCopyRegion copy_region;
+ copy_region.buffer_offset = mip_layouts[i].offset;
+ copy_region.texture_subresources.aspect = tex->read_aspect_flags;
+ copy_region.texture_subresources.mipmap = i;
+ copy_region.texture_subresources.base_layer = p_layer;
+ copy_region.texture_subresources.layer_count = 1;
+ copy_region.texture_region_size.x = w;
+ copy_region.texture_region_size.y = h;
+ copy_region.texture_region_size.z = d;
+ command_buffer_texture_copy_regions_vector.push_back(copy_region);
+
+ w = MAX(1u, w >> 1);
+ h = MAX(1u, h >> 1);
+ d = MAX(1u, d >> 1);
}
- // Post-copy barrier.
- if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {
- RDD::TextureBarrier tb;
- tb.texture = tex->driver_id;
- tb.src_access = RDD::BARRIER_ACCESS_TRANSFER_READ_BIT;
- tb.dst_access = RDD::BARRIER_ACCESS_SHADER_READ_BIT;
- if ((tex->usage_flags & TEXTURE_USAGE_STORAGE_BIT)) {
- tb.dst_access.set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
- }
- tb.prev_layout = RDD::TEXTURE_LAYOUT_TRANSFER_SRC_OPTIMAL;
- tb.next_layout = tex->layout;
- tb.subresources.aspect = tex->barrier_aspect_flags;
- tb.subresources.mipmap_count = tex->mipmaps;
- tb.subresources.base_layer = p_layer;
- tb.subresources.layer_count = 1;
-
- driver->command_pipeline_barrier(command_buffer, RDD::PIPELINE_STAGE_TRANSFER_BIT, RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT | RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT | RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT, {}, {}, tb);
+ if (_texture_make_mutable(tex, p_texture)) {
+ // The texture must be mutable to be used as a copy source due to layout transitions.
+ draw_graph.add_synchronization();
}
+ draw_graph.add_texture_get_data(tex->driver_id, tex->draw_tracker, tmp_buffer, command_buffer_texture_copy_regions_vector);
+
_flush(true);
const uint8_t *read_ptr = driver->buffer_map(tmp_buffer);
ERR_FAIL_NULL_V(read_ptr, Vector<uint8_t>());
Vector<uint8_t> buffer_data;
- {
- uint32_t tight_buffer_size = get_image_format_required_size(tex->format, tex->width, tex->height, tex->depth, tex->mipmaps);
- buffer_data.resize(tight_buffer_size);
-
- uint8_t *write_ptr = buffer_data.ptrw();
-
- uint32_t w = tex->width;
- uint32_t h = tex->height;
- uint32_t d = tex->depth;
- for (uint32_t i = 0; i < tex->mipmaps; i++) {
- uint32_t width = 0, height = 0, depth = 0;
- uint32_t tight_mip_size = get_image_format_required_size(tex->format, w, h, d, 1, &width, &height, &depth);
- uint32_t block_w = 0, block_h = 0;
- get_compressed_image_format_block_dimensions(tex->format, block_w, block_h);
- uint32_t tight_row_pitch = tight_mip_size / ((height / block_h) * depth);
-
- {
- // Copy row-by-row to erase padding due to alignments.
- const uint8_t *rp = read_ptr;
- uint8_t *wp = write_ptr;
- for (uint32_t row = h * d / block_h; row != 0; row--) {
- memcpy(wp, rp, tight_row_pitch);
- rp += mip_layouts[i].row_pitch;
- wp += tight_row_pitch;
- }
- }
+ uint32_t tight_buffer_size = get_image_format_required_size(tex->format, tex->width, tex->height, tex->depth, tex->mipmaps);
+ buffer_data.resize(tight_buffer_size);
+
+ uint8_t *write_ptr = buffer_data.ptrw();
- w = MAX(1u, w >> 1);
- h = MAX(1u, h >> 1);
- d = MAX(1u, d >> 1);
- read_ptr += mip_layouts[i].size;
- write_ptr += tight_mip_size;
+ w = tex->width;
+ h = tex->height;
+ d = tex->depth;
+ for (uint32_t i = 0; i < tex->mipmaps; i++) {
+ uint32_t width = 0, height = 0, depth = 0;
+ uint32_t tight_mip_size = get_image_format_required_size(tex->format, w, h, d, 1, &width, &height, &depth);
+ uint32_t block_w = 0, block_h = 0;
+ get_compressed_image_format_block_dimensions(tex->format, block_w, block_h);
+ uint32_t tight_row_pitch = tight_mip_size / ((height / block_h) * depth);
+
+ // Copy row-by-row to erase padding due to alignments.
+ const uint8_t *rp = read_ptr;
+ uint8_t *wp = write_ptr;
+ for (uint32_t row = h * d / block_h; row != 0; row--) {
+ memcpy(wp, rp, tight_row_pitch);
+ rp += mip_layouts[i].row_pitch;
+ wp += tight_row_pitch;
}
+
+ w = MAX(1u, w >> 1);
+ h = MAX(1u, h >> 1);
+ d = MAX(1u, d >> 1);
+ read_ptr += mip_layouts[i].size;
+ write_ptr += tight_mip_size;
}
driver->buffer_unmap(tmp_buffer);
@@ -1610,7 +1407,7 @@ uint64_t RenderingDevice::texture_get_native_handle(RID p_texture) {
}
#endif
-Error RenderingDevice::texture_copy(RID p_from_texture, RID p_to_texture, const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_size, uint32_t p_src_mipmap, uint32_t p_dst_mipmap, uint32_t p_src_layer, uint32_t p_dst_layer, BitField<BarrierMask> p_post_barrier) {
+Error RenderingDevice::texture_copy(RID p_from_texture, RID p_to_texture, const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_size, uint32_t p_src_mipmap, uint32_t p_dst_mipmap, uint32_t p_src_layer, uint32_t p_dst_layer) {
_THREAD_SAFE_METHOD_
Texture *src_tex = texture_owner.get_or_null(p_from_texture);
@@ -1658,133 +1455,34 @@ Error RenderingDevice::texture_copy(RID p_from_texture, RID p_to_texture, const
ERR_FAIL_COND_V_MSG(src_tex->read_aspect_flags != dst_tex->read_aspect_flags, ERR_INVALID_PARAMETER,
"Source and destination texture must be of the same type (color or depth).");
- RDD::CommandBufferID command_buffer = frames[frame].draw_command_buffer;
-
- // PRE Copy the image.
-
- if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {
- { // Source.
- RDD::TextureBarrier tb;
- tb.texture = src_tex->driver_id;
- tb.dst_access = RDD::BARRIER_ACCESS_TRANSFER_READ_BIT;
- tb.prev_layout = src_tex->layout;
- tb.next_layout = RDD::TEXTURE_LAYOUT_TRANSFER_SRC_OPTIMAL;
- tb.subresources.aspect = src_tex->barrier_aspect_flags;
- tb.subresources.base_mipmap = p_src_mipmap;
- tb.subresources.mipmap_count = 1;
- tb.subresources.base_layer = p_src_layer;
- tb.subresources.layer_count = 1;
-
- driver->command_pipeline_barrier(command_buffer, RDD::PIPELINE_STAGE_TOP_OF_PIPE_BIT, RDD::PIPELINE_STAGE_TRANSFER_BIT, {}, {}, tb);
- }
- { // Dest.
- RDD::TextureBarrier tb;
- tb.texture = dst_tex->driver_id;
- tb.dst_access = RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT;
- tb.prev_layout = dst_tex->layout;
- tb.next_layout = RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL;
- tb.subresources.aspect = dst_tex->read_aspect_flags;
- tb.subresources.base_mipmap = p_dst_mipmap;
- tb.subresources.mipmap_count = 1;
- tb.subresources.base_layer = p_dst_layer;
- tb.subresources.layer_count = 1;
-
- driver->command_pipeline_barrier(command_buffer, RDD::PIPELINE_STAGE_TOP_OF_PIPE_BIT, RDD::PIPELINE_STAGE_TRANSFER_BIT, {}, {}, tb);
- }
- }
-
- // COPY.
-
- {
- RDD::TextureCopyRegion copy_region;
- copy_region.src_subresources.aspect = src_tex->read_aspect_flags;
- copy_region.src_subresources.mipmap = p_src_mipmap;
- copy_region.src_subresources.base_layer = p_src_layer;
- copy_region.src_subresources.layer_count = 1;
- copy_region.src_offset = p_from;
+ RDD::TextureCopyRegion copy_region;
+ copy_region.src_subresources.aspect = src_tex->read_aspect_flags;
+ copy_region.src_subresources.mipmap = p_src_mipmap;
+ copy_region.src_subresources.base_layer = p_src_layer;
+ copy_region.src_subresources.layer_count = 1;
+ copy_region.src_offset = p_from;
- copy_region.dst_subresources.aspect = dst_tex->read_aspect_flags;
- copy_region.dst_subresources.mipmap = p_dst_mipmap;
- copy_region.dst_subresources.base_layer = p_dst_layer;
- copy_region.dst_subresources.layer_count = 1;
- copy_region.dst_offset = p_to;
+ copy_region.dst_subresources.aspect = dst_tex->read_aspect_flags;
+ copy_region.dst_subresources.mipmap = p_dst_mipmap;
+ copy_region.dst_subresources.base_layer = p_dst_layer;
+ copy_region.dst_subresources.layer_count = 1;
+ copy_region.dst_offset = p_to;
- copy_region.size = p_size;
+ copy_region.size = p_size;
- driver->command_copy_texture(command_buffer, src_tex->driver_id, RDD::TEXTURE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst_tex->driver_id, RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL, copy_region);
+ // The textures must be mutable to be used in the copy operation.
+ bool src_made_mutable = _texture_make_mutable(src_tex, p_from_texture);
+ bool dst_made_mutable = _texture_make_mutable(dst_tex, p_to_texture);
+ if (src_made_mutable || dst_made_mutable) {
+ draw_graph.add_synchronization();
}
- if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {
- // RESTORE LAYOUT for SRC and DST.
-
- BitField<RDD::PipelineStageBits> stages;
- BitField<RDD::BarrierAccessBits> access;
- if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) {
- stages.set_flag(RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT);
- access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
- }
- if (p_post_barrier.has_flag(BARRIER_MASK_VERTEX)) {
- stages.set_flag(RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT);
- access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
- }
- if (p_post_barrier.has_flag(BARRIER_MASK_FRAGMENT)) {
- stages.set_flag(RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
- access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
- }
- if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) {
- stages.set_flag(RDD::PIPELINE_STAGE_TRANSFER_BIT);
- access.set_flag(RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT);
- }
-
- if (stages.is_empty()) {
- stages.set_flag(RDD::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT);
- }
-
- { // Restore src.
- RDD::TextureBarrier tb;
- tb.texture = src_tex->driver_id;
- tb.src_access = RDD::BARRIER_ACCESS_TRANSFER_READ_BIT;
- tb.dst_access = access;
- tb.prev_layout = RDD::TEXTURE_LAYOUT_TRANSFER_SRC_OPTIMAL;
- tb.next_layout = src_tex->layout;
- tb.subresources.aspect = src_tex->barrier_aspect_flags;
- tb.subresources.base_mipmap = p_src_mipmap;
- tb.subresources.mipmap_count = 1;
- tb.subresources.base_layer = p_src_layer;
- tb.subresources.layer_count = 1;
-
- driver->command_pipeline_barrier(command_buffer, RDD::PIPELINE_STAGE_TRANSFER_BIT, stages, {}, {}, tb);
- }
-
- { // Make dst readable.
-
- RDD::TextureBarrier tb;
- tb.texture = dst_tex->driver_id;
- tb.src_access = RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT;
- tb.dst_access = access;
- tb.prev_layout = RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL;
- tb.next_layout = dst_tex->layout;
- tb.subresources.aspect = dst_tex->read_aspect_flags;
- tb.subresources.base_mipmap = p_dst_mipmap;
- tb.subresources.mipmap_count = 1;
- tb.subresources.base_layer = p_dst_layer;
- tb.subresources.layer_count = 1;
-
- driver->command_pipeline_barrier(command_buffer, RDD::PIPELINE_STAGE_TRANSFER_BIT, stages, {}, {}, tb);
- }
-
- if (dst_tex->used_in_frame != frames_drawn) {
- dst_tex->used_in_raster = false;
- dst_tex->used_in_compute = false;
- dst_tex->used_in_frame = frames_drawn;
- }
- dst_tex->used_in_transfer = true;
- }
+ draw_graph.add_texture_copy(src_tex->driver_id, src_tex->draw_tracker, dst_tex->driver_id, dst_tex->draw_tracker, copy_region);
return OK;
}
-Error RenderingDevice::texture_resolve_multisample(RID p_from_texture, RID p_to_texture, BitField<BarrierMask> p_post_barrier) {
+Error RenderingDevice::texture_resolve_multisample(RID p_from_texture, RID p_to_texture) {
_THREAD_SAFE_METHOD_
Texture *src_tex = texture_owner.get_or_null(p_from_texture);
@@ -1815,108 +1513,19 @@ Error RenderingDevice::texture_resolve_multisample(RID p_from_texture, RID p_to_
ERR_FAIL_COND_V_MSG(src_tex->read_aspect_flags != dst_tex->read_aspect_flags, ERR_INVALID_PARAMETER,
"Source and destination texture must be of the same type (color or depth).");
- RDD::CommandBufferID command_buffer = frames[frame].draw_command_buffer;
-
- if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {
- // PRE Copy the image.
-
- { // Source.
- RDD::TextureBarrier tb;
- tb.texture = src_tex->driver_id;
- tb.dst_access = RDD::BARRIER_ACCESS_TRANSFER_READ_BIT;
- tb.prev_layout = src_tex->layout;
- tb.next_layout = RDD::TEXTURE_LAYOUT_TRANSFER_SRC_OPTIMAL;
- tb.subresources.aspect = src_tex->barrier_aspect_flags;
- tb.subresources.base_mipmap = src_tex->base_mipmap;
- tb.subresources.mipmap_count = 1;
- tb.subresources.base_layer = src_tex->base_layer;
- tb.subresources.layer_count = 1;
-
- driver->command_pipeline_barrier(command_buffer, RDD::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, RDD::PIPELINE_STAGE_TRANSFER_BIT, {}, {}, tb);
- }
- { // Dest.
- RDD::TextureBarrier tb;
- tb.texture = dst_tex->driver_id;
- tb.dst_access = RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT;
- tb.prev_layout = dst_tex->layout;
- tb.next_layout = RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL;
- tb.subresources.aspect = dst_tex->barrier_aspect_flags;
- tb.subresources.base_mipmap = dst_tex->base_mipmap;
- tb.subresources.mipmap_count = 1;
- tb.subresources.base_layer = dst_tex->base_layer;
- tb.subresources.layer_count = 1;
-
- driver->command_pipeline_barrier(command_buffer, RDD::PIPELINE_STAGE_TOP_OF_PIPE_BIT, RDD::PIPELINE_STAGE_TRANSFER_BIT, {}, {}, tb);
- }
+ // The textures must be mutable to be used in the resolve operation.
+ bool src_made_mutable = _texture_make_mutable(src_tex, p_from_texture);
+ bool dst_made_mutable = _texture_make_mutable(dst_tex, p_to_texture);
+ if (src_made_mutable || dst_made_mutable) {
+ draw_graph.add_synchronization();
}
- // RESOLVE.
- driver->command_resolve_texture(command_buffer, src_tex->driver_id, RDD::TEXTURE_LAYOUT_TRANSFER_SRC_OPTIMAL, src_tex->base_layer, src_tex->base_mipmap, dst_tex->driver_id, RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL, dst_tex->base_layer, dst_tex->base_mipmap);
-
- if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {
- // RESTORE LAYOUT for SRC and DST.
-
- BitField<RDD::PipelineStageBits> stages;
- BitField<RDD::BarrierAccessBits> access;
- if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) {
- stages.set_flag(RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT);
- access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
- }
- if (p_post_barrier.has_flag(BARRIER_MASK_VERTEX)) {
- stages.set_flag(RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT);
- access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
- }
- if (p_post_barrier.has_flag(BARRIER_MASK_FRAGMENT)) {
- stages.set_flag(RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
- access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
- }
- if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) {
- stages.set_flag(RDD::PIPELINE_STAGE_TRANSFER_BIT);
- access.set_flag(RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT);
- }
-
- if (stages.is_empty()) {
- stages.set_flag(RDD::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT);
- }
-
- { // Restore src.
- RDD::TextureBarrier tb;
- tb.texture = src_tex->driver_id;
- tb.src_access = RDD::BARRIER_ACCESS_TRANSFER_READ_BIT;
- tb.dst_access = access;
- tb.prev_layout = RDD::TEXTURE_LAYOUT_TRANSFER_SRC_OPTIMAL;
- tb.next_layout = src_tex->layout;
- tb.subresources.aspect = src_tex->barrier_aspect_flags;
- tb.subresources.base_mipmap = src_tex->base_mipmap;
- tb.subresources.mipmap_count = 1;
- tb.subresources.base_layer = src_tex->base_layer;
- tb.subresources.layer_count = 1;
-
- driver->command_pipeline_barrier(command_buffer, RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT, stages, {}, {}, tb);
- }
-
- { // Make dst readable.
-
- RDD::TextureBarrier tb;
- tb.texture = dst_tex->driver_id;
- tb.src_access = RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT;
- tb.dst_access = access;
- tb.prev_layout = RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL;
- tb.next_layout = dst_tex->layout;
- tb.subresources.aspect = RDD::TEXTURE_ASPECT_COLOR_BIT;
- tb.subresources.base_mipmap = dst_tex->base_mipmap;
- tb.subresources.mipmap_count = 1;
- tb.subresources.base_layer = dst_tex->base_layer;
- tb.subresources.layer_count = 1;
-
- driver->command_pipeline_barrier(command_buffer, RDD::PIPELINE_STAGE_TRANSFER_BIT, stages, {}, {}, tb);
- }
- }
+ draw_graph.add_texture_resolve(src_tex->driver_id, src_tex->draw_tracker, dst_tex->driver_id, dst_tex->draw_tracker, src_tex->base_layer, src_tex->base_mipmap, dst_tex->base_layer, dst_tex->base_mipmap);
return OK;
}
-Error RenderingDevice::texture_clear(RID p_texture, const Color &p_color, uint32_t p_base_mipmap, uint32_t p_mipmaps, uint32_t p_base_layer, uint32_t p_layers, BitField<BarrierMask> p_post_barrier) {
+Error RenderingDevice::texture_clear(RID p_texture, const Color &p_color, uint32_t p_base_mipmap, uint32_t p_mipmaps, uint32_t p_base_layer, uint32_t p_layers) {
_THREAD_SAFE_METHOD_
Texture *src_tex = texture_owner.get_or_null(p_texture);
@@ -1939,33 +1548,6 @@ Error RenderingDevice::texture_clear(RID p_texture, const Color &p_color, uint32
ERR_FAIL_COND_V(p_base_mipmap + p_mipmaps > src_tex->mipmaps, ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V(p_base_layer + p_layers > src_layer_count, ERR_INVALID_PARAMETER);
- RDD::CommandBufferID command_buffer = frames[frame].draw_command_buffer;
-
- RDD::TextureLayout clear_layout = (src_tex->layout == RDD::TEXTURE_LAYOUT_GENERAL) ? RDD::TEXTURE_LAYOUT_GENERAL : RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL;
-
- // NOTE: Perhaps the valid stages/accesses for a given owner should be a property of the owner. (Here and places like _get_buffer_from_owner.)
- const BitField<RDD::PipelineStageBits> valid_texture_stages = RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT | RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT | RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT;
- constexpr BitField<RDD::BarrierAccessBits> read_access = RDD::BARRIER_ACCESS_SHADER_READ_BIT;
- constexpr BitField<RDD::BarrierAccessBits> read_write_access = RDD::BARRIER_ACCESS_SHADER_READ_BIT | RDD::BARRIER_ACCESS_SHADER_WRITE_BIT;
- const BitField<RDD::BarrierAccessBits> valid_texture_access = (src_tex->usage_flags & TEXTURE_USAGE_STORAGE_BIT) ? read_write_access : read_access;
-
- // Barrier from previous access with optional layout change (see clear_layout logic above).
- if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {
- RDD::TextureBarrier tb;
- tb.texture = src_tex->driver_id;
- tb.src_access = valid_texture_access;
- tb.dst_access = RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT;
- tb.prev_layout = src_tex->layout;
- tb.next_layout = clear_layout;
- tb.subresources.aspect = src_tex->read_aspect_flags;
- tb.subresources.base_mipmap = src_tex->base_mipmap + p_base_mipmap;
- tb.subresources.mipmap_count = p_mipmaps;
- tb.subresources.base_layer = src_tex->base_layer + p_base_layer;
- tb.subresources.layer_count = p_layers;
-
- driver->command_pipeline_barrier(command_buffer, valid_texture_stages, RDD::PIPELINE_STAGE_TRANSFER_BIT, {}, {}, tb);
- }
-
RDD::TextureSubresourceRange range;
range.aspect = src_tex->read_aspect_flags;
range.base_mipmap = src_tex->base_mipmap + p_base_mipmap;
@@ -1973,55 +1555,13 @@ Error RenderingDevice::texture_clear(RID p_texture, const Color &p_color, uint32
range.base_layer = src_tex->base_layer + p_base_layer;
range.layer_count = p_layers;
- driver->command_clear_color_texture(command_buffer, src_tex->driver_id, clear_layout, p_color, range);
-
- // Barrier to post clear accesses (changing back the layout if needed).
- if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {
- BitField<RDD::PipelineStageBits> stages;
- BitField<RDD::BarrierAccessBits> access;
- if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) {
- stages.set_flag(RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT);
- access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
- }
- if (p_post_barrier.has_flag(BARRIER_MASK_VERTEX)) {
- stages.set_flag(RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT);
- access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
- }
- if (p_post_barrier.has_flag(BARRIER_MASK_FRAGMENT)) {
- stages.set_flag(RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
- access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
- }
- if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) {
- stages.set_flag(RDD::PIPELINE_STAGE_TRANSFER_BIT);
- access.set_flag(RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT);
- }
-
- if (stages.is_empty()) {
- stages.set_flag(RDD::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT);
- }
-
- RDD::TextureBarrier tb;
- tb.texture = src_tex->driver_id;
- tb.src_access = RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT;
- tb.dst_access = access;
- tb.prev_layout = clear_layout;
- tb.next_layout = src_tex->layout;
- tb.subresources.aspect = src_tex->read_aspect_flags;
- tb.subresources.base_mipmap = src_tex->base_mipmap + p_base_mipmap;
- tb.subresources.mipmap_count = p_mipmaps;
- tb.subresources.base_layer = src_tex->base_layer + p_base_layer;
- tb.subresources.layer_count = p_layers;
-
- driver->command_pipeline_barrier(command_buffer, RDD::PIPELINE_STAGE_TRANSFER_BIT, stages, {}, {}, tb);
-
- if (src_tex->used_in_frame != frames_drawn) {
- src_tex->used_in_raster = false;
- src_tex->used_in_compute = false;
- src_tex->used_in_frame = frames_drawn;
- }
- src_tex->used_in_transfer = true;
+ if (_texture_make_mutable(src_tex, p_texture)) {
+ // The texture must be mutable to be used as a clear destination.
+ draw_graph.add_synchronization();
}
+ draw_graph.add_texture_clear(src_tex->driver_id, src_tex->draw_tracker, p_color, range);
+
return OK;
}
@@ -2040,6 +1580,30 @@ bool RenderingDevice::texture_is_format_supported_for_usage(DataFormat p_format,
/**** FRAMEBUFFER ****/
/*********************/
+static RDD::AttachmentLoadOp initial_action_to_load_op(RenderingDevice::InitialAction p_action) {
+ switch (p_action) {
+ case RenderingDevice::INITIAL_ACTION_LOAD:
+ return RDD::ATTACHMENT_LOAD_OP_LOAD;
+ case RenderingDevice::INITIAL_ACTION_CLEAR:
+ return RDD::ATTACHMENT_LOAD_OP_CLEAR;
+ case RenderingDevice::INITIAL_ACTION_DISCARD:
+ return RDD::ATTACHMENT_LOAD_OP_DONT_CARE;
+ default:
+ ERR_FAIL_V_MSG(RDD::ATTACHMENT_LOAD_OP_DONT_CARE, "Invalid initial action value (" + itos(p_action) + ")");
+ }
+}
+
+static RDD::AttachmentStoreOp final_action_to_store_op(RenderingDevice::FinalAction p_action) {
+ switch (p_action) {
+ case RenderingDevice::FINAL_ACTION_STORE:
+ return RDD::ATTACHMENT_STORE_OP_STORE;
+ case RenderingDevice::FINAL_ACTION_DISCARD:
+ return RDD::ATTACHMENT_STORE_OP_DONT_CARE;
+ default:
+ ERR_FAIL_V_MSG(RDD::ATTACHMENT_STORE_OP_DONT_CARE, "Invalid final action value (" + itos(p_action) + ")");
+ }
+}
+
RDD::RenderPassID RenderingDevice::_render_pass_create(const Vector<AttachmentFormat> &p_attachments, const Vector<FramebufferPass> &p_passes, InitialAction p_initial_action, FinalAction p_final_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, uint32_t p_view_count, Vector<TextureSamples> *r_samples) {
// NOTE:
// Before the refactor to RenderingDevice-RenderingDeviceDriver, there was commented out code to
@@ -2077,209 +1641,40 @@ RDD::RenderPassID RenderingDevice::_render_pass_create(const Vector<AttachmentFo
description.format = p_attachments[i].format;
description.samples = p_attachments[i].samples;
- bool is_sampled = (p_attachments[i].usage_flags & TEXTURE_USAGE_SAMPLING_BIT);
- bool is_storage = (p_attachments[i].usage_flags & TEXTURE_USAGE_STORAGE_BIT);
- bool is_depth = (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
-
// We can setup a framebuffer where we write to our VRS texture to set it up.
// We make the assumption here that if our texture is actually used as our VRS attachment.
// It is used as such for each subpass. This is fairly certain seeing the restrictions on subpasses.
bool is_vrs = (p_attachments[i].usage_flags & TEXTURE_USAGE_VRS_ATTACHMENT_BIT) && i == p_passes[0].vrs_attachment;
if (is_vrs) {
- // For VRS we only read, there is no writing to this texture.
description.load_op = RDD::ATTACHMENT_LOAD_OP_LOAD;
- description.initial_layout = RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
- description.stencil_load_op = RDD::ATTACHMENT_LOAD_OP_LOAD;
- } else {
- // For each UNDEFINED, assume the prior use was a *read*, as we'd be discarding the output of a write.
- // Also, each UNDEFINED will do an immediate layout transition (write), s.t. we must ensure execution synchronization vs
- // the read. If this is a performance issue, one could track the actual last accessor of each resource, adding only that
- // stage.
-
- switch (is_depth ? p_initial_depth_action : p_initial_action) {
- case INITIAL_ACTION_CLEAR_REGION:
- case INITIAL_ACTION_CLEAR: {
- if ((p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT)) {
- description.load_op = RDD::ATTACHMENT_LOAD_OP_CLEAR;
- description.initial_layout = is_sampled ? RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? RDD::TEXTURE_LAYOUT_GENERAL : RDD::TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
- description.stencil_load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE;
- } else if ((p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
- description.load_op = RDD::ATTACHMENT_LOAD_OP_CLEAR;
- description.initial_layout = is_sampled ? RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? RDD::TEXTURE_LAYOUT_GENERAL : RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
- description.stencil_load_op = RDD::ATTACHMENT_LOAD_OP_CLEAR;
- } else {
- description.load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE;
- description.stencil_load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE;
- description.initial_layout = RDD::TEXTURE_LAYOUT_UNDEFINED; // Don't care what is there.
- }
- } break;
- case INITIAL_ACTION_KEEP: {
- if ((p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT)) {
- description.load_op = RDD::ATTACHMENT_LOAD_OP_LOAD;
- description.initial_layout = is_sampled ? RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? RDD::TEXTURE_LAYOUT_GENERAL : RDD::TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
- description.stencil_load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE;
- } else if ((p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
- description.load_op = RDD::ATTACHMENT_LOAD_OP_LOAD;
- description.initial_layout = is_sampled ? RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? RDD::TEXTURE_LAYOUT_GENERAL : RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
- description.stencil_load_op = RDD::ATTACHMENT_LOAD_OP_LOAD;
- } else {
- description.load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE;
- description.stencil_load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE;
- description.initial_layout = RDD::TEXTURE_LAYOUT_UNDEFINED; // Don't care what is there.
- }
- } break;
- case INITIAL_ACTION_DROP: {
- if ((p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT)) {
- description.load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE;
- description.initial_layout = is_sampled ? RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? RDD::TEXTURE_LAYOUT_GENERAL : RDD::TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
- description.stencil_load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE;
- } else if ((p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
- description.load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE;
- description.initial_layout = RDD::TEXTURE_LAYOUT_UNDEFINED; // Don't care what is there.
- description.stencil_load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE;
- } else {
- description.load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE;
- description.stencil_load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE;
- description.initial_layout = RDD::TEXTURE_LAYOUT_UNDEFINED; // Don't care what is there.
- }
- } break;
- case INITIAL_ACTION_CLEAR_REGION_CONTINUE:
- case INITIAL_ACTION_CONTINUE: {
- if ((p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT)) {
- description.load_op = RDD::ATTACHMENT_LOAD_OP_LOAD;
- description.initial_layout = RDD::TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
- description.stencil_load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE;
- } else if ((p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
- description.load_op = RDD::ATTACHMENT_LOAD_OP_LOAD;
- description.initial_layout = RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
- description.stencil_load_op = RDD::ATTACHMENT_LOAD_OP_LOAD;
- } else {
- description.load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE;
- description.stencil_load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE;
- description.initial_layout = RDD::TEXTURE_LAYOUT_UNDEFINED; // Don't care what is there.
- }
- } break;
- default: {
- ERR_FAIL_V(RDD::RenderPassID()); // Should never reach here.
- }
- }
- }
-
- bool used_last = false;
-
- {
- int last_pass = p_passes.size() - 1;
-
- if (is_depth) {
- // Likely missing depth resolve?
- if (p_passes[last_pass].depth_attachment == i) {
- used_last = true;
- }
- } else if (is_vrs) {
- if (p_passes[last_pass].vrs_attachment == i) {
- used_last = true;
- }
- } else {
- if (p_passes[last_pass].resolve_attachments.size()) {
- // If using resolve attachments, check resolve attachments.
- for (int j = 0; j < p_passes[last_pass].resolve_attachments.size(); j++) {
- if (p_passes[last_pass].resolve_attachments[j] == i) {
- used_last = true;
- break;
- }
- }
- }
- if (!used_last) {
- for (int j = 0; j < p_passes[last_pass].color_attachments.size(); j++) {
- if (p_passes[last_pass].color_attachments[j] == i) {
- used_last = true;
- break;
- }
- }
- }
- }
-
- if (!used_last) {
- for (int j = 0; j < p_passes[last_pass].preserve_attachments.size(); j++) {
- if (p_passes[last_pass].preserve_attachments[j] == i) {
- used_last = true;
- break;
- }
- }
- }
- }
-
- FinalAction final_action = p_final_action;
- FinalAction final_depth_action = p_final_depth_action;
-
- if (!used_last) {
- if (is_depth) {
- final_depth_action = FINAL_ACTION_DISCARD;
-
- } else {
- final_action = FINAL_ACTION_DISCARD;
- }
- }
-
- if (is_vrs) {
- // We don't change our VRS texture during this process.
-
description.store_op = RDD::ATTACHMENT_STORE_OP_DONT_CARE;
+ description.stencil_load_op = RDD::ATTACHMENT_LOAD_OP_LOAD;
description.stencil_store_op = RDD::ATTACHMENT_STORE_OP_DONT_CARE;
+ description.initial_layout = RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
description.final_layout = RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
} else {
- switch (is_depth ? final_depth_action : final_action) {
- case FINAL_ACTION_READ: {
- if ((p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT)) {
- description.store_op = RDD::ATTACHMENT_STORE_OP_STORE;
- description.stencil_store_op = RDD::ATTACHMENT_STORE_OP_DONT_CARE;
- description.final_layout = is_sampled ? RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? RDD::TEXTURE_LAYOUT_GENERAL : RDD::TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
- } else if ((p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
- description.store_op = RDD::ATTACHMENT_STORE_OP_STORE;
- description.stencil_store_op = RDD::ATTACHMENT_STORE_OP_STORE;
- description.final_layout = is_sampled ? RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? RDD::TEXTURE_LAYOUT_GENERAL : RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
- } else {
- description.load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE;
- description.stencil_load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE;
- description.final_layout = RDD::TEXTURE_LAYOUT_UNDEFINED; // Don't care what is there.
- // TODO: What does this mean about the next usage (and thus appropriate dependency masks.
- }
- } break;
- case FINAL_ACTION_DISCARD: {
- if ((p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT)) {
- description.store_op = RDD::ATTACHMENT_STORE_OP_DONT_CARE;
- description.stencil_store_op = RDD::ATTACHMENT_STORE_OP_DONT_CARE;
- description.final_layout = is_sampled ? RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? RDD::TEXTURE_LAYOUT_GENERAL : RDD::TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
- } else if ((p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
- description.store_op = RDD::ATTACHMENT_STORE_OP_DONT_CARE;
- description.stencil_store_op = RDD::ATTACHMENT_STORE_OP_DONT_CARE;
- description.final_layout = is_sampled ? RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? RDD::TEXTURE_LAYOUT_GENERAL : RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
- } else {
- description.store_op = RDD::ATTACHMENT_STORE_OP_DONT_CARE;
- description.stencil_store_op = RDD::ATTACHMENT_STORE_OP_DONT_CARE;
- description.final_layout = RDD::TEXTURE_LAYOUT_UNDEFINED; // Don't care what is there.
- }
- } break;
- case FINAL_ACTION_CONTINUE: {
- if ((p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT)) {
- description.store_op = RDD::ATTACHMENT_STORE_OP_STORE;
- description.stencil_store_op = RDD::ATTACHMENT_STORE_OP_DONT_CARE;
- description.final_layout = RDD::TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
- } else if ((p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
- description.store_op = RDD::ATTACHMENT_STORE_OP_STORE;
- description.stencil_store_op = RDD::ATTACHMENT_STORE_OP_STORE;
- description.final_layout = RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
- } else {
- description.store_op = RDD::ATTACHMENT_STORE_OP_DONT_CARE;
- description.stencil_store_op = RDD::ATTACHMENT_STORE_OP_DONT_CARE;
- description.final_layout = RDD::TEXTURE_LAYOUT_UNDEFINED; // Don't care what is there.
- }
-
- } break;
- default: {
- ERR_FAIL_V(RDD::RenderPassID()); // Should never reach here.
- }
+ if (p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
+ description.load_op = initial_action_to_load_op(p_initial_action);
+ description.store_op = final_action_to_store_op(p_final_action);
+ description.stencil_load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE;
+ description.stencil_store_op = RDD::ATTACHMENT_STORE_OP_DONT_CARE;
+ description.initial_layout = RDD::TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+ description.final_layout = RDD::TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+ } else if (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
+ description.load_op = initial_action_to_load_op(p_initial_depth_action);
+ description.store_op = final_action_to_store_op(p_final_depth_action);
+ description.stencil_load_op = initial_action_to_load_op(p_initial_depth_action);
+ description.stencil_store_op = final_action_to_store_op(p_final_depth_action);
+ description.initial_layout = RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
+ description.final_layout = RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
+ } else {
+ description.load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE;
+ description.store_op = RDD::ATTACHMENT_STORE_OP_DONT_CARE;
+ description.stencil_load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE;
+ description.stencil_store_op = RDD::ATTACHMENT_STORE_OP_DONT_CARE;
+ description.initial_layout = RDD::TEXTURE_LAYOUT_UNDEFINED;
+ description.final_layout = RDD::TEXTURE_LAYOUT_UNDEFINED;
}
}
@@ -2465,7 +1860,7 @@ RenderingDevice::FramebufferFormatID RenderingDevice::framebuffer_format_create_
}
Vector<TextureSamples> samples;
- RDD::RenderPassID render_pass = _render_pass_create(p_attachments, p_passes, INITIAL_ACTION_CLEAR, FINAL_ACTION_READ, INITIAL_ACTION_CLEAR, FINAL_ACTION_READ, p_view_count, &samples); // Actions don't matter for this use case.
+ RDD::RenderPassID render_pass = _render_pass_create(p_attachments, p_passes, INITIAL_ACTION_CLEAR, FINAL_ACTION_STORE, INITIAL_ACTION_CLEAR, FINAL_ACTION_STORE, p_view_count, &samples); // Actions don't matter for this use case.
if (!render_pass) { // Was likely invalid.
return INVALID_ID;
@@ -2701,18 +2096,14 @@ RID RenderingDevice::vertex_buffer_create(uint32_t p_size_bytes, const Vector<ui
buffer.driver_id = driver->buffer_create(buffer.size, buffer.usage, RDD::MEMORY_ALLOCATION_TYPE_GPU);
ERR_FAIL_COND_V(!buffer.driver_id, RID());
+ // Vertex buffers are assumed to be immutable unless they don't have initial data or they've been marked for storage explicitly.
+ if (p_data.is_empty() || p_use_as_storage) {
+ buffer.draw_tracker = RDG::resource_tracker_create();
+ buffer.draw_tracker->buffer_driver_id = buffer.driver_id;
+ }
+
if (p_data.size()) {
- uint64_t data_size = p_data.size();
- const uint8_t *r = p_data.ptr();
- _buffer_update(&buffer, 0, r, data_size);
- if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {
- RDD::BufferBarrier bb;
- bb.buffer = buffer.driver_id;
- bb.src_access = RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT;
- bb.dst_access = RDD::BARRIER_ACCESS_VERTEX_ATTRIBUTE_READ_BIT;
- bb.size = data_size;
- driver->command_pipeline_barrier(frames[frame].setup_command_buffer, RDD::PIPELINE_STAGE_TRANSFER_BIT, RDD::PIPELINE_STAGE_VERTEX_INPUT_BIT, {}, bb, {});
- }
+ _buffer_update(&buffer, RID(), 0, p_data.ptr(), p_data.size());
}
buffer_memory += buffer.size;
@@ -2809,6 +2200,12 @@ RID RenderingDevice::vertex_array_create(uint32_t p_vertex_count, VertexFormatID
}
vertex_array.buffers.push_back(buffer->driver_id);
+
+ if (buffer->draw_tracker != nullptr) {
+ vertex_array.draw_trackers.push_back(buffer->draw_tracker);
+ } else {
+ vertex_array.untracked_buffers.insert(p_src_buffers[i]);
+ }
}
RID id = vertex_array_owner.make_rid(vertex_array);
@@ -2863,18 +2260,14 @@ RID RenderingDevice::index_buffer_create(uint32_t p_index_count, IndexBufferForm
index_buffer.driver_id = driver->buffer_create(index_buffer.size, index_buffer.usage, RDD::MEMORY_ALLOCATION_TYPE_GPU);
ERR_FAIL_COND_V(!index_buffer.driver_id, RID());
+ // Index buffers are assumed to be immutable unless they don't have initial data.
+ if (p_data.is_empty()) {
+ index_buffer.draw_tracker = RDG::resource_tracker_create();
+ index_buffer.draw_tracker->buffer_driver_id = index_buffer.driver_id;
+ }
+
if (p_data.size()) {
- uint64_t data_size = p_data.size();
- const uint8_t *r = p_data.ptr();
- _buffer_update(&index_buffer, 0, r, data_size);
- if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {
- RDD::BufferBarrier bb;
- bb.buffer = index_buffer.driver_id;
- bb.src_access = RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT;
- bb.dst_access = RDD::BARRIER_ACCESS_INDEX_READ_BIT;
- bb.size = data_size;
- driver->command_pipeline_barrier(frames[frame].setup_command_buffer, RDD::PIPELINE_STAGE_TRANSFER_BIT, RDD::PIPELINE_STAGE_VERTEX_INPUT_BIT, {}, bb, {});
- }
+ _buffer_update(&index_buffer, RID(), 0, p_data.ptr(), p_data.size());
}
buffer_memory += index_buffer.size;
@@ -2899,6 +2292,7 @@ RID RenderingDevice::index_array_create(RID p_index_buffer, uint32_t p_index_off
IndexArray index_array;
index_array.max_index = index_buffer->max_index;
index_array.driver_id = index_buffer->driver_id;
+ index_array.draw_tracker = index_buffer->draw_tracker;
index_array.offset = p_index_offset;
index_array.indices = p_index_count;
index_array.format = index_buffer->format;
@@ -2991,6 +2385,29 @@ RID RenderingDevice::shader_create_from_bytecode(const Vector<uint8_t> &p_shader
shader->set_formats.push_back(format);
}
+ for (ShaderStage stage : shader_desc.stages) {
+ switch (stage) {
+ case SHADER_STAGE_VERTEX:
+ shader->stage_bits.set_flag(RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT);
+ break;
+ case SHADER_STAGE_FRAGMENT:
+ shader->stage_bits.set_flag(RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
+ break;
+ case SHADER_STAGE_TESSELATION_CONTROL:
+ shader->stage_bits.set_flag(RDD::PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT);
+ break;
+ case SHADER_STAGE_TESSELATION_EVALUATION:
+ shader->stage_bits.set_flag(RDD::PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT);
+ break;
+ case SHADER_STAGE_COMPUTE:
+ shader->stage_bits.set_flag(RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT);
+ break;
+ default:
+ DEV_ASSERT(false && "Unknown shader stage.");
+ break;
+ }
+ }
+
#ifdef DEV_ENABLED
set_resource_name(id, "RID:" + itos(id.get_id()));
#endif
@@ -3025,18 +2442,14 @@ RID RenderingDevice::uniform_buffer_create(uint32_t p_size_bytes, const Vector<u
buffer.driver_id = driver->buffer_create(buffer.size, buffer.usage, RDD::MEMORY_ALLOCATION_TYPE_GPU);
ERR_FAIL_COND_V(!buffer.driver_id, RID());
+ // Uniform buffers are assumed to be immutable unless they don't have initial data.
+ if (p_data.is_empty()) {
+ buffer.draw_tracker = RDG::resource_tracker_create();
+ buffer.draw_tracker->buffer_driver_id = buffer.driver_id;
+ }
+
if (p_data.size()) {
- uint64_t data_size = p_data.size();
- const uint8_t *r = p_data.ptr();
- _buffer_update(&buffer, 0, r, data_size);
- if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {
- RDD::BufferBarrier bb;
- bb.buffer = buffer.driver_id;
- bb.src_access = RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT;
- bb.dst_access = RDD::BARRIER_ACCESS_UNIFORM_READ_BIT;
- bb.size = data_size;
- driver->command_pipeline_barrier(frames[frame].setup_command_buffer, RDD::PIPELINE_STAGE_TRANSFER_BIT, RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT | RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT | RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT, {}, bb, {});
- }
+ _buffer_update(&buffer, RID(), 0, p_data.ptr(), p_data.size());
}
buffer_memory += buffer.size;
@@ -3073,8 +2486,9 @@ RID RenderingDevice::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p
// Used for verification to make sure a uniform set does not use a framebuffer bound texture.
LocalVector<UniformSet::AttachableTexture> attachable_textures;
- Vector<Texture *> mutable_sampled_textures;
- Vector<Texture *> mutable_storage_textures;
+ Vector<RDG::ResourceTracker *> draw_trackers;
+ Vector<RDG::ResourceUsage> draw_trackers_usage;
+ HashMap<RID, RDG::ResourceUsage> untracked_usage;
for (uint32_t i = 0; i < set_uniform_count; i++) {
const ShaderUniform &set_uniform = set_uniforms[i];
@@ -3126,7 +2540,8 @@ RID RenderingDevice::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p
RDD::SamplerID *sampler_driver_id = sampler_owner.get_or_null(uniform.get_id(j + 0));
ERR_FAIL_COND_V_MSG(!sampler_driver_id, RID(), "SamplerBuffer (binding: " + itos(uniform.binding) + ", index " + itos(j + 1) + ") is not a valid sampler.");
- Texture *texture = texture_owner.get_or_null(uniform.get_id(j + 1));
+ RID texture_id = uniform.get_id(j + 1);
+ Texture *texture = texture_owner.get_or_null(texture_id);
ERR_FAIL_NULL_V_MSG(texture, RID(), "Texture (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid texture.");
ERR_FAIL_COND_V_MSG(!(texture->usage_flags & TEXTURE_USAGE_SAMPLING_BIT), RID(),
@@ -3139,8 +2554,11 @@ RID RenderingDevice::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p
attachable_textures.push_back(attachable_texture);
}
- if ((texture->usage_flags & TEXTURE_USAGE_STORAGE_BIT)) {
- mutable_sampled_textures.push_back(texture);
+ if (texture->draw_tracker != nullptr) {
+ draw_trackers.push_back(texture->draw_tracker);
+ draw_trackers_usage.push_back(RDG::RESOURCE_USAGE_TEXTURE_SAMPLE);
+ } else {
+ untracked_usage[texture_id] = RDG::RESOURCE_USAGE_TEXTURE_SAMPLE;
}
DEV_ASSERT(!texture->owner.is_valid() || texture_owner.get_or_null(texture->owner));
@@ -3159,7 +2577,8 @@ RID RenderingDevice::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p
}
for (uint32_t j = 0; j < uniform.get_id_count(); j++) {
- Texture *texture = texture_owner.get_or_null(uniform.get_id(j));
+ RID texture_id = uniform.get_id(j);
+ Texture *texture = texture_owner.get_or_null(texture_id);
ERR_FAIL_NULL_V_MSG(texture, RID(), "Texture (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid texture.");
ERR_FAIL_COND_V_MSG(!(texture->usage_flags & TEXTURE_USAGE_SAMPLING_BIT), RID(),
@@ -3172,8 +2591,11 @@ RID RenderingDevice::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p
attachable_textures.push_back(attachable_texture);
}
- if ((texture->usage_flags & TEXTURE_USAGE_STORAGE_BIT)) {
- mutable_sampled_textures.push_back(texture);
+ if (texture->draw_tracker != nullptr) {
+ draw_trackers.push_back(texture->draw_tracker);
+ draw_trackers_usage.push_back(RDG::RESOURCE_USAGE_TEXTURE_SAMPLE);
+ } else {
+ untracked_usage[texture_id] = RDG::RESOURCE_USAGE_TEXTURE_SAMPLE;
}
DEV_ASSERT(!texture->owner.is_valid() || texture_owner.get_or_null(texture->owner));
@@ -3191,7 +2613,8 @@ RID RenderingDevice::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p
}
for (uint32_t j = 0; j < uniform.get_id_count(); j++) {
- Texture *texture = texture_owner.get_or_null(uniform.get_id(j));
+ RID texture_id = uniform.get_id(j);
+ Texture *texture = texture_owner.get_or_null(texture_id);
ERR_FAIL_NULL_V_MSG(texture, RID(),
"Image (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid texture.");
@@ -3199,8 +2622,19 @@ RID RenderingDevice::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p
ERR_FAIL_COND_V_MSG(!(texture->usage_flags & TEXTURE_USAGE_STORAGE_BIT), RID(),
"Image (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") needs the TEXTURE_USAGE_STORAGE_BIT usage flag set in order to be used as uniform.");
- if ((texture->usage_flags & TEXTURE_USAGE_SAMPLING_BIT)) {
- mutable_storage_textures.push_back(texture);
+ if (_texture_make_mutable(texture, texture_id)) {
+ // The texture must be mutable as a layout transition will be required.
+ draw_graph.add_synchronization();
+ }
+
+ if (texture->draw_tracker != nullptr) {
+ draw_trackers.push_back(texture->draw_tracker);
+
+ if (set_uniform.writable) {
+ draw_trackers_usage.push_back(RDG::RESOURCE_USAGE_STORAGE_IMAGE_READ_WRITE);
+ } else {
+ draw_trackers_usage.push_back(RDG::RESOURCE_USAGE_STORAGE_IMAGE_READ);
+ }
}
DEV_ASSERT(!texture->owner.is_valid() || texture_owner.get_or_null(texture->owner));
@@ -3218,9 +2652,27 @@ RID RenderingDevice::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p
}
for (uint32_t j = 0; j < uniform.get_id_count(); j++) {
- Buffer *buffer = texture_buffer_owner.get_or_null(uniform.get_id(j));
+ RID buffer_id = uniform.get_id(j);
+ Buffer *buffer = texture_buffer_owner.get_or_null(buffer_id);
ERR_FAIL_NULL_V_MSG(buffer, RID(), "Texture Buffer (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid texture buffer.");
+ if (set_uniform.writable && _buffer_make_mutable(buffer, buffer_id)) {
+ // The buffer must be mutable if it's used for writing.
+ draw_graph.add_synchronization();
+ }
+
+ if (buffer->draw_tracker != nullptr) {
+ draw_trackers.push_back(buffer->draw_tracker);
+
+ if (set_uniform.writable) {
+ draw_trackers_usage.push_back(RDG::RESOURCE_USAGE_TEXTURE_BUFFER_READ_WRITE);
+ } else {
+ draw_trackers_usage.push_back(RDG::RESOURCE_USAGE_TEXTURE_BUFFER_READ);
+ }
+ } else {
+ untracked_usage[buffer_id] = RDG::RESOURCE_USAGE_TEXTURE_BUFFER_READ;
+ }
+
driver_uniform.ids.push_back(buffer->driver_id);
}
} break;
@@ -3237,9 +2689,17 @@ RID RenderingDevice::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p
RDD::SamplerID *sampler_driver_id = sampler_owner.get_or_null(uniform.get_id(j + 0));
ERR_FAIL_COND_V_MSG(!sampler_driver_id, RID(), "SamplerBuffer (binding: " + itos(uniform.binding) + ", index " + itos(j + 1) + ") is not a valid sampler.");
- Buffer *buffer = texture_buffer_owner.get_or_null(uniform.get_id(j + 1));
+ RID buffer_id = uniform.get_id(j + 1);
+ Buffer *buffer = texture_buffer_owner.get_or_null(buffer_id);
ERR_FAIL_NULL_V_MSG(buffer, RID(), "SamplerBuffer (binding: " + itos(uniform.binding) + ", index " + itos(j + 1) + ") is not a valid texture buffer.");
+ if (buffer->draw_tracker != nullptr) {
+ draw_trackers.push_back(buffer->draw_tracker);
+ draw_trackers_usage.push_back(RDG::RESOURCE_USAGE_TEXTURE_BUFFER_READ);
+ } else {
+ untracked_usage[buffer_id] = RDG::RESOURCE_USAGE_TEXTURE_BUFFER_READ;
+ }
+
driver_uniform.ids.push_back(*sampler_driver_id);
driver_uniform.ids.push_back(buffer->driver_id);
}
@@ -3251,12 +2711,20 @@ RID RenderingDevice::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p
ERR_FAIL_COND_V_MSG(uniform.get_id_count() != 1, RID(),
"Uniform buffer supplied (binding: " + itos(uniform.binding) + ") must provide one ID (" + itos(uniform.get_id_count()) + " provided).");
- Buffer *buffer = uniform_buffer_owner.get_or_null(uniform.get_id(0));
+ RID buffer_id = uniform.get_id(0);
+ Buffer *buffer = uniform_buffer_owner.get_or_null(buffer_id);
ERR_FAIL_NULL_V_MSG(buffer, RID(), "Uniform buffer supplied (binding: " + itos(uniform.binding) + ") is invalid.");
ERR_FAIL_COND_V_MSG(buffer->size < (uint32_t)set_uniform.length, RID(),
"Uniform buffer supplied (binding: " + itos(uniform.binding) + ") size (" + itos(buffer->size) + " is smaller than size of shader uniform: (" + itos(set_uniform.length) + ").");
+ if (buffer->draw_tracker != nullptr) {
+ draw_trackers.push_back(buffer->draw_tracker);
+ draw_trackers_usage.push_back(RDG::RESOURCE_USAGE_UNIFORM_BUFFER_READ);
+ } else {
+ untracked_usage[buffer_id] = RDG::RESOURCE_USAGE_UNIFORM_BUFFER_READ;
+ }
+
driver_uniform.ids.push_back(buffer->driver_id);
} break;
case UNIFORM_TYPE_STORAGE_BUFFER: {
@@ -3265,10 +2733,11 @@ RID RenderingDevice::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p
Buffer *buffer = nullptr;
- if (storage_buffer_owner.owns(uniform.get_id(0))) {
- buffer = storage_buffer_owner.get_or_null(uniform.get_id(0));
- } else if (vertex_buffer_owner.owns(uniform.get_id(0))) {
- buffer = vertex_buffer_owner.get_or_null(uniform.get_id(0));
+ RID buffer_id = uniform.get_id(0);
+ if (storage_buffer_owner.owns(buffer_id)) {
+ buffer = storage_buffer_owner.get_or_null(buffer_id);
+ } else if (vertex_buffer_owner.owns(buffer_id)) {
+ buffer = vertex_buffer_owner.get_or_null(buffer_id);
ERR_FAIL_COND_V_MSG(!(buffer->usage.has_flag(RDD::BUFFER_USAGE_STORAGE_BIT)), RID(), "Vertex buffer supplied (binding: " + itos(uniform.binding) + ") was not created with storage flag.");
}
@@ -3278,6 +2747,23 @@ RID RenderingDevice::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p
ERR_FAIL_COND_V_MSG(set_uniform.length > 0 && buffer->size != (uint32_t)set_uniform.length, RID(),
"Storage buffer supplied (binding: " + itos(uniform.binding) + ") size (" + itos(buffer->size) + " does not match size of shader uniform: (" + itos(set_uniform.length) + ").");
+ if (set_uniform.writable && _buffer_make_mutable(buffer, buffer_id)) {
+ // The buffer must be mutable if it's used for writing.
+ draw_graph.add_synchronization();
+ }
+
+ if (buffer->draw_tracker != nullptr) {
+ draw_trackers.push_back(buffer->draw_tracker);
+
+ if (set_uniform.writable) {
+ draw_trackers_usage.push_back(RDG::RESOURCE_USAGE_STORAGE_BUFFER_READ_WRITE);
+ } else {
+ draw_trackers_usage.push_back(RDG::RESOURCE_USAGE_STORAGE_BUFFER_READ);
+ }
+ } else {
+ untracked_usage[buffer_id] = RDG::RESOURCE_USAGE_STORAGE_BUFFER_READ;
+ }
+
driver_uniform.ids.push_back(buffer->driver_id);
} break;
case UNIFORM_TYPE_INPUT_ATTACHMENT: {
@@ -3292,7 +2778,8 @@ RID RenderingDevice::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p
}
for (uint32_t j = 0; j < uniform.get_id_count(); j++) {
- Texture *texture = texture_owner.get_or_null(uniform.get_id(j));
+ RID texture_id = uniform.get_id(j);
+ Texture *texture = texture_owner.get_or_null(texture_id);
ERR_FAIL_NULL_V_MSG(texture, RID(),
"InputAttachment (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid texture.");
@@ -3302,6 +2789,17 @@ RID RenderingDevice::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p
DEV_ASSERT(!texture->owner.is_valid() || texture_owner.get_or_null(texture->owner));
+ if (_texture_make_mutable(texture, texture_id)) {
+ // The texture must be mutable as a layout transition will be required.
+ draw_graph.add_synchronization();
+ }
+
+ if (texture->draw_tracker != nullptr) {
+ bool depth_stencil_read = (texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
+ draw_trackers.push_back(texture->draw_tracker);
+ draw_trackers_usage.push_back(depth_stencil_read ? RDG::RESOURCE_USAGE_ATTACHMENT_DEPTH_STENCIL_READ : RDG::RESOURCE_USAGE_ATTACHMENT_COLOR_READ);
+ }
+
driver_uniform.ids.push_back(texture->driver_id);
}
} break;
@@ -3317,8 +2815,9 @@ RID RenderingDevice::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p
uniform_set.driver_id = driver_uniform_set;
uniform_set.format = shader->set_formats[p_shader_set];
uniform_set.attachable_textures = attachable_textures;
- uniform_set.mutable_sampled_textures = mutable_sampled_textures;
- uniform_set.mutable_storage_textures = mutable_storage_textures;
+ uniform_set.draw_trackers = draw_trackers;
+ uniform_set.draw_trackers_usage = draw_trackers_usage;
+ uniform_set.untracked_usage = untracked_usage;
uniform_set.shader_set = p_shader_set;
uniform_set.shader_id = p_shader;
@@ -3486,6 +2985,7 @@ RID RenderingDevice::render_pipeline_create(RID p_shader, FramebufferFormatID p_
pipeline.shader_layout_hash = shader->layout_hash;
pipeline.set_formats = shader->set_formats;
pipeline.push_constant_size = shader->push_constant_size;
+ pipeline.stage_bits = shader->stage_bits;
#ifdef DEBUG_ENABLED
pipeline.validation.dynamic_state = p_dynamic_state_flags;
@@ -3623,15 +3123,13 @@ RenderingDevice::DrawListID RenderingDevice::draw_list_begin_for_screen(DisplayS
ERR_FAIL_COND_V_MSG(draw_list != nullptr, INVALID_ID, "Only one draw list can be active at the same time.");
ERR_FAIL_COND_V_MSG(compute_list != nullptr, INVALID_ID, "Only one draw/compute list can be active at the same time.");
- RDD::CommandBufferID command_buffer = frames[frame].draw_command_buffer;
-
if (!context->window_is_valid_swapchain(p_screen)) {
return INVALID_ID;
}
- Size2i size = Size2i(context->window_get_width(p_screen), context->window_get_height(p_screen));
+ Rect2i viewport = Rect2i(0, 0, context->window_get_width(p_screen), context->window_get_height(p_screen));
- _draw_list_allocate(Rect2i(Vector2i(), size), 0, 0);
+ _draw_list_allocate(viewport, 0);
#ifdef DEBUG_ENABLED
draw_list_framebuffer_format = screen_get_framebuffer_format();
#endif
@@ -3639,16 +3137,11 @@ RenderingDevice::DrawListID RenderingDevice::draw_list_begin_for_screen(DisplayS
RDD::RenderPassClearValue clear_value;
clear_value.color = p_clear_color;
- driver->command_begin_render_pass(
- command_buffer,
- context->window_get_render_pass(p_screen),
- context->window_get_framebuffer(p_screen),
- RDD::COMMAND_BUFFER_TYPE_PRIMARY,
- Rect2i(0, 0, size.width, size.height),
- VectorView(&clear_value, 1));
- driver->command_render_set_viewport(command_buffer, Rect2i(Point2i(), size));
- driver->command_render_set_scissor(command_buffer, Rect2i(Point2i(), size));
+ draw_graph.add_draw_list_begin(context->window_get_render_pass(p_screen), context->window_get_framebuffer(p_screen), viewport, clear_value, true, false);
+
+ _draw_list_set_viewport(viewport);
+ _draw_list_set_scissor(viewport);
return int64_t(ID_TYPE_DRAW_LIST) << ID_BASE_SHIFT;
}
@@ -3694,8 +3187,12 @@ Error RenderingDevice::_draw_list_setup_framebuffer(Framebuffer *p_framebuffer,
return OK;
}
-Error RenderingDevice::_draw_list_render_pass_begin(Framebuffer *p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_colors, float p_clear_depth, uint32_t p_clear_stencil, Point2i p_viewport_offset, Point2i p_viewport_size, RDD::FramebufferID p_framebuffer_driver_id, RDD::RenderPassID p_render_pass, RDD::CommandBufferID p_command_buffer, RDD::CommandBufferType p_cmd_buffer_mode, const Vector<RID> &p_storage_textures, bool p_constrained_to_region) {
+Error RenderingDevice::_draw_list_render_pass_begin(Framebuffer *p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_colors, float p_clear_depth, uint32_t p_clear_stencil, Point2i p_viewport_offset, Point2i p_viewport_size, RDD::FramebufferID p_framebuffer_driver_id, RDD::RenderPassID p_render_pass) {
LocalVector<RDD::RenderPassClearValue> clear_values;
+ LocalVector<RDG::ResourceTracker *> resource_trackers;
+ LocalVector<RDG::ResourceUsage> resource_usages;
+ bool uses_color = false;
+ bool uses_depth = false;
clear_values.resize(p_framebuffer->texture_ids.size());
int clear_values_count = 0;
{
@@ -3709,69 +3206,33 @@ Error RenderingDevice::_draw_list_render_pass_begin(Framebuffer *p_framebuffer,
continue;
}
- if (color_index < p_clear_colors.size() && texture->usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
- ERR_FAIL_INDEX_V(color_index, p_clear_colors.size(), ERR_BUG); // A bug.
- clear_value.color = p_clear_colors[color_index];
- color_index++;
+ if (texture->usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
+ if (color_index < p_clear_colors.size()) {
+ ERR_FAIL_INDEX_V(color_index, p_clear_colors.size(), ERR_BUG); // A bug.
+ clear_value.color = p_clear_colors[color_index];
+ color_index++;
+ }
+
+ resource_trackers.push_back(texture->draw_tracker);
+ resource_usages.push_back(RDG::RESOURCE_USAGE_ATTACHMENT_COLOR_READ_WRITE);
+ uses_color = true;
} else if (texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
clear_value.depth = p_clear_depth;
clear_value.stencil = p_clear_stencil;
+ resource_trackers.push_back(texture->draw_tracker);
+ resource_usages.push_back(RDG::RESOURCE_USAGE_ATTACHMENT_DEPTH_STENCIL_READ_WRITE);
+ uses_depth = true;
}
clear_values[clear_values_count++] = clear_value;
}
}
- for (int i = 0; i < p_storage_textures.size(); i++) {
- Texture *texture = texture_owner.get_or_null(p_storage_textures[i]);
- if (!texture) {
- continue;
- }
- ERR_CONTINUE_MSG(!(texture->usage_flags & TEXTURE_USAGE_STORAGE_BIT), "Supplied storage texture " + itos(i) + " for draw list is not set to be used for storage.");
-
- if (texture->usage_flags & TEXTURE_USAGE_SAMPLING_BIT) {
- if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {
- // Must change layout to general.
- RDD::TextureBarrier tb;
- tb.texture = texture->driver_id;
- tb.src_access = (RDD::BARRIER_ACCESS_SHADER_READ_BIT | RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
- tb.dst_access = (RDD::BARRIER_ACCESS_SHADER_READ_BIT | RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
- tb.prev_layout = texture->layout;
- tb.next_layout = RDD::TEXTURE_LAYOUT_GENERAL;
- tb.subresources.aspect = texture->read_aspect_flags;
- tb.subresources.base_mipmap = texture->base_mipmap;
- tb.subresources.mipmap_count = texture->mipmaps;
- tb.subresources.base_layer = texture->base_layer;
- tb.subresources.layer_count = texture->layers;
-
- driver->command_pipeline_barrier(p_command_buffer, RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT | RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT, RDD::PIPELINE_STAGE_VERTEX_INPUT_BIT | RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT, {}, {}, tb);
-
- texture->layout = RDD::TEXTURE_LAYOUT_GENERAL;
- }
-
- draw_list_storage_textures.push_back(p_storage_textures[i]);
- }
- }
-
- Rect2i region;
- if (p_constrained_to_region) {
- region = Rect2i(p_viewport_offset, p_viewport_size);
- } else {
- region = Rect2i(Point2i(), p_framebuffer->size);
- }
-
- driver->command_begin_render_pass(
- p_command_buffer,
- p_render_pass,
- p_framebuffer_driver_id,
- p_cmd_buffer_mode,
- region,
- clear_values);
+ draw_graph.add_draw_list_begin(p_render_pass, p_framebuffer_driver_id, Rect2i(p_viewport_offset, p_viewport_size), clear_values, uses_color, uses_depth);
+ draw_graph.add_draw_list_usages(resource_trackers, resource_usages);
// Mark textures as bound.
draw_list_bound_textures.clear();
- draw_list_unbind_color_textures = p_final_color_action != FINAL_ACTION_CONTINUE;
- draw_list_unbind_depth_textures = p_final_depth_action != FINAL_ACTION_CONTINUE;
for (int i = 0; i < p_framebuffer->texture_ids.size(); i++) {
Texture *texture = texture_owner.get_or_null(p_framebuffer->texture_ids[i]);
@@ -3785,6 +3246,14 @@ Error RenderingDevice::_draw_list_render_pass_begin(Framebuffer *p_framebuffer,
return OK;
}
+void RenderingDevice::_draw_list_set_viewport(Rect2i p_rect) {
+ draw_graph.add_draw_list_set_viewport(p_rect);
+}
+
+void RenderingDevice::_draw_list_set_scissor(Rect2i p_rect) {
+ draw_graph.add_draw_list_set_scissor(p_rect);
+}
+
void RenderingDevice::_draw_list_insert_clear_region(DrawList *p_draw_list, Framebuffer *p_framebuffer, Point2i p_viewport_offset, Point2i p_viewport_size, bool p_clear_color, const Vector<Color> &p_clear_colors, bool p_clear_depth, float p_depth, uint32_t p_stencil) {
LocalVector<RDD::AttachmentClear> clear_attachments;
int color_index = 0;
@@ -3818,24 +3287,19 @@ void RenderingDevice::_draw_list_insert_clear_region(DrawList *p_draw_list, Fram
}
Rect2i rect = Rect2i(p_viewport_offset, p_viewport_size);
-
- driver->command_render_clear_attachments(p_draw_list->command_buffer, clear_attachments, rect);
+ draw_graph.add_draw_list_clear_attachments(clear_attachments, rect);
}
-RenderingDevice::DrawListID RenderingDevice::draw_list_begin(RID p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const Vector<RID> &p_storage_textures) {
+RenderingDevice::DrawListID RenderingDevice::draw_list_begin(RID p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region) {
_THREAD_SAFE_METHOD_
ERR_FAIL_COND_V_MSG(draw_list != nullptr, INVALID_ID, "Only one draw list can be active at the same time.");
- ERR_FAIL_COND_V_MSG(compute_list != nullptr && !compute_list->state.allow_draw_overlap, INVALID_ID, "Only one draw/compute list can be active at the same time.");
Framebuffer *framebuffer = framebuffer_owner.get_or_null(p_framebuffer);
ERR_FAIL_NULL_V(framebuffer, INVALID_ID);
Point2i viewport_offset;
Point2i viewport_size = framebuffer->size;
- bool constrained_to_region = false;
- bool needs_clear_color = false;
- bool needs_clear_depth = false;
if (p_region != Rect2() && p_region != Rect2(Vector2(), viewport_size)) { // Check custom region.
Rect2i viewport(viewport_offset, viewport_size);
@@ -3848,34 +3312,9 @@ RenderingDevice::DrawListID RenderingDevice::draw_list_begin(RID p_framebuffer,
viewport_offset = regioni.position;
viewport_size = regioni.size;
-
- // If clearing regions both in color and depth, we can switch to a fast path where we let Vulkan to the clears
- // and we constrain the render area to the region.
- if (p_initial_color_action == INITIAL_ACTION_CLEAR_REGION && p_initial_depth_action == INITIAL_ACTION_CLEAR_REGION) {
- constrained_to_region = true;
- p_initial_color_action = INITIAL_ACTION_CLEAR;
- p_initial_depth_action = INITIAL_ACTION_CLEAR;
- } else {
- if (p_initial_color_action == INITIAL_ACTION_CLEAR_REGION_CONTINUE) {
- needs_clear_color = true;
- p_initial_color_action = INITIAL_ACTION_CONTINUE;
- }
- if (p_initial_depth_action == INITIAL_ACTION_CLEAR_REGION_CONTINUE) {
- needs_clear_depth = true;
- p_initial_depth_action = INITIAL_ACTION_CONTINUE;
- }
- if (p_initial_color_action == INITIAL_ACTION_CLEAR_REGION) {
- needs_clear_color = true;
- p_initial_color_action = INITIAL_ACTION_KEEP;
- }
- if (p_initial_depth_action == INITIAL_ACTION_CLEAR_REGION) {
- needs_clear_depth = true;
- p_initial_depth_action = INITIAL_ACTION_KEEP;
- }
- }
}
- if (p_initial_color_action == INITIAL_ACTION_CLEAR || needs_clear_color) { // Check clear values.
+ if (p_initial_color_action == INITIAL_ACTION_CLEAR) { // Check clear values.
int color_count = 0;
for (int i = 0; i < framebuffer->texture_ids.size(); i++) {
Texture *texture = texture_owner.get_or_null(framebuffer->texture_ids[i]);
@@ -3897,8 +3336,7 @@ RenderingDevice::DrawListID RenderingDevice::draw_list_begin(RID p_framebuffer,
Error err = _draw_list_setup_framebuffer(framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, &fb_driver_id, &render_pass, &draw_list_subpass_count);
ERR_FAIL_COND_V(err != OK, INVALID_ID);
- RDD::CommandBufferID command_buffer = frames[frame].draw_command_buffer;
- err = _draw_list_render_pass_begin(framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, viewport_offset, viewport_size, fb_driver_id, render_pass, command_buffer, RDD::COMMAND_BUFFER_TYPE_PRIMARY, p_storage_textures, constrained_to_region);
+ err = _draw_list_render_pass_begin(framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, viewport_offset, viewport_size, fb_driver_id, render_pass);
if (err != OK) {
return INVALID_ID;
@@ -3907,135 +3345,23 @@ RenderingDevice::DrawListID RenderingDevice::draw_list_begin(RID p_framebuffer,
draw_list_render_pass = render_pass;
draw_list_vkframebuffer = fb_driver_id;
- _draw_list_allocate(Rect2i(viewport_offset, viewport_size), 0, 0);
+ _draw_list_allocate(Rect2i(viewport_offset, viewport_size), 0);
#ifdef DEBUG_ENABLED
draw_list_framebuffer_format = framebuffer->format_id;
#endif
draw_list_current_subpass = 0;
- if (needs_clear_color || needs_clear_depth) {
- DEV_ASSERT(!constrained_to_region);
- _draw_list_insert_clear_region(draw_list, framebuffer, viewport_offset, viewport_size, needs_clear_color, p_clear_color_values, needs_clear_depth, p_clear_depth, p_clear_stencil);
- }
-
- driver->command_render_set_viewport(command_buffer, Rect2i(viewport_offset, viewport_size));
- driver->command_render_set_scissor(command_buffer, Rect2i(viewport_offset, viewport_size));
+ _draw_list_set_viewport(Rect2i(viewport_offset, viewport_size));
+ _draw_list_set_scissor(Rect2i(viewport_offset, viewport_size));
return int64_t(ID_TYPE_DRAW_LIST) << ID_BASE_SHIFT;
}
+#ifndef DISABLE_DEPRECATED
Error RenderingDevice::draw_list_begin_split(RID p_framebuffer, uint32_t p_splits, DrawListID *r_split_ids, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const Vector<RID> &p_storage_textures) {
- _THREAD_SAFE_METHOD_
-
- ERR_FAIL_COND_V_MSG(draw_list != nullptr, ERR_BUSY, "Only one draw list can be active at the same time.");
- ERR_FAIL_COND_V_MSG(compute_list != nullptr && !compute_list->state.allow_draw_overlap, ERR_BUSY, "Only one draw/compute list can be active at the same time.");
-
- ERR_FAIL_COND_V(p_splits < 1, ERR_INVALID_DECLARATION);
-
- Framebuffer *framebuffer = framebuffer_owner.get_or_null(p_framebuffer);
- ERR_FAIL_NULL_V(framebuffer, ERR_INVALID_DECLARATION);
-
- Point2i viewport_offset;
- Point2i viewport_size = framebuffer->size;
- bool constrained_to_region = false;
- bool needs_clear_color = false;
- bool needs_clear_depth = false;
-
- if (p_region != Rect2() && p_region != Rect2(Vector2(), viewport_size)) { // Check custom region.
- Rect2i viewport(viewport_offset, viewport_size);
- Rect2i regioni = p_region;
- if (!(regioni.position.x >= viewport.position.x) && (regioni.position.y >= viewport.position.y) &&
- ((regioni.position.x + regioni.size.x) <= (viewport.position.x + viewport.size.x)) &&
- ((regioni.position.y + regioni.size.y) <= (viewport.position.y + viewport.size.y))) {
- ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "When supplying a custom region, it must be contained within the framebuffer rectangle");
- }
-
- viewport_offset = regioni.position;
- viewport_size = regioni.size;
-
- // If clearing regions both in color and depth, we can switch to a fast path where we let Vulkan to the clears
- // and we constrain the render area to the region.
- if (p_initial_color_action == INITIAL_ACTION_CLEAR_REGION && p_initial_depth_action == INITIAL_ACTION_CLEAR_REGION) {
- constrained_to_region = true;
- p_initial_color_action = INITIAL_ACTION_CLEAR;
- p_initial_depth_action = INITIAL_ACTION_CLEAR;
- } else {
- if (p_initial_color_action == INITIAL_ACTION_CLEAR_REGION_CONTINUE) {
- needs_clear_color = true;
- p_initial_color_action = INITIAL_ACTION_CONTINUE;
- }
- if (p_initial_depth_action == INITIAL_ACTION_CLEAR_REGION_CONTINUE) {
- needs_clear_depth = true;
- p_initial_depth_action = INITIAL_ACTION_CONTINUE;
- }
- if (p_initial_color_action == INITIAL_ACTION_CLEAR_REGION) {
- needs_clear_color = true;
- p_initial_color_action = INITIAL_ACTION_KEEP;
- }
- if (p_initial_depth_action == INITIAL_ACTION_CLEAR_REGION) {
- needs_clear_depth = true;
- p_initial_depth_action = INITIAL_ACTION_KEEP;
- }
- }
- }
-
- if (p_initial_color_action == INITIAL_ACTION_CLEAR || needs_clear_color) { // Check clear values.
-
- int color_count = 0;
- for (int i = 0; i < framebuffer->texture_ids.size(); i++) {
- Texture *texture = texture_owner.get_or_null(framebuffer->texture_ids[i]);
-
- if (!texture || !(texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
- color_count++;
- }
- }
-
- ERR_FAIL_COND_V_MSG(p_clear_color_values.size() != color_count, ERR_INVALID_PARAMETER,
- "Clear color values supplied (" + itos(p_clear_color_values.size()) + ") differ from the amount required for framebuffer (" + itos(color_count) + ").");
- }
-
- RDD::FramebufferID fb_driver_id;
- RDD::RenderPassID render_pass;
-
- Error err = _draw_list_setup_framebuffer(framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, &fb_driver_id, &render_pass, &draw_list_subpass_count);
- ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);
-
- RDD::CommandBufferID frame_command_buffer = frames[frame].draw_command_buffer;
- err = _draw_list_render_pass_begin(framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, viewport_offset, viewport_size, fb_driver_id, render_pass, frame_command_buffer, RDD::COMMAND_BUFFER_TYPE_SECONDARY, p_storage_textures, constrained_to_region);
-
- if (err != OK) {
- return ERR_CANT_CREATE;
- }
-
- draw_list_current_subpass = 0;
-
-#ifdef DEBUG_ENABLED
- draw_list_framebuffer_format = framebuffer->format_id;
-#endif
- draw_list_render_pass = render_pass;
- draw_list_vkframebuffer = fb_driver_id;
-
- err = _draw_list_allocate(Rect2i(viewport_offset, viewport_size), p_splits, 0);
- if (err != OK) {
- return err;
- }
-
- if (needs_clear_color || needs_clear_depth) {
- DEV_ASSERT(!constrained_to_region);
- _draw_list_insert_clear_region(&draw_list[0], framebuffer, viewport_offset, viewport_size, needs_clear_color, p_clear_color_values, needs_clear_depth, p_clear_depth, p_clear_stencil);
- }
-
- bool secondary_viewport_scissor = driver->api_trait_get(RDD::API_TRAIT_SECONDARY_VIEWPORT_SCISSOR);
- for (uint32_t i = 0; i < p_splits; i++) {
- if (secondary_viewport_scissor) {
- driver->command_render_set_viewport(draw_list[i].command_buffer, Rect2i(viewport_offset, viewport_size));
- driver->command_render_set_scissor(draw_list[i].command_buffer, Rect2i(viewport_offset, viewport_size));
- }
- r_split_ids[i] = (int64_t(ID_TYPE_SPLIT_DRAW_LIST) << ID_BASE_SHIFT) + i;
- }
-
- return OK;
+ ERR_FAIL_V_MSG(ERR_UNAVAILABLE, "Deprecated. Split draw lists are used automatically by RenderingDevice.");
}
+#endif
RenderingDevice::DrawList *RenderingDevice::_get_draw_list_ptr(DrawListID p_id) {
if (p_id < 0) {
@@ -4045,22 +3371,7 @@ RenderingDevice::DrawList *RenderingDevice::_get_draw_list_ptr(DrawListID p_id)
if (!draw_list) {
return nullptr;
} else if (p_id == (int64_t(ID_TYPE_DRAW_LIST) << ID_BASE_SHIFT)) {
- if (draw_list_split) {
- return nullptr;
- }
return draw_list;
- } else if (p_id >> DrawListID(ID_BASE_SHIFT) == ID_TYPE_SPLIT_DRAW_LIST) {
- if (!draw_list_split) {
- return nullptr;
- }
-
- uint64_t index = p_id & ((DrawListID(1) << DrawListID(ID_BASE_SHIFT)) - 1); // Mask.
-
- if (index >= draw_list_count) {
- return nullptr;
- }
-
- return &draw_list[index];
} else {
return nullptr;
}
@@ -4073,7 +3384,7 @@ void RenderingDevice::draw_list_set_blend_constants(DrawListID p_list, const Col
ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified.");
#endif
- driver->command_render_set_blend_constants(dl->command_buffer, p_color);
+ draw_graph.add_draw_list_set_blend_constants(p_color);
}
void RenderingDevice::draw_list_bind_render_pipeline(DrawListID p_list, RID p_render_pipeline) {
@@ -4095,7 +3406,7 @@ void RenderingDevice::draw_list_bind_render_pipeline(DrawListID p_list, RID p_re
dl->state.pipeline = p_render_pipeline;
- driver->command_bind_render_pipeline(dl->command_buffer, pipeline->driver_id);
+ draw_graph.add_draw_list_bind_pipeline(pipeline->driver_id, pipeline->stage_bits);
if (dl->state.pipeline_shader != pipeline->shader) {
// Shader changed, so descriptor sets may become incompatible.
@@ -4183,21 +3494,6 @@ void RenderingDevice::draw_list_bind_uniform_set(DrawListID p_list, RID p_unifor
dl->state.sets[p_index].uniform_set_format = uniform_set->format;
dl->state.sets[p_index].uniform_set = p_uniform_set;
- if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {
- uint32_t mst_count = uniform_set->mutable_storage_textures.size();
- if (mst_count) {
- Texture **mst_textures = const_cast<UniformSet *>(uniform_set)->mutable_storage_textures.ptrw();
- for (uint32_t i = 0; i < mst_count; i++) {
- if (mst_textures[i]->used_in_frame != frames_drawn) {
- mst_textures[i]->used_in_frame = frames_drawn;
- mst_textures[i]->used_in_transfer = false;
- mst_textures[i]->used_in_compute = false;
- }
- mst_textures[i]->used_in_raster = true;
- }
- }
- }
-
#ifdef DEBUG_ENABLED
{ // Validate that textures bound are not attached as framebuffer bindings.
uint32_t attachable_count = uniform_set->attachable_textures.size();
@@ -4235,7 +3531,12 @@ void RenderingDevice::draw_list_bind_vertex_array(DrawListID p_list, RID p_verte
dl->validation.vertex_max_instances_allowed = vertex_array->max_instances_allowed;
#endif
dl->validation.vertex_array_size = vertex_array->vertex_count;
- driver->command_render_bind_vertex_buffers(dl->command_buffer, vertex_array->buffers.size(), vertex_array->buffers.ptr(), vertex_array->offsets.ptr());
+
+ draw_graph.add_draw_list_bind_vertex_buffers(vertex_array->buffers, vertex_array->offsets);
+
+ for (int i = 0; i < vertex_array->draw_trackers.size(); i++) {
+ draw_graph.add_draw_list_usage(vertex_array->draw_trackers[i], RDG::RESOURCE_USAGE_VERTEX_BUFFER_READ);
+ }
}
void RenderingDevice::draw_list_bind_index_array(DrawListID p_list, RID p_index_array) {
@@ -4256,10 +3557,14 @@ void RenderingDevice::draw_list_bind_index_array(DrawListID p_list, RID p_index_
#ifdef DEBUG_ENABLED
dl->validation.index_array_max_index = index_array->max_index;
#endif
- dl->validation.index_array_size = index_array->indices;
- dl->validation.index_array_offset = index_array->offset;
+ dl->validation.index_array_count = index_array->indices;
+
+ const uint64_t offset_bytes = index_array->offset * (index_array->format == INDEX_BUFFER_FORMAT_UINT16 ? sizeof(uint16_t) : sizeof(uint32_t));
+ draw_graph.add_draw_list_bind_index_buffer(index_array->driver_id, index_array->format, offset_bytes);
- driver->command_render_bind_index_buffer(dl->command_buffer, index_array->driver_id, index_array->format, index_array->offset);
+ if (index_array->draw_tracker != nullptr) {
+ draw_graph.add_draw_list_usage(index_array->draw_tracker, RDG::RESOURCE_USAGE_INDEX_BUFFER_READ);
+ }
}
void RenderingDevice::draw_list_set_line_width(DrawListID p_list, float p_width) {
@@ -4269,7 +3574,7 @@ void RenderingDevice::draw_list_set_line_width(DrawListID p_list, float p_width)
ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified.");
#endif
- driver->command_render_set_line_width(dl->command_buffer, p_width);
+ draw_graph.add_draw_list_set_line_width(p_width);
}
void RenderingDevice::draw_list_set_push_constant(DrawListID p_list, const void *p_data, uint32_t p_data_size) {
@@ -4284,7 +3589,9 @@ void RenderingDevice::draw_list_set_push_constant(DrawListID p_list, const void
ERR_FAIL_COND_MSG(p_data_size != dl->validation.pipeline_push_constant_size,
"This render pipeline requires (" + itos(dl->validation.pipeline_push_constant_size) + ") bytes of push constant data, supplied: (" + itos(p_data_size) + ")");
#endif
- driver->command_bind_push_constants(dl->command_buffer, dl->state.pipeline_shader_driver_id, 0, VectorView((const uint32_t *)p_data, p_data_size / sizeof(uint32_t)));
+
+ draw_graph.add_draw_list_set_push_constant(dl->state.pipeline_shader_driver_id, p_data, p_data_size);
+
#ifdef DEBUG_ENABLED
dl->validation.pipeline_push_constant_supplied = true;
#endif
@@ -4338,14 +3645,19 @@ void RenderingDevice::draw_list_draw(DrawListID p_list, bool p_use_indices, uint
}
}
#endif
- driver->command_uniform_set_prepare_for_use(dl->command_buffer, dl->state.sets[i].uniform_set_driver_id, dl->state.pipeline_shader_driver_id, i);
+ draw_graph.add_draw_list_uniform_set_prepare_for_use(dl->state.pipeline_shader_driver_id, dl->state.sets[i].uniform_set_driver_id, i);
}
for (uint32_t i = 0; i < dl->state.set_count; i++) {
if (dl->state.sets[i].pipeline_expected_format == 0) {
continue; // Nothing expected by this pipeline.
}
if (!dl->state.sets[i].bound) {
- driver->command_bind_render_uniform_set(dl->command_buffer, dl->state.sets[i].uniform_set_driver_id, dl->state.pipeline_shader_driver_id, i);
+ // All good, see if this requires re-binding.
+ draw_graph.add_draw_list_bind_uniform_set(dl->state.pipeline_shader_driver_id, dl->state.sets[i].uniform_set_driver_id, i);
+
+ UniformSet *uniform_set = uniform_set_owner.get_or_null(dl->state.sets[i].uniform_set);
+ draw_graph.add_draw_list_usages(uniform_set->draw_trackers, uniform_set->draw_trackers_usage);
+
dl->state.sets[i].bound = true;
}
}
@@ -4355,13 +3667,13 @@ void RenderingDevice::draw_list_draw(DrawListID p_list, bool p_use_indices, uint
ERR_FAIL_COND_MSG(p_procedural_vertices > 0,
"Procedural vertices can't be used together with indices.");
- ERR_FAIL_COND_MSG(!dl->validation.index_array_size,
+ ERR_FAIL_COND_MSG(!dl->validation.index_array_count,
"Draw command requested indices, but no index buffer was set.");
ERR_FAIL_COND_MSG(dl->validation.pipeline_uses_restart_indices != dl->validation.index_buffer_uses_restart_indices,
"The usage of restart indices in index buffer does not match the render primitive in the pipeline.");
#endif
- uint32_t to_draw = dl->validation.index_array_size;
+ uint32_t to_draw = dl->validation.index_array_count;
#ifdef DEBUG_ENABLED
ERR_FAIL_COND_MSG(to_draw < dl->validation.pipeline_primitive_minimum,
@@ -4370,7 +3682,8 @@ void RenderingDevice::draw_list_draw(DrawListID p_list, bool p_use_indices, uint
ERR_FAIL_COND_MSG((to_draw % dl->validation.pipeline_primitive_divisor) != 0,
"Index amount (" + itos(to_draw) + ") must be a multiple of the amount of indices required by the render primitive (" + itos(dl->validation.pipeline_primitive_divisor) + ").");
#endif
- driver->command_render_draw_indexed(dl->command_buffer, to_draw, p_instances, dl->validation.index_array_offset, 0, 0);
+
+ draw_graph.add_draw_list_draw_indexed(to_draw, p_instances, 0);
} else {
uint32_t to_draw;
@@ -4396,7 +3709,7 @@ void RenderingDevice::draw_list_draw(DrawListID p_list, bool p_use_indices, uint
"Vertex amount (" + itos(to_draw) + ") must be a multiple of the amount of vertices required by the render primitive (" + itos(dl->validation.pipeline_primitive_divisor) + ").");
#endif
- driver->command_render_draw(dl->command_buffer, to_draw, p_instances, 0, 0);
+ draw_graph.add_draw_list_draw(to_draw, p_instances);
}
}
@@ -4416,7 +3729,7 @@ void RenderingDevice::draw_list_enable_scissor(DrawListID p_list, const Rect2 &p
return;
}
- driver->command_render_set_scissor(dl->command_buffer, rect);
+ _draw_list_set_scissor(rect);
}
void RenderingDevice::draw_list_disable_scissor(DrawListID p_list) {
@@ -4426,7 +3739,7 @@ void RenderingDevice::draw_list_disable_scissor(DrawListID p_list) {
ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified.");
#endif
- driver->command_render_set_scissor(dl->command_buffer, dl->viewport);
+ _draw_list_set_scissor(dl->viewport);
}
uint32_t RenderingDevice::draw_list_get_current_pass() {
@@ -4443,230 +3756,80 @@ RenderingDevice::DrawListID RenderingDevice::draw_list_switch_to_next_pass() {
Rect2i viewport;
_draw_list_free(&viewport);
- driver->command_next_render_subpass(frames[frame].draw_command_buffer, RDD::COMMAND_BUFFER_TYPE_PRIMARY);
+ draw_graph.add_draw_list_next_subpass(RDD::COMMAND_BUFFER_TYPE_PRIMARY);
- _draw_list_allocate(viewport, 0, draw_list_current_subpass);
+ _draw_list_allocate(viewport, draw_list_current_subpass);
return int64_t(ID_TYPE_DRAW_LIST) << ID_BASE_SHIFT;
}
-Error RenderingDevice::draw_list_switch_to_next_pass_split(uint32_t p_splits, DrawListID *r_split_ids) {
- _THREAD_SAFE_METHOD_
- ERR_FAIL_COND_V(draw_list == nullptr, ERR_INVALID_PARAMETER);
- ERR_FAIL_COND_V(draw_list_current_subpass >= draw_list_subpass_count - 1, ERR_INVALID_PARAMETER);
- draw_list_current_subpass++;
-
- Rect2i viewport;
- _draw_list_free(&viewport);
-
- driver->command_next_render_subpass(frames[frame].draw_command_buffer, RDD::COMMAND_BUFFER_TYPE_PRIMARY);
-
- _draw_list_allocate(viewport, p_splits, draw_list_current_subpass);
-
- for (uint32_t i = 0; i < p_splits; i++) {
- r_split_ids[i] = (int64_t(ID_TYPE_SPLIT_DRAW_LIST) << ID_BASE_SHIFT) + i;
- }
-
- return OK;
+#ifndef DISABLE_DEPRECATED
+Error RenderingDevice::draw_list_switch_to_next_pass_split(uint32_t p_splits, DrawListID *r_split_ids) {
+ ERR_FAIL_V_MSG(ERR_UNAVAILABLE, "Deprecated. Split draw lists are used automatically by RenderingDevice.");
}
+#endif
-Error RenderingDevice::_draw_list_allocate(const Rect2i &p_viewport, uint32_t p_splits, uint32_t p_subpass) {
+Error RenderingDevice::_draw_list_allocate(const Rect2i &p_viewport, uint32_t p_subpass) {
// Lock while draw_list is active.
_THREAD_SAFE_LOCK_
- if (p_splits == 0) {
- draw_list = memnew(DrawList);
- draw_list->command_buffer = frames[frame].draw_command_buffer;
- draw_list->viewport = p_viewport;
- draw_list_count = 0;
- draw_list_split = false;
- } else {
- if (p_splits > (uint32_t)split_draw_list_allocators.size()) {
- uint32_t from = split_draw_list_allocators.size();
- split_draw_list_allocators.resize(p_splits);
- for (uint32_t i = from; i < p_splits; i++) {
- RDD::CommandPoolID cmd_pool = driver->command_pool_create(RDD::COMMAND_BUFFER_TYPE_SECONDARY);
- ERR_FAIL_COND_V(!cmd_pool, ERR_CANT_CREATE);
- split_draw_list_allocators.write[i].command_pool = cmd_pool;
-
- for (int j = 0; j < frame_count; j++) {
- RDD::CommandBufferID cmd_buffer = driver->command_buffer_create(RDD::COMMAND_BUFFER_TYPE_SECONDARY, cmd_pool);
- ERR_FAIL_COND_V(!cmd_buffer, ERR_CANT_CREATE);
- split_draw_list_allocators.write[i].command_buffers.push_back(cmd_buffer);
- }
- }
- }
- draw_list = memnew_arr(DrawList, p_splits);
- draw_list_count = p_splits;
- draw_list_split = true;
-
- for (uint32_t i = 0; i < p_splits; i++) {
- // Take a command buffer and initialize it.
- RDD::CommandBufferID cmd_buffer = split_draw_list_allocators[i].command_buffers[frame];
-
- bool ok = driver->command_buffer_begin_secondary(cmd_buffer, draw_list_render_pass, p_subpass, draw_list_vkframebuffer);
- if (!ok) {
- memdelete_arr(draw_list);
- draw_list = nullptr;
- ERR_FAIL_V(ERR_CANT_CREATE);
- }
-
- draw_list[i].command_buffer = cmd_buffer;
- draw_list[i].viewport = p_viewport;
- }
- }
+ draw_list = memnew(DrawList);
+ draw_list->viewport = p_viewport;
+ draw_list_count = 0;
return OK;
}
void RenderingDevice::_draw_list_free(Rect2i *r_last_viewport) {
- if (draw_list_split) {
- // Send all command buffers.
- RDD::CommandBufferID *command_buffers = (RDD::CommandBufferID *)alloca(sizeof(RDD::CommandBufferID) * draw_list_count);
- for (uint32_t i = 0; i < draw_list_count; i++) {
- driver->command_buffer_end(draw_list[i].command_buffer);
- command_buffers[i] = draw_list[i].command_buffer;
- if (r_last_viewport) {
- if (i == 0 || draw_list[i].viewport_set) {
- *r_last_viewport = draw_list[i].viewport;
- }
- }
- }
-
- driver->command_buffer_execute_secondary(frames[frame].draw_command_buffer, VectorView(command_buffers, draw_list_count));
- memdelete_arr(draw_list);
- draw_list = nullptr;
-
- } else {
- if (r_last_viewport) {
- *r_last_viewport = draw_list->viewport;
- }
- // Just end the list.
- memdelete(draw_list);
- draw_list = nullptr;
+ if (r_last_viewport) {
+ *r_last_viewport = draw_list->viewport;
}
+ // Just end the list.
+ memdelete(draw_list);
+ draw_list = nullptr;
// Draw_list is no longer active.
_THREAD_SAFE_UNLOCK_
}
-void RenderingDevice::draw_list_end(BitField<BarrierMask> p_post_barrier) {
+void RenderingDevice::draw_list_end() {
_THREAD_SAFE_METHOD_
ERR_FAIL_COND_MSG(!draw_list, "Immediate draw list is already inactive.");
- _draw_list_free();
+ draw_graph.add_draw_list_end();
- driver->command_end_render_pass(frames[frame].draw_command_buffer);
+ _draw_list_free();
for (int i = 0; i < draw_list_bound_textures.size(); i++) {
Texture *texture = texture_owner.get_or_null(draw_list_bound_textures[i]);
ERR_CONTINUE(!texture); // Wtf.
- if (draw_list_unbind_color_textures && (texture->usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT)) {
+ if (texture->usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
texture->bound = false;
}
- if (draw_list_unbind_depth_textures && (texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
+ if (texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
texture->bound = false;
}
}
- draw_list_bound_textures.clear();
- if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {
- BitField<RDD::PipelineStageBits> dst_stages;
- BitField<RDD::BarrierAccessBits> dst_access;
- if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) {
- dst_stages.set_flag(RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT);
- dst_access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
- }
- if (p_post_barrier.has_flag(BARRIER_MASK_VERTEX)) {
- dst_stages.set_flag(RDD::PIPELINE_STAGE_VERTEX_INPUT_BIT).set_flag(RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT); // RDD::PIPELINE_STAGE_DRAW_INDIRECT_BIT
- dst_access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT).set_flag(RDD::BARRIER_ACCESS_INDEX_READ_BIT).set_flag(RDD::BARRIER_ACCESS_VERTEX_ATTRIBUTE_READ_BIT); // RDD::BARRIER_ACCESS_INDIRECT_COMMAND_READ_BIT
- }
- if (p_post_barrier.has_flag(BARRIER_MASK_FRAGMENT)) {
- dst_stages.set_flag(RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT); // RDD::PIPELINE_STAGE_DRAW_INDIRECT_BIT
- dst_access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT); // RDD::BARRIER_ACCESS_INDIRECT_COMMAND_READ_BIT
- }
- if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) {
- dst_stages.set_flag(RDD::PIPELINE_STAGE_TRANSFER_BIT);
- dst_access.set_flag(RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT).set_flag(RDD::BARRIER_ACCESS_TRANSFER_READ_BIT);
- }
-
- if (dst_stages.is_empty()) {
- dst_stages.set_flag(RDD::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT);
- }
-
- RDD::TextureBarrier *texture_barriers = nullptr;
-
- uint32_t texture_barrier_count = draw_list_storage_textures.size();
-
- if (texture_barrier_count) {
- texture_barriers = (RDD::TextureBarrier *)alloca(sizeof(RDD::TextureBarrier) * draw_list_storage_textures.size());
- }
-
- BitField<RDD::PipelineStageBits> src_stage(RDD::PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
- RDD::PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | RDD::PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT);
- BitField<RDD::BarrierAccessBits> src_access(
- RDD::BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | RDD::BARRIER_ACCESS_COLOR_ATTACHMENT_WRITE_BIT);
-
- if (texture_barrier_count) {
- src_stage.set_flag(RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT).set_flag(RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
- src_access.set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
- }
-
- for (uint32_t i = 0; i < texture_barrier_count; i++) {
- Texture *texture = texture_owner.get_or_null(draw_list_storage_textures[i]);
-
- RDD::TextureBarrier &tb = texture_barriers[i];
- tb.texture = texture->driver_id;
- tb.src_access = src_access;
- tb.dst_access = dst_access;
- tb.prev_layout = texture->layout;
- tb.next_layout = RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
- tb.subresources.aspect = texture->read_aspect_flags;
- tb.subresources.base_mipmap = texture->base_mipmap;
- tb.subresources.mipmap_count = texture->mipmaps;
- tb.subresources.base_layer = texture->base_layer;
- tb.subresources.layer_count = texture->layers;
-
- texture->layout = RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
- }
-
- // To ensure proper synchronization, we must make sure rendering is done before:
- // * Some buffer is copied.
- // * Another render pass happens (since we may be done).
-
- RDD::MemoryBarrier mb;
- mb.src_access = src_access;
- mb.dst_access = dst_access;
-
- if (texture_barrier_count > 0 || p_post_barrier != BARRIER_MASK_NO_BARRIER) {
- driver->command_pipeline_barrier(frames[frame].draw_command_buffer, src_stage, dst_stages, mb, {}, VectorView(texture_barriers, texture_barrier_count));
- }
- }
-
- draw_list_storage_textures.clear();
-
-#ifdef FORCE_FULL_BARRIER
- _full_barrier(true);
-#endif
+ draw_list_bound_textures.clear();
}
/***********************/
/**** COMPUTE LISTS ****/
/***********************/
-RenderingDevice::ComputeListID RenderingDevice::compute_list_begin(bool p_allow_draw_overlap) {
+RenderingDevice::ComputeListID RenderingDevice::compute_list_begin() {
_THREAD_SAFE_METHOD_
- ERR_FAIL_COND_V_MSG(!p_allow_draw_overlap && draw_list != nullptr, INVALID_ID, "Only one draw list can be active at the same time.");
ERR_FAIL_COND_V_MSG(compute_list != nullptr, INVALID_ID, "Only one draw/compute list can be active at the same time.");
// Lock while compute_list is active.
_THREAD_SAFE_LOCK_
compute_list = memnew(ComputeList);
- compute_list->command_buffer = frames[frame].draw_command_buffer;
- compute_list->state.allow_draw_overlap = p_allow_draw_overlap;
+
+ draw_graph.add_compute_list_begin();
return ID_TYPE_COMPUTE_LIST;
}
@@ -4688,7 +3851,7 @@ void RenderingDevice::compute_list_bind_compute_pipeline(ComputeListID p_list, R
cl->state.pipeline = p_compute_pipeline;
- driver->command_bind_compute_pipeline(cl->command_buffer, pipeline->driver_id);
+ draw_graph.add_compute_list_bind_pipeline(pipeline->driver_id);
if (cl->state.pipeline_shader != pipeline->shader) {
// Shader changed, so descriptor sets may become incompatible.
@@ -4779,109 +3942,6 @@ void RenderingDevice::compute_list_bind_uniform_set(ComputeListID p_list, RID p_
cl->state.sets[p_index].uniform_set_format = uniform_set->format;
cl->state.sets[p_index].uniform_set = p_uniform_set;
- if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {
- uint32_t textures_to_sampled_count = uniform_set->mutable_sampled_textures.size();
- uint32_t textures_to_storage_count = uniform_set->mutable_storage_textures.size();
-
- Texture **textures_to_sampled = uniform_set->mutable_sampled_textures.ptrw();
-
- RDD::TextureBarrier *texture_barriers = nullptr;
-
- if (textures_to_sampled_count + textures_to_storage_count) {
- texture_barriers = (RDD::TextureBarrier *)alloca(sizeof(RDD::TextureBarrier) * (textures_to_sampled_count + textures_to_storage_count));
- }
- uint32_t texture_barrier_count = 0;
-
- BitField<RDD::PipelineStageBits> src_stages;
-
- for (uint32_t i = 0; i < textures_to_sampled_count; i++) {
- if (textures_to_sampled[i]->layout != RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
- src_stages.set_flag(RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT);
-
- RDD::TextureBarrier &tb = texture_barriers[texture_barrier_count++];
- tb.texture = textures_to_sampled[i]->driver_id;
- tb.src_access = (RDD::BARRIER_ACCESS_SHADER_READ_BIT | RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
- tb.dst_access = (RDD::BARRIER_ACCESS_SHADER_READ_BIT | RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
- tb.prev_layout = textures_to_sampled[i]->layout;
- tb.next_layout = RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
- tb.subresources.aspect = textures_to_sampled[i]->read_aspect_flags;
- tb.subresources.base_mipmap = textures_to_sampled[i]->base_mipmap;
- tb.subresources.mipmap_count = textures_to_sampled[i]->mipmaps;
- tb.subresources.base_layer = textures_to_sampled[i]->base_layer;
- tb.subresources.layer_count = textures_to_sampled[i]->layers;
-
- textures_to_sampled[i]->layout = RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
-
- cl->state.textures_to_sampled_layout.erase(textures_to_sampled[i]);
- }
-
- if (textures_to_sampled[i]->used_in_frame != frames_drawn) {
- textures_to_sampled[i]->used_in_frame = frames_drawn;
- textures_to_sampled[i]->used_in_transfer = false;
- textures_to_sampled[i]->used_in_raster = false;
- }
- textures_to_sampled[i]->used_in_compute = true;
- }
-
- Texture **textures_to_storage = uniform_set->mutable_storage_textures.ptrw();
-
- for (uint32_t i = 0; i < textures_to_storage_count; i++) {
- if (textures_to_storage[i]->layout != RDD::TEXTURE_LAYOUT_GENERAL) {
- BitField<RDD::BarrierAccessBits> src_access;
-
- if (textures_to_storage[i]->used_in_frame == frames_drawn) {
- if (textures_to_storage[i]->used_in_compute) {
- src_stages.set_flag(RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT);
- src_access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
- }
- if (textures_to_storage[i]->used_in_raster) {
- src_stages.set_flag(RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT).set_flag(RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT);
- src_access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
- }
- if (textures_to_storage[i]->used_in_transfer) {
- src_stages.set_flag(RDD::PIPELINE_STAGE_TRANSFER_BIT);
- src_access.set_flag(RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT).set_flag(RDD::BARRIER_ACCESS_TRANSFER_READ_BIT);
- }
-
- textures_to_storage[i]->used_in_compute = false;
- textures_to_storage[i]->used_in_raster = false;
- textures_to_storage[i]->used_in_transfer = false;
-
- } else {
- src_access.clear();
- textures_to_storage[i]->used_in_compute = false;
- textures_to_storage[i]->used_in_raster = false;
- textures_to_storage[i]->used_in_transfer = false;
- textures_to_storage[i]->used_in_frame = frames_drawn;
- }
-
- RDD::TextureBarrier &tb = texture_barriers[texture_barrier_count++];
- tb.texture = textures_to_storage[i]->driver_id;
- tb.src_access = src_access;
- tb.dst_access = (RDD::BARRIER_ACCESS_SHADER_READ_BIT | RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
- tb.prev_layout = textures_to_storage[i]->layout;
- tb.next_layout = RDD::TEXTURE_LAYOUT_GENERAL;
- tb.subresources.aspect = textures_to_storage[i]->read_aspect_flags;
- tb.subresources.base_mipmap = textures_to_storage[i]->base_mipmap;
- tb.subresources.mipmap_count = textures_to_storage[i]->mipmaps;
- tb.subresources.base_layer = textures_to_storage[i]->base_layer;
- tb.subresources.layer_count = textures_to_storage[i]->layers;
-
- textures_to_storage[i]->layout = RDD::TEXTURE_LAYOUT_GENERAL;
-
- cl->state.textures_to_sampled_layout.insert(textures_to_storage[i]); // Needs to go back to sampled layout afterwards.
- }
- }
-
- if (texture_barrier_count) {
- if (src_stages.is_empty()) {
- src_stages.set_flag(RDD::PIPELINE_STAGE_TOP_OF_PIPE_BIT);
- }
-
- driver->command_pipeline_barrier(cl->command_buffer, src_stages, RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT, {}, {}, VectorView(texture_barriers, texture_barrier_count));
- }
- }
-
#if 0
{ // Validate that textures bound are not attached as framebuffer bindings.
uint32_t attachable_count = uniform_set->attachable_textures.size();
@@ -4901,6 +3961,7 @@ void RenderingDevice::compute_list_bind_uniform_set(ComputeListID p_list, RID p_
void RenderingDevice::compute_list_set_push_constant(ComputeListID p_list, const void *p_data, uint32_t p_data_size) {
ERR_FAIL_COND(p_list != ID_TYPE_COMPUTE_LIST);
ERR_FAIL_NULL(compute_list);
+ ERR_FAIL_COND_MSG(p_data_size > MAX_PUSH_CONSTANT_SIZE, "Push constants can't be bigger than 128 bytes to maintain compatibility.");
ComputeList *cl = compute_list;
@@ -4912,7 +3973,13 @@ void RenderingDevice::compute_list_set_push_constant(ComputeListID p_list, const
ERR_FAIL_COND_MSG(p_data_size != cl->validation.pipeline_push_constant_size,
"This compute pipeline requires (" + itos(cl->validation.pipeline_push_constant_size) + ") bytes of push constant data, supplied: (" + itos(p_data_size) + ")");
#endif
- driver->command_bind_push_constants(cl->command_buffer, cl->state.pipeline_shader_driver_id, 0, VectorView((const uint32_t *)p_data, p_data_size / sizeof(uint32_t)));
+
+ draw_graph.add_compute_list_set_push_constant(cl->state.pipeline_shader_driver_id, p_data, p_data_size);
+
+ // Store it in the state in case we need to restart the compute list.
+ memcpy(cl->state.push_constant_data, p_data, p_data_size);
+ cl->state.push_constant_size = p_data_size;
+
#ifdef DEBUG_ENABLED
cl->validation.pipeline_push_constant_supplied = true;
#endif
@@ -4970,19 +4037,24 @@ void RenderingDevice::compute_list_dispatch(ComputeListID p_list, uint32_t p_x_g
}
}
#endif
- driver->command_uniform_set_prepare_for_use(cl->command_buffer, cl->state.sets[i].uniform_set_driver_id, cl->state.pipeline_shader_driver_id, i);
+ draw_graph.add_compute_list_uniform_set_prepare_for_use(cl->state.pipeline_shader_driver_id, cl->state.sets[i].uniform_set_driver_id, i);
}
for (uint32_t i = 0; i < cl->state.set_count; i++) {
if (cl->state.sets[i].pipeline_expected_format == 0) {
continue; // Nothing expected by this pipeline.
}
if (!cl->state.sets[i].bound) {
- driver->command_bind_compute_uniform_set(cl->command_buffer, cl->state.sets[i].uniform_set_driver_id, cl->state.pipeline_shader_driver_id, i);
+ // All good, see if this requires re-binding.
+ draw_graph.add_compute_list_bind_uniform_set(cl->state.pipeline_shader_driver_id, cl->state.sets[i].uniform_set_driver_id, i);
+
+ UniformSet *uniform_set = uniform_set_owner.get_or_null(cl->state.sets[i].uniform_set);
+ draw_graph.add_compute_list_usages(uniform_set->draw_trackers, uniform_set->draw_trackers_usage);
+
cl->state.sets[i].bound = true;
}
}
- driver->command_compute_dispatch(cl->command_buffer, p_x_groups, p_y_groups, p_z_groups);
+ draw_graph.add_compute_list_dispatch(p_x_groups, p_y_groups, p_z_groups);
}
void RenderingDevice::compute_list_dispatch_threads(ComputeListID p_list, uint32_t p_x_threads, uint32_t p_y_threads, uint32_t p_z_threads) {
@@ -5058,106 +4130,56 @@ void RenderingDevice::compute_list_dispatch_indirect(ComputeListID p_list, RID p
}
}
#endif
- driver->command_uniform_set_prepare_for_use(cl->command_buffer, cl->state.sets[i].uniform_set_driver_id, cl->state.pipeline_shader_driver_id, i);
+ draw_graph.add_compute_list_uniform_set_prepare_for_use(cl->state.pipeline_shader_driver_id, cl->state.sets[i].uniform_set_driver_id, i);
}
for (uint32_t i = 0; i < cl->state.set_count; i++) {
if (cl->state.sets[i].pipeline_expected_format == 0) {
continue; // Nothing expected by this pipeline.
}
if (!cl->state.sets[i].bound) {
- driver->command_bind_compute_uniform_set(cl->command_buffer, cl->state.sets[i].uniform_set_driver_id, cl->state.pipeline_shader_driver_id, i);
+ // All good, see if this requires re-binding.
+ draw_graph.add_compute_list_bind_uniform_set(cl->state.pipeline_shader_driver_id, cl->state.sets[i].uniform_set_driver_id, i);
+
+ UniformSet *uniform_set = uniform_set_owner.get_or_null(cl->state.sets[i].uniform_set);
+ draw_graph.add_compute_list_usages(uniform_set->draw_trackers, uniform_set->draw_trackers_usage);
+
cl->state.sets[i].bound = true;
}
}
- driver->command_compute_dispatch_indirect(cl->command_buffer, buffer->driver_id, p_offset);
+ draw_graph.add_compute_list_dispatch_indirect(buffer->driver_id, p_offset);
+
+ if (buffer->draw_tracker != nullptr) {
+ draw_graph.add_compute_list_usage(buffer->draw_tracker, RDG::RESOURCE_USAGE_INDIRECT_BUFFER_READ);
+ }
}
void RenderingDevice::compute_list_add_barrier(ComputeListID p_list) {
// Must be called within a compute list, the class mutex is locked during that time
- BitField<RDD::PipelineStageBits> stages(RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT);
- BitField<RDD::BarrierAccessBits> access(RDD::BARRIER_ACCESS_SHADER_READ_BIT);
- _compute_list_add_barrier(BARRIER_MASK_COMPUTE, stages, access);
-}
-
-void RenderingDevice::_compute_list_add_barrier(BitField<BarrierMask> p_post_barrier, BitField<RDD::PipelineStageBits> p_stages, BitField<RDD::BarrierAccessBits> p_access) {
- ERR_FAIL_NULL(compute_list);
-
- if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {
- RDD::TextureBarrier *texture_barriers = nullptr;
-
- uint32_t texture_barrier_count = compute_list->state.textures_to_sampled_layout.size();
-
- if (texture_barrier_count) {
- texture_barriers = (RDD::TextureBarrier *)alloca(sizeof(RDD::TextureBarrier) * texture_barrier_count);
- }
-
- texture_barrier_count = 0; // We'll count how many we end up issuing.
-
- for (Texture *E : compute_list->state.textures_to_sampled_layout) {
- if (E->layout != RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
- RDD::TextureBarrier &tb = texture_barriers[texture_barrier_count++];
- tb.texture = E->driver_id;
- tb.src_access = RDD::BARRIER_ACCESS_SHADER_READ_BIT | RDD::BARRIER_ACCESS_SHADER_WRITE_BIT;
- tb.dst_access = p_access;
- tb.prev_layout = E->layout;
- tb.next_layout = RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
- tb.subresources.aspect = E->read_aspect_flags;
- tb.subresources.base_mipmap = E->base_mipmap;
- tb.subresources.mipmap_count = E->mipmaps;
- tb.subresources.base_layer = E->base_layer;
- tb.subresources.layer_count = E->layers;
-
- E->layout = RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
- }
-
- if (E->used_in_frame != frames_drawn) {
- E->used_in_transfer = false;
- E->used_in_raster = false;
- E->used_in_compute = false;
- E->used_in_frame = frames_drawn;
- }
- }
+ compute_list_barrier_state = compute_list->state;
+ compute_list_end();
+ compute_list_begin();
- if (p_stages) {
- RDD::MemoryBarrier mb;
- mb.src_access = RDD::BARRIER_ACCESS_SHADER_WRITE_BIT;
- mb.dst_access = p_access;
- driver->command_pipeline_barrier(compute_list->command_buffer, RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT, p_stages, mb, {}, VectorView(texture_barriers, texture_barrier_count));
+ if (compute_list_barrier_state.pipeline.is_valid()) {
+ compute_list_bind_compute_pipeline(p_list, compute_list_barrier_state.pipeline);
+ }
- } else if (texture_barrier_count) {
- driver->command_pipeline_barrier(compute_list->command_buffer, RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT, RDD::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, {}, {}, VectorView(texture_barriers, texture_barrier_count));
+ for (uint32_t i = 0; i < compute_list_barrier_state.set_count; i++) {
+ if (compute_list_barrier_state.sets[i].uniform_set.is_valid()) {
+ compute_list_bind_uniform_set(p_list, compute_list_barrier_state.sets[i].uniform_set, i);
}
}
-#ifdef FORCE_FULL_BARRIER
- _full_barrier(true);
-#endif
+ if (compute_list_barrier_state.push_constant_size > 0) {
+ compute_list_set_push_constant(p_list, compute_list_barrier_state.push_constant_data, compute_list_barrier_state.push_constant_size);
+ }
}
-void RenderingDevice::compute_list_end(BitField<BarrierMask> p_post_barrier) {
+void RenderingDevice::compute_list_end() {
ERR_FAIL_NULL(compute_list);
- BitField<RDD::PipelineStageBits> stages;
- BitField<RDD::BarrierAccessBits> access;
- if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) {
- stages.set_flag(RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT);
- access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
- }
- if (p_post_barrier.has_flag(BARRIER_MASK_VERTEX)) {
- stages.set_flag(RDD::PIPELINE_STAGE_VERTEX_INPUT_BIT).set_flag(RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT).set_flag(RDD::PIPELINE_STAGE_DRAW_INDIRECT_BIT);
- access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT).set_flag(RDD::BARRIER_ACCESS_INDEX_READ_BIT).set_flag(RDD::BARRIER_ACCESS_VERTEX_ATTRIBUTE_READ_BIT).set_flag(RDD::BARRIER_ACCESS_INDIRECT_COMMAND_READ_BIT);
- }
- if (p_post_barrier.has_flag(BARRIER_MASK_FRAGMENT)) {
- stages.set_flag(RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT).set_flag(RDD::PIPELINE_STAGE_DRAW_INDIRECT_BIT);
- access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT).set_flag(RDD::BARRIER_ACCESS_INDIRECT_COMMAND_READ_BIT);
- }
- if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) {
- stages.set_flag(RDD::PIPELINE_STAGE_TRANSFER_BIT);
- access.set_flag(RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT).set_flag(RDD::BARRIER_ACCESS_TRANSFER_READ_BIT);
- }
- _compute_list_add_barrier(p_post_barrier, stages, access);
+ draw_graph.add_compute_list_end();
memdelete(compute_list);
compute_list = nullptr;
@@ -5166,66 +4188,168 @@ void RenderingDevice::compute_list_end(BitField<BarrierMask> p_post_barrier) {
_THREAD_SAFE_UNLOCK_
}
+#ifndef DISABLE_DEPRECATED
void RenderingDevice::barrier(BitField<BarrierMask> p_from, BitField<BarrierMask> p_to) {
- if (!driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {
- return;
- }
+ WARN_PRINT("Deprecated. Barriers are automatically inserted by RenderingDevice.");
+}
- BitField<RDD::PipelineStageBits> src_stages;
- BitField<RDD::BarrierAccessBits> src_access;
+void RenderingDevice::full_barrier() {
+ WARN_PRINT("Deprecated. Barriers are automatically inserted by RenderingDevice.");
+}
+#endif
- if (p_from == 0) {
- src_stages.set_flag(RDD::PIPELINE_STAGE_TOP_OF_PIPE_BIT);
+/***********************/
+/**** COMMAND GRAPH ****/
+/***********************/
+
+bool RenderingDevice::_texture_make_mutable(Texture *p_texture, RID p_texture_id) {
+ if (p_texture->draw_tracker != nullptr) {
+ // Texture already has a tracker.
+ return false;
} else {
- if (p_from.has_flag(BARRIER_MASK_COMPUTE)) {
- src_stages.set_flag(RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT);
- src_access.set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
- }
- if (p_from.has_flag(BARRIER_MASK_FRAGMENT)) {
- src_stages.set_flag(RDD::PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT).set_flag(RDD::PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT).set_flag(RDD::PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT);
- src_access.set_flag(RDD::BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT).set_flag(RDD::BARRIER_ACCESS_COLOR_ATTACHMENT_WRITE_BIT);
+ if (p_texture->owner.is_valid()) {
+ // Texture has an owner.
+ Texture *owner_texture = texture_owner.get_or_null(p_texture->owner);
+ ERR_FAIL_COND_V(!owner_texture, false);
+
+ if (owner_texture->draw_tracker != nullptr) {
+ // Create a tracker for this dependency in particular.
+ if (p_texture->slice_type == TEXTURE_SLICE_MAX) {
+ // Shared texture.
+ p_texture->draw_tracker = owner_texture->draw_tracker;
+ p_texture->draw_tracker->reference_count++;
+ } else {
+ // Slice texture.
+ HashMap<Rect2i, RDG::ResourceTracker *>::ConstIterator draw_tracker_iterator = owner_texture->slice_trackers.find(p_texture->slice_rect);
+ RDG::ResourceTracker *draw_tracker = nullptr;
+ if (draw_tracker_iterator != owner_texture->slice_trackers.end()) {
+ // Reuse the tracker at the matching rectangle.
+ draw_tracker = draw_tracker_iterator->value;
+ } else {
+ // Create a new tracker and store it on the map.
+ draw_tracker = RDG::resource_tracker_create();
+ draw_tracker->parent = owner_texture->draw_tracker;
+ draw_tracker->texture_driver_id = p_texture->driver_id;
+ draw_tracker->texture_subresources = p_texture->barrier_range();
+ draw_tracker->texture_slice_or_dirty_rect = p_texture->slice_rect;
+ owner_texture->slice_trackers[p_texture->slice_rect] = draw_tracker;
+ }
+
+ p_texture->slice_trackers.clear();
+ p_texture->draw_tracker = draw_tracker;
+ p_texture->draw_tracker->reference_count++;
+ }
+
+ if (p_texture_id.is_valid()) {
+ _dependencies_make_mutable(p_texture_id, p_texture->draw_tracker);
+ }
+ } else {
+ // Delegate this to the owner instead, as it'll make all its dependencies mutable.
+ _texture_make_mutable(owner_texture, p_texture->owner);
+ }
+ } else {
+ // Regular texture.
+ p_texture->draw_tracker = RDG::resource_tracker_create();
+ p_texture->draw_tracker->texture_driver_id = p_texture->driver_id;
+ p_texture->draw_tracker->texture_subresources = p_texture->barrier_range();
+ p_texture->draw_tracker->reference_count = 1;
+
+ if (p_texture_id.is_valid()) {
+ if (p_texture->has_initial_data) {
+ // If the texture was initialized with initial data but wasn't made mutable from the start, assume the texture sampling usage.
+ p_texture->draw_tracker->usage = RDG::RESOURCE_USAGE_TEXTURE_SAMPLE;
+ }
+
+ _dependencies_make_mutable(p_texture_id, p_texture->draw_tracker);
+ }
}
- if (p_from.has_flag(BARRIER_MASK_TRANSFER)) {
- src_stages.set_flag(RDD::PIPELINE_STAGE_TRANSFER_BIT);
- src_access.set_flag(RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT);
+
+ return true;
+ }
+}
+
+bool RenderingDevice::_buffer_make_mutable(Buffer *p_buffer, RID p_buffer_id) {
+ if (p_buffer->draw_tracker != nullptr) {
+ // Buffer already has a tracker.
+ return false;
+ } else {
+ // Create a tracker for the buffer and make all its dependencies mutable.
+ p_buffer->draw_tracker = RDG::resource_tracker_create();
+ p_buffer->draw_tracker->buffer_driver_id = p_buffer->driver_id;
+ if (p_buffer_id.is_valid()) {
+ _dependencies_make_mutable(p_buffer_id, p_buffer->draw_tracker);
}
+
+ return true;
}
+}
- BitField<RDD::PipelineStageBits> dst_stages;
- BitField<RDD::BarrierAccessBits> dst_access;
+bool RenderingDevice::_vertex_array_make_mutable(VertexArray *p_vertex_array, RID p_resource_id, RDG::ResourceTracker *p_resource_tracker) {
+ if (!p_vertex_array->untracked_buffers.has(p_resource_id)) {
+ // Vertex array thinks the buffer is already tracked or does not use it.
+ return false;
+ } else {
+ // Vertex array is aware of the buffer but it isn't being tracked.
+ p_vertex_array->draw_trackers.push_back(p_resource_tracker);
+ p_vertex_array->untracked_buffers.erase(p_resource_id);
+ return true;
+ }
+}
- if (p_to == 0) {
- dst_stages.set_flag(RDD::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT);
+bool RenderingDevice::_index_array_make_mutable(IndexArray *p_index_array, RDG::ResourceTracker *p_resource_tracker) {
+ if (p_index_array->draw_tracker != nullptr) {
+ // Index array already has a tracker.
+ return false;
} else {
- if (p_to.has_flag(BARRIER_MASK_COMPUTE)) {
- dst_stages.set_flag(RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT);
- dst_access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
- }
- if (p_to.has_flag(BARRIER_MASK_VERTEX)) {
- dst_stages.set_flag(RDD::PIPELINE_STAGE_VERTEX_INPUT_BIT).set_flag(RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT).set_flag(RDD::PIPELINE_STAGE_DRAW_INDIRECT_BIT);
- dst_access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT).set_flag(RDD::BARRIER_ACCESS_INDEX_READ_BIT).set_flag(RDD::BARRIER_ACCESS_VERTEX_ATTRIBUTE_READ_BIT).set_flag(RDD::BARRIER_ACCESS_INDIRECT_COMMAND_READ_BIT);
- }
- if (p_to.has_flag(BARRIER_MASK_FRAGMENT)) {
- dst_stages.set_flag(RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT).set_flag(RDD::PIPELINE_STAGE_DRAW_INDIRECT_BIT);
- dst_access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT).set_flag(RDD::BARRIER_ACCESS_INDIRECT_COMMAND_READ_BIT);
- }
- if (p_to.has_flag(BARRIER_MASK_TRANSFER)) {
- dst_stages.set_flag(RDD::PIPELINE_STAGE_TRANSFER_BIT);
- dst_access.set_flag(RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT).set_flag(RDD::BARRIER_ACCESS_TRANSFER_READ_BIT);
- }
+ // Index array should assign the tracker from the buffer.
+ p_index_array->draw_tracker = p_resource_tracker;
+ return true;
}
+}
- RDD::MemoryBarrier mb;
- mb.src_access = src_access;
- mb.dst_access = dst_access;
- driver->command_pipeline_barrier(frames[frame].draw_command_buffer, src_stages, dst_stages, mb, {}, {});
+bool RenderingDevice::_uniform_set_make_mutable(UniformSet *p_uniform_set, RID p_resource_id, RDG::ResourceTracker *p_resource_tracker) {
+ HashMap<RID, RDG::ResourceUsage>::Iterator E = p_uniform_set->untracked_usage.find(p_resource_id);
+ if (!E) {
+ // Uniform set thinks the resource is already tracked or does not use it.
+ return false;
+ } else {
+ // Uniform set has seen the resource but hasn't added its tracker yet.
+ p_uniform_set->draw_trackers.push_back(p_resource_tracker);
+ p_uniform_set->draw_trackers_usage.push_back(E->value);
+ p_uniform_set->untracked_usage.remove(E);
+ return true;
+ }
}
-void RenderingDevice::full_barrier() {
-#ifndef DEBUG_ENABLED
- ERR_PRINT("Full barrier is debug-only, should not be used in production");
-#endif
- _full_barrier(true);
+bool RenderingDevice::_dependency_make_mutable(RID p_id, RID p_resource_id, RDG::ResourceTracker *p_resource_tracker) {
+ if (texture_owner.owns(p_id)) {
+ Texture *texture = texture_owner.get_or_null(p_id);
+ return _texture_make_mutable(texture, p_id);
+ } else if (vertex_array_owner.owns(p_id)) {
+ VertexArray *vertex_array = vertex_array_owner.get_or_null(p_id);
+ return _vertex_array_make_mutable(vertex_array, p_resource_id, p_resource_tracker);
+ } else if (index_array_owner.owns(p_id)) {
+ IndexArray *index_array = index_array_owner.get_or_null(p_id);
+ return _index_array_make_mutable(index_array, p_resource_tracker);
+ } else if (uniform_set_owner.owns(p_id)) {
+ UniformSet *uniform_set = uniform_set_owner.get_or_null(p_id);
+ return _uniform_set_make_mutable(uniform_set, p_resource_id, p_resource_tracker);
+ } else {
+ DEV_ASSERT(false && "Unknown resource type to make mutable.");
+ return false;
+ }
+}
+
+bool RenderingDevice::_dependencies_make_mutable(RID p_id, RDG::ResourceTracker *p_resource_tracker) {
+ bool made_mutable = false;
+ HashMap<RID, HashSet<RID>>::Iterator E = dependency_map.find(p_id);
+ if (E) {
+ for (RID rid : E->value) {
+ made_mutable = _dependency_make_mutable(rid, p_id, p_resource_tracker) || made_mutable;
+ }
+ }
+
+ return made_mutable;
}
/**************************/
@@ -5251,6 +4375,22 @@ void RenderingDevice::_free_internal(RID p_id) {
// Push everything so it's disposed of next time this frame index is processed (means, it's safe to do it).
if (texture_owner.owns(p_id)) {
Texture *texture = texture_owner.get_or_null(p_id);
+ RDG::ResourceTracker *draw_tracker = texture->draw_tracker;
+ if (draw_tracker != nullptr) {
+ draw_tracker->reference_count--;
+ if (draw_tracker->reference_count == 0) {
+ RDG::resource_tracker_free(draw_tracker);
+
+ if (texture->owner.is_valid() && (texture->slice_type != TEXTURE_SLICE_MAX)) {
+ // If this was a texture slice, erase the tracker from the map.
+ Texture *owner_texture = texture_owner.get_or_null(texture->owner);
+ if (owner_texture != nullptr) {
+ owner_texture->slice_trackers.erase(texture->slice_rect);
+ }
+ }
+ }
+ }
+
frames[frame].textures_to_dispose_of.push_back(*texture);
texture_owner.free(p_id);
} else if (framebuffer_owner.owns(p_id)) {
@@ -5268,12 +4408,14 @@ void RenderingDevice::_free_internal(RID p_id) {
sampler_owner.free(p_id);
} else if (vertex_buffer_owner.owns(p_id)) {
Buffer *vertex_buffer = vertex_buffer_owner.get_or_null(p_id);
+ RDG::resource_tracker_free(vertex_buffer->draw_tracker);
frames[frame].buffers_to_dispose_of.push_back(*vertex_buffer);
vertex_buffer_owner.free(p_id);
} else if (vertex_array_owner.owns(p_id)) {
vertex_array_owner.free(p_id);
} else if (index_buffer_owner.owns(p_id)) {
IndexBuffer *index_buffer = index_buffer_owner.get_or_null(p_id);
+ RDG::resource_tracker_free(index_buffer->draw_tracker);
frames[frame].buffers_to_dispose_of.push_back(*index_buffer);
index_buffer_owner.free(p_id);
} else if (index_array_owner.owns(p_id)) {
@@ -5286,14 +4428,17 @@ void RenderingDevice::_free_internal(RID p_id) {
shader_owner.free(p_id);
} else if (uniform_buffer_owner.owns(p_id)) {
Buffer *uniform_buffer = uniform_buffer_owner.get_or_null(p_id);
+ RDG::resource_tracker_free(uniform_buffer->draw_tracker);
frames[frame].buffers_to_dispose_of.push_back(*uniform_buffer);
uniform_buffer_owner.free(p_id);
} else if (texture_buffer_owner.owns(p_id)) {
Buffer *texture_buffer = texture_buffer_owner.get_or_null(p_id);
+ RDG::resource_tracker_free(texture_buffer->draw_tracker);
frames[frame].buffers_to_dispose_of.push_back(*texture_buffer);
texture_buffer_owner.free(p_id);
} else if (storage_buffer_owner.owns(p_id)) {
Buffer *storage_buffer = storage_buffer_owner.get_or_null(p_id);
+ RDG::resource_tracker_free(storage_buffer->draw_tracker);
frames[frame].buffers_to_dispose_of.push_back(*storage_buffer);
storage_buffer_owner.free(p_id);
} else if (uniform_set_owner.owns(p_id)) {
@@ -5370,18 +4515,21 @@ void RenderingDevice::set_resource_name(RID p_id, const String &p_name) {
}
void RenderingDevice::draw_command_begin_label(String p_label_name, const Color &p_color) {
- _THREAD_SAFE_METHOD_
- context->command_begin_label(frames[frame].draw_command_buffer, p_label_name, p_color);
+ if (!context->is_debug_utils_enabled()) {
+ return;
+ }
+
+ draw_graph.begin_label(p_label_name, p_color);
}
+#ifndef DISABLE_DEPRECATED
void RenderingDevice::draw_command_insert_label(String p_label_name, const Color &p_color) {
- _THREAD_SAFE_METHOD_
- context->command_insert_label(frames[frame].draw_command_buffer, p_label_name, p_color);
+ WARN_PRINT("Deprecated. Inserting labels no longer applies due to command reordering.");
}
+#endif
void RenderingDevice::draw_command_end_label() {
- _THREAD_SAFE_METHOD_
- context->command_end_label(frames[frame].draw_command_buffer);
+ draw_graph.end_label();
}
String RenderingDevice::get_device_vendor_name() const {
@@ -5404,7 +4552,7 @@ String RenderingDevice::get_device_pipeline_cache_uuid() const {
return context->get_device_pipeline_cache_uuid();
}
-void RenderingDevice::_finalize_command_bufers() {
+void RenderingDevice::_finalize_command_buffers(bool p_postpare) {
if (draw_list) {
ERR_PRINT("Found open draw list at the end of the frame, this should never happen (further drawing will likely not work).");
}
@@ -5413,7 +4561,13 @@ void RenderingDevice::_finalize_command_bufers() {
ERR_PRINT("Found open compute list at the end of the frame, this should never happen (further compute will likely not work).");
}
- {
+ { // Complete the setup buffer (that needs to be processed before anything else).
+ draw_graph.end(frames[frame].draw_command_buffer, RENDER_GRAPH_REORDER, RENDER_GRAPH_FULL_BARRIERS);
+
+ if (p_postpare) {
+ context->postpare_buffers(frames[frame].draw_command_buffer);
+ }
+
driver->end_segment();
driver->command_buffer_end(frames[frame].setup_command_buffer);
driver->command_buffer_end(frames[frame].draw_command_buffer);
@@ -5421,6 +4575,8 @@ void RenderingDevice::_finalize_command_bufers() {
}
void RenderingDevice::_begin_frame() {
+ draw_graph.begin();
+
// Erase pending resources.
_free_pending_resources(frame);
@@ -5464,12 +4620,15 @@ void RenderingDevice::swap_buffers() {
ERR_FAIL_COND_MSG(local_device.is_valid(), "Local devices can't swap buffers.");
_THREAD_SAFE_METHOD_
- context->postpare_buffers(frames[frame].draw_command_buffer);
- _finalize_command_bufers();
+ _finalize_command_buffers(true);
- screen_prepared = false;
// Swap buffers.
- context->swap_buffers();
+ if (!screen_prepared) {
+ context->flush(true, true, false);
+ } else {
+ screen_prepared = false;
+ context->swap_buffers();
+ }
frame = (frame + 1) % frame_count;
@@ -5482,7 +4641,7 @@ void RenderingDevice::submit() {
ERR_FAIL_COND_MSG(local_device.is_null(), "Only local devices can submit and sync.");
ERR_FAIL_COND_MSG(local_device_processing, "device already submitted, call sync to wait until done.");
- _finalize_command_bufers();
+ _finalize_command_buffers(false);
RDD::CommandBufferID command_buffers[2] = { frames[frame].setup_command_buffer, frames[frame].draw_command_buffer };
context->local_device_push_command_buffers(local_device, command_buffers, 2);
@@ -5614,11 +4773,14 @@ void RenderingDevice::_flush(bool p_current_frame) {
if (local_device.is_valid() && !p_current_frame) {
return; // Flushing previous frames has no effect with local device.
}
+
// Not doing this crashes RADV (undefined behavior).
if (p_current_frame) {
+ draw_graph.end(frames[frame].draw_command_buffer, RENDER_GRAPH_REORDER, RENDER_GRAPH_FULL_BARRIERS);
driver->end_segment();
driver->command_buffer_end(frames[frame].setup_command_buffer);
driver->command_buffer_end(frames[frame].draw_command_buffer);
+ draw_graph.begin();
}
if (local_device.is_valid()) {
@@ -5739,7 +4901,6 @@ void RenderingDevice::initialize(ApiContextRD *p_context, bool p_local_device) {
draw_list = nullptr;
draw_list_count = 0;
- draw_list_split = false;
compute_list = nullptr;
@@ -5756,6 +4917,8 @@ void RenderingDevice::initialize(ApiContextRD *p_context, bool p_local_device) {
pipelines_cache_size = driver->pipeline_cache_query_size();
print_verbose(vformat("Startup PSO cache (%.1f MiB)", pipelines_cache_size / (1024.0f * 1024.0f)));
}
+
+ draw_graph.initialize(driver, frame_count, SECONDARY_COMMAND_BUFFERS_PER_FRAME);
}
Vector<uint8_t> RenderingDevice::_load_pipeline_cache() {
@@ -5853,46 +5016,11 @@ void RenderingDevice::_free_rids(T &p_owner, const char *p_type) {
void RenderingDevice::capture_timestamp(const String &p_name) {
ERR_FAIL_COND_MSG(draw_list != nullptr, "Capturing timestamps during draw list creation is not allowed. Offending timestamp was: " + p_name);
+ ERR_FAIL_COND_MSG(compute_list != nullptr, "Capturing timestamps during compute list creation is not allowed. Offending timestamp was: " + p_name);
ERR_FAIL_COND(frames[frame].timestamp_count >= max_timestamp_query_elements);
- // This should be optional for profiling, else it will slow things down.
- if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {
- RDD::MemoryBarrier mb;
- mb.src_access = (RDD::BARRIER_ACCESS_INDIRECT_COMMAND_READ_BIT |
- RDD::BARRIER_ACCESS_INDEX_READ_BIT |
- RDD::BARRIER_ACCESS_VERTEX_ATTRIBUTE_READ_BIT |
- RDD::BARRIER_ACCESS_UNIFORM_READ_BIT |
- RDD::BARRIER_ACCESS_INPUT_ATTACHMENT_READ_BIT |
- RDD::BARRIER_ACCESS_SHADER_READ_BIT |
- RDD::BARRIER_ACCESS_SHADER_WRITE_BIT |
- RDD::BARRIER_ACCESS_COLOR_ATTACHMENT_READ_BIT |
- RDD::BARRIER_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
- RDD::BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
- RDD::BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
- RDD::BARRIER_ACCESS_TRANSFER_READ_BIT |
- RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT |
- RDD::BARRIER_ACCESS_HOST_READ_BIT |
- RDD::BARRIER_ACCESS_HOST_WRITE_BIT);
- mb.dst_access = (RDD::BARRIER_ACCESS_INDIRECT_COMMAND_READ_BIT |
- RDD::BARRIER_ACCESS_INDEX_READ_BIT |
- RDD::BARRIER_ACCESS_VERTEX_ATTRIBUTE_READ_BIT |
- RDD::BARRIER_ACCESS_UNIFORM_READ_BIT |
- RDD::BARRIER_ACCESS_INPUT_ATTACHMENT_READ_BIT |
- RDD::BARRIER_ACCESS_SHADER_READ_BIT |
- RDD::BARRIER_ACCESS_SHADER_WRITE_BIT |
- RDD::BARRIER_ACCESS_COLOR_ATTACHMENT_READ_BIT |
- RDD::BARRIER_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
- RDD::BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
- RDD::BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
- RDD::BARRIER_ACCESS_TRANSFER_READ_BIT |
- RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT |
- RDD::BARRIER_ACCESS_HOST_READ_BIT |
- RDD::BARRIER_ACCESS_HOST_WRITE_BIT);
-
- driver->command_pipeline_barrier(frames[frame].draw_command_buffer, RDD::PIPELINE_STAGE_ALL_COMMANDS_BIT, RDD::PIPELINE_STAGE_ALL_COMMANDS_BIT, mb, {}, {});
- }
-
- driver->command_timestamp_write(frames[frame].draw_command_buffer, frames[frame].timestamp_pool, frames[frame].timestamp_count);
+ draw_graph.add_capture_timestamp(frames[frame].timestamp_pool, frames[frame].timestamp_count);
+
frames[frame].timestamp_names[frames[frame].timestamp_count] = p_name;
frames[frame].timestamp_cpu_values[frames[frame].timestamp_count] = OS::get_singleton()->get_ticks_usec();
frames[frame].timestamp_count++;
@@ -6060,10 +5188,6 @@ void RenderingDevice::finalize() {
driver->pipeline_cache_free();
}
- for (int i = 0; i < split_draw_list_allocators.size(); i++) {
- driver->command_pool_free(split_draw_list_allocators[i].command_pool);
- }
-
frames.clear();
for (int i = 0; i < staging_buffer_blocks.size(); i++) {
@@ -6102,7 +5226,7 @@ void RenderingDevice::_bind_methods() {
ClassDB::bind_method(D_METHOD("texture_create_shared_from_slice", "view", "with_texture", "layer", "mipmap", "mipmaps", "slice_type"), &RenderingDevice::_texture_create_shared_from_slice, DEFVAL(1), DEFVAL(TEXTURE_SLICE_2D));
ClassDB::bind_method(D_METHOD("texture_create_from_extension", "type", "format", "samples", "usage_flags", "image", "width", "height", "depth", "layers"), &RenderingDevice::texture_create_from_extension);
- ClassDB::bind_method(D_METHOD("texture_update", "texture", "layer", "data", "post_barrier"), &RenderingDevice::texture_update, DEFVAL(BARRIER_MASK_ALL_BARRIERS));
+ ClassDB::bind_method(D_METHOD("texture_update", "texture", "layer", "data"), &RenderingDevice::texture_update);
ClassDB::bind_method(D_METHOD("texture_get_data", "texture", "layer"), &RenderingDevice::texture_get_data);
ClassDB::bind_method(D_METHOD("texture_is_format_supported_for_usage", "format", "usage_flags"), &RenderingDevice::texture_is_format_supported_for_usage);
@@ -6110,9 +5234,9 @@ void RenderingDevice::_bind_methods() {
ClassDB::bind_method(D_METHOD("texture_is_shared", "texture"), &RenderingDevice::texture_is_shared);
ClassDB::bind_method(D_METHOD("texture_is_valid", "texture"), &RenderingDevice::texture_is_valid);
- ClassDB::bind_method(D_METHOD("texture_copy", "from_texture", "to_texture", "from_pos", "to_pos", "size", "src_mipmap", "dst_mipmap", "src_layer", "dst_layer", "post_barrier"), &RenderingDevice::texture_copy, DEFVAL(BARRIER_MASK_ALL_BARRIERS));
- ClassDB::bind_method(D_METHOD("texture_clear", "texture", "color", "base_mipmap", "mipmap_count", "base_layer", "layer_count", "post_barrier"), &RenderingDevice::texture_clear, DEFVAL(BARRIER_MASK_ALL_BARRIERS));
- ClassDB::bind_method(D_METHOD("texture_resolve_multisample", "from_texture", "to_texture", "post_barrier"), &RenderingDevice::texture_resolve_multisample, DEFVAL(BARRIER_MASK_ALL_BARRIERS));
+ ClassDB::bind_method(D_METHOD("texture_copy", "from_texture", "to_texture", "from_pos", "to_pos", "size", "src_mipmap", "dst_mipmap", "src_layer", "dst_layer"), &RenderingDevice::texture_copy);
+ ClassDB::bind_method(D_METHOD("texture_clear", "texture", "color", "base_mipmap", "mipmap_count", "base_layer", "layer_count"), &RenderingDevice::texture_clear);
+ ClassDB::bind_method(D_METHOD("texture_resolve_multisample", "from_texture", "to_texture"), &RenderingDevice::texture_resolve_multisample);
ClassDB::bind_method(D_METHOD("texture_get_format", "texture"), &RenderingDevice::_texture_get_format);
#ifndef DISABLE_DEPRECATED
@@ -6154,8 +5278,9 @@ void RenderingDevice::_bind_methods() {
ClassDB::bind_method(D_METHOD("uniform_set_create", "uniforms", "shader", "shader_set"), &RenderingDevice::_uniform_set_create);
ClassDB::bind_method(D_METHOD("uniform_set_is_valid", "uniform_set"), &RenderingDevice::uniform_set_is_valid);
- ClassDB::bind_method(D_METHOD("buffer_update", "buffer", "offset", "size_bytes", "data", "post_barrier"), &RenderingDevice::_buffer_update_bind, DEFVAL(BARRIER_MASK_ALL_BARRIERS));
- ClassDB::bind_method(D_METHOD("buffer_clear", "buffer", "offset", "size_bytes", "post_barrier"), &RenderingDevice::buffer_clear, DEFVAL(BARRIER_MASK_ALL_BARRIERS));
+ ClassDB::bind_method(D_METHOD("buffer_copy", "src_buffer", "dst_buffer", "src_offset", "dst_offset", "size"), &RenderingDevice::buffer_copy);
+ ClassDB::bind_method(D_METHOD("buffer_update", "buffer", "offset", "size_bytes", "data"), &RenderingDevice::_buffer_update_bind);
+ ClassDB::bind_method(D_METHOD("buffer_clear", "buffer", "offset", "size_bytes"), &RenderingDevice::buffer_clear);
ClassDB::bind_method(D_METHOD("buffer_get_data", "buffer", "offset_bytes", "size_bytes"), &RenderingDevice::buffer_get_data, DEFVAL(0), DEFVAL(0));
ClassDB::bind_method(D_METHOD("render_pipeline_create", "shader", "framebuffer_format", "vertex_format", "primitive", "rasterization_state", "multisample_state", "stencil_state", "color_blend_state", "dynamic_state_flags", "for_render_pass", "specialization_constants"), &RenderingDevice::_render_pipeline_create, DEFVAL(0), DEFVAL(0), DEFVAL(TypedArray<RDPipelineSpecializationConstant>()));
@@ -6170,8 +5295,10 @@ void RenderingDevice::_bind_methods() {
ClassDB::bind_method(D_METHOD("draw_list_begin_for_screen", "screen", "clear_color"), &RenderingDevice::draw_list_begin_for_screen, DEFVAL(DisplayServer::MAIN_WINDOW_ID), DEFVAL(Color()));
- ClassDB::bind_method(D_METHOD("draw_list_begin", "framebuffer", "initial_color_action", "final_color_action", "initial_depth_action", "final_depth_action", "clear_color_values", "clear_depth", "clear_stencil", "region", "storage_textures"), &RenderingDevice::_draw_list_begin, DEFVAL(Vector<Color>()), DEFVAL(1.0), DEFVAL(0), DEFVAL(Rect2()), DEFVAL(TypedArray<RID>()));
+ ClassDB::bind_method(D_METHOD("draw_list_begin", "framebuffer", "initial_color_action", "final_color_action", "initial_depth_action", "final_depth_action", "clear_color_values", "clear_depth", "clear_stencil", "region"), &RenderingDevice::draw_list_begin, DEFVAL(Vector<Color>()), DEFVAL(1.0), DEFVAL(0), DEFVAL(Rect2()));
+#ifndef DISABLE_DEPRECATED
ClassDB::bind_method(D_METHOD("draw_list_begin_split", "framebuffer", "splits", "initial_color_action", "final_color_action", "initial_depth_action", "final_depth_action", "clear_color_values", "clear_depth", "clear_stencil", "region", "storage_textures"), &RenderingDevice::_draw_list_begin_split, DEFVAL(Vector<Color>()), DEFVAL(1.0), DEFVAL(0), DEFVAL(Rect2()), DEFVAL(TypedArray<RID>()));
+#endif
ClassDB::bind_method(D_METHOD("draw_list_set_blend_constants", "draw_list", "color"), &RenderingDevice::draw_list_set_blend_constants);
ClassDB::bind_method(D_METHOD("draw_list_bind_render_pipeline", "draw_list", "render_pipeline"), &RenderingDevice::draw_list_bind_render_pipeline);
@@ -6186,17 +5313,19 @@ void RenderingDevice::_bind_methods() {
ClassDB::bind_method(D_METHOD("draw_list_disable_scissor", "draw_list"), &RenderingDevice::draw_list_disable_scissor);
ClassDB::bind_method(D_METHOD("draw_list_switch_to_next_pass"), &RenderingDevice::draw_list_switch_to_next_pass);
+#ifndef DISABLE_DEPRECATED
ClassDB::bind_method(D_METHOD("draw_list_switch_to_next_pass_split", "splits"), &RenderingDevice::_draw_list_switch_to_next_pass_split);
+#endif
- ClassDB::bind_method(D_METHOD("draw_list_end", "post_barrier"), &RenderingDevice::draw_list_end, DEFVAL(BARRIER_MASK_ALL_BARRIERS));
+ ClassDB::bind_method(D_METHOD("draw_list_end"), &RenderingDevice::draw_list_end);
- ClassDB::bind_method(D_METHOD("compute_list_begin", "allow_draw_overlap"), &RenderingDevice::compute_list_begin, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("compute_list_begin"), &RenderingDevice::compute_list_begin);
ClassDB::bind_method(D_METHOD("compute_list_bind_compute_pipeline", "compute_list", "compute_pipeline"), &RenderingDevice::compute_list_bind_compute_pipeline);
ClassDB::bind_method(D_METHOD("compute_list_set_push_constant", "compute_list", "buffer", "size_bytes"), &RenderingDevice::_compute_list_set_push_constant);
ClassDB::bind_method(D_METHOD("compute_list_bind_uniform_set", "compute_list", "uniform_set", "set_index"), &RenderingDevice::compute_list_bind_uniform_set);
ClassDB::bind_method(D_METHOD("compute_list_dispatch", "compute_list", "x_groups", "y_groups", "z_groups"), &RenderingDevice::compute_list_dispatch);
ClassDB::bind_method(D_METHOD("compute_list_add_barrier", "compute_list"), &RenderingDevice::compute_list_add_barrier);
- ClassDB::bind_method(D_METHOD("compute_list_end", "post_barrier"), &RenderingDevice::compute_list_end, DEFVAL(BARRIER_MASK_ALL_BARRIERS));
+ ClassDB::bind_method(D_METHOD("compute_list_end"), &RenderingDevice::compute_list_end);
ClassDB::bind_method(D_METHOD("free_rid", "rid"), &RenderingDevice::free);
@@ -6212,15 +5341,19 @@ void RenderingDevice::_bind_methods() {
ClassDB::bind_method(D_METHOD("submit"), &RenderingDevice::submit);
ClassDB::bind_method(D_METHOD("sync"), &RenderingDevice::sync);
+#ifndef DISABLE_DEPRECATED
ClassDB::bind_method(D_METHOD("barrier", "from", "to"), &RenderingDevice::barrier, DEFVAL(BARRIER_MASK_ALL_BARRIERS), DEFVAL(BARRIER_MASK_ALL_BARRIERS));
ClassDB::bind_method(D_METHOD("full_barrier"), &RenderingDevice::full_barrier);
+#endif
ClassDB::bind_method(D_METHOD("create_local_device"), &RenderingDevice::create_local_device);
ClassDB::bind_method(D_METHOD("set_resource_name", "id", "name"), &RenderingDevice::set_resource_name);
ClassDB::bind_method(D_METHOD("draw_command_begin_label", "name", "color"), &RenderingDevice::draw_command_begin_label);
+#ifndef DISABLE_DEPRECATED
ClassDB::bind_method(D_METHOD("draw_command_insert_label", "name", "color"), &RenderingDevice::draw_command_insert_label);
+#endif
ClassDB::bind_method(D_METHOD("draw_command_end_label"), &RenderingDevice::draw_command_end_label);
ClassDB::bind_method(D_METHOD("get_device_vendor_name"), &RenderingDevice::get_device_vendor_name);
@@ -6487,6 +5620,7 @@ void RenderingDevice::_bind_methods() {
BIND_ENUM_CONSTANT(DATA_FORMAT_G16_B16_R16_3PLANE_444_UNORM);
BIND_ENUM_CONSTANT(DATA_FORMAT_MAX);
+#ifndef DISABLE_DEPRECATED
BIND_BITFIELD_FLAG(BARRIER_MASK_VERTEX);
BIND_BITFIELD_FLAG(BARRIER_MASK_FRAGMENT);
BIND_BITFIELD_FLAG(BARRIER_MASK_COMPUTE);
@@ -6494,6 +5628,7 @@ void RenderingDevice::_bind_methods() {
BIND_BITFIELD_FLAG(BARRIER_MASK_RASTER);
BIND_BITFIELD_FLAG(BARRIER_MASK_ALL_BARRIERS);
BIND_BITFIELD_FLAG(BARRIER_MASK_NO_BARRIER);
+#endif
BIND_ENUM_CONSTANT(TEXTURE_TYPE_1D);
BIND_ENUM_CONSTANT(TEXTURE_TYPE_2D);
@@ -6668,18 +5803,25 @@ void RenderingDevice::_bind_methods() {
BIND_BITFIELD_FLAG(DYNAMIC_STATE_STENCIL_WRITE_MASK);
BIND_BITFIELD_FLAG(DYNAMIC_STATE_STENCIL_REFERENCE);
- BIND_ENUM_CONSTANT(INITIAL_ACTION_CLEAR); //start rendering and clear the framebuffer (supply params)
- BIND_ENUM_CONSTANT(INITIAL_ACTION_CLEAR_REGION); //start rendering and clear the framebuffer (supply params)
- BIND_ENUM_CONSTANT(INITIAL_ACTION_CLEAR_REGION_CONTINUE); //continue rendering and clear the framebuffer (supply params)
- BIND_ENUM_CONSTANT(INITIAL_ACTION_KEEP); //start rendering); but keep attached color texture contents (depth will be cleared)
- BIND_ENUM_CONSTANT(INITIAL_ACTION_DROP); //start rendering); ignore what is there); just write above it
- BIND_ENUM_CONSTANT(INITIAL_ACTION_CONTINUE); //continue rendering (framebuffer must have been left in "continue" state as final action previously)
+ BIND_ENUM_CONSTANT(INITIAL_ACTION_LOAD);
+ BIND_ENUM_CONSTANT(INITIAL_ACTION_CLEAR);
+ BIND_ENUM_CONSTANT(INITIAL_ACTION_DISCARD);
BIND_ENUM_CONSTANT(INITIAL_ACTION_MAX);
+#ifndef DISABLE_DEPRECATED
+ BIND_ENUM_CONSTANT(INITIAL_ACTION_CLEAR_REGION);
+ BIND_ENUM_CONSTANT(INITIAL_ACTION_CLEAR_REGION_CONTINUE);
+ BIND_ENUM_CONSTANT(INITIAL_ACTION_KEEP);
+ BIND_ENUM_CONSTANT(INITIAL_ACTION_DROP);
+ BIND_ENUM_CONSTANT(INITIAL_ACTION_CONTINUE);
+#endif
- BIND_ENUM_CONSTANT(FINAL_ACTION_READ); //will no longer render to it); allows attached textures to be read again); but depth buffer contents will be dropped (Can't be read from)
- BIND_ENUM_CONSTANT(FINAL_ACTION_DISCARD); // discard contents after rendering
- BIND_ENUM_CONSTANT(FINAL_ACTION_CONTINUE); //will continue rendering later); attached textures can't be read until re-bound with "finish"
+ BIND_ENUM_CONSTANT(FINAL_ACTION_STORE);
+ BIND_ENUM_CONSTANT(FINAL_ACTION_DISCARD);
BIND_ENUM_CONSTANT(FINAL_ACTION_MAX);
+#ifndef DISABLE_DEPRECATED
+ BIND_ENUM_CONSTANT(FINAL_ACTION_READ);
+ BIND_ENUM_CONSTANT(FINAL_ACTION_CONTINUE);
+#endif
BIND_ENUM_CONSTANT(SHADER_STAGE_VERTEX);
BIND_ENUM_CONSTANT(SHADER_STAGE_FRAGMENT);
@@ -6946,8 +6088,8 @@ RID RenderingDevice::_uniform_set_create(const TypedArray<RDUniform> &p_uniforms
return uniform_set_create(uniforms, p_shader, p_shader_set);
}
-Error RenderingDevice::_buffer_update_bind(RID p_buffer, uint32_t p_offset, uint32_t p_size, const Vector<uint8_t> &p_data, BitField<BarrierMask> p_post_barrier) {
- return buffer_update(p_buffer, p_offset, p_size, p_data.ptr(), p_post_barrier);
+Error RenderingDevice::_buffer_update_bind(RID p_buffer, uint32_t p_offset, uint32_t p_size, const Vector<uint8_t> &p_data) {
+ return buffer_update(p_buffer, p_offset, p_size, p_data.ptr());
}
static Vector<RenderingDevice::PipelineSpecializationConstant> _get_spec_constants(const TypedArray<RDPipelineSpecializationConstant> &p_constants) {
@@ -7018,47 +6160,15 @@ RID RenderingDevice::_compute_pipeline_create(RID p_shader, const TypedArray<RDP
return compute_pipeline_create(p_shader, _get_spec_constants(p_specialization_constants));
}
-RenderingDevice::DrawListID RenderingDevice::_draw_list_begin(RID p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const TypedArray<RID> &p_storage_textures) {
- Vector<RID> stextures;
- for (int i = 0; i < p_storage_textures.size(); i++) {
- stextures.push_back(p_storage_textures[i]);
- }
- return draw_list_begin(p_framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, p_region, stextures);
-}
-
+#ifndef DISABLE_DEPRECATED
Vector<int64_t> RenderingDevice::_draw_list_begin_split(RID p_framebuffer, uint32_t p_splits, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const TypedArray<RID> &p_storage_textures) {
- Vector<DrawListID> splits;
- splits.resize(p_splits);
- Vector<RID> stextures;
- for (int i = 0; i < p_storage_textures.size(); i++) {
- stextures.push_back(p_storage_textures[i]);
- }
- draw_list_begin_split(p_framebuffer, p_splits, splits.ptrw(), p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, p_region, stextures);
-
- Vector<int64_t> split_ids;
- split_ids.resize(splits.size());
- for (int i = 0; i < splits.size(); i++) {
- split_ids.write[i] = splits[i];
- }
-
- return split_ids;
+ ERR_FAIL_V_MSG(Vector<int64_t>(), "Deprecated. Split draw lists are used automatically by RenderingDevice.");
}
Vector<int64_t> RenderingDevice::_draw_list_switch_to_next_pass_split(uint32_t p_splits) {
- Vector<DrawListID> splits;
- splits.resize(p_splits);
-
- Error err = draw_list_switch_to_next_pass_split(p_splits, splits.ptrw());
- ERR_FAIL_COND_V(err != OK, Vector<int64_t>());
-
- Vector<int64_t> split_ids;
- split_ids.resize(splits.size());
- for (int i = 0; i < splits.size(); i++) {
- split_ids.write[i] = splits[i];
- }
-
- return split_ids;
+ ERR_FAIL_V_MSG(Vector<int64_t>(), "Deprecated. Split draw lists are used automatically by RenderingDevice.");
}
+#endif
void RenderingDevice::_draw_list_set_push_constant(DrawListID p_list, const Vector<uint8_t> &p_data, uint32_t p_data_size) {
ERR_FAIL_COND((uint32_t)p_data.size() > p_data_size);
diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h
index 90ed2828c0..2ccef66308 100644
--- a/servers/rendering/rendering_device.h
+++ b/servers/rendering/rendering_device.h
@@ -42,6 +42,7 @@
#include "servers/rendering/rendering_device.h"
#include "servers/rendering/rendering_device_commons.h"
#include "servers/rendering/rendering_device_driver.h"
+#include "servers/rendering/rendering_device_graph.h"
class RDTextureFormat;
class RDTextureView;
@@ -93,6 +94,9 @@ public:
uint32_t version_minor = 0;
};
+ typedef int64_t DrawListID;
+ typedef int64_t ComputeListID;
+
typedef String (*ShaderSPIRVGetCacheKeyFunction)(const RenderingDevice *p_render_device);
typedef Vector<uint8_t> (*ShaderCompileToSPIRVFunction)(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language, String *r_error, const RenderingDevice *p_render_device);
typedef Vector<uint8_t> (*ShaderCacheFunction)(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language);
@@ -131,8 +135,7 @@ public:
ID_TYPE_FRAMEBUFFER_FORMAT,
ID_TYPE_VERTEX_FORMAT,
ID_TYPE_DRAW_LIST,
- ID_TYPE_SPLIT_DRAW_LIST,
- ID_TYPE_COMPUTE_LIST,
+ ID_TYPE_COMPUTE_LIST = 4,
ID_TYPE_MAX,
ID_BASE_SHIFT = 58, // 5 bits for ID types.
ID_MASK = (ID_BASE_SHIFT - 1),
@@ -145,25 +148,7 @@ private:
void _add_dependency(RID p_id, RID p_depends_on);
void _free_dependencies(RID p_id);
- /*****************/
- /**** BARRIER ****/
- /*****************/
-
-public:
- enum BarrierMask {
- BARRIER_MASK_VERTEX = 1,
- BARRIER_MASK_FRAGMENT = 8,
- BARRIER_MASK_COMPUTE = 2,
- BARRIER_MASK_TRANSFER = 4,
-
- BARRIER_MASK_RASTER = BARRIER_MASK_VERTEX | BARRIER_MASK_FRAGMENT, // 9,
- BARRIER_MASK_ALL_BARRIERS = 0x7FFF, // all flags set
- BARRIER_MASK_NO_BARRIER = 0x8000,
- };
-
private:
- void _full_barrier(bool p_sync_with_draw);
-
/***************************/
/**** BUFFER MANAGEMENT ****/
/***************************/
@@ -201,26 +186,34 @@ private:
uint64_t staging_buffer_max_size = 0;
bool staging_buffer_used = false;
- Error _staging_buffer_allocate(uint32_t p_amount, uint32_t p_required_align, uint32_t &r_alloc_offset, uint32_t &r_alloc_size, bool p_can_segment = true);
+ enum StagingRequiredAction {
+ STAGING_REQUIRED_ACTION_NONE,
+ STAGING_REQUIRED_ACTION_FLUSH_CURRENT,
+ STAGING_REQUIRED_ACTION_FLUSH_OLDER
+ };
+
+ Error _staging_buffer_allocate(uint32_t p_amount, uint32_t p_required_align, uint32_t &r_alloc_offset, uint32_t &r_alloc_size, StagingRequiredAction &r_required_action, bool p_can_segment = true);
+ void _staging_buffer_execute_required_action(StagingRequiredAction p_required_action);
Error _insert_staging_block();
struct Buffer {
RDD::BufferID driver_id;
uint32_t size = 0;
BitField<RDD::BufferUsageBits> usage;
+ RDG::ResourceTracker *draw_tracker = nullptr;
};
- Buffer *_get_buffer_from_owner(RID p_buffer, BitField<RDD::PipelineStageBits> &r_stages, BitField<RDD::BarrierAccessBits> &r_access, BitField<BarrierMask> p_post_barrier);
- Error _buffer_update(Buffer *p_buffer, size_t p_offset, const uint8_t *p_data, size_t p_data_size, bool p_use_draw_command_buffer = false, uint32_t p_required_align = 32);
+ Buffer *_get_buffer_from_owner(RID p_buffer);
+ Error _buffer_update(Buffer *p_buffer, RID p_buffer_id, size_t p_offset, const uint8_t *p_data, size_t p_data_size, bool p_use_draw_queue = false, uint32_t p_required_align = 32);
RID_Owner<Buffer> uniform_buffer_owner;
RID_Owner<Buffer> storage_buffer_owner;
RID_Owner<Buffer> texture_buffer_owner;
public:
- Error buffer_copy(RID p_src_buffer, RID p_dst_buffer, uint32_t p_src_offset, uint32_t p_dst_offset, uint32_t p_size, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS);
- Error buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS);
- Error buffer_clear(RID p_buffer, uint32_t p_offset, uint32_t p_size, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS);
+ Error buffer_copy(RID p_src_buffer, RID p_dst_buffer, uint32_t p_src_offset, uint32_t p_dst_offset, uint32_t p_size);
+ Error buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data);
+ Error buffer_clear(RID p_buffer, uint32_t p_offset, uint32_t p_size);
Vector<uint8_t> buffer_get_data(RID p_buffer, uint32_t p_offset = 0, uint32_t p_size = 0); // This causes stall, only use to retrieve large buffers for saving.
/*****************/
@@ -245,6 +238,8 @@ public:
TextureType type = TEXTURE_TYPE_MAX;
DataFormat format = DATA_FORMAT_MAX;
TextureSamples samples = TEXTURE_SAMPLES_MAX;
+ TextureSliceType slice_type = TEXTURE_SLICE_MAX;
+ Rect2i slice_rect;
uint32_t width = 0;
uint32_t height = 0;
uint32_t depth = 0;
@@ -256,26 +251,33 @@ public:
Vector<DataFormat> allowed_shared_formats;
- RDD::TextureLayout layout = RDD::TEXTURE_LAYOUT_UNDEFINED;
-
- uint64_t used_in_frame = 0;
- bool used_in_transfer = false;
- bool used_in_raster = false;
- bool used_in_compute = false;
-
bool is_resolve_buffer = false;
+ bool has_initial_data = false;
BitField<RDD::TextureAspectBits> read_aspect_flags;
BitField<RDD::TextureAspectBits> barrier_aspect_flags;
- bool bound = false; // Bound to framebffer.
+ bool bound = false; // Bound to framebuffer.
RID owner;
+
+ RDG::ResourceTracker *draw_tracker = nullptr;
+ HashMap<Rect2i, RDG::ResourceTracker *> slice_trackers;
+
+ RDD::TextureSubresourceRange barrier_range() const {
+ RDD::TextureSubresourceRange r;
+ r.aspect = barrier_aspect_flags;
+ r.base_mipmap = base_mipmap;
+ r.mipmap_count = mipmaps;
+ r.base_layer = base_layer;
+ r.layer_count = layers;
+ return r;
+ }
};
RID_Owner<Texture> texture_owner;
uint32_t texture_upload_region_size_px = 0;
Vector<uint8_t> _texture_get_data(Texture *tex, uint32_t p_layer, bool p_2d = false);
- Error _texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, BitField<BarrierMask> p_post_barrier, bool p_use_setup_queue);
+ Error _texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, bool p_use_setup_queue, bool p_validate_can_update);
public:
struct TextureView {
@@ -306,7 +308,7 @@ public:
RID texture_create_shared(const TextureView &p_view, RID p_with_texture);
RID texture_create_from_extension(TextureType p_type, DataFormat p_format, TextureSamples p_samples, BitField<RenderingDevice::TextureUsageBits> p_usage, uint64_t p_image, uint64_t p_width, uint64_t p_height, uint64_t p_depth, uint64_t p_layers);
RID texture_create_shared_from_slice(const TextureView &p_view, RID p_with_texture, uint32_t p_layer, uint32_t p_mipmap, uint32_t p_mipmaps = 1, TextureSliceType p_slice_type = TEXTURE_SLICE_2D, uint32_t p_layers = 0);
- Error texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS);
+ Error texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data);
Vector<uint8_t> texture_get_data(RID p_texture, uint32_t p_layer); // CPU textures will return immediately, while GPU textures will most likely force a flush
bool texture_is_format_supported_for_usage(DataFormat p_format, BitField<TextureUsageBits> p_usage) const;
@@ -318,29 +320,36 @@ public:
uint64_t texture_get_native_handle(RID p_texture);
#endif
- Error texture_copy(RID p_from_texture, RID p_to_texture, const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_size, uint32_t p_src_mipmap, uint32_t p_dst_mipmap, uint32_t p_src_layer, uint32_t p_dst_layer, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS);
- Error texture_clear(RID p_texture, const Color &p_color, uint32_t p_base_mipmap, uint32_t p_mipmaps, uint32_t p_base_layer, uint32_t p_layers, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS);
- Error texture_resolve_multisample(RID p_from_texture, RID p_to_texture, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS);
+ Error texture_copy(RID p_from_texture, RID p_to_texture, const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_size, uint32_t p_src_mipmap, uint32_t p_dst_mipmap, uint32_t p_src_layer, uint32_t p_dst_layer);
+ Error texture_clear(RID p_texture, const Color &p_color, uint32_t p_base_mipmap, uint32_t p_mipmaps, uint32_t p_base_layer, uint32_t p_layers);
+ Error texture_resolve_multisample(RID p_from_texture, RID p_to_texture);
/************************/
/**** DRAW LISTS (I) ****/
/************************/
enum InitialAction {
- INITIAL_ACTION_CLEAR, // Start rendering and clear the whole framebuffer.
- INITIAL_ACTION_CLEAR_REGION, // Start rendering and clear the framebuffer in the specified region.
- INITIAL_ACTION_CLEAR_REGION_CONTINUE, // Continue rendering and clear the framebuffer in the specified region. Framebuffer must have been left in `FINAL_ACTION_CONTINUE` state as the final action previously.
- INITIAL_ACTION_KEEP, // Start rendering, but keep attached color texture contents. If the framebuffer was previously used to read in a shader, this will automatically insert a layout transition.
- INITIAL_ACTION_DROP, // Start rendering, ignore what is there; write above it. In general, this is the fastest option when you will be writing every single pixel and you don't need a clear color.
- INITIAL_ACTION_CONTINUE, // Continue rendering. Framebuffer must have been left in `FINAL_ACTION_CONTINUE` state as the final action previously.
- INITIAL_ACTION_MAX
+ INITIAL_ACTION_LOAD,
+ INITIAL_ACTION_CLEAR,
+ INITIAL_ACTION_DISCARD,
+ INITIAL_ACTION_MAX,
+#ifndef DISABLE_DEPRECATED
+ INITIAL_ACTION_CLEAR_REGION = INITIAL_ACTION_CLEAR,
+ INITIAL_ACTION_CLEAR_REGION_CONTINUE = INITIAL_ACTION_CLEAR,
+ INITIAL_ACTION_KEEP = INITIAL_ACTION_LOAD,
+ INITIAL_ACTION_DROP = INITIAL_ACTION_DISCARD,
+ INITIAL_ACTION_CONTINUE = INITIAL_ACTION_LOAD,
+#endif
};
enum FinalAction {
- FINAL_ACTION_READ, // Store the texture for reading and make it read-only if it has the `TEXTURE_USAGE_SAMPLING_BIT` bit (only applies to color, depth and stencil attachments).
- FINAL_ACTION_DISCARD, // Discard the texture data and make it read-only if it has the `TEXTURE_USAGE_SAMPLING_BIT` bit (only applies to color, depth and stencil attachments).
- FINAL_ACTION_CONTINUE, // Store the texture and continue for further processing. Similar to `FINAL_ACTION_READ`, but does not make the texture read-only if it has the `TEXTURE_USAGE_SAMPLING_BIT` bit.
- FINAL_ACTION_MAX
+ FINAL_ACTION_STORE,
+ FINAL_ACTION_DISCARD,
+ FINAL_ACTION_MAX,
+#ifndef DISABLE_DEPRECATED
+ FINAL_ACTION_READ = FINAL_ACTION_STORE,
+ FINAL_ACTION_CONTINUE = FINAL_ACTION_STORE,
+#endif
};
/*********************/
@@ -668,7 +677,9 @@ private:
uint32_t max_instances_allowed = 0;
Vector<RDD::BufferID> buffers; // Not owned, just referenced.
+ Vector<RDG::ResourceTracker *> draw_trackers; // Not owned, just referenced.
Vector<uint64_t> offsets;
+ HashSet<RID> untracked_buffers;
};
RID_Owner<VertexArray> vertex_array_owner;
@@ -685,6 +696,7 @@ private:
struct IndexArray {
uint32_t max_index = 0; // Remember the maximum index here too, for validation.
RDD::BufferID driver_id; // Not owned, inherited from index buffer.
+ RDG::ResourceTracker *draw_tracker = nullptr; // Not owned, inherited from index buffer.
uint32_t offset = 0;
uint32_t indices = 0;
IndexBufferFormat format = INDEX_BUFFER_FORMAT_UINT16;
@@ -762,6 +774,7 @@ private:
String name; // Used for debug.
RDD::ShaderID driver_id;
uint32_t layout_hash = 0;
+ BitField<RDD::PipelineStageBits> stage_bits;
Vector<uint32_t> set_formats;
};
@@ -770,10 +783,42 @@ private:
RID_Owner<Shader> shader_owner;
#ifndef DISABLE_DEPRECATED
- BitField<BarrierMask> _convert_barrier_mask_81356(BitField<BarrierMask> p_old_barrier);
+public:
+ enum BarrierMask{
+ BARRIER_MASK_VERTEX = 1,
+ BARRIER_MASK_FRAGMENT = 8,
+ BARRIER_MASK_COMPUTE = 2,
+ BARRIER_MASK_TRANSFER = 4,
+
+ BARRIER_MASK_RASTER = BARRIER_MASK_VERTEX | BARRIER_MASK_FRAGMENT, // 9,
+ BARRIER_MASK_ALL_BARRIERS = 0x7FFF, // all flags set
+ BARRIER_MASK_NO_BARRIER = 0x8000,
+ };
+
+ void barrier(BitField<BarrierMask> p_from = BARRIER_MASK_ALL_BARRIERS, BitField<BarrierMask> p_to = BARRIER_MASK_ALL_BARRIERS);
+ void full_barrier();
+ void draw_command_insert_label(String p_label_name, const Color &p_color = Color(1, 1, 1, 1));
+ Error draw_list_begin_split(RID p_framebuffer, uint32_t p_splits, DrawListID *r_split_ids, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2(), const Vector<RID> &p_storage_textures = Vector<RID>());
+ Error draw_list_switch_to_next_pass_split(uint32_t p_splits, DrawListID *r_split_ids);
+ Vector<int64_t> _draw_list_begin_split(RID p_framebuffer, uint32_t p_splits, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2(), const TypedArray<RID> &p_storage_textures = TypedArray<RID>());
+ Vector<int64_t> _draw_list_switch_to_next_pass_split(uint32_t p_splits);
+
+private:
void _draw_list_end_bind_compat_81356(BitField<BarrierMask> p_post_barrier);
void _compute_list_end_bind_compat_81356(BitField<BarrierMask> p_post_barrier);
void _barrier_bind_compat_81356(BitField<BarrierMask> p_from, BitField<BarrierMask> p_to);
+ void _draw_list_end_bind_compat_84976(BitField<BarrierMask> p_post_barrier);
+ void _compute_list_end_bind_compat_84976(BitField<BarrierMask> p_post_barrier);
+ InitialAction _convert_initial_action_84976(InitialAction p_old_initial_action);
+ FinalAction _convert_final_action_84976(FinalAction p_old_final_action);
+ DrawListID _draw_list_begin_bind_compat_84976(RID p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const TypedArray<RID> &p_storage_textures);
+ ComputeListID _compute_list_begin_bind_compat_84976(bool p_allow_draw_overlap);
+ Error _buffer_update_bind_compat_84976(RID p_buffer, uint32_t p_offset, uint32_t p_size, const Vector<uint8_t> &p_data, BitField<BarrierMask> p_post_barrier);
+ Error _buffer_clear_bind_compat_84976(RID p_buffer, uint32_t p_offset, uint32_t p_size, BitField<BarrierMask> p_post_barrier);
+ Error _texture_update_bind_compat_84976(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, BitField<BarrierMask> p_post_barrier);
+ Error _texture_copy_bind_compat_84976(RID p_from_texture, RID p_to_texture, const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_size, uint32_t p_src_mipmap, uint32_t p_dst_mipmap, uint32_t p_src_layer, uint32_t p_dst_layer, BitField<BarrierMask> p_post_barrier);
+ Error _texture_clear_bind_compat_84976(RID p_texture, const Color &p_color, uint32_t p_base_mipmap, uint32_t p_mipmaps, uint32_t p_base_layer, uint32_t p_layers, BitField<BarrierMask> p_post_barrier);
+ Error _texture_resolve_multisample_bind_compat_84976(RID p_from_texture, RID p_to_texture, BitField<BarrierMask> p_post_barrier);
#endif
public:
@@ -875,6 +920,9 @@ public:
};
private:
+ static const uint32_t MAX_UNIFORM_SETS = 16;
+ static const uint32_t MAX_PUSH_CONSTANT_SIZE = 128;
+
// This structure contains the descriptor set. They _need_ to be allocated
// for a shader (and will be erased when this shader is erased), but should
// work for other shaders as long as the hash matches. This covers using
@@ -894,8 +942,9 @@ private:
};
LocalVector<AttachableTexture> attachable_textures; // Used for validation.
- Vector<Texture *> mutable_sampled_textures; // Used for layout change.
- Vector<Texture *> mutable_storage_textures; // Used for layout change.
+ Vector<RDG::ResourceTracker *> draw_trackers;
+ Vector<RDG::ResourceUsage> draw_trackers_usage;
+ HashMap<RID, RDG::ResourceUsage> untracked_usage;
InvalidationCallback invalidated_callback = nullptr;
void *invalidated_callback_userdata = nullptr;
};
@@ -941,6 +990,7 @@ private:
uint32_t shader_layout_hash = 0;
Vector<uint32_t> set_formats;
RDD::PipelineID driver_id;
+ BitField<RDD::PipelineStageBits> stage_bits;
uint32_t push_constant_size = 0;
};
@@ -986,8 +1036,6 @@ public:
/**** DRAW LISTS (II) ****/
/*************************/
- typedef int64_t DrawListID;
-
private:
// Draw list contains both the command buffer
// used for drawing as well as a LOT of
@@ -995,20 +1043,7 @@ private:
// validation is cheap so most of it can
// also run in release builds.
- // When using split command lists, this is
- // implemented internally using secondary command
- // buffers. As they can be created in threads,
- // each needs its own command pool.
-
- struct SplitDrawListAllocator {
- RDD::CommandPoolID command_pool;
- Vector<RDD::CommandBufferID> command_buffers; // One for each frame.
- };
-
- Vector<SplitDrawListAllocator> split_draw_list_allocators;
-
struct DrawList {
- RDD::CommandBufferID command_buffer; // If persistent, this is owned, otherwise it's shared with the ringbuffer.
Rect2i viewport;
bool viewport_set = false;
@@ -1040,9 +1075,8 @@ private:
uint32_t vertex_array_size = 0;
uint32_t vertex_max_instances_allowed = 0xFFFFFFFF;
bool index_buffer_uses_restart_indices = false;
- uint32_t index_array_size = 0;
+ uint32_t index_array_count = 0;
uint32_t index_array_max_index = 0;
- uint32_t index_array_offset = 0;
Vector<uint32_t> set_formats;
Vector<bool> set_bound;
Vector<RID> set_rids;
@@ -1060,13 +1094,12 @@ private:
#else
struct Validation {
uint32_t vertex_array_size = 0;
- uint32_t index_array_size = 0;
- uint32_t index_array_offset;
+ uint32_t index_array_count = 0;
} validation;
#endif
};
- DrawList *draw_list = nullptr; // One for regular draw lists, multiple for split.
+ DrawList *draw_list = nullptr;
uint32_t draw_list_subpass_count = 0;
uint32_t draw_list_count = 0;
RDD::RenderPassID draw_list_render_pass;
@@ -1076,23 +1109,20 @@ private:
#endif
uint32_t draw_list_current_subpass = 0;
- bool draw_list_split = false;
Vector<RID> draw_list_bound_textures;
- Vector<RID> draw_list_storage_textures;
- bool draw_list_unbind_color_textures = false;
- bool draw_list_unbind_depth_textures = false;
void _draw_list_insert_clear_region(DrawList *p_draw_list, Framebuffer *p_framebuffer, Point2i p_viewport_offset, Point2i p_viewport_size, bool p_clear_color, const Vector<Color> &p_clear_colors, bool p_clear_depth, float p_depth, uint32_t p_stencil);
Error _draw_list_setup_framebuffer(Framebuffer *p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, RDD::FramebufferID *r_framebuffer, RDD::RenderPassID *r_render_pass, uint32_t *r_subpass_count);
- Error _draw_list_render_pass_begin(Framebuffer *p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_colors, float p_clear_depth, uint32_t p_clear_stencil, Point2i p_viewport_offset, Point2i p_viewport_size, RDD::FramebufferID p_framebuffer_driver_id, RDD::RenderPassID p_render_pass, RDD::CommandBufferID p_command_buffer, RDD::CommandBufferType p_cmd_buffer_mode, const Vector<RID> &p_storage_textures, bool p_constrained_to_region);
+ Error _draw_list_render_pass_begin(Framebuffer *p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_colors, float p_clear_depth, uint32_t p_clear_stencil, Point2i p_viewport_offset, Point2i p_viewport_size, RDD::FramebufferID p_framebuffer_driver_id, RDD::RenderPassID p_render_pass);
+ void _draw_list_set_viewport(Rect2i p_rect);
+ void _draw_list_set_scissor(Rect2i p_rect);
_FORCE_INLINE_ DrawList *_get_draw_list_ptr(DrawListID p_id);
- Error _draw_list_allocate(const Rect2i &p_viewport, uint32_t p_splits, uint32_t p_subpass);
+ Error _draw_list_allocate(const Rect2i &p_viewport, uint32_t p_subpass);
void _draw_list_free(Rect2i *r_last_viewport = nullptr);
public:
DrawListID draw_list_begin_for_screen(DisplayServer::WindowID p_screen = 0, const Color &p_clear_color = Color());
- DrawListID draw_list_begin(RID p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2(), const Vector<RID> &p_storage_textures = Vector<RID>());
- Error draw_list_begin_split(RID p_framebuffer, uint32_t p_splits, DrawListID *r_split_ids, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2(), const Vector<RID> &p_storage_textures = Vector<RID>());
+ DrawListID draw_list_begin(RID p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2());
void draw_list_set_blend_constants(DrawListID p_list, const Color &p_color);
void draw_list_bind_render_pipeline(DrawListID p_list, RID p_render_pipeline);
@@ -1109,20 +1139,15 @@ public:
uint32_t draw_list_get_current_pass();
DrawListID draw_list_switch_to_next_pass();
- Error draw_list_switch_to_next_pass_split(uint32_t p_splits, DrawListID *r_split_ids);
- void draw_list_end(BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS);
+ void draw_list_end();
+private:
/***********************/
/**** COMPUTE LISTS ****/
/***********************/
- typedef int64_t ComputeListID;
-
-private:
struct ComputeList {
- RDD::CommandBufferID command_buffer; // If persistent, this is owned, otherwise it's shared with the ringbuffer.
-
struct SetState {
uint32_t pipeline_expected_format = 0;
uint32_t uniform_set_format = 0;
@@ -1132,7 +1157,6 @@ private:
};
struct State {
- HashSet<Texture *> textures_to_sampled_layout;
SetState sets[MAX_UNIFORM_SETS];
uint32_t set_count = 0;
RID pipeline;
@@ -1140,7 +1164,8 @@ private:
RDD::ShaderID pipeline_shader_driver_id;
uint32_t pipeline_shader_layout_hash = 0;
uint32_t local_group_size[3] = { 0, 0, 0 };
- bool allow_draw_overlap;
+ uint8_t push_constant_data[MAX_PUSH_CONSTANT_SIZE] = {};
+ uint32_t push_constant_size = 0;
} state;
#ifdef DEBUG_ENABLED
@@ -1160,11 +1185,10 @@ private:
};
ComputeList *compute_list = nullptr;
-
- void _compute_list_add_barrier(BitField<BarrierMask> p_post_barrier, BitField<RDD::PipelineStageBits> p_stages, BitField<RDD::BarrierAccessBits> p_access);
+ ComputeList::State compute_list_barrier_state;
public:
- ComputeListID compute_list_begin(bool p_allow_draw_overlap = false);
+ ComputeListID compute_list_begin();
void compute_list_bind_compute_pipeline(ComputeListID p_list, RID p_compute_pipeline);
void compute_list_bind_uniform_set(ComputeListID p_list, RID p_uniform_set, uint32_t p_index);
void compute_list_set_push_constant(ComputeListID p_list, const void *p_data, uint32_t p_data_size);
@@ -1173,10 +1197,22 @@ public:
void compute_list_dispatch_indirect(ComputeListID p_list, RID p_buffer, uint32_t p_offset);
void compute_list_add_barrier(ComputeListID p_list);
- void compute_list_end(BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS);
+ void compute_list_end();
- void barrier(BitField<BarrierMask> p_from = BARRIER_MASK_ALL_BARRIERS, BitField<BarrierMask> p_to = BARRIER_MASK_ALL_BARRIERS);
- void full_barrier();
+private:
+ /***********************/
+ /**** COMMAND GRAPH ****/
+ /***********************/
+
+ bool _texture_make_mutable(Texture *p_texture, RID p_texture_id);
+ bool _buffer_make_mutable(Buffer *p_buffer, RID p_buffer_id);
+ bool _vertex_array_make_mutable(VertexArray *p_vertex_array, RID p_resource_id, RDG::ResourceTracker *p_resource_tracker);
+ bool _index_array_make_mutable(IndexArray *p_index_array, RDG::ResourceTracker *p_resource_tracker);
+ bool _uniform_set_make_mutable(UniformSet *p_uniform_set, RID p_resource_id, RDG::ResourceTracker *p_resource_tracker);
+ bool _dependency_make_mutable(RID p_id, RID p_resource_id, RDG::ResourceTracker *p_resource_tracker);
+ bool _dependencies_make_mutable(RID p_id, RDG::ResourceTracker *p_resource_tracker);
+
+ RenderingDeviceGraph draw_graph;
/**************************/
/**** FRAME MANAGEMENT ****/
@@ -1258,7 +1294,7 @@ private:
template <class T>
void _free_rids(T &p_owner, const char *p_type);
- void _finalize_command_bufers();
+ void _finalize_command_buffers(bool p_postpare);
void _begin_frame();
#ifdef DEV_ENABLED
@@ -1311,7 +1347,6 @@ public:
void set_resource_name(RID p_id, const String &p_name);
void draw_command_begin_label(String p_label_name, const Color &p_color = Color(1, 1, 1, 1));
- void draw_command_insert_label(String p_label_name, const Color &p_color = Color(1, 1, 1, 1));
void draw_command_end_label();
String get_device_vendor_name() const;
@@ -1353,16 +1388,13 @@ private:
RID _uniform_set_create(const TypedArray<RDUniform> &p_uniforms, RID p_shader, uint32_t p_shader_set);
- Error _buffer_update_bind(RID p_buffer, uint32_t p_offset, uint32_t p_size, const Vector<uint8_t> &p_data, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS);
+ Error _buffer_update_bind(RID p_buffer, uint32_t p_offset, uint32_t p_size, const Vector<uint8_t> &p_data);
RID _render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const Ref<RDPipelineRasterizationState> &p_rasterization_state, const Ref<RDPipelineMultisampleState> &p_multisample_state, const Ref<RDPipelineDepthStencilState> &p_depth_stencil_state, const Ref<RDPipelineColorBlendState> &p_blend_state, BitField<PipelineDynamicStateFlags> p_dynamic_state_flags, uint32_t p_for_render_pass, const TypedArray<RDPipelineSpecializationConstant> &p_specialization_constants);
RID _compute_pipeline_create(RID p_shader, const TypedArray<RDPipelineSpecializationConstant> &p_specialization_constants);
- DrawListID _draw_list_begin(RID p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2(), const TypedArray<RID> &p_storage_textures = TypedArray<RID>());
- Vector<int64_t> _draw_list_begin_split(RID p_framebuffer, uint32_t p_splits, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2(), const TypedArray<RID> &p_storage_textures = TypedArray<RID>());
void _draw_list_set_push_constant(DrawListID p_list, const Vector<uint8_t> &p_data, uint32_t p_data_size);
void _compute_list_set_push_constant(ComputeListID p_list, const Vector<uint8_t> &p_data, uint32_t p_data_size);
- Vector<int64_t> _draw_list_switch_to_next_pass_split(uint32_t p_splits);
};
VARIANT_ENUM_CAST(RenderingDevice::DeviceType)
@@ -1371,7 +1403,6 @@ VARIANT_ENUM_CAST(RenderingDevice::ShaderStage)
VARIANT_ENUM_CAST(RenderingDevice::ShaderLanguage)
VARIANT_ENUM_CAST(RenderingDevice::CompareOperator)
VARIANT_ENUM_CAST(RenderingDevice::DataFormat)
-VARIANT_BITFIELD_CAST(RenderingDevice::BarrierMask);
VARIANT_ENUM_CAST(RenderingDevice::TextureType)
VARIANT_ENUM_CAST(RenderingDevice::TextureSamples)
VARIANT_BITFIELD_CAST(RenderingDevice::TextureUsageBits)
@@ -1399,6 +1430,10 @@ VARIANT_ENUM_CAST(RenderingDevice::Limit)
VARIANT_ENUM_CAST(RenderingDevice::MemoryType)
VARIANT_ENUM_CAST(RenderingDevice::Features)
+#ifndef DISABLE_DEPRECATED
+VARIANT_BITFIELD_CAST(RenderingDevice::BarrierMask);
+#endif
+
typedef RenderingDevice RD;
#endif // RENDERING_DEVICE_H
diff --git a/servers/rendering/rendering_device_commons.h b/servers/rendering/rendering_device_commons.h
index dabd0c0867..a8936f8cca 100644
--- a/servers/rendering/rendering_device_commons.h
+++ b/servers/rendering/rendering_device_commons.h
@@ -379,6 +379,7 @@ public:
TEXTURE_SLICE_CUBEMAP,
TEXTURE_SLICE_3D,
TEXTURE_SLICE_2D_ARRAY,
+ TEXTURE_SLICE_MAX
};
/*****************/
@@ -910,6 +911,7 @@ protected:
Vector<Vector<ShaderUniform>> uniform_sets;
Vector<ShaderSpecializationConstant> specialization_constants;
+ Vector<ShaderStage> stages;
};
struct ShaderReflection : public ShaderDescription {
diff --git a/servers/rendering/rendering_device_driver.h b/servers/rendering/rendering_device_driver.h
index bb71a29bbc..663222e69d 100644
--- a/servers/rendering/rendering_device_driver.h
+++ b/servers/rendering/rendering_device_driver.h
@@ -181,6 +181,10 @@ public:
BUFFER_USAGE_INDIRECT_BIT = (1 << 8),
};
+ enum {
+ BUFFER_WHOLE_SIZE = ~0ULL
+ };
+
virtual BufferID buffer_create(uint64_t p_size, BitField<BufferUsageBits> p_usage, MemoryAllocationType p_allocation_type) = 0;
// Only for a buffer with BUFFER_USAGE_TEXEL_BIT.
virtual bool buffer_set_texel_format(BufferID p_buffer, DataFormat p_format) = 0;
@@ -535,6 +539,8 @@ public:
float depth;
uint32_t stencil;
};
+
+ RenderPassClearValue() {}
};
struct AttachmentClear {
@@ -621,6 +627,13 @@ public:
virtual void command_timestamp_write(CommandBufferID p_cmd_buffer, QueryPoolID p_pool_id, uint32_t p_index) = 0;
/****************/
+ /**** LABELS ****/
+ /****************/
+
+ virtual void command_begin_label(CommandBufferID p_cmd_buffer, const char *p_label_name, const Color &p_color) = 0;
+ virtual void command_end_label(CommandBufferID p_cmd_buffer) = 0;
+
+ /****************/
/**** SCREEN ****/
/****************/
diff --git a/servers/rendering/rendering_device_graph.cpp b/servers/rendering/rendering_device_graph.cpp
new file mode 100644
index 0000000000..bfacd38065
--- /dev/null
+++ b/servers/rendering/rendering_device_graph.cpp
@@ -0,0 +1,1930 @@
+/**************************************************************************/
+/* rendering_device_graph.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#include "rendering_device_graph.h"
+
+#define PRINT_RENDER_GRAPH 0
+#define FORCE_FULL_ACCESS_BITS 0
+#define PRINT_RESOURCE_TRACKER_TOTAL 0
+
+RenderingDeviceGraph::RenderingDeviceGraph() {
+ // Default initialization.
+}
+
+RenderingDeviceGraph::~RenderingDeviceGraph() {
+ _wait_for_secondary_command_buffer_tasks();
+
+ for (Frame &f : frames) {
+ for (SecondaryCommandBuffer &secondary : f.secondary_command_buffers) {
+ if (secondary.command_pool.id != 0) {
+ driver->command_pool_free(secondary.command_pool);
+ }
+ }
+ }
+}
+
+bool RenderingDeviceGraph::_is_write_usage(ResourceUsage p_usage) {
+ switch (p_usage) {
+ case RESOURCE_USAGE_TRANSFER_FROM:
+ case RESOURCE_USAGE_UNIFORM_BUFFER_READ:
+ case RESOURCE_USAGE_INDIRECT_BUFFER_READ:
+ case RESOURCE_USAGE_TEXTURE_BUFFER_READ:
+ case RESOURCE_USAGE_STORAGE_BUFFER_READ:
+ case RESOURCE_USAGE_VERTEX_BUFFER_READ:
+ case RESOURCE_USAGE_INDEX_BUFFER_READ:
+ case RESOURCE_USAGE_TEXTURE_SAMPLE:
+ case RESOURCE_USAGE_STORAGE_IMAGE_READ:
+ case RESOURCE_USAGE_ATTACHMENT_COLOR_READ:
+ case RESOURCE_USAGE_ATTACHMENT_DEPTH_STENCIL_READ:
+ return false;
+ case RESOURCE_USAGE_TRANSFER_TO:
+ case RESOURCE_USAGE_TEXTURE_BUFFER_READ_WRITE:
+ case RESOURCE_USAGE_STORAGE_BUFFER_READ_WRITE:
+ case RESOURCE_USAGE_STORAGE_IMAGE_READ_WRITE:
+ case RESOURCE_USAGE_ATTACHMENT_COLOR_READ_WRITE:
+ case RESOURCE_USAGE_ATTACHMENT_DEPTH_STENCIL_READ_WRITE:
+ return true;
+ default:
+ DEV_ASSERT(false && "Invalid resource tracker usage.");
+ return false;
+ }
+}
+
+RDD::TextureLayout RenderingDeviceGraph::_usage_to_image_layout(ResourceUsage p_usage) {
+ switch (p_usage) {
+ case RESOURCE_USAGE_TRANSFER_FROM:
+ return RDD::TEXTURE_LAYOUT_TRANSFER_SRC_OPTIMAL;
+ case RESOURCE_USAGE_TRANSFER_TO:
+ return RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL;
+ case RESOURCE_USAGE_TEXTURE_SAMPLE:
+ return RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+ case RESOURCE_USAGE_STORAGE_IMAGE_READ:
+ case RESOURCE_USAGE_STORAGE_IMAGE_READ_WRITE:
+ return RDD::TEXTURE_LAYOUT_GENERAL;
+ case RESOURCE_USAGE_ATTACHMENT_COLOR_READ:
+ case RESOURCE_USAGE_ATTACHMENT_COLOR_READ_WRITE:
+ return RDD::TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+ case RESOURCE_USAGE_ATTACHMENT_DEPTH_STENCIL_READ:
+ return RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
+ case RESOURCE_USAGE_ATTACHMENT_DEPTH_STENCIL_READ_WRITE:
+ return RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
+ case RESOURCE_USAGE_NONE:
+ return RDD::TEXTURE_LAYOUT_UNDEFINED;
+ default:
+ DEV_ASSERT(false && "Invalid resource tracker usage or not an image usage.");
+ return RDD::TEXTURE_LAYOUT_UNDEFINED;
+ }
+}
+
+RDD::BarrierAccessBits RenderingDeviceGraph::_usage_to_access_bits(ResourceUsage p_usage) {
+#if FORCE_FULL_ACCESS_BITS
+ return RDD::BarrierAccessBits(RDD::BARRIER_ACCESS_MEMORY_READ_BIT | RDD::BARRIER_ACCESS_MEMORY_WRITE_BIT);
+#else
+ switch (p_usage) {
+ case RESOURCE_USAGE_NONE:
+ return RDD::BarrierAccessBits(0);
+ case RESOURCE_USAGE_TRANSFER_FROM:
+ return RDD::BARRIER_ACCESS_TRANSFER_READ_BIT;
+ case RESOURCE_USAGE_TRANSFER_TO:
+ return RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT;
+ case RESOURCE_USAGE_UNIFORM_BUFFER_READ:
+ return RDD::BARRIER_ACCESS_UNIFORM_READ_BIT;
+ case RESOURCE_USAGE_INDIRECT_BUFFER_READ:
+ return RDD::BARRIER_ACCESS_INDIRECT_COMMAND_READ_BIT;
+ case RESOURCE_USAGE_STORAGE_BUFFER_READ:
+ case RESOURCE_USAGE_STORAGE_IMAGE_READ:
+ case RESOURCE_USAGE_TEXTURE_BUFFER_READ:
+ case RESOURCE_USAGE_TEXTURE_SAMPLE:
+ return RDD::BARRIER_ACCESS_SHADER_READ_BIT;
+ case RESOURCE_USAGE_TEXTURE_BUFFER_READ_WRITE:
+ case RESOURCE_USAGE_STORAGE_BUFFER_READ_WRITE:
+ case RESOURCE_USAGE_STORAGE_IMAGE_READ_WRITE:
+ return RDD::BarrierAccessBits(RDD::BARRIER_ACCESS_SHADER_READ_BIT | RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
+ case RESOURCE_USAGE_VERTEX_BUFFER_READ:
+ return RDD::BARRIER_ACCESS_VERTEX_ATTRIBUTE_READ_BIT;
+ case RESOURCE_USAGE_INDEX_BUFFER_READ:
+ return RDD::BARRIER_ACCESS_INDEX_READ_BIT;
+ case RESOURCE_USAGE_ATTACHMENT_COLOR_READ:
+ return RDD::BARRIER_ACCESS_COLOR_ATTACHMENT_READ_BIT;
+ case RESOURCE_USAGE_ATTACHMENT_COLOR_READ_WRITE:
+ return RDD::BarrierAccessBits(RDD::BARRIER_ACCESS_COLOR_ATTACHMENT_READ_BIT | RDD::BARRIER_ACCESS_COLOR_ATTACHMENT_WRITE_BIT);
+ case RESOURCE_USAGE_ATTACHMENT_DEPTH_STENCIL_READ:
+ return RDD::BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
+ case RESOURCE_USAGE_ATTACHMENT_DEPTH_STENCIL_READ_WRITE:
+ return RDD::BarrierAccessBits(RDD::BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | RDD::BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT);
+ default:
+ DEV_ASSERT(false && "Invalid usage.");
+ return RDD::BarrierAccessBits(0);
+ }
+#endif
+}
+
+int32_t RenderingDeviceGraph::_add_to_command_list(int32_t p_command_index, int32_t p_list_index) {
+ DEV_ASSERT(p_command_index < int32_t(command_count));
+ DEV_ASSERT(p_list_index < int32_t(command_list_nodes.size()));
+
+ int32_t next_index = int32_t(command_list_nodes.size());
+ command_list_nodes.resize(next_index + 1);
+
+ RecordedCommandListNode &new_node = command_list_nodes[next_index];
+ new_node.command_index = p_command_index;
+ new_node.next_list_index = p_list_index;
+ return next_index;
+}
+
+void RenderingDeviceGraph::_add_adjacent_command(int32_t p_previous_command_index, int32_t p_command_index, RecordedCommand *r_command) {
+ const uint32_t previous_command_data_offset = command_data_offsets[p_previous_command_index];
+ RecordedCommand &previous_command = *reinterpret_cast<RecordedCommand *>(&command_data[previous_command_data_offset]);
+ previous_command.adjacent_command_list_index = _add_to_command_list(p_command_index, previous_command.adjacent_command_list_index);
+ r_command->src_stages = r_command->src_stages | previous_command.dst_stages;
+}
+
+int32_t RenderingDeviceGraph::_add_to_write_list(int32_t p_command_index, Rect2i suberesources, int32_t p_list_index) {
+ DEV_ASSERT(p_command_index < int32_t(command_count));
+ DEV_ASSERT(p_list_index < int32_t(write_list_nodes.size()));
+
+ int32_t next_index = int32_t(write_list_nodes.size());
+ write_list_nodes.resize(next_index + 1);
+
+ RecordedWriteListNode &new_node = write_list_nodes[next_index];
+ new_node.command_index = p_command_index;
+ new_node.next_list_index = p_list_index;
+ new_node.subresources = suberesources;
+ return next_index;
+}
+
+RenderingDeviceGraph::RecordedCommand *RenderingDeviceGraph::_allocate_command(uint32_t p_command_size, int32_t &r_command_index) {
+ uint32_t command_data_offset = command_data.size();
+ command_data_offsets.push_back(command_data_offset);
+ command_data.resize(command_data_offset + p_command_size);
+ r_command_index = command_count++;
+ RecordedCommand *new_command = reinterpret_cast<RecordedCommand *>(&command_data[command_data_offset]);
+ *new_command = RecordedCommand();
+ return new_command;
+}
+
+RenderingDeviceGraph::DrawListInstruction *RenderingDeviceGraph::_allocate_draw_list_instruction(uint32_t p_instruction_size) {
+ uint32_t draw_list_data_offset = draw_instruction_list.data.size();
+ draw_instruction_list.data.resize(draw_list_data_offset + p_instruction_size);
+ return reinterpret_cast<DrawListInstruction *>(&draw_instruction_list.data[draw_list_data_offset]);
+}
+
+RenderingDeviceGraph::ComputeListInstruction *RenderingDeviceGraph::_allocate_compute_list_instruction(uint32_t p_instruction_size) {
+ uint32_t compute_list_data_offset = compute_instruction_list.data.size();
+ compute_instruction_list.data.resize(compute_list_data_offset + p_instruction_size);
+ return reinterpret_cast<ComputeListInstruction *>(&compute_instruction_list.data[compute_list_data_offset]);
+}
+
+void RenderingDeviceGraph::_add_command_to_graph(ResourceTracker **p_resource_trackers, ResourceUsage *p_resource_usages, uint32_t p_resource_count, int32_t p_command_index, RecordedCommand *r_command) {
+ if (command_label_index >= 0) {
+ // If a label is active, tag the command with the label.
+ r_command->label_index = command_label_index;
+ }
+
+ if (r_command->type == RecordedCommand::TYPE_CAPTURE_TIMESTAMP) {
+ // All previous commands starting from the previous timestamp should be adjacent to this command.
+ int32_t start_command_index = uint32_t(MAX(command_timestamp_index, 0));
+ for (int32_t i = start_command_index; i < p_command_index; i++) {
+ _add_adjacent_command(i, p_command_index, r_command);
+ }
+
+ // Make this command the new active timestamp command.
+ command_timestamp_index = p_command_index;
+ } else if (command_timestamp_index >= 0) {
+ // Timestamp command should be adjacent to this command.
+ _add_adjacent_command(command_timestamp_index, p_command_index, r_command);
+ }
+
+ if (command_synchronization_pending) {
+ // All previous commands should be adjacent to this command.
+ int32_t start_command_index = uint32_t(MAX(command_synchronization_index, 0));
+ for (int32_t i = start_command_index; i < p_command_index; i++) {
+ _add_adjacent_command(i, p_command_index, r_command);
+ }
+
+ command_synchronization_index = p_command_index;
+ command_synchronization_pending = false;
+ } else if (command_synchronization_index >= 0) {
+ // Synchronization command should be adjacent to this command.
+ _add_adjacent_command(command_synchronization_index, p_command_index, r_command);
+ }
+
+ for (uint32_t i = 0; i < p_resource_count; i++) {
+ ResourceTracker *resource_tracker = p_resource_trackers[i];
+ DEV_ASSERT(resource_tracker != nullptr);
+
+ resource_tracker->reset_if_outdated(tracking_frame);
+
+ ResourceUsage new_resource_usage = p_resource_usages[i];
+ bool write_usage = _is_write_usage(new_resource_usage);
+ BitField<RDD::BarrierAccessBits> new_usage_access = _usage_to_access_bits(new_resource_usage);
+ bool is_resource_a_slice = resource_tracker->parent != nullptr;
+ if (is_resource_a_slice) {
+ // This resource depends on a parent resource.
+ resource_tracker->parent->reset_if_outdated(tracking_frame);
+
+ if (resource_tracker->texture_slice_command_index != p_command_index) {
+ // Indicate this slice has been used by this command.
+ resource_tracker->texture_slice_command_index = p_command_index;
+ }
+
+ if (resource_tracker->parent->usage == RESOURCE_USAGE_NONE) {
+ if (resource_tracker->parent->texture_driver_id != 0) {
+ // If the resource is a texture, we transition it entirely to the layout determined by the first slice that uses it.
+ _add_texture_barrier_to_command(resource_tracker->parent->texture_driver_id, RDD::BarrierAccessBits(0), new_usage_access, RDG::RESOURCE_USAGE_NONE, new_resource_usage, resource_tracker->parent->texture_subresources, command_normalization_barriers, r_command->normalization_barrier_index, r_command->normalization_barrier_count);
+ }
+
+ // If the parent hasn't been used yet, we assign the usage of the slice to the entire resource.
+ resource_tracker->parent->usage = new_resource_usage;
+
+ // Also assign the usage to the slice and consider it a write operation.
+ resource_tracker->usage = new_resource_usage;
+ write_usage = true;
+ } else if (resource_tracker->in_parent_dirty_list) {
+ if (resource_tracker->parent->usage == new_resource_usage) {
+ // The slice will be transitioned to the resource of the parent and can be deleted from the dirty list.
+ ResourceTracker *previous_tracker = nullptr;
+ ResourceTracker *current_tracker = resource_tracker->parent->dirty_shared_list;
+ bool initialized_dirty_rect = false;
+ while (current_tracker != nullptr) {
+ if (current_tracker == resource_tracker) {
+ current_tracker->in_parent_dirty_list = false;
+
+ if (previous_tracker != nullptr) {
+ previous_tracker->next_shared = current_tracker->next_shared;
+ } else {
+ resource_tracker->parent->dirty_shared_list = current_tracker->next_shared;
+ }
+
+ current_tracker = current_tracker->next_shared;
+ } else {
+ if (initialized_dirty_rect) {
+ resource_tracker->parent->texture_slice_or_dirty_rect = resource_tracker->parent->texture_slice_or_dirty_rect.merge(current_tracker->texture_slice_or_dirty_rect);
+ } else {
+ resource_tracker->parent->texture_slice_or_dirty_rect = current_tracker->texture_slice_or_dirty_rect;
+ initialized_dirty_rect = true;
+ }
+
+ previous_tracker = current_tracker;
+ current_tracker = current_tracker->next_shared;
+ }
+ }
+ }
+ } else {
+ if (resource_tracker->parent->dirty_shared_list != nullptr && resource_tracker->parent->texture_slice_or_dirty_rect.intersects(resource_tracker->texture_slice_or_dirty_rect)) {
+ // There's an intersection with the current dirty area of the parent and the slice. We must verify if the intersection is against a slice
+ // that was used in this command or not. Any slice we can find that wasn't used by this command must be reverted to the layout of the parent.
+ ResourceTracker *previous_tracker = nullptr;
+ ResourceTracker *current_tracker = resource_tracker->parent->dirty_shared_list;
+ bool initialized_dirty_rect = false;
+ while (current_tracker != nullptr) {
+ if (current_tracker->texture_slice_or_dirty_rect.intersects(resource_tracker->texture_slice_or_dirty_rect)) {
+ if (current_tracker->command_frame == tracking_frame && current_tracker->texture_slice_command_index == p_command_index) {
+ ERR_FAIL_MSG("Texture slices that overlap can't be used in the same command.");
+ } else {
+ // Delete the slice from the dirty list and revert it to the usage of the parent.
+ if (current_tracker->texture_driver_id != 0) {
+ _add_texture_barrier_to_command(current_tracker->texture_driver_id, current_tracker->usage_access, new_usage_access, current_tracker->usage, resource_tracker->parent->usage, current_tracker->texture_subresources, command_normalization_barriers, r_command->normalization_barrier_index, r_command->normalization_barrier_count);
+ }
+
+ current_tracker->in_parent_dirty_list = false;
+
+ if (previous_tracker != nullptr) {
+ previous_tracker->next_shared = current_tracker->next_shared;
+ } else {
+ resource_tracker->parent->dirty_shared_list = current_tracker->next_shared;
+ }
+
+ current_tracker = current_tracker->next_shared;
+ }
+ } else {
+ // Recalculate the dirty rect of the parent so the deleted slices are excluded.
+ if (initialized_dirty_rect) {
+ resource_tracker->parent->texture_slice_or_dirty_rect = resource_tracker->parent->texture_slice_or_dirty_rect.merge(current_tracker->texture_slice_or_dirty_rect);
+ } else {
+ resource_tracker->parent->texture_slice_or_dirty_rect = current_tracker->texture_slice_or_dirty_rect;
+ initialized_dirty_rect = true;
+ }
+
+ previous_tracker = current_tracker;
+ current_tracker = current_tracker->next_shared;
+ }
+ }
+ }
+
+ // If it wasn't in the list, assume the usage is the same as the parent.
+ resource_tracker->usage = resource_tracker->parent->usage;
+
+ if (resource_tracker->usage != new_resource_usage) {
+ // Insert to the dirty list if the requested usage is different.
+ resource_tracker->next_shared = resource_tracker->parent->dirty_shared_list;
+ resource_tracker->parent->dirty_shared_list = resource_tracker;
+ resource_tracker->in_parent_dirty_list = true;
+ if (resource_tracker->parent->dirty_shared_list != nullptr) {
+ resource_tracker->parent->texture_slice_or_dirty_rect = resource_tracker->parent->texture_slice_or_dirty_rect.merge(resource_tracker->texture_slice_or_dirty_rect);
+ } else {
+ resource_tracker->parent->texture_slice_or_dirty_rect = resource_tracker->texture_slice_or_dirty_rect;
+ }
+ }
+ }
+ } else {
+ if (resource_tracker->dirty_shared_list != nullptr) {
+ // Consider the usage as write if we must transition any of the slices.
+ write_usage = true;
+ }
+
+ while (resource_tracker->dirty_shared_list != nullptr) {
+ if (resource_tracker->dirty_shared_list->texture_driver_id != 0) {
+ // Transition all slices to the layout of the parent resource.
+ _add_texture_barrier_to_command(resource_tracker->dirty_shared_list->texture_driver_id, resource_tracker->dirty_shared_list->usage_access, new_usage_access, resource_tracker->dirty_shared_list->usage, resource_tracker->usage, resource_tracker->dirty_shared_list->texture_subresources, command_normalization_barriers, r_command->normalization_barrier_index, r_command->normalization_barrier_count);
+ }
+
+ resource_tracker->dirty_shared_list->in_parent_dirty_list = false;
+ resource_tracker->dirty_shared_list = resource_tracker->dirty_shared_list->next_shared;
+ }
+ }
+
+ // Use the resource's parent tracker directly for all search operations.
+ bool resource_has_parent = resource_tracker->parent != nullptr;
+ ResourceTracker *search_tracker = resource_has_parent ? resource_tracker->parent : resource_tracker;
+ const RDD::TextureSubresourceRange &subresources = resource_tracker->texture_subresources;
+ Rect2i resource_tracker_rect(subresources.base_mipmap, subresources.base_layer, subresources.mipmap_count, subresources.layer_count);
+ bool different_usage = resource_tracker->usage != new_resource_usage;
+ bool write_usage_after_write = (write_usage && search_tracker->write_command_or_list_index >= 0);
+ if (different_usage || write_usage_after_write) {
+ // A barrier must be pushed if the usage is different of it's a write usage and there was already a command that wrote to this resource previously.
+ if (resource_tracker->texture_driver_id.id != 0) {
+ if (resource_tracker->usage_access.is_empty()) {
+ // FIXME: If the tracker does not know the previous type of usage, assume the generic memory write one.
+ // Tracking access bits across texture slices can be tricky, so this failsafe can be removed once that's improved.
+ resource_tracker->usage_access = RDD::BARRIER_ACCESS_MEMORY_WRITE_BIT;
+ }
+
+ _add_texture_barrier_to_command(resource_tracker->texture_driver_id, resource_tracker->usage_access, new_usage_access, resource_tracker->usage, new_resource_usage, resource_tracker->texture_subresources, command_transition_barriers, r_command->transition_barrier_index, r_command->transition_barrier_count);
+ } else if (resource_tracker->buffer_driver_id.id != 0) {
+#if USE_BUFFER_BARRIERS
+ _add_buffer_barrier_to_command(resource_tracker->buffer_driver_id, resource_tracker->usage_access, new_usage_access, r_command->buffer_barrier_index, r_command->buffer_barrier_count);
+#endif
+ // FIXME: Memory barriers are currently pushed regardless of whether buffer barriers are being used or not. Refer to the comment on the
+ // definition of USE_BUFFER_BARRIERS for the reason behind this. This can be fixed to be one case or the other once it's been confirmed
+ // the buffer and memory barrier behavior discrepancy has been solved.
+ r_command->memory_barrier.src_access = resource_tracker->usage_access;
+ r_command->memory_barrier.dst_access = new_usage_access;
+ } else {
+ DEV_ASSERT(false && "Resource tracker does not contain a valid buffer or texture ID.");
+ }
+ }
+
+ // Always update the access of the tracker according to the latest usage.
+ resource_tracker->usage_access = new_usage_access;
+
+ if (different_usage) {
+ // Even if the usage of the resource isn't a write usage explicitly, a different usage implies a transition and it should therefore be considered a write.
+ write_usage = true;
+ resource_tracker->usage = new_resource_usage;
+ }
+
+ if (search_tracker->write_command_or_list_index >= 0) {
+ if (search_tracker->write_command_list_enabled) {
+ // Make this command adjacent to any commands that wrote to this resource and intersect with the slice if it applies.
+ // For buffers or textures that never use slices, this list will only be one element long at most.
+ int32_t previous_write_list_index = -1;
+ int32_t write_list_index = search_tracker->write_command_or_list_index;
+ while (write_list_index >= 0) {
+ const RecordedWriteListNode &write_list_node = write_list_nodes[write_list_index];
+ if (!resource_has_parent || resource_tracker_rect.intersects(write_list_node.subresources)) {
+ if (write_list_node.command_index == p_command_index) {
+ ERR_FAIL_COND_MSG(!resource_has_parent, "Command can't have itself as a dependency.");
+ } else {
+ // Command is dependent on this command. Add this command to the adjacency list of the write command.
+ _add_adjacent_command(write_list_node.command_index, p_command_index, r_command);
+
+ if (resource_has_parent && write_usage && resource_tracker_rect.encloses(write_list_node.subresources)) {
+ // Eliminate redundant writes from the list.
+ if (previous_write_list_index >= 0) {
+ RecordedWriteListNode &previous_list_node = write_list_nodes[previous_write_list_index];
+ previous_list_node.next_list_index = write_list_node.next_list_index;
+ } else {
+ search_tracker->write_command_or_list_index = write_list_node.next_list_index;
+ }
+
+ write_list_index = write_list_node.next_list_index;
+ continue;
+ }
+ }
+ }
+
+ previous_write_list_index = write_list_index;
+ write_list_index = write_list_node.next_list_index;
+ }
+ } else {
+ // The index is just the latest command index that wrote to the resource.
+ if (search_tracker->write_command_or_list_index == p_command_index) {
+ ERR_FAIL_MSG("Command can't have itself as a dependency.");
+ } else {
+ _add_adjacent_command(search_tracker->write_command_or_list_index, p_command_index, r_command);
+ }
+ }
+ }
+
+ if (write_usage) {
+ if (resource_has_parent) {
+ if (!search_tracker->write_command_list_enabled && search_tracker->write_command_or_list_index >= 0) {
+ // Write command list was not being used but there was a write command recorded. Add a new node with the entire parent resource's subresources and the recorded command index to the list.
+ const RDD::TextureSubresourceRange &tracker_subresources = search_tracker->texture_subresources;
+ Rect2i tracker_rect(tracker_subresources.base_mipmap, tracker_subresources.base_layer, tracker_subresources.mipmap_count, tracker_subresources.layer_count);
+ search_tracker->write_command_or_list_index = _add_to_write_list(search_tracker->write_command_or_list_index, tracker_rect, -1);
+ }
+
+ search_tracker->write_command_or_list_index = _add_to_write_list(p_command_index, resource_tracker_rect, search_tracker->write_command_or_list_index);
+ search_tracker->write_command_list_enabled = true;
+ } else {
+ search_tracker->write_command_or_list_index = p_command_index;
+ search_tracker->write_command_list_enabled = false;
+ }
+
+ // We add this command to the adjacency list of all commands that were reading from this resource. We clear the list in the process.
+ int32_t previous_command_list_index = -1;
+ int32_t read_command_list_index = search_tracker->read_command_list_index;
+ while (read_command_list_index >= 0) {
+ const RecordedCommandListNode &command_list_node = command_list_nodes[read_command_list_index];
+ if (command_list_node.command_index == p_command_index) {
+ if (!resource_has_parent) {
+ // Slices are allowed to be in different usages in the same command as they are guaranteed to have no overlap in the same command.
+ ERR_FAIL_MSG("Command can't have itself as a dependency.");
+ } else {
+ // Advance to the next element.
+ read_command_list_index = command_list_node.next_list_index;
+ previous_command_list_index = read_command_list_index;
+ }
+ } else {
+ if (previous_command_list_index >= 0) {
+ // Erase this element and connect the previous one to the next element.
+ command_list_nodes[previous_command_list_index].next_list_index = command_list_node.next_list_index;
+ read_command_list_index = command_list_node.next_list_index;
+ previous_command_list_index = read_command_list_index;
+ } else {
+ // Erase this element from the head of the list.
+ DEV_ASSERT(search_tracker->read_command_list_index == read_command_list_index);
+ read_command_list_index = command_list_node.next_list_index;
+ search_tracker->read_command_list_index = read_command_list_index;
+ }
+
+ // Add this command to the adjacency list of each command that was reading this resource.
+ _add_adjacent_command(command_list_node.command_index, p_command_index, r_command);
+ }
+ }
+ } else {
+ // We add a read dependency to the tracker to indicate this command reads from the resource.
+ search_tracker->read_command_list_index = _add_to_command_list(p_command_index, search_tracker->read_command_list_index);
+ }
+ }
+}
+
+void RenderingDeviceGraph::_add_texture_barrier_to_command(RDD::TextureID p_texture_id, BitField<RDD::BarrierAccessBits> p_src_access, BitField<RDD::BarrierAccessBits> p_dst_access, ResourceUsage p_prev_usage, ResourceUsage p_next_usage, RDD::TextureSubresourceRange p_subresources, LocalVector<RDD::TextureBarrier> &r_barrier_vector, int32_t &r_barrier_index, int32_t &r_barrier_count) {
+ if (!driver_honors_barriers) {
+ return;
+ }
+
+ if (r_barrier_index < 0) {
+ r_barrier_index = r_barrier_vector.size();
+ }
+
+ RDD::TextureBarrier texture_barrier;
+ texture_barrier.texture = p_texture_id;
+ texture_barrier.src_access = p_src_access;
+ texture_barrier.dst_access = p_dst_access;
+ texture_barrier.prev_layout = _usage_to_image_layout(p_prev_usage);
+ texture_barrier.next_layout = _usage_to_image_layout(p_next_usage);
+ texture_barrier.subresources = p_subresources;
+ r_barrier_vector.push_back(texture_barrier);
+ r_barrier_count++;
+}
+
+#if USE_BUFFER_BARRIERS
+void RenderingDeviceGraph::_add_buffer_barrier_to_command(RDD::BufferID p_buffer_id, BitField<RDD::BarrierAccessBits> p_src_access, BitField<RDD::BarrierAccessBits> p_dst_access, int32_t &r_barrier_index, int32_t &r_barrier_count) {
+ if (!driver_honors_barriers) {
+ return;
+ }
+
+ if (r_barrier_index < 0) {
+ r_barrier_index = command_buffer_barriers.size();
+ }
+
+ RDD::BufferBarrier buffer_barrier;
+ buffer_barrier.buffer = p_buffer_id;
+ buffer_barrier.src_access = p_src_access;
+ buffer_barrier.dst_access = p_dst_access;
+ buffer_barrier.offset = 0;
+ buffer_barrier.size = RDD::BUFFER_WHOLE_SIZE;
+ command_buffer_barriers.push_back(buffer_barrier);
+ r_barrier_count++;
+}
+#endif
+
+void RenderingDeviceGraph::_run_compute_list_command(RDD::CommandBufferID p_command_buffer, const uint8_t *p_instruction_data, uint32_t p_instruction_data_size) {
+ uint32_t instruction_data_cursor = 0;
+ while (instruction_data_cursor < p_instruction_data_size) {
+ DEV_ASSERT((instruction_data_cursor + sizeof(ComputeListInstruction)) <= p_instruction_data_size);
+
+ const ComputeListInstruction *instruction = reinterpret_cast<const ComputeListInstruction *>(&p_instruction_data[instruction_data_cursor]);
+ switch (instruction->type) {
+ case ComputeListInstruction::TYPE_BIND_PIPELINE: {
+ const ComputeListBindPipelineInstruction *bind_pipeline_instruction = reinterpret_cast<const ComputeListBindPipelineInstruction *>(instruction);
+ driver->command_bind_compute_pipeline(p_command_buffer, bind_pipeline_instruction->pipeline);
+ instruction_data_cursor += sizeof(ComputeListBindPipelineInstruction);
+ } break;
+ case ComputeListInstruction::TYPE_BIND_UNIFORM_SET: {
+ const ComputeListBindUniformSetInstruction *bind_uniform_set_instruction = reinterpret_cast<const ComputeListBindUniformSetInstruction *>(instruction);
+ driver->command_bind_compute_uniform_set(p_command_buffer, bind_uniform_set_instruction->uniform_set, bind_uniform_set_instruction->shader, bind_uniform_set_instruction->set_index);
+ instruction_data_cursor += sizeof(ComputeListBindUniformSetInstruction);
+ } break;
+ case ComputeListInstruction::TYPE_DISPATCH: {
+ const ComputeListDispatchInstruction *dispatch_instruction = reinterpret_cast<const ComputeListDispatchInstruction *>(instruction);
+ driver->command_compute_dispatch(p_command_buffer, dispatch_instruction->x_groups, dispatch_instruction->y_groups, dispatch_instruction->z_groups);
+ instruction_data_cursor += sizeof(ComputeListDispatchInstruction);
+ } break;
+ case ComputeListInstruction::TYPE_DISPATCH_INDIRECT: {
+ const ComputeListDispatchIndirectInstruction *dispatch_indirect_instruction = reinterpret_cast<const ComputeListDispatchIndirectInstruction *>(instruction);
+ driver->command_compute_dispatch_indirect(p_command_buffer, dispatch_indirect_instruction->buffer, dispatch_indirect_instruction->offset);
+ instruction_data_cursor += sizeof(ComputeListDispatchIndirectInstruction);
+ } break;
+ case ComputeListInstruction::TYPE_SET_PUSH_CONSTANT: {
+ const ComputeListSetPushConstantInstruction *set_push_constant_instruction = reinterpret_cast<const ComputeListSetPushConstantInstruction *>(instruction);
+ const VectorView push_constant_data_view(reinterpret_cast<const uint32_t *>(set_push_constant_instruction->data()), set_push_constant_instruction->size / sizeof(uint32_t));
+ driver->command_bind_push_constants(p_command_buffer, set_push_constant_instruction->shader, 0, push_constant_data_view);
+ instruction_data_cursor += sizeof(ComputeListSetPushConstantInstruction);
+ instruction_data_cursor += set_push_constant_instruction->size;
+ } break;
+ case ComputeListInstruction::TYPE_UNIFORM_SET_PREPARE_FOR_USE: {
+ const ComputeListUniformSetPrepareForUseInstruction *uniform_set_prepare_for_use_instruction = reinterpret_cast<const ComputeListUniformSetPrepareForUseInstruction *>(instruction);
+ driver->command_uniform_set_prepare_for_use(p_command_buffer, uniform_set_prepare_for_use_instruction->uniform_set, uniform_set_prepare_for_use_instruction->shader, uniform_set_prepare_for_use_instruction->set_index);
+ instruction_data_cursor += sizeof(ComputeListUniformSetPrepareForUseInstruction);
+ } break;
+ default:
+ DEV_ASSERT(false && "Unknown compute list instruction type.");
+ return;
+ }
+ }
+}
+
+void RenderingDeviceGraph::_run_draw_list_command(RDD::CommandBufferID p_command_buffer, const uint8_t *p_instruction_data, uint32_t p_instruction_data_size) {
+ uint32_t instruction_data_cursor = 0;
+ while (instruction_data_cursor < p_instruction_data_size) {
+ DEV_ASSERT((instruction_data_cursor + sizeof(DrawListInstruction)) <= p_instruction_data_size);
+
+ const DrawListInstruction *instruction = reinterpret_cast<const DrawListInstruction *>(&p_instruction_data[instruction_data_cursor]);
+ switch (instruction->type) {
+ case DrawListInstruction::TYPE_BIND_INDEX_BUFFER: {
+ const DrawListBindIndexBufferInstruction *bind_index_buffer_instruction = reinterpret_cast<const DrawListBindIndexBufferInstruction *>(instruction);
+ driver->command_render_bind_index_buffer(p_command_buffer, bind_index_buffer_instruction->buffer, bind_index_buffer_instruction->format, bind_index_buffer_instruction->offset);
+ instruction_data_cursor += sizeof(DrawListBindIndexBufferInstruction);
+ } break;
+ case DrawListInstruction::TYPE_BIND_PIPELINE: {
+ const DrawListBindPipelineInstruction *bind_pipeline_instruction = reinterpret_cast<const DrawListBindPipelineInstruction *>(instruction);
+ driver->command_bind_render_pipeline(p_command_buffer, bind_pipeline_instruction->pipeline);
+ instruction_data_cursor += sizeof(DrawListBindPipelineInstruction);
+ } break;
+ case DrawListInstruction::TYPE_BIND_UNIFORM_SET: {
+ const DrawListBindUniformSetInstruction *bind_uniform_set_instruction = reinterpret_cast<const DrawListBindUniformSetInstruction *>(instruction);
+ driver->command_bind_render_uniform_set(p_command_buffer, bind_uniform_set_instruction->uniform_set, bind_uniform_set_instruction->shader, bind_uniform_set_instruction->set_index);
+ instruction_data_cursor += sizeof(DrawListBindUniformSetInstruction);
+ } break;
+ case DrawListInstruction::TYPE_BIND_VERTEX_BUFFERS: {
+ const DrawListBindVertexBuffersInstruction *bind_vertex_buffers_instruction = reinterpret_cast<const DrawListBindVertexBuffersInstruction *>(instruction);
+ driver->command_render_bind_vertex_buffers(p_command_buffer, bind_vertex_buffers_instruction->vertex_buffers_count, bind_vertex_buffers_instruction->vertex_buffers(), bind_vertex_buffers_instruction->vertex_buffer_offsets());
+ instruction_data_cursor += sizeof(DrawListBindVertexBuffersInstruction);
+ instruction_data_cursor += sizeof(RDD::BufferID) * bind_vertex_buffers_instruction->vertex_buffers_count;
+ instruction_data_cursor += sizeof(uint64_t) * bind_vertex_buffers_instruction->vertex_buffers_count;
+ } break;
+ case DrawListInstruction::TYPE_CLEAR_ATTACHMENTS: {
+ const DrawListClearAttachmentsInstruction *clear_attachments_instruction = reinterpret_cast<const DrawListClearAttachmentsInstruction *>(instruction);
+ const VectorView attachments_clear_view(clear_attachments_instruction->attachments_clear(), clear_attachments_instruction->attachments_clear_count);
+ const VectorView attachments_clear_rect_view(clear_attachments_instruction->attachments_clear_rect(), clear_attachments_instruction->attachments_clear_rect_count);
+ driver->command_render_clear_attachments(p_command_buffer, attachments_clear_view, attachments_clear_rect_view);
+ instruction_data_cursor += sizeof(DrawListClearAttachmentsInstruction);
+ instruction_data_cursor += sizeof(RDD::AttachmentClear) * clear_attachments_instruction->attachments_clear_count;
+ instruction_data_cursor += sizeof(Rect2i) * clear_attachments_instruction->attachments_clear_rect_count;
+ } break;
+ case DrawListInstruction::TYPE_DRAW: {
+ const DrawListDrawInstruction *draw_instruction = reinterpret_cast<const DrawListDrawInstruction *>(instruction);
+ driver->command_render_draw(p_command_buffer, draw_instruction->vertex_count, draw_instruction->instance_count, 0, 0);
+ instruction_data_cursor += sizeof(DrawListDrawInstruction);
+ } break;
+ case DrawListInstruction::TYPE_DRAW_INDEXED: {
+ const DrawListDrawIndexedInstruction *draw_indexed_instruction = reinterpret_cast<const DrawListDrawIndexedInstruction *>(instruction);
+ driver->command_render_draw_indexed(p_command_buffer, draw_indexed_instruction->index_count, draw_indexed_instruction->instance_count, draw_indexed_instruction->first_index, 0, 0);
+ instruction_data_cursor += sizeof(DrawListDrawIndexedInstruction);
+ } break;
+ case DrawListInstruction::TYPE_EXECUTE_COMMANDS: {
+ const DrawListExecuteCommandsInstruction *execute_commands_instruction = reinterpret_cast<const DrawListExecuteCommandsInstruction *>(instruction);
+ driver->command_buffer_execute_secondary(p_command_buffer, execute_commands_instruction->command_buffer);
+ instruction_data_cursor += sizeof(DrawListExecuteCommandsInstruction);
+ } break;
+ case DrawListInstruction::TYPE_NEXT_SUBPASS: {
+ const DrawListNextSubpassInstruction *next_subpass_instruction = reinterpret_cast<const DrawListNextSubpassInstruction *>(instruction);
+ driver->command_next_render_subpass(p_command_buffer, next_subpass_instruction->command_buffer_type);
+ instruction_data_cursor += sizeof(DrawListNextSubpassInstruction);
+ } break;
+ case DrawListInstruction::TYPE_SET_BLEND_CONSTANTS: {
+ const DrawListSetBlendConstantsInstruction *set_blend_constants_instruction = reinterpret_cast<const DrawListSetBlendConstantsInstruction *>(instruction);
+ driver->command_render_set_blend_constants(p_command_buffer, set_blend_constants_instruction->color);
+ instruction_data_cursor += sizeof(DrawListSetBlendConstantsInstruction);
+ } break;
+ case DrawListInstruction::TYPE_SET_LINE_WIDTH: {
+ const DrawListSetLineWidthInstruction *set_line_width_instruction = reinterpret_cast<const DrawListSetLineWidthInstruction *>(instruction);
+ driver->command_render_set_line_width(p_command_buffer, set_line_width_instruction->width);
+ instruction_data_cursor += sizeof(DrawListSetLineWidthInstruction);
+ } break;
+ case DrawListInstruction::TYPE_SET_PUSH_CONSTANT: {
+ const DrawListSetPushConstantInstruction *set_push_constant_instruction = reinterpret_cast<const DrawListSetPushConstantInstruction *>(instruction);
+ const VectorView push_constant_data_view(reinterpret_cast<const uint32_t *>(set_push_constant_instruction->data()), set_push_constant_instruction->size / sizeof(uint32_t));
+ driver->command_bind_push_constants(p_command_buffer, set_push_constant_instruction->shader, 0, push_constant_data_view);
+ instruction_data_cursor += sizeof(DrawListSetPushConstantInstruction);
+ instruction_data_cursor += set_push_constant_instruction->size;
+ } break;
+ case DrawListInstruction::TYPE_SET_SCISSOR: {
+ const DrawListSetScissorInstruction *set_scissor_instruction = reinterpret_cast<const DrawListSetScissorInstruction *>(instruction);
+ driver->command_render_set_scissor(p_command_buffer, set_scissor_instruction->rect);
+ instruction_data_cursor += sizeof(DrawListSetScissorInstruction);
+ } break;
+ case DrawListInstruction::TYPE_SET_VIEWPORT: {
+ const DrawListSetViewportInstruction *set_viewport_instruction = reinterpret_cast<const DrawListSetViewportInstruction *>(instruction);
+ driver->command_render_set_viewport(p_command_buffer, set_viewport_instruction->rect);
+ instruction_data_cursor += sizeof(DrawListSetViewportInstruction);
+ } break;
+ case DrawListInstruction::TYPE_UNIFORM_SET_PREPARE_FOR_USE: {
+ const DrawListUniformSetPrepareForUseInstruction *uniform_set_prepare_for_use_instruction = reinterpret_cast<const DrawListUniformSetPrepareForUseInstruction *>(instruction);
+ driver->command_uniform_set_prepare_for_use(p_command_buffer, uniform_set_prepare_for_use_instruction->uniform_set, uniform_set_prepare_for_use_instruction->shader, uniform_set_prepare_for_use_instruction->set_index);
+ instruction_data_cursor += sizeof(DrawListUniformSetPrepareForUseInstruction);
+ } break;
+ default:
+ DEV_ASSERT(false && "Unknown draw list instruction type.");
+ return;
+ }
+ }
+}
+
+void RenderingDeviceGraph::_run_secondary_command_buffer_task(const SecondaryCommandBuffer *p_secondary) {
+ driver->command_buffer_begin_secondary(p_secondary->command_buffer, p_secondary->render_pass, 0, p_secondary->framebuffer);
+ _run_draw_list_command(p_secondary->command_buffer, p_secondary->instruction_data.ptr(), p_secondary->instruction_data.size());
+ driver->command_buffer_end(p_secondary->command_buffer);
+}
+
+void RenderingDeviceGraph::_wait_for_secondary_command_buffer_tasks() {
+ for (uint32_t i = 0; i < frames[frame].secondary_command_buffers_used; i++) {
+ WorkerThreadPool::TaskID &task = frames[frame].secondary_command_buffers[i].task;
+ if (task != WorkerThreadPool::INVALID_TASK_ID) {
+ WorkerThreadPool::get_singleton()->wait_for_task_completion(task);
+ task = WorkerThreadPool::INVALID_TASK_ID;
+ }
+ }
+}
+
+void RenderingDeviceGraph::_run_render_commands(RDD::CommandBufferID p_command_buffer, int32_t p_level, const RecordedCommandSort *p_sorted_commands, uint32_t p_sorted_commands_count, int32_t &r_current_label_index, int32_t &r_current_label_level) {
+ for (uint32_t i = 0; i < p_sorted_commands_count; i++) {
+ const uint32_t command_index = p_sorted_commands[i].index;
+ const uint32_t command_data_offset = command_data_offsets[command_index];
+ const RecordedCommand *command = reinterpret_cast<RecordedCommand *>(&command_data[command_data_offset]);
+ _run_label_command_change(p_command_buffer, command->label_index, p_level, false, true, &p_sorted_commands[i], p_sorted_commands_count - i, r_current_label_index, r_current_label_level);
+
+ switch (command->type) {
+ case RecordedCommand::TYPE_BUFFER_CLEAR: {
+ const RecordedBufferClearCommand *buffer_clear_command = reinterpret_cast<const RecordedBufferClearCommand *>(command);
+ driver->command_clear_buffer(p_command_buffer, buffer_clear_command->buffer, buffer_clear_command->offset, buffer_clear_command->size);
+ } break;
+ case RecordedCommand::TYPE_BUFFER_COPY: {
+ const RecordedBufferCopyCommand *buffer_copy_command = reinterpret_cast<const RecordedBufferCopyCommand *>(command);
+ driver->command_copy_buffer(p_command_buffer, buffer_copy_command->source, buffer_copy_command->destination, buffer_copy_command->region);
+ } break;
+ case RecordedCommand::TYPE_BUFFER_GET_DATA: {
+ const RecordedBufferGetDataCommand *buffer_get_data_command = reinterpret_cast<const RecordedBufferGetDataCommand *>(command);
+ driver->command_copy_buffer(p_command_buffer, buffer_get_data_command->source, buffer_get_data_command->destination, buffer_get_data_command->region);
+ } break;
+ case RecordedCommand::TYPE_BUFFER_UPDATE: {
+ const RecordedBufferUpdateCommand *buffer_update_command = reinterpret_cast<const RecordedBufferUpdateCommand *>(command);
+ const RecordedBufferCopy *command_buffer_copies = buffer_update_command->buffer_copies();
+ for (uint32_t j = 0; j < buffer_update_command->buffer_copies_count; j++) {
+ driver->command_copy_buffer(p_command_buffer, command_buffer_copies[j].source, buffer_update_command->destination, command_buffer_copies[j].region);
+ }
+ } break;
+ case RecordedCommand::TYPE_COMPUTE_LIST: {
+ const RecordedComputeListCommand *compute_list_command = reinterpret_cast<const RecordedComputeListCommand *>(command);
+ _run_compute_list_command(p_command_buffer, compute_list_command->instruction_data(), compute_list_command->instruction_data_size);
+ } break;
+ case RecordedCommand::TYPE_DRAW_LIST: {
+ const RecordedDrawListCommand *draw_list_command = reinterpret_cast<const RecordedDrawListCommand *>(command);
+ const VectorView clear_values(draw_list_command->clear_values(), draw_list_command->clear_values_count);
+ driver->command_begin_render_pass(p_command_buffer, draw_list_command->render_pass, draw_list_command->framebuffer, draw_list_command->command_buffer_type, draw_list_command->region, clear_values);
+ _run_draw_list_command(p_command_buffer, draw_list_command->instruction_data(), draw_list_command->instruction_data_size);
+ driver->command_end_render_pass(p_command_buffer);
+ } break;
+ case RecordedCommand::TYPE_TEXTURE_CLEAR: {
+ const RecordedTextureClearCommand *texture_clear_command = reinterpret_cast<const RecordedTextureClearCommand *>(command);
+ driver->command_clear_color_texture(p_command_buffer, texture_clear_command->texture, RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL, texture_clear_command->color, texture_clear_command->range);
+ } break;
+ case RecordedCommand::TYPE_TEXTURE_COPY: {
+ const RecordedTextureCopyCommand *texture_copy_command = reinterpret_cast<const RecordedTextureCopyCommand *>(command);
+ driver->command_copy_texture(p_command_buffer, texture_copy_command->from_texture, RDD::TEXTURE_LAYOUT_TRANSFER_SRC_OPTIMAL, texture_copy_command->to_texture, RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL, texture_copy_command->region);
+ } break;
+ case RecordedCommand::TYPE_TEXTURE_GET_DATA: {
+ const RecordedTextureGetDataCommand *texture_get_data_command = reinterpret_cast<const RecordedTextureGetDataCommand *>(command);
+ const VectorView<RDD::BufferTextureCopyRegion> command_buffer_texture_copy_regions_view(texture_get_data_command->buffer_texture_copy_regions(), texture_get_data_command->buffer_texture_copy_regions_count);
+ driver->command_copy_texture_to_buffer(p_command_buffer, texture_get_data_command->from_texture, RDD::TEXTURE_LAYOUT_TRANSFER_SRC_OPTIMAL, texture_get_data_command->to_buffer, command_buffer_texture_copy_regions_view);
+ } break;
+ case RecordedCommand::TYPE_TEXTURE_RESOLVE: {
+ const RecordedTextureResolveCommand *texture_resolve_command = reinterpret_cast<const RecordedTextureResolveCommand *>(command);
+ driver->command_resolve_texture(p_command_buffer, texture_resolve_command->from_texture, RDD::TEXTURE_LAYOUT_TRANSFER_SRC_OPTIMAL, texture_resolve_command->src_layer, texture_resolve_command->src_mipmap, texture_resolve_command->to_texture, RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL, texture_resolve_command->dst_layer, texture_resolve_command->dst_mipmap);
+ } break;
+ case RecordedCommand::TYPE_TEXTURE_UPDATE: {
+ const RecordedTextureUpdateCommand *texture_update_command = reinterpret_cast<const RecordedTextureUpdateCommand *>(command);
+ const RecordedBufferToTextureCopy *command_buffer_to_texture_copies = texture_update_command->buffer_to_texture_copies();
+ for (uint32_t j = 0; j < texture_update_command->buffer_to_texture_copies_count; j++) {
+ driver->command_copy_buffer_to_texture(p_command_buffer, command_buffer_to_texture_copies[j].from_buffer, texture_update_command->to_texture, RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL, command_buffer_to_texture_copies[j].region);
+ }
+ } break;
+ case RecordedCommand::TYPE_CAPTURE_TIMESTAMP: {
+ const RecordedCaptureTimestampCommand *texture_capture_timestamp_command = reinterpret_cast<const RecordedCaptureTimestampCommand *>(command);
+ driver->command_timestamp_write(p_command_buffer, texture_capture_timestamp_command->pool, texture_capture_timestamp_command->index);
+ } break;
+ default: {
+ DEV_ASSERT(false && "Unknown recorded command type.");
+ return;
+ }
+ }
+ }
+}
+
+void RenderingDeviceGraph::_run_label_command_change(RDD::CommandBufferID p_command_buffer, int32_t p_new_label_index, int32_t p_new_level, bool p_ignore_previous_value, bool p_use_label_for_empty, const RecordedCommandSort *p_sorted_commands, uint32_t p_sorted_commands_count, int32_t &r_current_label_index, int32_t &r_current_label_level) {
+ if (command_label_count == 0) {
+ // Ignore any label operations if no labels were pushed.
+ return;
+ }
+
+ if (p_ignore_previous_value || p_new_label_index != r_current_label_index || p_new_level != r_current_label_level) {
+ if (!p_ignore_previous_value && (p_use_label_for_empty || r_current_label_index >= 0)) {
+ // End the current label.
+ driver->command_end_label(p_command_buffer);
+ }
+
+ String label_name;
+ Color label_color;
+ if (p_new_label_index >= 0) {
+ const char *label_chars = &command_label_chars[command_label_offsets[p_new_label_index]];
+ label_name.parse_utf8(label_chars);
+ label_color = command_label_colors[p_new_label_index];
+ } else if (p_use_label_for_empty) {
+ label_name = "Command graph";
+ label_color = Color(1, 1, 1, 1);
+ }
+
+ // Add the level to the name.
+ label_name += " (L" + itos(p_new_level) + ")";
+
+ if (p_sorted_commands != nullptr && p_sorted_commands_count > 0) {
+ // Analyze the commands in the level that have the same label to detect what type of operations are performed.
+ bool copy_commands = false;
+ bool compute_commands = false;
+ bool draw_commands = false;
+ for (uint32_t i = 0; i < p_sorted_commands_count; i++) {
+ const uint32_t command_index = p_sorted_commands[i].index;
+ const uint32_t command_data_offset = command_data_offsets[command_index];
+ const RecordedCommand *command = reinterpret_cast<RecordedCommand *>(&command_data[command_data_offset]);
+ if (command->label_index != p_new_label_index) {
+ break;
+ }
+
+ switch (command->type) {
+ case RecordedCommand::TYPE_BUFFER_CLEAR:
+ case RecordedCommand::TYPE_BUFFER_COPY:
+ case RecordedCommand::TYPE_BUFFER_GET_DATA:
+ case RecordedCommand::TYPE_BUFFER_UPDATE:
+ case RecordedCommand::TYPE_TEXTURE_CLEAR:
+ case RecordedCommand::TYPE_TEXTURE_COPY:
+ case RecordedCommand::TYPE_TEXTURE_GET_DATA:
+ case RecordedCommand::TYPE_TEXTURE_RESOLVE:
+ case RecordedCommand::TYPE_TEXTURE_UPDATE: {
+ copy_commands = true;
+ } break;
+ case RecordedCommand::TYPE_COMPUTE_LIST: {
+ compute_commands = true;
+ } break;
+ case RecordedCommand::TYPE_DRAW_LIST: {
+ draw_commands = true;
+ } break;
+ default: {
+ // Ignore command.
+ } break;
+ }
+
+ if (copy_commands && compute_commands && draw_commands) {
+ // There's no more command types to find.
+ break;
+ }
+ }
+
+ if (copy_commands || compute_commands || draw_commands) {
+ // Add the operations to the name.
+ bool plus_after_copy = copy_commands && (compute_commands || draw_commands);
+ bool plus_after_compute = compute_commands && draw_commands;
+ label_name += " (";
+ label_name += copy_commands ? "Copy" : "";
+ label_name += plus_after_copy ? "+" : "";
+ label_name += compute_commands ? "Compute" : "";
+ label_name += plus_after_compute ? "+" : "";
+ label_name += draw_commands ? "Draw" : "";
+ label_name += ")";
+ }
+ }
+
+ // Start the new label.
+ CharString label_name_utf8 = label_name.utf8();
+ driver->command_begin_label(p_command_buffer, label_name_utf8.get_data(), label_color);
+
+ r_current_label_index = p_new_label_index;
+ r_current_label_level = p_new_level;
+ }
+}
+
+void RenderingDeviceGraph::_boost_priority_for_render_commands(RecordedCommandSort *p_sorted_commands, uint32_t p_sorted_commands_count, uint32_t &r_boosted_priority) {
+ if (p_sorted_commands_count == 0) {
+ return;
+ }
+
+ const uint32_t boosted_priority_value = 0;
+ if (r_boosted_priority > 0) {
+ bool perform_sort = false;
+ for (uint32_t j = 0; j < p_sorted_commands_count; j++) {
+ if (p_sorted_commands[j].priority == r_boosted_priority) {
+ p_sorted_commands[j].priority = boosted_priority_value;
+ perform_sort = true;
+ }
+ }
+
+ if (perform_sort) {
+ SortArray<RecordedCommandSort> command_sorter;
+ command_sorter.sort(p_sorted_commands, p_sorted_commands_count);
+ }
+ }
+
+ if (p_sorted_commands[p_sorted_commands_count - 1].priority != boosted_priority_value) {
+ r_boosted_priority = p_sorted_commands[p_sorted_commands_count - 1].priority;
+ }
+}
+
+void RenderingDeviceGraph::_group_barriers_for_render_commands(RDD::CommandBufferID p_command_buffer, const RecordedCommandSort *p_sorted_commands, uint32_t p_sorted_commands_count, bool p_full_memory_barrier) {
+ if (!driver_honors_barriers) {
+ return;
+ }
+
+ barrier_group.clear();
+ barrier_group.src_stages = RDD::PIPELINE_STAGE_TOP_OF_PIPE_BIT;
+ barrier_group.dst_stages = RDD::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
+
+ for (uint32_t i = 0; i < p_sorted_commands_count; i++) {
+ const uint32_t command_index = p_sorted_commands[i].index;
+ const uint32_t command_data_offset = command_data_offsets[command_index];
+ const RecordedCommand *command = reinterpret_cast<RecordedCommand *>(&command_data[command_data_offset]);
+
+ // Merge command's stage bits with the barrier group.
+ barrier_group.src_stages = barrier_group.src_stages | command->src_stages;
+ barrier_group.dst_stages = barrier_group.dst_stages | command->dst_stages;
+
+ // Merge command's memory barrier bits with the barrier group.
+ barrier_group.memory_barrier.src_access = barrier_group.memory_barrier.src_access | command->memory_barrier.src_access;
+ barrier_group.memory_barrier.dst_access = barrier_group.memory_barrier.dst_access | command->memory_barrier.dst_access;
+
+ // Gather texture barriers.
+ for (int32_t j = 0; j < command->normalization_barrier_count; j++) {
+ const RDD::TextureBarrier &recorded_barrier = command_normalization_barriers[command->normalization_barrier_index + j];
+ barrier_group.normalization_barriers.push_back(recorded_barrier);
+ }
+
+ for (int32_t j = 0; j < command->transition_barrier_count; j++) {
+ const RDD::TextureBarrier &recorded_barrier = command_transition_barriers[command->transition_barrier_index + j];
+ barrier_group.transition_barriers.push_back(recorded_barrier);
+ }
+
+#if USE_BUFFER_BARRIERS
+ // Gather buffer barriers.
+ for (int32_t j = 0; j < command->buffer_barrier_count; j++) {
+ const RDD::BufferBarrier &recorded_barrier = command_buffer_barriers[command->buffer_barrier_index + j];
+ barrier_group.buffer_barriers.push_back(recorded_barrier);
+ }
+#endif
+ }
+
+ if (p_full_memory_barrier) {
+ barrier_group.src_stages = RDD::PIPELINE_STAGE_ALL_COMMANDS_BIT;
+ barrier_group.dst_stages = RDD::PIPELINE_STAGE_ALL_COMMANDS_BIT;
+ barrier_group.memory_barrier.src_access = RDD::BARRIER_ACCESS_MEMORY_READ_BIT | RDD::BARRIER_ACCESS_MEMORY_WRITE_BIT;
+ barrier_group.memory_barrier.dst_access = RDD::BARRIER_ACCESS_MEMORY_READ_BIT | RDD::BARRIER_ACCESS_MEMORY_WRITE_BIT;
+ }
+
+ const bool is_memory_barrier_empty = barrier_group.memory_barrier.src_access.is_empty() && barrier_group.memory_barrier.dst_access.is_empty();
+ const bool are_texture_barriers_empty = barrier_group.normalization_barriers.is_empty() && barrier_group.transition_barriers.is_empty();
+#if USE_BUFFER_BARRIERS
+ const bool are_buffer_barriers_empty = barrier_group.buffer_barriers.is_empty();
+#else
+ const bool are_buffer_barriers_empty = true;
+#endif
+ if (is_memory_barrier_empty && are_texture_barriers_empty && are_buffer_barriers_empty) {
+ // Commands don't require synchronization.
+ return;
+ }
+
+ const VectorView<RDD::MemoryBarrier> memory_barriers = !is_memory_barrier_empty ? barrier_group.memory_barrier : VectorView<RDD::MemoryBarrier>();
+ const VectorView<RDD::TextureBarrier> texture_barriers = barrier_group.normalization_barriers.is_empty() ? barrier_group.transition_barriers : barrier_group.normalization_barriers;
+#if USE_BUFFER_BARRIERS
+ const VectorView<RDD::BufferBarrier> buffer_barriers = !are_buffer_barriers_empty ? barrier_group.buffer_barriers : VectorView<RDD::BufferBarrier>();
+#else
+ const VectorView<RDD::BufferBarrier> buffer_barriers = VectorView<RDD::BufferBarrier>();
+#endif
+
+ driver->command_pipeline_barrier(p_command_buffer, barrier_group.src_stages, barrier_group.dst_stages, memory_barriers, buffer_barriers, texture_barriers);
+
+ bool separate_texture_barriers = !barrier_group.normalization_barriers.is_empty() && !barrier_group.transition_barriers.is_empty();
+ if (separate_texture_barriers) {
+ driver->command_pipeline_barrier(p_command_buffer, barrier_group.src_stages, barrier_group.dst_stages, VectorView<RDD::MemoryBarrier>(), VectorView<RDD::BufferBarrier>(), barrier_group.transition_barriers);
+ }
+}
+
+void RenderingDeviceGraph::_print_render_commands(const RecordedCommandSort *p_sorted_commands, uint32_t p_sorted_commands_count) {
+ for (uint32_t i = 0; i < p_sorted_commands_count; i++) {
+ const uint32_t command_index = p_sorted_commands[i].index;
+ const uint32_t command_level = p_sorted_commands[i].level;
+ const uint32_t command_data_offset = command_data_offsets[command_index];
+ const RecordedCommand *command = reinterpret_cast<RecordedCommand *>(&command_data[command_data_offset]);
+ switch (command->type) {
+ case RecordedCommand::TYPE_BUFFER_CLEAR: {
+ const RecordedBufferClearCommand *buffer_clear_command = reinterpret_cast<const RecordedBufferClearCommand *>(command);
+ print_line(command_index, "LEVEL", command_level, "BUFFER CLEAR DESTINATION", itos(buffer_clear_command->buffer.id));
+ } break;
+ case RecordedCommand::TYPE_BUFFER_COPY: {
+ const RecordedBufferCopyCommand *buffer_copy_command = reinterpret_cast<const RecordedBufferCopyCommand *>(command);
+ print_line(command_index, "LEVEL", command_level, "BUFFER COPY SOURCE", itos(buffer_copy_command->source.id), "DESTINATION", itos(buffer_copy_command->destination.id));
+ } break;
+ case RecordedCommand::TYPE_BUFFER_GET_DATA: {
+ const RecordedBufferGetDataCommand *buffer_get_data_command = reinterpret_cast<const RecordedBufferGetDataCommand *>(command);
+ print_line(command_index, "LEVEL", command_level, "BUFFER GET DATA DESTINATION", itos(buffer_get_data_command->destination.id));
+ } break;
+ case RecordedCommand::TYPE_BUFFER_UPDATE: {
+ const RecordedBufferUpdateCommand *buffer_update_command = reinterpret_cast<const RecordedBufferUpdateCommand *>(command);
+ print_line(command_index, "LEVEL", command_level, "BUFFER UPDATE DESTINATION", itos(buffer_update_command->destination.id), "COPIES", buffer_update_command->buffer_copies_count);
+ } break;
+ case RecordedCommand::TYPE_COMPUTE_LIST: {
+ const RecordedComputeListCommand *compute_list_command = reinterpret_cast<const RecordedComputeListCommand *>(command);
+ print_line(command_index, "LEVEL", command_level, "COMPUTE LIST SIZE", compute_list_command->instruction_data_size);
+ } break;
+ case RecordedCommand::TYPE_DRAW_LIST: {
+ const RecordedDrawListCommand *draw_list_command = reinterpret_cast<const RecordedDrawListCommand *>(command);
+ print_line(command_index, "LEVEL", command_level, "DRAW LIST SIZE", draw_list_command->instruction_data_size);
+ } break;
+ case RecordedCommand::TYPE_TEXTURE_CLEAR: {
+ const RecordedTextureClearCommand *texture_clear_command = reinterpret_cast<const RecordedTextureClearCommand *>(command);
+ print_line(command_index, "LEVEL", command_level, "TEXTURE CLEAR", itos(texture_clear_command->texture.id), "COLOR", texture_clear_command->color);
+ } break;
+ case RecordedCommand::TYPE_TEXTURE_COPY: {
+ const RecordedTextureCopyCommand *texture_copy_command = reinterpret_cast<const RecordedTextureCopyCommand *>(command);
+ print_line(command_index, "LEVEL", command_level, "TEXTURE COPY FROM", itos(texture_copy_command->from_texture.id), "TO", itos(texture_copy_command->to_texture.id));
+ } break;
+ case RecordedCommand::TYPE_TEXTURE_GET_DATA: {
+ print_line(command_index, "LEVEL", command_level, "TEXTURE GET DATA");
+ } break;
+ case RecordedCommand::TYPE_TEXTURE_RESOLVE: {
+ const RecordedTextureResolveCommand *texture_resolve_command = reinterpret_cast<const RecordedTextureResolveCommand *>(command);
+ print_line(command_index, "LEVEL", command_level, "TEXTURE RESOLVE FROM", itos(texture_resolve_command->from_texture.id), "TO", itos(texture_resolve_command->to_texture.id));
+ } break;
+ case RecordedCommand::TYPE_TEXTURE_UPDATE: {
+ const RecordedTextureUpdateCommand *texture_update_command = reinterpret_cast<const RecordedTextureUpdateCommand *>(command);
+ print_line(command_index, "LEVEL", command_level, "TEXTURE UPDATE TO", itos(texture_update_command->to_texture.id));
+ } break;
+ case RecordedCommand::TYPE_CAPTURE_TIMESTAMP: {
+ const RecordedCaptureTimestampCommand *texture_capture_timestamp_command = reinterpret_cast<const RecordedCaptureTimestampCommand *>(command);
+ print_line(command_index, "LEVEL", command_level, "CAPTURE TIMESTAMP POOL", itos(texture_capture_timestamp_command->pool.id), "INDEX", texture_capture_timestamp_command->index);
+ } break;
+ default:
+ DEV_ASSERT(false && "Unknown recorded command type.");
+ return;
+ }
+ }
+}
+
+void RenderingDeviceGraph::_print_draw_list(const uint8_t *p_instruction_data, uint32_t p_instruction_data_size) {
+ uint32_t instruction_data_cursor = 0;
+ while (instruction_data_cursor < p_instruction_data_size) {
+ DEV_ASSERT((instruction_data_cursor + sizeof(DrawListInstruction)) <= p_instruction_data_size);
+
+ const DrawListInstruction *instruction = reinterpret_cast<const DrawListInstruction *>(&p_instruction_data[instruction_data_cursor]);
+ switch (instruction->type) {
+ case DrawListInstruction::TYPE_BIND_INDEX_BUFFER: {
+ const DrawListBindIndexBufferInstruction *bind_index_buffer_instruction = reinterpret_cast<const DrawListBindIndexBufferInstruction *>(instruction);
+ print_line("\tBIND INDEX BUFFER ID", itos(bind_index_buffer_instruction->buffer.id), "FORMAT", bind_index_buffer_instruction->format, "OFFSET", bind_index_buffer_instruction->offset);
+ instruction_data_cursor += sizeof(DrawListBindIndexBufferInstruction);
+ } break;
+ case DrawListInstruction::TYPE_BIND_PIPELINE: {
+ const DrawListBindPipelineInstruction *bind_pipeline_instruction = reinterpret_cast<const DrawListBindPipelineInstruction *>(instruction);
+ print_line("\tBIND PIPELINE ID", itos(bind_pipeline_instruction->pipeline.id));
+ instruction_data_cursor += sizeof(DrawListBindPipelineInstruction);
+ } break;
+ case DrawListInstruction::TYPE_BIND_UNIFORM_SET: {
+ const DrawListBindUniformSetInstruction *bind_uniform_set_instruction = reinterpret_cast<const DrawListBindUniformSetInstruction *>(instruction);
+ print_line("\tBIND UNIFORM SET ID", itos(bind_uniform_set_instruction->uniform_set.id), "SET INDEX", bind_uniform_set_instruction->set_index);
+ instruction_data_cursor += sizeof(DrawListBindUniformSetInstruction);
+ } break;
+ case DrawListInstruction::TYPE_BIND_VERTEX_BUFFERS: {
+ const DrawListBindVertexBuffersInstruction *bind_vertex_buffers_instruction = reinterpret_cast<const DrawListBindVertexBuffersInstruction *>(instruction);
+ print_line("\tBIND VERTEX BUFFERS COUNT", bind_vertex_buffers_instruction->vertex_buffers_count);
+ instruction_data_cursor += sizeof(DrawListBindVertexBuffersInstruction);
+ instruction_data_cursor += sizeof(RDD::BufferID) * bind_vertex_buffers_instruction->vertex_buffers_count;
+ instruction_data_cursor += sizeof(uint64_t) * bind_vertex_buffers_instruction->vertex_buffers_count;
+ } break;
+ case DrawListInstruction::TYPE_CLEAR_ATTACHMENTS: {
+ const DrawListClearAttachmentsInstruction *clear_attachments_instruction = reinterpret_cast<const DrawListClearAttachmentsInstruction *>(instruction);
+ print_line("\tATTACHMENTS CLEAR COUNT", clear_attachments_instruction->attachments_clear_count, "RECT COUNT", clear_attachments_instruction->attachments_clear_rect_count);
+ instruction_data_cursor += sizeof(DrawListClearAttachmentsInstruction);
+ instruction_data_cursor += sizeof(RDD::AttachmentClear) * clear_attachments_instruction->attachments_clear_count;
+ instruction_data_cursor += sizeof(Rect2i) * clear_attachments_instruction->attachments_clear_rect_count;
+ } break;
+ case DrawListInstruction::TYPE_DRAW: {
+ const DrawListDrawInstruction *draw_instruction = reinterpret_cast<const DrawListDrawInstruction *>(instruction);
+ print_line("\tDRAW VERTICES", draw_instruction->vertex_count, "INSTANCES", draw_instruction->instance_count);
+ instruction_data_cursor += sizeof(DrawListDrawInstruction);
+ } break;
+ case DrawListInstruction::TYPE_DRAW_INDEXED: {
+ const DrawListDrawIndexedInstruction *draw_indexed_instruction = reinterpret_cast<const DrawListDrawIndexedInstruction *>(instruction);
+ print_line("\tDRAW INDICES", draw_indexed_instruction->index_count, "INSTANCES", draw_indexed_instruction->instance_count, "FIRST INDEX", draw_indexed_instruction->first_index);
+ instruction_data_cursor += sizeof(DrawListDrawIndexedInstruction);
+ } break;
+ case DrawListInstruction::TYPE_EXECUTE_COMMANDS: {
+ print_line("\tEXECUTE COMMANDS");
+ instruction_data_cursor += sizeof(DrawListExecuteCommandsInstruction);
+ } break;
+ case DrawListInstruction::TYPE_NEXT_SUBPASS: {
+ print_line("\tNEXT SUBPASS");
+ instruction_data_cursor += sizeof(DrawListNextSubpassInstruction);
+ } break;
+ case DrawListInstruction::TYPE_SET_BLEND_CONSTANTS: {
+ const DrawListSetBlendConstantsInstruction *set_blend_constants_instruction = reinterpret_cast<const DrawListSetBlendConstantsInstruction *>(instruction);
+ print_line("\tSET BLEND CONSTANTS COLOR", set_blend_constants_instruction->color);
+ instruction_data_cursor += sizeof(DrawListSetBlendConstantsInstruction);
+ } break;
+ case DrawListInstruction::TYPE_SET_LINE_WIDTH: {
+ const DrawListSetLineWidthInstruction *set_line_width_instruction = reinterpret_cast<const DrawListSetLineWidthInstruction *>(instruction);
+ print_line("\tSET LINE WIDTH", set_line_width_instruction->width);
+ instruction_data_cursor += sizeof(DrawListSetLineWidthInstruction);
+ } break;
+ case DrawListInstruction::TYPE_SET_PUSH_CONSTANT: {
+ const DrawListSetPushConstantInstruction *set_push_constant_instruction = reinterpret_cast<const DrawListSetPushConstantInstruction *>(instruction);
+ print_line("\tSET PUSH CONSTANT SIZE", set_push_constant_instruction->size);
+ instruction_data_cursor += sizeof(DrawListSetPushConstantInstruction);
+ instruction_data_cursor += set_push_constant_instruction->size;
+ } break;
+ case DrawListInstruction::TYPE_SET_SCISSOR: {
+ const DrawListSetScissorInstruction *set_scissor_instruction = reinterpret_cast<const DrawListSetScissorInstruction *>(instruction);
+ print_line("\tSET SCISSOR", set_scissor_instruction->rect);
+ instruction_data_cursor += sizeof(DrawListSetScissorInstruction);
+ } break;
+ case DrawListInstruction::TYPE_SET_VIEWPORT: {
+ const DrawListSetViewportInstruction *set_viewport_instruction = reinterpret_cast<const DrawListSetViewportInstruction *>(instruction);
+ print_line("\tSET VIEWPORT", set_viewport_instruction->rect);
+ instruction_data_cursor += sizeof(DrawListSetViewportInstruction);
+ } break;
+ case DrawListInstruction::TYPE_UNIFORM_SET_PREPARE_FOR_USE: {
+ const DrawListUniformSetPrepareForUseInstruction *uniform_set_prepare_for_use_instruction = reinterpret_cast<const DrawListUniformSetPrepareForUseInstruction *>(instruction);
+ print_line("\tUNIFORM SET PREPARE FOR USE ID", itos(uniform_set_prepare_for_use_instruction->uniform_set.id), "SHADER ID", itos(uniform_set_prepare_for_use_instruction->shader.id), "INDEX", uniform_set_prepare_for_use_instruction->set_index);
+ instruction_data_cursor += sizeof(DrawListUniformSetPrepareForUseInstruction);
+ } break;
+ default:
+ DEV_ASSERT(false && "Unknown draw list instruction type.");
+ return;
+ }
+ }
+}
+
+void RenderingDeviceGraph::_print_compute_list(const uint8_t *p_instruction_data, uint32_t p_instruction_data_size) {
+ uint32_t instruction_data_cursor = 0;
+ while (instruction_data_cursor < p_instruction_data_size) {
+ DEV_ASSERT((instruction_data_cursor + sizeof(ComputeListInstruction)) <= p_instruction_data_size);
+
+ const ComputeListInstruction *instruction = reinterpret_cast<const ComputeListInstruction *>(&p_instruction_data[instruction_data_cursor]);
+ switch (instruction->type) {
+ case ComputeListInstruction::TYPE_BIND_PIPELINE: {
+ const ComputeListBindPipelineInstruction *bind_pipeline_instruction = reinterpret_cast<const ComputeListBindPipelineInstruction *>(instruction);
+ print_line("\tBIND PIPELINE ID", itos(bind_pipeline_instruction->pipeline.id));
+ instruction_data_cursor += sizeof(ComputeListBindPipelineInstruction);
+ } break;
+ case ComputeListInstruction::TYPE_BIND_UNIFORM_SET: {
+ const ComputeListBindUniformSetInstruction *bind_uniform_set_instruction = reinterpret_cast<const ComputeListBindUniformSetInstruction *>(instruction);
+ print_line("\tBIND UNIFORM SET ID", itos(bind_uniform_set_instruction->uniform_set.id), "SHADER ID", itos(bind_uniform_set_instruction->shader.id));
+ instruction_data_cursor += sizeof(ComputeListBindUniformSetInstruction);
+ } break;
+ case ComputeListInstruction::TYPE_DISPATCH: {
+ const ComputeListDispatchInstruction *dispatch_instruction = reinterpret_cast<const ComputeListDispatchInstruction *>(instruction);
+ print_line("\tDISPATCH", dispatch_instruction->x_groups, dispatch_instruction->y_groups, dispatch_instruction->z_groups);
+ instruction_data_cursor += sizeof(ComputeListDispatchInstruction);
+ } break;
+ case ComputeListInstruction::TYPE_DISPATCH_INDIRECT: {
+ const ComputeListDispatchIndirectInstruction *dispatch_indirect_instruction = reinterpret_cast<const ComputeListDispatchIndirectInstruction *>(instruction);
+ print_line("\tDISPATCH INDIRECT BUFFER ID", itos(dispatch_indirect_instruction->buffer.id), "OFFSET", dispatch_indirect_instruction->offset);
+ instruction_data_cursor += sizeof(ComputeListDispatchIndirectInstruction);
+ } break;
+ case ComputeListInstruction::TYPE_SET_PUSH_CONSTANT: {
+ const ComputeListSetPushConstantInstruction *set_push_constant_instruction = reinterpret_cast<const ComputeListSetPushConstantInstruction *>(instruction);
+ print_line("\tSET PUSH CONSTANT SIZE", set_push_constant_instruction->size);
+ instruction_data_cursor += sizeof(ComputeListSetPushConstantInstruction);
+ instruction_data_cursor += set_push_constant_instruction->size;
+ } break;
+ case ComputeListInstruction::TYPE_UNIFORM_SET_PREPARE_FOR_USE: {
+ const ComputeListUniformSetPrepareForUseInstruction *uniform_set_prepare_for_use_instruction = reinterpret_cast<const ComputeListUniformSetPrepareForUseInstruction *>(instruction);
+ print_line("\tUNIFORM SET PREPARE FOR USE ID", itos(uniform_set_prepare_for_use_instruction->uniform_set.id), "SHADER ID", itos(uniform_set_prepare_for_use_instruction->shader.id), "INDEX", itos(uniform_set_prepare_for_use_instruction->set_index));
+ instruction_data_cursor += sizeof(ComputeListUniformSetPrepareForUseInstruction);
+ } break;
+ default:
+ DEV_ASSERT(false && "Unknown compute list instruction type.");
+ return;
+ }
+ }
+}
+
+void RenderingDeviceGraph::initialize(RDD *p_driver, uint32_t p_frame_count, uint32_t p_secondary_command_buffers_per_frame) {
+ driver = p_driver;
+ frames.resize(p_frame_count);
+
+ for (uint32_t i = 0; i < p_frame_count; i++) {
+ frames[i].secondary_command_buffers.resize(p_secondary_command_buffers_per_frame);
+
+ for (uint32_t j = 0; j < p_secondary_command_buffers_per_frame; j++) {
+ SecondaryCommandBuffer &secondary = frames[i].secondary_command_buffers[j];
+ secondary.command_pool = driver->command_pool_create(RDD::COMMAND_BUFFER_TYPE_SECONDARY);
+ secondary.command_buffer = driver->command_buffer_create(RDD::COMMAND_BUFFER_TYPE_SECONDARY, secondary.command_pool);
+ secondary.task = WorkerThreadPool::INVALID_TASK_ID;
+ }
+ }
+
+ driver_honors_barriers = driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS);
+}
+
+void RenderingDeviceGraph::begin() {
+ command_data.clear();
+ command_data_offsets.clear();
+ command_normalization_barriers.clear();
+ command_transition_barriers.clear();
+ command_label_chars.clear();
+ command_label_colors.clear();
+ command_label_offsets.clear();
+ command_list_nodes.clear();
+ write_list_nodes.clear();
+ command_count = 0;
+ command_label_count = 0;
+ command_timestamp_index = -1;
+ command_synchronization_index = -1;
+ command_synchronization_pending = false;
+ command_label_index = -1;
+ frames[frame].secondary_command_buffers_used = 0;
+ draw_instruction_list.index = 0;
+ compute_instruction_list.index = 0;
+ tracking_frame++;
+
+#ifdef DEV_ENABLED
+ write_dependency_counters.clear();
+#endif
+}
+
+void RenderingDeviceGraph::add_buffer_clear(RDD::BufferID p_dst, ResourceTracker *p_dst_tracker, uint32_t p_offset, uint32_t p_size) {
+ DEV_ASSERT(p_dst_tracker != nullptr);
+
+ int32_t command_index;
+ RecordedBufferClearCommand *command = static_cast<RecordedBufferClearCommand *>(_allocate_command(sizeof(RecordedBufferClearCommand), command_index));
+ command->type = RecordedCommand::TYPE_BUFFER_CLEAR;
+ command->dst_stages = RDD::PIPELINE_STAGE_TRANSFER_BIT;
+ command->buffer = p_dst;
+ command->offset = p_offset;
+ command->size = p_size;
+
+ ResourceUsage usage = RESOURCE_USAGE_TRANSFER_TO;
+ _add_command_to_graph(&p_dst_tracker, &usage, 1, command_index, command);
+}
+
+void RenderingDeviceGraph::add_buffer_copy(RDD::BufferID p_src, ResourceTracker *p_src_tracker, RDD::BufferID p_dst, ResourceTracker *p_dst_tracker, RDD::BufferCopyRegion p_region) {
+ // Source tracker is allowed to be null as it could be a read-only buffer.
+ DEV_ASSERT(p_dst_tracker != nullptr);
+
+ int32_t command_index;
+ RecordedBufferCopyCommand *command = static_cast<RecordedBufferCopyCommand *>(_allocate_command(sizeof(RecordedBufferCopyCommand), command_index));
+ command->type = RecordedCommand::TYPE_BUFFER_COPY;
+ command->dst_stages = RDD::PIPELINE_STAGE_TRANSFER_BIT;
+ command->source = p_src;
+ command->destination = p_dst;
+ command->region = p_region;
+
+ ResourceTracker *trackers[2] = { p_dst_tracker, p_src_tracker };
+ ResourceUsage usages[2] = { RESOURCE_USAGE_TRANSFER_TO, RESOURCE_USAGE_TRANSFER_FROM };
+ _add_command_to_graph(trackers, usages, p_src_tracker != nullptr ? 2 : 1, command_index, command);
+}
+
+void RenderingDeviceGraph::add_buffer_get_data(RDD::BufferID p_src, ResourceTracker *p_src_tracker, RDD::BufferID p_dst, RDD::BufferCopyRegion p_region) {
+ // Source tracker is allowed to be null as it could be a read-only buffer.
+ int32_t command_index;
+ RecordedBufferGetDataCommand *command = static_cast<RecordedBufferGetDataCommand *>(_allocate_command(sizeof(RecordedBufferGetDataCommand), command_index));
+ command->type = RecordedCommand::TYPE_BUFFER_GET_DATA;
+ command->dst_stages = RDD::PIPELINE_STAGE_TRANSFER_BIT;
+ command->source = p_src;
+ command->destination = p_dst;
+ command->region = p_region;
+
+ if (p_src_tracker != nullptr) {
+ ResourceUsage usage = RESOURCE_USAGE_TRANSFER_FROM;
+ _add_command_to_graph(&p_src_tracker, &usage, 1, command_index, command);
+ } else {
+ _add_command_to_graph(nullptr, nullptr, 0, command_index, command);
+ }
+}
+
+void RenderingDeviceGraph::add_buffer_update(RDD::BufferID p_dst, ResourceTracker *p_dst_tracker, VectorView<RecordedBufferCopy> p_buffer_copies) {
+ DEV_ASSERT(p_dst_tracker != nullptr);
+
+ size_t buffer_copies_size = p_buffer_copies.size() * sizeof(RecordedBufferCopy);
+ uint64_t command_size = sizeof(RecordedBufferUpdateCommand) + buffer_copies_size;
+ int32_t command_index;
+ RecordedBufferUpdateCommand *command = static_cast<RecordedBufferUpdateCommand *>(_allocate_command(command_size, command_index));
+ command->type = RecordedCommand::TYPE_BUFFER_UPDATE;
+ command->dst_stages = RDD::PIPELINE_STAGE_TRANSFER_BIT;
+ command->destination = p_dst;
+ command->buffer_copies_count = p_buffer_copies.size();
+
+ RecordedBufferCopy *buffer_copies = command->buffer_copies();
+ for (uint32_t i = 0; i < command->buffer_copies_count; i++) {
+ buffer_copies[i] = p_buffer_copies[i];
+ }
+
+ ResourceUsage buffer_usage = RESOURCE_USAGE_TRANSFER_TO;
+ _add_command_to_graph(&p_dst_tracker, &buffer_usage, 1, command_index, command);
+}
+
+void RenderingDeviceGraph::add_compute_list_begin() {
+ compute_instruction_list.clear();
+ compute_instruction_list.index++;
+}
+
+void RenderingDeviceGraph::add_compute_list_bind_pipeline(RDD::PipelineID p_pipeline) {
+ ComputeListBindPipelineInstruction *instruction = reinterpret_cast<ComputeListBindPipelineInstruction *>(_allocate_compute_list_instruction(sizeof(ComputeListBindPipelineInstruction)));
+ instruction->type = ComputeListInstruction::TYPE_BIND_PIPELINE;
+ instruction->pipeline = p_pipeline;
+ compute_instruction_list.stages.set_flag(RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT);
+}
+
+void RenderingDeviceGraph::add_compute_list_bind_uniform_set(RDD::ShaderID p_shader, RDD::UniformSetID p_uniform_set, uint32_t set_index) {
+ ComputeListBindUniformSetInstruction *instruction = reinterpret_cast<ComputeListBindUniformSetInstruction *>(_allocate_compute_list_instruction(sizeof(ComputeListBindUniformSetInstruction)));
+ instruction->type = ComputeListInstruction::TYPE_BIND_UNIFORM_SET;
+ instruction->shader = p_shader;
+ instruction->uniform_set = p_uniform_set;
+ instruction->set_index = set_index;
+}
+
+void RenderingDeviceGraph::add_compute_list_dispatch(uint32_t p_x_groups, uint32_t p_y_groups, uint32_t p_z_groups) {
+ ComputeListDispatchInstruction *instruction = reinterpret_cast<ComputeListDispatchInstruction *>(_allocate_compute_list_instruction(sizeof(ComputeListDispatchInstruction)));
+ instruction->type = ComputeListInstruction::TYPE_DISPATCH;
+ instruction->x_groups = p_x_groups;
+ instruction->y_groups = p_y_groups;
+ instruction->z_groups = p_z_groups;
+}
+
+void RenderingDeviceGraph::add_compute_list_dispatch_indirect(RDD::BufferID p_buffer, uint32_t p_offset) {
+ ComputeListDispatchIndirectInstruction *instruction = reinterpret_cast<ComputeListDispatchIndirectInstruction *>(_allocate_compute_list_instruction(sizeof(ComputeListDispatchIndirectInstruction)));
+ instruction->type = ComputeListInstruction::TYPE_DISPATCH_INDIRECT;
+ instruction->buffer = p_buffer;
+ instruction->offset = p_offset;
+ compute_instruction_list.stages.set_flag(RDD::PIPELINE_STAGE_DRAW_INDIRECT_BIT);
+}
+
+void RenderingDeviceGraph::add_compute_list_set_push_constant(RDD::ShaderID p_shader, const void *p_data, uint32_t p_data_size) {
+ uint32_t instruction_size = sizeof(ComputeListSetPushConstantInstruction) + p_data_size;
+ ComputeListSetPushConstantInstruction *instruction = reinterpret_cast<ComputeListSetPushConstantInstruction *>(_allocate_compute_list_instruction(instruction_size));
+ instruction->type = ComputeListInstruction::TYPE_SET_PUSH_CONSTANT;
+ instruction->size = p_data_size;
+ instruction->shader = p_shader;
+ memcpy(instruction->data(), p_data, p_data_size);
+}
+
+void RenderingDeviceGraph::add_compute_list_uniform_set_prepare_for_use(RDD::ShaderID p_shader, RDD::UniformSetID p_uniform_set, uint32_t set_index) {
+ ComputeListUniformSetPrepareForUseInstruction *instruction = reinterpret_cast<ComputeListUniformSetPrepareForUseInstruction *>(_allocate_compute_list_instruction(sizeof(ComputeListUniformSetPrepareForUseInstruction)));
+ instruction->type = ComputeListInstruction::TYPE_UNIFORM_SET_PREPARE_FOR_USE;
+ instruction->shader = p_shader;
+ instruction->uniform_set = p_uniform_set;
+ instruction->set_index = set_index;
+}
+
+void RenderingDeviceGraph::add_compute_list_usage(ResourceTracker *p_tracker, ResourceUsage p_usage) {
+ DEV_ASSERT(p_tracker != nullptr);
+
+ p_tracker->reset_if_outdated(tracking_frame);
+
+ if (p_tracker->compute_list_index != compute_instruction_list.index) {
+ compute_instruction_list.command_trackers.push_back(p_tracker);
+ compute_instruction_list.command_tracker_usages.push_back(p_usage);
+ p_tracker->compute_list_index = compute_instruction_list.index;
+ }
+}
+
+void RenderingDeviceGraph::add_compute_list_usages(VectorView<ResourceTracker *> p_trackers, VectorView<ResourceUsage> p_usages) {
+ DEV_ASSERT(p_trackers.size() == p_usages.size());
+
+ for (uint32_t i = 0; i < p_trackers.size(); i++) {
+ add_compute_list_usage(p_trackers[i], p_usages[i]);
+ }
+}
+
+void RenderingDeviceGraph::add_compute_list_end() {
+ int32_t command_index;
+ uint32_t instruction_data_size = compute_instruction_list.data.size();
+ uint32_t command_size = sizeof(RecordedComputeListCommand) + instruction_data_size;
+ RecordedComputeListCommand *command = static_cast<RecordedComputeListCommand *>(_allocate_command(command_size, command_index));
+ command->type = RecordedCommand::TYPE_COMPUTE_LIST;
+ command->dst_stages = compute_instruction_list.stages;
+ command->instruction_data_size = instruction_data_size;
+ memcpy(command->instruction_data(), compute_instruction_list.data.ptr(), instruction_data_size);
+ _add_command_to_graph(compute_instruction_list.command_trackers.ptr(), compute_instruction_list.command_tracker_usages.ptr(), compute_instruction_list.command_trackers.size(), command_index, command);
+}
+
+void RenderingDeviceGraph::add_draw_list_begin(RDD::RenderPassID p_render_pass, RDD::FramebufferID p_framebuffer, Rect2i p_region, VectorView<RDD::RenderPassClearValue> p_clear_values, bool p_uses_color, bool p_uses_depth) {
+ draw_instruction_list.clear();
+ draw_instruction_list.index++;
+ draw_instruction_list.render_pass = p_render_pass;
+ draw_instruction_list.framebuffer = p_framebuffer;
+ draw_instruction_list.region = p_region;
+ draw_instruction_list.clear_values.resize(p_clear_values.size());
+ for (uint32_t i = 0; i < p_clear_values.size(); i++) {
+ draw_instruction_list.clear_values[i] = p_clear_values[i];
+ }
+
+ if (p_uses_color) {
+ draw_instruction_list.stages.set_flag(RDD::PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
+ }
+
+ if (p_uses_depth) {
+ draw_instruction_list.stages.set_flag(RDD::PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT);
+ draw_instruction_list.stages.set_flag(RDD::PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT);
+ }
+}
+
+void RenderingDeviceGraph::add_draw_list_bind_index_buffer(RDD::BufferID p_buffer, RDD::IndexBufferFormat p_format, uint32_t p_offset) {
+ DrawListBindIndexBufferInstruction *instruction = reinterpret_cast<DrawListBindIndexBufferInstruction *>(_allocate_draw_list_instruction(sizeof(DrawListBindIndexBufferInstruction)));
+ instruction->type = DrawListInstruction::TYPE_BIND_INDEX_BUFFER;
+ instruction->buffer = p_buffer;
+ instruction->format = p_format;
+ instruction->offset = p_offset;
+
+ if (instruction->buffer.id != 0) {
+ draw_instruction_list.stages.set_flag(RDD::PIPELINE_STAGE_VERTEX_INPUT_BIT);
+ }
+}
+
+void RenderingDeviceGraph::add_draw_list_bind_pipeline(RDD::PipelineID p_pipeline, BitField<RDD::PipelineStageBits> p_pipeline_stage_bits) {
+ DrawListBindPipelineInstruction *instruction = reinterpret_cast<DrawListBindPipelineInstruction *>(_allocate_draw_list_instruction(sizeof(DrawListBindPipelineInstruction)));
+ instruction->type = DrawListInstruction::TYPE_BIND_PIPELINE;
+ instruction->pipeline = p_pipeline;
+ draw_instruction_list.stages = draw_instruction_list.stages | p_pipeline_stage_bits;
+}
+
+void RenderingDeviceGraph::add_draw_list_bind_uniform_set(RDD::ShaderID p_shader, RDD::UniformSetID p_uniform_set, uint32_t set_index) {
+ DrawListBindUniformSetInstruction *instruction = reinterpret_cast<DrawListBindUniformSetInstruction *>(_allocate_draw_list_instruction(sizeof(DrawListBindUniformSetInstruction)));
+ instruction->type = DrawListInstruction::TYPE_BIND_UNIFORM_SET;
+ instruction->shader = p_shader;
+ instruction->uniform_set = p_uniform_set;
+ instruction->set_index = set_index;
+}
+
+void RenderingDeviceGraph::add_draw_list_bind_vertex_buffers(VectorView<RDD::BufferID> p_vertex_buffers, VectorView<uint64_t> p_vertex_buffer_offsets) {
+ DEV_ASSERT(p_vertex_buffers.size() == p_vertex_buffer_offsets.size());
+
+ uint32_t instruction_size = sizeof(DrawListBindVertexBuffersInstruction) + sizeof(RDD::BufferID) * p_vertex_buffers.size() + sizeof(uint64_t) * p_vertex_buffer_offsets.size();
+ DrawListBindVertexBuffersInstruction *instruction = reinterpret_cast<DrawListBindVertexBuffersInstruction *>(_allocate_draw_list_instruction(instruction_size));
+ instruction->type = DrawListInstruction::TYPE_BIND_VERTEX_BUFFERS;
+ instruction->vertex_buffers_count = p_vertex_buffers.size();
+
+ RDD::BufferID *vertex_buffers = instruction->vertex_buffers();
+ uint64_t *vertex_buffer_offsets = instruction->vertex_buffer_offsets();
+ for (uint32_t i = 0; i < instruction->vertex_buffers_count; i++) {
+ vertex_buffers[i] = p_vertex_buffers[i];
+ vertex_buffer_offsets[i] = p_vertex_buffer_offsets[i];
+ }
+
+ if (instruction->vertex_buffers_count > 0) {
+ draw_instruction_list.stages.set_flag(RDD::PIPELINE_STAGE_VERTEX_INPUT_BIT);
+ }
+}
+
+void RenderingDeviceGraph::add_draw_list_clear_attachments(VectorView<RDD::AttachmentClear> p_attachments_clear, VectorView<Rect2i> p_attachments_clear_rect) {
+ uint32_t instruction_size = sizeof(DrawListClearAttachmentsInstruction) + sizeof(RDD::AttachmentClear) * p_attachments_clear.size() + sizeof(Rect2i) * p_attachments_clear_rect.size();
+ DrawListClearAttachmentsInstruction *instruction = reinterpret_cast<DrawListClearAttachmentsInstruction *>(_allocate_draw_list_instruction(instruction_size));
+ instruction->type = DrawListInstruction::TYPE_CLEAR_ATTACHMENTS;
+ instruction->attachments_clear_count = p_attachments_clear.size();
+ instruction->attachments_clear_rect_count = p_attachments_clear_rect.size();
+
+ RDD::AttachmentClear *attachments_clear = instruction->attachments_clear();
+ Rect2i *attachments_clear_rect = instruction->attachments_clear_rect();
+ for (uint32_t i = 0; i < instruction->attachments_clear_count; i++) {
+ attachments_clear[i] = p_attachments_clear[i];
+ }
+
+ for (uint32_t i = 0; i < instruction->attachments_clear_rect_count; i++) {
+ attachments_clear_rect[i] = p_attachments_clear_rect[i];
+ }
+}
+
+void RenderingDeviceGraph::add_draw_list_draw(uint32_t p_vertex_count, uint32_t p_instance_count) {
+ DrawListDrawInstruction *instruction = reinterpret_cast<DrawListDrawInstruction *>(_allocate_draw_list_instruction(sizeof(DrawListDrawInstruction)));
+ instruction->type = DrawListInstruction::TYPE_DRAW;
+ instruction->vertex_count = p_vertex_count;
+ instruction->instance_count = p_instance_count;
+}
+
+void RenderingDeviceGraph::add_draw_list_draw_indexed(uint32_t p_index_count, uint32_t p_instance_count, uint32_t p_first_index) {
+ DrawListDrawIndexedInstruction *instruction = reinterpret_cast<DrawListDrawIndexedInstruction *>(_allocate_draw_list_instruction(sizeof(DrawListDrawIndexedInstruction)));
+ instruction->type = DrawListInstruction::TYPE_DRAW_INDEXED;
+ instruction->index_count = p_index_count;
+ instruction->instance_count = p_instance_count;
+ instruction->first_index = p_first_index;
+}
+
+void RenderingDeviceGraph::add_draw_list_execute_commands(RDD::CommandBufferID p_command_buffer) {
+ DrawListExecuteCommandsInstruction *instruction = reinterpret_cast<DrawListExecuteCommandsInstruction *>(_allocate_draw_list_instruction(sizeof(DrawListExecuteCommandsInstruction)));
+ instruction->type = DrawListInstruction::TYPE_EXECUTE_COMMANDS;
+ instruction->command_buffer = p_command_buffer;
+}
+
+void RenderingDeviceGraph::add_draw_list_next_subpass(RDD::CommandBufferType p_command_buffer_type) {
+ DrawListNextSubpassInstruction *instruction = reinterpret_cast<DrawListNextSubpassInstruction *>(_allocate_draw_list_instruction(sizeof(DrawListNextSubpassInstruction)));
+ instruction->type = DrawListInstruction::TYPE_NEXT_SUBPASS;
+ instruction->command_buffer_type = p_command_buffer_type;
+}
+
+void RenderingDeviceGraph::add_draw_list_set_blend_constants(const Color &p_color) {
+ DrawListSetBlendConstantsInstruction *instruction = reinterpret_cast<DrawListSetBlendConstantsInstruction *>(_allocate_draw_list_instruction(sizeof(DrawListSetBlendConstantsInstruction)));
+ instruction->type = DrawListInstruction::TYPE_SET_BLEND_CONSTANTS;
+ instruction->color = p_color;
+}
+
+void RenderingDeviceGraph::add_draw_list_set_line_width(float p_width) {
+ DrawListSetLineWidthInstruction *instruction = reinterpret_cast<DrawListSetLineWidthInstruction *>(_allocate_draw_list_instruction(sizeof(DrawListSetLineWidthInstruction)));
+ instruction->type = DrawListInstruction::TYPE_SET_LINE_WIDTH;
+ instruction->width = p_width;
+}
+
+void RenderingDeviceGraph::add_draw_list_set_push_constant(RDD::ShaderID p_shader, const void *p_data, uint32_t p_data_size) {
+ uint32_t instruction_size = sizeof(DrawListSetPushConstantInstruction) + p_data_size;
+ DrawListSetPushConstantInstruction *instruction = reinterpret_cast<DrawListSetPushConstantInstruction *>(_allocate_draw_list_instruction(instruction_size));
+ instruction->type = DrawListInstruction::TYPE_SET_PUSH_CONSTANT;
+ instruction->size = p_data_size;
+ instruction->shader = p_shader;
+ memcpy(instruction->data(), p_data, p_data_size);
+}
+
+void RenderingDeviceGraph::add_draw_list_set_scissor(Rect2i p_rect) {
+ DrawListSetScissorInstruction *instruction = reinterpret_cast<DrawListSetScissorInstruction *>(_allocate_draw_list_instruction(sizeof(DrawListSetScissorInstruction)));
+ instruction->type = DrawListInstruction::TYPE_SET_SCISSOR;
+ instruction->rect = p_rect;
+}
+
+void RenderingDeviceGraph::add_draw_list_set_viewport(Rect2i p_rect) {
+ DrawListSetViewportInstruction *instruction = reinterpret_cast<DrawListSetViewportInstruction *>(_allocate_draw_list_instruction(sizeof(DrawListSetViewportInstruction)));
+ instruction->type = DrawListInstruction::TYPE_SET_VIEWPORT;
+ instruction->rect = p_rect;
+}
+
+void RenderingDeviceGraph::add_draw_list_uniform_set_prepare_for_use(RDD::ShaderID p_shader, RDD::UniformSetID p_uniform_set, uint32_t set_index) {
+ DrawListUniformSetPrepareForUseInstruction *instruction = reinterpret_cast<DrawListUniformSetPrepareForUseInstruction *>(_allocate_draw_list_instruction(sizeof(DrawListUniformSetPrepareForUseInstruction)));
+ instruction->type = DrawListInstruction::TYPE_UNIFORM_SET_PREPARE_FOR_USE;
+ instruction->shader = p_shader;
+ instruction->uniform_set = p_uniform_set;
+ instruction->set_index = set_index;
+}
+
+void RenderingDeviceGraph::add_draw_list_usage(ResourceTracker *p_tracker, ResourceUsage p_usage) {
+ p_tracker->reset_if_outdated(tracking_frame);
+
+ if (p_tracker->draw_list_index != draw_instruction_list.index) {
+ draw_instruction_list.command_trackers.push_back(p_tracker);
+ draw_instruction_list.command_tracker_usages.push_back(p_usage);
+ p_tracker->draw_list_index = draw_instruction_list.index;
+ }
+}
+
+void RenderingDeviceGraph::add_draw_list_usages(VectorView<ResourceTracker *> p_trackers, VectorView<ResourceUsage> p_usages) {
+ DEV_ASSERT(p_trackers.size() == p_usages.size());
+
+ for (uint32_t i = 0; i < p_trackers.size(); i++) {
+ add_draw_list_usage(p_trackers[i], p_usages[i]);
+ }
+}
+
+void RenderingDeviceGraph::add_draw_list_end() {
+ // Arbitrary size threshold to evaluate if it'd be best to record the draw list on the background as a secondary buffer.
+ const uint32_t instruction_data_threshold_for_secondary = 16384;
+ RDD::CommandBufferType command_buffer_type;
+ uint32_t &secondary_buffers_used = frames[frame].secondary_command_buffers_used;
+ if (draw_instruction_list.data.size() > instruction_data_threshold_for_secondary && secondary_buffers_used < frames[frame].secondary_command_buffers.size()) {
+ // Copy the current instruction list data into another array that will be used by the secondary command buffer worker.
+ SecondaryCommandBuffer &secondary = frames[frame].secondary_command_buffers[secondary_buffers_used];
+ secondary.render_pass = draw_instruction_list.render_pass;
+ secondary.framebuffer = draw_instruction_list.framebuffer;
+ secondary.instruction_data.resize(draw_instruction_list.data.size());
+ memcpy(secondary.instruction_data.ptr(), draw_instruction_list.data.ptr(), draw_instruction_list.data.size());
+
+ // Run a background task for recording the secondary command buffer.
+ secondary.task = WorkerThreadPool::get_singleton()->add_template_task(this, &RenderingDeviceGraph::_run_secondary_command_buffer_task, &secondary, true);
+
+ // Clear the instruction list and add a single command for executing the secondary command buffer instead.
+ draw_instruction_list.data.clear();
+ add_draw_list_execute_commands(secondary.command_buffer);
+ secondary_buffers_used++;
+
+ command_buffer_type = RDD::COMMAND_BUFFER_TYPE_SECONDARY;
+ } else {
+ command_buffer_type = RDD::COMMAND_BUFFER_TYPE_PRIMARY;
+ }
+
+ int32_t command_index;
+ uint32_t clear_values_size = sizeof(RDD::RenderPassClearValue) * draw_instruction_list.clear_values.size();
+ uint32_t instruction_data_size = draw_instruction_list.data.size();
+ uint32_t command_size = sizeof(RecordedDrawListCommand) + clear_values_size + instruction_data_size;
+ RecordedDrawListCommand *command = static_cast<RecordedDrawListCommand *>(_allocate_command(command_size, command_index));
+ command->type = RecordedCommand::TYPE_DRAW_LIST;
+ command->dst_stages = draw_instruction_list.stages;
+ command->instruction_data_size = instruction_data_size;
+ command->render_pass = draw_instruction_list.render_pass;
+ command->framebuffer = draw_instruction_list.framebuffer;
+ command->command_buffer_type = command_buffer_type;
+ command->region = draw_instruction_list.region;
+ command->clear_values_count = draw_instruction_list.clear_values.size();
+
+ RDD::RenderPassClearValue *clear_values = command->clear_values();
+ for (uint32_t i = 0; i < command->clear_values_count; i++) {
+ clear_values[i] = draw_instruction_list.clear_values[i];
+ }
+
+ memcpy(command->instruction_data(), draw_instruction_list.data.ptr(), instruction_data_size);
+ _add_command_to_graph(draw_instruction_list.command_trackers.ptr(), draw_instruction_list.command_tracker_usages.ptr(), draw_instruction_list.command_trackers.size(), command_index, command);
+}
+
+void RenderingDeviceGraph::add_texture_clear(RDD::TextureID p_dst, ResourceTracker *p_dst_tracker, const Color &p_color, const RDD::TextureSubresourceRange &p_range) {
+ DEV_ASSERT(p_dst_tracker != nullptr);
+
+ int32_t command_index;
+ RecordedTextureClearCommand *command = static_cast<RecordedTextureClearCommand *>(_allocate_command(sizeof(RecordedTextureClearCommand), command_index));
+ command->type = RecordedCommand::TYPE_TEXTURE_CLEAR;
+ command->dst_stages = RDD::PIPELINE_STAGE_TRANSFER_BIT;
+ command->texture = p_dst;
+ command->color = p_color;
+ command->range = p_range;
+
+ ResourceUsage usage = RESOURCE_USAGE_TRANSFER_TO;
+ _add_command_to_graph(&p_dst_tracker, &usage, 1, command_index, command);
+}
+
+void RenderingDeviceGraph::add_texture_copy(RDD::TextureID p_src, ResourceTracker *p_src_tracker, RDD::TextureID p_dst, ResourceTracker *p_dst_tracker, RDD::TextureCopyRegion p_region) {
+ DEV_ASSERT(p_src_tracker != nullptr);
+ DEV_ASSERT(p_dst_tracker != nullptr);
+
+ int32_t command_index;
+ RecordedTextureCopyCommand *command = static_cast<RecordedTextureCopyCommand *>(_allocate_command(sizeof(RecordedTextureCopyCommand), command_index));
+ command->type = RecordedCommand::TYPE_TEXTURE_COPY;
+ command->dst_stages = RDD::PIPELINE_STAGE_TRANSFER_BIT;
+ command->from_texture = p_src;
+ command->to_texture = p_dst;
+ command->region = p_region;
+
+ ResourceTracker *trackers[2] = { p_dst_tracker, p_src_tracker };
+ ResourceUsage usages[2] = { RESOURCE_USAGE_TRANSFER_TO, RESOURCE_USAGE_TRANSFER_FROM };
+ _add_command_to_graph(trackers, usages, 2, command_index, command);
+}
+
+void RenderingDeviceGraph::add_texture_get_data(RDD::TextureID p_src, ResourceTracker *p_src_tracker, RDD::BufferID p_dst, VectorView<RDD::BufferTextureCopyRegion> p_buffer_texture_copy_regions) {
+ DEV_ASSERT(p_src_tracker != nullptr);
+
+ int32_t command_index;
+ uint64_t command_size = sizeof(RecordedTextureGetDataCommand) + p_buffer_texture_copy_regions.size() * sizeof(RDD::BufferTextureCopyRegion);
+ RecordedTextureGetDataCommand *command = static_cast<RecordedTextureGetDataCommand *>(_allocate_command(command_size, command_index));
+ command->type = RecordedCommand::TYPE_TEXTURE_GET_DATA;
+ command->dst_stages = RDD::PIPELINE_STAGE_TRANSFER_BIT;
+ command->from_texture = p_src;
+ command->to_buffer = p_dst;
+ command->buffer_texture_copy_regions_count = p_buffer_texture_copy_regions.size();
+
+ RDD::BufferTextureCopyRegion *buffer_texture_copy_regions = command->buffer_texture_copy_regions();
+ for (uint32_t i = 0; i < command->buffer_texture_copy_regions_count; i++) {
+ buffer_texture_copy_regions[i] = p_buffer_texture_copy_regions[i];
+ }
+
+ ResourceUsage usage = RESOURCE_USAGE_TRANSFER_FROM;
+ _add_command_to_graph(&p_src_tracker, &usage, 1, command_index, command);
+}
+
+void RenderingDeviceGraph::add_texture_resolve(RDD::TextureID p_src, ResourceTracker *p_src_tracker, RDD::TextureID p_dst, ResourceTracker *p_dst_tracker, uint32_t p_src_layer, uint32_t p_src_mipmap, uint32_t p_dst_layer, uint32_t p_dst_mipmap) {
+ DEV_ASSERT(p_src_tracker != nullptr);
+ DEV_ASSERT(p_dst_tracker != nullptr);
+
+ int32_t command_index;
+ RecordedTextureResolveCommand *command = static_cast<RecordedTextureResolveCommand *>(_allocate_command(sizeof(RecordedTextureResolveCommand), command_index));
+ command->type = RecordedCommand::TYPE_TEXTURE_RESOLVE;
+ command->dst_stages = RDD::PIPELINE_STAGE_TRANSFER_BIT;
+ command->from_texture = p_src;
+ command->to_texture = p_dst;
+ command->src_layer = p_src_layer;
+ command->src_mipmap = p_src_mipmap;
+ command->dst_layer = p_dst_layer;
+ command->dst_mipmap = p_dst_mipmap;
+
+ ResourceTracker *trackers[2] = { p_dst_tracker, p_src_tracker };
+ ResourceUsage usages[2] = { RESOURCE_USAGE_TRANSFER_TO, RESOURCE_USAGE_TRANSFER_FROM };
+ _add_command_to_graph(trackers, usages, 2, command_index, command);
+}
+
+void RenderingDeviceGraph::add_texture_update(RDD::TextureID p_dst, ResourceTracker *p_dst_tracker, VectorView<RecordedBufferToTextureCopy> p_buffer_copies) {
+ DEV_ASSERT(p_dst_tracker != nullptr);
+
+ int32_t command_index;
+ uint64_t command_size = sizeof(RecordedTextureUpdateCommand) + p_buffer_copies.size() * sizeof(RecordedBufferToTextureCopy);
+ RecordedTextureUpdateCommand *command = static_cast<RecordedTextureUpdateCommand *>(_allocate_command(command_size, command_index));
+ command->type = RecordedCommand::TYPE_TEXTURE_UPDATE;
+ command->dst_stages = RDD::PIPELINE_STAGE_TRANSFER_BIT;
+ command->to_texture = p_dst;
+ command->buffer_to_texture_copies_count = p_buffer_copies.size();
+
+ RecordedBufferToTextureCopy *buffer_to_texture_copies = command->buffer_to_texture_copies();
+ for (uint32_t i = 0; i < command->buffer_to_texture_copies_count; i++) {
+ buffer_to_texture_copies[i] = p_buffer_copies[i];
+ }
+
+ ResourceUsage usage = RESOURCE_USAGE_TRANSFER_TO;
+ _add_command_to_graph(&p_dst_tracker, &usage, 1, command_index, command);
+}
+
+void RenderingDeviceGraph::add_capture_timestamp(RDD::QueryPoolID p_query_pool, uint32_t p_index) {
+ int32_t command_index;
+ RecordedCaptureTimestampCommand *command = static_cast<RecordedCaptureTimestampCommand *>(_allocate_command(sizeof(RecordedCaptureTimestampCommand), command_index));
+ command->type = RecordedCommand::TYPE_CAPTURE_TIMESTAMP;
+ command->dst_stages = 0;
+ command->pool = p_query_pool;
+ command->index = p_index;
+ _add_command_to_graph(nullptr, nullptr, 0, command_index, command);
+}
+
+void RenderingDeviceGraph::add_synchronization() {
+ // Synchronization is only acknowledged if commands have been recorded on the graph already.
+ if (command_count > 0) {
+ command_synchronization_pending = true;
+ }
+}
+
+void RenderingDeviceGraph::begin_label(const String &p_label_name, const Color &p_color) {
+ uint32_t command_label_offset = command_label_chars.size();
+ PackedByteArray command_label_utf8 = p_label_name.to_utf8_buffer();
+ int command_label_utf8_size = command_label_utf8.size();
+ command_label_chars.resize(command_label_offset + command_label_utf8_size + 1);
+ memcpy(&command_label_chars[command_label_offset], command_label_utf8.ptr(), command_label_utf8.size());
+ command_label_chars[command_label_offset + command_label_utf8_size] = '\0';
+ command_label_colors.push_back(p_color);
+ command_label_offsets.push_back(command_label_offset);
+ command_label_index = command_label_count;
+ command_label_count++;
+}
+
+void RenderingDeviceGraph::end_label() {
+ command_label_index = -1;
+}
+
+void RenderingDeviceGraph::end(RDD::CommandBufferID p_command_buffer, bool p_reorder_commands, bool p_full_barriers) {
+ if (command_count == 0) {
+ // No commands have been logged, do nothing.
+ return;
+ }
+
+ thread_local LocalVector<RecordedCommandSort> commands_sorted;
+ if (p_reorder_commands) {
+ thread_local LocalVector<int64_t> command_stack;
+ thread_local LocalVector<int32_t> sorted_command_indices;
+ thread_local LocalVector<uint32_t> command_degrees;
+ int32_t adjacency_list_index = 0;
+ int32_t command_index;
+
+ // Count all the incoming connections to every node by traversing their adjacency list.
+ command_degrees.resize(command_count);
+ memset(command_degrees.ptr(), 0, sizeof(uint32_t) * command_degrees.size());
+ for (uint32_t i = 0; i < command_count; i++) {
+ const RecordedCommand &recorded_command = *reinterpret_cast<const RecordedCommand *>(&command_data[command_data_offsets[i]]);
+ adjacency_list_index = recorded_command.adjacent_command_list_index;
+ while (adjacency_list_index >= 0) {
+ const RecordedCommandListNode &command_list_node = command_list_nodes[adjacency_list_index];
+ DEV_ASSERT((command_list_node.command_index != int32_t(i)) && "Command can't have itself as a dependency.");
+ command_degrees[command_list_node.command_index] += 1;
+ adjacency_list_index = command_list_node.next_list_index;
+ }
+ }
+
+ // Push to the stack all nodes that have no incoming connections.
+ command_stack.clear();
+ for (uint32_t i = 0; i < command_count; i++) {
+ if (command_degrees[i] == 0) {
+ command_stack.push_back(i);
+ }
+ }
+
+ sorted_command_indices.clear();
+ while (!command_stack.is_empty()) {
+ // Pop command from the stack.
+ command_index = command_stack[command_stack.size() - 1];
+ command_stack.resize(command_stack.size() - 1);
+
+ // Add it to the sorted commands.
+ sorted_command_indices.push_back(command_index);
+
+ // Search for its adjacents and lower their degree for every visit. If the degree reaches zero, we push the command to the stack.
+ const uint32_t command_data_offset = command_data_offsets[command_index];
+ const RecordedCommand &recorded_command = *reinterpret_cast<const RecordedCommand *>(&command_data[command_data_offset]);
+ adjacency_list_index = recorded_command.adjacent_command_list_index;
+ while (adjacency_list_index >= 0) {
+ const RecordedCommandListNode &command_list_node = command_list_nodes[adjacency_list_index];
+ uint32_t &command_degree = command_degrees[command_list_node.command_index];
+ DEV_ASSERT(command_degree > 0);
+ command_degree--;
+ if (command_degree == 0) {
+ command_stack.push_back(command_list_node.command_index);
+ }
+
+ adjacency_list_index = command_list_node.next_list_index;
+ }
+ }
+
+ // Batch buffer, texture, draw lists and compute operations together.
+ const uint32_t PriorityTable[RecordedCommand::TYPE_MAX] = {
+ 0, // TYPE_NONE
+ 1, // TYPE_BUFFER_CLEAR
+ 1, // TYPE_BUFFER_COPY
+ 1, // TYPE_BUFFER_GET_DATA
+ 1, // TYPE_BUFFER_UPDATE
+ 4, // TYPE_COMPUTE_LIST
+ 3, // TYPE_DRAW_LIST
+ 2, // TYPE_TEXTURE_CLEAR
+ 2, // TYPE_TEXTURE_COPY
+ 2, // TYPE_TEXTURE_GET_DATA
+ 2, // TYPE_TEXTURE_RESOLVE
+ 2, // TYPE_TEXTURE_UPDATE
+ };
+
+ commands_sorted.clear();
+ commands_sorted.resize(command_count);
+
+ for (uint32_t i = 0; i < command_count; i++) {
+ const int32_t sorted_command_index = sorted_command_indices[i];
+ const uint32_t command_data_offset = command_data_offsets[sorted_command_index];
+ const RecordedCommand recorded_command = *reinterpret_cast<const RecordedCommand *>(&command_data[command_data_offset]);
+ const uint32_t next_command_level = commands_sorted[sorted_command_index].level + 1;
+ adjacency_list_index = recorded_command.adjacent_command_list_index;
+ while (adjacency_list_index >= 0) {
+ const RecordedCommandListNode &command_list_node = command_list_nodes[adjacency_list_index];
+ uint32_t &adjacent_command_level = commands_sorted[command_list_node.command_index].level;
+ if (adjacent_command_level < next_command_level) {
+ adjacent_command_level = next_command_level;
+ }
+
+ adjacency_list_index = command_list_node.next_list_index;
+ }
+
+ commands_sorted[sorted_command_index].index = sorted_command_index;
+ commands_sorted[sorted_command_index].priority = PriorityTable[recorded_command.type];
+ }
+ } else {
+ commands_sorted.clear();
+ commands_sorted.resize(command_count);
+
+ for (uint32_t i = 0; i < command_count; i++) {
+ commands_sorted[i].index = i;
+ }
+ }
+
+ _wait_for_secondary_command_buffer_tasks();
+
+ if (command_count > 0) {
+ int32_t current_label_index = -1;
+ int32_t current_label_level = -1;
+ _run_label_command_change(p_command_buffer, -1, -1, true, true, nullptr, 0, current_label_index, current_label_level);
+
+ if (p_reorder_commands) {
+#if PRINT_RENDER_GRAPH
+ print_line("BEFORE SORT");
+ _print_render_commands(commands_sorted.ptr(), command_count);
+#endif
+
+ commands_sorted.sort();
+
+#if PRINT_RENDER_GRAPH
+ print_line("AFTER SORT");
+ _print_render_commands(commands_sorted.ptr(), command_count);
+#endif
+
+ uint32_t boosted_priority = 0;
+ uint32_t current_level = commands_sorted[0].level;
+ uint32_t current_level_start = 0;
+ for (uint32_t i = 0; i < command_count; i++) {
+ if (current_level != commands_sorted[i].level) {
+ RecordedCommandSort *level_command_ptr = &commands_sorted[current_level_start];
+ uint32_t level_command_count = i - current_level_start;
+ _boost_priority_for_render_commands(level_command_ptr, level_command_count, boosted_priority);
+ _group_barriers_for_render_commands(p_command_buffer, level_command_ptr, level_command_count, p_full_barriers);
+ _run_render_commands(p_command_buffer, current_level, level_command_ptr, level_command_count, current_label_index, current_label_level);
+ current_level = commands_sorted[i].level;
+ current_level_start = i;
+ }
+ }
+
+ RecordedCommandSort *level_command_ptr = &commands_sorted[current_level_start];
+ uint32_t level_command_count = command_count - current_level_start;
+ _boost_priority_for_render_commands(level_command_ptr, level_command_count, boosted_priority);
+ _group_barriers_for_render_commands(p_command_buffer, level_command_ptr, level_command_count, p_full_barriers);
+ _run_render_commands(p_command_buffer, current_level, level_command_ptr, level_command_count, current_label_index, current_label_level);
+
+#if PRINT_RENDER_GRAPH
+ print_line("COMMANDS", command_count, "LEVELS", current_level + 1);
+#endif
+ } else {
+ for (uint32_t i = 0; i < command_count; i++) {
+ _group_barriers_for_render_commands(p_command_buffer, &commands_sorted[i], 1, p_full_barriers);
+ _run_render_commands(p_command_buffer, i, &commands_sorted[i], 1, current_label_index, current_label_level);
+ }
+ }
+
+ _run_label_command_change(p_command_buffer, -1, -1, true, false, nullptr, 0, current_label_index, current_label_level);
+ }
+
+ // Advance the frame counter. It's not necessary to do this if no commands are recorded because that means no secondary command buffers were used.
+ frame = (frame + 1) % frames.size();
+}
+
+#if PRINT_RESOURCE_TRACKER_TOTAL
+static uint32_t resource_tracker_total = 0;
+#endif
+
+RenderingDeviceGraph::ResourceTracker *RenderingDeviceGraph::resource_tracker_create() {
+#if PRINT_RESOURCE_TRACKER_TOTAL
+ print_line("Resource trackers:", ++resource_tracker_total);
+#endif
+ return memnew(ResourceTracker);
+}
+
+void RenderingDeviceGraph::resource_tracker_free(ResourceTracker *tracker) {
+ if (tracker == nullptr) {
+ return;
+ }
+
+ if (tracker->in_parent_dirty_list) {
+ // Delete the tracker from the parent's dirty linked list.
+ if (tracker->parent->dirty_shared_list == tracker) {
+ tracker->parent->dirty_shared_list = tracker->next_shared;
+ } else {
+ ResourceTracker *node = tracker->parent->dirty_shared_list;
+ while (node != nullptr) {
+ if (node->next_shared == tracker) {
+ node->next_shared = tracker->next_shared;
+ node = nullptr;
+ } else {
+ node = node->next_shared;
+ }
+ }
+ }
+ }
+
+ memdelete(tracker);
+
+#if PRINT_RESOURCE_TRACKER_TOTAL
+ print_line("Resource trackers:", --resource_tracker_total);
+#endif
+}
diff --git a/servers/rendering/rendering_device_graph.h b/servers/rendering/rendering_device_graph.h
new file mode 100644
index 0000000000..84fbe02095
--- /dev/null
+++ b/servers/rendering/rendering_device_graph.h
@@ -0,0 +1,668 @@
+/**************************************************************************/
+/* rendering_device_graph.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef RENDERING_DEVICE_GRAPH_H
+#define RENDERING_DEVICE_GRAPH_H
+
+#include "core/object/worker_thread_pool.h"
+#include "rendering_device_commons.h"
+#include "rendering_device_driver.h"
+
+// Buffer barriers have not shown any significant improvement or shown to be
+// even detrimental to performance. However, there are currently some known
+// cases where using them can solve problems that using singular memory
+// barriers does not, probably due to driver issues (see comment on PR #84976
+// https://github.com/godotengine/godot/pull/84976#issuecomment-1878566830).
+
+#define USE_BUFFER_BARRIERS 1
+
+class RenderingDeviceGraph {
+public:
+ struct ComputeListInstruction {
+ enum Type {
+ TYPE_NONE,
+ TYPE_BIND_PIPELINE,
+ TYPE_BIND_UNIFORM_SET,
+ TYPE_DISPATCH,
+ TYPE_DISPATCH_INDIRECT,
+ TYPE_SET_PUSH_CONSTANT,
+ TYPE_UNIFORM_SET_PREPARE_FOR_USE
+ };
+
+ Type type = TYPE_NONE;
+ };
+
+ struct DrawListInstruction {
+ enum Type {
+ TYPE_NONE,
+ TYPE_BIND_INDEX_BUFFER,
+ TYPE_BIND_PIPELINE,
+ TYPE_BIND_UNIFORM_SET,
+ TYPE_BIND_VERTEX_BUFFERS,
+ TYPE_CLEAR_ATTACHMENTS,
+ TYPE_DRAW,
+ TYPE_DRAW_INDEXED,
+ TYPE_EXECUTE_COMMANDS,
+ TYPE_NEXT_SUBPASS,
+ TYPE_SET_BLEND_CONSTANTS,
+ TYPE_SET_LINE_WIDTH,
+ TYPE_SET_PUSH_CONSTANT,
+ TYPE_SET_SCISSOR,
+ TYPE_SET_VIEWPORT,
+ TYPE_UNIFORM_SET_PREPARE_FOR_USE
+ };
+
+ Type type = TYPE_NONE;
+ };
+
+ struct RecordedCommand {
+ enum Type {
+ TYPE_NONE,
+ TYPE_BUFFER_CLEAR,
+ TYPE_BUFFER_COPY,
+ TYPE_BUFFER_GET_DATA,
+ TYPE_BUFFER_UPDATE,
+ TYPE_COMPUTE_LIST,
+ TYPE_DRAW_LIST,
+ TYPE_TEXTURE_CLEAR,
+ TYPE_TEXTURE_COPY,
+ TYPE_TEXTURE_GET_DATA,
+ TYPE_TEXTURE_RESOLVE,
+ TYPE_TEXTURE_UPDATE,
+ TYPE_CAPTURE_TIMESTAMP,
+ TYPE_MAX
+ };
+
+ Type type = TYPE_NONE;
+ int32_t adjacent_command_list_index = -1;
+ RDD::MemoryBarrier memory_barrier;
+ int32_t normalization_barrier_index = -1;
+ int normalization_barrier_count = 0;
+ int32_t transition_barrier_index = -1;
+ int32_t transition_barrier_count = 0;
+#if USE_BUFFER_BARRIERS
+ int32_t buffer_barrier_index = -1;
+ int32_t buffer_barrier_count = 0;
+#endif
+ int32_t label_index = -1;
+ BitField<RDD::PipelineStageBits> src_stages;
+ BitField<RDD::PipelineStageBits> dst_stages;
+ };
+
+ struct RecordedBufferCopy {
+ RDD::BufferID source;
+ RDD::BufferCopyRegion region;
+ };
+
+ struct RecordedBufferToTextureCopy {
+ RDD::BufferID from_buffer;
+ RDD::BufferTextureCopyRegion region;
+ };
+
+ enum ResourceUsage {
+ RESOURCE_USAGE_NONE,
+ RESOURCE_USAGE_TRANSFER_FROM,
+ RESOURCE_USAGE_TRANSFER_TO,
+ RESOURCE_USAGE_UNIFORM_BUFFER_READ,
+ RESOURCE_USAGE_INDIRECT_BUFFER_READ,
+ RESOURCE_USAGE_TEXTURE_BUFFER_READ,
+ RESOURCE_USAGE_TEXTURE_BUFFER_READ_WRITE,
+ RESOURCE_USAGE_STORAGE_BUFFER_READ,
+ RESOURCE_USAGE_STORAGE_BUFFER_READ_WRITE,
+ RESOURCE_USAGE_VERTEX_BUFFER_READ,
+ RESOURCE_USAGE_INDEX_BUFFER_READ,
+ RESOURCE_USAGE_TEXTURE_SAMPLE,
+ RESOURCE_USAGE_STORAGE_IMAGE_READ,
+ RESOURCE_USAGE_STORAGE_IMAGE_READ_WRITE,
+ RESOURCE_USAGE_ATTACHMENT_COLOR_READ,
+ RESOURCE_USAGE_ATTACHMENT_COLOR_READ_WRITE,
+ RESOURCE_USAGE_ATTACHMENT_DEPTH_STENCIL_READ,
+ RESOURCE_USAGE_ATTACHMENT_DEPTH_STENCIL_READ_WRITE
+ };
+
+ struct ResourceTracker {
+ uint32_t reference_count = 0;
+ int64_t command_frame = -1;
+ int32_t read_command_list_index = -1;
+ int32_t write_command_or_list_index = -1;
+ int32_t draw_list_index = -1;
+ int32_t compute_list_index = -1;
+ ResourceUsage usage = RESOURCE_USAGE_NONE;
+ BitField<RDD::BarrierAccessBits> usage_access;
+ RDD::BufferID buffer_driver_id;
+ RDD::TextureID texture_driver_id;
+ RDD::TextureSubresourceRange texture_subresources;
+ int32_t texture_slice_command_index = -1;
+ ResourceTracker *parent = nullptr;
+ ResourceTracker *dirty_shared_list = nullptr;
+ ResourceTracker *next_shared = nullptr;
+ Rect2i texture_slice_or_dirty_rect;
+ bool in_parent_dirty_list = false;
+ bool write_command_list_enabled = false;
+
+ _FORCE_INLINE_ void reset_if_outdated(int64_t new_command_frame) {
+ if (new_command_frame != command_frame) {
+ usage_access.clear();
+ command_frame = new_command_frame;
+ read_command_list_index = -1;
+ write_command_or_list_index = -1;
+ draw_list_index = -1;
+ compute_list_index = -1;
+ texture_slice_command_index = -1;
+ write_command_list_enabled = false;
+ }
+ }
+ };
+
+private:
+ struct InstructionList {
+ LocalVector<uint8_t> data;
+ LocalVector<ResourceTracker *> command_trackers;
+ LocalVector<ResourceUsage> command_tracker_usages;
+ BitField<RDD::PipelineStageBits> stages;
+ int32_t index = 0;
+
+ void clear() {
+ data.clear();
+ command_trackers.clear();
+ command_tracker_usages.clear();
+ stages.clear();
+ }
+ };
+
+ struct ComputeInstructionList : InstructionList {
+ // No extra contents.
+ };
+
+ struct DrawInstructionList : InstructionList {
+ RDD::RenderPassID render_pass;
+ RDD::FramebufferID framebuffer;
+ Rect2i region;
+ LocalVector<RDD::RenderPassClearValue> clear_values;
+ };
+
+ struct RecordedCommandSort {
+ uint32_t level = 0;
+ uint32_t priority = 0;
+ int32_t index = -1;
+
+ RecordedCommandSort() = default;
+
+ bool operator<(const RecordedCommandSort &p_other) const {
+ if (level < p_other.level) {
+ return true;
+ } else if (level > p_other.level) {
+ return false;
+ }
+
+ if (priority < p_other.priority) {
+ return true;
+ } else if (priority > p_other.priority) {
+ return false;
+ }
+
+ return index < p_other.index;
+ }
+ };
+
+ struct RecordedCommandListNode {
+ int32_t command_index = -1;
+ int32_t next_list_index = -1;
+ };
+
+ struct RecordedWriteListNode {
+ int32_t command_index = -1;
+ int32_t next_list_index = -1;
+ Rect2i subresources;
+ };
+
+ struct RecordedBufferClearCommand : RecordedCommand {
+ RDD::BufferID buffer;
+ uint32_t offset = 0;
+ uint32_t size = 0;
+ };
+
+ struct RecordedBufferCopyCommand : RecordedCommand {
+ RDD::BufferID source;
+ RDD::BufferID destination;
+ RDD::BufferCopyRegion region;
+ };
+
+ struct RecordedBufferGetDataCommand : RecordedCommand {
+ RDD::BufferID source;
+ RDD::BufferID destination;
+ RDD::BufferCopyRegion region;
+ };
+
+ struct RecordedBufferUpdateCommand : RecordedCommand {
+ RDD::BufferID destination;
+ uint32_t buffer_copies_count = 0;
+
+ _FORCE_INLINE_ RecordedBufferCopy *buffer_copies() {
+ return reinterpret_cast<RecordedBufferCopy *>(&this[1]);
+ }
+
+ _FORCE_INLINE_ const RecordedBufferCopy *buffer_copies() const {
+ return reinterpret_cast<const RecordedBufferCopy *>(&this[1]);
+ }
+ };
+
+ struct RecordedComputeListCommand : RecordedCommand {
+ uint32_t instruction_data_size = 0;
+
+ _FORCE_INLINE_ uint8_t *instruction_data() {
+ return reinterpret_cast<uint8_t *>(&this[1]);
+ }
+
+ _FORCE_INLINE_ const uint8_t *instruction_data() const {
+ return reinterpret_cast<const uint8_t *>(&this[1]);
+ }
+ };
+
+ struct RecordedDrawListCommand : RecordedCommand {
+ uint32_t instruction_data_size = 0;
+ RDD::RenderPassID render_pass;
+ RDD::FramebufferID framebuffer;
+ RDD::CommandBufferType command_buffer_type;
+ Rect2i region;
+ uint32_t clear_values_count = 0;
+
+ _FORCE_INLINE_ RDD::RenderPassClearValue *clear_values() {
+ return reinterpret_cast<RDD::RenderPassClearValue *>(&this[1]);
+ }
+
+ _FORCE_INLINE_ const RDD::RenderPassClearValue *clear_values() const {
+ return reinterpret_cast<const RDD::RenderPassClearValue *>(&this[1]);
+ }
+
+ _FORCE_INLINE_ uint8_t *instruction_data() {
+ return reinterpret_cast<uint8_t *>(&clear_values()[clear_values_count]);
+ }
+
+ _FORCE_INLINE_ const uint8_t *instruction_data() const {
+ return reinterpret_cast<const uint8_t *>(&clear_values()[clear_values_count]);
+ }
+ };
+
+ struct RecordedTextureClearCommand : RecordedCommand {
+ RDD::TextureID texture;
+ RDD::TextureSubresourceRange range;
+ Color color;
+ };
+
+ struct RecordedTextureCopyCommand : RecordedCommand {
+ RDD::TextureID from_texture;
+ RDD::TextureID to_texture;
+ RDD::TextureCopyRegion region;
+ };
+
+ struct RecordedTextureGetDataCommand : RecordedCommand {
+ RDD::TextureID from_texture;
+ RDD::BufferID to_buffer;
+ uint32_t buffer_texture_copy_regions_count = 0;
+
+ _FORCE_INLINE_ RDD::BufferTextureCopyRegion *buffer_texture_copy_regions() {
+ return reinterpret_cast<RDD::BufferTextureCopyRegion *>(&this[1]);
+ }
+
+ _FORCE_INLINE_ const RDD::BufferTextureCopyRegion *buffer_texture_copy_regions() const {
+ return reinterpret_cast<const RDD::BufferTextureCopyRegion *>(&this[1]);
+ }
+ };
+
+ struct RecordedTextureResolveCommand : RecordedCommand {
+ RDD::TextureID from_texture;
+ RDD::TextureID to_texture;
+ uint32_t src_layer = 0;
+ uint32_t src_mipmap = 0;
+ uint32_t dst_layer = 0;
+ uint32_t dst_mipmap = 0;
+ };
+
+ struct RecordedTextureUpdateCommand : RecordedCommand {
+ RDD::TextureID to_texture;
+ uint32_t buffer_to_texture_copies_count = 0;
+
+ _FORCE_INLINE_ RecordedBufferToTextureCopy *buffer_to_texture_copies() {
+ return reinterpret_cast<RecordedBufferToTextureCopy *>(&this[1]);
+ }
+
+ _FORCE_INLINE_ const RecordedBufferToTextureCopy *buffer_to_texture_copies() const {
+ return reinterpret_cast<const RecordedBufferToTextureCopy *>(&this[1]);
+ }
+ };
+
+ struct RecordedCaptureTimestampCommand : RecordedCommand {
+ RDD::QueryPoolID pool;
+ uint32_t index = 0;
+ };
+
+ struct DrawListBindIndexBufferInstruction : DrawListInstruction {
+ RDD::BufferID buffer;
+ RenderingDeviceCommons::IndexBufferFormat format;
+ uint32_t offset = 0;
+ };
+
+ struct DrawListBindPipelineInstruction : DrawListInstruction {
+ RDD::PipelineID pipeline;
+ };
+
+ struct DrawListBindUniformSetInstruction : DrawListInstruction {
+ RDD::UniformSetID uniform_set;
+ RDD::ShaderID shader;
+ uint32_t set_index = 0;
+ };
+
+ struct DrawListBindVertexBuffersInstruction : DrawListInstruction {
+ uint32_t vertex_buffers_count = 0;
+
+ _FORCE_INLINE_ RDD::BufferID *vertex_buffers() {
+ return reinterpret_cast<RDD::BufferID *>(&this[1]);
+ }
+
+ _FORCE_INLINE_ const RDD::BufferID *vertex_buffers() const {
+ return reinterpret_cast<const RDD::BufferID *>(&this[1]);
+ }
+
+ _FORCE_INLINE_ uint64_t *vertex_buffer_offsets() {
+ return reinterpret_cast<uint64_t *>(&vertex_buffers()[vertex_buffers_count]);
+ }
+
+ _FORCE_INLINE_ const uint64_t *vertex_buffer_offsets() const {
+ return reinterpret_cast<const uint64_t *>(&vertex_buffers()[vertex_buffers_count]);
+ }
+ };
+
+ struct DrawListClearAttachmentsInstruction : DrawListInstruction {
+ uint32_t attachments_clear_count = 0;
+ uint32_t attachments_clear_rect_count = 0;
+
+ _FORCE_INLINE_ RDD::AttachmentClear *attachments_clear() {
+ return reinterpret_cast<RDD::AttachmentClear *>(&this[1]);
+ }
+
+ _FORCE_INLINE_ const RDD::AttachmentClear *attachments_clear() const {
+ return reinterpret_cast<const RDD::AttachmentClear *>(&this[1]);
+ }
+
+ _FORCE_INLINE_ Rect2i *attachments_clear_rect() {
+ return reinterpret_cast<Rect2i *>(&attachments_clear()[attachments_clear_count]);
+ }
+
+ _FORCE_INLINE_ const Rect2i *attachments_clear_rect() const {
+ return reinterpret_cast<const Rect2i *>(&attachments_clear()[attachments_clear_count]);
+ }
+ };
+
+ struct DrawListDrawInstruction : DrawListInstruction {
+ uint32_t vertex_count = 0;
+ uint32_t instance_count = 0;
+ };
+
+ struct DrawListDrawIndexedInstruction : DrawListInstruction {
+ uint32_t index_count = 0;
+ uint32_t instance_count = 0;
+ uint32_t first_index = 0;
+ };
+
+ struct DrawListEndRenderPassInstruction : DrawListInstruction {
+ // No contents.
+ };
+
+ struct DrawListExecuteCommandsInstruction : DrawListInstruction {
+ RDD::CommandBufferID command_buffer;
+ };
+
+ struct DrawListSetPushConstantInstruction : DrawListInstruction {
+ uint32_t size = 0;
+ RDD::ShaderID shader;
+
+ _FORCE_INLINE_ uint8_t *data() {
+ return reinterpret_cast<uint8_t *>(&this[1]);
+ }
+
+ _FORCE_INLINE_ const uint8_t *data() const {
+ return reinterpret_cast<const uint8_t *>(&this[1]);
+ }
+ };
+
+ struct DrawListNextSubpassInstruction : DrawListInstruction {
+ RDD::CommandBufferType command_buffer_type;
+ };
+
+ struct DrawListSetBlendConstantsInstruction : DrawListInstruction {
+ Color color;
+ };
+
+ struct DrawListSetLineWidthInstruction : DrawListInstruction {
+ float width;
+ };
+
+ struct DrawListSetScissorInstruction : DrawListInstruction {
+ Rect2i rect;
+ };
+
+ struct DrawListSetViewportInstruction : DrawListInstruction {
+ Rect2i rect;
+ };
+
+ struct DrawListUniformSetPrepareForUseInstruction : DrawListInstruction {
+ RDD::UniformSetID uniform_set;
+ RDD::ShaderID shader;
+ uint32_t set_index = 0;
+ };
+
+ struct ComputeListBindPipelineInstruction : ComputeListInstruction {
+ RDD::PipelineID pipeline;
+ };
+
+ struct ComputeListBindUniformSetInstruction : ComputeListInstruction {
+ RDD::UniformSetID uniform_set;
+ RDD::ShaderID shader;
+ uint32_t set_index = 0;
+ };
+
+ struct ComputeListDispatchInstruction : ComputeListInstruction {
+ uint32_t x_groups = 0;
+ uint32_t y_groups = 0;
+ uint32_t z_groups = 0;
+ };
+
+ struct ComputeListDispatchIndirectInstruction : ComputeListInstruction {
+ RDD::BufferID buffer;
+ uint32_t offset = 0;
+ };
+
+ struct ComputeListSetPushConstantInstruction : ComputeListInstruction {
+ uint32_t size = 0;
+ RDD::ShaderID shader;
+
+ _FORCE_INLINE_ uint8_t *data() {
+ return reinterpret_cast<uint8_t *>(&this[1]);
+ }
+
+ _FORCE_INLINE_ const uint8_t *data() const {
+ return reinterpret_cast<const uint8_t *>(&this[1]);
+ }
+ };
+
+ struct ComputeListUniformSetPrepareForUseInstruction : ComputeListInstruction {
+ RDD::UniformSetID uniform_set;
+ RDD::ShaderID shader;
+ uint32_t set_index = 0;
+ };
+
+ struct BarrierGroup {
+ BitField<RDD::PipelineStageBits> src_stages;
+ BitField<RDD::PipelineStageBits> dst_stages;
+ RDD::MemoryBarrier memory_barrier;
+ LocalVector<RDD::TextureBarrier> normalization_barriers;
+ LocalVector<RDD::TextureBarrier> transition_barriers;
+#if USE_BUFFER_BARRIERS
+ LocalVector<RDD::BufferBarrier> buffer_barriers;
+#endif
+
+ void clear() {
+ src_stages.clear();
+ dst_stages.clear();
+ memory_barrier.src_access.clear();
+ memory_barrier.dst_access.clear();
+ normalization_barriers.clear();
+ transition_barriers.clear();
+#if USE_BUFFER_BARRIERS
+ buffer_barriers.clear();
+#endif
+ }
+ };
+
+ struct SecondaryCommandBuffer {
+ LocalVector<uint8_t> instruction_data;
+ RDD::CommandBufferID command_buffer;
+ RDD::CommandPoolID command_pool;
+ RDD::RenderPassID render_pass;
+ RDD::FramebufferID framebuffer;
+ WorkerThreadPool::TaskID task;
+ };
+
+ struct Frame {
+ TightLocalVector<SecondaryCommandBuffer> secondary_command_buffers;
+ uint32_t secondary_command_buffers_used = 0;
+ };
+
+ RDD *driver = nullptr;
+ int64_t tracking_frame = 0;
+ LocalVector<uint8_t> command_data;
+ LocalVector<uint32_t> command_data_offsets;
+ LocalVector<RDD::TextureBarrier> command_normalization_barriers;
+ LocalVector<RDD::TextureBarrier> command_transition_barriers;
+ LocalVector<RDD::BufferBarrier> command_buffer_barriers;
+ LocalVector<char> command_label_chars;
+ LocalVector<Color> command_label_colors;
+ LocalVector<uint32_t> command_label_offsets;
+ int32_t command_label_index = -1;
+ DrawInstructionList draw_instruction_list;
+ ComputeInstructionList compute_instruction_list;
+ uint32_t command_count = 0;
+ uint32_t command_label_count = 0;
+ LocalVector<RecordedCommandListNode> command_list_nodes;
+ LocalVector<RecordedWriteListNode> write_list_nodes;
+ int32_t command_timestamp_index = -1;
+ int32_t command_synchronization_index = -1;
+ bool command_synchronization_pending = false;
+ BarrierGroup barrier_group;
+ bool driver_honors_barriers = false;
+ TightLocalVector<Frame> frames;
+ uint32_t frame = 0;
+
+#ifdef DEV_ENABLED
+ RBMap<ResourceTracker *, uint32_t> write_dependency_counters;
+#endif
+
+ static bool _is_write_usage(ResourceUsage p_usage);
+ static RDD::TextureLayout _usage_to_image_layout(ResourceUsage p_usage);
+ static RDD::BarrierAccessBits _usage_to_access_bits(ResourceUsage p_usage);
+ int32_t _add_to_command_list(int32_t p_command_index, int32_t p_list_index);
+ void _add_adjacent_command(int32_t p_previous_command_index, int32_t p_command_index, RecordedCommand *r_command);
+ int32_t _add_to_write_list(int32_t p_command_index, Rect2i suberesources, int32_t p_list_index);
+ RecordedCommand *_allocate_command(uint32_t p_command_size, int32_t &r_command_index);
+ DrawListInstruction *_allocate_draw_list_instruction(uint32_t p_instruction_size);
+ ComputeListInstruction *_allocate_compute_list_instruction(uint32_t p_instruction_size);
+ void _add_command_to_graph(ResourceTracker **p_resource_trackers, ResourceUsage *p_resource_usages, uint32_t p_resource_count, int32_t p_command_index, RecordedCommand *r_command);
+ void _add_texture_barrier_to_command(RDD::TextureID p_texture_id, BitField<RDD::BarrierAccessBits> p_src_access, BitField<RDD::BarrierAccessBits> p_dst_access, ResourceUsage p_prev_usage, ResourceUsage p_next_usage, RDD::TextureSubresourceRange p_subresources, LocalVector<RDD::TextureBarrier> &r_barrier_vector, int32_t &r_barrier_index, int32_t &r_barrier_count);
+#if USE_BUFFER_BARRIERS
+ void _add_buffer_barrier_to_command(RDD::BufferID p_buffer_id, BitField<RDD::BarrierAccessBits> p_src_access, BitField<RDD::BarrierAccessBits> p_dst_access, int32_t &r_barrier_index, int32_t &r_barrier_count);
+#endif
+ void _run_compute_list_command(RDD::CommandBufferID p_command_buffer, const uint8_t *p_instruction_data, uint32_t p_instruction_data_size);
+ void _run_draw_list_command(RDD::CommandBufferID p_command_buffer, const uint8_t *p_instruction_data, uint32_t p_instruction_data_size);
+ void _run_secondary_command_buffer_task(const SecondaryCommandBuffer *p_secondary);
+ void _wait_for_secondary_command_buffer_tasks();
+ void _run_render_commands(RDD::CommandBufferID p_command_buffer, int32_t p_level, const RecordedCommandSort *p_sorted_commands, uint32_t p_sorted_commands_count, int32_t &r_current_label_index, int32_t &r_current_label_level);
+ void _run_label_command_change(RDD::CommandBufferID p_command_buffer, int32_t p_new_label_index, int32_t p_new_level, bool p_ignore_previous_value, bool p_use_label_for_empty, const RecordedCommandSort *p_sorted_commands, uint32_t p_sorted_commands_count, int32_t &r_current_label_index, int32_t &r_current_label_level);
+ void _boost_priority_for_render_commands(RecordedCommandSort *p_sorted_commands, uint32_t p_sorted_commands_count, uint32_t &r_boosted_priority);
+ void _group_barriers_for_render_commands(RDD::CommandBufferID p_command_buffer, const RecordedCommandSort *p_sorted_commands, uint32_t p_sorted_commands_count, bool p_full_memory_barrier);
+ void _print_render_commands(const RecordedCommandSort *p_sorted_commands, uint32_t p_sorted_commands_count);
+ void _print_draw_list(const uint8_t *p_instruction_data, uint32_t p_instruction_data_size);
+ void _print_compute_list(const uint8_t *p_instruction_data, uint32_t p_instruction_data_size);
+
+public:
+ RenderingDeviceGraph();
+ ~RenderingDeviceGraph();
+ void initialize(RDD *p_driver, uint32_t p_frame_count, uint32_t p_secondary_command_buffers_per_frame);
+ void begin();
+ void add_buffer_clear(RDD::BufferID p_dst, ResourceTracker *p_dst_tracker, uint32_t p_offset, uint32_t p_size);
+ void add_buffer_copy(RDD::BufferID p_src, ResourceTracker *p_src_tracker, RDD::BufferID p_dst, ResourceTracker *p_dst_tracker, RDD::BufferCopyRegion p_region);
+ void add_buffer_get_data(RDD::BufferID p_src, ResourceTracker *p_src_tracker, RDD::BufferID p_dst, RDD::BufferCopyRegion p_region);
+ void add_buffer_update(RDD::BufferID p_dst, ResourceTracker *p_dst_tracker, VectorView<RecordedBufferCopy> p_buffer_copies);
+ void add_compute_list_begin();
+ void add_compute_list_bind_pipeline(RDD::PipelineID p_pipeline);
+ void add_compute_list_bind_uniform_set(RDD::ShaderID p_shader, RDD::UniformSetID p_uniform_set, uint32_t set_index);
+ void add_compute_list_dispatch(uint32_t p_x_groups, uint32_t p_y_groups, uint32_t p_z_groups);
+ void add_compute_list_dispatch_indirect(RDD::BufferID p_buffer, uint32_t p_offset);
+ void add_compute_list_set_push_constant(RDD::ShaderID p_shader, const void *p_data, uint32_t p_data_size);
+ void add_compute_list_uniform_set_prepare_for_use(RDD::ShaderID p_shader, RDD::UniformSetID p_uniform_set, uint32_t set_index);
+ void add_compute_list_usage(ResourceTracker *p_tracker, ResourceUsage p_usage);
+ void add_compute_list_usages(VectorView<ResourceTracker *> p_trackers, VectorView<ResourceUsage> p_usages);
+ void add_compute_list_end();
+ void add_draw_list_begin(RDD::RenderPassID p_render_pass, RDD::FramebufferID p_framebuffer, Rect2i p_region, VectorView<RDD::RenderPassClearValue> p_clear_values, bool p_uses_color, bool p_uses_depth);
+ void add_draw_list_bind_index_buffer(RDD::BufferID p_buffer, RDD::IndexBufferFormat p_format, uint32_t p_offset);
+ void add_draw_list_bind_pipeline(RDD::PipelineID p_pipeline, BitField<RDD::PipelineStageBits> p_pipeline_stage_bits);
+ void add_draw_list_bind_uniform_set(RDD::ShaderID p_shader, RDD::UniformSetID p_uniform_set, uint32_t set_index);
+ void add_draw_list_bind_vertex_buffers(VectorView<RDD::BufferID> p_vertex_buffers, VectorView<uint64_t> p_vertex_buffer_offsets);
+ void add_draw_list_clear_attachments(VectorView<RDD::AttachmentClear> p_attachments_clear, VectorView<Rect2i> p_attachments_clear_rect);
+ void add_draw_list_draw(uint32_t p_vertex_count, uint32_t p_instance_count);
+ void add_draw_list_draw_indexed(uint32_t p_index_count, uint32_t p_instance_count, uint32_t p_first_index);
+ void add_draw_list_execute_commands(RDD::CommandBufferID p_command_buffer);
+ void add_draw_list_next_subpass(RDD::CommandBufferType p_command_buffer_type);
+ void add_draw_list_set_blend_constants(const Color &p_color);
+ void add_draw_list_set_line_width(float p_width);
+ void add_draw_list_set_push_constant(RDD::ShaderID p_shader, const void *p_data, uint32_t p_data_size);
+ void add_draw_list_set_scissor(Rect2i p_rect);
+ void add_draw_list_set_viewport(Rect2i p_rect);
+ void add_draw_list_uniform_set_prepare_for_use(RDD::ShaderID p_shader, RDD::UniformSetID p_uniform_set, uint32_t set_index);
+ void add_draw_list_usage(ResourceTracker *p_tracker, ResourceUsage p_usage);
+ void add_draw_list_usages(VectorView<ResourceTracker *> p_trackers, VectorView<ResourceUsage> p_usages);
+ void add_draw_list_end();
+ void add_texture_clear(RDD::TextureID p_dst, ResourceTracker *p_dst_tracker, const Color &p_color, const RDD::TextureSubresourceRange &p_range);
+ void add_texture_copy(RDD::TextureID p_src, ResourceTracker *p_src_tracker, RDD::TextureID p_dst, ResourceTracker *p_dst_tracker, RDD::TextureCopyRegion p_region);
+ void add_texture_get_data(RDD::TextureID p_src, ResourceTracker *p_src_tracker, RDD::BufferID p_dst, VectorView<RDD::BufferTextureCopyRegion> p_buffer_texture_copy_regions);
+ void add_texture_resolve(RDD::TextureID p_src, ResourceTracker *p_src_tracker, RDD::TextureID p_dst, ResourceTracker *p_dst_tracker, uint32_t p_src_layer, uint32_t p_src_mipmap, uint32_t p_dst_layer, uint32_t p_dst_mipmap);
+ void add_texture_update(RDD::TextureID p_dst, ResourceTracker *p_dst_tracker, VectorView<RecordedBufferToTextureCopy> p_buffer_copies);
+ void add_capture_timestamp(RDD::QueryPoolID p_query_pool, uint32_t p_index);
+ void add_synchronization();
+ void begin_label(const String &p_label_name, const Color &p_color);
+ void end_label();
+ void end(RDD::CommandBufferID p_command_buffer, bool p_reorder_commands, bool p_full_barriers);
+ static ResourceTracker *resource_tracker_create();
+ static void resource_tracker_free(ResourceTracker *tracker);
+};
+
+using RDG = RenderingDeviceGraph;
+
+#endif // RENDERING_DEVICE_GRAPH_H
diff --git a/servers/rendering/rendering_server_default.cpp b/servers/rendering/rendering_server_default.cpp
index 77fe91e4c9..f7620ad5dc 100644
--- a/servers/rendering/rendering_server_default.cpp
+++ b/servers/rendering/rendering_server_default.cpp
@@ -91,10 +91,7 @@ void RenderingServerDefault::_draw(bool p_swap_buffers, double frame_step) {
RSG::viewport->draw_viewports(p_swap_buffers);
RSG::canvas_render->update();
- if (!OS::get_singleton()->get_current_rendering_driver_name().begins_with("opengl3")) {
- // Already called for gl_compatibility renderer.
- RSG::rasterizer->end_frame(p_swap_buffers);
- }
+ RSG::rasterizer->end_frame(p_swap_buffers);
XRServer *xr_server = XRServer::get_singleton();
if (xr_server != nullptr) {
@@ -214,6 +211,7 @@ void RenderingServerDefault::_finish() {
free(test_cube);
}
+ RSG::canvas->finalize();
RSG::rasterizer->finalize();
}
@@ -289,9 +287,11 @@ void RenderingServerDefault::set_default_clear_color(const Color &p_color) {
RSG::viewport->set_default_clear_color(p_color);
}
+#ifndef DISABLE_DEPRECATED
bool RenderingServerDefault::has_feature(Features p_feature) const {
return false;
}
+#endif
void RenderingServerDefault::sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir) {
RSG::scene->sdfgi_set_debug_probe_select(p_position, p_dir);
diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h
index dac1275957..11ec670280 100644
--- a/servers/rendering/rendering_server_default.h
+++ b/servers/rendering/rendering_server_default.h
@@ -1021,7 +1021,9 @@ public:
virtual Color get_default_clear_color() override;
virtual void set_default_clear_color(const Color &p_color) override;
+#ifndef DISABLE_DEPRECATED
virtual bool has_feature(Features p_feature) const override;
+#endif
virtual bool has_os_feature(const String &p_feature) const override;
virtual void set_debug_generate_wireframes(bool p_generate) override;
diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp
index a2da26eb65..fef1a205d6 100644
--- a/servers/rendering/shader_language.cpp
+++ b/servers/rendering/shader_language.cpp
@@ -4665,7 +4665,7 @@ bool ShaderLanguage::_validate_assign(Node *p_node, const FunctionInfo &p_functi
return false;
}
-bool ShaderLanguage::_propagate_function_call_sampler_uniform_settings(StringName p_name, int p_argument, TextureFilter p_filter, TextureRepeat p_repeat) {
+bool ShaderLanguage::_propagate_function_call_sampler_uniform_settings(const StringName &p_name, int p_argument, TextureFilter p_filter, TextureRepeat p_repeat) {
for (int i = 0; i < shader->vfunctions.size(); i++) {
if (shader->vfunctions[i].name == p_name) {
ERR_FAIL_INDEX_V(p_argument, shader->vfunctions[i].function->arguments.size(), false);
@@ -4699,7 +4699,7 @@ bool ShaderLanguage::_propagate_function_call_sampler_uniform_settings(StringNam
ERR_FAIL_V(false); //bug? function not found
}
-bool ShaderLanguage::_propagate_function_call_sampler_builtin_reference(StringName p_name, int p_argument, const StringName &p_builtin) {
+bool ShaderLanguage::_propagate_function_call_sampler_builtin_reference(const StringName &p_name, int p_argument, const StringName &p_builtin) {
for (int i = 0; i < shader->vfunctions.size(); i++) {
if (shader->vfunctions[i].name == p_name) {
ERR_FAIL_INDEX_V(p_argument, shader->vfunctions[i].function->arguments.size(), false);
diff --git a/servers/rendering/shader_language.h b/servers/rendering/shader_language.h
index c707f6aad7..737545b8ca 100644
--- a/servers/rendering/shader_language.h
+++ b/servers/rendering/shader_language.h
@@ -1092,8 +1092,8 @@ private:
bool _validate_function_call(BlockNode *p_block, const FunctionInfo &p_function_info, OperatorNode *p_func, DataType *r_ret_type, StringName *r_ret_type_str, bool *r_is_custom_function = nullptr);
bool _parse_function_arguments(BlockNode *p_block, const FunctionInfo &p_function_info, OperatorNode *p_func, int *r_complete_arg = nullptr);
- bool _propagate_function_call_sampler_uniform_settings(StringName p_name, int p_argument, TextureFilter p_filter, TextureRepeat p_repeat);
- bool _propagate_function_call_sampler_builtin_reference(StringName p_name, int p_argument, const StringName &p_builtin);
+ bool _propagate_function_call_sampler_uniform_settings(const StringName &p_name, int p_argument, TextureFilter p_filter, TextureRepeat p_repeat);
+ bool _propagate_function_call_sampler_builtin_reference(const StringName &p_name, int p_argument, const StringName &p_builtin);
bool _validate_varying_assign(ShaderNode::Varying &p_varying, String *r_message);
bool _check_node_constness(const Node *p_node) const;
diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp
index 00015b74a1..27e677bce0 100644
--- a/servers/rendering_server.cpp
+++ b/servers/rendering_server.cpp
@@ -2204,6 +2204,25 @@ void RenderingServer::fix_surface_compatibility(SurfaceData &p_surface, const St
}
#endif
+#ifdef TOOLS_ENABLED
+void RenderingServer::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const {
+ String pf = p_function;
+ if (p_idx == 0) {
+ if (pf == "global_shader_parameter_set" || pf == "global_shader_parameter_set_override" ||
+ pf == "global_shader_parameter_get" || pf == "global_shader_parameter_get_type" || pf == "global_shader_parameter_remove") {
+ for (StringName E : global_shader_parameter_get_list()) {
+ r_options->push_back(E.operator String().quote());
+ }
+ } else if (pf == "has_os_feature") {
+ for (String E : { "\"rgtc\"", "\"s3tc\"", "\"bptc\"", "\"etc\"", "\"etc2\"", "\"astc\"" }) {
+ r_options->push_back(E);
+ }
+ }
+ }
+ Object::get_argument_options(p_function, p_idx, r_options);
+}
+#endif
+
void RenderingServer::_bind_methods() {
BIND_CONSTANT(NO_INDEX_ARRAY);
BIND_CONSTANT(ARRAY_WEIGHTS_SIZE);
@@ -3343,7 +3362,6 @@ void RenderingServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_default_clear_color"), &RenderingServer::get_default_clear_color);
ClassDB::bind_method(D_METHOD("set_default_clear_color", "color"), &RenderingServer::set_default_clear_color);
- ClassDB::bind_method(D_METHOD("has_feature", "feature"), &RenderingServer::has_feature);
ClassDB::bind_method(D_METHOD("has_os_feature", "feature"), &RenderingServer::has_os_feature);
ClassDB::bind_method(D_METHOD("set_debug_generate_wireframes", "generate"), &RenderingServer::set_debug_generate_wireframes);
@@ -3361,9 +3379,6 @@ void RenderingServer::_bind_methods() {
BIND_ENUM_CONSTANT(RENDERING_INFO_BUFFER_MEM_USED);
BIND_ENUM_CONSTANT(RENDERING_INFO_VIDEO_MEM_USED);
- BIND_ENUM_CONSTANT(FEATURE_SHADERS);
- BIND_ENUM_CONSTANT(FEATURE_MULTITHREADED);
-
ADD_SIGNAL(MethodInfo("frame_pre_draw"));
ADD_SIGNAL(MethodInfo("frame_post_draw"));
@@ -3373,6 +3388,13 @@ void RenderingServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("create_local_rendering_device"), &RenderingServer::create_local_rendering_device);
ClassDB::bind_method(D_METHOD("call_on_render_thread", "callable"), &RenderingServer::call_on_render_thread);
+
+#ifndef DISABLE_DEPRECATED
+ ClassDB::bind_method(D_METHOD("has_feature", "feature"), &RenderingServer::has_feature);
+
+ BIND_ENUM_CONSTANT(FEATURE_SHADERS);
+ BIND_ENUM_CONSTANT(FEATURE_MULTITHREADED);
+#endif
}
void RenderingServer::mesh_add_surface_from_mesh_data(RID p_mesh, const Geometry3D::MeshData &p_mesh_data) {
@@ -3552,7 +3574,6 @@ void RenderingServer::init() {
GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "rendering/limits/spatial_indexer/update_iterations_per_frame", PROPERTY_HINT_RANGE, "0,1024,1"), 10);
GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "rendering/limits/spatial_indexer/threaded_cull_minimum_instances", PROPERTY_HINT_RANGE, "32,65536,1"), 1000);
- GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "rendering/limits/forward_renderer/threaded_render_minimum_instances", PROPERTY_HINT_RANGE, "32,65536,1"), 500);
GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "rendering/limits/cluster_builder/max_clustered_elements", PROPERTY_HINT_RANGE, "32,8192,1"), 512);
diff --git a/servers/rendering_server.h b/servers/rendering_server.h
index 016801fa6e..958c21f893 100644
--- a/servers/rendering_server.h
+++ b/servers/rendering_server.h
@@ -1612,13 +1612,14 @@ public:
virtual Color get_default_clear_color() = 0;
virtual void set_default_clear_color(const Color &p_color) = 0;
+#ifndef DISABLE_DEPRECATED
+ // Never actually used, should be removed when we can break compatibility.
enum Features {
FEATURE_SHADERS,
FEATURE_MULTITHREADED,
};
-
virtual bool has_feature(Features p_feature) const = 0;
-
+#endif
virtual bool has_os_feature(const String &p_feature) const = 0;
virtual void set_debug_generate_wireframes(bool p_generate) = 0;
@@ -1639,6 +1640,10 @@ public:
virtual void call_on_render_thread(const Callable &p_callable) = 0;
+#ifdef TOOLS_ENABLED
+ virtual void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const override;
+#endif
+
RenderingServer();
virtual ~RenderingServer();
@@ -1744,10 +1749,13 @@ VARIANT_ENUM_CAST(RenderingServer::CanvasLightShadowFilter);
VARIANT_ENUM_CAST(RenderingServer::CanvasOccluderPolygonCullMode);
VARIANT_ENUM_CAST(RenderingServer::GlobalShaderParameterType);
VARIANT_ENUM_CAST(RenderingServer::RenderingInfo);
-VARIANT_ENUM_CAST(RenderingServer::Features);
VARIANT_ENUM_CAST(RenderingServer::CanvasTextureChannel);
VARIANT_ENUM_CAST(RenderingServer::BakeChannels);
+#ifndef DISABLE_DEPRECATED
+VARIANT_ENUM_CAST(RenderingServer::Features);
+#endif
+
// Alias to make it easier to use.
#define RS RenderingServer
diff --git a/tests/core/string/test_node_path.h b/tests/core/string/test_node_path.h
index b0c810bb54..031a33c570 100644
--- a/tests/core/string/test_node_path.h
+++ b/tests/core/string/test_node_path.h
@@ -98,44 +98,44 @@ TEST_CASE("[NodePath] Relative path") {
}
TEST_CASE("[NodePath] Absolute path") {
- const NodePath node_path_aboslute = NodePath("/root/Sprite2D");
+ const NodePath node_path_absolute = NodePath("/root/Sprite2D");
CHECK_MESSAGE(
- node_path_aboslute.get_as_property_path() == NodePath(":root/Sprite2D"),
+ node_path_absolute.get_as_property_path() == NodePath(":root/Sprite2D"),
"The returned property path should match the expected value.");
CHECK_MESSAGE(
- node_path_aboslute.get_concatenated_subnames() == "",
+ node_path_absolute.get_concatenated_subnames() == "",
"The returned concatenated subnames should match the expected value.");
CHECK_MESSAGE(
- node_path_aboslute.get_name(0) == "root",
+ node_path_absolute.get_name(0) == "root",
"The returned name at index 0 should match the expected value.");
CHECK_MESSAGE(
- node_path_aboslute.get_name(1) == "Sprite2D",
+ node_path_absolute.get_name(1) == "Sprite2D",
"The returned name at index 1 should match the expected value.");
ERR_PRINT_OFF;
CHECK_MESSAGE(
- node_path_aboslute.get_name(2) == "",
+ node_path_absolute.get_name(2) == "",
"The returned name at invalid index 2 should match the expected value.");
CHECK_MESSAGE(
- node_path_aboslute.get_name(-1) == "",
+ node_path_absolute.get_name(-1) == "",
"The returned name at invalid index -1 should match the expected value.");
ERR_PRINT_ON;
CHECK_MESSAGE(
- node_path_aboslute.get_name_count() == 2,
+ node_path_absolute.get_name_count() == 2,
"The returned number of names should match the expected value.");
CHECK_MESSAGE(
- node_path_aboslute.get_subname_count() == 0,
+ node_path_absolute.get_subname_count() == 0,
"The returned number of subnames should match the expected value.");
CHECK_MESSAGE(
- node_path_aboslute.is_absolute(),
+ node_path_absolute.is_absolute(),
"The node path should be considered absolute.");
CHECK_MESSAGE(
- !node_path_aboslute.is_empty(),
+ !node_path_absolute.is_empty(),
"The node path shouldn't be considered empty.");
}
diff --git a/tests/core/variant/test_array.h b/tests/core/variant/test_array.h
index 228d77b3b5..ea61ae2a02 100644
--- a/tests/core/variant/test_array.h
+++ b/tests/core/variant/test_array.h
@@ -367,7 +367,7 @@ TEST_CASE("[Array] Duplicate recursive array") {
Array a_shallow = a.duplicate(false);
CHECK_EQ(a, a_shallow);
- // Deep copy of recursive array endup with recursion limit and return
+ // Deep copy of recursive array ends up with recursion limit and return
// an invalid result (multiple nested arrays), the point is we should
// not end up with a segfault and an error log should be printed
ERR_PRINT_OFF;
diff --git a/tests/test_main.cpp b/tests/test_main.cpp
index 5187ebd00f..7f49805274 100644
--- a/tests/test_main.cpp
+++ b/tests/test_main.cpp
@@ -30,6 +30,8 @@
#include "test_main.h"
+#include "editor/editor_paths.h"
+#include "editor/editor_settings.h"
#include "tests/core/config/test_project_settings.h"
#include "tests/core/input/test_input_event.h"
#include "tests/core/input/test_input_event_key.h"
@@ -94,7 +96,6 @@
#include "tests/scene/test_arraymesh.h"
#include "tests/scene/test_audio_stream_wav.h"
#include "tests/scene/test_bit_map.h"
-#include "tests/scene/test_camera_3d.h"
#include "tests/scene/test_code_edit.h"
#include "tests/scene/test_color_picker.h"
#include "tests/scene/test_control.h"
@@ -103,16 +104,12 @@
#include "tests/scene/test_curve_3d.h"
#include "tests/scene/test_gradient.h"
#include "tests/scene/test_navigation_agent_2d.h"
-#include "tests/scene/test_navigation_agent_3d.h"
#include "tests/scene/test_navigation_obstacle_2d.h"
-#include "tests/scene/test_navigation_obstacle_3d.h"
#include "tests/scene/test_navigation_region_2d.h"
-#include "tests/scene/test_navigation_region_3d.h"
#include "tests/scene/test_node.h"
#include "tests/scene/test_node_2d.h"
#include "tests/scene/test_packed_scene.h"
#include "tests/scene/test_path_2d.h"
-#include "tests/scene/test_path_3d.h"
#include "tests/scene/test_primitives.h"
#include "tests/scene/test_sprite_frames.h"
#include "tests/scene/test_text_edit.h"
@@ -122,10 +119,18 @@
#include "tests/scene/test_window.h"
#include "tests/servers/rendering/test_shader_preprocessor.h"
#include "tests/servers/test_navigation_server_2d.h"
-#include "tests/servers/test_navigation_server_3d.h"
#include "tests/servers/test_text_server.h"
#include "tests/test_validate_testing.h"
+#ifndef _3D_DISABLED
+#include "tests/scene/test_camera_3d.h"
+#include "tests/scene/test_navigation_agent_3d.h"
+#include "tests/scene/test_navigation_obstacle_3d.h"
+#include "tests/scene/test_navigation_region_3d.h"
+#include "tests/scene/test_path_3d.h"
+#include "tests/servers/test_navigation_server_3d.h"
+#endif // _3D_DISABLED
+
#include "modules/modules_tests.gen.h"
#include "tests/display_server_mock.h"
@@ -221,7 +226,7 @@ struct GodotTestCaseListener : public doctest::IReporter {
String name = String(p_in.m_name);
String suite_name = String(p_in.m_test_suite);
- if (name.find("[SceneTree]") != -1) {
+ if (name.find("[SceneTree]") != -1 || name.find("[Editor]") != -1) {
memnew(MessageQueue);
memnew(Input);
@@ -264,6 +269,13 @@ struct GodotTestCaseListener : public doctest::IReporter {
if (!DisplayServer::get_singleton()->has_feature(DisplayServer::Feature::FEATURE_SUBWINDOWS)) {
SceneTree::get_singleton()->get_root()->set_embedding_subwindows(true);
}
+
+ if (name.find("[Editor]") != -1) {
+ Engine::get_singleton()->set_editor_hint(true);
+ EditorPaths::create();
+ EditorSettings::create();
+ }
+
return;
}
@@ -286,6 +298,12 @@ struct GodotTestCaseListener : public doctest::IReporter {
}
void test_case_end(const doctest::CurrentTestCaseStats &) override {
+ if (EditorSettings::get_singleton()) {
+ EditorSettings::destroy();
+ }
+
+ Engine::get_singleton()->set_editor_hint(false);
+
if (SceneTree::get_singleton()) {
SceneTree::get_singleton()->finalize();
}
diff --git a/thirdparty/README.md b/thirdparty/README.md
index 510219194b..51ba9f1df4 100644
--- a/thirdparty/README.md
+++ b/thirdparty/README.md
@@ -727,7 +727,7 @@ with the provided patch.
## openxr
- Upstream: https://github.com/KhronosGroup/OpenXR-SDK
-- Version: 1.0.31 (95fe35ffb383710a6e0567e958ead9a3b66e930c, 2023)
+- Version: 1.0.33 (dc1e23937fe45eabcce80f6588cf47449edb29d1, 2024)
- License: Apache 2.0
Files extracted from upstream source:
@@ -861,7 +861,7 @@ instead of `miniz.h` as an external dependency.
## thorvg
- Upstream: https://github.com/thorvg/thorvg
-- Version: 0.11.6 (3dba4f12f8f05f86acbc51096ca3a15f5d96bc06, 2023)
+- Version: 0.12.0 (25ea242d3867ed66807714f5a52d080984d3c8cc, 2024)
- License: MIT
Files extracted from upstream source:
diff --git a/thirdparty/amd-fsr2/shaders/ffx_fsr2_depth_clip_pass.glsl b/thirdparty/amd-fsr2/shaders/ffx_fsr2_depth_clip_pass.glsl
index 65cc8b67ef..d989416eb3 100644
--- a/thirdparty/amd-fsr2/shaders/ffx_fsr2_depth_clip_pass.glsl
+++ b/thirdparty/amd-fsr2/shaders/ffx_fsr2_depth_clip_pass.glsl
@@ -29,7 +29,6 @@
#define FSR2_BIND_SRV_DILATED_DEPTH 2
#define FSR2_BIND_SRV_REACTIVE_MASK 3
#define FSR2_BIND_SRV_TRANSPARENCY_AND_COMPOSITION_MASK 4
-#define FSR2_BIND_SRV_PREPARED_INPUT_COLOR 5
#define FSR2_BIND_SRV_PREVIOUS_DILATED_MOTION_VECTORS 6
#define FSR2_BIND_SRV_INPUT_MOTION_VECTORS 7
#define FSR2_BIND_SRV_INPUT_COLOR 8
diff --git a/thirdparty/openxr/COPYING.adoc b/thirdparty/openxr/COPYING.adoc
index 473e7fdc5d..18c85fa6c7 100644
--- a/thirdparty/openxr/COPYING.adoc
+++ b/thirdparty/openxr/COPYING.adoc
@@ -1,6 +1,6 @@
= COPYING.adoc for the Khronos Group OpenXR projects
-// Copyright (c) 2020-2023, The Khronos Group Inc.
+// Copyright (c) 2020-2024, The Khronos Group Inc.
//
// SPDX-License-Identifier: CC-BY-4.0
diff --git a/thirdparty/openxr/include/openxr/openxr.h b/thirdparty/openxr/include/openxr/openxr.h
index 9ba17cbe06..3e9d6599bb 100644
--- a/thirdparty/openxr/include/openxr/openxr.h
+++ b/thirdparty/openxr/include/openxr/openxr.h
@@ -2,7 +2,7 @@
#define OPENXR_H_ 1
/*
-** Copyright 2017-2023 The Khronos Group Inc.
+** Copyright 2017-2024, The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0 OR MIT
*/
@@ -25,7 +25,7 @@ extern "C" {
((((major) & 0xffffULL) << 48) | (((minor) & 0xffffULL) << 32) | ((patch) & 0xffffffffULL))
// OpenXR current version number.
-#define XR_CURRENT_API_VERSION XR_MAKE_VERSION(1, 0, 31)
+#define XR_CURRENT_API_VERSION XR_MAKE_VERSION(1, 0, 33)
#define XR_VERSION_MAJOR(version) (uint16_t)(((uint64_t)(version) >> 48)& 0xffffULL)
#define XR_VERSION_MINOR(version) (uint16_t)(((uint64_t)(version) >> 32) & 0xffffULL)
@@ -218,6 +218,18 @@ typedef enum XrResult {
XR_RENDER_MODEL_UNAVAILABLE_FB = 1000119020,
XR_ERROR_MARKER_NOT_TRACKED_VARJO = -1000124000,
XR_ERROR_MARKER_ID_INVALID_VARJO = -1000124001,
+ XR_ERROR_MARKER_DETECTOR_PERMISSION_DENIED_ML = -1000138000,
+ XR_ERROR_MARKER_DETECTOR_LOCATE_FAILED_ML = -1000138001,
+ XR_ERROR_MARKER_DETECTOR_INVALID_DATA_QUERY_ML = -1000138002,
+ XR_ERROR_MARKER_DETECTOR_INVALID_CREATE_INFO_ML = -1000138003,
+ XR_ERROR_MARKER_INVALID_ML = -1000138004,
+ XR_ERROR_LOCALIZATION_MAP_INCOMPATIBLE_ML = -1000139000,
+ XR_ERROR_LOCALIZATION_MAP_UNAVAILABLE_ML = -1000139001,
+ XR_ERROR_LOCALIZATION_MAP_FAIL_ML = -1000139002,
+ XR_ERROR_LOCALIZATION_MAP_IMPORT_EXPORT_PERMISSION_DENIED_ML = -1000139003,
+ XR_ERROR_LOCALIZATION_MAP_PERMISSION_DENIED_ML = -1000139004,
+ XR_ERROR_LOCALIZATION_MAP_ALREADY_EXISTS_ML = -1000139005,
+ XR_ERROR_LOCALIZATION_MAP_CANNOT_EXPORT_CLOUD_MAP_ML = -1000139006,
XR_ERROR_SPATIAL_ANCHOR_NAME_NOT_FOUND_MSFT = -1000142001,
XR_ERROR_SPATIAL_ANCHOR_NAME_INVALID_MSFT = -1000142002,
XR_SCENE_MARKER_DATA_NOT_STRING_MSFT = 1000147000,
@@ -228,6 +240,7 @@ typedef enum XrResult {
XR_ERROR_SPACE_CLOUD_STORAGE_DISABLED_FB = -1000169004,
XR_ERROR_PASSTHROUGH_COLOR_LUT_BUFFER_SIZE_MISMATCH_META = -1000266000,
XR_ERROR_HINT_ALREADY_SET_QCOM = -1000306000,
+ XR_ERROR_NOT_AN_ANCHOR_HTC = -1000319000,
XR_ERROR_SPACE_NOT_LOCATABLE_EXT = -1000429000,
XR_ERROR_PLANE_DETECTION_PERMISSION_DENIED_EXT = -1000429001,
XR_RESULT_MAX_ENUM = 0x7FFFFFFF
@@ -445,6 +458,20 @@ typedef enum XrStructureType {
XR_TYPE_FRAME_END_INFO_ML = 1000135000,
XR_TYPE_GLOBAL_DIMMER_FRAME_END_INFO_ML = 1000136000,
XR_TYPE_COORDINATE_SPACE_CREATE_INFO_ML = 1000137000,
+ XR_TYPE_SYSTEM_MARKER_UNDERSTANDING_PROPERTIES_ML = 1000138000,
+ XR_TYPE_MARKER_DETECTOR_CREATE_INFO_ML = 1000138001,
+ XR_TYPE_MARKER_DETECTOR_ARUCO_INFO_ML = 1000138002,
+ XR_TYPE_MARKER_DETECTOR_SIZE_INFO_ML = 1000138003,
+ XR_TYPE_MARKER_DETECTOR_APRIL_TAG_INFO_ML = 1000138004,
+ XR_TYPE_MARKER_DETECTOR_CUSTOM_PROFILE_INFO_ML = 1000138005,
+ XR_TYPE_MARKER_DETECTOR_SNAPSHOT_INFO_ML = 1000138006,
+ XR_TYPE_MARKER_DETECTOR_STATE_ML = 1000138007,
+ XR_TYPE_MARKER_SPACE_CREATE_INFO_ML = 1000138008,
+ XR_TYPE_LOCALIZATION_MAP_ML = 1000139000,
+ XR_TYPE_EVENT_DATA_LOCALIZATION_CHANGED_ML = 1000139001,
+ XR_TYPE_MAP_LOCALIZATION_REQUEST_INFO_ML = 1000139002,
+ XR_TYPE_LOCALIZATION_MAP_IMPORT_INFO_ML = 1000139003,
+ XR_TYPE_LOCALIZATION_ENABLE_EVENTS_INFO_ML = 1000139004,
XR_TYPE_EVENT_DATA_HEADSET_FIT_CHANGED_ML = 1000472000,
XR_TYPE_EVENT_DATA_EYE_CALIBRATION_CHANGED_ML = 1000472001,
XR_TYPE_USER_CALIBRATION_ENABLE_EVENTS_INFO_ML = 1000472002,
@@ -534,6 +561,8 @@ typedef enum XrStructureType {
XR_TYPE_FOVEATION_APPLY_INFO_HTC = 1000318000,
XR_TYPE_FOVEATION_DYNAMIC_MODE_INFO_HTC = 1000318001,
XR_TYPE_FOVEATION_CUSTOM_MODE_INFO_HTC = 1000318002,
+ XR_TYPE_SYSTEM_ANCHOR_PROPERTIES_HTC = 1000319000,
+ XR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_HTC = 1000319001,
XR_TYPE_ACTIVE_ACTION_SET_PRIORITIES_EXT = 1000373000,
XR_TYPE_SYSTEM_FORCE_FEEDBACK_CURL_PROPERTIES_MNDX = 1000375000,
XR_TYPE_FORCE_FEEDBACK_CURL_APPLY_LOCATIONS_MNDX = 1000375001,
@@ -580,6 +609,7 @@ typedef enum XrReferenceSpaceType {
XR_REFERENCE_SPACE_TYPE_STAGE = 3,
XR_REFERENCE_SPACE_TYPE_UNBOUNDED_MSFT = 1000038000,
XR_REFERENCE_SPACE_TYPE_COMBINED_EYE_VARJO = 1000121000,
+ XR_REFERENCE_SPACE_TYPE_LOCALIZATION_MAP_ML = 1000139000,
XR_REFERENCE_SPACE_TYPE_LOCAL_FLOOR_EXT = 1000426000,
XR_REFERENCE_SPACE_TYPE_MAX_ENUM = 0x7FFFFFFF
} XrReferenceSpaceType;
@@ -634,6 +664,8 @@ typedef enum XrObjectType {
XR_OBJECT_TYPE_PASSTHROUGH_FB = 1000118000,
XR_OBJECT_TYPE_PASSTHROUGH_LAYER_FB = 1000118002,
XR_OBJECT_TYPE_GEOMETRY_INSTANCE_FB = 1000118004,
+ XR_OBJECT_TYPE_MARKER_DETECTOR_ML = 1000138000,
+ XR_OBJECT_TYPE_EXPORTED_LOCALIZATION_MAP_ML = 1000139000,
XR_OBJECT_TYPE_SPATIAL_ANCHOR_STORE_CONNECTION_MSFT = 1000142000,
XR_OBJECT_TYPE_FACE_TRACKER_FB = 1000201000,
XR_OBJECT_TYPE_EYE_TRACKER_FB = 1000202000,
@@ -1677,7 +1709,7 @@ typedef struct XrCompositionLayerColorScaleBiasKHR {
#define XR_KHR_loader_init 1
-#define XR_KHR_loader_init_SPEC_VERSION 1
+#define XR_KHR_loader_init_SPEC_VERSION 2
#define XR_KHR_LOADER_INIT_EXTENSION_NAME "XR_KHR_loader_init"
typedef struct XR_MAY_ALIAS XrLoaderInitInfoBaseHeaderKHR {
XrStructureType type;
@@ -4342,6 +4374,360 @@ typedef struct XrGlobalDimmerFrameEndInfoML {
+#define XR_ML_marker_understanding 1
+XR_DEFINE_ATOM(XrMarkerML)
+XR_DEFINE_HANDLE(XrMarkerDetectorML)
+#define XR_ML_marker_understanding_SPEC_VERSION 1
+#define XR_ML_MARKER_UNDERSTANDING_EXTENSION_NAME "XR_ML_marker_understanding"
+
+typedef enum XrMarkerDetectorProfileML {
+ XR_MARKER_DETECTOR_PROFILE_DEFAULT_ML = 0,
+ XR_MARKER_DETECTOR_PROFILE_SPEED_ML = 1,
+ XR_MARKER_DETECTOR_PROFILE_ACCURACY_ML = 2,
+ XR_MARKER_DETECTOR_PROFILE_SMALL_TARGETS_ML = 3,
+ XR_MARKER_DETECTOR_PROFILE_LARGE_FOV_ML = 4,
+ XR_MARKER_DETECTOR_PROFILE_CUSTOM_ML = 5,
+ XR_MARKER_DETECTOR_PROFILE_MAX_ENUM_ML = 0x7FFFFFFF
+} XrMarkerDetectorProfileML;
+
+typedef enum XrMarkerTypeML {
+ XR_MARKER_TYPE_ARUCO_ML = 0,
+ XR_MARKER_TYPE_APRIL_TAG_ML = 1,
+ XR_MARKER_TYPE_QR_ML = 2,
+ XR_MARKER_TYPE_EAN_13_ML = 3,
+ XR_MARKER_TYPE_UPC_A_ML = 4,
+ XR_MARKER_TYPE_CODE_128_ML = 5,
+ XR_MARKER_TYPE_MAX_ENUM_ML = 0x7FFFFFFF
+} XrMarkerTypeML;
+
+typedef enum XrMarkerArucoDictML {
+ XR_MARKER_ARUCO_DICT_4X4_50_ML = 0,
+ XR_MARKER_ARUCO_DICT_4X4_100_ML = 1,
+ XR_MARKER_ARUCO_DICT_4X4_250_ML = 2,
+ XR_MARKER_ARUCO_DICT_4X4_1000_ML = 3,
+ XR_MARKER_ARUCO_DICT_5X5_50_ML = 4,
+ XR_MARKER_ARUCO_DICT_5X5_100_ML = 5,
+ XR_MARKER_ARUCO_DICT_5X5_250_ML = 6,
+ XR_MARKER_ARUCO_DICT_5X5_1000_ML = 7,
+ XR_MARKER_ARUCO_DICT_6X6_50_ML = 8,
+ XR_MARKER_ARUCO_DICT_6X6_100_ML = 9,
+ XR_MARKER_ARUCO_DICT_6X6_250_ML = 10,
+ XR_MARKER_ARUCO_DICT_6X6_1000_ML = 11,
+ XR_MARKER_ARUCO_DICT_7X7_50_ML = 12,
+ XR_MARKER_ARUCO_DICT_7X7_100_ML = 13,
+ XR_MARKER_ARUCO_DICT_7X7_250_ML = 14,
+ XR_MARKER_ARUCO_DICT_7X7_1000_ML = 15,
+ XR_MARKER_ARUCO_DICT_MAX_ENUM_ML = 0x7FFFFFFF
+} XrMarkerArucoDictML;
+
+typedef enum XrMarkerAprilTagDictML {
+ XR_MARKER_APRIL_TAG_DICT_16H5_ML = 0,
+ XR_MARKER_APRIL_TAG_DICT_25H9_ML = 1,
+ XR_MARKER_APRIL_TAG_DICT_36H10_ML = 2,
+ XR_MARKER_APRIL_TAG_DICT_36H11_ML = 3,
+ XR_MARKER_APRIL_TAG_DICT_MAX_ENUM_ML = 0x7FFFFFFF
+} XrMarkerAprilTagDictML;
+
+typedef enum XrMarkerDetectorFpsML {
+ XR_MARKER_DETECTOR_FPS_LOW_ML = 0,
+ XR_MARKER_DETECTOR_FPS_MEDIUM_ML = 1,
+ XR_MARKER_DETECTOR_FPS_HIGH_ML = 2,
+ XR_MARKER_DETECTOR_FPS_MAX_ML = 3,
+ XR_MARKER_DETECTOR_FPS_MAX_ENUM_ML = 0x7FFFFFFF
+} XrMarkerDetectorFpsML;
+
+typedef enum XrMarkerDetectorResolutionML {
+ XR_MARKER_DETECTOR_RESOLUTION_LOW_ML = 0,
+ XR_MARKER_DETECTOR_RESOLUTION_MEDIUM_ML = 1,
+ XR_MARKER_DETECTOR_RESOLUTION_HIGH_ML = 2,
+ XR_MARKER_DETECTOR_RESOLUTION_MAX_ENUM_ML = 0x7FFFFFFF
+} XrMarkerDetectorResolutionML;
+
+typedef enum XrMarkerDetectorCameraML {
+ XR_MARKER_DETECTOR_CAMERA_RGB_CAMERA_ML = 0,
+ XR_MARKER_DETECTOR_CAMERA_WORLD_CAMERAS_ML = 1,
+ XR_MARKER_DETECTOR_CAMERA_MAX_ENUM_ML = 0x7FFFFFFF
+} XrMarkerDetectorCameraML;
+
+typedef enum XrMarkerDetectorCornerRefineMethodML {
+ XR_MARKER_DETECTOR_CORNER_REFINE_METHOD_NONE_ML = 0,
+ XR_MARKER_DETECTOR_CORNER_REFINE_METHOD_SUBPIX_ML = 1,
+ XR_MARKER_DETECTOR_CORNER_REFINE_METHOD_CONTOUR_ML = 2,
+ XR_MARKER_DETECTOR_CORNER_REFINE_METHOD_APRIL_TAG_ML = 3,
+ XR_MARKER_DETECTOR_CORNER_REFINE_METHOD_MAX_ENUM_ML = 0x7FFFFFFF
+} XrMarkerDetectorCornerRefineMethodML;
+
+typedef enum XrMarkerDetectorFullAnalysisIntervalML {
+ XR_MARKER_DETECTOR_FULL_ANALYSIS_INTERVAL_MAX_ML = 0,
+ XR_MARKER_DETECTOR_FULL_ANALYSIS_INTERVAL_FAST_ML = 1,
+ XR_MARKER_DETECTOR_FULL_ANALYSIS_INTERVAL_MEDIUM_ML = 2,
+ XR_MARKER_DETECTOR_FULL_ANALYSIS_INTERVAL_SLOW_ML = 3,
+ XR_MARKER_DETECTOR_FULL_ANALYSIS_INTERVAL_MAX_ENUM_ML = 0x7FFFFFFF
+} XrMarkerDetectorFullAnalysisIntervalML;
+
+typedef enum XrMarkerDetectorStatusML {
+ XR_MARKER_DETECTOR_STATUS_PENDING_ML = 0,
+ XR_MARKER_DETECTOR_STATUS_READY_ML = 1,
+ XR_MARKER_DETECTOR_STATUS_ERROR_ML = 2,
+ XR_MARKER_DETECTOR_STATUS_MAX_ENUM_ML = 0x7FFFFFFF
+} XrMarkerDetectorStatusML;
+// XrSystemMarkerUnderstandingPropertiesML extends XrSystemProperties
+typedef struct XrSystemMarkerUnderstandingPropertiesML {
+ XrStructureType type;
+ void* XR_MAY_ALIAS next;
+ XrBool32 supportsMarkerUnderstanding;
+} XrSystemMarkerUnderstandingPropertiesML;
+
+typedef struct XrMarkerDetectorCreateInfoML {
+ XrStructureType type;
+ const void* XR_MAY_ALIAS next;
+ XrMarkerDetectorProfileML profile;
+ XrMarkerTypeML markerType;
+} XrMarkerDetectorCreateInfoML;
+
+// XrMarkerDetectorArucoInfoML extends XrMarkerDetectorCreateInfoML
+typedef struct XrMarkerDetectorArucoInfoML {
+ XrStructureType type;
+ const void* XR_MAY_ALIAS next;
+ XrMarkerArucoDictML arucoDict;
+} XrMarkerDetectorArucoInfoML;
+
+// XrMarkerDetectorSizeInfoML extends XrMarkerDetectorCreateInfoML
+typedef struct XrMarkerDetectorSizeInfoML {
+ XrStructureType type;
+ const void* XR_MAY_ALIAS next;
+ float markerLength;
+} XrMarkerDetectorSizeInfoML;
+
+// XrMarkerDetectorAprilTagInfoML extends XrMarkerDetectorCreateInfoML
+typedef struct XrMarkerDetectorAprilTagInfoML {
+ XrStructureType type;
+ const void* XR_MAY_ALIAS next;
+ XrMarkerAprilTagDictML aprilTagDict;
+} XrMarkerDetectorAprilTagInfoML;
+
+// XrMarkerDetectorCustomProfileInfoML extends XrMarkerDetectorCreateInfoML
+typedef struct XrMarkerDetectorCustomProfileInfoML {
+ XrStructureType type;
+ const void* XR_MAY_ALIAS next;
+ XrMarkerDetectorFpsML fpsHint;
+ XrMarkerDetectorResolutionML resolutionHint;
+ XrMarkerDetectorCameraML cameraHint;
+ XrMarkerDetectorCornerRefineMethodML cornerRefineMethod;
+ XrBool32 useEdgeRefinement;
+ XrMarkerDetectorFullAnalysisIntervalML fullAnalysisIntervalHint;
+} XrMarkerDetectorCustomProfileInfoML;
+
+typedef struct XrMarkerDetectorSnapshotInfoML {
+ XrStructureType type;
+ const void* XR_MAY_ALIAS next;
+} XrMarkerDetectorSnapshotInfoML;
+
+typedef struct XrMarkerDetectorStateML {
+ XrStructureType type;
+ void* XR_MAY_ALIAS next;
+ XrMarkerDetectorStatusML state;
+} XrMarkerDetectorStateML;
+
+typedef struct XrMarkerSpaceCreateInfoML {
+ XrStructureType type;
+ const void* XR_MAY_ALIAS next;
+ XrMarkerDetectorML markerDetector;
+ XrMarkerML marker;
+ XrPosef poseInMarkerSpace;
+} XrMarkerSpaceCreateInfoML;
+
+typedef XrResult (XRAPI_PTR *PFN_xrCreateMarkerDetectorML)(XrSession session, const XrMarkerDetectorCreateInfoML* createInfo, XrMarkerDetectorML* markerDetector);
+typedef XrResult (XRAPI_PTR *PFN_xrDestroyMarkerDetectorML)(XrMarkerDetectorML markerDetector);
+typedef XrResult (XRAPI_PTR *PFN_xrSnapshotMarkerDetectorML)(XrMarkerDetectorML markerDetector, XrMarkerDetectorSnapshotInfoML* snapshotInfo);
+typedef XrResult (XRAPI_PTR *PFN_xrGetMarkerDetectorStateML)(XrMarkerDetectorML markerDetector, XrMarkerDetectorStateML* state);
+typedef XrResult (XRAPI_PTR *PFN_xrGetMarkersML)(XrMarkerDetectorML markerDetector, uint32_t markerCapacityInput, uint32_t* markerCountOutput, XrMarkerML* markers);
+typedef XrResult (XRAPI_PTR *PFN_xrGetMarkerReprojectionErrorML)(XrMarkerDetectorML markerDetector, XrMarkerML marker, float* reprojectionErrorMeters);
+typedef XrResult (XRAPI_PTR *PFN_xrGetMarkerLengthML)(XrMarkerDetectorML markerDetector, XrMarkerML marker, float* meters);
+typedef XrResult (XRAPI_PTR *PFN_xrGetMarkerNumberML)(XrMarkerDetectorML markerDetector, XrMarkerML marker, uint64_t* number);
+typedef XrResult (XRAPI_PTR *PFN_xrGetMarkerStringML)(XrMarkerDetectorML markerDetector, XrMarkerML marker, uint32_t bufferCapacityInput, uint32_t* bufferCountOutput, char* buffer);
+typedef XrResult (XRAPI_PTR *PFN_xrCreateMarkerSpaceML)(XrSession session, const XrMarkerSpaceCreateInfoML* createInfo, XrSpace* space);
+
+#ifndef XR_NO_PROTOTYPES
+#ifdef XR_EXTENSION_PROTOTYPES
+XRAPI_ATTR XrResult XRAPI_CALL xrCreateMarkerDetectorML(
+ XrSession session,
+ const XrMarkerDetectorCreateInfoML* createInfo,
+ XrMarkerDetectorML* markerDetector);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrDestroyMarkerDetectorML(
+ XrMarkerDetectorML markerDetector);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrSnapshotMarkerDetectorML(
+ XrMarkerDetectorML markerDetector,
+ XrMarkerDetectorSnapshotInfoML* snapshotInfo);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrGetMarkerDetectorStateML(
+ XrMarkerDetectorML markerDetector,
+ XrMarkerDetectorStateML* state);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrGetMarkersML(
+ XrMarkerDetectorML markerDetector,
+ uint32_t markerCapacityInput,
+ uint32_t* markerCountOutput,
+ XrMarkerML* markers);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrGetMarkerReprojectionErrorML(
+ XrMarkerDetectorML markerDetector,
+ XrMarkerML marker,
+ float* reprojectionErrorMeters);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrGetMarkerLengthML(
+ XrMarkerDetectorML markerDetector,
+ XrMarkerML marker,
+ float* meters);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrGetMarkerNumberML(
+ XrMarkerDetectorML markerDetector,
+ XrMarkerML marker,
+ uint64_t* number);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrGetMarkerStringML(
+ XrMarkerDetectorML markerDetector,
+ XrMarkerML marker,
+ uint32_t bufferCapacityInput,
+ uint32_t* bufferCountOutput,
+ char* buffer);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrCreateMarkerSpaceML(
+ XrSession session,
+ const XrMarkerSpaceCreateInfoML* createInfo,
+ XrSpace* space);
+#endif /* XR_EXTENSION_PROTOTYPES */
+#endif /* !XR_NO_PROTOTYPES */
+
+
+#define XR_ML_localization_map 1
+XR_DEFINE_HANDLE(XrExportedLocalizationMapML)
+#define XR_MAX_LOCALIZATION_MAP_NAME_LENGTH_ML 64
+#define XR_ML_localization_map_SPEC_VERSION 1
+#define XR_ML_LOCALIZATION_MAP_EXTENSION_NAME "XR_ML_localization_map"
+
+typedef enum XrLocalizationMapStateML {
+ XR_LOCALIZATION_MAP_STATE_NOT_LOCALIZED_ML = 0,
+ XR_LOCALIZATION_MAP_STATE_LOCALIZED_ML = 1,
+ XR_LOCALIZATION_MAP_STATE_LOCALIZATION_PENDING_ML = 2,
+ XR_LOCALIZATION_MAP_STATE_LOCALIZATION_SLEEPING_BEFORE_RETRY_ML = 3,
+ XR_LOCALIZATION_MAP_STATE_MAX_ENUM_ML = 0x7FFFFFFF
+} XrLocalizationMapStateML;
+
+typedef enum XrLocalizationMapTypeML {
+ XR_LOCALIZATION_MAP_TYPE_ON_DEVICE_ML = 0,
+ XR_LOCALIZATION_MAP_TYPE_CLOUD_ML = 1,
+ XR_LOCALIZATION_MAP_TYPE_MAX_ENUM_ML = 0x7FFFFFFF
+} XrLocalizationMapTypeML;
+
+typedef enum XrLocalizationMapConfidenceML {
+ XR_LOCALIZATION_MAP_CONFIDENCE_POOR_ML = 0,
+ XR_LOCALIZATION_MAP_CONFIDENCE_FAIR_ML = 1,
+ XR_LOCALIZATION_MAP_CONFIDENCE_GOOD_ML = 2,
+ XR_LOCALIZATION_MAP_CONFIDENCE_EXCELLENT_ML = 3,
+ XR_LOCALIZATION_MAP_CONFIDENCE_MAX_ENUM_ML = 0x7FFFFFFF
+} XrLocalizationMapConfidenceML;
+typedef XrFlags64 XrLocalizationMapErrorFlagsML;
+
+// Flag bits for XrLocalizationMapErrorFlagsML
+static const XrLocalizationMapErrorFlagsML XR_LOCALIZATION_MAP_ERROR_UNKNOWN_BIT_ML = 0x00000001;
+static const XrLocalizationMapErrorFlagsML XR_LOCALIZATION_MAP_ERROR_OUT_OF_MAPPED_AREA_BIT_ML = 0x00000002;
+static const XrLocalizationMapErrorFlagsML XR_LOCALIZATION_MAP_ERROR_LOW_FEATURE_COUNT_BIT_ML = 0x00000004;
+static const XrLocalizationMapErrorFlagsML XR_LOCALIZATION_MAP_ERROR_EXCESSIVE_MOTION_BIT_ML = 0x00000008;
+static const XrLocalizationMapErrorFlagsML XR_LOCALIZATION_MAP_ERROR_LOW_LIGHT_BIT_ML = 0x00000010;
+static const XrLocalizationMapErrorFlagsML XR_LOCALIZATION_MAP_ERROR_HEADPOSE_BIT_ML = 0x00000020;
+
+typedef struct XrLocalizationMapML {
+ XrStructureType type;
+ void* XR_MAY_ALIAS next;
+ char name[XR_MAX_LOCALIZATION_MAP_NAME_LENGTH_ML];
+ XrUuidEXT mapUuid;
+ XrLocalizationMapTypeML mapType;
+} XrLocalizationMapML;
+
+typedef struct XrEventDataLocalizationChangedML {
+ XrStructureType type;
+ const void* XR_MAY_ALIAS next;
+ XrSession session;
+ XrLocalizationMapStateML state;
+ XrLocalizationMapML map;
+ XrLocalizationMapConfidenceML confidence;
+ XrLocalizationMapErrorFlagsML errorFlags;
+} XrEventDataLocalizationChangedML;
+
+typedef struct XrLocalizationMapQueryInfoBaseHeaderML {
+ XrStructureType type;
+ const void* XR_MAY_ALIAS next;
+} XrLocalizationMapQueryInfoBaseHeaderML;
+
+typedef struct XrMapLocalizationRequestInfoML {
+ XrStructureType type;
+ const void* XR_MAY_ALIAS next;
+ XrUuidEXT mapUuid;
+} XrMapLocalizationRequestInfoML;
+
+typedef struct XrLocalizationMapImportInfoML {
+ XrStructureType type;
+ const void* XR_MAY_ALIAS next;
+ uint32_t size;
+ char* data;
+} XrLocalizationMapImportInfoML;
+
+typedef struct XrLocalizationEnableEventsInfoML {
+ XrStructureType type;
+ const void* XR_MAY_ALIAS next;
+ XrBool32 enabled;
+} XrLocalizationEnableEventsInfoML;
+
+typedef XrResult (XRAPI_PTR *PFN_xrEnableLocalizationEventsML)(XrSession session, const XrLocalizationEnableEventsInfoML * info);
+typedef XrResult (XRAPI_PTR *PFN_xrQueryLocalizationMapsML)(XrSession session, const XrLocalizationMapQueryInfoBaseHeaderML* queryInfo, uint32_t mapCapacityInput, uint32_t * mapCountOutput, XrLocalizationMapML* maps);
+typedef XrResult (XRAPI_PTR *PFN_xrRequestMapLocalizationML)(XrSession session, const XrMapLocalizationRequestInfoML* requestInfo);
+typedef XrResult (XRAPI_PTR *PFN_xrImportLocalizationMapML)(XrSession session, const XrLocalizationMapImportInfoML* importInfo, XrUuidEXT* mapUuid);
+typedef XrResult (XRAPI_PTR *PFN_xrCreateExportedLocalizationMapML)(XrSession session, const XrUuidEXT* mapUuid, XrExportedLocalizationMapML* map);
+typedef XrResult (XRAPI_PTR *PFN_xrDestroyExportedLocalizationMapML)(XrExportedLocalizationMapML map);
+typedef XrResult (XRAPI_PTR *PFN_xrGetExportedLocalizationMapDataML)(XrExportedLocalizationMapML map, uint32_t bufferCapacityInput, uint32_t* bufferCountOutput, char* buffer);
+
+#ifndef XR_NO_PROTOTYPES
+#ifdef XR_EXTENSION_PROTOTYPES
+XRAPI_ATTR XrResult XRAPI_CALL xrEnableLocalizationEventsML(
+ XrSession session,
+ const XrLocalizationEnableEventsInfoML * info);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrQueryLocalizationMapsML(
+ XrSession session,
+ const XrLocalizationMapQueryInfoBaseHeaderML* queryInfo,
+ uint32_t mapCapacityInput,
+ uint32_t * mapCountOutput,
+ XrLocalizationMapML* maps);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrRequestMapLocalizationML(
+ XrSession session,
+ const XrMapLocalizationRequestInfoML* requestInfo);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrImportLocalizationMapML(
+ XrSession session,
+ const XrLocalizationMapImportInfoML* importInfo,
+ XrUuidEXT* mapUuid);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrCreateExportedLocalizationMapML(
+ XrSession session,
+ const XrUuidEXT* mapUuid,
+ XrExportedLocalizationMapML* map);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrDestroyExportedLocalizationMapML(
+ XrExportedLocalizationMapML map);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrGetExportedLocalizationMapDataML(
+ XrExportedLocalizationMapML map,
+ uint32_t bufferCapacityInput,
+ uint32_t* bufferCountOutput,
+ char* buffer);
+#endif /* XR_EXTENSION_PROTOTYPES */
+#endif /* !XR_NO_PROTOTYPES */
+
+
#define XR_MSFT_spatial_anchor_persistence 1
XR_DEFINE_HANDLE(XrSpatialAnchorStoreConnectionMSFT)
#define XR_MAX_SPATIAL_ANCHOR_NAME_SIZE_MSFT 256
@@ -5814,6 +6200,11 @@ XRAPI_ATTR XrResult XRAPI_CALL xrUpdatePassthroughColorLutMETA(
#endif /* !XR_NO_PROTOTYPES */
+#define XR_META_touch_controller_plus 1
+#define XR_META_touch_controller_plus_SPEC_VERSION 1
+#define XR_META_TOUCH_CONTROLLER_PLUS_EXTENSION_NAME "XR_META_touch_controller_plus"
+
+
#define XR_EXT_uuid 1
#define XR_EXT_uuid_SPEC_VERSION 1
#define XR_EXT_UUID_EXTENSION_NAME "XR_EXT_uuid"
@@ -5980,6 +6371,46 @@ XRAPI_ATTR XrResult XRAPI_CALL xrApplyFoveationHTC(
#endif /* !XR_NO_PROTOTYPES */
+#define XR_HTC_anchor 1
+#define XR_MAX_SPATIAL_ANCHOR_NAME_SIZE_HTC 256
+#define XR_HTC_anchor_SPEC_VERSION 1
+#define XR_HTC_ANCHOR_EXTENSION_NAME "XR_HTC_anchor"
+// XrSystemAnchorPropertiesHTC extends XrSystemProperties
+typedef struct XrSystemAnchorPropertiesHTC {
+ XrStructureType type;
+ void* XR_MAY_ALIAS next;
+ XrBool32 supportsAnchor;
+} XrSystemAnchorPropertiesHTC;
+
+typedef struct XrSpatialAnchorNameHTC {
+ char name[XR_MAX_SPATIAL_ANCHOR_NAME_SIZE_HTC];
+} XrSpatialAnchorNameHTC;
+
+typedef struct XrSpatialAnchorCreateInfoHTC {
+ XrStructureType type;
+ const void* XR_MAY_ALIAS next;
+ XrSpace space;
+ XrPosef poseInSpace;
+ XrSpatialAnchorNameHTC name;
+} XrSpatialAnchorCreateInfoHTC;
+
+typedef XrResult (XRAPI_PTR *PFN_xrCreateSpatialAnchorHTC)(XrSession session, const XrSpatialAnchorCreateInfoHTC* createInfo, XrSpace* anchor);
+typedef XrResult (XRAPI_PTR *PFN_xrGetSpatialAnchorNameHTC)(XrSpace anchor, XrSpatialAnchorNameHTC* name);
+
+#ifndef XR_NO_PROTOTYPES
+#ifdef XR_EXTENSION_PROTOTYPES
+XRAPI_ATTR XrResult XRAPI_CALL xrCreateSpatialAnchorHTC(
+ XrSession session,
+ const XrSpatialAnchorCreateInfoHTC* createInfo,
+ XrSpace* anchor);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrGetSpatialAnchorNameHTC(
+ XrSpace anchor,
+ XrSpatialAnchorNameHTC* name);
+#endif /* XR_EXTENSION_PROTOTYPES */
+#endif /* !XR_NO_PROTOTYPES */
+
+
#define XR_EXT_active_action_set_priority 1
#define XR_EXT_active_action_set_priority_SPEC_VERSION 1
#define XR_EXT_ACTIVE_ACTION_SET_PRIORITY_EXTENSION_NAME "XR_EXT_active_action_set_priority"
@@ -6274,7 +6705,7 @@ typedef struct XrUserCalibrationEnableEventsInfoML {
XrBool32 enabled;
} XrUserCalibrationEnableEventsInfoML;
-typedef XrResult (XRAPI_PTR *PFN_xrEnableUserCalibrationEventsML)(XrInstance instance, const XrUserCalibrationEnableEventsInfoML* enableInfo);
+typedef XrResult (XRAPI_PTR *PFN_xrEnableUserCalibrationEventsML)(XrInstance instance, const XrUserCalibrationEnableEventsInfoML* enableInfo);
#ifndef XR_NO_PROTOTYPES
#ifdef XR_EXTENSION_PROTOTYPES
diff --git a/thirdparty/openxr/include/openxr/openxr_loader_negotiation.h b/thirdparty/openxr/include/openxr/openxr_loader_negotiation.h
new file mode 100644
index 0000000000..619b226760
--- /dev/null
+++ b/thirdparty/openxr/include/openxr/openxr_loader_negotiation.h
@@ -0,0 +1,140 @@
+#ifndef OPENXR_LOADER_NEGOTIATION_H_
+#define OPENXR_LOADER_NEGOTIATION_H_ 1
+
+/*
+** Copyright 2017-2024, The Khronos Group Inc.
+**
+** SPDX-License-Identifier: Apache-2.0 OR MIT
+*/
+
+/*
+** This header is generated from the Khronos OpenXR XML API Registry.
+**
+*/
+
+#include "openxr.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+#define XR_LOADER_VERSION_1_0 1
+
+#define XR_CURRENT_LOADER_API_LAYER_VERSION 1
+
+
+#define XR_CURRENT_LOADER_RUNTIME_VERSION 1
+
+
+#define XR_LOADER_INFO_STRUCT_VERSION 1
+
+
+#define XR_API_LAYER_INFO_STRUCT_VERSION 1
+
+
+#define XR_RUNTIME_INFO_STRUCT_VERSION 1
+
+
+#define XR_API_LAYER_NEXT_INFO_STRUCT_VERSION 1
+
+
+#define XR_API_LAYER_CREATE_INFO_STRUCT_VERSION 1
+
+
+#define XR_API_LAYER_MAX_SETTINGS_PATH_SIZE 512
+
+
+typedef enum XrLoaderInterfaceStructs {
+ XR_LOADER_INTERFACE_STRUCT_UNINTIALIZED = 0,
+ XR_LOADER_INTERFACE_STRUCT_LOADER_INFO = 1,
+ XR_LOADER_INTERFACE_STRUCT_API_LAYER_REQUEST = 2,
+ XR_LOADER_INTERFACE_STRUCT_RUNTIME_REQUEST = 3,
+ XR_LOADER_INTERFACE_STRUCT_API_LAYER_CREATE_INFO = 4,
+ XR_LOADER_INTERFACE_STRUCT_API_LAYER_NEXT_INFO = 5,
+ XR_LOADER_INTERFACE_STRUCTS_MAX_ENUM = 0x7FFFFFFF
+} XrLoaderInterfaceStructs;
+typedef XrResult (XRAPI_PTR *PFN_xrGetInstanceProcAddr)(XrInstance instance, const char* name, PFN_xrVoidFunction* function);
+
+typedef struct XrApiLayerCreateInfo XrApiLayerCreateInfo;
+typedef XrResult (XRAPI_PTR *PFN_xrCreateApiLayerInstance)(
+ const XrInstanceCreateInfo* info,
+ const XrApiLayerCreateInfo* apiLayerInfo,
+ XrInstance* instance);
+
+typedef struct XrApiLayerNextInfo {
+ XrLoaderInterfaceStructs structType;
+ uint32_t structVersion;
+ size_t structSize;
+ char layerName[XR_MAX_API_LAYER_NAME_SIZE];
+ PFN_xrGetInstanceProcAddr nextGetInstanceProcAddr;
+ PFN_xrCreateApiLayerInstance nextCreateApiLayerInstance;
+ struct XrApiLayerNextInfo* next;
+} XrApiLayerNextInfo;
+
+typedef struct XrApiLayerCreateInfo {
+ XrLoaderInterfaceStructs structType;
+ uint32_t structVersion;
+ size_t structSize;
+ void* XR_MAY_ALIAS loaderInstance;
+ char settings_file_location[XR_API_LAYER_MAX_SETTINGS_PATH_SIZE];
+ XrApiLayerNextInfo* nextInfo;
+} XrApiLayerCreateInfo;
+
+typedef struct XrNegotiateLoaderInfo {
+ XrLoaderInterfaceStructs structType;
+ uint32_t structVersion;
+ size_t structSize;
+ uint32_t minInterfaceVersion;
+ uint32_t maxInterfaceVersion;
+ XrVersion minApiVersion;
+ XrVersion maxApiVersion;
+} XrNegotiateLoaderInfo;
+
+typedef struct XrNegotiateRuntimeRequest {
+ XrLoaderInterfaceStructs structType;
+ uint32_t structVersion;
+ size_t structSize;
+ uint32_t runtimeInterfaceVersion;
+ XrVersion runtimeApiVersion;
+ PFN_xrGetInstanceProcAddr getInstanceProcAddr;
+} XrNegotiateRuntimeRequest;
+
+typedef struct XrNegotiateApiLayerRequest {
+ XrLoaderInterfaceStructs structType;
+ uint32_t structVersion;
+ size_t structSize;
+ uint32_t layerInterfaceVersion;
+ XrVersion layerApiVersion;
+ PFN_xrGetInstanceProcAddr getInstanceProcAddr;
+ PFN_xrCreateApiLayerInstance createApiLayerInstance;
+} XrNegotiateApiLayerRequest;
+
+typedef XrResult (XRAPI_PTR *PFN_xrCreateApiLayerInstance)(const XrInstanceCreateInfo* info, const XrApiLayerCreateInfo* layerInfo, XrInstance* instance);
+typedef XrResult (XRAPI_PTR *PFN_xrNegotiateLoaderRuntimeInterface)(const XrNegotiateLoaderInfo* loaderInfo, XrNegotiateRuntimeRequest* runtimeRequest);
+typedef XrResult (XRAPI_PTR *PFN_xrNegotiateLoaderApiLayerInterface)(const XrNegotiateLoaderInfo* loaderInfo, const char* layerName, XrNegotiateApiLayerRequest* apiLayerRequest);
+
+#ifndef XR_NO_PROTOTYPES
+#ifdef XR_EXTENSION_PROTOTYPES
+XRAPI_ATTR XrResult XRAPI_CALL xrCreateApiLayerInstance(
+ const XrInstanceCreateInfo* info,
+ const XrApiLayerCreateInfo* layerInfo,
+ XrInstance* instance);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrNegotiateLoaderRuntimeInterface(
+ const XrNegotiateLoaderInfo* loaderInfo,
+ XrNegotiateRuntimeRequest* runtimeRequest);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrNegotiateLoaderApiLayerInterface(
+ const XrNegotiateLoaderInfo* loaderInfo,
+ const char* layerName,
+ XrNegotiateApiLayerRequest* apiLayerRequest);
+#endif /* XR_EXTENSION_PROTOTYPES */
+#endif /* !XR_NO_PROTOTYPES */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/thirdparty/openxr/include/openxr/openxr_platform.h b/thirdparty/openxr/include/openxr/openxr_platform.h
index e4ddfcbb7d..1f47428676 100644
--- a/thirdparty/openxr/include/openxr/openxr_platform.h
+++ b/thirdparty/openxr/include/openxr/openxr_platform.h
@@ -2,7 +2,7 @@
#define OPENXR_PLATFORM_H_ 1
/*
-** Copyright 2017-2023 The Khronos Group Inc.
+** Copyright 2017-2024, The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0 OR MIT
*/
@@ -22,7 +22,7 @@ extern "C" {
#ifdef XR_USE_PLATFORM_ANDROID
#define XR_KHR_android_thread_settings 1
-#define XR_KHR_android_thread_settings_SPEC_VERSION 5
+#define XR_KHR_android_thread_settings_SPEC_VERSION 6
#define XR_KHR_ANDROID_THREAD_SETTINGS_EXTENSION_NAME "XR_KHR_android_thread_settings"
typedef enum XrAndroidThreadTypeKHR {
@@ -489,7 +489,7 @@ XRAPI_ATTR XrResult XRAPI_CALL xrGetVulkanGraphicsRequirements2KHR(
#ifdef XR_USE_PLATFORM_EGL
#define XR_MNDX_egl_enable 1
-#define XR_MNDX_egl_enable_SPEC_VERSION 1
+#define XR_MNDX_egl_enable_SPEC_VERSION 2
#define XR_MNDX_EGL_ENABLE_EXTENSION_NAME "XR_MNDX_egl_enable"
typedef PFN_xrVoidFunction (*PFN_xrEglGetProcAddressMNDX)(const char *name);
// XrGraphicsBindingEGLMNDX extends XrSessionCreateInfo
diff --git a/thirdparty/openxr/include/openxr/openxr_platform_defines.h b/thirdparty/openxr/include/openxr/openxr_platform_defines.h
index 820b7b3e1e..cd07c91360 100644
--- a/thirdparty/openxr/include/openxr/openxr_platform_defines.h
+++ b/thirdparty/openxr/include/openxr/openxr_platform_defines.h
@@ -1,5 +1,5 @@
/*
-** Copyright (c) 2017-2023, The Khronos Group Inc.
+** Copyright (c) 2017-2024, The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0 OR MIT
*/
diff --git a/thirdparty/openxr/include/openxr/openxr_reflection.h b/thirdparty/openxr/include/openxr/openxr_reflection.h
index 8f49323417..f6d66363bf 100644
--- a/thirdparty/openxr/include/openxr/openxr_reflection.h
+++ b/thirdparty/openxr/include/openxr/openxr_reflection.h
@@ -2,7 +2,7 @@
#define OPENXR_REFLECTION_H_ 1
/*
-** Copyright (c) 2017-2023, The Khronos Group Inc.
+** Copyright (c) 2017-2024, The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0 OR MIT
*/
@@ -114,6 +114,18 @@ XR_ENUM_STR(XrResult);
_(XR_RENDER_MODEL_UNAVAILABLE_FB, 1000119020) \
_(XR_ERROR_MARKER_NOT_TRACKED_VARJO, -1000124000) \
_(XR_ERROR_MARKER_ID_INVALID_VARJO, -1000124001) \
+ _(XR_ERROR_MARKER_DETECTOR_PERMISSION_DENIED_ML, -1000138000) \
+ _(XR_ERROR_MARKER_DETECTOR_LOCATE_FAILED_ML, -1000138001) \
+ _(XR_ERROR_MARKER_DETECTOR_INVALID_DATA_QUERY_ML, -1000138002) \
+ _(XR_ERROR_MARKER_DETECTOR_INVALID_CREATE_INFO_ML, -1000138003) \
+ _(XR_ERROR_MARKER_INVALID_ML, -1000138004) \
+ _(XR_ERROR_LOCALIZATION_MAP_INCOMPATIBLE_ML, -1000139000) \
+ _(XR_ERROR_LOCALIZATION_MAP_UNAVAILABLE_ML, -1000139001) \
+ _(XR_ERROR_LOCALIZATION_MAP_FAIL_ML, -1000139002) \
+ _(XR_ERROR_LOCALIZATION_MAP_IMPORT_EXPORT_PERMISSION_DENIED_ML, -1000139003) \
+ _(XR_ERROR_LOCALIZATION_MAP_PERMISSION_DENIED_ML, -1000139004) \
+ _(XR_ERROR_LOCALIZATION_MAP_ALREADY_EXISTS_ML, -1000139005) \
+ _(XR_ERROR_LOCALIZATION_MAP_CANNOT_EXPORT_CLOUD_MAP_ML, -1000139006) \
_(XR_ERROR_SPATIAL_ANCHOR_NAME_NOT_FOUND_MSFT, -1000142001) \
_(XR_ERROR_SPATIAL_ANCHOR_NAME_INVALID_MSFT, -1000142002) \
_(XR_SCENE_MARKER_DATA_NOT_STRING_MSFT, 1000147000) \
@@ -124,6 +136,7 @@ XR_ENUM_STR(XrResult);
_(XR_ERROR_SPACE_CLOUD_STORAGE_DISABLED_FB, -1000169004) \
_(XR_ERROR_PASSTHROUGH_COLOR_LUT_BUFFER_SIZE_MISMATCH_META, -1000266000) \
_(XR_ERROR_HINT_ALREADY_SET_QCOM, -1000306000) \
+ _(XR_ERROR_NOT_AN_ANCHOR_HTC, -1000319000) \
_(XR_ERROR_SPACE_NOT_LOCATABLE_EXT, -1000429000) \
_(XR_ERROR_PLANE_DETECTION_PERMISSION_DENIED_EXT, -1000429001) \
_(XR_RESULT_MAX_ENUM, 0x7FFFFFFF)
@@ -340,6 +353,20 @@ XR_ENUM_STR(XrResult);
_(XR_TYPE_FRAME_END_INFO_ML, 1000135000) \
_(XR_TYPE_GLOBAL_DIMMER_FRAME_END_INFO_ML, 1000136000) \
_(XR_TYPE_COORDINATE_SPACE_CREATE_INFO_ML, 1000137000) \
+ _(XR_TYPE_SYSTEM_MARKER_UNDERSTANDING_PROPERTIES_ML, 1000138000) \
+ _(XR_TYPE_MARKER_DETECTOR_CREATE_INFO_ML, 1000138001) \
+ _(XR_TYPE_MARKER_DETECTOR_ARUCO_INFO_ML, 1000138002) \
+ _(XR_TYPE_MARKER_DETECTOR_SIZE_INFO_ML, 1000138003) \
+ _(XR_TYPE_MARKER_DETECTOR_APRIL_TAG_INFO_ML, 1000138004) \
+ _(XR_TYPE_MARKER_DETECTOR_CUSTOM_PROFILE_INFO_ML, 1000138005) \
+ _(XR_TYPE_MARKER_DETECTOR_SNAPSHOT_INFO_ML, 1000138006) \
+ _(XR_TYPE_MARKER_DETECTOR_STATE_ML, 1000138007) \
+ _(XR_TYPE_MARKER_SPACE_CREATE_INFO_ML, 1000138008) \
+ _(XR_TYPE_LOCALIZATION_MAP_ML, 1000139000) \
+ _(XR_TYPE_EVENT_DATA_LOCALIZATION_CHANGED_ML, 1000139001) \
+ _(XR_TYPE_MAP_LOCALIZATION_REQUEST_INFO_ML, 1000139002) \
+ _(XR_TYPE_LOCALIZATION_MAP_IMPORT_INFO_ML, 1000139003) \
+ _(XR_TYPE_LOCALIZATION_ENABLE_EVENTS_INFO_ML, 1000139004) \
_(XR_TYPE_EVENT_DATA_HEADSET_FIT_CHANGED_ML, 1000472000) \
_(XR_TYPE_EVENT_DATA_EYE_CALIBRATION_CHANGED_ML, 1000472001) \
_(XR_TYPE_USER_CALIBRATION_ENABLE_EVENTS_INFO_ML, 1000472002) \
@@ -429,6 +456,8 @@ XR_ENUM_STR(XrResult);
_(XR_TYPE_FOVEATION_APPLY_INFO_HTC, 1000318000) \
_(XR_TYPE_FOVEATION_DYNAMIC_MODE_INFO_HTC, 1000318001) \
_(XR_TYPE_FOVEATION_CUSTOM_MODE_INFO_HTC, 1000318002) \
+ _(XR_TYPE_SYSTEM_ANCHOR_PROPERTIES_HTC, 1000319000) \
+ _(XR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_HTC, 1000319001) \
_(XR_TYPE_ACTIVE_ACTION_SET_PRIORITIES_EXT, 1000373000) \
_(XR_TYPE_SYSTEM_FORCE_FEEDBACK_CURL_PROPERTIES_MNDX, 1000375000) \
_(XR_TYPE_FORCE_FEEDBACK_CURL_APPLY_LOCATIONS_MNDX, 1000375001) \
@@ -467,6 +496,7 @@ XR_ENUM_STR(XrResult);
_(XR_REFERENCE_SPACE_TYPE_STAGE, 3) \
_(XR_REFERENCE_SPACE_TYPE_UNBOUNDED_MSFT, 1000038000) \
_(XR_REFERENCE_SPACE_TYPE_COMBINED_EYE_VARJO, 1000121000) \
+ _(XR_REFERENCE_SPACE_TYPE_LOCALIZATION_MAP_ML, 1000139000) \
_(XR_REFERENCE_SPACE_TYPE_LOCAL_FLOOR_EXT, 1000426000) \
_(XR_REFERENCE_SPACE_TYPE_MAX_ENUM, 0x7FFFFFFF)
@@ -517,6 +547,8 @@ XR_ENUM_STR(XrResult);
_(XR_OBJECT_TYPE_PASSTHROUGH_FB, 1000118000) \
_(XR_OBJECT_TYPE_PASSTHROUGH_LAYER_FB, 1000118002) \
_(XR_OBJECT_TYPE_GEOMETRY_INSTANCE_FB, 1000118004) \
+ _(XR_OBJECT_TYPE_MARKER_DETECTOR_ML, 1000138000) \
+ _(XR_OBJECT_TYPE_EXPORTED_LOCALIZATION_MAP_ML, 1000139000) \
_(XR_OBJECT_TYPE_SPATIAL_ANCHOR_STORE_CONNECTION_MSFT, 1000142000) \
_(XR_OBJECT_TYPE_FACE_TRACKER_FB, 1000201000) \
_(XR_OBJECT_TYPE_EYE_TRACKER_FB, 1000202000) \
@@ -527,6 +559,15 @@ XR_ENUM_STR(XrResult);
_(XR_OBJECT_TYPE_PLANE_DETECTOR_EXT, 1000429000) \
_(XR_OBJECT_TYPE_MAX_ENUM, 0x7FFFFFFF)
+#define XR_LIST_ENUM_XrLoaderInterfaceStructs(_) \
+ _(XR_LOADER_INTERFACE_STRUCT_UNINTIALIZED, 0) \
+ _(XR_LOADER_INTERFACE_STRUCT_LOADER_INFO, 1) \
+ _(XR_LOADER_INTERFACE_STRUCT_API_LAYER_REQUEST, 2) \
+ _(XR_LOADER_INTERFACE_STRUCT_RUNTIME_REQUEST, 3) \
+ _(XR_LOADER_INTERFACE_STRUCT_API_LAYER_CREATE_INFO, 4) \
+ _(XR_LOADER_INTERFACE_STRUCT_API_LAYER_NEXT_INFO, 5) \
+ _(XR_LOADER_INTERFACE_STRUCTS_MAX_ENUM, 0x7FFFFFFF)
+
#define XR_LIST_ENUM_XrAndroidThreadTypeKHR(_) \
_(XR_ANDROID_THREAD_TYPE_APPLICATION_MAIN_KHR, 1) \
_(XR_ANDROID_THREAD_TYPE_APPLICATION_WORKER_KHR, 2) \
@@ -877,6 +918,107 @@ XR_ENUM_STR(XrResult);
_(XR_PASSTHROUGH_LAYER_PURPOSE_TRACKED_KEYBOARD_MASKED_HANDS_FB, 1000203002) \
_(XR_PASSTHROUGH_LAYER_PURPOSE_MAX_ENUM_FB, 0x7FFFFFFF)
+#define XR_LIST_ENUM_XrMarkerDetectorProfileML(_) \
+ _(XR_MARKER_DETECTOR_PROFILE_DEFAULT_ML, 0) \
+ _(XR_MARKER_DETECTOR_PROFILE_SPEED_ML, 1) \
+ _(XR_MARKER_DETECTOR_PROFILE_ACCURACY_ML, 2) \
+ _(XR_MARKER_DETECTOR_PROFILE_SMALL_TARGETS_ML, 3) \
+ _(XR_MARKER_DETECTOR_PROFILE_LARGE_FOV_ML, 4) \
+ _(XR_MARKER_DETECTOR_PROFILE_CUSTOM_ML, 5) \
+ _(XR_MARKER_DETECTOR_PROFILE_MAX_ENUM_ML, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrMarkerTypeML(_) \
+ _(XR_MARKER_TYPE_ARUCO_ML, 0) \
+ _(XR_MARKER_TYPE_APRIL_TAG_ML, 1) \
+ _(XR_MARKER_TYPE_QR_ML, 2) \
+ _(XR_MARKER_TYPE_EAN_13_ML, 3) \
+ _(XR_MARKER_TYPE_UPC_A_ML, 4) \
+ _(XR_MARKER_TYPE_CODE_128_ML, 5) \
+ _(XR_MARKER_TYPE_MAX_ENUM_ML, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrMarkerArucoDictML(_) \
+ _(XR_MARKER_ARUCO_DICT_4X4_50_ML, 0) \
+ _(XR_MARKER_ARUCO_DICT_4X4_100_ML, 1) \
+ _(XR_MARKER_ARUCO_DICT_4X4_250_ML, 2) \
+ _(XR_MARKER_ARUCO_DICT_4X4_1000_ML, 3) \
+ _(XR_MARKER_ARUCO_DICT_5X5_50_ML, 4) \
+ _(XR_MARKER_ARUCO_DICT_5X5_100_ML, 5) \
+ _(XR_MARKER_ARUCO_DICT_5X5_250_ML, 6) \
+ _(XR_MARKER_ARUCO_DICT_5X5_1000_ML, 7) \
+ _(XR_MARKER_ARUCO_DICT_6X6_50_ML, 8) \
+ _(XR_MARKER_ARUCO_DICT_6X6_100_ML, 9) \
+ _(XR_MARKER_ARUCO_DICT_6X6_250_ML, 10) \
+ _(XR_MARKER_ARUCO_DICT_6X6_1000_ML, 11) \
+ _(XR_MARKER_ARUCO_DICT_7X7_50_ML, 12) \
+ _(XR_MARKER_ARUCO_DICT_7X7_100_ML, 13) \
+ _(XR_MARKER_ARUCO_DICT_7X7_250_ML, 14) \
+ _(XR_MARKER_ARUCO_DICT_7X7_1000_ML, 15) \
+ _(XR_MARKER_ARUCO_DICT_MAX_ENUM_ML, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrMarkerAprilTagDictML(_) \
+ _(XR_MARKER_APRIL_TAG_DICT_16H5_ML, 0) \
+ _(XR_MARKER_APRIL_TAG_DICT_25H9_ML, 1) \
+ _(XR_MARKER_APRIL_TAG_DICT_36H10_ML, 2) \
+ _(XR_MARKER_APRIL_TAG_DICT_36H11_ML, 3) \
+ _(XR_MARKER_APRIL_TAG_DICT_MAX_ENUM_ML, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrMarkerDetectorFpsML(_) \
+ _(XR_MARKER_DETECTOR_FPS_LOW_ML, 0) \
+ _(XR_MARKER_DETECTOR_FPS_MEDIUM_ML, 1) \
+ _(XR_MARKER_DETECTOR_FPS_HIGH_ML, 2) \
+ _(XR_MARKER_DETECTOR_FPS_MAX_ML, 3) \
+ _(XR_MARKER_DETECTOR_FPS_MAX_ENUM_ML, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrMarkerDetectorResolutionML(_) \
+ _(XR_MARKER_DETECTOR_RESOLUTION_LOW_ML, 0) \
+ _(XR_MARKER_DETECTOR_RESOLUTION_MEDIUM_ML, 1) \
+ _(XR_MARKER_DETECTOR_RESOLUTION_HIGH_ML, 2) \
+ _(XR_MARKER_DETECTOR_RESOLUTION_MAX_ENUM_ML, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrMarkerDetectorCameraML(_) \
+ _(XR_MARKER_DETECTOR_CAMERA_RGB_CAMERA_ML, 0) \
+ _(XR_MARKER_DETECTOR_CAMERA_WORLD_CAMERAS_ML, 1) \
+ _(XR_MARKER_DETECTOR_CAMERA_MAX_ENUM_ML, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrMarkerDetectorCornerRefineMethodML(_) \
+ _(XR_MARKER_DETECTOR_CORNER_REFINE_METHOD_NONE_ML, 0) \
+ _(XR_MARKER_DETECTOR_CORNER_REFINE_METHOD_SUBPIX_ML, 1) \
+ _(XR_MARKER_DETECTOR_CORNER_REFINE_METHOD_CONTOUR_ML, 2) \
+ _(XR_MARKER_DETECTOR_CORNER_REFINE_METHOD_APRIL_TAG_ML, 3) \
+ _(XR_MARKER_DETECTOR_CORNER_REFINE_METHOD_MAX_ENUM_ML, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrMarkerDetectorFullAnalysisIntervalML(_) \
+ _(XR_MARKER_DETECTOR_FULL_ANALYSIS_INTERVAL_MAX_ML, 0) \
+ _(XR_MARKER_DETECTOR_FULL_ANALYSIS_INTERVAL_FAST_ML, 1) \
+ _(XR_MARKER_DETECTOR_FULL_ANALYSIS_INTERVAL_MEDIUM_ML, 2) \
+ _(XR_MARKER_DETECTOR_FULL_ANALYSIS_INTERVAL_SLOW_ML, 3) \
+ _(XR_MARKER_DETECTOR_FULL_ANALYSIS_INTERVAL_MAX_ENUM_ML, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrMarkerDetectorStatusML(_) \
+ _(XR_MARKER_DETECTOR_STATUS_PENDING_ML, 0) \
+ _(XR_MARKER_DETECTOR_STATUS_READY_ML, 1) \
+ _(XR_MARKER_DETECTOR_STATUS_ERROR_ML, 2) \
+ _(XR_MARKER_DETECTOR_STATUS_MAX_ENUM_ML, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrLocalizationMapStateML(_) \
+ _(XR_LOCALIZATION_MAP_STATE_NOT_LOCALIZED_ML, 0) \
+ _(XR_LOCALIZATION_MAP_STATE_LOCALIZED_ML, 1) \
+ _(XR_LOCALIZATION_MAP_STATE_LOCALIZATION_PENDING_ML, 2) \
+ _(XR_LOCALIZATION_MAP_STATE_LOCALIZATION_SLEEPING_BEFORE_RETRY_ML, 3) \
+ _(XR_LOCALIZATION_MAP_STATE_MAX_ENUM_ML, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrLocalizationMapTypeML(_) \
+ _(XR_LOCALIZATION_MAP_TYPE_ON_DEVICE_ML, 0) \
+ _(XR_LOCALIZATION_MAP_TYPE_CLOUD_ML, 1) \
+ _(XR_LOCALIZATION_MAP_TYPE_MAX_ENUM_ML, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrLocalizationMapConfidenceML(_) \
+ _(XR_LOCALIZATION_MAP_CONFIDENCE_POOR_ML, 0) \
+ _(XR_LOCALIZATION_MAP_CONFIDENCE_FAIR_ML, 1) \
+ _(XR_LOCALIZATION_MAP_CONFIDENCE_GOOD_ML, 2) \
+ _(XR_LOCALIZATION_MAP_CONFIDENCE_EXCELLENT_ML, 3) \
+ _(XR_LOCALIZATION_MAP_CONFIDENCE_MAX_ENUM_ML, 0x7FFFFFFF)
+
#define XR_LIST_ENUM_XrSceneMarkerTypeMSFT(_) \
_(XR_SCENE_MARKER_TYPE_QR_CODE_MSFT, 1) \
_(XR_SCENE_MARKER_TYPE_MAX_ENUM_MSFT, 0x7FFFFFFF)
@@ -1281,6 +1423,14 @@ XR_ENUM_STR(XrResult);
#define XR_LIST_BITS_XrGlobalDimmerFrameEndInfoFlagsML(_) \
_(XR_GLOBAL_DIMMER_FRAME_END_INFO_ENABLED_BIT_ML, 0x00000001) \
+#define XR_LIST_BITS_XrLocalizationMapErrorFlagsML(_) \
+ _(XR_LOCALIZATION_MAP_ERROR_UNKNOWN_BIT_ML, 0x00000001) \
+ _(XR_LOCALIZATION_MAP_ERROR_OUT_OF_MAPPED_AREA_BIT_ML, 0x00000002) \
+ _(XR_LOCALIZATION_MAP_ERROR_LOW_FEATURE_COUNT_BIT_ML, 0x00000004) \
+ _(XR_LOCALIZATION_MAP_ERROR_EXCESSIVE_MOTION_BIT_ML, 0x00000008) \
+ _(XR_LOCALIZATION_MAP_ERROR_LOW_LIGHT_BIT_ML, 0x00000010) \
+ _(XR_LOCALIZATION_MAP_ERROR_HEADPOSE_BIT_ML, 0x00000020) \
+
#define XR_LIST_BITS_XrCompositionLayerSpaceWarpInfoFlagsFB(_) \
_(XR_COMPOSITION_LAYER_SPACE_WARP_INFO_FRAME_SKIP_BIT_FB, 0x00000001) \
@@ -1851,6 +2001,54 @@ XR_ENUM_STR(XrResult);
_(b) \
_(a) \
+/// Calls your macro with the name of each member of XrApiLayerNextInfo, in order.
+#define XR_LIST_STRUCT_XrApiLayerNextInfo(_) \
+ _(structType) \
+ _(structVersion) \
+ _(structSize) \
+ _(layerName) \
+ _(nextGetInstanceProcAddr) \
+ _(nextCreateApiLayerInstance) \
+ _(next) \
+
+/// Calls your macro with the name of each member of XrApiLayerCreateInfo, in order.
+#define XR_LIST_STRUCT_XrApiLayerCreateInfo(_) \
+ _(structType) \
+ _(structVersion) \
+ _(structSize) \
+ _(loaderInstance) \
+ _(settings_file_location) \
+ _(nextInfo) \
+
+/// Calls your macro with the name of each member of XrNegotiateLoaderInfo, in order.
+#define XR_LIST_STRUCT_XrNegotiateLoaderInfo(_) \
+ _(structType) \
+ _(structVersion) \
+ _(structSize) \
+ _(minInterfaceVersion) \
+ _(maxInterfaceVersion) \
+ _(minApiVersion) \
+ _(maxApiVersion) \
+
+/// Calls your macro with the name of each member of XrNegotiateRuntimeRequest, in order.
+#define XR_LIST_STRUCT_XrNegotiateRuntimeRequest(_) \
+ _(structType) \
+ _(structVersion) \
+ _(structSize) \
+ _(runtimeInterfaceVersion) \
+ _(runtimeApiVersion) \
+ _(getInstanceProcAddr) \
+
+/// Calls your macro with the name of each member of XrNegotiateApiLayerRequest, in order.
+#define XR_LIST_STRUCT_XrNegotiateApiLayerRequest(_) \
+ _(structType) \
+ _(structVersion) \
+ _(structSize) \
+ _(layerInterfaceVersion) \
+ _(layerApiVersion) \
+ _(getInstanceProcAddr) \
+ _(createApiLayerInstance) \
+
/// Calls your macro with the name of each member of XrCompositionLayerCubeKHR, in order.
#define XR_LIST_STRUCT_XrCompositionLayerCubeKHR(_) \
_(type) \
@@ -3212,6 +3410,109 @@ XR_ENUM_STR(XrResult);
_(cfuid) \
_(poseInCoordinateSpace) \
+/// Calls your macro with the name of each member of XrSystemMarkerUnderstandingPropertiesML, in order.
+#define XR_LIST_STRUCT_XrSystemMarkerUnderstandingPropertiesML(_) \
+ _(type) \
+ _(next) \
+ _(supportsMarkerUnderstanding) \
+
+/// Calls your macro with the name of each member of XrMarkerDetectorCreateInfoML, in order.
+#define XR_LIST_STRUCT_XrMarkerDetectorCreateInfoML(_) \
+ _(type) \
+ _(next) \
+ _(profile) \
+ _(markerType) \
+
+/// Calls your macro with the name of each member of XrMarkerDetectorArucoInfoML, in order.
+#define XR_LIST_STRUCT_XrMarkerDetectorArucoInfoML(_) \
+ _(type) \
+ _(next) \
+ _(arucoDict) \
+
+/// Calls your macro with the name of each member of XrMarkerDetectorSizeInfoML, in order.
+#define XR_LIST_STRUCT_XrMarkerDetectorSizeInfoML(_) \
+ _(type) \
+ _(next) \
+ _(markerLength) \
+
+/// Calls your macro with the name of each member of XrMarkerDetectorAprilTagInfoML, in order.
+#define XR_LIST_STRUCT_XrMarkerDetectorAprilTagInfoML(_) \
+ _(type) \
+ _(next) \
+ _(aprilTagDict) \
+
+/// Calls your macro with the name of each member of XrMarkerDetectorCustomProfileInfoML, in order.
+#define XR_LIST_STRUCT_XrMarkerDetectorCustomProfileInfoML(_) \
+ _(type) \
+ _(next) \
+ _(fpsHint) \
+ _(resolutionHint) \
+ _(cameraHint) \
+ _(cornerRefineMethod) \
+ _(useEdgeRefinement) \
+ _(fullAnalysisIntervalHint) \
+
+/// Calls your macro with the name of each member of XrMarkerDetectorSnapshotInfoML, in order.
+#define XR_LIST_STRUCT_XrMarkerDetectorSnapshotInfoML(_) \
+ _(type) \
+ _(next) \
+
+/// Calls your macro with the name of each member of XrMarkerDetectorStateML, in order.
+#define XR_LIST_STRUCT_XrMarkerDetectorStateML(_) \
+ _(type) \
+ _(next) \
+ _(state) \
+
+/// Calls your macro with the name of each member of XrMarkerSpaceCreateInfoML, in order.
+#define XR_LIST_STRUCT_XrMarkerSpaceCreateInfoML(_) \
+ _(type) \
+ _(next) \
+ _(markerDetector) \
+ _(marker) \
+ _(poseInMarkerSpace) \
+
+/// Calls your macro with the name of each member of XrLocalizationMapML, in order.
+#define XR_LIST_STRUCT_XrLocalizationMapML(_) \
+ _(type) \
+ _(next) \
+ _(name) \
+ _(mapUuid) \
+ _(mapType) \
+
+/// Calls your macro with the name of each member of XrEventDataLocalizationChangedML, in order.
+#define XR_LIST_STRUCT_XrEventDataLocalizationChangedML(_) \
+ _(type) \
+ _(next) \
+ _(session) \
+ _(state) \
+ _(map) \
+ _(confidence) \
+ _(errorFlags) \
+
+/// Calls your macro with the name of each member of XrLocalizationMapQueryInfoBaseHeaderML, in order.
+#define XR_LIST_STRUCT_XrLocalizationMapQueryInfoBaseHeaderML(_) \
+ _(type) \
+ _(next) \
+
+/// Calls your macro with the name of each member of XrMapLocalizationRequestInfoML, in order.
+#define XR_LIST_STRUCT_XrMapLocalizationRequestInfoML(_) \
+ _(type) \
+ _(next) \
+ _(mapUuid) \
+
+/// Calls your macro with the name of each member of XrLocalizationMapImportInfoML, in order.
+#define XR_LIST_STRUCT_XrLocalizationMapImportInfoML(_) \
+ _(type) \
+ _(next) \
+ _(size) \
+ _(data) \
+
+/// Calls your macro with the name of each member of XrLocalizationEnableEventsInfoML, in order.
+#define XR_LIST_STRUCT_XrLocalizationEnableEventsInfoML(_) \
+ _(type) \
+ _(next) \
+ _(enabled) \
+
/// Calls your macro with the name of each member of XrSpatialAnchorPersistenceNameMSFT, in order.
#define XR_LIST_STRUCT_XrSpatialAnchorPersistenceNameMSFT(_) \
_(name) \
@@ -3941,6 +4242,24 @@ XR_ENUM_STR(XrResult);
_(configCount) \
_(configs) \
+/// Calls your macro with the name of each member of XrSystemAnchorPropertiesHTC, in order.
+#define XR_LIST_STRUCT_XrSystemAnchorPropertiesHTC(_) \
+ _(type) \
+ _(next) \
+ _(supportsAnchor) \
+
+/// Calls your macro with the name of each member of XrSpatialAnchorNameHTC, in order.
+#define XR_LIST_STRUCT_XrSpatialAnchorNameHTC(_) \
+ _(name) \
+
+/// Calls your macro with the name of each member of XrSpatialAnchorCreateInfoHTC, in order.
+#define XR_LIST_STRUCT_XrSpatialAnchorCreateInfoHTC(_) \
+ _(type) \
+ _(next) \
+ _(space) \
+ _(poseInSpace) \
+ _(name) \
+
/// Calls your macro with the name of each member of XrActiveActionSetPriorityEXT, in order.
#define XR_LIST_STRUCT_XrActiveActionSetPriorityEXT(_) \
_(actionSet) \
@@ -4278,6 +4597,20 @@ XR_ENUM_STR(XrResult);
_(XrMarkerSpaceCreateInfoVARJO, XR_TYPE_MARKER_SPACE_CREATE_INFO_VARJO) \
_(XrFrameEndInfoML, XR_TYPE_FRAME_END_INFO_ML) \
_(XrGlobalDimmerFrameEndInfoML, XR_TYPE_GLOBAL_DIMMER_FRAME_END_INFO_ML) \
+ _(XrSystemMarkerUnderstandingPropertiesML, XR_TYPE_SYSTEM_MARKER_UNDERSTANDING_PROPERTIES_ML) \
+ _(XrMarkerDetectorCreateInfoML, XR_TYPE_MARKER_DETECTOR_CREATE_INFO_ML) \
+ _(XrMarkerDetectorArucoInfoML, XR_TYPE_MARKER_DETECTOR_ARUCO_INFO_ML) \
+ _(XrMarkerDetectorSizeInfoML, XR_TYPE_MARKER_DETECTOR_SIZE_INFO_ML) \
+ _(XrMarkerDetectorAprilTagInfoML, XR_TYPE_MARKER_DETECTOR_APRIL_TAG_INFO_ML) \
+ _(XrMarkerDetectorCustomProfileInfoML, XR_TYPE_MARKER_DETECTOR_CUSTOM_PROFILE_INFO_ML) \
+ _(XrMarkerDetectorSnapshotInfoML, XR_TYPE_MARKER_DETECTOR_SNAPSHOT_INFO_ML) \
+ _(XrMarkerDetectorStateML, XR_TYPE_MARKER_DETECTOR_STATE_ML) \
+ _(XrMarkerSpaceCreateInfoML, XR_TYPE_MARKER_SPACE_CREATE_INFO_ML) \
+ _(XrLocalizationMapML, XR_TYPE_LOCALIZATION_MAP_ML) \
+ _(XrEventDataLocalizationChangedML, XR_TYPE_EVENT_DATA_LOCALIZATION_CHANGED_ML) \
+ _(XrMapLocalizationRequestInfoML, XR_TYPE_MAP_LOCALIZATION_REQUEST_INFO_ML) \
+ _(XrLocalizationMapImportInfoML, XR_TYPE_LOCALIZATION_MAP_IMPORT_INFO_ML) \
+ _(XrLocalizationEnableEventsInfoML, XR_TYPE_LOCALIZATION_ENABLE_EVENTS_INFO_ML) \
_(XrSpatialAnchorPersistenceInfoMSFT, XR_TYPE_SPATIAL_ANCHOR_PERSISTENCE_INFO_MSFT) \
_(XrSpatialAnchorFromPersistedAnchorCreateInfoMSFT, XR_TYPE_SPATIAL_ANCHOR_FROM_PERSISTED_ANCHOR_CREATE_INFO_MSFT) \
_(XrSceneMarkersMSFT, XR_TYPE_SCENE_MARKERS_MSFT) \
@@ -4359,6 +4692,8 @@ XR_ENUM_STR(XrResult);
_(XrFoveationApplyInfoHTC, XR_TYPE_FOVEATION_APPLY_INFO_HTC) \
_(XrFoveationDynamicModeInfoHTC, XR_TYPE_FOVEATION_DYNAMIC_MODE_INFO_HTC) \
_(XrFoveationCustomModeInfoHTC, XR_TYPE_FOVEATION_CUSTOM_MODE_INFO_HTC) \
+ _(XrSystemAnchorPropertiesHTC, XR_TYPE_SYSTEM_ANCHOR_PROPERTIES_HTC) \
+ _(XrSpatialAnchorCreateInfoHTC, XR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_HTC) \
_(XrActiveActionSetPrioritiesEXT, XR_TYPE_ACTIVE_ACTION_SET_PRIORITIES_EXT) \
_(XrSystemForceFeedbackCurlPropertiesMNDX, XR_TYPE_SYSTEM_FORCE_FEEDBACK_CURL_PROPERTIES_MNDX) \
_(XrForceFeedbackCurlApplyLocationsMNDX, XR_TYPE_FORCE_FEEDBACK_CURL_APPLY_LOCATIONS_MNDX) \
@@ -4629,6 +4964,8 @@ XR_ENUM_STR(XrResult);
_(XR_ML_frame_end_info, 136) \
_(XR_ML_global_dimmer, 137) \
_(XR_ML_compat, 138) \
+ _(XR_ML_marker_understanding, 139) \
+ _(XR_ML_localization_map, 140) \
_(XR_MSFT_spatial_anchor_persistence, 143) \
_(XR_MSFT_scene_marker, 148) \
_(XR_ULTRALEAP_hand_tracking_forearm, 150) \
@@ -4667,11 +5004,13 @@ XR_ENUM_STR(XrResult);
_(XR_FB_spatial_entity_user, 242) \
_(XR_META_headset_id, 246) \
_(XR_META_passthrough_color_lut, 267) \
+ _(XR_META_touch_controller_plus, 280) \
_(XR_EXT_uuid, 300) \
_(XR_EXT_hand_interaction, 303) \
_(XR_QCOM_tracking_optimization_settings, 307) \
_(XR_HTC_passthrough, 318) \
_(XR_HTC_foveation, 319) \
+ _(XR_HTC_anchor, 320) \
_(XR_EXT_active_action_set_priority, 374) \
_(XR_MNDX_force_feedback_curl, 376) \
_(XR_BD_controller_interaction, 385) \
diff --git a/thirdparty/openxr/include/openxr/openxr_reflection_parent_structs.h b/thirdparty/openxr/include/openxr/openxr_reflection_parent_structs.h
index f410ddcf79..4241682e0b 100644
--- a/thirdparty/openxr/include/openxr/openxr_reflection_parent_structs.h
+++ b/thirdparty/openxr/include/openxr/openxr_reflection_parent_structs.h
@@ -2,7 +2,7 @@
#define OPENXR_REFLECTION_PARENT_STRUCTS_H_ 1
/*
-** Copyright (c) 2017-2023, The Khronos Group Inc.
+** Copyright (c) 2017-2024, The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0 OR MIT
*/
@@ -58,6 +58,7 @@ This file contains expansion macros (X Macros) for OpenXR structures that have a
_avail(XrEventDataSpatialAnchorCreateCompleteFB, XR_TYPE_EVENT_DATA_SPATIAL_ANCHOR_CREATE_COMPLETE_FB) \
_avail(XrEventDataSpaceSetStatusCompleteFB, XR_TYPE_EVENT_DATA_SPACE_SET_STATUS_COMPLETE_FB) \
_avail(XrEventDataMarkerTrackingUpdateVARJO, XR_TYPE_EVENT_DATA_MARKER_TRACKING_UPDATE_VARJO) \
+ _avail(XrEventDataLocalizationChangedML, XR_TYPE_EVENT_DATA_LOCALIZATION_CHANGED_ML) \
_avail(XrEventDataSpaceQueryResultsAvailableFB, XR_TYPE_EVENT_DATA_SPACE_QUERY_RESULTS_AVAILABLE_FB) \
_avail(XrEventDataSpaceQueryCompleteFB, XR_TYPE_EVENT_DATA_SPACE_QUERY_COMPLETE_FB) \
_avail(XrEventDataSpaceSaveCompleteFB, XR_TYPE_EVENT_DATA_SPACE_SAVE_COMPLETE_FB) \
diff --git a/thirdparty/openxr/include/openxr/openxr_reflection_structs.h b/thirdparty/openxr/include/openxr/openxr_reflection_structs.h
index 2d23ac15ca..bcc1333e29 100644
--- a/thirdparty/openxr/include/openxr/openxr_reflection_structs.h
+++ b/thirdparty/openxr/include/openxr/openxr_reflection_structs.h
@@ -2,7 +2,7 @@
#define OPENXR_REFLECTION_STRUCTS_H_ 1
/*
-** Copyright (c) 2017-2023, The Khronos Group Inc.
+** Copyright (c) 2017-2024, The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0 OR MIT
*/
@@ -225,6 +225,20 @@ This file contains expansion macros (X Macros) for OpenXR structures.
_avail(XrMarkerSpaceCreateInfoVARJO, XR_TYPE_MARKER_SPACE_CREATE_INFO_VARJO) \
_avail(XrFrameEndInfoML, XR_TYPE_FRAME_END_INFO_ML) \
_avail(XrGlobalDimmerFrameEndInfoML, XR_TYPE_GLOBAL_DIMMER_FRAME_END_INFO_ML) \
+ _avail(XrSystemMarkerUnderstandingPropertiesML, XR_TYPE_SYSTEM_MARKER_UNDERSTANDING_PROPERTIES_ML) \
+ _avail(XrMarkerDetectorCreateInfoML, XR_TYPE_MARKER_DETECTOR_CREATE_INFO_ML) \
+ _avail(XrMarkerDetectorArucoInfoML, XR_TYPE_MARKER_DETECTOR_ARUCO_INFO_ML) \
+ _avail(XrMarkerDetectorSizeInfoML, XR_TYPE_MARKER_DETECTOR_SIZE_INFO_ML) \
+ _avail(XrMarkerDetectorAprilTagInfoML, XR_TYPE_MARKER_DETECTOR_APRIL_TAG_INFO_ML) \
+ _avail(XrMarkerDetectorCustomProfileInfoML, XR_TYPE_MARKER_DETECTOR_CUSTOM_PROFILE_INFO_ML) \
+ _avail(XrMarkerDetectorSnapshotInfoML, XR_TYPE_MARKER_DETECTOR_SNAPSHOT_INFO_ML) \
+ _avail(XrMarkerDetectorStateML, XR_TYPE_MARKER_DETECTOR_STATE_ML) \
+ _avail(XrMarkerSpaceCreateInfoML, XR_TYPE_MARKER_SPACE_CREATE_INFO_ML) \
+ _avail(XrLocalizationMapML, XR_TYPE_LOCALIZATION_MAP_ML) \
+ _avail(XrEventDataLocalizationChangedML, XR_TYPE_EVENT_DATA_LOCALIZATION_CHANGED_ML) \
+ _avail(XrMapLocalizationRequestInfoML, XR_TYPE_MAP_LOCALIZATION_REQUEST_INFO_ML) \
+ _avail(XrLocalizationMapImportInfoML, XR_TYPE_LOCALIZATION_MAP_IMPORT_INFO_ML) \
+ _avail(XrLocalizationEnableEventsInfoML, XR_TYPE_LOCALIZATION_ENABLE_EVENTS_INFO_ML) \
_avail(XrSpatialAnchorPersistenceInfoMSFT, XR_TYPE_SPATIAL_ANCHOR_PERSISTENCE_INFO_MSFT) \
_avail(XrSpatialAnchorFromPersistedAnchorCreateInfoMSFT, XR_TYPE_SPATIAL_ANCHOR_FROM_PERSISTED_ANCHOR_CREATE_INFO_MSFT) \
_avail(XrSceneMarkersMSFT, XR_TYPE_SCENE_MARKERS_MSFT) \
@@ -306,6 +320,8 @@ This file contains expansion macros (X Macros) for OpenXR structures.
_avail(XrFoveationApplyInfoHTC, XR_TYPE_FOVEATION_APPLY_INFO_HTC) \
_avail(XrFoveationDynamicModeInfoHTC, XR_TYPE_FOVEATION_DYNAMIC_MODE_INFO_HTC) \
_avail(XrFoveationCustomModeInfoHTC, XR_TYPE_FOVEATION_CUSTOM_MODE_INFO_HTC) \
+ _avail(XrSystemAnchorPropertiesHTC, XR_TYPE_SYSTEM_ANCHOR_PROPERTIES_HTC) \
+ _avail(XrSpatialAnchorCreateInfoHTC, XR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_HTC) \
_avail(XrActiveActionSetPrioritiesEXT, XR_TYPE_ACTIVE_ACTION_SET_PRIORITIES_EXT) \
_avail(XrSystemForceFeedbackCurlPropertiesMNDX, XR_TYPE_SYSTEM_FORCE_FEEDBACK_CURL_PROPERTIES_MNDX) \
_avail(XrForceFeedbackCurlApplyLocationsMNDX, XR_TYPE_FORCE_FEEDBACK_CURL_APPLY_LOCATIONS_MNDX) \
diff --git a/thirdparty/openxr/src/common/extra_algorithms.h b/thirdparty/openxr/src/common/extra_algorithms.h
index eec429e12a..bdaa420e9f 100644
--- a/thirdparty/openxr/src/common/extra_algorithms.h
+++ b/thirdparty/openxr/src/common/extra_algorithms.h
@@ -1,11 +1,11 @@
-// Copyright (c) 2017-2023, The Khronos Group Inc.
+// Copyright (c) 2017-2024, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
// Copyright (c) 2019 Collabora, Ltd.
//
// SPDX-License-Identifier: Apache-2.0 OR MIT
//
-// Initial Author: Ryan Pavlik <ryan.pavlik@collabora.com>
+// Initial Author: Rylie Pavlik <rylie.pavlik@collabora.com>
//
/*!
diff --git a/thirdparty/openxr/src/common/filesystem_utils.cpp b/thirdparty/openxr/src/common/filesystem_utils.cpp
index 16e6ff3292..063c4c4cee 100644
--- a/thirdparty/openxr/src/common/filesystem_utils.cpp
+++ b/thirdparty/openxr/src/common/filesystem_utils.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2023, The Khronos Group Inc.
+// Copyright (c) 2017-2024, The Khronos Group Inc.
// Copyright (c) 2017 Valve Corporation
// Copyright (c) 2017 LunarG, Inc.
//
diff --git a/thirdparty/openxr/src/common/filesystem_utils.hpp b/thirdparty/openxr/src/common/filesystem_utils.hpp
index 3dea1b2c3e..2a923fac4c 100644
--- a/thirdparty/openxr/src/common/filesystem_utils.hpp
+++ b/thirdparty/openxr/src/common/filesystem_utils.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2023, The Khronos Group Inc.
+// Copyright (c) 2017-2024, The Khronos Group Inc.
// Copyright (c) 2017 Valve Corporation
// Copyright (c) 2017 LunarG, Inc.
//
diff --git a/thirdparty/openxr/src/common/hex_and_handles.h b/thirdparty/openxr/src/common/hex_and_handles.h
index 300669033f..12bdb3670c 100644
--- a/thirdparty/openxr/src/common/hex_and_handles.h
+++ b/thirdparty/openxr/src/common/hex_and_handles.h
@@ -1,11 +1,11 @@
-// Copyright (c) 2017-2023, The Khronos Group Inc.
+// Copyright (c) 2017-2024, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
// Copyright (c) 2019 Collabora, Ltd.
//
// SPDX-License-Identifier: Apache-2.0 OR MIT
//
-// Initial Author: Ryan Pavlik <ryan.pavlik@collabora.com>
+// Initial Author: Rylie Pavlik <rylie.pavlik@collabora.com>
//
/*!
diff --git a/thirdparty/openxr/src/common/loader_interfaces.h b/thirdparty/openxr/src/common/loader_interfaces.h
deleted file mode 100644
index 020c3456ea..0000000000
--- a/thirdparty/openxr/src/common/loader_interfaces.h
+++ /dev/null
@@ -1,114 +0,0 @@
-// Copyright (c) 2017-2023, The Khronos Group Inc.
-// Copyright (c) 2017 Valve Corporation
-// Copyright (c) 2017 LunarG, Inc.
-//
-// SPDX-License-Identifier: Apache-2.0 OR MIT
-//
-// Initial Author: Mark Young <marky@lunarg.com>
-//
-
-#pragma once
-
-#include <openxr/openxr.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// Forward declare.
-typedef struct XrApiLayerCreateInfo XrApiLayerCreateInfo;
-
-// Function pointer prototype for the xrCreateApiLayerInstance function used in place of xrCreateInstance.
-// This function allows us to pass special API layer information to each layer during the process of creating an Instance.
-typedef XrResult(XRAPI_PTR *PFN_xrCreateApiLayerInstance)(const XrInstanceCreateInfo *info,
- const XrApiLayerCreateInfo *apiLayerInfo, XrInstance *instance);
-
-// Loader/API Layer Interface versions
-// 1 - First version, introduces negotiation structure and functions
-#define XR_CURRENT_LOADER_API_LAYER_VERSION 1
-
-// Loader/Runtime Interface versions
-// 1 - First version, introduces negotiation structure and functions
-#define XR_CURRENT_LOADER_RUNTIME_VERSION 1
-
-// Version negotiation values
-typedef enum XrLoaderInterfaceStructs {
- XR_LOADER_INTERFACE_STRUCT_UNINTIALIZED = 0,
- XR_LOADER_INTERFACE_STRUCT_LOADER_INFO,
- XR_LOADER_INTERFACE_STRUCT_API_LAYER_REQUEST,
- XR_LOADER_INTERFACE_STRUCT_RUNTIME_REQUEST,
- XR_LOADER_INTERFACE_STRUCT_API_LAYER_CREATE_INFO,
- XR_LOADER_INTERFACE_STRUCT_API_LAYER_NEXT_INFO,
-} XrLoaderInterfaceStructs;
-
-#define XR_LOADER_INFO_STRUCT_VERSION 1
-typedef struct XrNegotiateLoaderInfo {
- XrLoaderInterfaceStructs structType; // XR_LOADER_INTERFACE_STRUCT_LOADER_INFO
- uint32_t structVersion; // XR_LOADER_INFO_STRUCT_VERSION
- size_t structSize; // sizeof(XrNegotiateLoaderInfo)
- uint32_t minInterfaceVersion;
- uint32_t maxInterfaceVersion;
- XrVersion minApiVersion;
- XrVersion maxApiVersion;
-} XrNegotiateLoaderInfo;
-
-#define XR_API_LAYER_INFO_STRUCT_VERSION 1
-typedef struct XrNegotiateApiLayerRequest {
- XrLoaderInterfaceStructs structType; // XR_LOADER_INTERFACE_STRUCT_API_LAYER_REQUEST
- uint32_t structVersion; // XR_API_LAYER_INFO_STRUCT_VERSION
- size_t structSize; // sizeof(XrNegotiateApiLayerRequest)
- uint32_t layerInterfaceVersion; // CURRENT_LOADER_API_LAYER_VERSION
- XrVersion layerApiVersion;
- PFN_xrGetInstanceProcAddr getInstanceProcAddr;
- PFN_xrCreateApiLayerInstance createApiLayerInstance;
-} XrNegotiateApiLayerRequest;
-
-#define XR_RUNTIME_INFO_STRUCT_VERSION 1
-typedef struct XrNegotiateRuntimeRequest {
- XrLoaderInterfaceStructs structType; // XR_LOADER_INTERFACE_STRUCT_RUNTIME_REQUEST
- uint32_t structVersion; // XR_RUNTIME_INFO_STRUCT_VERSION
- size_t structSize; // sizeof(XrNegotiateRuntimeRequest)
- uint32_t runtimeInterfaceVersion; // CURRENT_LOADER_RUNTIME_VERSION
- XrVersion runtimeApiVersion;
- PFN_xrGetInstanceProcAddr getInstanceProcAddr;
-} XrNegotiateRuntimeRequest;
-
-// Function used to negotiate an interface betewen the loader and an API layer. Each library exposing one or
-// more API layers needs to expose at least this function.
-typedef XrResult(XRAPI_PTR *PFN_xrNegotiateLoaderApiLayerInterface)(const XrNegotiateLoaderInfo *loaderInfo,
- const char *apiLayerName,
- XrNegotiateApiLayerRequest *apiLayerRequest);
-
-// Function used to negotiate an interface betewen the loader and a runtime. Each runtime should expose
-// at least this function.
-typedef XrResult(XRAPI_PTR *PFN_xrNegotiateLoaderRuntimeInterface)(const XrNegotiateLoaderInfo *loaderInfo,
- XrNegotiateRuntimeRequest *runtimeRequest);
-
-// Forward declare.
-typedef struct XrApiLayerNextInfo XrApiLayerNextInfo;
-
-#define XR_API_LAYER_NEXT_INFO_STRUCT_VERSION 1
-struct XrApiLayerNextInfo {
- XrLoaderInterfaceStructs structType; // XR_LOADER_INTERFACE_STRUCT_API_LAYER_NEXT_INFO
- uint32_t structVersion; // XR_API_LAYER_NEXT_INFO_STRUCT_VERSION
- size_t structSize; // sizeof(XrApiLayerNextInfo)
- char layerName[XR_MAX_API_LAYER_NAME_SIZE]; // Name of API layer which should receive this info
- PFN_xrGetInstanceProcAddr nextGetInstanceProcAddr; // Pointer to next API layer's xrGetInstanceProcAddr
- PFN_xrCreateApiLayerInstance nextCreateApiLayerInstance; // Pointer to next API layer's xrCreateApiLayerInstance
- XrApiLayerNextInfo *next; // Pointer to the next API layer info in the sequence
-};
-
-#define XR_API_LAYER_MAX_SETTINGS_PATH_SIZE 512
-#define XR_API_LAYER_CREATE_INFO_STRUCT_VERSION 1
-typedef struct XrApiLayerCreateInfo {
- XrLoaderInterfaceStructs structType; // XR_LOADER_INTERFACE_STRUCT_API_LAYER_CREATE_INFO
- uint32_t structVersion; // XR_API_LAYER_CREATE_INFO_STRUCT_VERSION
- size_t structSize; // sizeof(XrApiLayerCreateInfo)
- void *loaderInstance; // Pointer to the LoaderInstance class
- char settings_file_location[XR_API_LAYER_MAX_SETTINGS_PATH_SIZE]; // Location to the found settings file (or empty '\0')
- XrApiLayerNextInfo *nextInfo; // Pointer to the next API layer's Info
-} XrApiLayerCreateInfo;
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
diff --git a/thirdparty/openxr/src/common/object_info.cpp b/thirdparty/openxr/src/common/object_info.cpp
index 3f8f96bc6e..d45430a609 100644
--- a/thirdparty/openxr/src/common/object_info.cpp
+++ b/thirdparty/openxr/src/common/object_info.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2023, The Khronos Group Inc.
+// Copyright (c) 2017-2024, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
// Copyright (c) 2019 Collabora, Ltd.
@@ -6,7 +6,7 @@
// SPDX-License-Identifier: Apache-2.0 OR MIT
//
// Initial Authors: Mark Young <marky@lunarg.com>
-// Ryan Pavlik <ryan.pavlik@collabora.com>
+// Rylie Pavlik <rylie.pavlik@collabora.com>
// Dave Houlton <daveh@lunarg.com>
//
diff --git a/thirdparty/openxr/src/common/object_info.h b/thirdparty/openxr/src/common/object_info.h
index 247ede0dcc..572f06ab15 100644
--- a/thirdparty/openxr/src/common/object_info.h
+++ b/thirdparty/openxr/src/common/object_info.h
@@ -1,11 +1,11 @@
-// Copyright (c) 2017-2023, The Khronos Group Inc.
+// Copyright (c) 2017-2024, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
// Copyright (c) 2019 Collabora, Ltd.
//
// SPDX-License-Identifier: Apache-2.0 OR MIT
//
-// Initial Authors: Mark Young <marky@lunarg.com>, Ryan Pavlik <ryan.pavlik@collabora.com
+// Initial Authors: Mark Young <marky@lunarg.com>, Rylie Pavlik <rylie.pavlik@collabora.com
//
/*!
* @file
diff --git a/thirdparty/openxr/src/common/platform_utils.hpp b/thirdparty/openxr/src/common/platform_utils.hpp
index 0b295f5cc9..c4d75bf259 100644
--- a/thirdparty/openxr/src/common/platform_utils.hpp
+++ b/thirdparty/openxr/src/common/platform_utils.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2023, The Khronos Group Inc.
+// Copyright (c) 2017-2024, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
diff --git a/thirdparty/openxr/src/common/stdfs_conditions.h b/thirdparty/openxr/src/common/stdfs_conditions.h
index 0a551f08cd..9e2ba70d42 100644
--- a/thirdparty/openxr/src/common/stdfs_conditions.h
+++ b/thirdparty/openxr/src/common/stdfs_conditions.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2023, The Khronos Group Inc.
+// Copyright (c) 2017-2024, The Khronos Group Inc.
// Copyright (c) 2017 Valve Corporation
// Copyright (c) 2017 LunarG, Inc.
//
diff --git a/thirdparty/openxr/src/common/unique_asset.h b/thirdparty/openxr/src/common/unique_asset.h
index a8ae8077bc..fd5f8868e3 100644
--- a/thirdparty/openxr/src/common/unique_asset.h
+++ b/thirdparty/openxr/src/common/unique_asset.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2023, The Khronos Group Inc.
+// Copyright (c) 2017-2024, The Khronos Group Inc.
//
// SPDX-License-Identifier: Apache-2.0 OR MIT
#pragma once
diff --git a/thirdparty/openxr/src/common/vulkan_debug_object_namer.hpp b/thirdparty/openxr/src/common/vulkan_debug_object_namer.hpp
index 451219d20f..885389ce8e 100644
--- a/thirdparty/openxr/src/common/vulkan_debug_object_namer.hpp
+++ b/thirdparty/openxr/src/common/vulkan_debug_object_namer.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2023, The Khronos Group Inc.
+// Copyright (c) 2017-2024, The Khronos Group Inc.
//
// SPDX-License-Identifier: Apache-2.0
diff --git a/thirdparty/openxr/src/common/xr_dependencies.h b/thirdparty/openxr/src/common/xr_dependencies.h
index 6c9cf2d05f..55d93bfbac 100644
--- a/thirdparty/openxr/src/common/xr_dependencies.h
+++ b/thirdparty/openxr/src/common/xr_dependencies.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2018-2023, The Khronos Group Inc.
+// Copyright (c) 2018-2024, The Khronos Group Inc.
//
// SPDX-License-Identifier: Apache-2.0 OR MIT
//
diff --git a/thirdparty/openxr/src/common/xr_linear.h b/thirdparty/openxr/src/common/xr_linear.h
index ce65f8ddfb..2b295ed304 100644
--- a/thirdparty/openxr/src/common/xr_linear.h
+++ b/thirdparty/openxr/src/common/xr_linear.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2023, The Khronos Group Inc.
+// Copyright (c) 2017-2024, The Khronos Group Inc.
// Copyright (c) 2016, Oculus VR, LLC.
//
// SPDX-License-Identifier: Apache-2.0
diff --git a/thirdparty/openxr/src/loader/android_utilities.cpp b/thirdparty/openxr/src/loader/android_utilities.cpp
index 9a3ad76ce0..5c9b846b5a 100644
--- a/thirdparty/openxr/src/loader/android_utilities.cpp
+++ b/thirdparty/openxr/src/loader/android_utilities.cpp
@@ -1,9 +1,9 @@
-// Copyright (c) 2020-2023, The Khronos Group Inc.
+// Copyright (c) 2020-2024, The Khronos Group Inc.
// Copyright (c) 2020-2021, Collabora, Ltd.
//
// SPDX-License-Identifier: Apache-2.0 OR MIT
//
-// Initial Author: Ryan Pavlik <ryan.pavlik@collabora.com>
+// Initial Author: Rylie Pavlik <rylie.pavlik@collabora.com>
#include "android_utilities.h"
@@ -245,18 +245,38 @@ static int populateFunctions(wrap::android::content::Context const &context, boo
return 0;
}
+// The current file relies on android-jni-wrappers and jnipp, which may throw on failure.
+// This is problematic when the loader is compiled with exception handling disabled - the consumers can reasonably
+// expect that the compilation with -fno-exceptions will succeed, but the compiler will not accept the code that
+// uses `try` & `catch` keywords. We cannot use the `exception_handling.hpp` here since we're not at an ABI boundary,
+// so we define helper macros here. This is fine for now since the only occurrence of exception-handling code is in this file.
+#ifdef XRLOADER_DISABLE_EXCEPTION_HANDLING
+
+#define ANDROID_UTILITIES_TRY
+#define ANDROID_UTILITIES_CATCH_FALLBACK(...)
+
+#else
+
+#define ANDROID_UTILITIES_TRY try
+#define ANDROID_UTILITIES_CATCH_FALLBACK(...) \
+ catch (const std::exception &e) { \
+ __VA_ARGS__ \
+ }
+
+#endif // XRLOADER_DISABLE_EXCEPTION_HANDLING
+
/// Get cursor for active runtime, parameterized by whether or not we use the system broker
static bool getActiveRuntimeCursor(wrap::android::content::Context const &context, jni::Array<std::string> const &projection,
bool systemBroker, Cursor &cursor) {
auto uri = active_runtime::makeContentUri(systemBroker, XR_VERSION_MAJOR(XR_CURRENT_API_VERSION), ABI);
ALOGI("getActiveRuntimeCursor: Querying URI: %s", uri.toString().c_str());
- try {
- cursor = context.getContentResolver().query(uri, projection);
- } catch (const std::exception &e) {
+
+ ANDROID_UTILITIES_TRY { cursor = context.getContentResolver().query(uri, projection); }
+ ANDROID_UTILITIES_CATCH_FALLBACK({
ALOGW("Exception when querying %s content resolver: %s", getBrokerTypeName(systemBroker), e.what());
cursor = {};
return false;
- }
+ })
if (cursor.isNull()) {
ALOGW("Null cursor when querying %s content resolver.", getBrokerTypeName(systemBroker));
diff --git a/thirdparty/openxr/src/loader/android_utilities.h b/thirdparty/openxr/src/loader/android_utilities.h
index f66c9bf1d0..582a65056e 100644
--- a/thirdparty/openxr/src/loader/android_utilities.h
+++ b/thirdparty/openxr/src/loader/android_utilities.h
@@ -1,9 +1,9 @@
-// Copyright (c) 2020-2023, The Khronos Group Inc.
+// Copyright (c) 2020-2024, The Khronos Group Inc.
// Copyright (c) 2020-2021, Collabora, Ltd.
//
// SPDX-License-Identifier: Apache-2.0 OR MIT
//
-// Initial Author: Ryan Pavlik <ryan.pavlik@collabora.com>
+// Initial Author: Rylie Pavlik <rylie.pavlik@collabora.com>
#pragma once
#ifdef __ANDROID__
diff --git a/thirdparty/openxr/src/loader/api_layer_interface.cpp b/thirdparty/openxr/src/loader/api_layer_interface.cpp
index c9e24ec40b..fb509de270 100644
--- a/thirdparty/openxr/src/loader/api_layer_interface.cpp
+++ b/thirdparty/openxr/src/loader/api_layer_interface.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2023, The Khronos Group Inc.
+// Copyright (c) 2017-2024, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
@@ -9,13 +9,14 @@
#include "api_layer_interface.hpp"
-#include "loader_interfaces.h"
+#include "loader_init_data.hpp"
#include "loader_logger.hpp"
#include "loader_platform.hpp"
#include "manifest_file.hpp"
#include "platform_utils.hpp"
#include <openxr/openxr.h>
+#include <openxr/openxr_loader_negotiation.h>
#include <cstring>
#include <memory>
@@ -282,6 +283,38 @@ XrResult ApiLayerInterface::LoadApiLayers(const std::string& openxr_command, uin
LoaderLogger::LogWarningMessage(openxr_command, warning_message);
continue;
}
+#ifdef XR_KHR_LOADER_INIT_SUPPORT
+ if (!LoaderInitData::instance().initialized()) {
+ LoaderLogger::LogErrorMessage(openxr_command, "ApiLayerInterface::LoadApiLayers skipping manifest file " +
+ manifest_file->Filename() +
+ " because xrInitializeLoaderKHR was not yet called.");
+
+ LoaderPlatformLibraryClose(layer_library);
+ return XR_ERROR_VALIDATION_FAILURE;
+ }
+ bool forwardedInitLoader = false;
+ {
+ // If we have xrInitializeLoaderKHR exposed as an export, forward call to it.
+ const auto function_name = manifest_file->GetFunctionName("xrInitializeLoaderKHR");
+ auto initLoader =
+ reinterpret_cast<PFN_xrInitializeLoaderKHR>(LoaderPlatformLibraryGetProcAddr(layer_library, function_name));
+ if (initLoader != nullptr) {
+ // we found the entry point one way or another.
+ LoaderLogger::LogInfoMessage(openxr_command,
+ "ApiLayerInterface::LoadApiLayers forwarding xrInitializeLoaderKHR call to API layer "
+ "before calling xrNegotiateLoaderApiLayerInterface.");
+ XrResult res = initLoader(LoaderInitData::instance().getParam());
+ if (!XR_SUCCEEDED(res)) {
+ LoaderLogger::LogErrorMessage(
+ openxr_command, "ApiLayerInterface::LoadApiLayers forwarded call to xrInitializeLoaderKHR failed.");
+
+ LoaderPlatformLibraryClose(layer_library);
+ return res;
+ }
+ forwardedInitLoader = true;
+ }
+ }
+#endif
// Get and settle on an layer interface version (using any provided name if required).
std::string function_name = manifest_file->GetFunctionName("xrNegotiateLoaderApiLayerInterface");
@@ -324,6 +357,38 @@ XrResult ApiLayerInterface::LoadApiLayers(const std::string& openxr_command, uin
LoaderLogger::LogWarningMessage(openxr_command, warning_message);
res = XR_ERROR_FILE_CONTENTS_INVALID;
}
+
+#ifdef XR_KHR_LOADER_INIT_SUPPORT
+ if (XR_SUCCEEDED(res) && !forwardedInitLoader) {
+ // Forward initialize loader call, where possible and if we did not do so before.
+ PFN_xrVoidFunction initializeVoid = nullptr;
+ PFN_xrInitializeLoaderKHR initialize = nullptr;
+
+ // Now we may try asking xrGetInstanceProcAddr on the API layer
+ if (XR_SUCCEEDED(api_layer_info.getInstanceProcAddr(XR_NULL_HANDLE, "xrInitializeLoaderKHR", &initializeVoid))) {
+ if (initializeVoid == nullptr) {
+ LoaderLogger::LogErrorMessage(openxr_command,
+ "ApiLayerInterface::LoadApiLayers got success from xrGetInstanceProcAddr "
+ "for xrInitializeLoaderKHR, but output a null pointer.");
+ res = XR_ERROR_RUNTIME_FAILURE;
+ } else {
+ initialize = reinterpret_cast<PFN_xrInitializeLoaderKHR>(initializeVoid);
+ }
+ }
+ if (initialize != nullptr) {
+ // we found the entry point one way or another.
+ LoaderLogger::LogInfoMessage(openxr_command,
+ "ApiLayerInterface::LoadApiLayers forwarding xrInitializeLoaderKHR call to API layer "
+ "after calling xrNegotiateLoaderApiLayerInterface.");
+ res = initialize(LoaderInitData::instance().getParam());
+ if (!XR_SUCCEEDED(res)) {
+ LoaderLogger::LogErrorMessage(
+ openxr_command, "ApiLayerInterface::LoadApiLayers forwarded call to xrInitializeLoaderKHR failed.");
+ }
+ }
+ }
+#endif
+
if (XR_FAILED(res)) {
if (!any_loaded) {
last_error = res;
diff --git a/thirdparty/openxr/src/loader/api_layer_interface.hpp b/thirdparty/openxr/src/loader/api_layer_interface.hpp
index 98685b0c32..43758b31a4 100644
--- a/thirdparty/openxr/src/loader/api_layer_interface.hpp
+++ b/thirdparty/openxr/src/loader/api_layer_interface.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2023, The Khronos Group Inc.
+// Copyright (c) 2017-2024, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
@@ -14,9 +14,9 @@
#include <memory>
#include <openxr/openxr.h>
+#include <openxr/openxr_loader_negotiation.h>
#include "loader_platform.hpp"
-#include "loader_interfaces.h"
struct XrGeneratedDispatchTable;
diff --git a/thirdparty/openxr/src/loader/exception_handling.hpp b/thirdparty/openxr/src/loader/exception_handling.hpp
index bc0d9b65e3..62395fdf69 100644
--- a/thirdparty/openxr/src/loader/exception_handling.hpp
+++ b/thirdparty/openxr/src/loader/exception_handling.hpp
@@ -1,8 +1,8 @@
-// Copyright (c) 2019-2023, The Khronos Group Inc.
+// Copyright (c) 2019-2024, The Khronos Group Inc.
//
// SPDX-License-Identifier: Apache-2.0 OR MIT
//
-// Initial Author: Ryan Pavlik <ryan.pavlik@collabora.com>
+// Initial Author: Rylie Pavlik <rylie.pavlik@collabora.com>
//
// Provides protection for C ABI functions if standard library functions may throw.
diff --git a/thirdparty/openxr/src/loader/loader_core.cpp b/thirdparty/openxr/src/loader/loader_core.cpp
index 06e6870053..8bf2609a08 100644
--- a/thirdparty/openxr/src/loader/loader_core.cpp
+++ b/thirdparty/openxr/src/loader/loader_core.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2023, The Khronos Group Inc.
+// Copyright (c) 2017-2024, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
@@ -14,6 +14,7 @@
#include "api_layer_interface.hpp"
#include "exception_handling.hpp"
#include "hex_and_handles.h"
+#include "loader_init_data.hpp"
#include "loader_instance.hpp"
#include "loader_logger_recorders.hpp"
#include "loader_logger.hpp"
@@ -77,7 +78,7 @@ inline bool IsMissingNullTerminator(const char (&str)[max_length]) {
#ifdef XR_KHR_LOADER_INIT_SUPPORT // platforms that support XR_KHR_loader_init.
XRAPI_ATTR XrResult XRAPI_CALL LoaderXrInitializeLoaderKHR(const XrLoaderInitInfoBaseHeaderKHR *loaderInitInfo) XRLOADER_ABI_TRY {
LoaderLogger::LogVerboseMessage("xrInitializeLoaderKHR", "Entering loader trampoline");
- return InitializeLoader(loaderInitInfo);
+ return InitializeLoaderInitData(loaderInitInfo);
}
XRLOADER_ABI_CATCH_FALLBACK
#endif
diff --git a/thirdparty/openxr/src/loader/loader_init_data.cpp b/thirdparty/openxr/src/loader/loader_init_data.cpp
new file mode 100644
index 0000000000..11d3c4e77b
--- /dev/null
+++ b/thirdparty/openxr/src/loader/loader_init_data.cpp
@@ -0,0 +1,59 @@
+// Copyright (c) 2017-2024, The Khronos Group Inc.
+// Copyright (c) 2017-2019 Valve Corporation
+// Copyright (c) 2017-2019 LunarG, Inc.
+//
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+//
+// Initial Author: Mark Young <marky@lunarg.com>
+//
+
+#include "loader_init_data.hpp"
+
+#ifdef XR_KHR_LOADER_INIT_SUPPORT
+
+#ifdef XR_USE_PLATFORM_ANDROID
+// Check and copy the Android-specific init data.
+XrResult LoaderInitData::initialize(const XrLoaderInitInfoBaseHeaderKHR* info) {
+ if (info->type != XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR) {
+ return XR_ERROR_VALIDATION_FAILURE;
+ }
+ auto cast_info = reinterpret_cast<XrLoaderInitInfoAndroidKHR const*>(info);
+
+ if (cast_info->applicationVM == nullptr) {
+ return XR_ERROR_VALIDATION_FAILURE;
+ }
+ if (cast_info->applicationContext == nullptr) {
+ return XR_ERROR_VALIDATION_FAILURE;
+ }
+
+ // Copy and store the JVM pointer and Android Context, ensuring the JVM is initialised.
+ _data = *cast_info;
+ _data.next = nullptr;
+ jni::init(static_cast<jni::JavaVM*>(_data.applicationVM));
+ const jni::Object context = jni::Object{static_cast<jni::jobject>(_data.applicationContext)};
+
+ // Retrieve a reference to the Android AssetManager.
+ const auto assetManager = context.call<jni::Object>("getAssets()Landroid/content/res/AssetManager;");
+ _android_asset_manager = AAssetManager_fromJava(jni::env(), assetManager.getHandle());
+
+ // Retrieve the path to the native libraries.
+ const auto applicationContext = context.call<jni::Object>("getApplicationContext()Landroid/content/Context;");
+ const auto applicationInfo = context.call<jni::Object>("getApplicationInfo()Landroid/content/pm/ApplicationInfo;");
+ _native_library_path = applicationInfo.get<std::string>("nativeLibraryDir");
+
+ _initialized = true;
+ return XR_SUCCESS;
+}
+#endif // XR_USE_PLATFORM_ANDROID
+
+XrResult InitializeLoaderInitData(const XrLoaderInitInfoBaseHeaderKHR* loaderInitInfo) {
+ return LoaderInitData::instance().initialize(loaderInitInfo);
+}
+
+#ifdef XR_USE_PLATFORM_ANDROID
+std::string GetAndroidNativeLibraryDir() { return LoaderInitData::instance()._native_library_path; }
+
+void* Android_Get_Asset_Manager() { return LoaderInitData::instance()._android_asset_manager; }
+#endif // XR_USE_PLATFORM_ANDROID
+
+#endif // XR_KHR_LOADER_INIT_SUPPORT
diff --git a/thirdparty/openxr/src/loader/loader_init_data.hpp b/thirdparty/openxr/src/loader/loader_init_data.hpp
new file mode 100644
index 0000000000..fe6bc134d3
--- /dev/null
+++ b/thirdparty/openxr/src/loader/loader_init_data.hpp
@@ -0,0 +1,92 @@
+// Copyright (c) 2017-2024, The Khronos Group Inc.
+// Copyright (c) 2017-2019 Valve Corporation
+// Copyright (c) 2017-2019 LunarG, Inc.
+//
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+//
+// Initial Author: Mark Young <marky@lunarg.com>
+//
+
+#pragma once
+
+#include <xr_dependencies.h>
+#include <openxr/openxr_platform.h>
+
+#ifdef XR_USE_PLATFORM_ANDROID
+#include <json/value.h>
+#include <android/asset_manager_jni.h>
+#include "android_utilities.h"
+#endif // XR_USE_PLATFORM_ANDROID
+
+#ifdef XR_KHR_LOADER_INIT_SUPPORT
+
+/*!
+ * Stores a copy of the data passed to the xrInitializeLoaderKHR function in a singleton.
+ */
+class LoaderInitData {
+ public:
+ /*!
+ * Singleton accessor.
+ */
+ static LoaderInitData& instance() {
+ static LoaderInitData obj;
+ return obj;
+ }
+
+#ifdef XR_USE_PLATFORM_ANDROID
+ /*!
+ * Type alias for the platform-specific structure type.
+ */
+ using StructType = XrLoaderInitInfoAndroidKHR;
+ /*!
+ * Native library path.
+ */
+ std::string _native_library_path;
+ /*!
+ * Android asset manager.
+ */
+ AAssetManager* _android_asset_manager;
+#else
+#error "Platform specific XR_KHR_loader_init structure is not defined for this platform."
+#endif
+
+ /*!
+ * Get our copy of the data, casted to pass to the runtime's matching method.
+ */
+ const XrLoaderInitInfoBaseHeaderKHR* getParam() const { return reinterpret_cast<const XrLoaderInitInfoBaseHeaderKHR*>(&_data); }
+
+ /*!
+ * Get the data via its real structure type.
+ */
+ const StructType& getData() const { return _data; }
+
+ /*!
+ * Has this been correctly initialized?
+ */
+ bool initialized() const noexcept { return _initialized; }
+
+ /*!
+ * Initialize loader data - called by InitializeLoaderInitData() and thus ultimately by the loader's xrInitializeLoaderKHR
+ * implementation. Each platform that needs this extension will provide an implementation of this.
+ */
+ XrResult initialize(const XrLoaderInitInfoBaseHeaderKHR* info);
+
+ private:
+ //! Private constructor, forces use of singleton accessor.
+ LoaderInitData() = default;
+ //! Platform-specific init data
+ StructType _data = {};
+ //! Flag for indicating whether _data is valid.
+ bool _initialized = false;
+};
+
+//! Initialize loader init data, where required.
+XrResult InitializeLoaderInitData(const XrLoaderInitInfoBaseHeaderKHR* loaderInitInfo);
+
+#ifdef XR_USE_PLATFORM_ANDROID
+XrResult GetPlatformRuntimeVirtualManifest(Json::Value& out_manifest);
+std::string GetAndroidNativeLibraryDir();
+void* Android_Get_Asset_Manager();
+#endif // XR_USE_PLATFORM_ANDROID
+
+#endif // XR_KHR_LOADER_INIT_SUPPORT
diff --git a/thirdparty/openxr/src/loader/loader_instance.cpp b/thirdparty/openxr/src/loader/loader_instance.cpp
index ce5c205505..f18230087f 100644
--- a/thirdparty/openxr/src/loader/loader_instance.cpp
+++ b/thirdparty/openxr/src/loader/loader_instance.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2023, The Khronos Group Inc.
+// Copyright (c) 2017-2024, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
@@ -15,13 +15,13 @@
#include "api_layer_interface.hpp"
#include "hex_and_handles.h"
-#include "loader_interfaces.h"
#include "loader_logger.hpp"
#include "runtime_interface.hpp"
#include "xr_generated_dispatch_table_core.h"
#include "xr_generated_loader.hpp"
#include <openxr/openxr.h>
+#include <openxr/openxr_loader_negotiation.h>
#include <cstring>
#include <memory>
@@ -60,7 +60,7 @@ XrResult Get(LoaderInstance** loader_instance, const char* log_function_name) {
bool IsAvailable() { return GetSetCurrentLoaderInstance() != nullptr; }
-void Remove() { GetSetCurrentLoaderInstance().release(); }
+void Remove() { GetSetCurrentLoaderInstance().reset(nullptr); }
} // namespace ActiveLoaderInstance
// Extensions that are supported by the loader, but may not be supported
diff --git a/thirdparty/openxr/src/loader/loader_instance.hpp b/thirdparty/openxr/src/loader/loader_instance.hpp
index a0268a855c..b99e6b047f 100644
--- a/thirdparty/openxr/src/loader/loader_instance.hpp
+++ b/thirdparty/openxr/src/loader/loader_instance.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2023, The Khronos Group Inc.
+// Copyright (c) 2017-2024, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
@@ -10,9 +10,9 @@
#pragma once
#include "extra_algorithms.h"
-#include "loader_interfaces.h"
#include <openxr/openxr.h>
+#include <openxr/openxr_loader_negotiation.h>
#include <array>
#include <cmath>
diff --git a/thirdparty/openxr/src/loader/loader_logger.cpp b/thirdparty/openxr/src/loader/loader_logger.cpp
index 1c8d64f394..593e19a3ba 100644
--- a/thirdparty/openxr/src/loader/loader_logger.cpp
+++ b/thirdparty/openxr/src/loader/loader_logger.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2023, The Khronos Group Inc.
+// Copyright (c) 2017-2024, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
diff --git a/thirdparty/openxr/src/loader/loader_logger.hpp b/thirdparty/openxr/src/loader/loader_logger.hpp
index d31fac093a..964aa47962 100644
--- a/thirdparty/openxr/src/loader/loader_logger.hpp
+++ b/thirdparty/openxr/src/loader/loader_logger.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2023, The Khronos Group Inc.
+// Copyright (c) 2017-2024, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
diff --git a/thirdparty/openxr/src/loader/loader_logger_recorders.cpp b/thirdparty/openxr/src/loader/loader_logger_recorders.cpp
index 32e4687b2f..00392c27bd 100644
--- a/thirdparty/openxr/src/loader/loader_logger_recorders.cpp
+++ b/thirdparty/openxr/src/loader/loader_logger_recorders.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2023, The Khronos Group Inc.
+// Copyright (c) 2017-2024, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
diff --git a/thirdparty/openxr/src/loader/loader_logger_recorders.hpp b/thirdparty/openxr/src/loader/loader_logger_recorders.hpp
index 7b934202d5..b676c37e93 100644
--- a/thirdparty/openxr/src/loader/loader_logger_recorders.hpp
+++ b/thirdparty/openxr/src/loader/loader_logger_recorders.hpp
@@ -1,10 +1,10 @@
-// Copyright (c) 2017-2023, The Khronos Group Inc.
+// Copyright (c) 2017-2024, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
// SPDX-License-Identifier: Apache-2.0 OR MIT
//
-// Initial Author: Ryan Pavlik <ryan.pavlik@collabora.com>
+// Initial Author: Rylie Pavlik <rylie.pavlik@collabora.com>
//
#pragma once
diff --git a/thirdparty/openxr/src/loader/loader_platform.hpp b/thirdparty/openxr/src/loader/loader_platform.hpp
index 0ea80c05b8..964116caa4 100644
--- a/thirdparty/openxr/src/loader/loader_platform.hpp
+++ b/thirdparty/openxr/src/loader/loader_platform.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2023, The Khronos Group Inc.
+// Copyright (c) 2017-2024, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
diff --git a/thirdparty/openxr/src/loader/manifest_file.cpp b/thirdparty/openxr/src/loader/manifest_file.cpp
index 0683bc166a..f9699ece40 100644
--- a/thirdparty/openxr/src/loader/manifest_file.cpp
+++ b/thirdparty/openxr/src/loader/manifest_file.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2023, The Khronos Group Inc.
+// Copyright (c) 2017-2024, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
@@ -18,6 +18,7 @@
#endif // OPENXR_HAVE_COMMON_CONFIG
#include "filesystem_utils.hpp"
+#include "loader_init_data.hpp"
#include "loader_platform.hpp"
#include "platform_utils.hpp"
#include "loader_logger.hpp"
@@ -666,14 +667,14 @@ XrResult RuntimeManifestFile::FindManifestFiles(std::vector<std::unique_ptr<Runt
}
#else
-#if defined(XR_KHR_LOADER_INIT_SUPPORT)
+#if defined(XR_USE_PLATFORM_ANDROID)
Json::Value virtualManifest;
result = GetPlatformRuntimeVirtualManifest(virtualManifest);
if (XR_SUCCESS == result) {
RuntimeManifestFile::CreateIfValid(virtualManifest, "", manifest_files);
return result;
}
-#endif // defined(XR_KHR_LOADER_INIT_SUPPORT)
+#endif // defined(XR_USE_PLATFORM_ANDROID)
if (!PlatformGetGlobalRuntimeFileName(XR_VERSION_MAJOR(XR_CURRENT_API_VERSION), filename)) {
LoaderLogger::LogErrorMessage(
"", "RuntimeManifestFile::FindManifestFiles - failed to determine active runtime file path for this environment");
diff --git a/thirdparty/openxr/src/loader/manifest_file.hpp b/thirdparty/openxr/src/loader/manifest_file.hpp
index 46b842c663..52fe3134b0 100644
--- a/thirdparty/openxr/src/loader/manifest_file.hpp
+++ b/thirdparty/openxr/src/loader/manifest_file.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2023, The Khronos Group Inc.
+// Copyright (c) 2017-2024, The Khronos Group Inc.
// Copyright (c) 2017 Valve Corporation
// Copyright (c) 2017 LunarG, Inc.
//
diff --git a/thirdparty/openxr/src/loader/runtime_interface.cpp b/thirdparty/openxr/src/loader/runtime_interface.cpp
index 8312b15ba4..7812aca987 100644
--- a/thirdparty/openxr/src/loader/runtime_interface.cpp
+++ b/thirdparty/openxr/src/loader/runtime_interface.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2023, The Khronos Group Inc.
+// Copyright (c) 2017-2024, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
@@ -9,14 +9,15 @@
#include "runtime_interface.hpp"
+#include <openxr/openxr.h>
+#include <openxr/openxr_loader_negotiation.h>
+
#include "manifest_file.hpp"
-#include "loader_interfaces.h"
+#include "loader_init_data.hpp"
#include "loader_logger.hpp"
#include "loader_platform.hpp"
#include "xr_generated_dispatch_table_core.h"
-#include <openxr/openxr.h>
-
#include <cstring>
#include <memory>
#include <mutex>
@@ -26,8 +27,6 @@
#include <vector>
#ifdef XR_USE_PLATFORM_ANDROID
-#include "android_utilities.h"
-#include <android/asset_manager_jni.h>
#include <json/value.h>
// Needed for the loader init struct
@@ -35,112 +34,6 @@
#include <openxr/openxr_platform.h>
#endif // XR_USE_PLATFORM_ANDROID
-#ifdef XR_KHR_LOADER_INIT_SUPPORT
-namespace {
-/*!
- * Stores a copy of the data passed to the xrInitializeLoaderKHR function in a singleton.
- */
-class LoaderInitData {
- public:
- /*!
- * Singleton accessor.
- */
- static LoaderInitData& instance() {
- static LoaderInitData obj;
- return obj;
- }
-
-#ifdef XR_USE_PLATFORM_ANDROID
- /*!
- * Type alias for the platform-specific structure type.
- */
- using StructType = XrLoaderInitInfoAndroidKHR;
- /*!
- * Native library path.
- */
- std::string _native_library_path;
- /*!
- * Android asset manager.
- */
- AAssetManager* _android_asset_manager;
-#endif
-
- /*!
- * Get our copy of the data, casted to pass to the runtime's matching method.
- */
- const XrLoaderInitInfoBaseHeaderKHR* getParam() const { return reinterpret_cast<const XrLoaderInitInfoBaseHeaderKHR*>(&_data); }
-
- /*!
- * Get the data via its real structure type.
- */
- const StructType& getData() const { return _data; }
-
- /*!
- * Has this been correctly initialized?
- */
- bool initialized() const noexcept { return _initialized; }
-
- /*!
- * Initialize loader data - called by InitializeLoader() and thus ultimately by the loader's xrInitializeLoaderKHR
- * implementation. Each platform that needs this extension will provide an implementation of this.
- */
- XrResult initialize(const XrLoaderInitInfoBaseHeaderKHR* info);
-
- private:
- //! Private constructor, forces use of singleton accessor.
- LoaderInitData() = default;
- //! Platform-specific init data
- StructType _data = {};
- //! Flag for indicating whether _data is valid.
- bool _initialized = false;
-};
-
-#ifdef XR_USE_PLATFORM_ANDROID
-// Check and copy the Android-specific init data.
-XrResult LoaderInitData::initialize(const XrLoaderInitInfoBaseHeaderKHR* info) {
- if (info->type != XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR) {
- return XR_ERROR_VALIDATION_FAILURE;
- }
- auto cast_info = reinterpret_cast<XrLoaderInitInfoAndroidKHR const*>(info);
-
- if (cast_info->applicationVM == nullptr) {
- return XR_ERROR_VALIDATION_FAILURE;
- }
- if (cast_info->applicationContext == nullptr) {
- return XR_ERROR_VALIDATION_FAILURE;
- }
-
- // Copy and store the JVM pointer and Android Context, ensuring the JVM is initialised.
- _data = *cast_info;
- _data.next = nullptr;
- jni::init(static_cast<jni::JavaVM*>(_data.applicationVM));
- const jni::Object context = jni::Object{static_cast<jni::jobject>(_data.applicationContext)};
-
- // Retrieve a reference to the Android AssetManager.
- const auto assetManager = context.call<jni::Object>("getAssets()Landroid/content/res/AssetManager;");
- _android_asset_manager = AAssetManager_fromJava(jni::env(), assetManager.getHandle());
-
- // Retrieve the path to the native libraries.
- const auto applicationContext = context.call<jni::Object>("getApplicationContext()Landroid/content/Context;");
- const auto applicationInfo = context.call<jni::Object>("getApplicationInfo()Landroid/content/pm/ApplicationInfo;");
- _native_library_path = applicationInfo.get<std::string>("nativeLibraryDir");
-
- _initialized = true;
- return XR_SUCCESS;
-}
-#endif // XR_USE_PLATFORM_ANDROID
-} // namespace
-
-XrResult InitializeLoader(const XrLoaderInitInfoBaseHeaderKHR* loaderInitInfo) {
- return LoaderInitData::instance().initialize(loaderInitInfo);
-}
-
-std::string GetAndroidNativeLibraryDir() { return LoaderInitData::instance()._native_library_path; }
-
-void* Android_Get_Asset_Manager() { return LoaderInitData::instance()._android_asset_manager; }
-
-#endif // XR_KHR_LOADER_INIT_SUPPORT
-
#ifdef XR_USE_PLATFORM_ANDROID
XrResult GetPlatformRuntimeVirtualManifest(Json::Value& out_manifest) {
using wrap::android::content::Context;
diff --git a/thirdparty/openxr/src/loader/runtime_interface.hpp b/thirdparty/openxr/src/loader/runtime_interface.hpp
index 8d55ec674a..093f8ba767 100644
--- a/thirdparty/openxr/src/loader/runtime_interface.hpp
+++ b/thirdparty/openxr/src/loader/runtime_interface.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2023, The Khronos Group Inc.
+// Copyright (c) 2017-2024, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
@@ -19,22 +19,10 @@
#include <mutex>
#include <memory>
-#ifdef XR_USE_PLATFORM_ANDROID
-#define XR_KHR_LOADER_INIT_SUPPORT
-#endif
-
namespace Json {
class Value;
}
-#ifdef XR_KHR_LOADER_INIT_SUPPORT
-//! Initialize loader, where required.
-XrResult InitializeLoader(const XrLoaderInitInfoBaseHeaderKHR* loaderInitInfo);
-XrResult GetPlatformRuntimeVirtualManifest(Json::Value& out_manifest);
-std::string GetAndroidNativeLibraryDir();
-void* Android_Get_Asset_Manager();
-#endif
-
class RuntimeManifestFile;
struct XrGeneratedDispatchTable;
diff --git a/thirdparty/openxr/src/loader/xr_generated_loader.cpp b/thirdparty/openxr/src/loader/xr_generated_loader.cpp
index 8c79afddc5..7bddbdc3ea 100644
--- a/thirdparty/openxr/src/loader/xr_generated_loader.cpp
+++ b/thirdparty/openxr/src/loader/xr_generated_loader.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2023, The Khronos Group Inc.
+// Copyright (c) 2017-2024, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
// SPDX-License-Identifier: Apache-2.0 OR MIT
@@ -6,7 +6,7 @@
// See loader_source_generator.py for modifications
// ************************************************************
-// Copyright (c) 2017-2023, The Khronos Group Inc.
+// Copyright (c) 2017-2024, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
diff --git a/thirdparty/openxr/src/loader/xr_generated_loader.hpp b/thirdparty/openxr/src/loader/xr_generated_loader.hpp
index e28e35bbcf..68a6b9470d 100644
--- a/thirdparty/openxr/src/loader/xr_generated_loader.hpp
+++ b/thirdparty/openxr/src/loader/xr_generated_loader.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2023, The Khronos Group Inc.
+// Copyright (c) 2017-2024, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
// SPDX-License-Identifier: Apache-2.0 OR MIT
@@ -6,7 +6,7 @@
// See loader_source_generator.py for modifications
// ************************************************************
-// Copyright (c) 2017-2023, The Khronos Group Inc.
+// Copyright (c) 2017-2024, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
@@ -34,10 +34,9 @@
#include "xr_dependencies.h"
#include "openxr/openxr.h"
+#include "openxr/openxr_loader_negotiation.h"
#include "openxr/openxr_platform.h"
-#include "loader_interfaces.h"
-
#include "loader_instance.hpp"
#include "loader_platform.hpp"
diff --git a/thirdparty/openxr/src/xr_generated_dispatch_table_core.c b/thirdparty/openxr/src/xr_generated_dispatch_table_core.c
index de88ef7e6c..e73e8b2b95 100644
--- a/thirdparty/openxr/src/xr_generated_dispatch_table_core.c
+++ b/thirdparty/openxr/src/xr_generated_dispatch_table_core.c
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2023, The Khronos Group Inc.
+// Copyright (c) 2017-2024, The Khronos Group Inc.
// Copyright (c) 2017-2019, Valve Corporation
// Copyright (c) 2017-2019, LunarG, Inc.
@@ -8,7 +8,7 @@
// See utility_source_generator.py for modifications
// ************************************************************
-// Copyright (c) 2017-2023, The Khronos Group Inc.
+// Copyright (c) 2017-2024, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
diff --git a/thirdparty/openxr/src/xr_generated_dispatch_table_core.h b/thirdparty/openxr/src/xr_generated_dispatch_table_core.h
index 0f3e7e0502..5871231267 100644
--- a/thirdparty/openxr/src/xr_generated_dispatch_table_core.h
+++ b/thirdparty/openxr/src/xr_generated_dispatch_table_core.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2023, The Khronos Group Inc.
+// Copyright (c) 2017-2024, The Khronos Group Inc.
// Copyright (c) 2017-2019, Valve Corporation
// Copyright (c) 2017-2019, LunarG, Inc.
@@ -8,7 +8,7 @@
// See utility_source_generator.py for modifications
// ************************************************************
-// Copyright (c) 2017-2023, The Khronos Group Inc.
+// Copyright (c) 2017-2024, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
diff --git a/thirdparty/thorvg/AUTHORS b/thirdparty/thorvg/AUTHORS
index 3a459e9bb4..d5d5e9be97 100644
--- a/thirdparty/thorvg/AUTHORS
+++ b/thirdparty/thorvg/AUTHORS
@@ -23,3 +23,5 @@ Rafał Mikrut <mikrutrafal@protonmail.com>
Martin Capitanio <capnm@capitanio.org>
RuiwenTang <tangruiwen1989@gmail.com>
YouJin Lee <ol-of@naver.com>
+SergeyLebedkin <sergii@lottiefiles.com>
+Jinny You <jinny@lottiefiles.com>
diff --git a/thirdparty/thorvg/LICENSE b/thirdparty/thorvg/LICENSE
index d056ff6cbf..f97be65005 100644
--- a/thirdparty/thorvg/LICENSE
+++ b/thirdparty/thorvg/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2020 - 2023 notice for the ThorVG Project (see AUTHORS)
+Copyright (c) 2020 - 2024 notice for the ThorVG Project (see AUTHORS)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
diff --git a/thirdparty/thorvg/inc/config.h b/thirdparty/thorvg/inc/config.h
index 98f35a6e45..d1abc5a290 100644
--- a/thirdparty/thorvg/inc/config.h
+++ b/thirdparty/thorvg/inc/config.h
@@ -9,5 +9,5 @@
// For internal debugging:
//#define THORVG_LOG_ENABLED
-#define THORVG_VERSION_STRING "0.11.6"
+#define THORVG_VERSION_STRING "0.12.0"
#endif
diff --git a/thirdparty/thorvg/inc/thorvg.h b/thirdparty/thorvg/inc/thorvg.h
index 20acda7667..6aee53f7e0 100644
--- a/thirdparty/thorvg/inc/thorvg.h
+++ b/thirdparty/thorvg/inc/thorvg.h
@@ -1,17 +1,3 @@
-/*!
- * @file thorvg.h
- *
- * The main APIs enabling the TVG initialization, preparation of the canvas and provisioning of its content:
- * - drawing shapes: line, arc, curve, path, polygon...
- * - drawing pictures: tvg, svg, png, jpg, bitmap...
- * - drawing fillings: solid, linear and radial gradient...
- * - drawing stroking: continuous stroking with arbitrary width, join, cap, dash styles.
- * - drawing composition: blending, masking, path clipping...
- * - drawing scene graph & affine transformation (translation, rotation, scale, ...)
- * and finally drawing the canvas and TVG termination.
- */
-
-
#ifndef _THORVG_H_
#define _THORVG_H_
@@ -172,10 +158,10 @@ enum class CompositeMethod
InvAlphaMask, ///< Alpha Masking using the complement to the compositing target's pixels as an alpha value.
LumaMask, ///< Alpha Masking using the grayscale (0.2125R + 0.7154G + 0.0721*B) of the compositing target's pixels. @since 0.9
InvLumaMask, ///< Alpha Masking using the grayscale (0.2125R + 0.7154G + 0.0721*B) of the complement to the compositing target's pixels.
- AddMask, ///< Combines the target and source objects pixels using target alpha. (T * TA) + (S * (255 - TA)) @BETA_API
- SubtractMask, ///< Subtracts the source color from the target color while considering their respective target alpha. (T * TA) - (S * (255 - TA)) @BETA_API
- IntersectMask, ///< Computes the result by taking the minimum value between the target alpha and the source alpha and multiplies it with the target color. (T * min(TA, SA)) @BETA_API
- DifferenceMask ///< Calculates the absolute difference between the target color and the source color multiplied by the complement of the target alpha. abs(T - S * (255 - TA)) @BETA_API
+ AddMask, ///< Combines the target and source objects pixels using target alpha. (T * TA) + (S * (255 - TA)) (Experimental API)
+ SubtractMask, ///< Subtracts the source color from the target color while considering their respective target alpha. (T * TA) - (S * (255 - TA)) (Experimental API)
+ IntersectMask, ///< Computes the result by taking the minimum value between the target alpha and the source alpha and multiplies it with the target color. (T * min(TA, SA)) (Experimental API)
+ DifferenceMask ///< Calculates the absolute difference between the target color and the source color multiplied by the complement of the target alpha. abs(T - S * (255 - TA)) (Experimental API)
};
@@ -186,7 +172,7 @@ enum class CompositeMethod
*
* @see Paint::blend()
*
- * @BETA_API
+ * @note Experimental API
*/
enum class BlendMethod : uint8_t
{
@@ -213,7 +199,8 @@ enum class BlendMethod : uint8_t
enum class CanvasEngine
{
Sw = (1 << 1), ///< CPU rasterizer.
- Gl = (1 << 2) ///< OpenGL rasterizer.
+ Gl = (1 << 2), ///< OpenGL rasterizer.
+ Wg = (1 << 3), ///< WebGPU rasterizer. (Experimental API)
};
@@ -247,7 +234,7 @@ struct Matrix
* @param pt The vertex coordinate
* @param uv The normalized texture coordinate in the range (0.0..1.0, 0.0..1.0)
*
- * @BETA_API
+ * @note Experimental API
*/
struct Vertex
{
@@ -261,7 +248,7 @@ struct Vertex
*
* @param vertex The three vertices that make up the polygon
*
- * @BETA_API
+ * @note Experimental API
*/
struct Polygon
{
@@ -291,7 +278,7 @@ public:
*
* @param[in] degree The value of the angle in degrees.
*
- * @return Result::Success when succeed, Result::FailedAllocation otherwise.
+ * @retval Result::Success when succeed, Result::FailedAllocation otherwise.
*/
Result rotate(float degree) noexcept;
@@ -300,7 +287,7 @@ public:
*
* @param[in] factor The value of the scaling factor. The default value is 1.
*
- * @return Result::Success when succeed, Result::FailedAllocation otherwise.
+ * @retval Result::Success when succeed, Result::FailedAllocation otherwise.
*/
Result scale(float factor) noexcept;
@@ -313,7 +300,7 @@ public:
* @param[in] x The value of the horizontal shift.
* @param[in] y The value of the vertical shift.
*
- * @return Result::Success when succeed, Result::FailedAllocation otherwise.
+ * @retval Result::Success when succeed, Result::FailedAllocation otherwise.
*/
Result translate(float x, float y) noexcept;
@@ -324,7 +311,7 @@ public:
*
* @param[in] m The 3x3 augmented matrix.
*
- * @return Result::Success when succeed, Result::FailedAllocation otherwise.
+ * @retval Result::Success when succeed, Result::FailedAllocation otherwise.
*/
Result transform(const Matrix& m) noexcept;
@@ -345,7 +332,7 @@ public:
*
* @param[in] o The opacity value in the range [0 ~ 255], where 0 is completely transparent and 255 is opaque.
*
- * @return Result::Success when succeed.
+ * @retval Result::Success when succeed.
*
* @note Setting the opacity with this API may require multiple render pass for composition. It is recommended to avoid changing the opacity if possible.
* @note ClipPath won't use the opacity value. (see: enum class CompositeMethod::ClipPath)
@@ -358,7 +345,7 @@ public:
* @param[in] target The paint of the target object.
* @param[in] method The method used to composite the source object with the target.
*
- * @return Result::Success when succeed, Result::InvalidArguments otherwise.
+ * @retval Result::Success when succeed, Result::InvalidArguments otherwise.
*/
Result composite(std::unique_ptr<Paint> target, CompositeMethod method) noexcept;
@@ -371,9 +358,9 @@ public:
*
* @param[in] method The blending method to be set.
*
- * @return Result::Success when the blending method is successfully set.
+ * @retval Result::Success when the blending method is successfully set.
*
- * @BETA_API
+ * @note Experimental API
*/
Result blend(BlendMethod method) const noexcept;
@@ -404,7 +391,7 @@ public:
* @param[out] h The height of the object.
* @param[in] transformed If @c true, the paint's transformations are taken into account, otherwise they aren't.
*
- * @return Result::Success when succeed, Result::InsufficientCondition otherwise.
+ * @retval Result::Success when succeed, Result::InsufficientCondition otherwise.
*
* @note The bounding box doesn't indicate the actual drawing region. It's the smallest rectangle that encloses the object.
*/
@@ -442,7 +429,7 @@ public:
*
* @return The blending method
*
- * @BETA_API
+ * @note Experimental API
*/
BlendMethod blend() const noexcept;
@@ -493,7 +480,7 @@ public:
* @param[in] colorStops An array of ColorStop data structure.
* @param[in] cnt The count of the @p colorStops array equal to the colors number used in the gradient.
*
- * @return Result::Success when succeed.
+ * @retval Result::Success when succeed.
*/
Result colorStops(const ColorStop* colorStops, uint32_t cnt) noexcept;
@@ -502,7 +489,7 @@ public:
*
* @param[in] s The FillSpread value.
*
- * @return Result::Success when succeed.
+ * @retval Result::Success when succeed.
*/
Result spread(FillSpread s) noexcept;
@@ -513,7 +500,7 @@ public:
*
* @param[in] m The 3x3 augmented matrix.
*
- * @return Result::Success when succeed, Result::FailedAllocation otherwise.
+ * @retval Result::Success when succeed, Result::FailedAllocation otherwise.
*/
Result transform(const Matrix& m) noexcept;
@@ -538,7 +525,7 @@ public:
*
* In case no transformation was applied, the identity matrix is returned.
*
- * @retval The augmented transformation matrix.
+ * @return The augmented transformation matrix.
*/
Matrix transform() const noexcept;
@@ -600,7 +587,7 @@ public:
* @warning Please avoid accessing the paints during Canvas update/draw. You can access them after calling sync().
* @see Canvas::sync()
*
- * @BETA_API
+ * @note Experimental API
*/
std::list<Paint*>& paints() noexcept;
@@ -631,7 +618,7 @@ public:
*
* @param[in] free If @c true, the memory occupied by paints is deallocated, otherwise it is not.
*
- * @return Result::Success when succeed, Result::InsufficientCondition otherwise.
+ * @retval Result::Success when succeed, Result::InsufficientCondition otherwise.
*
* @see Canvas::push()
* @see Canvas::paints()
@@ -646,7 +633,7 @@ public:
*
* @param[in] paint A pointer to the Paint object or @c nullptr.
*
- * @return Result::Success when succeed, Result::InsufficientCondition otherwise.
+ * @retval Result::Success when succeed, Result::InsufficientCondition otherwise.
*
* @note The Update behavior can be asynchronous if the assigned thread number is greater than zero.
*/
@@ -655,7 +642,7 @@ public:
/**
* @brief Requests the canvas to draw the Paint objects.
*
- * @return Result::Success when succeed, Result::InsufficientCondition otherwise.
+ * @retval Result::Success when succeed, Result::InsufficientCondition otherwise.
*
* @note Drawing can be asynchronous if the assigned thread number is greater than zero. To guarantee the drawing is done, call sync() afterwards.
* @see Canvas::sync()
@@ -668,7 +655,7 @@ public:
* The Canvas rendering can be performed asynchronously. To make sure that rendering is finished,
* the sync() must be called after the draw() regardless of threading.
*
- * @return Result::Success when succeed, Result::InsufficientCondition otherwise.
+ * @retval Result::Success when succeed, Result::InsufficientCondition otherwise.
* @see Canvas::draw()
*/
virtual Result sync() noexcept;
@@ -702,7 +689,7 @@ public:
* @param[in] x2 The horizontal coordinate of the second point used to determine the gradient bounds.
* @param[in] y2 The vertical coordinate of the second point used to determine the gradient bounds.
*
- * @return Result::Success when succeed.
+ * @retval Result::Success when succeed.
*
* @note In case the first and the second points are equal, an object filled with such a gradient fill is not rendered.
*/
@@ -720,7 +707,7 @@ public:
* @param[out] x2 The horizontal coordinate of the second point used to determine the gradient bounds.
* @param[out] y2 The vertical coordinate of the second point used to determine the gradient bounds.
*
- * @return Result::Success when succeed.
+ * @retval Result::Success when succeed.
*/
Result linear(float* x1, float* y1, float* x2, float* y2) const noexcept;
@@ -764,7 +751,7 @@ public:
* @param[in] cy The vertical coordinate of the center of the bounding circle.
* @param[in] radius The radius of the bounding circle.
*
- * @return Result::Success when succeed, Result::InvalidArguments in case the @p radius value is zero or less.
+ * @retval Result::Success when succeed, Result::InvalidArguments in case the @p radius value is zero or less.
*/
Result radial(float cx, float cy, float radius) noexcept;
@@ -777,7 +764,7 @@ public:
* @param[out] cy The vertical coordinate of the center of the bounding circle.
* @param[out] radius The radius of the bounding circle.
*
- * @return Result::Success when succeed.
+ * @retval Result::Success when succeed.
*/
Result radial(float* cx, float* cy, float* radius) const noexcept;
@@ -823,7 +810,7 @@ public:
*
* The transformation matrix, the color, the fill and the stroke properties are retained.
*
- * @return Result::Success when succeed.
+ * @retval Result::Success when succeed.
*
* @note The memory, where the path data is stored, is not deallocated at this stage for caching effect.
*/
@@ -837,7 +824,7 @@ public:
* @param[in] x The horizontal coordinate of the initial point of the sub-path.
* @param[in] y The vertical coordinate of the initial point of the sub-path.
*
- * @return Result::Success when succeed.
+ * @retval Result::Success when succeed.
*/
Result moveTo(float x, float y) noexcept;
@@ -849,7 +836,7 @@ public:
* @param[in] x The horizontal coordinate of the end-point of the line.
* @param[in] y The vertical coordinate of the end-point of the line.
*
- * @return Result::Success when succeed.
+ * @retval Result::Success when succeed.
*
* @note In case this is the first command in the path, it corresponds to the moveTo() call.
*/
@@ -868,7 +855,7 @@ public:
* @param[in] x The horizontal coordinate of the end-point of the curve.
* @param[in] y The vertical coordinate of the end-point of the curve.
*
- * @return Result::Success when succeed.
+ * @retval Result::Success when succeed.
*
* @note In case this is the first command in the path, no data from the path are rendered.
*/
@@ -879,7 +866,7 @@ public:
*
* The value of the current point is set to the initial point of the closed sub-path.
*
- * @return Result::Success when succeed.
+ * @retval Result::Success when succeed.
*
* @note In case the sub-path does not contain any points, this function has no effect.
*/
@@ -905,7 +892,7 @@ public:
* @param[in] rx The x-axis radius of the ellipse defining the rounded corners of the rectangle.
* @param[in] ry The y-axis radius of the ellipse defining the rounded corners of the rectangle.
*
- * @return Result::Success when succeed.
+ * @retval Result::Success when succeed.
*
* @note For @p rx and @p ry greater than or equal to the half of @p w and the half of @p h, respectively, the shape become an ellipse.
*/
@@ -925,7 +912,7 @@ public:
* @param[in] rx The x-axis radius of the ellipse.
* @param[in] ry The y-axis radius of the ellipse.
*
- * @return Result::Success when succeed.
+ * @retval Result::Success when succeed.
*/
Result appendCircle(float cx, float cy, float rx, float ry) noexcept;
@@ -942,7 +929,7 @@ public:
* @param[in] sweep The central angle of the arc given in degrees, measured counter-clockwise from @p startAngle.
* @param[in] pie Specifies whether to draw radii from the arc's center to both of its end-point - drawn if @c true.
*
- * @return Result::Success when succeed.
+ * @retval Result::Success when succeed.
*
* @note Setting @p sweep value greater than 360 degrees, is equivalent to calling appendCircle(cx, cy, radius, radius).
*/
@@ -960,7 +947,7 @@ public:
* @param[in] pts The array of the two-dimensional points.
* @param[in] ptsCnt The number of the points in the @p pts array.
*
- * @return Result::Success when succeed, Result::InvalidArguments otherwise.
+ * @retval Result::Success when succeed, Result::InvalidArguments otherwise.
*
* @note The interface is designed for optimal path setting if the caller has a completed path commands already.
*/
@@ -971,7 +958,7 @@ public:
*
* @param[in] width The width of the stroke. The default value is 0.
*
- * @return Result::Success when succeed, Result::FailedAllocation otherwise.
+ * @retval Result::Success when succeed, Result::FailedAllocation otherwise.
*/
Result stroke(float width) noexcept;
@@ -983,7 +970,7 @@ public:
* @param[in] b The blue color channel value in the range [0 ~ 255]. The default value is 0.
* @param[in] a The alpha channel value in the range [0 ~ 255], where 0 is completely transparent and 255 is opaque. The default value is 0.
*
- * @return Result::Success when succeed, Result::FailedAllocation otherwise.
+ * @retval Result::Success when succeed, Result::FailedAllocation otherwise.
*/
Result stroke(uint8_t r, uint8_t g, uint8_t b, uint8_t a = 255) noexcept;
@@ -1018,7 +1005,7 @@ public:
*
* @param[in] cap The cap style value. The default value is @c StrokeCap::Square.
*
- * @return Result::Success when succeed, Result::FailedAllocation otherwise.
+ * @retval Result::Success when succeed, Result::FailedAllocation otherwise.
*/
Result stroke(StrokeCap cap) noexcept;
@@ -1029,7 +1016,7 @@ public:
*
* @param[in] join The join style value. The default value is @c StrokeJoin::Bevel.
*
- * @return Result::Success when succeed, Result::FailedAllocation otherwise.
+ * @retval Result::Success when succeed, Result::FailedAllocation otherwise.
*/
Result stroke(StrokeJoin join) noexcept;
@@ -1039,7 +1026,7 @@ public:
*
* @param[in] miterlimit The miterlimit imposes a limit on the extent of the stroke join, when the @c StrokeJoin::Miter join style is set. The default value is 4.
*
- * @return Result::Success when succeed, Result::NonSupport unsupported value, Result::FailedAllocation otherwise.
+ * @retval Result::Success when succeed, Result::NonSupport unsupported value, Result::FailedAllocation otherwise.
*
* @since 0.11
*/
@@ -1055,7 +1042,7 @@ public:
* @param[in] b The blue color channel value in the range [0 ~ 255]. The default value is 0.
* @param[in] a The alpha channel value in the range [0 ~ 255], where 0 is completely transparent and 255 is opaque. The default value is 0.
*
- * @return Result::Success when succeed.
+ * @retval Result::Success when succeed.
*
* @note Either a solid color or a gradient fill is applied, depending on what was set as last.
* @note ClipPath won't use the fill values. (see: enum class CompositeMethod::ClipPath)
@@ -1069,7 +1056,7 @@ public:
*
* @param[in] f The unique pointer to the gradient fill.
*
- * @return Result::Success when succeed, Result::MemoryCorruption otherwise.
+ * @retval Result::Success when succeed, Result::MemoryCorruption otherwise.
*
* @note Either a solid color or a gradient fill is applied, depending on what was set as last.
*/
@@ -1080,7 +1067,7 @@ public:
*
* @param[in] r The fill rule value. The default value is @c FillRule::Winding.
*
- * @return Result::Success when succeed.
+ * @retval Result::Success when succeed.
*/
Result fill(FillRule r) noexcept;
@@ -1090,7 +1077,7 @@ public:
*
* @param[in] strokeFirst If @c true the stroke is rendered before the fill, otherwise the stroke is rendered as the second one (the default option).
*
- * @return Result::Success when succeed, Result::FailedAllocation otherwise.
+ * @retval Result::Success when succeed, Result::FailedAllocation otherwise.
*
* @since 0.10
*/
@@ -1156,7 +1143,7 @@ public:
* @param[out] b The blue color channel value in the range [0 ~ 255].
* @param[out] a The alpha channel value in the range [0 ~ 255], where 0 is completely transparent and 255 is opaque.
*
- * @return Result::Success when succeed, Result::InsufficientCondition otherwise.
+ * @retval Result::Success when succeed, Result::InsufficientCondition otherwise.
*/
Result strokeColor(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a = nullptr) const noexcept;
@@ -1295,7 +1282,7 @@ public:
* @param[in] w A new width of the image in pixels.
* @param[in] h A new height of the image in pixels.
*
- * @return Result::Success when succeed, Result::InsufficientCondition otherwise.
+ * @retval Result::Success when succeed, Result::InsufficientCondition otherwise.
*/
Result size(float w, float h) noexcept;
@@ -1305,13 +1292,20 @@ public:
* @param[out] w The width of the image in pixels.
* @param[out] h The height of the image in pixels.
*
- * @return Result::Success when succeed.
+ * @retval Result::Success when succeed.
*/
Result size(float* w, float* h) const noexcept;
/**
* @brief Loads a raw data from a memory block with a given size.
*
+ * @param[in] paint A Tvg_Paint pointer to the picture object.
+ * @param[in] data A pointer to a memory location where the content of the picture raw data is stored.
+ * @param[in] w The width of the image @p data in pixels.
+ * @param[in] h The height of the image @p data in pixels.
+ * @param[in] premultiplied If @c true, the given image data is alpha-premultiplied.
+ * @param[in] copy If @c true the data are copied into the engine local buffer, otherwise they are not.
+ *
* @retval Result::Success When succeed, Result::InsufficientCondition otherwise.
* @retval Result::FailedAllocation An internal error possibly with memory allocation.
*
@@ -1339,7 +1333,7 @@ public:
* @note The Polygons are copied internally, so modifying them after calling Mesh::mesh has no affect.
* @warning Please do not use it, this API is not official one. It could be modified in the next version.
*
- * @BETA_API
+ * @note Experimental API
*/
Result mesh(const Polygon* triangles, uint32_t triangleCnt) noexcept;
@@ -1348,12 +1342,12 @@ public:
*
* @param[out] triangles Optional. A pointer to the array of Polygons used by this mesh.
*
- * @return uint32_t The number of polygons in the array.
+ * @return The number of polygons in the array.
*
* @note Modifying the triangles returned by this method will modify them directly within the mesh.
* @warning Please do not use it, this API is not official one. It could be modified in the next version.
*
- * @BETA_API
+ * @note Experimental API
*/
uint32_t mesh(const Polygon** triangles) const noexcept;
@@ -1402,7 +1396,7 @@ public:
*
* @param[in] paint A Paint object to be drawn.
*
- * @return Result::Success when succeed, Result::MemoryCorruption otherwise.
+ * @retval Result::Success when succeed, Result::MemoryCorruption otherwise.
*
* @note The rendering order of the paints is the same as the order as they were pushed. Consider sorting the paints before pushing them if you intend to use layering.
* @see Scene::paints()
@@ -1432,7 +1426,7 @@ public:
* @see Scene::push()
* @see Scene::clear()
*
- * @BETA_API
+ * @note Experimental API
*/
std::list<Paint*>& paints() noexcept;
@@ -1442,7 +1436,7 @@ public:
*
* @param[in] free If @c true, the memory occupied by paints is deallocated, otherwise it is not.
*
- * @return Result::Success when succeed
+ * @retval Result::Success when succeed
*
* @warning If you don't free the paints they become dangled. They are supposed to be reused, otherwise you are responsible for their lives. Thus please use the @p free argument only when you know how it works, otherwise it's not recommended.
*
@@ -1471,6 +1465,138 @@ public:
/**
+ * @class Text
+ *
+ * @brief A class to represent text objects in a graphical context, allowing for rendering and manipulation of unicode text.
+ *
+ * @note Experimental API
+ */
+class TVG_API Text final : public Paint
+{
+public:
+ ~Text();
+
+ /**
+ * @brief Sets the font properties for the text.
+ *
+ * This function allows you to define the font characteristics used for text rendering.
+ * It sets the font name, size and optionally the style.
+ *
+ * @param[in] name The name of the font. This should correspond to a font available in the canvas.
+ * @param[in] size The size of the font in points. This determines how large the text will appear.
+ * @param[in] style The style of the font. It can be used to set the font to 'italic'.
+ * If not specified, the default style is used. Only 'italic' style is supported currently.
+ *
+ * @retval Result::Success when the font properties are set successfully.
+ * @retval Result::InsufficientCondition when the specified @p name cannot be found.
+ *
+ * @note Experimental API
+ */
+ Result font(const char* name, float size, const char* style = nullptr) noexcept;
+
+ /**
+ * @brief Assigns the given unicode text to be rendered.
+ *
+ * This function sets the unicode string that will be displayed by the rendering system.
+ * The text is set according to the specified UTF encoding method, which defaults to UTF-8.
+ *
+ * @param[in] text The multi-byte text encoded with utf8 string to be rendered.
+ *
+ * @retval Result::Success when succeed.
+ *
+ * @note Experimental API
+ */
+ Result text(const char* text) noexcept;
+
+ /**
+ * @brief Sets the text color.
+ *
+ * @param[in] r The red color channel value in the range [0 ~ 255]. The default value is 0.
+ * @param[in] g The green color channel value in the range [0 ~ 255]. The default value is 0.
+ * @param[in] b The blue color channel value in the range [0 ~ 255]. The default value is 0.
+ *
+ * @retval Result::Success when succeed.
+ * @retval Result::InsufficientCondition when the font has not been set up prior to this operation.
+ *
+ * @see Text::font()
+ *
+ * @note Experimental API
+ */
+ Result fill(uint8_t r, uint8_t g, uint8_t b) noexcept;
+
+ /**
+ * @brief Sets the gradient fill for all of the figures from the text.
+ *
+ * The parts of the text defined as inner are filled.
+ *
+ * @param[in] f The unique pointer to the gradient fill.
+ *
+ * @retval Result::Success when succeed, Result::MemoryCorruption otherwise.
+ * @retval Result::InsufficientCondition when the font has not been set up prior to this operation.
+ *
+ * @note Either a solid color or a gradient fill is applied, depending on what was set as last.
+ * @note Experimental API
+ *
+ * @see Text::font()
+ */
+ Result fill(std::unique_ptr<Fill> f) noexcept;
+
+ /**
+ * @brief Loads a scalable font data(ttf) from a file.
+ *
+ * @param[in] path The path to the font file.
+ *
+ * @retval Result::Success When succeed.
+ * @retval Result::InvalidArguments In case the @p path is invalid.
+ * @retval Result::NonSupport When trying to load a file with an unknown extension.
+ * @retval Result::Unknown If an error occurs at a later stage.
+ *
+ * @note Experimental API
+ *
+ * @see Text::unload(const std::string& path)
+ */
+ static Result load(const std::string& path) noexcept;
+
+ /**
+ * @brief Unloads the specified scalable font data (TTF) that was previously loaded.
+ *
+ * This function is used to release resources associated with a font file that has been loaded into memory.
+ *
+ * @param[in] path The file path of the loaded font.
+ *
+ * @retval Result::Success Successfully unloads the font data.
+ * @retval Result::InsufficientCondition Fails if the loader is not initialized.
+ *
+ * @note If the font data is currently in use, it will not be immediately unloaded.
+ * @note Experimental API
+ *
+ * @see Text::load(const std::string& path)
+ */
+ static Result unload(const std::string& path) noexcept;
+
+ /**
+ * @brief Creates a new Text object.
+ *
+ * @return A new Text object.
+ *
+ * @note Experimental API
+ */
+ static std::unique_ptr<Text> gen() noexcept;
+
+ /**
+ * @brief Return the unique id value of this class.
+ *
+ * This method can be referred for identifying the Text class type.
+ *
+ * @return The type id of the Text class.
+ */
+ static uint32_t identifier() noexcept;
+
+ _TVG_DECLARE_PRIVATE(Text);
+};
+
+
+/**
* @class SwCanvas
*
* @brief A class for the rendering graphical elements with a software raster engine.
@@ -1487,8 +1613,8 @@ public:
{
ABGR8888 = 0, ///< The channels are joined in the order: alpha, blue, green, red. Colors are alpha-premultiplied. (a << 24 | b << 16 | g << 8 | r)
ARGB8888, ///< The channels are joined in the order: alpha, red, green, blue. Colors are alpha-premultiplied. (a << 24 | r << 16 | g << 8 | b)
- ABGR8888S, ///< @BETA_API The channels are joined in the order: alpha, blue, green, red. Colors are un-alpha-premultiplied.
- ARGB8888S, ///< @BETA_API The channels are joined in the order: alpha, red, green, blue. Colors are un-alpha-premultiplied.
+ ABGR8888S, ///< The channels are joined in the order: alpha, blue, green, red. Colors are un-alpha-premultiplied. @since 0.12
+ ARGB8888S, ///< The channels are joined in the order: alpha, red, green, blue. Colors are un-alpha-premultiplied. @since 0.12
};
/**
@@ -1564,7 +1690,7 @@ public:
*
* @warning Please do not use it. This class is not fully supported yet.
*
- * @BETA_API
+ * @note Experimental API
*/
class TVG_API GlCanvas final : public Canvas
{
@@ -1576,7 +1702,7 @@ public:
*
* @warning Please do not use it, this API is not official one. It could be modified in the next version.
*
- * @BETA_API
+ * @note Experimental API
*/
Result target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h) noexcept;
@@ -1585,7 +1711,7 @@ public:
*
* @return A new GlCanvas object.
*
- * @BETA_API
+ * @note Experimental API
*/
static std::unique_ptr<GlCanvas> gen() noexcept;
@@ -1594,6 +1720,42 @@ public:
/**
+ * @class WgCanvas
+ *
+ * @brief A class for the rendering graphic elements with a WebGPU raster engine.
+ *
+ * @warning Please do not use it. This class is not fully supported yet.
+ *
+ * @note Experimental API
+ */
+class TVG_API WgCanvas final : public Canvas
+{
+public:
+ ~WgCanvas();
+
+ /**
+ * @brief Sets the target window for the rasterization.
+ *
+ * @warning Please do not use it, this API is not official one. It could be modified in the next version.
+ *
+ * @note Experimental API
+ */
+ Result target(void* window, uint32_t w, uint32_t h) noexcept;
+
+ /**
+ * @brief Creates a new WgCanvas object.
+ *
+ * @return A new WgCanvas object.
+ *
+ * @note Experimental API
+ */
+ static std::unique_ptr<WgCanvas> gen() noexcept;
+
+ _TVG_DECLARE_PRIVATE(WgCanvas);
+};
+
+
+/**
* @class Initializer
*
* @brief A class that enables initialization and termination of the TVG engines.
@@ -1650,7 +1812,7 @@ public:
*
* This class supports the display and control of animation frames.
*
- * @BETA_API
+ * @note Experimental API
*/
class TVG_API Animation
@@ -1669,7 +1831,7 @@ public:
*
* @see totalFrame()
*
- * @BETA_API
+ * @note Experimental API
*/
Result frame(float no) noexcept;
@@ -1684,7 +1846,7 @@ public:
*
* @warning The picture instance is owned by Animation. It should not be deleted manually.
*
- * @BETA_API
+ * @note Experimental API
*/
Picture* picture() const noexcept;
@@ -1698,7 +1860,7 @@ public:
* @see Animation::frame(float no)
* @see Animation::totalFrame()
*
- * @BETA_API
+ * @note Experimental API
*/
float curFrame() const noexcept;
@@ -1710,7 +1872,7 @@ public:
* @note Frame numbering starts from 0.
* @note If the Picture is not properly configured, this function will return 0.
*
- * @BETA_API
+ * @note Experimental API
*/
float totalFrame() const noexcept;
@@ -1721,7 +1883,7 @@ public:
*
* @note If the Picture is not properly configured, this function will return 0.
*
- * @BETA_API
+ * @% Experimental API
*/
float duration() const noexcept;
@@ -1730,7 +1892,7 @@ public:
*
* @return A new Animation object.
*
- * @BETA_API
+ * @note Experimental API
*/
static std::unique_ptr<Animation> gen() noexcept;
@@ -1761,6 +1923,15 @@ public:
~Saver();
/**
+ * @brief Sets the base background content for the saved image.
+ *
+ * @param[in] paint The paint to be drawn as the background image for the saving paint.
+ *
+ * @note Experimental API
+ */
+ Result background(std::unique_ptr<Paint> paint) noexcept;
+
+ /**
* @brief Exports the given @p paint data to the given @p path
*
* If the saver module supports any compression mechanism, it will optimize the data size.
@@ -1794,18 +1965,18 @@ public:
* @param[in] quality The encoded quality level. @c 0 is the minimum, @c 100 is the maximum value(recommended).
* @param[in] fps The desired frames per second (FPS). For example, to encode data at 60 FPS, pass 60. Pass 0 to keep the original frame data.
*
- * @return Result::Success if the export succeeds.
- * @return Result::InsufficientCondition if there are ongoing resource-saving operations.
- * @return Result::NonSupport if an attempt is made to save the file with an unknown extension or in an unsupported format.
- * @return Result::MemoryCorruption in case of an internal error.
- * @return Result::Unknown if attempting to save an empty paint.
+ * @retval Result::Success if the export succeeds.
+ * @retval Result::InsufficientCondition if there are ongoing resource-saving operations.
+ * @retval Result::NonSupport if an attempt is made to save the file with an unknown extension or in an unsupported format.
+ * @retval Result::MemoryCorruption in case of an internal error.
+ * @retval Result::Unknown if attempting to save an empty paint.
*
* @note A higher frames per second (FPS) would result in a larger file size. It is recommended to use the default value.
* @note Saving can be asynchronous if the assigned thread number is greater than zero. To guarantee the saving is done, call sync() afterwards.
*
* @see Saver::sync()
*
- * @note: Experimental API
+ * @note Experimental API
*/
Result save(std::unique_ptr<Animation> animation, const std::string& path, uint32_t quality = 100, uint32_t fps = 0) noexcept;
@@ -1882,7 +2053,7 @@ public:
* @brief The cast() function is a utility function used to cast a 'Paint' to type 'T'.
* @since 0.11
*/
-template<typename T>
+template<typename T = tvg::Paint>
std::unique_ptr<T> cast(Paint* paint)
{
return std::unique_ptr<T>(static_cast<T*>(paint));
@@ -1893,7 +2064,7 @@ std::unique_ptr<T> cast(Paint* paint)
* @brief The cast() function is a utility function used to cast a 'Fill' to type 'T'.
* @since 0.11
*/
-template<typename T>
+template<typename T = tvg::Fill>
std::unique_ptr<T> cast(Fill* fill)
{
return std::unique_ptr<T>(static_cast<T*>(fill));
diff --git a/thirdparty/thorvg/src/common/tvgArray.h b/thirdparty/thorvg/src/common/tvgArray.h
index 1afc647b68..acb3a41b97 100644
--- a/thirdparty/thorvg/src/common/tvgArray.h
+++ b/thirdparty/thorvg/src/common/tvgArray.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -39,6 +39,11 @@ struct Array
Array(){}
+ Array(int32_t size)
+ {
+ reserve(size);
+ }
+
Array(const Array& rhs)
{
reset();
diff --git a/thirdparty/thorvg/src/common/tvgBezier.cpp b/thirdparty/thorvg/src/common/tvgBezier.cpp
index f9daf07b84..5fb501721e 100644
--- a/thirdparty/thorvg/src/common/tvgBezier.cpp
+++ b/thirdparty/thorvg/src/common/tvgBezier.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
diff --git a/thirdparty/thorvg/src/common/tvgBezier.h b/thirdparty/thorvg/src/common/tvgBezier.h
index 539a63bdd3..cb2766c505 100644
--- a/thirdparty/thorvg/src/common/tvgBezier.h
+++ b/thirdparty/thorvg/src/common/tvgBezier.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
diff --git a/thirdparty/thorvg/src/common/tvgCompressor.cpp b/thirdparty/thorvg/src/common/tvgCompressor.cpp
index e38940f3d0..778fc4d0a2 100644
--- a/thirdparty/thorvg/src/common/tvgCompressor.cpp
+++ b/thirdparty/thorvg/src/common/tvgCompressor.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
diff --git a/thirdparty/thorvg/src/common/tvgCompressor.h b/thirdparty/thorvg/src/common/tvgCompressor.h
index 05d23f4293..0756127ec6 100644
--- a/thirdparty/thorvg/src/common/tvgCompressor.h
+++ b/thirdparty/thorvg/src/common/tvgCompressor.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
diff --git a/thirdparty/thorvg/src/common/tvgInlist.h b/thirdparty/thorvg/src/common/tvgInlist.h
new file mode 100644
index 0000000000..ff28cfd48e
--- /dev/null
+++ b/thirdparty/thorvg/src/common/tvgInlist.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2023 - 2024 the ThorVG project. All rights reserved.
+
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _TVG_INLIST_H_
+#define _TVG_INLIST_H_
+
+namespace tvg {
+
+//NOTE: declare this in your list item
+#define INLIST_ITEM(T) \
+ T* prev; \
+ T* next
+
+template<typename T>
+struct Inlist
+{
+ T* head = nullptr;
+ T* tail = nullptr;
+
+ void free()
+ {
+ while (head) {
+ auto t = head;
+ head = t->next;
+ delete(t);
+ }
+ head = tail = nullptr;
+ }
+
+ void back(T* element)
+ {
+ if (tail) {
+ tail->next = element;
+ element->prev = tail;
+ element->next = nullptr;
+ tail = element;
+ } else {
+ head = tail = element;
+ element->prev = nullptr;
+ element->next = nullptr;
+ }
+ }
+
+ void front(T* element)
+ {
+ if (head) {
+ head->prev = element;
+ element->prev = nullptr;
+ element->next = head;
+ head = element;
+ } else {
+ head = tail = element;
+ element->prev = nullptr;
+ element->next = nullptr;
+ }
+ }
+
+ T* back()
+ {
+ if (!tail) return nullptr;
+ auto t = tail;
+ tail = t->prev;
+ if (!tail) head = nullptr;
+ return t;
+ }
+
+ T* front()
+ {
+ if (!head) return nullptr;
+ auto t = head;
+ head = t->next;
+ if (!head) tail = nullptr;
+ return t;
+ }
+
+ void remove(T* element)
+ {
+ if (element->prev) element->prev->next = element->next;
+ if (element->next) element->next->prev = element->prev;
+ if (element == head) head = element->next;
+ if (element == tail) tail = element->prev;
+ }
+
+ bool empty()
+ {
+ return head ? false : true;
+ }
+};
+
+}
+
+#endif // _TVG_INLIST_H_
diff --git a/thirdparty/thorvg/src/common/tvgList.h b/thirdparty/thorvg/src/common/tvgList.h
deleted file mode 100644
index 01e87a840f..0000000000
--- a/thirdparty/thorvg/src/common/tvgList.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (c) 2023 the ThorVG project. All rights reserved.
-
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
-
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
-
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#ifndef _TVG_LIST_H_
-#define _TVG_LIST_H_
-
-namespace tvg {
-
-template<typename T>
-struct LinkedList
-{
- T *head = nullptr;
- T *tail = nullptr;
-
- LinkedList() = default;
- LinkedList(T *head, T *tail) : head(head), tail(tail)
- {
- }
-
- template<T *T::*Prev, T *T::*Next>
- static void insert(T *t, T *prev, T *next, T **head, T **tail)
- {
- t->*Prev = prev;
- t->*Next = next;
-
- if (prev) {
- prev->*Next = t;
- } else if (head) {
- *head = t;
- }
-
- if (next) {
- next->*Prev = t;
- } else if (tail) {
- *tail = t;
- }
- }
-
- template<T *T::*Prev, T *T::*Next>
- static void remove(T *t, T **head, T **tail)
- {
- if (t->*Prev) {
- t->*Prev->*Next = t->*Next;
- } else if (head) {
- *head = t->*Next;
- }
-
- if (t->*Next) {
- t->*Next->*Prev = t->*Prev;
- } else if (tail) {
- *tail = t->*Prev;
- }
-
- t->*Prev = t->*Next = nullptr;
- }
-
- template <T* T::*Next>
- static bool contains(T *t, T **head, T **tail) {
- for (T *it = *head; it; it = it->*Next) {
- if (it == t) {
- return true;
- }
- }
-
- return false;
- }
-};
-
-}
-
-#endif // _TVG_LIST_H_
diff --git a/thirdparty/thorvg/src/common/tvgMath.cpp b/thirdparty/thorvg/src/common/tvgMath.cpp
index a9463c8077..42bc2cf4aa 100644
--- a/thirdparty/thorvg/src/common/tvgMath.cpp
+++ b/thirdparty/thorvg/src/common/tvgMath.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2021 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
diff --git a/thirdparty/thorvg/src/common/tvgMath.h b/thirdparty/thorvg/src/common/tvgMath.h
index 004fff1e7b..50c3458efc 100644
--- a/thirdparty/thorvg/src/common/tvgMath.h
+++ b/thirdparty/thorvg/src/common/tvgMath.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2021 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -174,6 +174,18 @@ static inline Point operator*(const Point& lhs, float rhs)
}
+static inline Point operator*(const float& lhs, const Point& rhs)
+{
+ return {lhs * rhs.x, lhs * rhs.y};
+}
+
+
+static inline Point operator/(const Point& lhs, const float rhs)
+{
+ return {lhs.x / rhs, lhs.y / rhs};
+}
+
+
template <typename T>
static inline T mathLerp(const T &start, const T &end, float t)
{
diff --git a/thirdparty/thorvg/src/common/tvgStr.cpp b/thirdparty/thorvg/src/common/tvgStr.cpp
index eeed4fc404..311b986511 100644
--- a/thirdparty/thorvg/src/common/tvgStr.cpp
+++ b/thirdparty/thorvg/src/common/tvgStr.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
diff --git a/thirdparty/thorvg/src/common/tvgStr.h b/thirdparty/thorvg/src/common/tvgStr.h
index 448cc69336..9e5f9ba9b5 100644
--- a/thirdparty/thorvg/src/common/tvgStr.h
+++ b/thirdparty/thorvg/src/common/tvgStr.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
diff --git a/thirdparty/thorvg/src/loaders/external_png/tvgPngLoader.cpp b/thirdparty/thorvg/src/loaders/external_png/tvgPngLoader.cpp
index 30a66f9cad..10277f846d 100644
--- a/thirdparty/thorvg/src/loaders/external_png/tvgPngLoader.cpp
+++ b/thirdparty/thorvg/src/loaders/external_png/tvgPngLoader.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -20,19 +20,25 @@
* SOFTWARE.
*/
-#include "tvgLoader.h"
#include "tvgPngLoader.h"
/************************************************************************/
/* Internal Class Implementation */
/************************************************************************/
+void PngLoader::clear()
+{
+ png_image_free(image);
+ free(image);
+ image = nullptr;
+}
+
/************************************************************************/
/* External Class Implementation */
/************************************************************************/
-PngLoader::PngLoader()
+PngLoader::PngLoader() : ImageLoader(FileType::Png)
{
image = static_cast<png_imagep>(calloc(1, sizeof(png_image)));
image->version = PNG_IMAGE_VERSION;
@@ -41,13 +47,11 @@ PngLoader::PngLoader()
PngLoader::~PngLoader()
{
- if (content) {
- free((void*)content);
- content = nullptr;
- }
- free(image);
+ clear();
+ free((void*)surface.buf32);
}
+
bool PngLoader::open(const string& path)
{
image->opaque = NULL;
@@ -56,11 +60,11 @@ bool PngLoader::open(const string& path)
w = (float)image->width;
h = (float)image->height;
- cs = ColorSpace::ARGB8888;
return true;
}
+
bool PngLoader::open(const char* data, uint32_t size, bool copy)
{
image->opaque = NULL;
@@ -69,7 +73,6 @@ bool PngLoader::open(const char* data, uint32_t size, bool copy)
w = (float)image->width;
h = (float)image->height;
- cs = ColorSpace::ARGB8888;
return true;
}
@@ -77,6 +80,10 @@ bool PngLoader::open(const char* data, uint32_t size, bool copy)
bool PngLoader::read()
{
+ if (!LoadModule::read()) return true;
+
+ if (w == 0 || h == 0) return false;
+
png_bytep buffer;
image->format = PNG_FORMAT_BGRA;
buffer = static_cast<png_bytep>(malloc(PNG_IMAGE_SIZE((*image))));
@@ -89,32 +96,17 @@ bool PngLoader::read()
free(buffer);
return false;
}
- content = reinterpret_cast<uint32_t*>(buffer);
- return true;
-}
+ //setup the surface
+ surface.buf32 = reinterpret_cast<uint32_t*>(buffer);
+ surface.stride = (uint32_t)w;
+ surface.w = (uint32_t)w;
+ surface.h = (uint32_t)h;
+ surface.channelSize = sizeof(uint32_t);
+ surface.cs = ColorSpace::ARGB8888;
+ surface.premultiplied = false;
-bool PngLoader::close()
-{
- png_image_free(image);
- return true;
-}
+ clear();
-unique_ptr<Surface> PngLoader::bitmap()
-{
- if (!content) return nullptr;
-
- //TODO: It's better to keep this surface instance in the loader side
- auto surface = new Surface;
- surface->buf32 = content;
- surface->stride = (uint32_t)w;
- surface->w = (uint32_t)w;
- surface->h = (uint32_t)h;
- surface->cs = cs;
- surface->channelSize = sizeof(uint32_t);
- surface->owner = true;
- surface->premultiplied = false;
-
- return unique_ptr<Surface>(surface);
+ return true;
}
-
diff --git a/thirdparty/thorvg/src/loaders/external_png/tvgPngLoader.h b/thirdparty/thorvg/src/loaders/external_png/tvgPngLoader.h
index 5354e1bdd6..c45544eb07 100644
--- a/thirdparty/thorvg/src/loaders/external_png/tvgPngLoader.h
+++ b/thirdparty/thorvg/src/loaders/external_png/tvgPngLoader.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -24,24 +24,22 @@
#define _TVG_PNG_LOADER_H_
#include <png.h>
+#include "tvgLoader.h"
-class PngLoader : public LoadModule
+class PngLoader : public ImageLoader
{
public:
PngLoader();
~PngLoader();
- using LoadModule::open;
bool open(const string& path) override;
bool open(const char* data, uint32_t size, bool copy) override;
bool read() override;
- bool close() override;
-
- unique_ptr<Surface> bitmap() override;
private:
+ void clear();
+
png_imagep image = nullptr;
- uint32_t* content = nullptr;
};
#endif //_TVG_PNG_LOADER_H_
diff --git a/thirdparty/thorvg/src/loaders/jpg/tvgJpgLoader.cpp b/thirdparty/thorvg/src/loaders/jpg/tvgJpgLoader.cpp
index 6edda86cc1..86a46245d9 100644
--- a/thirdparty/thorvg/src/loaders/jpg/tvgJpgLoader.cpp
+++ b/thirdparty/thorvg/src/loaders/jpg/tvgJpgLoader.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2021 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -21,7 +21,6 @@
*/
#include <memory.h>
-#include "tvgLoader.h"
#include "tvgJpgLoader.h"
/************************************************************************/
@@ -38,30 +37,45 @@ void JpgLoader::clear()
}
+void JpgLoader::run(unsigned tid)
+{
+ surface.buf8 = jpgdDecompress(decoder);
+ surface.stride = static_cast<uint32_t>(w);
+ surface.w = static_cast<uint32_t>(w);
+ surface.h = static_cast<uint32_t>(h);
+ surface.cs = ColorSpace::ARGB8888;
+ surface.channelSize = sizeof(uint32_t);
+ surface.premultiplied = true;
+
+ clear();
+}
+
+
/************************************************************************/
/* External Class Implementation */
/************************************************************************/
+JpgLoader::JpgLoader() : ImageLoader(FileType::Jpg)
+{
+
+}
+
JpgLoader::~JpgLoader()
{
- jpgdDelete(decoder);
- if (freeData) free(data);
- free(image);
+ clear();
+ free(surface.buf8);
}
bool JpgLoader::open(const string& path)
{
- clear();
-
int width, height;
decoder = jpgdHeader(path.c_str(), &width, &height);
if (!decoder) return false;
w = static_cast<float>(width);
h = static_cast<float>(height);
- cs = ColorSpace::ARGB8888;
return true;
}
@@ -69,8 +83,6 @@ bool JpgLoader::open(const string& path)
bool JpgLoader::open(const char* data, uint32_t size, bool copy)
{
- clear();
-
if (copy) {
this->data = (char *) malloc(size);
if (!this->data) return false;
@@ -87,7 +99,6 @@ bool JpgLoader::open(const char* data, uint32_t size, bool copy)
w = static_cast<float>(width);
h = static_cast<float>(height);
- cs = ColorSpace::ARGB8888;
return true;
}
@@ -96,7 +107,9 @@ bool JpgLoader::open(const char* data, uint32_t size, bool copy)
bool JpgLoader::read()
{
- if (!decoder || w <= 0 || h <= 0) return false;
+ if (!LoadModule::read()) return true;
+
+ if (!decoder || w == 0 || h == 0) return false;
TaskScheduler::request(this);
@@ -106,38 +119,14 @@ bool JpgLoader::read()
bool JpgLoader::close()
{
+ if (!LoadModule::close()) return false;
this->done();
- clear();
return true;
}
-unique_ptr<Surface> JpgLoader::bitmap()
+Surface* JpgLoader::bitmap()
{
this->done();
-
- if (!image) return nullptr;
-
- //TODO: It's better to keep this surface instance in the loader side
- auto surface = new Surface;
- surface->buf8 = image;
- surface->stride = static_cast<uint32_t>(w);
- surface->w = static_cast<uint32_t>(w);
- surface->h = static_cast<uint32_t>(h);
- surface->cs = cs;
- surface->channelSize = sizeof(uint32_t);
- surface->premultiplied = true;
- surface->owner = true;
-
- return unique_ptr<Surface>(surface);
-}
-
-
-void JpgLoader::run(unsigned tid)
-{
- if (image) {
- free(image);
- image = nullptr;
- }
- image = jpgdDecompress(decoder);
+ return ImageLoader::bitmap();
}
diff --git a/thirdparty/thorvg/src/loaders/jpg/tvgJpgLoader.h b/thirdparty/thorvg/src/loaders/jpg/tvgJpgLoader.h
index 6d2febe94f..05cbb54c85 100644
--- a/thirdparty/thorvg/src/loaders/jpg/tvgJpgLoader.h
+++ b/thirdparty/thorvg/src/loaders/jpg/tvgJpgLoader.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2021 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -23,30 +23,30 @@
#ifndef _TVG_JPG_LOADER_H_
#define _TVG_JPG_LOADER_H_
+#include "tvgLoader.h"
#include "tvgTaskScheduler.h"
#include "tvgJpgd.h"
-class JpgLoader : public LoadModule, public Task
+class JpgLoader : public ImageLoader, public Task
{
private:
jpeg_decoder* decoder = nullptr;
char* data = nullptr;
- unsigned char *image = nullptr;
bool freeData = false;
void clear();
+ void run(unsigned tid) override;
public:
+ JpgLoader();
~JpgLoader();
- using LoadModule::open;
bool open(const string& path) override;
bool open(const char* data, uint32_t size, bool copy) override;
bool read() override;
bool close() override;
- unique_ptr<Surface> bitmap() override;
- void run(unsigned tid) override;
+ Surface* bitmap() override;
};
#endif //_TVG_JPG_LOADER_H_
diff --git a/thirdparty/thorvg/src/loaders/jpg/tvgJpgd.cpp b/thirdparty/thorvg/src/loaders/jpg/tvgJpgd.cpp
index 3cd852a4bb..6f2bd916d5 100644
--- a/thirdparty/thorvg/src/loaders/jpg/tvgJpgd.cpp
+++ b/thirdparty/thorvg/src/loaders/jpg/tvgJpgd.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2021 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
diff --git a/thirdparty/thorvg/src/loaders/jpg/tvgJpgd.h b/thirdparty/thorvg/src/loaders/jpg/tvgJpgd.h
index 030fdc2946..e1fe35f488 100644
--- a/thirdparty/thorvg/src/loaders/jpg/tvgJpgd.h
+++ b/thirdparty/thorvg/src/loaders/jpg/tvgJpgd.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2021 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
diff --git a/thirdparty/thorvg/src/loaders/png/tvgLodePng.cpp b/thirdparty/thorvg/src/loaders/png/tvgLodePng.cpp
index fc4cce4061..fb7527f045 100644
--- a/thirdparty/thorvg/src/loaders/png/tvgLodePng.cpp
+++ b/thirdparty/thorvg/src/loaders/png/tvgLodePng.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
diff --git a/thirdparty/thorvg/src/loaders/png/tvgLodePng.h b/thirdparty/thorvg/src/loaders/png/tvgLodePng.h
index 7254a55477..cd3efacf98 100644
--- a/thirdparty/thorvg/src/loaders/png/tvgLodePng.h
+++ b/thirdparty/thorvg/src/loaders/png/tvgLodePng.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
diff --git a/thirdparty/thorvg/src/loaders/png/tvgPngLoader.cpp b/thirdparty/thorvg/src/loaders/png/tvgPngLoader.cpp
index 32ff57c5c3..111180b657 100644
--- a/thirdparty/thorvg/src/loaders/png/tvgPngLoader.cpp
+++ b/thirdparty/thorvg/src/loaders/png/tvgPngLoader.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2021 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -29,14 +29,22 @@
/* Internal Class Implementation */
/************************************************************************/
-void PngLoader::clear()
+
+void PngLoader::run(unsigned tid)
{
- lodepng_state_cleanup(&state);
+ auto width = static_cast<unsigned>(w);
+ auto height = static_cast<unsigned>(h);
- if (freeData) free(data);
- data = nullptr;
- size = 0;
- freeData = false;
+ if (lodepng_decode(&surface.buf8, &width, &height, &state, data, size)) {
+ TVGERR("PNG", "Failed to decode image");
+ }
+
+ //setup the surface
+ surface.stride = width;
+ surface.w = width;
+ surface.h = height;
+ surface.channelSize = sizeof(uint32_t);
+ surface.premultiplied = false;
}
@@ -44,7 +52,7 @@ void PngLoader::clear()
/* External Class Implementation */
/************************************************************************/
-PngLoader::PngLoader()
+PngLoader::PngLoader() : ImageLoader(FileType::Png)
{
lodepng_state_init(&state);
}
@@ -53,14 +61,13 @@ PngLoader::PngLoader()
PngLoader::~PngLoader()
{
if (freeData) free(data);
- free(image);
+ free(surface.buf8);
+ lodepng_state_cleanup(&state);
}
bool PngLoader::open(const string& path)
{
- clear();
-
auto pngFile = fopen(path.c_str(), "rb");
if (!pngFile) return false;
@@ -76,26 +83,23 @@ bool PngLoader::open(const string& path)
freeData = true;
- if (fread(data, size, 1, pngFile) < 1) goto failure;
+ if (fread(data, size, 1, pngFile) < 1) goto finalize;
lodepng_state_init(&state);
unsigned int width, height;
- if (lodepng_inspect(&width, &height, &state, data, size) > 0) goto failure;
+ if (lodepng_inspect(&width, &height, &state, data, size) > 0) goto finalize;
w = static_cast<float>(width);
h = static_cast<float>(height);
- if (state.info_png.color.colortype == LCT_RGBA) cs = ColorSpace::ABGR8888;
- else cs = ColorSpace::ARGB8888;
+ if (state.info_png.color.colortype == LCT_RGBA) surface.cs = ColorSpace::ABGR8888;
+ else surface.cs = ColorSpace::ARGB8888;
ret = true;
goto finalize;
-failure:
- clear();
-
finalize:
fclose(pngFile);
return ret;
@@ -104,10 +108,6 @@ finalize:
bool PngLoader::open(const char* data, uint32_t size, bool copy)
{
- clear();
-
- lodepng_state_init(&state);
-
unsigned int width, height;
if (lodepng_inspect(&width, &height, &state, (unsigned char*)(data), size) > 0) return false;
@@ -125,7 +125,7 @@ bool PngLoader::open(const char* data, uint32_t size, bool copy)
h = static_cast<float>(height);
this->size = size;
- cs = ColorSpace::ABGR8888;
+ surface.cs = ColorSpace::ABGR8888;
return true;
}
@@ -133,53 +133,18 @@ bool PngLoader::open(const char* data, uint32_t size, bool copy)
bool PngLoader::read()
{
- if (!data || w <= 0 || h <= 0) return false;
-
- TaskScheduler::request(this);
+ if (!data || w == 0 || h == 0) return false;
- return true;
-}
+ if (!LoadModule::read()) return true;
+ TaskScheduler::request(this);
-bool PngLoader::close()
-{
- this->done();
- clear();
return true;
}
-unique_ptr<Surface> PngLoader::bitmap()
+Surface* PngLoader::bitmap()
{
this->done();
-
- if (!image) return nullptr;
-
- //TODO: It's better to keep this surface instance in the loader side
- auto surface = new Surface;
- surface->buf8 = image;
- surface->stride = static_cast<uint32_t>(w);
- surface->w = static_cast<uint32_t>(w);
- surface->h = static_cast<uint32_t>(h);
- surface->cs = cs;
- surface->channelSize = sizeof(uint32_t);
- surface->premultiplied = false;
- surface->owner = true;
-
- return unique_ptr<Surface>(surface);
-}
-
-
-void PngLoader::run(unsigned tid)
-{
- if (image) {
- free(image);
- image = nullptr;
- }
- auto width = static_cast<unsigned>(w);
- auto height = static_cast<unsigned>(h);
-
- if (lodepng_decode(&image, &width, &height, &state, data, size)) {
- TVGERR("PNG", "Failed to decode image");
- }
+ return ImageLoader::bitmap();
}
diff --git a/thirdparty/thorvg/src/loaders/png/tvgPngLoader.h b/thirdparty/thorvg/src/loaders/png/tvgPngLoader.h
index 579d197ad6..06fbbf7349 100644
--- a/thirdparty/thorvg/src/loaders/png/tvgPngLoader.h
+++ b/thirdparty/thorvg/src/loaders/png/tvgPngLoader.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2021 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -27,29 +27,25 @@
#include "tvgTaskScheduler.h"
-class PngLoader : public LoadModule, public Task
+class PngLoader : public ImageLoader, public Task
{
private:
LodePNGState state;
unsigned char* data = nullptr;
- unsigned char *image = nullptr;
unsigned long size = 0;
bool freeData = false;
- void clear();
+ void run(unsigned tid) override;
public:
PngLoader();
~PngLoader();
- using LoadModule::open;
bool open(const string& path) override;
bool open(const char* data, uint32_t size, bool copy) override;
bool read() override;
- bool close() override;
- unique_ptr<Surface> bitmap() override;
- void run(unsigned tid) override;
+ Surface* bitmap() override;
};
#endif //_TVG_PNG_LOADER_H_
diff --git a/thirdparty/thorvg/src/loaders/raw/tvgRawLoader.cpp b/thirdparty/thorvg/src/loaders/raw/tvgRawLoader.cpp
index 5f5e72b0dd..b797f98218 100644
--- a/thirdparty/thorvg/src/loaders/raw/tvgRawLoader.cpp
+++ b/thirdparty/thorvg/src/loaders/raw/tvgRawLoader.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -34,17 +34,21 @@
/* External Class Implementation */
/************************************************************************/
+RawLoader::RawLoader() : ImageLoader(FileType::Raw)
+{
+}
+
+
RawLoader::~RawLoader()
{
- if (copy && content) {
- free((void*)content);
- content = nullptr;
- }
+ if (copy) free(surface.buf32);
}
bool RawLoader::open(const uint32_t* data, uint32_t w, uint32_t h, bool copy)
{
+ if (!LoadModule::read()) return true;
+
if (!data || w == 0 || h == 0) return false;
this->w = (float)w;
@@ -52,13 +56,19 @@ bool RawLoader::open(const uint32_t* data, uint32_t w, uint32_t h, bool copy)
this->copy = copy;
if (copy) {
- content = (uint32_t*)malloc(sizeof(uint32_t) * w * h);
- if (!content) return false;
- memcpy((void*)content, data, sizeof(uint32_t) * w * h);
+ surface.buf32 = (uint32_t*)malloc(sizeof(uint32_t) * w * h);
+ if (!surface.buf32) return false;
+ memcpy((void*)surface.buf32, data, sizeof(uint32_t) * w * h);
}
- else content = const_cast<uint32_t*>(data);
+ else surface.buf32 = const_cast<uint32_t*>(data);
- cs = ColorSpace::ARGB8888;
+ //setup the surface
+ surface.stride = w;
+ surface.w = w;
+ surface.h = h;
+ surface.cs = ColorSpace::ARGB8888;
+ surface.channelSize = sizeof(uint32_t);
+ surface.premultiplied = true;
return true;
}
@@ -66,30 +76,7 @@ bool RawLoader::open(const uint32_t* data, uint32_t w, uint32_t h, bool copy)
bool RawLoader::read()
{
- return true;
-}
-
+ LoadModule::read();
-bool RawLoader::close()
-{
return true;
}
-
-
-unique_ptr<Surface> RawLoader::bitmap()
-{
- if (!content) return nullptr;
-
- //TODO: It's better to keep this surface instance in the loader side
- auto surface = new Surface;
- surface->buf32 = content;
- surface->stride = static_cast<uint32_t>(w);
- surface->w = static_cast<uint32_t>(w);
- surface->h = static_cast<uint32_t>(h);
- surface->cs = cs;
- surface->channelSize = sizeof(uint32_t);
- surface->premultiplied = true;
- surface->owner = true;
-
- return unique_ptr<Surface>(surface);
-}
diff --git a/thirdparty/thorvg/src/loaders/raw/tvgRawLoader.h b/thirdparty/thorvg/src/loaders/raw/tvgRawLoader.h
index 69f9bdc47a..970cdd9c83 100644
--- a/thirdparty/thorvg/src/loaders/raw/tvgRawLoader.h
+++ b/thirdparty/thorvg/src/loaders/raw/tvgRawLoader.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -23,20 +23,17 @@
#ifndef _TVG_RAW_LOADER_H_
#define _TVG_RAW_LOADER_H_
-class RawLoader : public LoadModule
+class RawLoader : public ImageLoader
{
public:
- uint32_t* content = nullptr;
bool copy = false;
+ RawLoader();
~RawLoader();
using LoadModule::open;
- bool open(const uint32_t* data, uint32_t w, uint32_t h, bool copy) override;
+ bool open(const uint32_t* data, uint32_t w, uint32_t h, bool copy);
bool read() override;
- bool close() override;
-
- unique_ptr<Surface> bitmap() override;
};
diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgCssStyle.cpp b/thirdparty/thorvg/src/loaders/svg/tvgSvgCssStyle.cpp
index c3c477a263..2826dc9134 100644
--- a/thirdparty/thorvg/src/loaders/svg/tvgSvgCssStyle.cpp
+++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgCssStyle.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2022 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgCssStyle.h b/thirdparty/thorvg/src/loaders/svg/tvgSvgCssStyle.h
index 228c5996da..7d8dcfa94a 100644
--- a/thirdparty/thorvg/src/loaders/svg/tvgSvgCssStyle.h
+++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgCssStyle.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2022 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp b/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp
index be99ec085c..6e52476625 100644
--- a/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp
+++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -3528,6 +3528,10 @@ void SvgLoader::clear(bool all)
loaderData.images.reset();
if (copy) free((char*)content);
+
+ delete(root);
+ root = nullptr;
+
size = 0;
content = nullptr;
copy = false;
@@ -3538,14 +3542,15 @@ void SvgLoader::clear(bool all)
/* External Class Implementation */
/************************************************************************/
-SvgLoader::SvgLoader()
+SvgLoader::SvgLoader() : ImageLoader(FileType::Svg)
{
}
SvgLoader::~SvgLoader()
{
- close();
+ this->done();
+ clear();
}
@@ -3554,7 +3559,7 @@ void SvgLoader::run(unsigned tid)
//According to the SVG standard the value of the width/height of the viewbox set to 0 disables rendering
if ((viewFlag & SvgViewFlag::Viewbox) && (fabsf(vw) <= FLT_EPSILON || fabsf(vh) <= FLT_EPSILON)) {
TVGLOG("SVG", "The <viewBox> width and/or height set to 0 - rendering disabled.");
- root = Scene::gen();
+ root = Scene::gen().release();
return;
}
@@ -3727,6 +3732,8 @@ bool SvgLoader::read()
{
if (!content || size == 0) return false;
+ if (!LoadModule::read()) return true;
+
//the loading has been already completed in header()
if (root) return true;
@@ -3738,16 +3745,17 @@ bool SvgLoader::read()
bool SvgLoader::close()
{
+ if (!LoadModule::close()) return false;
this->done();
-
clear();
-
return true;
}
-unique_ptr<Paint> SvgLoader::paint()
+Paint* SvgLoader::paint()
{
this->done();
- return std::move(root);
+ auto ret = root;
+ root = nullptr;
+ return ret;
}
diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.h b/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.h
index 4bac52e0b9..e0cba8b11e 100644
--- a/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.h
+++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -26,7 +26,7 @@
#include "tvgTaskScheduler.h"
#include "tvgSvgLoaderCommon.h"
-class SvgLoader : public LoadModule, public Task
+class SvgLoader : public ImageLoader, public Task
{
public:
string filePath;
@@ -35,21 +35,20 @@ public:
uint32_t size = 0;
SvgLoaderData loaderData;
- unique_ptr<Scene> root;
+ Scene* root = nullptr;
bool copy = false;
SvgLoader();
~SvgLoader();
- using LoadModule::open;
bool open(const string& path) override;
bool open(const char* data, uint32_t size, bool copy) override;
bool resize(Paint* paint, float w, float h) override;
bool read() override;
bool close() override;
- unique_ptr<Paint> paint() override;
+ Paint* paint() override;
private:
SvgViewFlag viewFlag = SvgViewFlag::None;
diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgLoaderCommon.h b/thirdparty/thorvg/src/loaders/svg/tvgSvgLoaderCommon.h
index b4ee3e8e0d..d6febd6825 100644
--- a/thirdparty/thorvg/src/loaders/svg/tvgSvgLoaderCommon.h
+++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgLoaderCommon.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgPath.cpp b/thirdparty/thorvg/src/loaders/svg/tvgSvgPath.cpp
index 79a9c0771d..f618a3c827 100644
--- a/thirdparty/thorvg/src/loaders/svg/tvgSvgPath.cpp
+++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgPath.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -53,6 +53,7 @@
#include <cstring>
#include <math.h>
#include <ctype.h>
+#include "tvgShape.h"
#include "tvgSvgLoaderCommon.h"
#include "tvgSvgPath.h"
#include "tvgStr.h"
@@ -534,7 +535,7 @@ static char* _nextCommand(char* path, char* cmd, float* arr, int* count)
/************************************************************************/
-bool svgPathToTvgPath(const char* svgPath, Array<PathCommand>& cmds, Array<Point>& pts)
+bool svgPathToShape(const char* svgPath, Shape* shape)
{
float numberArray[7];
int numberCount = 0;
@@ -545,11 +546,16 @@ bool svgPathToTvgPath(const char* svgPath, Array<PathCommand>& cmds, Array<Point
bool isQuadratic = false;
char* path = (char*)svgPath;
+ auto& pts = P(shape)->rs.path.pts;
+ auto& cmds = P(shape)->rs.path.cmds;
+ auto lastCmds = cmds.count;
+
while ((path[0] != '\0')) {
path = _nextCommand(path, &cmd, numberArray, &numberCount);
if (!path) break;
if (!_processCommand(&cmds, &pts, cmd, numberArray, numberCount, &cur, &curCtl, &startPoint, &isQuadratic)) break;
}
+ if (cmds.count > lastCmds && cmds[lastCmds] != PathCommand::MoveTo) return false;
return true;
}
diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgPath.h b/thirdparty/thorvg/src/loaders/svg/tvgSvgPath.h
index 4199088dc1..b8641dd165 100644
--- a/thirdparty/thorvg/src/loaders/svg/tvgSvgPath.h
+++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgPath.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -25,6 +25,6 @@
#include <tvgCommon.h>
-bool svgPathToTvgPath(const char* svgPath, Array<PathCommand>& cmds, Array<Point>& pts);
+bool svgPathToShape(const char* svgPath, Shape* shape);
#endif //_TVG_SVG_PATH_H_
diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.cpp b/thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.cpp
index 1791df57f0..674c30f5bd 100644
--- a/thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.cpp
+++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -396,10 +396,9 @@ static bool _recognizeShape(SvgNode* node, Shape* shape)
switch (node->type) {
case SvgNodeType::Path: {
if (node->node.path.path) {
- Array<PathCommand> cmds;
- Array<Point> pts;
- if (svgPathToTvgPath(node->node.path.path, cmds, pts)) {
- shape->appendPath(cmds.data, cmds.count, pts.data, pts.count);
+ if (!svgPathToShape(node->node.path.path, shape)) {
+ TVGERR("SVG", "Invalid path information.");
+ return false;
}
}
break;
@@ -845,7 +844,7 @@ static void _updateInvalidViewSize(const Scene* scene, Box& vBox, float& w, floa
/* External Class Implementation */
/************************************************************************/
-unique_ptr<Scene> svgSceneBuild(SvgLoaderData& loaderData, Box vBox, float w, float h, AspectRatioAlign align, AspectRatioMeetOrSlice meetOrSlice, const string& svgPath, SvgViewFlag viewFlag)
+Scene* svgSceneBuild(SvgLoaderData& loaderData, Box vBox, float w, float h, AspectRatioAlign align, AspectRatioMeetOrSlice meetOrSlice, const string& svgPath, SvgViewFlag viewFlag)
{
//TODO: aspect ratio is valid only if viewBox was set
@@ -863,8 +862,7 @@ unique_ptr<Scene> svgSceneBuild(SvgLoaderData& loaderData, Box vBox, float w, fl
}
auto viewBoxClip = Shape::gen();
- viewBoxClip->appendRect(0, 0, w, h, 0, 0);
- viewBoxClip->fill(0, 0, 0);
+ viewBoxClip->appendRect(0, 0, w, h);
auto compositeLayer = Scene::gen();
compositeLayer->composite(std::move(viewBoxClip), CompositeMethod::ClipPath);
@@ -880,5 +878,5 @@ unique_ptr<Scene> svgSceneBuild(SvgLoaderData& loaderData, Box vBox, float w, fl
loaderData.doc->node.doc.w = w;
loaderData.doc->node.doc.h = h;
- return root;
+ return root.release();
}
diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.h b/thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.h
index f6a60f850d..0663a37f05 100644
--- a/thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.h
+++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -25,6 +25,6 @@
#include "tvgCommon.h"
-unique_ptr<Scene> svgSceneBuild(SvgLoaderData& loaderData, Box vBox, float w, float h, AspectRatioAlign align, AspectRatioMeetOrSlice meetOrSlice, const string& svgPath, SvgViewFlag viewFlag);
+Scene* svgSceneBuild(SvgLoaderData& loaderData, Box vBox, float w, float h, AspectRatioAlign align, AspectRatioMeetOrSlice meetOrSlice, const string& svgPath, SvgViewFlag viewFlag);
#endif //_TVG_SVG_SCENE_BUILDER_H_
diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgUtil.cpp b/thirdparty/thorvg/src/loaders/svg/tvgSvgUtil.cpp
index 7940188ade..32affd04c6 100644
--- a/thirdparty/thorvg/src/loaders/svg/tvgSvgUtil.cpp
+++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgUtil.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgUtil.h b/thirdparty/thorvg/src/loaders/svg/tvgSvgUtil.h
index ee0e3f8861..220a4b3e55 100644
--- a/thirdparty/thorvg/src/loaders/svg/tvgSvgUtil.h
+++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgUtil.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
diff --git a/thirdparty/thorvg/src/loaders/svg/tvgXmlParser.cpp b/thirdparty/thorvg/src/loaders/svg/tvgXmlParser.cpp
index dbc3b17b70..aec30d2384 100644
--- a/thirdparty/thorvg/src/loaders/svg/tvgXmlParser.cpp
+++ b/thirdparty/thorvg/src/loaders/svg/tvgXmlParser.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
diff --git a/thirdparty/thorvg/src/loaders/svg/tvgXmlParser.h b/thirdparty/thorvg/src/loaders/svg/tvgXmlParser.h
index 7333bb09fb..30ca23b565 100644
--- a/thirdparty/thorvg/src/loaders/svg/tvgXmlParser.h
+++ b/thirdparty/thorvg/src/loaders/svg/tvgXmlParser.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwCommon.h b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwCommon.h
index 8fe7b77edd..3d73075a4a 100644
--- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwCommon.h
+++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwCommon.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -261,13 +261,26 @@ struct SwSurface : Surface
SwAlpha alphas[4]; //Alpha:2, InvAlpha:3, Luma:4, InvLuma:5
SwBlender blender = nullptr; //blender (optional)
SwCompositor* compositor = nullptr; //compositor (optional)
- BlendMethod blendMethod; //blending method (uint8_t)
+ BlendMethod blendMethod; //blending method (uint8_t)
SwAlpha alpha(CompositeMethod method)
{
auto idx = (int)(method) - 2; //0: None, 1: ClipPath
return alphas[idx > 3 ? 0 : idx]; //CompositeMethod has only four Matting methods.
}
+
+ SwSurface()
+ {
+ }
+
+ SwSurface(const SwSurface* rhs) : Surface(rhs)
+ {
+ join = rhs->join;
+ memcpy(alphas, rhs->alphas, sizeof(alphas));
+ blender = rhs->blender;
+ compositor = rhs->compositor;
+ blendMethod = rhs->blendMethod;
+ }
};
struct SwCompositor : Compositor
diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwFill.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwFill.cpp
index cede9e6eb7..8956cd9f24 100644
--- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwFill.cpp
+++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwFill.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -167,7 +167,6 @@ bool _prepareLinear(SwFill* fill, const LinearGradient* linear, const Matrix* tr
fill->linear.dy = dx * invTransform.e12 + fill->linear.dy * invTransform.e22;
fill->linear.len = fill->linear.dx * fill->linear.dx + fill->linear.dy * fill->linear.dy;
- if (fill->linear.len < FLT_EPSILON) return true;
}
return true;
diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwImage.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwImage.cpp
index b1624037bc..c162945501 100644
--- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwImage.cpp
+++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwImage.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwMath.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwMath.cpp
index d58dd9e3c5..42e405195e 100644
--- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwMath.cpp
+++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwMath.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwMemPool.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwMemPool.cpp
index 54ae594bff..68eb7a5a6f 100644
--- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwMemPool.cpp
+++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwMemPool.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRaster.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRaster.cpp
index 96a0ed35ad..9a6dc45950 100644
--- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRaster.cpp
+++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRaster.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -1714,7 +1714,7 @@ static bool _rasterSolidGradientRle(SwSurface* surface, const SwRleData* rle, co
static bool _rasterLinearGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
{
- if (!rle || fill->linear.len < FLT_EPSILON) return false;
+ if (!rle) return false;
if (_compositing(surface)) {
if (_matting(surface)) return _rasterGradientMattedRle<FillLinear>(surface, rle, fill);
@@ -1855,7 +1855,9 @@ void rasterUnpremultiply(Surface* surface)
void rasterPremultiply(Surface* surface)
{
- if (surface->channelSize != sizeof(uint32_t)) return;
+ unique_lock<mutex> lock{surface->mtx};
+ if (surface->premultiplied || (surface->channelSize != sizeof(uint32_t))) return;
+ surface->premultiplied = true;
TVGLOG("SW_ENGINE", "Premultiply [Size: %d x %d]", surface->w, surface->h);
@@ -1869,7 +1871,6 @@ void rasterPremultiply(Surface* surface)
*dst = (c & 0xff000000) + ((((c >> 8) & 0xff) * a) & 0xff00) + ((((c & 0x00ff00ff) * a) >> 8) & 0x00ff00ff);
}
}
- surface->premultiplied = true;
}
@@ -1935,6 +1936,9 @@ bool rasterImage(SwSurface* surface, SwImage* image, const RenderMesh* mesh, con
bool rasterConvertCS(Surface* surface, ColorSpace to)
{
+ unique_lock<mutex> lock{surface->mtx};
+ if (surface->cs == to) return true;
+
//TOOD: Support SIMD accelerations
auto from = surface->cs;
@@ -1946,6 +1950,5 @@ bool rasterConvertCS(Surface* surface, ColorSpace to)
surface->cs = to;
return cRasterARGBtoABGR(surface);
}
-
return false;
}
diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterAvx.h b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterAvx.h
index 090fa29a7a..177c7b847f 100644
--- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterAvx.h
+++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterAvx.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2021 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterC.h b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterC.h
index da3c7077e8..6d0bd9383d 100644
--- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterC.h
+++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterC.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2021 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterNeon.h b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterNeon.h
index ba77ed53cf..cfbeb0caca 100644
--- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterNeon.h
+++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterNeon.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2021 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterTexmap.h b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterTexmap.h
index 698ab37da2..04e382b842 100644
--- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterTexmap.h
+++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterTexmap.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2021 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp
index 18815e69a9..c9c543fbb5 100644
--- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp
+++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -45,8 +45,11 @@ struct SwTask : Task
bool pushed = false; //Pushed into task list?
bool disposed = false; //Disposed task?
- RenderRegion bounds() const
+ RenderRegion bounds()
{
+ //Can we skip the synchronization?
+ done();
+
RenderRegion region;
//Range over?
@@ -278,10 +281,8 @@ struct SwImageTask : SwTask
auto clipRegion = bbox;
//Convert colorspace if it's not aligned.
- if (source->owner) {
- if (source->cs != surface->cs) rasterConvertCS(source, surface->cs);
- if (!source->premultiplied) rasterPremultiply(source);
- }
+ rasterConvertCS(source, surface->cs);
+ rasterPremultiply(source);
image.data = source->data;
image.w = source->w;
@@ -433,7 +434,6 @@ bool SwRenderer::target(pixel_t* data, uint32_t stride, uint32_t w, uint32_t h,
surface->cs = cs;
surface->channelSize = CHANNEL_SIZE(cs);
surface->premultiplied = true;
- surface->owner = true;
vport.x = vport.y = 0;
vport.w = surface->w;
@@ -635,11 +635,8 @@ Compositor* SwRenderer::target(const RenderRegion& region, ColorSpace cs)
//New Composition
if (!cmp) {
- cmp = new SwSurface;
-
//Inherits attributes from main surface
- *cmp = *surface;
-
+ cmp = new SwSurface(surface);
cmp->compositor = new SwCompositor;
//TODO: We can optimize compositor surface size from (surface->stride x surface->h) to Parameter(w x h)
diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.h b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.h
index 4393740bd9..83d942388f 100644
--- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.h
+++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRle.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRle.cpp
index a4a7fabdee..33c94e1063 100644
--- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRle.cpp
+++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRle.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwShape.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwShape.cpp
index ae2ddd2af7..e001ced2a8 100644
--- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwShape.cpp
+++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwShape.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwStroke.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwStroke.cpp
index 75c5fa5667..8f44cf3616 100644
--- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwStroke.cpp
+++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwStroke.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
diff --git a/thirdparty/thorvg/src/renderer/tvgAccessor.cpp b/thirdparty/thorvg/src/renderer/tvgAccessor.cpp
index 0c636979b5..903437f29d 100644
--- a/thirdparty/thorvg/src/renderer/tvgAccessor.cpp
+++ b/thirdparty/thorvg/src/renderer/tvgAccessor.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2021 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
diff --git a/thirdparty/thorvg/src/renderer/tvgAnimation.cpp b/thirdparty/thorvg/src/renderer/tvgAnimation.cpp
index b4ea534b91..995eca7f41 100644
--- a/thirdparty/thorvg/src/renderer/tvgAnimation.cpp
+++ b/thirdparty/thorvg/src/renderer/tvgAnimation.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2023 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -64,7 +64,7 @@ Animation::Animation() : pImpl(new Impl)
Result Animation::frame(float no) noexcept
{
- auto loader = pImpl->picture->pImpl->loader.get();
+ auto loader = pImpl->picture->pImpl->loader;
if (!loader) return Result::InsufficientCondition;
if (!loader->animatable()) return Result::NonSupport;
@@ -82,7 +82,7 @@ Picture* Animation::picture() const noexcept
float Animation::curFrame() const noexcept
{
- auto loader = pImpl->picture->pImpl->loader.get();
+ auto loader = pImpl->picture->pImpl->loader;
if (!loader) return 0;
if (!loader->animatable()) return 0;
@@ -93,7 +93,7 @@ float Animation::curFrame() const noexcept
float Animation::totalFrame() const noexcept
{
- auto loader = pImpl->picture->pImpl->loader.get();
+ auto loader = pImpl->picture->pImpl->loader;
if (!loader) return 0;
if (!loader->animatable()) return 0;
@@ -104,7 +104,7 @@ float Animation::totalFrame() const noexcept
float Animation::duration() const noexcept
{
- auto loader = pImpl->picture->pImpl->loader.get();
+ auto loader = pImpl->picture->pImpl->loader;
if (!loader) return 0;
if (!loader->animatable()) return 0;
diff --git a/thirdparty/thorvg/src/renderer/tvgBinaryDesc.h b/thirdparty/thorvg/src/renderer/tvgBinaryDesc.h
index b1468148d6..29f84eb82a 100644
--- a/thirdparty/thorvg/src/renderer/tvgBinaryDesc.h
+++ b/thirdparty/thorvg/src/renderer/tvgBinaryDesc.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2021 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -36,7 +36,7 @@ using TvgBinFlag = TvgBinByte;
#define TVG_HEADER_SIZE 33 //TVG_HEADER_SIGNATURE_LENGTH + TVG_HEADER_VERSION_LENGTH + 2*SIZE(float) + TVG_HEADER_RESERVED_LENGTH + TVG_HEADER_COMPRESS_SIZE
#define TVG_HEADER_SIGNATURE "ThorVG"
#define TVG_HEADER_SIGNATURE_LENGTH 6
-#define TVG_HEADER_VERSION "001100" //Major 00, Minor 11, Micro 00
+#define TVG_HEADER_VERSION "001200" //Major 00, Minor 12, Micro 00
#define TVG_HEADER_VERSION_LENGTH 6
#define TVG_HEADER_RESERVED_LENGTH 1 //Storing flags for extensions
#define TVG_HEADER_COMPRESS_SIZE 12 //TVG_HEADER_UNCOMPRESSED_SIZE + TVG_HEADER_COMPRESSED_SIZE + TVG_HEADER_COMPRESSED_SIZE_BITS
diff --git a/thirdparty/thorvg/src/renderer/tvgCanvas.cpp b/thirdparty/thorvg/src/renderer/tvgCanvas.cpp
index 25741f611d..11d6b778f7 100644
--- a/thirdparty/thorvg/src/renderer/tvgCanvas.cpp
+++ b/thirdparty/thorvg/src/renderer/tvgCanvas.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
diff --git a/thirdparty/thorvg/src/renderer/tvgCanvas.h b/thirdparty/thorvg/src/renderer/tvgCanvas.h
index f893f9f7c0..25181de47e 100644
--- a/thirdparty/thorvg/src/renderer/tvgCanvas.h
+++ b/thirdparty/thorvg/src/renderer/tvgCanvas.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -20,14 +20,11 @@
* SOFTWARE.
*/
-#ifndef _TVG_CANVAS_IMPL_H_
-#define _TVG_CANVAS_IMPL_H_
+#ifndef _TVG_CANVAS_H_
+#define _TVG_CANVAS_H_
#include "tvgPaint.h"
-/************************************************************************/
-/* Internal Class Implementation */
-/************************************************************************/
struct Canvas::Impl
{
@@ -143,4 +140,4 @@ struct Canvas::Impl
}
};
-#endif /* _TVG_CANVAS_IMPL_H_ */
+#endif /* _TVG_CANVAS_H_ */
diff --git a/thirdparty/thorvg/src/renderer/tvgCommon.h b/thirdparty/thorvg/src/renderer/tvgCommon.h
index 2b67681a40..deb419bc65 100644
--- a/thirdparty/thorvg/src/renderer/tvgCommon.h
+++ b/thirdparty/thorvg/src/renderer/tvgCommon.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -61,8 +61,9 @@ using namespace tvg;
#define TVG_CLASS_ID_PICTURE 3
#define TVG_CLASS_ID_LINEAR 4
#define TVG_CLASS_ID_RADIAL 5
+#define TVG_CLASS_ID_TEXT 6
-enum class FileType { Tvg = 0, Svg, Lottie, Raw, Png, Jpg, Webp, Gif, Unknown };
+enum class FileType { Tvg = 0, Svg, Ttf, Lottie, Raw, Png, Jpg, Webp, Gif, Unknown };
using Size = Point;
diff --git a/thirdparty/thorvg/src/renderer/tvgFill.cpp b/thirdparty/thorvg/src/renderer/tvgFill.cpp
index 9215882c8d..ea1010051e 100644
--- a/thirdparty/thorvg/src/renderer/tvgFill.cpp
+++ b/thirdparty/thorvg/src/renderer/tvgFill.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
diff --git a/thirdparty/thorvg/src/renderer/tvgFill.h b/thirdparty/thorvg/src/renderer/tvgFill.h
index ff3dd48c49..47f0c051c0 100644
--- a/thirdparty/thorvg/src/renderer/tvgFill.h
+++ b/thirdparty/thorvg/src/renderer/tvgFill.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
diff --git a/thirdparty/thorvg/src/renderer/tvgFrameModule.h b/thirdparty/thorvg/src/renderer/tvgFrameModule.h
index 332cca3090..df97ccb894 100644
--- a/thirdparty/thorvg/src/renderer/tvgFrameModule.h
+++ b/thirdparty/thorvg/src/renderer/tvgFrameModule.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2023 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -28,9 +28,10 @@
namespace tvg
{
-class FrameModule: public LoadModule
+class FrameModule: public ImageLoader
{
public:
+ FrameModule(FileType type) : ImageLoader(type) {}
virtual ~FrameModule() {}
virtual bool frame(float no) = 0; //set the current frame number
diff --git a/thirdparty/thorvg/src/renderer/tvgGlCanvas.cpp b/thirdparty/thorvg/src/renderer/tvgGlCanvas.cpp
index aa7f8dbe2a..f6f0d354d1 100644
--- a/thirdparty/thorvg/src/renderer/tvgGlCanvas.cpp
+++ b/thirdparty/thorvg/src/renderer/tvgGlCanvas.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
diff --git a/thirdparty/thorvg/src/renderer/tvgInitializer.cpp b/thirdparty/thorvg/src/renderer/tvgInitializer.cpp
index b7326a9fbc..76d89b40ed 100644
--- a/thirdparty/thorvg/src/renderer/tvgInitializer.cpp
+++ b/thirdparty/thorvg/src/renderer/tvgInitializer.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -36,6 +36,10 @@
#include "tvgGlRenderer.h"
#endif
+#ifdef THORVG_WG_RASTER_SUPPORT
+ #include "tvgWgRenderer.h"
+#endif
+
/************************************************************************/
/* Internal Class Implementation */
@@ -91,19 +95,27 @@ static bool _buildVersionInfo()
Result Initializer::init(CanvasEngine engine, uint32_t threads) noexcept
{
auto nonSupport = true;
+ if (static_cast<int>(engine) == 0) return Result::InvalidArguments;
if (engine & CanvasEngine::Sw) {
#ifdef THORVG_SW_RASTER_SUPPORT
if (!SwRenderer::init(threads)) return Result::FailedAllocation;
nonSupport = false;
#endif
- } else if (engine & CanvasEngine::Gl) {
+ }
+
+ if (engine & CanvasEngine::Gl) {
#ifdef THORVG_GL_RASTER_SUPPORT
if (!GlRenderer::init(threads)) return Result::FailedAllocation;
nonSupport = false;
#endif
- } else {
- return Result::InvalidArguments;
+ }
+
+ if (engine & CanvasEngine::Wg) {
+ #ifdef THORVG_WG_RASTER_SUPPORT
+ if (!WgRenderer::init(threads)) return Result::FailedAllocation;
+ nonSupport = false;
+ #endif
}
if (nonSupport) return Result::NonSupport;
@@ -125,19 +137,27 @@ Result Initializer::term(CanvasEngine engine) noexcept
if (_initCnt == 0) return Result::InsufficientCondition;
auto nonSupport = true;
+ if (static_cast<int>(engine) == 0) return Result::InvalidArguments;
if (engine & CanvasEngine::Sw) {
#ifdef THORVG_SW_RASTER_SUPPORT
if (!SwRenderer::term()) return Result::InsufficientCondition;
nonSupport = false;
#endif
- } else if (engine & CanvasEngine::Gl) {
+ }
+
+ if (engine & CanvasEngine::Gl) {
#ifdef THORVG_GL_RASTER_SUPPORT
if (!GlRenderer::term()) return Result::InsufficientCondition;
nonSupport = false;
#endif
- } else {
- return Result::InvalidArguments;
+ }
+
+ if (engine & CanvasEngine::Wg) {
+ #ifdef THORVG_WG_RASTER_SUPPORT
+ if (!WgRenderer::term()) return Result::InsufficientCondition;
+ nonSupport = false;
+ #endif
}
if (nonSupport) return Result::NonSupport;
@@ -156,3 +176,4 @@ uint16_t THORVG_VERSION_NUMBER()
{
return _version;
}
+
diff --git a/thirdparty/thorvg/src/renderer/tvgIteratorAccessor.h b/thirdparty/thorvg/src/renderer/tvgIteratorAccessor.h
index 2347613ed8..46e900a582 100644
--- a/thirdparty/thorvg/src/renderer/tvgIteratorAccessor.h
+++ b/thirdparty/thorvg/src/renderer/tvgIteratorAccessor.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2021 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
diff --git a/thirdparty/thorvg/src/renderer/tvgLoadModule.h b/thirdparty/thorvg/src/renderer/tvgLoadModule.h
index 29ceba3fcc..0ea766395e 100644
--- a/thirdparty/thorvg/src/renderer/tvgLoadModule.h
+++ b/thirdparty/thorvg/src/renderer/tvgLoadModule.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -24,35 +24,73 @@
#define _TVG_LOAD_MODULE_H_
#include "tvgRender.h"
+#include "tvgInlist.h"
-namespace tvg
-{
-class LoadModule
+struct LoadModule
{
-public:
- float w = 0, h = 0; //default image size
- ColorSpace cs = ColorSpace::Unsupported; //must be clarified at open()
+ INLIST_ITEM(LoadModule);
+
+ //Use either hashkey(data) or hashpath(path)
+ uint64_t hashkey;
+ char* hashpath = nullptr;
- virtual ~LoadModule() {}
+ FileType type; //current loader file type
+ uint16_t sharing = 0; //reference count
+ bool readied = false; //read done already.
+
+ LoadModule(FileType type) : type(type) {}
+ virtual ~LoadModule()
+ {
+ free(hashpath);
+ }
virtual bool open(const string& path) { return false; }
virtual bool open(const char* data, uint32_t size, bool copy) { return false; }
- virtual bool open(const uint32_t* data, uint32_t w, uint32_t h, bool copy) { return false; }
-
- //Override this if the vector-format has own resizing policy.
virtual bool resize(Paint* paint, float w, float h) { return false; }
-
- virtual bool animatable() { return false; } //true if this loader supports animation.
virtual void sync() {}; //finish immediately if any async update jobs.
- virtual bool read() = 0;
- virtual bool close() = 0;
+ virtual bool read()
+ {
+ if (readied) return false;
+ readied = true;
+ return true;
+ }
- virtual unique_ptr<Surface> bitmap() { return nullptr; }
- virtual unique_ptr<Paint> paint() { return nullptr; }
+ virtual bool close()
+ {
+ if (sharing == 0) return true;
+ --sharing;
+ return false;
+ }
};
-}
+
+struct ImageLoader : LoadModule
+{
+ float w = 0, h = 0; //default image size
+ Surface surface;
+
+ ImageLoader(FileType type) : LoadModule(type) {}
+
+ virtual bool animatable() { return false; } //true if this loader supports animation.
+ virtual Paint* paint() { return nullptr; }
+
+ virtual Surface* bitmap()
+ {
+ if (surface.data) return &surface;
+ return nullptr;
+ }
+};
+
+
+struct FontLoader : LoadModule
+{
+ float scale = 1.0f;
+
+ FontLoader(FileType type) : LoadModule(type) {}
+
+ virtual bool request(Shape* shape, char* text, bool italic = false) = 0;
+};
#endif //_TVG_LOAD_MODULE_H_
diff --git a/thirdparty/thorvg/src/renderer/tvgLoader.cpp b/thirdparty/thorvg/src/renderer/tvgLoader.cpp
index 65330e9e77..628b0fa17f 100644
--- a/thirdparty/thorvg/src/renderer/tvgLoader.cpp
+++ b/thirdparty/thorvg/src/renderer/tvgLoader.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -20,6 +20,9 @@
* SOFTWARE.
*/
+#include <string.h>
+
+#include "tvgInlist.h"
#include "tvgLoader.h"
#ifdef THORVG_SVG_LOADER_SUPPORT
@@ -42,16 +45,30 @@
#include "tvgWebpLoader.h"
#endif
+#ifdef THORVG_TTF_LOADER_SUPPORT
+ #include "tvgTtfLoader.h"
+#endif
+
#ifdef THORVG_LOTTIE_LOADER_SUPPORT
#include "tvgLottieLoader.h"
#endif
#include "tvgRawLoader.h"
+
+uint64_t HASH_KEY(const char* data, uint64_t size)
+{
+ return (((uint64_t) data) << 32) | size;
+}
+
/************************************************************************/
/* Internal Class Implementation */
/************************************************************************/
+static mutex mtx;
+static Inlist<LoadModule> _activeLoaders;
+
+
static LoadModule* _find(FileType type)
{
switch(type) {
@@ -67,6 +84,12 @@ static LoadModule* _find(FileType type)
#endif
break;
}
+ case FileType::Ttf: {
+#ifdef THORVG_TTF_LOADER_SUPPORT
+ return new TtfLoader;
+#endif
+ break;
+ }
case FileType::Lottie: {
#ifdef THORVG_LOTTIE_LOADER_SUPPORT
return new LottieLoader;
@@ -111,6 +134,10 @@ static LoadModule* _find(FileType type)
format = "SVG";
break;
}
+ case FileType::Ttf: {
+ format = "TTF";
+ break;
+ }
case FileType::Lottie: {
format = "lottie(json)";
break;
@@ -152,29 +179,71 @@ static LoadModule* _findByPath(const string& path)
if (!ext.compare("png")) return _find(FileType::Png);
if (!ext.compare("jpg")) return _find(FileType::Jpg);
if (!ext.compare("webp")) return _find(FileType::Webp);
+ if (!ext.compare("ttf") || !ext.compare("ttc")) return _find(FileType::Ttf);
+ if (!ext.compare("otf") || !ext.compare("otc")) return _find(FileType::Ttf);
return nullptr;
}
-static LoadModule* _findByType(const string& mimeType)
+static FileType _convert(const string& mimeType)
{
- if (mimeType.empty()) return nullptr;
-
auto type = FileType::Unknown;
if (mimeType == "tvg") type = FileType::Tvg;
else if (mimeType == "svg" || mimeType == "svg+xml") type = FileType::Svg;
+ else if (mimeType == "ttf" || mimeType == "otf") type = FileType::Ttf;
else if (mimeType == "lottie") type = FileType::Lottie;
else if (mimeType == "raw") type = FileType::Raw;
else if (mimeType == "png") type = FileType::Png;
else if (mimeType == "jpg" || mimeType == "jpeg") type = FileType::Jpg;
else if (mimeType == "webp") type = FileType::Webp;
- else {
- TVGLOG("RENDERER", "Given mimetype is unknown = \"%s\".", mimeType.c_str());
- return nullptr;
+ else TVGLOG("RENDERER", "Given mimetype is unknown = \"%s\".", mimeType.c_str());
+
+ return type;
+}
+
+
+static LoadModule* _findByType(const string& mimeType)
+{
+ return _find(_convert(mimeType));
+}
+
+
+static LoadModule* _findFromCache(const string& path)
+{
+ unique_lock<mutex> lock{mtx};
+
+ auto loader = _activeLoaders.head;
+
+ while (loader) {
+ if (loader->hashpath && !strcmp(loader->hashpath, path.c_str())) {
+ ++loader->sharing;
+ return loader;
+ }
+ loader = loader->next;
}
+ return nullptr;
+}
+
+
+static LoadModule* _findFromCache(const char* data, uint32_t size, const string& mimeType)
+{
+ auto type = _convert(mimeType);
+ if (type == FileType::Unknown) return nullptr;
- return _find(type);
+ unique_lock<mutex> lock{mtx};
+ auto loader = _activeLoaders.head;
+
+ auto key = HASH_KEY(data, size);
+
+ while (loader) {
+ if (loader->type == type && loader->hashkey == key) {
+ ++loader->sharing;
+ return loader;
+ }
+ loader = loader->next;
+ }
+ return nullptr;
}
@@ -185,40 +254,95 @@ static LoadModule* _findByType(const string& mimeType)
bool LoaderMgr::init()
{
- //TODO:
-
return true;
}
bool LoaderMgr::term()
{
- //TODO:
+ auto loader = _activeLoaders.head;
+
+ //clean up the remained font loaders which is globally used.
+ while (loader && loader->type == FileType::Ttf) {
+ auto ret = loader->close();
+ auto tmp = loader;
+ loader = loader->next;
+ _activeLoaders.remove(tmp);
+ if (ret) delete(loader);
+ }
+ return true;
+}
+
+bool LoaderMgr::retrieve(LoadModule* loader)
+{
+ if (!loader) return false;
+ if (loader->close()) {
+ {
+ unique_lock<mutex> lock{mtx};
+ _activeLoaders.remove(loader);
+ }
+ delete(loader);
+ }
return true;
}
-shared_ptr<LoadModule> LoaderMgr::loader(const string& path, bool* invalid)
+LoadModule* LoaderMgr::loader(const string& path, bool* invalid)
{
*invalid = false;
+ if (auto loader = _findFromCache(path)) return loader;
+
if (auto loader = _findByPath(path)) {
- if (loader->open(path)) return shared_ptr<LoadModule>(loader);
- else delete(loader);
+ if (loader->open(path)) {
+ loader->hashpath = strdup(path.c_str());
+ {
+ unique_lock<mutex> lock{mtx};
+ _activeLoaders.back(loader);
+ }
+ return loader;
+ }
+ delete(loader);
*invalid = true;
}
return nullptr;
}
-shared_ptr<LoadModule> LoaderMgr::loader(const char* data, uint32_t size, const string& mimeType, bool copy)
+bool LoaderMgr::retrieve(const string& path)
+{
+ return retrieve(_findFromCache(path));
+}
+
+
+LoadModule* LoaderMgr::loader(const char* key)
+{
+ auto loader = _activeLoaders.head;
+
+ while (loader) {
+ if (loader->hashpath && strstr(loader->hashpath, key)) {
+ ++loader->sharing;
+ return loader;
+ }
+ loader = loader->next;
+ }
+ return nullptr;
+}
+
+
+LoadModule* LoaderMgr::loader(const char* data, uint32_t size, const string& mimeType, bool copy)
{
+ if (auto loader = _findFromCache(data, size, mimeType)) return loader;
+
//Try with the given MimeType
if (!mimeType.empty()) {
if (auto loader = _findByType(mimeType)) {
if (loader->open(data, size, copy)) {
- return shared_ptr<LoadModule>(loader);
+ loader->hashkey = HASH_KEY(data, size);
+ unique_lock<mutex> lock{mtx};
+ _activeLoaders.back(loader);
+ return loader;
} else {
TVGLOG("LOADER", "Given mimetype \"%s\" seems incorrect or not supported.", mimeType.c_str());
delete(loader);
@@ -229,8 +353,15 @@ shared_ptr<LoadModule> LoaderMgr::loader(const char* data, uint32_t size, const
for (int i = 0; i < static_cast<int>(FileType::Unknown); i++) {
auto loader = _find(static_cast<FileType>(i));
if (loader) {
- if (loader->open(data, size, copy)) return shared_ptr<LoadModule>(loader);
- else delete(loader);
+ if (loader->open(data, size, copy)) {
+ loader->hashkey = HASH_KEY(data, size);
+ {
+ unique_lock<mutex> lock{mtx};
+ _activeLoaders.back(loader);
+ }
+ return loader;
+ }
+ delete(loader);
}
}
}
@@ -238,12 +369,21 @@ shared_ptr<LoadModule> LoaderMgr::loader(const char* data, uint32_t size, const
}
-shared_ptr<LoadModule> LoaderMgr::loader(const uint32_t *data, uint32_t w, uint32_t h, bool copy)
+LoadModule* LoaderMgr::loader(const uint32_t *data, uint32_t w, uint32_t h, bool copy)
{
+ //TODO: should we check premultiplied??
+ if (auto loader = _findFromCache((const char*)(data), w * h, "raw")) return loader;
+
//function is dedicated for raw images only
auto loader = new RawLoader;
- if (loader->open(data, w, h, copy)) return shared_ptr<LoadModule>(loader);
- else delete(loader);
-
+ if (loader->open(data, w, h, copy)) {
+ loader->hashkey = HASH_KEY((const char*)data, w * h);
+ {
+ unique_lock<mutex> lock{mtx};
+ _activeLoaders.back(loader);
+ }
+ return loader;
+ }
+ delete(loader);
return nullptr;
}
diff --git a/thirdparty/thorvg/src/renderer/tvgLoader.h b/thirdparty/thorvg/src/renderer/tvgLoader.h
index 17ff9e2637..b15032df27 100644
--- a/thirdparty/thorvg/src/renderer/tvgLoader.h
+++ b/thirdparty/thorvg/src/renderer/tvgLoader.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -29,9 +29,12 @@ struct LoaderMgr
{
static bool init();
static bool term();
- static shared_ptr<LoadModule> loader(const string& path, bool* invalid);
- static shared_ptr<LoadModule> loader(const char* data, uint32_t size, const string& mimeType, bool copy);
- static shared_ptr<LoadModule> loader(const uint32_t* data, uint32_t w, uint32_t h, bool copy);
+ static LoadModule* loader(const string& path, bool* invalid);
+ static LoadModule* loader(const char* data, uint32_t size, const string& mimeType, bool copy);
+ static LoadModule* loader(const uint32_t* data, uint32_t w, uint32_t h, bool copy);
+ static LoadModule* loader(const char* key);
+ static bool retrieve(const string& path);
+ static bool retrieve(LoadModule* loader);
};
#endif //_TVG_LOADER_H_
diff --git a/thirdparty/thorvg/src/renderer/tvgPaint.cpp b/thirdparty/thorvg/src/renderer/tvgPaint.cpp
index 008e6589b5..563db3b44a 100644
--- a/thirdparty/thorvg/src/renderer/tvgPaint.cpp
+++ b/thirdparty/thorvg/src/renderer/tvgPaint.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -25,6 +25,7 @@
#include "tvgShape.h"
#include "tvgPicture.h"
#include "tvgScene.h"
+#include "tvgText.h"
/************************************************************************/
/* Internal Class Implementation */
@@ -35,6 +36,7 @@
case TVG_CLASS_ID_SHAPE: ret = P((Shape*)paint)->METHOD; break; \
case TVG_CLASS_ID_SCENE: ret = P((Scene*)paint)->METHOD; break; \
case TVG_CLASS_ID_PICTURE: ret = P((Picture*)paint)->METHOD; break; \
+ case TVG_CLASS_ID_TEXT: ret = P((Text*)paint)->METHOD; break; \
default: ret = {}; \
}
diff --git a/thirdparty/thorvg/src/renderer/tvgPaint.h b/thirdparty/thorvg/src/renderer/tvgPaint.h
index f4721f8e15..4ec9fa7f7e 100644
--- a/thirdparty/thorvg/src/renderer/tvgPaint.h
+++ b/thirdparty/thorvg/src/renderer/tvgPaint.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
diff --git a/thirdparty/thorvg/src/renderer/tvgPicture.cpp b/thirdparty/thorvg/src/renderer/tvgPicture.cpp
index e382795698..7f120593f4 100644
--- a/thirdparty/thorvg/src/renderer/tvgPicture.cpp
+++ b/thirdparty/thorvg/src/renderer/tvgPicture.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -30,9 +30,8 @@ RenderUpdateFlag Picture::Impl::load()
{
if (loader) {
if (!paint) {
- if (auto p = loader->paint()) {
- paint = p.release();
- loader->close();
+ paint = loader->paint();
+ if (paint) {
if (w != loader->w || h != loader->h) {
if (!resizing) {
w = loader->w;
@@ -41,13 +40,12 @@ RenderUpdateFlag Picture::Impl::load()
loader->resize(paint, w, h);
resizing = false;
}
- if (paint) return RenderUpdateFlag::None;
+ return RenderUpdateFlag::None;
}
} else loader->sync();
if (!surface) {
- if ((surface = loader->bitmap().release())) {
- loader->close();
+ if ((surface = loader->bitmap())) {
return RenderUpdateFlag::Image;
}
}
@@ -55,6 +53,93 @@ RenderUpdateFlag Picture::Impl::load()
return RenderUpdateFlag::None;
}
+
+bool Picture::Impl::needComposition(uint8_t opacity)
+{
+ //In this case, paint(scene) would try composition itself.
+ if (opacity < 255) return false;
+
+ //Composition test
+ const Paint* target;
+ auto method = picture->composite(&target);
+ if (!target || method == tvg::CompositeMethod::ClipPath) return false;
+ if (target->pImpl->opacity == 255 || target->pImpl->opacity == 0) return false;
+
+ return true;
+}
+
+
+bool Picture::Impl::render(RenderMethod &renderer)
+{
+ bool ret = false;
+ if (surface) return renderer.renderImage(rd);
+ else if (paint) {
+ Compositor* cmp = nullptr;
+ if (needComp) {
+ cmp = renderer.target(bounds(renderer), renderer.colorSpace());
+ renderer.beginComposite(cmp, CompositeMethod::None, 255);
+ }
+ ret = paint->pImpl->render(renderer);
+ if (cmp) renderer.endComposite(cmp);
+ }
+ return ret;
+}
+
+
+bool Picture::Impl::size(float w, float h)
+{
+ this->w = w;
+ this->h = h;
+ resizing = true;
+ return true;
+}
+
+
+RenderRegion Picture::Impl::bounds(RenderMethod& renderer)
+{
+ if (rd) return renderer.region(rd);
+ if (paint) return paint->pImpl->bounds(renderer);
+ return {0, 0, 0, 0};
+}
+
+
+RenderTransform Picture::Impl::resizeTransform(const RenderTransform* pTransform)
+{
+ //Overriding Transformation by the desired image size
+ auto sx = w / loader->w;
+ auto sy = h / loader->h;
+ auto scale = sx < sy ? sx : sy;
+
+ RenderTransform tmp;
+ tmp.m = {scale, 0, 0, 0, scale, 0, 0, 0, 1};
+
+ if (!pTransform) return tmp;
+ else return RenderTransform(pTransform, &tmp);
+}
+
+
+Result Picture::Impl::load(ImageLoader* loader)
+{
+ //Same resource has been loaded.
+ if (this->loader == loader) {
+ this->loader->sharing--; //make it sure the reference counting.
+ return Result::Success;
+ } else if (this->loader) {
+ LoaderMgr::retrieve(this->loader);
+ }
+
+ this->loader = loader;
+
+ if (!loader->read()) return Result::Unknown;
+
+ this->w = loader->w;
+ this->h = loader->h;
+
+ return Result::Success;
+}
+
+
+
/************************************************************************/
/* External Class Implementation */
/************************************************************************/
diff --git a/thirdparty/thorvg/src/renderer/tvgPicture.h b/thirdparty/thorvg/src/renderer/tvgPicture.h
index 447f56ecb7..26a171ba66 100644
--- a/thirdparty/thorvg/src/renderer/tvgPicture.h
+++ b/thirdparty/thorvg/src/renderer/tvgPicture.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -20,16 +20,13 @@
* SOFTWARE.
*/
-#ifndef _TVG_PICTURE_IMPL_H_
-#define _TVG_PICTURE_IMPL_H_
+#ifndef _TVG_PICTURE_H_
+#define _TVG_PICTURE_H_
#include <string>
#include "tvgPaint.h"
#include "tvgLoader.h"
-/************************************************************************/
-/* Internal Class Implementation */
-/************************************************************************/
struct PictureIterator : Iterator
{
@@ -60,7 +57,7 @@ struct PictureIterator : Iterator
struct Picture::Impl
{
- shared_ptr<LoadModule> loader = nullptr;
+ ImageLoader* loader = nullptr;
Paint* paint = nullptr; //vector picture uses
Surface* surface = nullptr; //bitmap picture uses
@@ -71,14 +68,21 @@ struct Picture::Impl
bool resizing = false;
bool needComp = false; //need composition
+ RenderTransform resizeTransform(const RenderTransform* pTransform);
+ bool needComposition(uint8_t opacity);
+ bool render(RenderMethod &renderer);
+ bool size(float w, float h);
+ RenderRegion bounds(RenderMethod& renderer);
+ Result load(ImageLoader* ploader);
+
Impl(Picture* p) : picture(p)
{
}
~Impl()
{
+ LoaderMgr::retrieve(loader);
delete(paint);
- delete(surface);
}
bool dispose(RenderMethod& renderer)
@@ -89,34 +93,6 @@ struct Picture::Impl
return true;
}
- RenderTransform resizeTransform(const RenderTransform* pTransform)
- {
- //Overriding Transformation by the desired image size
- auto sx = w / loader->w;
- auto sy = h / loader->h;
- auto scale = sx < sy ? sx : sy;
-
- RenderTransform tmp;
- tmp.m = {scale, 0, 0, 0, scale, 0, 0, 0, 1};
-
- if (!pTransform) return tmp;
- else return RenderTransform(pTransform, &tmp);
- }
-
- bool needComposition(uint8_t opacity)
- {
- //In this case, paint(scene) would try composition itself.
- if (opacity < 255) return false;
-
- //Composition test
- const Paint* target;
- auto method = picture->composite(&target);
- if (!target || method == tvg::CompositeMethod::ClipPath) return false;
- if (target->pImpl->opacity == 255 || target->pImpl->opacity == 0) return false;
-
- return true;
- }
-
RenderData update(RenderMethod &renderer, const RenderTransform* pTransform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag pFlag, bool clipper)
{
auto flag = load();
@@ -135,30 +111,6 @@ struct Picture::Impl
return rd;
}
- bool render(RenderMethod &renderer)
- {
- bool ret = false;
- if (surface) return renderer.renderImage(rd);
- else if (paint) {
- Compositor* cmp = nullptr;
- if (needComp) {
- cmp = renderer.target(bounds(renderer), renderer.colorSpace());
- renderer.beginComposite(cmp, CompositeMethod::None, 255);
- }
- ret = paint->pImpl->render(renderer);
- if (cmp) renderer.endComposite(cmp);
- }
- return ret;
- }
-
- bool size(float w, float h)
- {
- this->w = w;
- this->h = h;
- resizing = true;
- return true;
- }
-
bool bounds(float* x, float* y, float* w, float* h, bool stroking)
{
if (rm.triangleCnt > 0) {
@@ -195,50 +147,35 @@ struct Picture::Impl
return true;
}
- RenderRegion bounds(RenderMethod& renderer)
- {
- if (rd) return renderer.region(rd);
- if (paint) return paint->pImpl->bounds(renderer);
- return {0, 0, 0, 0};
- }
-
Result load(const string& path)
{
if (paint || surface) return Result::InsufficientCondition;
- if (loader) loader->close();
+
bool invalid; //Invalid Path
- loader = LoaderMgr::loader(path, &invalid);
+ auto loader = static_cast<ImageLoader*>(LoaderMgr::loader(path, &invalid));
if (!loader) {
if (invalid) return Result::InvalidArguments;
return Result::NonSupport;
}
- if (!loader->read()) return Result::Unknown;
- w = loader->w;
- h = loader->h;
- return Result::Success;
+ return load(loader);
}
Result load(const char* data, uint32_t size, const string& mimeType, bool copy)
{
if (paint || surface) return Result::InsufficientCondition;
- if (loader) loader->close();
- loader = LoaderMgr::loader(data, size, mimeType, copy);
+ auto loader = static_cast<ImageLoader*>(LoaderMgr::loader(data, size, mimeType, copy));
if (!loader) return Result::NonSupport;
- if (!loader->read()) return Result::Unknown;
- w = loader->w;
- h = loader->h;
- return Result::Success;
+ return load(loader);
}
Result load(uint32_t* data, uint32_t w, uint32_t h, bool copy)
{
if (paint || surface) return Result::InsufficientCondition;
- if (loader) loader->close();
- loader = LoaderMgr::loader(data, w, h, copy);
+
+ auto loader = static_cast<ImageLoader*>(LoaderMgr::loader(data, w, h, copy));
if (!loader) return Result::FailedAllocation;
- this->w = loader->w;
- this->h = loader->h;
- return Result::Success;
+
+ return load(loader);
}
void mesh(const Polygon* triangles, const uint32_t triangleCnt)
@@ -258,18 +195,17 @@ struct Picture::Impl
{
load();
- auto ret = Picture::gen();
+ auto ret = Picture::gen().release();
+ auto dup = ret->pImpl;
- auto dup = ret.get()->pImpl;
if (paint) dup->paint = paint->duplicate();
- dup->loader = loader;
- if (surface) {
- dup->surface = new Surface;
- *dup->surface = *surface;
- //TODO: A dupilcation is not a proxy... it needs copy of the pixel data?
- dup->surface->owner = false;
+ if (loader) {
+ dup->loader = loader;
+ ++dup->loader->sharing;
}
+
+ dup->surface = surface;
dup->w = w;
dup->h = h;
dup->resizing = resizing;
@@ -280,7 +216,7 @@ struct Picture::Impl
memcpy(dup->rm.triangles, rm.triangles, sizeof(Polygon) * rm.triangleCnt);
}
- return ret.release();
+ return ret;
}
Iterator* iterator()
@@ -308,4 +244,4 @@ struct Picture::Impl
RenderUpdateFlag load();
};
-#endif //_TVG_PICTURE_IMPL_H_
+#endif //_TVG_PICTURE_H_
diff --git a/thirdparty/thorvg/src/renderer/tvgRender.cpp b/thirdparty/thorvg/src/renderer/tvgRender.cpp
index 64d76d3562..bdfb9f322e 100644
--- a/thirdparty/thorvg/src/renderer/tvgRender.cpp
+++ b/thirdparty/thorvg/src/renderer/tvgRender.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
diff --git a/thirdparty/thorvg/src/renderer/tvgRender.h b/thirdparty/thorvg/src/renderer/tvgRender.h
index 6c0a7d5f13..1e70b53494 100644
--- a/thirdparty/thorvg/src/renderer/tvgRender.h
+++ b/thirdparty/thorvg/src/renderer/tvgRender.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -23,6 +23,7 @@
#ifndef _TVG_RENDER_H_
#define _TVG_RENDER_H_
+#include <mutex>
#include "tvgCommon.h"
#include "tvgArray.h"
@@ -49,17 +50,33 @@ enum ColorSpace
struct Surface
{
union {
- pixel_t* data; //system based data pointer
- uint32_t* buf32; //for explicit 32bits channels
- uint8_t* buf8; //for explicit 8bits grayscale
+ pixel_t* data = nullptr; //system based data pointer
+ uint32_t* buf32; //for explicit 32bits channels
+ uint8_t* buf8; //for explicit 8bits grayscale
};
- uint32_t stride;
- uint32_t w, h;
- ColorSpace cs;
- uint8_t channelSize;
+ mutex mtx; //used for thread safety
+ uint32_t stride = 0;
+ uint32_t w = 0, h = 0;
+ ColorSpace cs = ColorSpace::Unsupported;
+ uint8_t channelSize = 0;
+ bool premultiplied = 0; //Alpha-premultiplied
+
+ Surface()
+ {
+ }
+
+ Surface(const Surface* rhs)
+ {
+ data = rhs->data;
+ stride = rhs->stride;
+ w = rhs->w;
+ h = rhs->h;
+ cs = rhs->cs;
+ channelSize = rhs->channelSize;
+ premultiplied = rhs->premultiplied;
+ }
+
- bool premultiplied; //Alpha-premultiplied
- bool owner; //Only owner could modify the buffer
};
struct Compositor
diff --git a/thirdparty/thorvg/src/renderer/tvgSaveModule.h b/thirdparty/thorvg/src/renderer/tvgSaveModule.h
index 09e7bde72b..fed05c52df 100644
--- a/thirdparty/thorvg/src/renderer/tvgSaveModule.h
+++ b/thirdparty/thorvg/src/renderer/tvgSaveModule.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2021 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -34,7 +34,7 @@ public:
virtual ~SaveModule() {}
virtual bool save(Paint* paint, const string& path, bool compress) = 0;
- virtual bool save(Animation* animation, const string& path, uint32_t quality, uint32_t fps) = 0;
+ virtual bool save(Animation* animation, Paint* bg, const string& path, uint32_t quality, uint32_t fps) = 0;
virtual bool close() = 0;
};
diff --git a/thirdparty/thorvg/src/renderer/tvgSaver.cpp b/thirdparty/thorvg/src/renderer/tvgSaver.cpp
index 038d1ad097..11eb24d437 100644
--- a/thirdparty/thorvg/src/renderer/tvgSaver.cpp
+++ b/thirdparty/thorvg/src/renderer/tvgSaver.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2021 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -37,9 +37,12 @@
struct Saver::Impl
{
SaveModule* saveModule = nullptr;
+ Paint* bg = nullptr;
+
~Impl()
{
delete(saveModule);
+ delete(bg);
}
};
@@ -139,7 +142,16 @@ Result Saver::save(std::unique_ptr<Paint> paint, const string& path, bool compre
}
-Result Saver::save(std::unique_ptr<Animation> animation, const string& path, uint32_t quality, uint32_t fps) noexcept
+Result Saver::background(unique_ptr<Paint> paint) noexcept
+{
+ delete(pImpl->bg);
+ pImpl->bg = paint.release();
+
+ return Result::Success;
+}
+
+
+Result Saver::save(unique_ptr<Animation> animation, const string& path, uint32_t quality, uint32_t fps) noexcept
{
auto a = animation.release();
if (!a) return Result::MemoryCorruption;
@@ -156,7 +168,7 @@ Result Saver::save(std::unique_ptr<Animation> animation, const string& path, uin
}
if (auto saveModule = _find(path)) {
- if (saveModule->save(a, path, quality, fps)) {
+ if (saveModule->save(a, pImpl->bg, path, quality, fps)) {
pImpl->saveModule = saveModule;
return Result::Success;
} else {
diff --git a/thirdparty/thorvg/src/renderer/tvgScene.cpp b/thirdparty/thorvg/src/renderer/tvgScene.cpp
index cd73913b30..f5809cf93b 100644
--- a/thirdparty/thorvg/src/renderer/tvgScene.cpp
+++ b/thirdparty/thorvg/src/renderer/tvgScene.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
diff --git a/thirdparty/thorvg/src/renderer/tvgScene.h b/thirdparty/thorvg/src/renderer/tvgScene.h
index b558e95a2f..1a5600c231 100644
--- a/thirdparty/thorvg/src/renderer/tvgScene.h
+++ b/thirdparty/thorvg/src/renderer/tvgScene.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -20,15 +20,12 @@
* SOFTWARE.
*/
-#ifndef _TVG_SCENE_IMPL_H_
-#define _TVG_SCENE_IMPL_H_
+#ifndef _TVG_SCENE_H_
+#define _TVG_SCENE_H_
#include <float.h>
#include "tvgPaint.h"
-/************************************************************************/
-/* Internal Class Implementation */
-/************************************************************************/
struct SceneIterator : Iterator
{
@@ -126,8 +123,7 @@ struct Scene::Impl
this->renderer = &renderer;
if (clipper) {
- Array<RenderData> rds;
- rds.reserve(paints.size());
+ Array<RenderData> rds(paints.size());
for (auto paint : paints) {
rds.push(paint->pImpl->update(renderer, transform, clips, opacity, flag, true));
}
@@ -216,9 +212,8 @@ struct Scene::Impl
Paint* duplicate()
{
- auto ret = Scene::gen();
-
- auto dup = ret.get()->pImpl;
+ auto ret = Scene::gen().release();
+ auto dup = ret->pImpl;
for (auto paint : paints) {
auto cdup = paint->duplicate();
@@ -226,7 +221,7 @@ struct Scene::Impl
dup->paints.push_back(cdup);
}
- return ret.release();
+ return ret;
}
void clear(bool free)
@@ -247,4 +242,4 @@ struct Scene::Impl
}
};
-#endif //_TVG_SCENE_IMPL_H_
+#endif //_TVG_SCENE_H_
diff --git a/thirdparty/thorvg/src/renderer/tvgShape.cpp b/thirdparty/thorvg/src/renderer/tvgShape.cpp
index 9a64c7df9f..23b8006dd9 100644
--- a/thirdparty/thorvg/src/renderer/tvgShape.cpp
+++ b/thirdparty/thorvg/src/renderer/tvgShape.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
diff --git a/thirdparty/thorvg/src/renderer/tvgShape.h b/thirdparty/thorvg/src/renderer/tvgShape.h
index 46b2d7d0db..a7f1226690 100644
--- a/thirdparty/thorvg/src/renderer/tvgShape.h
+++ b/thirdparty/thorvg/src/renderer/tvgShape.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -20,16 +20,13 @@
* SOFTWARE.
*/
-#ifndef _TVG_SHAPE_IMPL_H_
-#define _TVG_SHAPE_IMPL_H_
+#ifndef _TVG_SHAPE_H_
+#define _TVG_SHAPE_H_
#include <memory.h>
#include "tvgMath.h"
#include "tvgPaint.h"
-/************************************************************************/
-/* Internal Class Implementation */
-/************************************************************************/
struct Shape::Impl
{
@@ -341,9 +338,9 @@ struct Shape::Impl
Paint* duplicate()
{
- auto ret = Shape::gen();
+ auto ret = Shape::gen().release();
+ auto dup = ret->pImpl;
- auto dup = ret.get()->pImpl;
dup->rs.rule = rs.rule;
//Color
@@ -379,7 +376,7 @@ struct Shape::Impl
dup->flag |= RenderUpdateFlag::Gradient;
}
- return ret.release();
+ return ret;
}
Iterator* iterator()
@@ -388,4 +385,4 @@ struct Shape::Impl
}
};
-#endif //_TVG_SHAPE_IMPL_H_
+#endif //_TVG_SHAPE_H_
diff --git a/thirdparty/thorvg/src/renderer/tvgSwCanvas.cpp b/thirdparty/thorvg/src/renderer/tvgSwCanvas.cpp
index 95df6b486d..4404057049 100644
--- a/thirdparty/thorvg/src/renderer/tvgSwCanvas.cpp
+++ b/thirdparty/thorvg/src/renderer/tvgSwCanvas.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
diff --git a/thirdparty/thorvg/src/renderer/tvgTaskScheduler.cpp b/thirdparty/thorvg/src/renderer/tvgTaskScheduler.cpp
index e3887c60fc..36d1ce1f8b 100644
--- a/thirdparty/thorvg/src/renderer/tvgTaskScheduler.cpp
+++ b/thirdparty/thorvg/src/renderer/tvgTaskScheduler.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -20,11 +20,11 @@
* SOFTWARE.
*/
-#include <deque>
#include <thread>
-#include <vector>
#include <atomic>
#include <condition_variable>
+#include "tvgArray.h"
+#include "tvgInlist.h"
#include "tvgTaskScheduler.h"
/************************************************************************/
@@ -34,7 +34,7 @@
namespace tvg {
struct TaskQueue {
- deque<Task*> taskDeque;
+ Inlist<Task> taskDeque;
mutex mtx;
condition_variable ready;
bool done = false;
@@ -44,8 +44,6 @@ struct TaskQueue {
unique_lock<mutex> lock{mtx, try_to_lock};
if (!lock || taskDeque.empty()) return false;
*task = taskDeque.front();
- taskDeque.pop_front();
-
return true;
}
@@ -54,11 +52,9 @@ struct TaskQueue {
{
unique_lock<mutex> lock{mtx, try_to_lock};
if (!lock) return false;
- taskDeque.push_back(task);
+ taskDeque.back(task);
}
-
ready.notify_one();
-
return true;
}
@@ -82,8 +78,6 @@ struct TaskQueue {
if (taskDeque.empty()) return false;
*task = taskDeque.front();
- taskDeque.pop_front();
-
return true;
}
@@ -91,12 +85,10 @@ struct TaskQueue {
{
{
unique_lock<mutex> lock{mtx};
- taskDeque.push_back(task);
+ taskDeque.back(task);
}
-
ready.notify_one();
}
-
};
@@ -105,24 +97,36 @@ static thread_local bool _async = true; //toggle async tasking for each thread
struct TaskSchedulerImpl
{
- uint32_t threadCnt;
- vector<thread> threads;
- vector<TaskQueue> taskQueues;
+ Array<thread*> threads;
+ Array<TaskQueue*> taskQueues;
atomic<uint32_t> idx{0};
- TaskSchedulerImpl(unsigned threadCnt) : threadCnt(threadCnt), taskQueues(threadCnt)
+ TaskSchedulerImpl(unsigned threadCnt)
{
threads.reserve(threadCnt);
+ taskQueues.reserve(threadCnt);
for (unsigned i = 0; i < threadCnt; ++i) {
- threads.emplace_back([&, i] { run(i); });
+ taskQueues.push(new TaskQueue);
+ threads.push(new thread);
+ }
+ for (unsigned i = 0; i < threadCnt; ++i) {
+ *threads.data[i] = thread([&, i] { run(i); });
}
}
~TaskSchedulerImpl()
{
- for (auto& queue : taskQueues) queue.complete();
- for (auto& thread : threads) thread.join();
+ for (auto tq = taskQueues.data; tq < taskQueues.end(); ++tq) {
+ (*tq)->complete();
+ }
+ for (auto thread = threads.data; thread < threads.end(); ++thread) {
+ (*thread)->join();
+ delete(*thread);
+ }
+ for (auto tq = taskQueues.data; tq < taskQueues.end(); ++tq) {
+ delete(*tq);
+ }
}
void run(unsigned i)
@@ -132,14 +136,14 @@ struct TaskSchedulerImpl
//Thread Loop
while (true) {
auto success = false;
- for (unsigned x = 0; x < threadCnt * 2; ++x) {
- if (taskQueues[(i + x) % threadCnt].tryPop(&task)) {
+ for (unsigned x = 0; x < threads.count * 2; ++x) {
+ if (taskQueues[(i + x) % threads.count]->tryPop(&task)) {
success = true;
break;
}
}
- if (!success && !taskQueues[i].pop(&task)) break;
+ if (!success && !taskQueues[i]->pop(&task)) break;
(*task)(i + 1);
}
}
@@ -147,13 +151,13 @@ struct TaskSchedulerImpl
void request(Task* task)
{
//Async
- if (threadCnt > 0 && _async) {
+ if (threads.count > 0 && _async) {
task->prepare();
auto i = idx++;
- for (unsigned n = 0; n < threadCnt; ++n) {
- if (taskQueues[(i + n) % threadCnt].tryPush(task)) return;
+ for (unsigned n = 0; n < threads.count; ++n) {
+ if (taskQueues[(i + n) % threads.count]->tryPush(task)) return;
}
- taskQueues[i % threadCnt].push(task);
+ taskQueues[i % threads.count]->push(task);
//Sync
} else {
task->run(0);
@@ -192,7 +196,7 @@ void TaskScheduler::request(Task* task)
unsigned TaskScheduler::threads()
{
- if (inst) return inst->threadCnt;
+ if (inst) return inst->threads.count;
return 0;
}
diff --git a/thirdparty/thorvg/src/renderer/tvgTaskScheduler.h b/thirdparty/thorvg/src/renderer/tvgTaskScheduler.h
index 2dad80f5d0..483e084880 100644
--- a/thirdparty/thorvg/src/renderer/tvgTaskScheduler.h
+++ b/thirdparty/thorvg/src/renderer/tvgTaskScheduler.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
+ * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -26,6 +26,7 @@
#include <mutex>
#include <condition_variable>
#include "tvgCommon.h"
+#include "tvgInlist.h"
namespace tvg
{
@@ -50,6 +51,8 @@ private:
bool pending = false;
public:
+ INLIST_ITEM(Task);
+
virtual ~Task() = default;
void done()
diff --git a/thirdparty/thorvg/src/renderer/tvgText.cpp b/thirdparty/thorvg/src/renderer/tvgText.cpp
new file mode 100644
index 0000000000..1fe244c11d
--- /dev/null
+++ b/thirdparty/thorvg/src/renderer/tvgText.cpp
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2023 - 2024 the ThorVG project. All rights reserved.
+
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+
+#include "tvgText.h"
+
+
+/************************************************************************/
+/* Internal Class Implementation */
+/************************************************************************/
+
+
+
+/************************************************************************/
+/* External Class Implementation */
+/************************************************************************/
+
+
+Text::Text() : pImpl(new Impl)
+{
+ Paint::pImpl->id = TVG_CLASS_ID_TEXT;
+}
+
+
+Text::~Text()
+{
+ delete(pImpl);
+}
+
+
+Result Text::text(const char* text) noexcept
+{
+ return pImpl->text(text);
+}
+
+
+Result Text::font(const char* name, float size, const char* style) noexcept
+{
+ return pImpl->font(name, size, style);
+}
+
+
+Result Text::load(const std::string& path) noexcept
+{
+ bool invalid; //invalid path
+ if (!LoaderMgr::loader(path, &invalid)) {
+ if (invalid) return Result::InvalidArguments;
+ else return Result::NonSupport;
+ }
+
+ return Result::Success;
+}
+
+
+Result Text::unload(const std::string& path) noexcept
+{
+ if (LoaderMgr::retrieve(path)) return Result::Success;
+ return Result::InsufficientCondition;
+}
+
+
+Result Text::fill(uint8_t r, uint8_t g, uint8_t b) noexcept
+{
+ if (!pImpl->paint) return Result::InsufficientCondition;
+
+ return pImpl->fill(r, g, b);
+}
+
+
+Result Text::fill(unique_ptr<Fill> f) noexcept
+{
+ if (!pImpl->paint) return Result::InsufficientCondition;
+
+ auto p = f.release();
+ if (!p) return Result::MemoryCorruption;
+
+ return pImpl->fill(p);
+}
+
+
+unique_ptr<Text> Text::gen() noexcept
+{
+ return unique_ptr<Text>(new Text);
+}
+
+
+uint32_t Text::identifier() noexcept
+{
+ return TVG_CLASS_ID_TEXT;
+}
diff --git a/thirdparty/thorvg/src/renderer/tvgText.h b/thirdparty/thorvg/src/renderer/tvgText.h
new file mode 100644
index 0000000000..b9f7ef6079
--- /dev/null
+++ b/thirdparty/thorvg/src/renderer/tvgText.h
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2023 - 2024 the ThorVG project. All rights reserved.
+
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _TVG_TEXT_H
+#define _TVG_TEXT_H
+
+#include <cstring>
+#include "tvgShape.h"
+#include "tvgFill.h"
+
+#ifdef THORVG_TTF_LOADER_SUPPORT
+ #include "tvgTtfLoader.h"
+#else
+ #include "tvgLoader.h"
+#endif
+
+struct Text::Impl
+{
+ RenderData rd = nullptr;
+ FontLoader* loader = nullptr;
+ Shape* paint = nullptr;
+ char* utf8 = nullptr;
+ float fontSize;
+ bool italic = false;
+ bool changed = false;
+
+ ~Impl()
+ {
+ free(utf8);
+ LoaderMgr::retrieve(loader);
+ delete(paint);
+ }
+
+ Result fill(uint8_t r, uint8_t g, uint8_t b)
+ {
+ return paint->fill(r, g, b);
+ }
+
+ Result fill(Fill* f)
+ {
+ return paint->fill(cast<Fill>(f));
+ }
+
+ Result text(const char* utf8)
+ {
+ free(this->utf8);
+ if (utf8) this->utf8 = strdup(utf8);
+ else this->utf8 = nullptr;
+ changed = true;
+
+ return Result::Success;
+ }
+
+ Result font(const char* name, float size, const char* style)
+ {
+ auto loader = LoaderMgr::loader(name);
+ if (!loader) return Result::InsufficientCondition;
+
+ //Same resource has been loaded.
+ if (this->loader == loader) {
+ this->loader->sharing--; //make it sure the reference counting.
+ return Result::Success;
+ } else if (this->loader) {
+ LoaderMgr::retrieve(this->loader);
+ }
+ this->loader = static_cast<FontLoader*>(loader);
+
+ if (!paint) paint = Shape::gen().release();
+
+ fontSize = size;
+ if (style && strstr(style, "italic")) italic = true;
+ changed = true;
+ return Result::Success;
+ }
+
+ RenderRegion bounds(RenderMethod& renderer)
+ {
+ return renderer.region(rd);
+ }
+
+ bool render(RenderMethod& renderer)
+ {
+ if (paint) return PP(paint)->render(renderer);
+ return false;
+ }
+
+ bool load()
+ {
+ if (!loader) return false;
+
+ //reload
+ if (changed) {
+ loader->request(paint, utf8, italic);
+ loader->read();
+ changed = false;
+ }
+ if (paint) {
+ loader->resize(paint, fontSize, fontSize);
+ return true;
+ }
+ return false;
+ }
+
+ RenderData update(RenderMethod& renderer, const RenderTransform* transform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag pFlag, bool clipper)
+ {
+ if (!load()) return nullptr;
+
+ //transform the gradient coordinates based on the final scaled font.
+ if (P(paint)->flag & RenderUpdateFlag::Gradient) {
+ auto fill = P(paint)->rs.fill;
+ auto scale = 1.0f / loader->scale;
+ if (fill->identifier() == TVG_CLASS_ID_LINEAR) {
+ P(static_cast<LinearGradient*>(fill))->x1 *= scale;
+ P(static_cast<LinearGradient*>(fill))->y1 *= scale;
+ P(static_cast<LinearGradient*>(fill))->x2 *= scale;
+ P(static_cast<LinearGradient*>(fill))->y2 *= scale;
+ } else {
+ P(static_cast<RadialGradient*>(fill))->cx *= scale;
+ P(static_cast<RadialGradient*>(fill))->cy *= scale;
+ P(static_cast<RadialGradient*>(fill))->r *= scale;
+ P(static_cast<RadialGradient*>(fill))->fx *= scale;
+ P(static_cast<RadialGradient*>(fill))->fy *= scale;
+ P(static_cast<RadialGradient*>(fill))->fr *= scale;
+ }
+ }
+ rd = PP(paint)->update(renderer, transform, clips, opacity, pFlag, clipper);
+ return rd;
+ }
+
+ bool bounds(float* x, float* y, float* w, float* h, TVG_UNUSED bool stroking)
+ {
+ if (!load() || !paint) return false;
+ paint->bounds(x, y, w, h, true);
+ return true;
+ }
+
+ bool dispose(RenderMethod& renderer)
+ {
+ renderer.dispose(rd);
+ this->rd = nullptr;
+ return true;
+ }
+
+ Paint* duplicate()
+ {
+ load();
+
+ auto ret = Text::gen().release();
+ auto dup = ret->pImpl;
+ if (paint) dup->paint = static_cast<Shape*>(paint->duplicate());
+
+ if (loader) {
+ dup->loader = loader;
+ ++dup->loader->sharing;
+ }
+
+ dup->utf8 = strdup(utf8);
+ dup->italic = italic;
+ dup->fontSize = fontSize;
+
+ return ret;
+ }
+
+ Iterator* iterator()
+ {
+ return nullptr;
+ }
+};
+
+
+
+#endif //_TVG_TEXT_H
diff --git a/thirdparty/thorvg/src/renderer/tvgWgCanvas.cpp b/thirdparty/thorvg/src/renderer/tvgWgCanvas.cpp
new file mode 100644
index 0000000000..5205df1737
--- /dev/null
+++ b/thirdparty/thorvg/src/renderer/tvgWgCanvas.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2023 - 2024 the ThorVG project. All rights reserved.
+
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "tvgCanvas.h"
+
+#ifdef THORVG_WG_RASTER_SUPPORT
+ #include "tvgWgRenderer.h"
+#endif
+
+/************************************************************************/
+/* Internal Class Implementation */
+/************************************************************************/
+
+struct WgCanvas::Impl
+{
+};
+
+
+/************************************************************************/
+/* External Class Implementation */
+/************************************************************************/
+
+#ifdef THORVG_WG_RASTER_SUPPORT
+WgCanvas::WgCanvas() : Canvas(WgRenderer::gen()), pImpl(new Impl)
+#else
+WgCanvas::WgCanvas() : Canvas(nullptr), pImpl(nullptr)
+#endif
+{
+}
+
+WgCanvas::~WgCanvas()
+{
+ delete pImpl;
+}
+
+Result WgCanvas::target(void* window, uint32_t w, uint32_t h) noexcept
+{
+#ifdef THORVG_WG_RASTER_SUPPORT
+ if (!window) return Result::InvalidArguments;
+ if ((w == 0) || (h == 0)) return Result::InvalidArguments;
+
+ //We know renderer type, avoid dynamic_cast for performance.
+ auto renderer = static_cast<WgRenderer*>(Canvas::pImpl->renderer);
+ if (!renderer) return Result::MemoryCorruption;
+
+ if (!renderer->target(window, w, h)) return Result::Unknown;
+
+ //Paints must be updated again with this new target.
+ Canvas::pImpl->needRefresh();
+
+ return Result::Success;
+#endif
+ return Result::NonSupport;
+}
+
+unique_ptr<WgCanvas> WgCanvas::gen() noexcept
+{
+#ifdef THORVG_WG_RASTER_SUPPORT
+ return unique_ptr<WgCanvas>(new WgCanvas);
+#endif
+ return nullptr;
+}
diff --git a/thirdparty/thorvg/update-thorvg.sh b/thirdparty/thorvg/update-thorvg.sh
index d4323848da..a1732d5157 100755
--- a/thirdparty/thorvg/update-thorvg.sh
+++ b/thirdparty/thorvg/update-thorvg.sh
@@ -1,6 +1,6 @@
#!/bin/bash -e
-VERSION=0.11.6
+VERSION=0.12.0
cd thirdparty/thorvg/ || true
rm -rf AUTHORS LICENSE inc/ src/ *.zip *.tar.gz tmp/
@@ -52,6 +52,7 @@ cp -rv src/renderer ../src/
# Only sw_engine is enabled.
rm -rfv ../src/renderer/gl_engine
+rm -rfv ../src/renderer/wg_engine
# Enabled embedded loaders: raw, JPEG, PNG.
mkdir ../src/loaders